apps/strider/lib/routes/jobs/index.js
/*
* routes/jobs/index.js
*/
const _ = require('lodash');
const common = require('../../common');
const config = require('../../config');
const debug = require('debug')('strider:routes:jobs');
const ljobs = require('../../jobs');
const models = require('../../models');
const pjson = require('../../../package.json');
const filter = require('../../utils/ansi');
const utils = require('../../utils');
const Job = models.Job;
module.exports = {
html: html,
multijob: multijob,
jobs: jobs,
};
/*
* GET /org/repo/[job/:job_id] - view latest build for repo
*
* middleware.project set "project" and "accessLevel" on the req object.
*/
function multijob(req, res) {
const type = req.accepts('html', 'json', 'plain');
switch (type) {
case 'json':
return data(req, res);
case 'plain':
return output(req, res);
default:
return html(req, res);
}
}
function filterJob(job) {
if (job.trigger.message === 'Retest') {
job.trigger.message = 'Manually Retested';
}
if (job.trigger.message === 'Redeploy') {
job.trigger.message = 'Manually Redeployed';
}
return job;
}
function findJob(job) {
// job.runner can be undefined if it hasn't been fully prepared yet.
// this is a sort of race between job.prepare and job.new events.
// fixes https://github.com/Strider-CD/strider/issues/273
if (!job.runner) return;
const runner = common.extensions.runner[job.runner.id];
if (runner) return runner.getJobData(job._id) || {};
}
function html(req, res, next) {
if (req.params.org === 'auth') {
return next();
}
const id = req.params.id;
const projectName = req.project.name;
const jobsQuantity = req.user
? req.user.jobsQuantityOnPage
: config.jobsQuantityOnPage.default;
Job.find({ project: projectName, archived: null })
.sort({ finished: -1 })
.limit(jobsQuantity)
.lean()
.exec(function (err, jobs) {
if (err) {
debug('[job] error finding jobs', err.message);
return res.status(500).send('Failed to find jobs');
}
// Use our custom sort function
jobs.sort(ljobs.sort);
Job.find({
project: projectName,
archived: null,
finished: null,
})
.sort({ started: -1 })
.lean()
.exec(function (err, running) {
if (err) {
debug('[job] error finding running jobs', err.message);
return res.status(500).send('Failed to find running jobs');
}
let i;
for (i = 0; i < running.length; i++) {
_.extend(running[i], findJob(running[i]));
delete running[i].data;
delete running[i].id;
}
jobs = running.concat(jobs);
const showStatus = {};
const sanitized = utils.sanitizeProject(req.project);
sanitized.access_level = req.accessLevel;
req.project.branches.forEach(function (branch) {
const plugins = (showStatus[branch.name] = {});
branch.plugins.forEach(function (plugin) {
plugins[plugin.id] = plugin.enabled && plugin.showStatus;
});
});
let job = id ? null : jobs[0];
for (i = 0; i < jobs.length; i++) {
if (!job && jobs[i]._id === id) job = jobs[i];
jobs[i] = ljobs.small(jobs[i]);
jobs[i] = filterJob(jobs[i]);
jobs[i].project = sanitized;
}
if (job) {
job.status = ljobs.status(job);
job.project = sanitized;
}
const isGlobalAdmin = req.user && req.user.account_level > 0;
const canAdminProject = sanitized.access_level > 0 || isGlobalAdmin;
// Make sure jobs are only listed once.
jobs = _.uniqBy(jobs, (job) => job._id.toString());
res.format({
html: function () {
debug(
'Build page requested. Logging jobs to investigate duplicate job listings.'
);
debug(jobs);
res.render('build.html', {
project: sanitized,
accessLevel: req.accessLevel,
canAdminProject: canAdminProject,
jobs: jobs,
job: job,
statusBlocks: common.statusBlocks,
showStatus: showStatus,
page_base: `${req.params.org}/${req.params.repo}`,
version: pjson.version,
});
},
json: function () {
res.send({
project: sanitized,
accessLevel: req.accessLevel,
canAdminProject: canAdminProject,
jobs: jobs,
job: job,
});
},
});
});
});
}
function getJob(req, res, next) {
let query;
if (!req.params.job_id) {
query = Job.findOne(
{ project: req.project.name.toLowerCase(), archived: null },
{},
{ sort: { finished: -1 } }
);
} else {
query = Job.findOne({
project: req.project.name.toLowerCase(),
_id: req.params.job_id,
archived: null,
});
}
query.exec(function (err, job) {
if (err || !job) return res.status(404).send('Failed to find job');
job = filterJob(job);
if (!job.finished) {
_.extend(job, findJob(job));
}
next(job);
});
}
function output(req, res) {
getJob(req, res, function (job) {
res.setHeader('Content-type', 'text/plain');
res.send(job.std.merged ? filter(job.std.merged) : '');
});
}
function data(req, res) {
getJob(req, res, function (job) {
res.setHeader('Content-type', 'application/json');
res.send(job);
});
}
function jobs(req, res) {
Job.find({ project: req.project.name.toLowerCase(), archived: null })
.sort({ finished: -1 })
.limit(20)
.lean()
.exec(function (err, jobs) {
if (err) return res.status(500).send('Failed to retrieve jobs');
res.send(
JSON.stringify(
jobs.map(function (j) {
return filterJob(j);
})
)
);
});
}