apps/strider/dist-lib/routes/api/repo.js
/*
* Repo-specific actions - such as deactivation, deletion etc.
* routes/api/repo.js
*/
const async = require('async');
const common = require('../../common');
const debug = require('debug')('strider:routes:api:repo');
const Job = require('../../models').Job;
const Project = require('../../models').Project;
const ssh = require('../../utils/ssh');
const User = require('../../models').User;
const utils = require('../../utils');
function makePlugins(plugins) {
const configs = [];
let plugin;
for (let i = 0; i < plugins.length; i++) {
plugin = common.extensions.job[plugins[i]];
if (!plugin)
return false;
const config = utils.defaultSchema(plugin);
configs.push({
id: plugins[i],
enabled: true,
config: config,
});
}
return configs;
}
/**
* @api {delete} /:org/:repo/cache Clear Cache
* @apiUse ProjectReference
* @apiPermission ProjectAdmin
* @apiDescription Clears/invalidates the cache for a project.
* @apiName ClearCache
* @apiGroup Repo
* @apiVersion 1.0.0
*
* @apiExample {curl} CURL Example:
* curl -X DELETE http://localhost/api/strider-cd/strider/cache
*/
exports.clearCache = function (req, res) {
clearProjectCache(req.project, function (err, result) {
if (err) {
return res.status(500).send('failed to clear cache');
}
if (result) {
res.send(result);
}
else {
res.sendStatus(204);
}
});
};
function clearProjectCache(project, cb) {
const runners = [];
const tasks = [];
project.branches.forEach(function (branch) {
const nonMasterMirrored = branch.name !== 'master' && branch.mirror_master;
if (nonMasterMirrored || runners.indexOf(branch.runner.id) !== -1) {
return;
}
runners.push(branch.runner.id);
});
runners.forEach(function (rid) {
const runner = common.extensions.runner[rid];
debug(rid, common.extensions.runner, project);
if (!runner || !runner.clearCache)
return;
tasks.push(runner.clearCache.bind(runner, project));
});
if (!tasks.length) {
return cb(undefined, 'No runners supported cache clearing');
}
async.parallel(tasks, cb);
}
/**
* @api {put} /:org Create Repo
* @apiDescription Create a new project for a repo.
* @apiName CreateRepo
* @apiGroup Repo
* @apiVersion 1.0.0
*
* @apiParam (RequestBody) {String} name The name of the new branch
* @apiParam (RequestBody) {String} display_name Human-readable project name
* @apiParam (RequestBody) {String} display_url The URL for the repo (e.g. Github homepage)
* @apiParam (RequestBody) {Boolean} public=false Whether this project is public or not.
* @apiParam (RequestBody) {Boolean} prefetch_config=true Whether the strider.json should be fetched in advance.
* @apiParam (RequestBody) {String} account The ID of provider account
* @apiParam (RequestBody) {String} repo_id The ID of the repo
* @apiParam (RequestBody) {Object} provider A json object with 'id' and 'config' properties.
*/
exports.createProject = function (req, res, next) {
if (req.params.org === 'auth') {
return next();
}
let name = `${req.params.org}/${req.params.repo}`;
debug(`Setting up new project "${name}"...`);
const display_name = req.body.display_name;
const display_url = req.body.display_url;
const isPublic = req.body.public === 'true' || req.body.public === '1';
let prefetch_config = true;
const project_type = req.body.project_type || 'node.js';
if (req.body.prefetch_config === 'false' ||
req.body.prefetch_config === '0') {
prefetch_config = false;
}
const provider = req.body.provider;
function error(code, str) {
return res.status(code).json({
results: [],
status: 'error',
errors: [{ code: code, reason: str }],
});
}
if (!display_name) {
return error(400, 'display_name is required');
}
if (!provider || !provider.id) {
return error(400, 'provider.id is required');
}
if (common.extensions.provider[provider.id].hosted) {
if (!provider.account) {
return error(400, 'provider.account is required');
}
if (!provider.repo_id) {
return error(400, 'provider.repo_id is required');
}
}
if (!provider.config) {
provider.config = utils.defaultSchema(provider.config);
}
if (!common.project_types[project_type]) {
return error(400, 'Invalid project type specified');
}
const plugins = makePlugins(common.project_types[project_type].plugins);
if (!plugins) {
return error(400, 'Project type specified is not available; one or more required plugins is not installed');
}
function projectResult(err, project) {
if (project) {
debug(`User ${req.user.email} tried to create project for repo ${name}, but it already exists`);
return error(409, 'project already exists');
}
return ssh.generateKeyPair(`${name}-${req.user.email}`, createProjectWithKey);
}
function createProjectWithKey(err, privkey, pubkey) {
if (err)
return error(500, 'Failed to generate ssh keypair');
const project = {
name: name,
display_name: display_name,
display_url: display_url,
public: isPublic,
prefetch_config: prefetch_config,
creator: req.user._id,
provider: provider,
branches: [
{
name: 'master',
active: true,
mirror_master: false,
deploy_on_green: true,
deploy_on_pull_request: false,
pubkey: pubkey,
privkey: privkey,
plugins: plugins,
runner: {
id: 'simple-runner',
config: { pty: false },
},
},
{
name: '*',
mirror_master: true,
},
],
};
const plugin = common.extensions.provider[provider.id];
if (!plugin.hosted || !plugin.setupRepo) {
return Project.create(project, projectCreated);
}
debug(`Setting up repository "${project.name}" with provider "${provider.id}"...`);
plugin.setupRepo(req.user.account(provider).config, provider.config, project, function (err, config) {
if (err) {
debug(`Setting up repository "${project.name}" failed!`, err.status, err.message);
return error(500, `Failed to setup repo: ${err.message}`);
}
project.provider.config = config;
Project.create(project, projectCreated);
});
}
function projectCreated(err, p) {
if (err) {
debug(`Error creating repo ${name} for user ${req.user.email}: ${err}`);
debug(err.stack);
return error(500, 'internal server error');
}
// Project object created, add to User object
User.updateOne({ _id: req.user._id }, {
$push: {
projects: {
name: name,
display_name: p.display_name,
access_level: 2,
},
},
}, function (err, num) {
if (err || !num)
debug('Failed to give the creator repo access...');
return res.json({
project: {
_id: p._id,
name: p.name,
display_name: p.display_name,
},
results: [{ code: 200, message: 'project created' }],
status: 'ok',
errors: [],
});
});
}
name = name.toLowerCase().replace(/ /g, '-');
Project.findOne({ name: name }, projectResult);
};
/**
* @api {delete} /:org/:repo Delete Repo
* @apiUse ProjectReference
* @apiPermission ProjectAdmin
* @apiDescription Deletes a repository/project. Also archives all jobs (marks as archived in DB which makes them hidden).
* @apiName DeleteRepo
* @apiGroup Repo
* @apiVersion 1.0.0
*
* @apiExample {curl} CURL Example:
* curl -X DELETE http://localhost/api/strider-cd/strider
*/
exports.deleteProject = function (req, res) {
async.parallel([
function (next) {
const provider = req.project.provider;
const plugin = common.extensions.provider[provider.id];
if (!plugin.hosted || !plugin.teardownRepo)
return next();
plugin.teardownRepo(req.project.creator.account(provider).config, provider.config, req.project, function (err) {
if (err)
debug('Error while tearing down repo', req.project.name, provider.id, err);
next();
});
},
req.project.remove.bind(req.project),
function (next) {
clearProjectCache(req.project, function (error) {
next(error);
});
},
function (next) {
const now = new Date();
Job.updateOne({ project: req.project.name }, { $set: { archived: now } }, { multi: true }, next);
},
], function (err) {
if (err) {
debug('repo.delete_index() - Error deleting repo config for url %s by user %s: %s', req.project.name, req.user.email, err);
return res.status(500).send(`Failed to delete project: ${err.message}`);
}
const r = {
errors: [],
status: 'ok',
results: [],
};
res.send(JSON.stringify(r, null, '\t'));
});
};
//# sourceMappingURL=repo.js.map