├── .gitignore
├── .travis.yml
├── Readme.md
├── buildkite.png
├── cli.js
├── graph.js
├── index.css
├── index.html
├── index.js
├── package.json
└── web.js
/.gitignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 | npm-debug.log*
5 |
6 | # Runtime data
7 | pids
8 | *.pid
9 | *.seed
10 |
11 | # Directory for instrumented libs generated by jscoverage/JSCover
12 | lib-cov
13 |
14 | # Coverage directory used by tools like istanbul
15 | coverage
16 |
17 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
18 | .grunt
19 |
20 | # node-waf configuration
21 | .lock-wscript
22 |
23 | # Compiled binary addons (http://nodejs.org/api/addons.html)
24 | build/Release
25 |
26 | # Dependency directory
27 | node_modules
28 |
29 | # Optional npm cache directory
30 | .npm
31 |
32 | # Optional REPL history
33 | .node_repl_history
34 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: node_js
2 | node_js:
3 | - '4'
4 | - '5'
5 |
--------------------------------------------------------------------------------
/Readme.md:
--------------------------------------------------------------------------------
1 | bkboard
2 | =======
3 |
4 | [![NPM version][npm-image]][npm-url]
5 | [![build status][travis-image]][travis-url]
6 | [![Downloads][downloads-image]][downloads-url]
7 | [![js-standard-style][standard-image]][standard-url]
8 |
9 | A Buildkite build report dashboard in terminal and web, or anywhere.
10 |
11 |
12 |
13 | ### Installation
14 |
15 | ```sh
16 | $ npm install bkboard --save
17 | ```
18 |
19 | ### Usage in browser
20 |
21 | ```JavaScript
22 | var bkboard = require('bkboard')
23 |
24 | /**
25 | * Get the builds data from a pipeline
26 | * @param {String} The token string
27 | * @param {Object} The opts object contains 'from', 'to', 'org', 'pipeline'
28 | * @param {Function} Callback function with `err, builds`
29 | */
30 | bkboard(token, opts, function (err, builds) {
31 | if (err) {
32 | console.log('err', err)
33 | return
34 | }
35 |
36 | drawBoard(builds)
37 | })
38 | ```
39 |
40 | Example `opts` object:
41 |
42 | ```JavaScript
43 | {
44 | from: '2016-03-13T00:00:00Z',
45 | to: '2016-03-18T00:00:00Z',
46 | org: 'xxx',
47 | pipeline: 'xxx'
48 | }
49 | ```
50 |
51 | ### Usage from terminal
52 |
53 | ```sh
54 | $ npm install bkboard -g
55 | ```
56 |
57 | You can get Buildkite api_token from https://buildkite.com/user/api-access-tokens and set it with `git config` or pass it to `process.env.BUILDKITE_API_KEY`.
58 |
59 | **Note:** Please make sure you have the `Read Builds (read_builds)` permission enable to be able to read builds from Buildkite API.
60 |
61 | > Permission to list and retrieve details of builds
62 |
63 | ### Exampe
64 |
65 | ```sh
66 | $ bkboard --from='2016-03-13T00:00:00Z' --to='2016-03-16T00:00:00Z' --org='$ORG' --pipeline='$PIPELINE'
67 | ```
68 |
69 | ### License
70 |
71 | MIT
72 |
73 | [npm-image]: https://img.shields.io/npm/v/bkboard.svg?style=flat-square
74 | [npm-url]: https://npmjs.org/package/bkboard
75 | [travis-image]: https://img.shields.io/travis/fraserxu/bkboard/master.svg?style=flat-square
76 | [travis-url]: https://travis-ci.org/fraserxu/bkboard
77 | [downloads-image]: http://img.shields.io/npm/dm/bkboard.svg?style=flat-square
78 | [downloads-url]: https://npmjs.org/package/bkboard
79 | [standard-image]: https://img.shields.io/badge/code%20style-standard-brightgreen.svg?style=flat-square
80 | [standard-url]: https://github.com/feross/standard
81 |
--------------------------------------------------------------------------------
/buildkite.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fraserxu/bkboard/40625055aad5518460bc7aa8916c0ea85b36560e/buildkite.png
--------------------------------------------------------------------------------
/cli.js:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env node
2 |
3 | var _ = require('lodash')
4 | var ora = require('ora')
5 | var argv = require('minimist')(process.argv.slice(2))
6 | var gitConfig = require('git-config')
7 |
8 | var drawBoard = require('./graph.js')
9 | var getBuilds = require('./index.js')
10 |
11 | var COLORS = {
12 | passed: 'green',
13 | failed: 'red'
14 | }
15 |
16 | var config = gitConfig.sync()
17 | var BUILDKITE_API_KEY = config.buildkite.apikey || process.env.BUILDKITE_API_KEY
18 | var spinner = ora('Loading builds from Buildkite...')
19 |
20 | if (!BUILDKITE_API_KEY) {
21 | throw new Error('BUILDKITE_API_KEY not found.')
22 | }
23 |
24 | // list builds for a pipeline
25 | var from = argv._[0] || argv.f || argv.from || '2016-03-13T00:00:00Z'
26 | var to = argv._[1] || argv.t || argv.to || '2016-03-16T00:00:00Z'
27 | var org = argv._[2] || argv.o || argv.org
28 | var pipeline = argv._[3] || argv.p || argv.pipeline
29 |
30 | function groupBuildsByState (builds) {
31 | var buildsByState = _.groupBy(builds, function (build) {
32 | return build.state
33 | })
34 |
35 | var total = builds.length
36 | var data = Object.keys(buildsByState).map(function (state) {
37 | return {
38 | percent: ((buildsByState[state].length / total) * 100).toFixed(0),
39 | label: state,
40 | color: COLORS[state] || 'cyan'
41 | }
42 | })
43 |
44 | return data
45 | }
46 |
47 | function groupBuildsByCreator (builds) {
48 | var buildsByCreator = _.groupBy(builds, function (build) {
49 | if (build.creator && build.creator.name) {
50 | return build.creator.name
51 | } else {
52 | return 'Unknown'
53 | }
54 | })
55 |
56 | var titles = Object.keys(buildsByCreator).map(function (name) {
57 | return name.split(' ')[0]
58 | })
59 | var data = Object.keys(buildsByCreator).map(function (key) {
60 | return buildsByCreator[key].length
61 | })
62 | return {
63 | titles: titles,
64 | data: data
65 | }
66 | }
67 |
68 | getBuilds(BUILDKITE_API_KEY, {
69 | org: org,
70 | pipeline: pipeline,
71 | from: from,
72 | to: to
73 | }, function (err, builds) {
74 | if (err) {
75 | console.log('err', err)
76 | spinner.stop()
77 | process.exit(1)
78 | }
79 |
80 | builds = builds.map(function (build) {
81 | return {
82 | state: build.state,
83 | creator: build.creator
84 | }
85 | })
86 |
87 | var buildsByState = groupBuildsByState(builds)
88 | var buildsByCreator = groupBuildsByCreator(builds)
89 |
90 | drawBoard(buildsByCreator, buildsByState)
91 | })
92 |
93 | spinner.start()
94 |
--------------------------------------------------------------------------------
/graph.js:
--------------------------------------------------------------------------------
1 | var blessed = require('blessed')
2 | var contrib = require('blessed-contrib')
3 |
4 | module.exports = function drawBoard (barData, donutData) {
5 | var screen = blessed.screen()
6 | var Grid = contrib.grid
7 | var grid = new Grid({
8 | rows: 2,
9 | cols: 1,
10 | screen: screen
11 | })
12 |
13 | var bar = grid.set(0, 0, 1, 1, contrib.bar, {
14 | label: 'Buildkite Weekly builds by creator chart',
15 | barWidth: 5,
16 | barSpacing: 1,
17 | xOffset: 0,
18 | maxHeight: 5
19 | })
20 | var donut = grid.set(1, 0, 1, 1, contrib.donut, {
21 | label: 'Buildkite Weekly builds by state chart',
22 | radius: 8,
23 | arcWidth: 3,
24 | remainColor: 'black',
25 | yPadding: 2
26 | })
27 |
28 | bar.setData(barData)
29 | donut.setData(donutData)
30 |
31 | screen.key(['escape', 'q', 'C-c'], function (ch, key) {
32 | return process.exit(0)
33 | })
34 |
35 | screen.render()
36 | }
37 |
--------------------------------------------------------------------------------
/index.css:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fraserxu/bkboard/40625055aad5518460bc7aa8916c0ea85b36560e/index.css
--------------------------------------------------------------------------------
/index.html:
--------------------------------------------------------------------------------
1 |
2 |