diff --git a/public/images/builds/canceled.svg b/public/images/builds/canceled.svg
new file mode 100644
index 0000000..3e0de41
--- /dev/null
+++ b/public/images/builds/canceled.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/public/images/builds/errored.svg b/public/images/builds/errored.svg
new file mode 100644
index 0000000..df1b7d0
--- /dev/null
+++ b/public/images/builds/errored.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/public/images/builds/failed.svg b/public/images/builds/failed.svg
new file mode 100644
index 0000000..bba2e8f
--- /dev/null
+++ b/public/images/builds/failed.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/public/images/builds/invalid.svg b/public/images/builds/invalid.svg
new file mode 100644
index 0000000..ce1e483
--- /dev/null
+++ b/public/images/builds/invalid.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/public/images/builds/no_tests.svg b/public/images/builds/no_tests.svg
new file mode 100644
index 0000000..b44858d
--- /dev/null
+++ b/public/images/builds/no_tests.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/public/images/builds/none.svg b/public/images/builds/none.svg
new file mode 100644
index 0000000..5031356
--- /dev/null
+++ b/public/images/builds/none.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/public/images/builds/passed.svg b/public/images/builds/passed.svg
new file mode 100644
index 0000000..5398cb7
--- /dev/null
+++ b/public/images/builds/passed.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/public/images/builds/success.svg b/public/images/builds/success.svg
new file mode 100644
index 0000000..5398cb7
--- /dev/null
+++ b/public/images/builds/success.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/public/images/builds/timedout.svg b/public/images/builds/timedout.svg
new file mode 100644
index 0000000..52df931
--- /dev/null
+++ b/public/images/builds/timedout.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/public/images/builds/unknown.svg b/public/images/builds/unknown.svg
new file mode 100644
index 0000000..c72a2f5
--- /dev/null
+++ b/public/images/builds/unknown.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/public/images/circle-ci-no-builds.svg b/public/images/circle-ci-no-builds.svg
deleted file mode 100644
index 686290c..0000000
--- a/public/images/circle-ci-no-builds.svg
+++ /dev/null
@@ -1,4 +0,0 @@
-
diff --git a/public/styles/app.css b/public/styles/app.css
index 98758c5..8171d02 100644
--- a/public/styles/app.css
+++ b/public/styles/app.css
@@ -21,3 +21,7 @@ td, th {
td.left, th.left {
text-align: left;
}
+
+.hide {
+ display: none;
+}
diff --git a/src/RepoMatrix.coffee b/src/RepoMatrix.coffee
index 1517262..9340a66 100644
--- a/src/RepoMatrix.coffee
+++ b/src/RepoMatrix.coffee
@@ -1,8 +1,8 @@
Promise = require 'bluebird'
Octokat = require 'octokat'
request = require 'request-promise'
-{log} = require 'lightsaber'
-{flatten, merge, round, sample, size, sortBy} = require 'lodash'
+{log, pjson} = require 'lightsaber'
+{get, flatten, keys, merge, round, sample, size, sortBy} = require 'lodash'
Wave = require 'loading-wave'
$ = require 'jquery'
require('datatables.net')()
@@ -69,6 +69,31 @@ class RepoMatrix
CONTRIBUTE = 'CONTRIBUTE.md'
]
+ CI =
+ travis:
+ addProject: (repoFullName) -> "https://travis-ci.org/#{repoFullName}"
+ urlTemplate: (repoFullName) -> "https://travis-ci.org/#{repoFullName}"
+ apiTemplate: (repoFullName) -> "https://api.travis-ci.org/repos/#{repoFullName}/branches/master"
+ apiStatePath: "branch.state"
+ circle:
+ addProject: -> "https://circleci.com/add-projects"
+ urlTemplate: (repoFullName) -> "https://circleci.com/gh/#{repoFullName}"
+ apiTemplate: (repoFullName) -> "https://circleci.com/api/v1.1/project/github/#{repoFullName}/tree/master"
+ apiStatePath: "[0].outcome"
+
+ # roughly in order of best -> worst states
+ BUILD_STATES =
+ passed: 10
+ success: 10
+ canceled: 20
+ unknown: 25
+ none: 30
+ no_tests: 35
+ invalid: 40
+ timedout: 45
+ errored: 50
+ failed: 60
+
github = new Octokat
@start: ->
@@ -121,10 +146,14 @@ class RepoMatrix
@showMatrix: (repos) ->
$('#matrix').append @matrix repos
- $('table').DataTable
- paging: false
- searching: false
- fixedHeader: true
+ @loadCiBadges(repos)
+ .catch (error) =>
+ console.error error
+ .then =>
+ $('table').DataTable
+ paging: false
+ searching: false
+ fixedHeader: true
@getFiles: (repos) ->
repos = sortBy repos, 'fullName'
@@ -168,8 +197,8 @@ class RepoMatrix
for repo in repos
tr =>
td class: 'left', => a href: "https://github.com/#{repo.fullName}", => repo.fullName # Name
- td class: 'left', => @travis repo.fullName # Builds
- td class: 'left', => @circle repo.fullName # Builds
+ td class: 'left', id: "#{@slug(repo.fullName)}-travis" # Builds
+ td class: 'left', id: "#{@slug(repo.fullName)}-circle" # Builds
td class: 'no-padding', => @check repo.files[README] # README.md
td class: 'no-padding', => @check(repo.files[README]?.length > 500) # README.md
td class: 'no-padding', => @check repo.files[LICENSE] # Files
@@ -184,20 +213,47 @@ class RepoMatrix
td => repo.stargazersCount.toString()
td => repo.openIssuesCount.toString()
+ @loadCiBadges: (repos) =>
+ promises = for ciBrand, ciData of CI
+ do (ciBrand, ciData) =>
+ {addProject, apiTemplate, apiStatePath, urlTemplate} = ciData
+ Promise.map repos, (repo) =>
+ new Promise (resolve) =>
+ apiUrl = apiTemplate(repo.fullName)
+ $.getJSON apiUrl
+ .fail (err) =>
+ if err.status is 404
+ @addCiBadge repo.fullName, ciBrand, 'none', addProject
+ else
+ console.error err
+ resolve()
+ .done (data) =>
+ state = get(data, apiStatePath)
+ if state in keys(BUILD_STATES)
+ @addCiBadge repo.fullName, ciBrand, state, urlTemplate
+ else
+ @addCiBadge repo.fullName, ciBrand, 'unknown', urlTemplate
+ console.error "Unknown build state `#{state}` -- please add to
+ BUILD_STATES and add a badge to images/builds/#{state}.svg"
+ # " -- selector: #{apiStatePath} -- full data:\n#{pjson data}"
+ resolve()
+ Promise.all promises
+
+ @addCiBadge: (repoFullName, ciBrand, state, urlTemplate) =>
+ tableCell = $("##{@slug(repoFullName)}-#{ciBrand}")
+ stateHtml = render -> span class: 'hide', -> BUILD_STATES[state].toString()
+ badgeHtml = render ->
+ a href: urlTemplate(repoFullName), _target: '_repos', ->
+ img src: "images/builds/#{state}.svg"
+ tableCell.append(stateHtml)
+ tableCell.append(badgeHtml)
+
@check: renderable (success) ->
if success
div class: 'success', -> '✓'
else
div class: 'failure', -> '✗'
- @travis: renderable (repoFullName) ->
- a href: "https://travis-ci.org/#{repoFullName}", ->
- img src: "https://travis-ci.org/#{repoFullName}.svg?branch=master"
-
- @circle: renderable (repoFullName) ->
- a href: "https://circleci.com/gh/#{repoFullName}", ->
- img src: "https://circleci.com/gh/#{repoFullName}.svg?style=svg", onError: "this.parentElement.href = 'https://circleci.com/add-projects'; this.src = 'images/circle-ci-no-builds.svg'"
-
@loadStats: ->
github.rateLimit.fetch()
.then (info) => $('#stats').append @stats info
@@ -209,4 +265,7 @@ class RepoMatrix
minutesUntilReset = (reset - now) / 60 # minutes
"Github API calls: #{remaining} remaining of #{limit} limit per hour; clean slate in: #{round minutesUntilReset, 1} minutes"
+ @slug: (string) ->
+ string.replace(/\W+/, '-')
+
module.exports = RepoMatrix