Skip to content

Instantly share code, notes, and snippets.

@barlog-m
Last active December 17, 2015 12:48
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save barlog-m/f0a182ffbd9e1a22735d to your computer and use it in GitHub Desktop.
Save barlog-m/f0a182ffbd9e1a22735d to your computer and use it in GitHub Desktop.
TeamCity node.js script for start build branch
{
"name": "teamcity-build-starter",
"version": "0.0.1",
"private": true,
"dependencies": {
"node-fetch": "latest"
}
}
'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