From 9b1c6d0fa0567829f9136b65d59a33d3aac03fb9 Mon Sep 17 00:00:00 2001 From: Rod Vagg Date: Sat, 11 Apr 2015 22:27:13 +1000 Subject: [PATCH] added initial nightly-builder app --- tools/nightly-builder/.gitignore | 1 + tools/nightly-builder/build-required.js | 49 ++++++++++++++++++++++ tools/nightly-builder/latest-build.js | 36 ++++++++++++++++ tools/nightly-builder/latest-commit.js | 27 ++++++++++++ tools/nightly-builder/nightly-builder.js | 30 ++++++++++++++ tools/nightly-builder/package.json | 23 ++++++++++ tools/nightly-builder/test.js | 47 +++++++++++++++++++++ tools/nightly-builder/trigger-build.js | 53 ++++++++++++++++++++++++ 8 files changed, 266 insertions(+) create mode 100644 tools/nightly-builder/.gitignore create mode 100644 tools/nightly-builder/build-required.js create mode 100644 tools/nightly-builder/latest-build.js create mode 100644 tools/nightly-builder/latest-commit.js create mode 100644 tools/nightly-builder/nightly-builder.js create mode 100644 tools/nightly-builder/package.json create mode 100644 tools/nightly-builder/test.js create mode 100644 tools/nightly-builder/trigger-build.js diff --git a/tools/nightly-builder/.gitignore b/tools/nightly-builder/.gitignore new file mode 100644 index 000000000..3c3629e64 --- /dev/null +++ b/tools/nightly-builder/.gitignore @@ -0,0 +1 @@ +node_modules diff --git a/tools/nightly-builder/build-required.js b/tools/nightly-builder/build-required.js new file mode 100644 index 000000000..1096a9d93 --- /dev/null +++ b/tools/nightly-builder/build-required.js @@ -0,0 +1,49 @@ +"use strict" + +const strftime = require('strftime').timezone(0) + , after = require('after') + , latestBuild = require('./latest-build') + , latestCommit = require('./latest-commit') + +const dateFormat = '%Y%m%d' + + +function timeString () { + return strftime(dateFormat) +} + + +function buildRequired (type, callback) { + let done = after(2, onData) + , build + , commit + + function onData (err) { + if (err) + return callback(err) + + let buildCommit = build.commit.substr(0, 10) + , buildDate = strftime(dateFormat, build.date) + , nowDate = timeString() + + commit = commit.substr(0, 10) + + if (buildCommit != commit) // only need to compare commit + return callback(null, { type: type, commit: commit, date: nowDate }) + + return callback() + } + + latestBuild(type, function (err, data) { + build = data + done(err) + }) + + latestCommit(type, function (err, data) { + commit = data + done(err) + }) +} + + +module.exports = buildRequired \ No newline at end of file diff --git a/tools/nightly-builder/latest-build.js b/tools/nightly-builder/latest-build.js new file mode 100644 index 000000000..c7c5c9a4d --- /dev/null +++ b/tools/nightly-builder/latest-build.js @@ -0,0 +1,36 @@ +"use strict" + +const jsonist = require('jsonist') + +const indexUrl = 'https://iojs.org/download/{type}/index.json' + + +function latestBuild (type, callback) { + let url = indexUrl.replace(/\{type\}/, type) + + function onGet (err, data) { + if (err) + return callback(err) + + let i = -1 + + while (data[++i]) { + let m = data[i].version.match(/nightly(20\d\d)(\d\d)(\d\d)(\w{10,})/) + , date = new Date(m && `${m[1]}-${m[2]}-${m[3]}` || data[i].date) + , commit = m && m[4] + + return callback(null, { + version : data[i].version + , date : date + , commit : commit + }) + } + + return callback(new Error(`no latest version for "${type}"`)) + } + + jsonist.get(url, onGet) +} + + +module.exports = latestBuild \ No newline at end of file diff --git a/tools/nightly-builder/latest-commit.js b/tools/nightly-builder/latest-commit.js new file mode 100644 index 000000000..fe7c44266 --- /dev/null +++ b/tools/nightly-builder/latest-commit.js @@ -0,0 +1,27 @@ +"use strict" + +const ghrepos = require('ghrepos') + +const nightlyRef = 'heads/v1.x' + , nightlyNextRef = 'heads/next' + + +function latestCommit (type, callback) { + let ref = type == 'nightly' ? nightlyRef : type == 'next-nightly' ? nightlyNextRef : null + + if (!ref) + throw new Error(`Unknown type "${type}"`) + + ghrepos.getRef(null, 'iojs', 'io.js', ref, function (err, data) { + if (err) + return callback(err) + + if (!data || !data.object) + return callback(new Error(`Got unexpected data from GitHub: ${JSON.stringify(data)}`)) + + return callback(null, data.object.sha) + }) +} + + +module.exports = latestCommit \ No newline at end of file diff --git a/tools/nightly-builder/nightly-builder.js b/tools/nightly-builder/nightly-builder.js new file mode 100644 index 000000000..90af6569e --- /dev/null +++ b/tools/nightly-builder/nightly-builder.js @@ -0,0 +1,30 @@ +"use strict" + +const argv = require('minimist')(process.argv.slice(2)) + , inspect = require('util').inspect + , buildRequired = require('./build-required') + , triggerBuild = require('./trigger-build') + + +if (typeof argv.type != 'string' + || !/^(nightly|next-nightly)$/.test(argv.type) + || typeof argv.token != 'string') { + + console.error('Usage: nightly-builder --type --token ') + return process.exit(1) +} + +buildRequired(argv.type, function (err, data) { + if (err) + throw err + + if (!data) + return console.log('No build required') + + triggerBuild(argv.token, data, function (err) { + if (err) + throw err + + console.log(`Build triggered: ${inspect(data)}`) + }) +}) \ No newline at end of file diff --git a/tools/nightly-builder/package.json b/tools/nightly-builder/package.json new file mode 100644 index 000000000..43e98352a --- /dev/null +++ b/tools/nightly-builder/package.json @@ -0,0 +1,23 @@ +{ + "name": "nightly-builder", + "version": "1.0.0", + "description": "nightly builder for io.js dist", + "main": "nightly-builder.js", + "author": "Rod Vagg ", + "license": "MIT", + "scripts": { + "test": "node ./test.js" + }, + "dependencies": { + "after": "~0.8.1", + "bl": "~0.9.4", + "ghrepos": "~1.0.2", + "hyperquest": "~1.0.1", + "jsonist": "~1.0.0", + "minimist": "~1.1.1", + "strftime": "~0.9.0" + }, + "devDependencies": { + "tape": "~4.0.0" + } +} diff --git a/tools/nightly-builder/test.js b/tools/nightly-builder/test.js new file mode 100644 index 000000000..a782619f7 --- /dev/null +++ b/tools/nightly-builder/test.js @@ -0,0 +1,47 @@ +"use strict" + +const test = require('tape') + , latestCommit = require('./latest-commit') + , latestBuild = require('./latest-build') + + +test('latest-build', function (t) { + t.plan(14) + var other = null + + function verify (type) { + return function (err, data) { + t.error(err, 'no error') + t.ok(data, 'got data') + let m = data.version && data.version.match(/v\d+\.\d+\.\d+-((?:next-)?nightly)20\d{6}\w{10,}/) + t.ok(m, `version (${data.version}) looks correct`) + t.equal(m && m[1], type, 'correct type') + t.ok(data.date < new Date(), `date (${data.date.toISOString()}) looks correct`) + t.ok(data.commit && data.commit.length >= 10, `commit (${data.commit}) looks right`) + t.notEqual(data.commit, other, 'commit not the same as other type of commit') + other = data.commit // who's gonna be first?? + } + } + + latestBuild('nightly', verify('nightly')) + latestBuild('next-nightly', verify('next-nightly')) +}) + + +test('latest-commit', function (t) { + t.plan(8) + var other = null + + function verify (type) { + return function (err, sha) { + t.error(err, 'no error') + t.equal(typeof sha, 'string', 'got sha') + t.equal(sha.length, 40, `sha looks good (${sha})`) + t.notEqual(sha, other, 'sha not the same as other type of sha') + other = sha // who's gonna be first?? + } + } + + latestCommit('nightly', verify('nightly')) + latestCommit('next-nightly', verify('next-nightly')) +}) diff --git a/tools/nightly-builder/trigger-build.js b/tools/nightly-builder/trigger-build.js new file mode 100644 index 000000000..23d628e40 --- /dev/null +++ b/tools/nightly-builder/trigger-build.js @@ -0,0 +1,53 @@ +"use strict"; + +const hyperquest = require('hyperquest') + , bl = require('bl') + , qs = require('querystring') + + +const urlbase = 'https://jenkins-iojs.nodesource.com/job/iojs+release+nightly/build?token=' + , buildUser = 'iojs' + , buildProject = 'io.js' + + +function triggerBuild(token, options, callback) { + let url = `${urlbase}${token}` + , data = { + parameter : [ + { + name : 'user' + , value : buildUser + } + , { + name : 'project' + , value : buildProject + } + , { + name : 'commit' + , value : options.commit + } + , { + name : 'datestring' + , value : options.date + } + , { + name : 'buildtype' + , value : options.type + } + ] + } + , post = qs.encode({ + token : token + , json : JSON.stringify(data) + }) + + let req = hyperquest(url, { + method: 'post' + , headers: { 'content-type': 'application/x-www-form-urlencoded' } + }) + req.end(post) + req.pipe(bl(callback)) +} + + +module.exports = triggerBuild \ No newline at end of file