Build server prototype (integration with GitHub / NuGet / etc)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
micro-build-server/BuildServer/lib/report-processor.ts

165 lines
5.4 KiB

"use strict";
import { join } from "path";
import { createReadStream, createWriteStream, exists } from "fs";
import { createGzip, createGunzip } from "zlib";
import * as glob from "glob";
import { ReadableStreamBuffer, WritableStreamBuffer } from "stream-buffers";
import * as _ from "underscore";
import * as JSONParse from "json-parse-safe";
const reportFilename = "report.json.gz";
const maxAttemptsNumber = 100;
const attemptsTimeout = 30000;
const reportReadTimeout = 5000;
const directoryCheckTimeout = 2000;
const attemptsDebugFrequency = 10;
const readableStreamBufferOptions = {
"chunkSize": 262144,
"frequency": 1
};
const getAllErrors = (report) => ((report.result || {}).errors || {}).$allMessages || [];
const getAllWarns = (report) => ((report.result || {}).warns || {}).$allMessages || [];
const getAllInfos = (report) => ((report.result || {}).infos || {}).$allMessages || [];
export const writeReport = (releaseDir, err, result, callback) => {
const data = JSON.stringify({
"date": Date.now(),
err,
result
});
const readable = new ReadableStreamBuffer(readableStreamBufferOptions);
const writeStream = createWriteStream(join(releaseDir, reportFilename));
readable
.on("error", callback)
.pipe(createGzip())
.on("error", callback)
.pipe(writeStream)
.on("error", callback)
.on("finish", () => {
writeStream.end();
callback();
});
readable.put(data);
readable.stop();
};
export const readReport = (releaseDir, callback) => {
const readStream = createReadStream(join(releaseDir, reportFilename));
const writable = new WritableStreamBuffer();
readStream
.on("error", callback)
.pipe(createGunzip())
.on("error", callback)
.pipe(writable)
.on("error", callback)
.on("finish", () => {
readStream.destroy();
const data = writable.getContentsAsString();
if (!data) {
return callback("ReportFileNotFound");
}
const { error, value } = JSONParse(data);
if (error) {
return callback("ReportFileMalformed");
}
return callback(null, value);
});
};
export const loadReport = (app, options, callback) => {
const releaseDir = join(app.get("releasepath"), options.owner, options.reponame, options.branch, options.rev);
glob("**", {
"cwd": releaseDir,
"mark": true
}, (err, files) => {
if (err) {
return callback(err, options);
}
const reportFile = join(releaseDir, reportFilename);
return exists(reportFile, (reportFileExists) => {
if (!reportFileExists) {
return callback("ReportFileNotFound", options);
}
return readReport(releaseDir, (readErr, report) => {
if (readErr) {
return callback(readErr, _.extend(options, { files }));
}
return callback(null, _.extend(options, {
files,
report
}));
});
});
});
};
export const getStatusMessageFromRelease = (app, originalOptions, callback) => {
const options = _.extend(originalOptions, { "attemptsGetReport": (Number(originalOptions.attemptsGetReport) || Number()) + 1 });
const releaseDir = join(app.get("releasepath"), options.owner, options.reponame, options.branch, options.rev);
const reportFile = join(releaseDir, reportFilename);
exists(reportFile, (reportFileExists) => {
if (!reportFileExists) {
return setTimeout(() => exists(releaseDir, (dirExists) => {
if (!dirExists) {
return callback("Release directory not found. Probably repository hooks are not configured");
}
if (options.attemptsGetReport > maxAttemptsNumber) {
return callback("Report file not found");
}
// Maybe it is building right now
if (!(options.attemptsGetReport % attemptsDebugFrequency) && options.onTenthAttempt) {
options.onTenthAttempt();
}
return setTimeout(() => exports.getStatusMessageFromRelease(app, options, callback), attemptsTimeout);
}), directoryCheckTimeout);
}
return setTimeout(() => readReport(releaseDir, (readErr, report) => {
if (readErr) {
return callback(readErr);
}
if (report.result === "MBSNotFound") {
return callback("mbs.json is not found");
}
const errors = getAllErrors(report);
const warns = getAllWarns(report);
const infos = getAllInfos(report);
if (errors.length + warns.length) {
return callback(_.map(
errors, (message) => `ERR: ${message.message}`
).concat(_.map(
warns, (message) => `WARN: ${message.message}`
))
.join("\r\n"));
}
if (!report.result || report.err) {
return callback(`CRITICAL ERROR: ${report.err}`);
}
return callback(null, (infos[infos.length - 1] || { "message": "OK" }).message);
}), reportReadTimeout);
});
};