UNPKG

strider

Version:

Brilliant continuous deployment platform

273 lines 9.96 kB
/* * 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