readme, etc

This commit is contained in:
wassname
2017-11-29 16:27:49 +08:00
parent 92487e86b2
commit 26d4f27835
7 changed files with 10191 additions and 241 deletions
Binary file not shown.

After

Width:  |  Height:  |  Size: 104 KiB

+9 -1
View File
@@ -1,8 +1,16 @@
Static site for comparing github repos/users.
[live site](https://wassname.github.io/compare_altcoin_development/src/)
# Screenshot
![](docs/img/2017-24-11-29-17_Selection_001.png)
TODO:
- [x] bitbucket
- [x] github organisations
- [x] progbar
- [x] configurable repos
- [x] user input
- [ ] detect data from forks?
- [ ] finer stats, e.g. total contributions, change in lines of code etc
File diff suppressed because it is too large Load Diff
+26 -19
View File
@@ -5,18 +5,28 @@
<title>Compare github repository statistics</title>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/datatables/1.10.13/css/jquery.dataTables.css">
<link rel="stylesheet" href="/css/style.css">
<link rel="stylesheet" href="css/style.css">
</head>
<body>
<div>
<label><a href="https://github.com/settings/tokens">Github api token: </a></label>
<input id="token" placeholder="token" value="1996bd63f4c524b4cd36499e3db39d321f0b39a7"/>
</div>
<table id="table" class="display" width="100%">
<div>
<label title="Enter each entry onseperate lines. Each line as 'name,url' where url is 'https://github.com/<orgname>/<reponame>' or 'https://github.com/orgs/<orgname>' or 'https://github.com/users/<username>' or a space seperated list 'https://github.com/<orgname>/<reponame1> https://github.com/<orgname>/<reponame2>">csv inputs</label>
<textarea id="repos" style="width: 100%; height:200px;">
<textbox id="markdown"></textbox>
</table>
<hr />
<div class="">
<h2>Gather new data (beta)</h2>
Enter your github api token, update the csv inputs if you want, and hit go. Monitor the javascript console for errors and watch the countdown that replaces the go button.
<div>
<label><a href="https://github.com/settings/tokens">Github api token: </a></label>
<input id="token" placeholder="token" value="1996bd63f4c524b4cd36499e3db39d321f0b39a7"/>
</div>
<div>
<label title="Enter each entry onseperate lines. Each line as 'name,url' where url is 'https://github.com/<orgname>/<reponame>' or 'https://github.com/orgs/<orgname>' or 'https://github.com/users/<username>' or a space seperated list 'https://github.com/<orgname>/<reponame1> https://github.com/<orgname>/<reponame2>">csv inputs</label>
<textarea id="repos" style="width: 100%; height:200px;">
#name,url/s
Bitcoin,https://github.com/bitcoin/bitcoin https://github.com/bitcoin/bips https://github.com/bitcoin/libbase58
Iota,https://github.com/orgs/iotaledger
@@ -66,18 +76,15 @@ Sia,https://github.com/NebulousLabs/Sia https://github.com/NebulousLabs/Sia-UI h
Status,https://github.com/orgs/status-im
Cardano,https://github.com/input-output-hk/cardano-sl
Tittiecoin,https://github.com/users/tittiecoin
</textarea>
</div>
<div class="">
<button id="go">go</button>
<button id="clear">clear cache</button>
</textarea>
</div>
<div class="">
<button id="go">go</button>
<button id="clear">clear cache</button>
</div>
</div>
<table id="table" class="display" width="100%">
<textbox id="markdown"></textbox>
</table>
</body>
@@ -94,7 +101,7 @@ Tittiecoin,https://github.com/users/tittiecoin
<script src="https://cdnjs.cloudflare.com/ajax/libs/gh.js/3.0.8/gh.min.js" charset="utf-8"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.17.1/moment.js" charset="utf-8"></script>
<script src="js/example_data.js" charset="utf-8"></script>
<script src="data/example_data.js" charset="utf-8"></script>
<script src="js/fetch_stats.js" charset="utf-8"></script>
<script src="js/main.js" charset="utf-8"></script>
</html>
File diff suppressed because one or more lines are too long
+45 -38
View File
@@ -3,7 +3,6 @@
*/
LITE_MODE = localStorage['LITE_MODE']
let gh = new GitHub(localStorage['gh_token'] || '')
$(document).ready(function() {
@@ -15,17 +14,16 @@ $(document).ready(function() {
gh = new GitHub(localStorage['gh_token'] || '')
})
var MergeBySumingNumbers = objects =>
objects.reduce((s,r)=>{
Object.keys(r).map(key=>{
v = r[key]
if (typeof(v)==="number") s[key]=(s[key]||0)+v
else s[key] = v
})
return s
},{})
var MergeBySumingNumbers = objects => objects.reduce((s, r) => {
Object.keys(r).map(key => {
v = r[key]
if (typeof(v) === "number") {
s[key] = _.round((s[key] || 0) + v, 3)
} else
s[key] = v
})
return s
}, {})
function promiseGitHubRepoStats(url) {
@@ -40,10 +38,17 @@ function promiseGitHubRepoStats(url) {
})
})
if (LITE_MODE) {return promiseStats}
if (LITE_MODE) {
return promiseStats
}
var promiseContributors = new Promise(function(resolve, reject) {
gh.get(apiUrl + '/contributors', {all:true, opts:{per_page:100}}, (err, response) => {
gh.get(apiUrl + '/contributors', {
all: true,
opts: {
per_page: 100
}
}, (err, response) => {
if (err)
reject(err)
else
@@ -57,7 +62,11 @@ function promiseGitHubRepoStats(url) {
})
var promiseCommits = new Promise(function(resolve, reject) {
gh.get(apiUrl + '/stats/participation', {opts:{per_page:100}}, (err, response) => {
gh.get(apiUrl + '/stats/participation', {
opts: {
per_page: 100
}
}, (err, response) => {
if (err)
reject(err)
else
@@ -70,7 +79,11 @@ function promiseGitHubRepoStats(url) {
})
var promiseChanges = new Promise(function(resolve, reject) {
gh.get(apiUrl + '/stats/code_frequency', {opts:{per_page:100}}, (err, response) => {
gh.get(apiUrl + '/stats/code_frequency', {
opts: {
per_page: 100
}
}, (err, response) => {
if (err)
reject(err)
else
@@ -83,7 +96,11 @@ function promiseGitHubRepoStats(url) {
})
var promiseReleases = new Promise(function(resolve, reject) {
gh.get(apiUrl + '/releases', {opts:{per_page:100}}, (err, response) => {
gh.get(apiUrl + '/releases', {
opts: {
per_page: 100
}
}, (err, response) => {
if (err)
reject(err)
else
@@ -96,38 +113,28 @@ function promiseGitHubRepoStats(url) {
return Promise.all([promiseStats, promiseContributors, promiseChanges, promiseCommits, promiseReleases]).then(data => _.merge(...data))
}
function promiseGitHubRepoStatsMulti(repos){
return Promise.all(
repos.map(promiseGitHubRepoStats)
)
.then(MergeBySumingNumbers)
function promiseGitHubRepoStatsMulti(repos) {
return Promise.all(repos.map(promiseGitHubRepoStats)).then(MergeBySumingNumbers)
}
function promiseGitHubOrgStats(org){
function promiseGitHubOrgStats(org) {
var apiUrl = org.replace('https://github.com/', '') + '/repos'
return new Promise(function(resolve, reject) {
gh.get(apiUrl, {opts:{per_page:100}}, (err, response) => {
gh.get(apiUrl, {
opts: {
per_page: 100
}
}, (err, response) => {
if (err)
reject(err)
else
resolve(response)
})
})
.then(data => data
// we could filter out minor repos here
.filter(row =>
row.stargazers_count>7 &&
moment(row.updated_at)>moment().subtract(12, 'months') &&
row.private === false &&
row.archived === false
)
.map(row=>row.full_name))
.then(promiseGitHubRepoStatsMulti)
}).then(data => data
// we could filter out minor repos here
.filter(row => row.stargazers_count > 7 && moment(row.updated_at) > moment().subtract(12, 'months') && row.private === false && row.archived === false).map(row => row.full_name)).then(promiseGitHubRepoStatsMulti)
}
function promiseBitbucketRepoStats(url) {
url = url.replace('https://bitbucket.org/', 'https://api.bitbucket.org/2.0/repositories/')
+123 -180
View File
@@ -1,89 +1,32 @@
/**
TODO:
- consider using add/minus as well/instead of commits
- total commits (add contributor contributions)
- sum projects over organisations
- see if it's a fork?
- add use input to enter repos
**/
// format: name from on coinmarketcap: core Github project or repo
function renderUrl(data){return '<a href="'+data+'">'+data+'</a>'}
function renderDate(data){return data?moment(data).format('YYYY/MM/DD'):data}
// ideally I want the input to bea list of github users or repos
// var coins = {
// "Bitcoin": 'https://github.com/bitcoin/bitcoin',
// "Ethereum": 'https://github.com/ethereum/go-ethereum',
// "Ripple": 'https://github.com/ripple/rippled',
// "Litecoin": 'https://github.com/litecoin-project/litecoin',
// "Monero": 'https://github.com/monero-project/monero',
// 'Dash': 'https://github.com/dashpay/dash',
// "Augur": "https://github.com/AugurProject/augur-core",
// "Maidsafe": "https://github.com/maidsafe/safe_client_libs",
// "Steem": "https://github.com/steemit/steem",
// "NEM": "https://github.com/NemProject/nem.core",
// //'Iconomi':'',
// "Factom": 'https://github.com/FactomProject/factomd',
// 'Dogecoin': 'https://github.com/dogecoin/dogecoin',
// 'Waves': 'https://github.com/wavesplatform/Waves',
// 'ZCash': 'https://github.com/zcash/zcash',
// 'DigixDAO': 'https://github.com/DigixGlobal/digixdao-contracts',
// 'Stellar Lumens': 'https://github.com/stellar/stellar-core',
// 'Lisk': 'https://github.com/LiskHQ/lisk',
// 'Tether': 'https://bitbucket.org/tetherto/tether-api-client-ruby',
// // 'E-Dinar Coin': 'https://github.com/edincoin/EDINARCOIN',
// //'ARDOR':'',
// 'GameCredits': 'https://github.com/gamecredits-project/GameCredits',
// 'Swiscoin': 'https://github.com/SCNPay/swiscoin',
// 'Bitshares': 'https://github.com/bitshares/bitshares-2',
// /** Notable below top 25 **/
// "Golem": "https://github.com/golemfactory/golem",
// "PIVX":"https://github.com/PIVX-Project/PIVX",
// "Nxt": 'https://bitbucket.org/JeanLucPicard/nxt', // bitbucket
// "Iota": "https://github.com/iotaledger/iri",
// "IotaOrg": "https://github.com/iotaledger",
// "Vertcoin": 'https://github.com/vertcoin/vertcoin',
// 'Stratis': 'https://github.com/stratisproject/stratisX',
// 'VCash': 'https://github.com/openvcash/vcash',
// "BitcoinUnlimited": "https://github.com/BitcoinUnlimited/BitcoinUnlimited",
// "Bitcoinclassic": "https://github.com/bitcoinclassic/bitcoinclassic",
// "Burstcoin": "https://github.com/BurstProject/burstcoin",
// "Blocknet": "https://github.com/atcsecure/blocknet",
// "Syscoin": "https://github.com/syscoin/syscoin2",
// "Gnosis":"https://github.com/gnosis/gnosis-contracts",
// // "":"https://github.com/voxelus"
// "Qora": "https://github.com/Qoracoin/Qora",
// "Storj": "https://github.com/Storj/core",
// "Sia": "https://github.com/NebulousLabs/Sia",
// "Bitcore": "https://github.com/dgbholdings/bitcore",
//
// 'Tittiecoin': 'https://github.com/tittiecoin/tittiecoin', // example shitcoin
// }
function renderUrl(data) {
return '<a href="' + data + '">' + data + '</a>'
}
function renderDate(data) {
return data
? moment(data).format('YYYY/MM/DD')
: data
}
var columns = [
{
"data": "coin",
"title": "coin"
},
{
}, {
"data": "commits_per_week",
"title": "commits per week (for last year)"
},
{
}, {
"data": "watchers",
"title": "watchers"
},
{
}, {
"data": "open_issues",
"title": "open issues"
},
{
"data": "size",
"title": "size",
"visible": false
},
{
}, {
"data": "size",
"title": "size",
"visible": false
}, {
"data": "created_at",
"title": "created",
render: renderDate
@@ -93,7 +36,7 @@ var columns = [
render: renderDate
}, {
"data": "contributors",
"title": "contributors (up to 100)"
"title": "contributors"
}, {
"data": "forks",
"title": "forks"
@@ -103,79 +46,73 @@ var columns = [
}, {
"data": "language",
"title": "language"
},
{
"data": "description",
"title": "description",
"visible": false
},
{
}, {
"data": "description",
"title": "description",
"visible": false
}, {
"data": "commits",
"title": "commits",
"visible": false
},
{
}, {
"data": "code_frequency",
"title": "code frequency",
"visible": false
},
{
"data": "pushed_at",
"title": "pushed",
"visible": false,
render: renderDate
},
{
}, {
"data": "pushed_at",
"title": "pushed",
"visible": false,
render: renderDate
}, {
"data": "url",
"title": "url",
render: renderUrl
},
// {
// "data": "id",
// "title": "id",
// "visible": false
// },
{
"data": "name",
"title": "name",
"visible": false
},
// {
// "data": "full_name",
// "title": "full_name",
// "visible": false
// },
// {
// "data": "owner",
// "title": "owner",
// "visible": false
// },
// {
// "data": "private",
// "title": "private",
// "visible": false
// },
{
"data": "fork",
"title": "fork",
"visible": false
},
{
"data": "homepage",
"title": "homepage",
"visible": false,
render: renderUrl
},
// {
// "data": "default_branch",
// "title": "default_branch",
// "visible": false
// },
// {
// "data": "permissions",
// "title": "permissions",
// "visible": false
// },
// {
// "data": "id",
// "title": "id",
// "visible": false
// },
{
"data": "name",
"title": "name",
"visible": false
},
// {
// "data": "full_name",
// "title": "full_name",
// "visible": false
// },
// {
// "data": "owner",
// "title": "owner",
// "visible": false
// },
// {
// "data": "private",
// "title": "private",
// "visible": false
// },
{
"data": "fork",
"title": "fork",
"visible": false
}, {
"data": "homepage",
"title": "homepage",
"visible": false,
render: renderUrl
},
// {
// "data": "default_branch",
// "title": "default_branch",
// "visible": false
// },
// {
// "data": "permissions",
// "title": "permissions",
// "visible": false
// },
]
@@ -213,39 +150,31 @@ function makeMarkDownTable(data) {
return table
}
/** fill missing attribtes so datatables stops complaining **/
function fillAll(data, columns){
return data
.filter(_.isObject)
.map(row=>{
function fillAll(data, columns) {
return data.filter(_.isObject).map(row => {
for (var i = 0; i < columns.length; i++) {
var key = columns[i].data
if (row[key]===undefined) row[key] = ''
if (row[key] === undefined)
row[key] = ''
}
return row
})
}
function refresh() {
function refresh(){
var coins = $('#repos').val()
.trim()
.split('\n')
.filter(row=>!row.startsWith('#'))
.map(row=>row.split(',', 2))
.reduce((o,[key,value])=>{
o[key]=value
return o
},{})
var coins = $('#repos').val().trim().split('\n').filter(row => !row.startsWith('#')).map(row => row.split(',', 2)).reduce((o, [key, value]) => {
o[key] = value
return o
}, {})
// Collect data
let promises
let countdown = Object.keys(coins).length
let total = countdown*1
let total = countdown * 1
$("#go").prop('disabled', true);
$("#go").text(''+countdown)
$("#go").text('' + countdown)
if (!localStorage['gh-data'])
promises = Promise.all(Object.keys(coins).map(coin => {
var url = coins[coin]
@@ -254,51 +183,54 @@ function refresh(){
if (url.includes('github.com')) {
if (url.includes(' ')) {
// handle a list of repos
return promiseGitHubRepoStatsMulti(url.split(' '))
.then(data => {
return promiseGitHubRepoStatsMulti(url.split(' ')).then(data => {
data.coin = coin
data.url = url
return data
}).catch(err => {console.error(err, url, coin)})
}
else if (url.includes('https://github.com/orgs') || url.includes('https://github.com/users')){
}).catch(err => {
console.error(err, url, coin)
})
} else if (url.includes('https://github.com/orgs') || url.includes('https://github.com/users')) {
// handle github org or user
return promiseGitHubOrgStats(url).then(data => {
data.coin = coin
data.url = url
return data
}).catch(err => {console.error(err, url, coin)})
}).catch(err => {
console.error(err, url, coin)
})
} else {
return promiseGitHubRepoStats(url).then(data => {
data.coin = coin
data.url = url
return data
}).catch(err => {console.error(err, url, coin)})
}).catch(err => {
console.error(err, url, coin)
})
}
} else {
return promiseBitbucketRepoStats(url).then(data => {
data.coin = coin
data.url = url
return data
}).catch(err => {console.error(err, url, coin)})
}).catch(err => {
console.error(err, url, coin)
})
}
}).map(promise=>promise
.then(value => {
countdown -= 1
$("#go").text(`${countdown}/${total}`)
return value
})
// .catch(err => {console.error(err)})
)
)
.then((data) => {
}).map(promise => promise.then(value => {
countdown -= 1
$("#go").text(`${countdown}/${total}`)
return value
})
.catch(err => {console.error(err)}))).then((data) => {
// cache so I can provide an offline snapshot
localStorage['gh-data2'] = JSON.stringify(data)
return data
})
else promises = Promise.resolve(JSON.parse(localStorage['gh-data']))
else
promises = Promise.resolve(JSON.parse(localStorage['gh-data']))
promises.then(data => {
// data = parseDates(data)
@@ -311,25 +243,36 @@ function refresh(){
[1, "asc"]
],
pageLength: 100,
"lengthMenu": [ 10, 25, 50, 75, 100,800],
"lengthMenu": [
10,
25,
50,
75,
100,
800
],
buttons: ['colvis'],
stateSave: true,
dom: 'Bfrtip',
dom: 'Bfrtip'
})
$('#markdown').val(makeMarkDownTable(data))
$("#go").prop('disabled', false);
$("#go").text("Go")
var markdown = makeMarkDownTable(data)
console.log(markdown)
// $('#markdown').val(markdown)
})
}
$(document).ready(function() {
// DEV purposes only
$('#clear').on('click', function(){
$('#clear').on('click', function() {
localStorage['gh-data'] = ''
window.location.reload()
})
$('#go').on('click', function(){
$('#go').on('click', function() {
refresh()
})
refresh()
})