diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..2b0f3d2 --- /dev/null +++ b/Makefile @@ -0,0 +1,10 @@ +all: get format + +get: + ../node_modules/coffee-script/bin/coffee -c get-repositories.coffee + ../node_modules/coffee-script/bin/coffee -c get-details.coffee + +format: + ../node_modules/coffee-script/bin/coffee format-languages.coffee + ../node_modules/coffee-script/bin/coffee format-users.coffee + ../node_modules/coffee-script/bin/coffee format-repositories.coffee diff --git a/check-logins.coffee b/check-logins.coffee new file mode 100644 index 0000000..dd7bab8 --- /dev/null +++ b/check-logins.coffee @@ -0,0 +1,18 @@ +#!/usr/bin/env coffee +utils = require './utils' +fs = require 'fs' +data = require './raw/github-users-stats.json' +prev = require './old-logins.json' +curr = require './temp-logins.json' + +filtered = prev + .filter(utils.isNotIn(curr)) + .map(utils.reverseFind(data)) + .filter((_) -> _) + .map (_) -> + login: _.login, followers: _.followers + .sort (a, b) -> + b.followers - a.followers + +console.log filtered +console.log JSON.stringify filtered.map(utils.prop 'login'), null, 2 diff --git a/format-languages.coffee b/format-languages.coffee new file mode 100644 index 0000000..fffa594 --- /dev/null +++ b/format-languages.coffee @@ -0,0 +1,23 @@ +#!/usr/bin/env coffee +utils = require './utils' + +getLanguageStats = (inputFile, outFile) -> + stats = require inputFile + total = stats.length + unsorted = Total: total + stats.forEach (stat) -> + {language} = stat + return unless language + unsorted[language] ?= 0 + unsorted[language] += 1 + + languages = {} + Object.keys(unsorted) + .sort (a, b) -> + unsorted[b] - unsorted[a] + .forEach (language) -> + languages[language] = unsorted[language] + + utils.writeStats outFile, languages + +getLanguageStats './raw/github-users-stats.json', './raw/github-languages-stats.json' diff --git a/format-users.coffee b/format-users.coffee new file mode 100644 index 0000000..1bb2006 --- /dev/null +++ b/format-users.coffee @@ -0,0 +1,85 @@ +#!/usr/bin/env coffee +fs = require 'fs' + +top = (stats, field, type) -> + get = (stat) -> + value = stat[field] + if type is 'list' then value.length else value + + format = (stat) -> + value = get stat + switch type + when 'thousands' then "#{(value / 1000)}k" + else value + + stats + .slice() + .sort (a, b) -> + get(b) - get(a) + .slice(0, 15) + .map (stat) -> + login = stat.login + "[#{login}](https://github.com/#{login}) (#{format stat})" + .join ', ' + +stats2markdown = (datafile, mdfile, title) -> + minFollowers = 176 + maxNumber = 256 + stats = require(datafile) + + today = new Date() + from = new Date() + from.setYear today.getFullYear() - 1 + + out = """ + # Most active GitHub users ([git.io/top](http://git.io/top)) + + The count of contributions (summary of Pull Requests, opened issues and commits) to public repos at GitHub.com from **#{from.toGMTString()}** till **#{today.toGMTString()}**. + + Only first 1000 GitHub users according to the count of followers are taken. + This is because of limitations of GitHub search. Sorting algo in pseudocode: + + ```coffeescript + githubUsers + .filter((user) -> user.followers > #{minFollowers}) + .sortBy('contributions') + .slice(0, #{maxNumber}) + ``` + + Made with data mining of GitHub.com ([raw data](https://gist.github.com/4524946), [script](https://github.com/paulmillr/top-github-users)) by [@paulmillr](https://github.com/paulmillr) with contribs of [@lifesinger](https://githubcom/lifesinger). Updated every sunday. + + + + + + + + + \n + """ + + rows = stats.slice(0, maxNumber).map (stat, index) -> + """ + + + + + + + + + """.replace(/\n/g, '') + + out += "#{rows.join('\n')}\n
#UsernameContributionsLanguageLocation
##{index + 1}#{stat.login}#{if stat.name then ' (' + stat.name + ')' else ''}#{stat.contributions}#{stat.language}#{stat.location}
\n\n" + + out += """## Top 10 users from this list by other metrics: + +* **Followers:** #{top stats, 'followers', 'thousands'} +* **Current contributions streak:** #{top stats, 'contributionsCurrentStreak'} +* **Organisations:** #{top stats, 'organizations', 'list'} + """ + + fs.writeFileSync mdfile, out + console.log 'Saved to', mdfile + +stats2markdown './raw/github-users-stats.json', './formatted/active.md' diff --git a/get-details.coffee b/get-details.coffee new file mode 100644 index 0000000..1719c55 --- /dev/null +++ b/get-details.coffee @@ -0,0 +1,50 @@ +#!/usr/bin/env coffee +cheerio = require 'cheerio' +utils = require './utils' + +stats = {} + +getStats = (html, url) -> + $ = cheerio.load html + byProp = (field) -> $("[itemprop='#{field}']") + getInt = (text) -> parseInt text.replace ',', '' + getOrgName = (index, item) -> $(item).attr('title') + getFollowers = -> + text = $('.stats li:nth-child(1) a').text().trim() + multiplier = if text.indexOf('k') > 0 then 1000 else 1 + (parseFloat text) * multiplier + + pageDesc = $('meta[name="description"]').attr('content') + + userStats = + name: byProp('name').text().trim() + login: byProp('additionalName').text().trim() + location: byProp('homeLocation').text().trim() + language: (/\sin ([\w-]+)/.exec(pageDesc)?[1] ? '') + gravatar: byProp('image').attr('href') + followers: getFollowers() + organizations: $('.orgs li > a').map(getOrgName) + contributions: getInt $('.contrib-day > .num').text() + contributionsStreak: getInt $('.contrib-streak > .num').text() + contributionsCurrentStreak: getInt $('.contrib-streak-current > .num').text() + + stats[userStats.login] = userStats + userStats + +sortStats = (stats) -> + minContributions = 1 + Object.keys(stats) + .filter (login) -> + stats[login].contributions >= minContributions + .sort (a, b) -> + stats[b].contributions - stats[a].contributions + .map (login) -> + stats[login] + +saveStats = -> + logins = require './temp-logins.json' + urls = logins.map (login) -> "https://github.com/#{login}" + utils.batchGet urls, getStats, -> + utils.writeStats './raw/github-users-stats.json', sortStats stats + +saveStats() diff --git a/get-users.coffee b/get-users.coffee new file mode 100644 index 0000000..a41dff2 --- /dev/null +++ b/get-users.coffee @@ -0,0 +1,18 @@ +#!/usr/bin/env coffee +fs = require 'fs' +utils = require './utils' + +saveTopLogins = -> + MIN_FOLLOWERS = 170 + MAX_PAGES = 10 + urls = utils.range(1, MAX_PAGES + 1).map (page) -> + "https://api.github.com/legacy/user/search/followers:%3E#{MIN_FOLLOWERS}?sort=followers&order=desc&start_page=#{page}" + + parse = (text) -> + JSON.parse(text).users.map (_) -> _.username + + utils.batchGet urls, parse, (all) -> + logins = [].concat.apply [], all + utils.writeStats './temp-logins.json', logins + +saveTopLogins()