Last active
December 17, 2015 12:48
-
-
Save barlog-m/f0a182ffbd9e1a22735d to your computer and use it in GitHub Desktop.
TeamCity node.js script for start build branch
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
"name": "teamcity-build-starter", | |
"version": "0.0.1", | |
"private": true, | |
"dependencies": { | |
"node-fetch": "latest" | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
'use strict'; | |
const | |
util = require('util'), | |
https = require('https'), | |
fs = require('fs'), | |
path = require('path'), | |
fetch = require('node-fetch'); | |
const | |
TIMEOUT = 3000, | |
RETRY_INTERVAL = 12000, | |
RETRIES = 9; | |
const | |
SERVER = 'tc.local', | |
USER = 'user', | |
PASSWORD = 'password', | |
ARCHIVE = 'app.zip', | |
TC_URL = util.format('https://%s', SERVER), | |
BUILDCONFIG_ID = 'FooMaven_Dist'; | |
var retryCounter = RETRIES; | |
if (require.main === module) { | |
registerHooks(); | |
var params = process.argv; | |
if (params.length <= 2) { | |
help(); | |
process.exit(-1); | |
} | |
const branch = params[2]; | |
console.info('Request to build branch [%s] with build config [%s] on server: [%s]', | |
branch, BUILDCONFIG_ID, TC_URL); | |
startBuild(branch, BUILDCONFIG_ID) | |
.then(checkBuildStatus) | |
.then(getArhiveUrl) | |
.then(downloadFile) | |
.then(done) | |
.catch(catchError); | |
} | |
function startBuild(branch, buildConfig) { | |
return new Promise(function (resolve, reject) { | |
fetch(TC_URL + '/teamcity' + '/httpAuth/app/rest/buildQueue', { | |
method: 'POST', | |
headers: { | |
'Accept': 'application/json', | |
'Content-Type': 'application/json', | |
'Authorization': 'Basic ' + new Buffer(USER + ':' + PASSWORD).toString('base64') | |
}, | |
timeout: TIMEOUT, | |
body: JSON.stringify(getBody(branch, buildConfig)) | |
}) | |
.then(processStatus) | |
.then(body2json) | |
.then(function (body) { | |
//console.log(body); | |
console.info('build task id: %d', body.id); | |
resolve(body.id); | |
}) | |
.catch(reject); | |
}); | |
} | |
function checkBuildStatus(id) { | |
const taskUrl = util.format('/teamcity' + '/httpAuth/app/rest/buildQueue/id:%d', id); | |
return new Promise(function (resolve, reject) { | |
console.log('check status of task: %s', id); | |
function retry(resolve) { | |
if (retryCounter <= 0) { | |
reject(new Error('Retries attempt exhausted')); | |
} | |
setTimeout(function () { | |
retryCounter--; | |
resolve(checkBuildStatus(id)); | |
}, RETRY_INTERVAL); | |
} | |
fetch(TC_URL + taskUrl, { | |
headers: { | |
'Accept': 'application/json', | |
'Content-Type': 'application/json', | |
'Authorization': 'Basic ' + new Buffer(USER + ':' + PASSWORD).toString('base64') | |
}, | |
timeout: TIMEOUT | |
}) | |
.then(processStatus) | |
.then(body2json) | |
.then(function (body) { | |
//console.log(body); | |
console.info('state: %s', body.state); | |
if (body.state !== 'finished') { | |
retry(resolve); | |
} | |
else if (body.status && (body.status === 'SUCCESS')) { | |
console.info('status: %s', body.status); | |
resolve(id); | |
} | |
else { | |
retry(resolve); | |
} | |
}) | |
.catch(reject); | |
}); | |
} | |
function getArhiveUrl(id) { | |
const artifactsUrl = util.format('/teamcity' + '/httpAuth/app/rest/builds/id:%d/artifacts/children/', id); | |
return new Promise(function (resolve, reject) { | |
fetch(TC_URL + artifactsUrl, { | |
headers: { | |
'Accept': 'application/json', | |
'Content-Type': 'application/json', | |
'Authorization': 'Basic ' + new Buffer(USER + ':' + PASSWORD).toString('base64') | |
}, | |
timeout: TIMEOUT | |
}) | |
.then(processStatus) | |
.then(body2json) | |
.then(function (body) { | |
if (body.file[0]) { | |
resolve('/teamcity' + body.file[0].content.href); | |
} else { | |
reject(new Error('response parse error for url: ' + TC_URL + artifactsUrl)); | |
} | |
}) | |
.catch(reject); | |
}); | |
} | |
function downloadFile(url) { | |
console.log('download: %s', TC_URL + url); | |
return new Promise(function (resolve, reject) { | |
var options = { | |
host: SERVER, | |
path: url, | |
headers: { | |
'Authorization': 'Basic ' + new Buffer(USER + ':' + PASSWORD).toString('base64') | |
}, | |
timeout: TIMEOUT | |
}; | |
var file = fs.createWriteStream(ARCHIVE); | |
https.get(options, function (response) { | |
response.pipe(file); | |
file | |
.on('finish', function () { | |
file.close(resolve); | |
}) | |
.on('error', reject); | |
}) | |
.on('error', function (err) { | |
fs.unlink(ARCHIVE); | |
reject(err); | |
}); | |
}); | |
} | |
function done() { | |
return Promise.resolve(console.info('done')); | |
} | |
function processStatus(response) { | |
if (response.status === 200) { | |
return Promise.resolve(response); | |
} else { | |
return Promise.reject(new Error('code: ' + response.status + ' message: ' + response.statusText)); | |
} | |
} | |
function body2json(response) { | |
return Promise.resolve(response.json()); | |
} | |
function getBody(branchName, buildConfigurationId) { | |
return { | |
branchName: branchName, | |
build: {}, | |
buildType: { | |
id: buildConfigurationId | |
} | |
}; | |
} | |
function catchError(err) { | |
console.error(err); | |
process.exit(-1); | |
} | |
function help() { | |
console.info('TeamCity build run script'); | |
console.info('Usage: node ./tc-build.js branch'); | |
} | |
function registerHooks() { | |
process.on('unhandledRejection', function (reason, obj) { | |
console.error('Unhandled Rejection at: [%s] reason: %s', obj, reason); | |
}); | |
process.on('uncaughtException', function (reason, obj) { | |
console.error('Unhandled Exception at: [%s] reason: %s', obj, reason); | |
}); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment