2018-06-04 18:07:22 +00:00
|
|
|
const is = require('@sindresorhus/is');
|
2018-02-12 12:31:41 +00:00
|
|
|
const addrs = require('email-addresses');
|
2018-07-27 17:49:56 +00:00
|
|
|
|
2018-07-09 09:14:06 +00:00
|
|
|
const get = require('./gl-got-wrapper');
|
2018-09-12 10:16:17 +00:00
|
|
|
const hostRules = require('../../util/host-rules');
|
2017-02-11 07:14:19 +00:00
|
|
|
|
2017-12-23 07:03:16 +00:00
|
|
|
let config = {};
|
2017-02-11 07:14:19 +00:00
|
|
|
|
|
|
|
module.exports = {
|
2017-04-21 05:00:26 +00:00
|
|
|
getRepos,
|
2018-08-29 11:38:06 +00:00
|
|
|
cleanRepo,
|
2017-02-11 07:14:19 +00:00
|
|
|
initRepo,
|
2018-09-10 11:56:53 +00:00
|
|
|
getRepoStatus: () => ({}),
|
2017-11-15 14:31:20 +00:00
|
|
|
getRepoForceRebase,
|
2017-07-06 08:26:18 +00:00
|
|
|
setBaseBranch,
|
2017-02-11 07:14:19 +00:00
|
|
|
// Search
|
2017-10-25 04:00:07 +00:00
|
|
|
getFileList,
|
2017-02-11 07:14:19 +00:00
|
|
|
// Branch
|
|
|
|
branchExists,
|
2017-11-05 07:18:20 +00:00
|
|
|
getAllRenovateBranches,
|
|
|
|
isBranchStale,
|
2017-02-11 07:14:19 +00:00
|
|
|
getBranchPr,
|
2017-04-17 04:46:24 +00:00
|
|
|
getBranchStatus,
|
2017-08-08 21:03:52 +00:00
|
|
|
getBranchStatusCheck,
|
2017-08-06 13:38:10 +00:00
|
|
|
setBranchStatus,
|
2017-06-22 09:56:23 +00:00
|
|
|
deleteBranch,
|
2017-11-05 07:18:20 +00:00
|
|
|
mergeBranch,
|
2017-08-28 09:37:09 +00:00
|
|
|
getBranchLastCommitTime,
|
2017-02-11 07:14:19 +00:00
|
|
|
// issue
|
2017-12-18 08:39:52 +00:00
|
|
|
ensureIssue,
|
|
|
|
ensureIssueClosing,
|
2017-02-11 07:14:19 +00:00
|
|
|
addAssignees,
|
|
|
|
addReviewers,
|
2018-09-14 10:51:33 +00:00
|
|
|
deleteLabel,
|
2017-10-19 11:30:26 +00:00
|
|
|
// Comments
|
2017-10-18 13:28:51 +00:00
|
|
|
ensureComment,
|
2017-10-19 11:30:26 +00:00
|
|
|
ensureCommentRemoval,
|
2017-02-11 07:14:19 +00:00
|
|
|
// PR
|
2018-01-11 10:49:01 +00:00
|
|
|
getPrList,
|
2017-02-11 07:14:19 +00:00
|
|
|
findPr,
|
|
|
|
createPr,
|
|
|
|
getPr,
|
2018-03-06 11:18:35 +00:00
|
|
|
getPrFiles,
|
2017-02-11 07:14:19 +00:00
|
|
|
updatePr,
|
2017-04-20 11:01:23 +00:00
|
|
|
mergePr,
|
2018-07-22 05:47:23 +00:00
|
|
|
getPrBody,
|
2017-02-11 07:14:19 +00:00
|
|
|
// file
|
|
|
|
commitFilesToBranch,
|
|
|
|
getFile,
|
2017-07-07 05:54:09 +00:00
|
|
|
// commits
|
|
|
|
getCommitMessages,
|
2018-07-28 06:47:49 +00:00
|
|
|
// vulnerability alerts
|
|
|
|
getVulnerabilityAlerts,
|
2017-02-11 07:14:19 +00:00
|
|
|
};
|
|
|
|
|
2017-04-21 05:00:26 +00:00
|
|
|
// Get all repositories that the user has access to
|
|
|
|
async function getRepos(token, endpoint) {
|
2018-04-04 11:38:06 +00:00
|
|
|
logger.info('Autodiscovering GitLab repositories');
|
2017-04-21 05:00:26 +00:00
|
|
|
logger.debug('getRepos(token, endpoint)');
|
2018-09-12 10:16:17 +00:00
|
|
|
const opts = hostRules.find({ platform: 'gitlab' }, { token, endpoint });
|
2018-07-06 05:26:36 +00:00
|
|
|
if (!opts.token) {
|
2017-04-21 05:00:26 +00:00
|
|
|
throw new Error('No token found for getRepos');
|
|
|
|
}
|
2018-09-12 10:16:17 +00:00
|
|
|
hostRules.update({ ...opts, platform: 'gitlab', default: true });
|
2017-04-21 05:00:26 +00:00
|
|
|
try {
|
2017-10-18 09:40:48 +00:00
|
|
|
const url = `projects?membership=true&per_page=100`;
|
|
|
|
const res = await get(url, { paginate: true });
|
|
|
|
logger.info(`Discovered ${res.body.length} project(s)`);
|
|
|
|
return res.body.map(repo => repo.path_with_namespace);
|
2017-04-21 05:00:26 +00:00
|
|
|
} catch (err) {
|
2017-07-19 06:05:26 +00:00
|
|
|
logger.error({ err }, `GitLab getRepos error`);
|
2017-04-21 05:00:26 +00:00
|
|
|
throw err;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-12-14 05:19:24 +00:00
|
|
|
function urlEscape(str) {
|
2018-02-03 11:06:25 +00:00
|
|
|
return str ? str.replace(/\//g, '%2F') : str;
|
2017-12-14 05:19:24 +00:00
|
|
|
}
|
|
|
|
|
2018-08-29 11:38:06 +00:00
|
|
|
function cleanRepo() {
|
|
|
|
// In theory most of this isn't necessary. In practice..
|
|
|
|
get.reset();
|
|
|
|
config = {};
|
|
|
|
}
|
|
|
|
|
2017-02-11 07:14:19 +00:00
|
|
|
// Initialize GitLab by getting base branch
|
2018-06-27 16:40:54 +00:00
|
|
|
async function initRepo({ repository, token, endpoint, gitAuthor }) {
|
2018-09-12 10:16:17 +00:00
|
|
|
const opts = hostRules.find({ platform: 'gitlab' }, { token, endpoint });
|
2018-07-06 05:26:36 +00:00
|
|
|
if (!opts.token) {
|
2018-01-25 11:24:13 +00:00
|
|
|
throw new Error(`No token found for GitLab repository ${repository}`);
|
2017-02-11 07:14:19 +00:00
|
|
|
}
|
2018-09-12 10:16:17 +00:00
|
|
|
hostRules.update({ ...opts, platform: 'gitlab', default: true });
|
2017-12-23 07:03:16 +00:00
|
|
|
config = {};
|
|
|
|
get.reset();
|
2018-01-25 11:24:13 +00:00
|
|
|
config.repository = urlEscape(repository);
|
2018-06-27 16:40:54 +00:00
|
|
|
if (gitAuthor) {
|
|
|
|
try {
|
|
|
|
config.gitAuthor = addrs.parseOneAddress(gitAuthor);
|
|
|
|
} catch (err) /* istanbul ignore next */ {
|
|
|
|
logger.error(
|
|
|
|
{ gitAuthor, err, message: err.message },
|
|
|
|
'Invalid gitAuthor'
|
|
|
|
);
|
|
|
|
throw new Error('Invalid gitAuthor');
|
|
|
|
}
|
|
|
|
}
|
2018-09-02 19:13:23 +00:00
|
|
|
let res;
|
2017-02-11 07:14:19 +00:00
|
|
|
try {
|
2018-09-02 19:13:23 +00:00
|
|
|
res = await get(`projects/${config.repository}`);
|
|
|
|
if (res.body.archived) {
|
|
|
|
logger.info(
|
|
|
|
'Repository is archived - throwing error to abort renovation'
|
|
|
|
);
|
|
|
|
throw new Error('archived');
|
|
|
|
}
|
2017-07-06 12:12:52 +00:00
|
|
|
config.defaultBranch = res.body.default_branch;
|
|
|
|
config.baseBranch = config.defaultBranch;
|
2018-01-25 11:24:13 +00:00
|
|
|
logger.debug(`${repository} default branch = ${config.baseBranch}`);
|
2017-06-22 09:56:23 +00:00
|
|
|
// Discover our user email
|
2017-10-17 05:15:01 +00:00
|
|
|
config.email = (await get(`user`)).body.email;
|
2017-12-23 07:03:16 +00:00
|
|
|
delete config.prList;
|
|
|
|
delete config.fileList;
|
|
|
|
await Promise.all([getPrList(), getFileList()]);
|
2017-02-11 07:14:19 +00:00
|
|
|
} catch (err) {
|
2018-09-02 19:13:23 +00:00
|
|
|
logger.debug('Caught initRepo error');
|
|
|
|
if (err.message === 'archived') {
|
|
|
|
throw err;
|
|
|
|
}
|
2018-09-05 08:31:21 +00:00
|
|
|
logger.info({ err }, 'Unknown GitLab initRepo error');
|
2017-02-11 07:14:19 +00:00
|
|
|
throw err;
|
|
|
|
}
|
2017-07-26 08:56:11 +00:00
|
|
|
return {};
|
2017-02-11 07:14:19 +00:00
|
|
|
}
|
|
|
|
|
2017-11-15 14:31:20 +00:00
|
|
|
function getRepoForceRebase() {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2018-02-03 09:39:04 +00:00
|
|
|
async function setBaseBranch(branchName) {
|
2017-07-06 08:26:18 +00:00
|
|
|
if (branchName) {
|
2018-02-03 09:39:04 +00:00
|
|
|
logger.debug(`Setting baseBranch to ${branchName}`);
|
2017-07-06 08:26:18 +00:00
|
|
|
config.baseBranch = branchName;
|
2018-02-03 09:39:04 +00:00
|
|
|
delete config.fileList;
|
|
|
|
await getFileList(branchName);
|
2017-07-06 08:26:18 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-02-11 07:14:19 +00:00
|
|
|
// Search
|
|
|
|
|
2017-10-16 09:59:59 +00:00
|
|
|
// Get full file list
|
2017-10-25 04:00:07 +00:00
|
|
|
async function getFileList(branchName = config.baseBranch) {
|
2017-10-16 09:59:59 +00:00
|
|
|
if (config.fileList) {
|
|
|
|
return config.fileList;
|
|
|
|
}
|
2017-10-18 06:25:42 +00:00
|
|
|
try {
|
2018-06-26 10:28:43 +00:00
|
|
|
let url = `projects/${
|
|
|
|
config.repository
|
|
|
|
}/repository/tree?ref=${branchName}&per_page=100`;
|
|
|
|
if (!(process.env.RENOVATE_DISABLE_FILE_RECURSION === 'true')) {
|
|
|
|
url += '&recursive=true';
|
|
|
|
}
|
|
|
|
const res = await get(url, { paginate: true });
|
2017-10-18 06:25:42 +00:00
|
|
|
config.fileList = res.body
|
2017-10-22 18:24:01 +00:00
|
|
|
.filter(item => item.type === 'blob' && item.mode !== '120000')
|
2017-10-18 06:25:42 +00:00
|
|
|
.map(item => item.path)
|
|
|
|
.sort();
|
2018-04-04 05:18:01 +00:00
|
|
|
logger.debug(`Retrieved fileList with length ${config.fileList.length}`);
|
2017-10-18 06:25:42 +00:00
|
|
|
} catch (err) {
|
2017-10-20 05:18:57 +00:00
|
|
|
logger.info('Error retrieving git tree - no files detected');
|
2017-10-18 06:25:42 +00:00
|
|
|
config.fileList = [];
|
|
|
|
}
|
2017-10-16 09:59:59 +00:00
|
|
|
return config.fileList;
|
|
|
|
}
|
|
|
|
|
2017-02-11 07:14:19 +00:00
|
|
|
// Branch
|
|
|
|
|
|
|
|
// Returns true if branch exists, otherwise false
|
|
|
|
async function branchExists(branchName) {
|
|
|
|
logger.debug(`Checking if branch exists: ${branchName}`);
|
|
|
|
try {
|
2018-01-25 11:24:13 +00:00
|
|
|
const url = `projects/${config.repository}/repository/branches/${urlEscape(
|
2017-12-14 05:19:24 +00:00
|
|
|
branchName
|
|
|
|
)}`;
|
2017-10-17 05:15:01 +00:00
|
|
|
const res = await get(url);
|
2017-02-11 07:14:19 +00:00
|
|
|
if (res.statusCode === 200) {
|
|
|
|
logger.debug('Branch exists');
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
// This probably shouldn't happen
|
2017-04-21 08:12:41 +00:00
|
|
|
logger.debug("Branch doesn't exist");
|
2017-02-11 07:14:19 +00:00
|
|
|
return false;
|
|
|
|
} catch (error) {
|
|
|
|
if (error.statusCode === 404) {
|
|
|
|
// If file not found, then return false
|
2017-04-21 08:12:41 +00:00
|
|
|
logger.debug("Branch doesn't exist");
|
2017-02-11 07:14:19 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
// Propagate if it's any other error
|
|
|
|
throw error;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-02-03 11:06:25 +00:00
|
|
|
async function getAllRenovateBranches(branchPrefix) {
|
|
|
|
logger.debug(`getAllRenovateBranches(${branchPrefix})`);
|
|
|
|
const allBranches = await get(
|
|
|
|
`projects/${config.repository}/repository/branches`
|
|
|
|
);
|
|
|
|
return allBranches.body.reduce((arr, branch) => {
|
|
|
|
if (branch.name.startsWith(branchPrefix)) {
|
|
|
|
arr.push(branch.name);
|
|
|
|
}
|
|
|
|
return arr;
|
|
|
|
}, []);
|
2017-11-05 07:18:20 +00:00
|
|
|
}
|
|
|
|
|
2018-04-14 19:47:22 +00:00
|
|
|
async function isBranchStale(branchName) {
|
|
|
|
logger.debug(`isBranchStale(${branchName})`);
|
|
|
|
const branchDetails = await getBranchDetails(branchName);
|
|
|
|
logger.trace({ branchDetails }, 'branchDetails');
|
|
|
|
const parentSha = branchDetails.body.commit.parent_ids[0];
|
|
|
|
logger.debug(`parentSha=${parentSha}`);
|
|
|
|
const baseCommitSHA = await getBaseCommitSHA();
|
|
|
|
logger.debug(`baseCommitSHA=${baseCommitSHA}`);
|
|
|
|
// Return true if the SHAs don't match
|
|
|
|
return parentSha !== baseCommitSHA;
|
2017-06-22 09:56:23 +00:00
|
|
|
}
|
|
|
|
|
2017-02-11 07:14:19 +00:00
|
|
|
// Returns the Pull Request for a branch. Null if not exists.
|
|
|
|
async function getBranchPr(branchName) {
|
|
|
|
logger.debug(`getBranchPr(${branchName})`);
|
2018-04-17 06:29:55 +00:00
|
|
|
if (!(await branchExists(branchName))) {
|
2018-02-28 03:43:30 +00:00
|
|
|
return null;
|
|
|
|
}
|
2017-11-07 10:52:15 +00:00
|
|
|
const urlString = `projects/${
|
2018-01-25 11:24:13 +00:00
|
|
|
config.repository
|
2017-11-07 10:52:15 +00:00
|
|
|
}/merge_requests?state=opened&per_page=100`;
|
2017-10-20 12:22:28 +00:00
|
|
|
const res = await get(urlString, { paginate: true });
|
2017-02-11 07:14:19 +00:00
|
|
|
logger.debug(`Got res with ${res.body.length} results`);
|
|
|
|
let pr = null;
|
2017-04-21 08:12:41 +00:00
|
|
|
res.body.forEach(result => {
|
2017-02-11 07:14:19 +00:00
|
|
|
if (result.source_branch === branchName) {
|
|
|
|
pr = result;
|
|
|
|
}
|
|
|
|
});
|
|
|
|
if (!pr) {
|
|
|
|
return null;
|
|
|
|
}
|
2017-11-01 09:36:58 +00:00
|
|
|
return getPr(pr.iid);
|
2017-02-11 07:14:19 +00:00
|
|
|
}
|
|
|
|
|
2017-04-17 04:46:24 +00:00
|
|
|
// Returns the combined status for a branch.
|
2017-07-05 05:02:25 +00:00
|
|
|
async function getBranchStatus(branchName, requiredStatusChecks) {
|
2017-04-17 04:46:24 +00:00
|
|
|
logger.debug(`getBranchStatus(${branchName})`);
|
2017-07-05 05:02:25 +00:00
|
|
|
if (!requiredStatusChecks) {
|
|
|
|
// null means disable status checks, so it always succeeds
|
|
|
|
return 'success';
|
|
|
|
}
|
|
|
|
if (requiredStatusChecks.length) {
|
|
|
|
// This is Unsupported
|
2017-07-19 06:05:26 +00:00
|
|
|
logger.warn({ requiredStatusChecks }, `Unsupported requiredStatusChecks`);
|
2017-07-05 05:02:25 +00:00
|
|
|
return 'failed';
|
|
|
|
}
|
2017-04-17 04:46:24 +00:00
|
|
|
// First, get the branch to find the commit SHA
|
2018-01-25 11:24:13 +00:00
|
|
|
let url = `projects/${config.repository}/repository/branches/${urlEscape(
|
2017-12-14 05:19:24 +00:00
|
|
|
branchName
|
|
|
|
)}`;
|
2017-10-17 05:15:01 +00:00
|
|
|
let res = await get(url);
|
2017-04-17 04:46:24 +00:00
|
|
|
const branchSha = res.body.commit.id;
|
|
|
|
// Now, check the statuses for that commit
|
2018-01-25 11:24:13 +00:00
|
|
|
url = `projects/${
|
|
|
|
config.repository
|
|
|
|
}/repository/commits/${branchSha}/statuses`;
|
2017-10-17 05:15:01 +00:00
|
|
|
res = await get(url);
|
2017-04-17 04:46:24 +00:00
|
|
|
logger.debug(`Got res with ${res.body.length} results`);
|
|
|
|
if (res.body.length === 0) {
|
|
|
|
// Return 'pending' if we have no status checks
|
|
|
|
return 'pending';
|
|
|
|
}
|
|
|
|
let status = 'success';
|
|
|
|
// Return 'success' if all are success
|
2017-04-21 08:12:41 +00:00
|
|
|
res.body.forEach(check => {
|
2017-04-17 04:46:24 +00:00
|
|
|
// If one is failed then don't overwrite that
|
2017-06-16 13:24:59 +00:00
|
|
|
if (status !== 'failure') {
|
2018-03-05 20:02:00 +00:00
|
|
|
if (!check.allow_failure) {
|
|
|
|
if (check.status === 'failed') {
|
|
|
|
status = 'failure';
|
|
|
|
} else if (check.status !== 'success') {
|
|
|
|
({ status } = check);
|
|
|
|
}
|
2017-04-17 04:46:24 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
|
|
|
return status;
|
|
|
|
}
|
|
|
|
|
2017-08-08 21:03:52 +00:00
|
|
|
async function getBranchStatusCheck(branchName, context) {
|
|
|
|
// First, get the branch to find the commit SHA
|
2018-01-25 11:24:13 +00:00
|
|
|
let url = `projects/${config.repository}/repository/branches/${urlEscape(
|
2017-12-14 05:19:24 +00:00
|
|
|
branchName
|
|
|
|
)}`;
|
2017-10-17 05:15:01 +00:00
|
|
|
let res = await get(url);
|
2017-08-08 21:03:52 +00:00
|
|
|
const branchSha = res.body.commit.id;
|
|
|
|
// Now, check the statuses for that commit
|
2018-01-25 11:24:13 +00:00
|
|
|
url = `projects/${
|
|
|
|
config.repository
|
|
|
|
}/repository/commits/${branchSha}/statuses`;
|
2017-10-17 05:15:01 +00:00
|
|
|
res = await get(url);
|
2017-08-08 21:03:52 +00:00
|
|
|
logger.debug(`Got res with ${res.body.length} results`);
|
|
|
|
for (const check of res.body) {
|
|
|
|
if (check.name === context) {
|
|
|
|
return check.state;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
2017-08-06 13:38:10 +00:00
|
|
|
async function setBranchStatus(
|
|
|
|
branchName,
|
|
|
|
context,
|
|
|
|
description,
|
|
|
|
state,
|
|
|
|
targetUrl
|
|
|
|
) {
|
|
|
|
// First, get the branch to find the commit SHA
|
2018-01-25 11:24:13 +00:00
|
|
|
let url = `projects/${config.repository}/repository/branches/${urlEscape(
|
2017-12-14 05:19:24 +00:00
|
|
|
branchName
|
|
|
|
)}`;
|
2017-10-17 05:15:01 +00:00
|
|
|
const res = await get(url);
|
2017-08-06 13:38:10 +00:00
|
|
|
const branchSha = res.body.commit.id;
|
|
|
|
// Now, check the statuses for that commit
|
2018-01-25 11:24:13 +00:00
|
|
|
url = `projects/${config.repository}/statuses/${branchSha}`;
|
2017-08-06 13:38:10 +00:00
|
|
|
const options = {
|
|
|
|
state,
|
|
|
|
description,
|
|
|
|
context,
|
|
|
|
};
|
|
|
|
if (targetUrl) {
|
|
|
|
options.target_url = targetUrl;
|
|
|
|
}
|
2017-10-17 05:15:01 +00:00
|
|
|
await get.post(url, { body: options });
|
2017-08-06 13:38:10 +00:00
|
|
|
}
|
|
|
|
|
2018-02-03 11:06:25 +00:00
|
|
|
async function deleteBranch(branchName, closePr = false) {
|
|
|
|
if (closePr) {
|
|
|
|
logger.debug('Closing PR');
|
|
|
|
const pr = await getBranchPr(branchName);
|
|
|
|
// istanbul ignore if
|
|
|
|
if (pr) {
|
|
|
|
await get.put(
|
|
|
|
`projects/${config.repository}/merge_requests/${pr.number}`,
|
|
|
|
{
|
|
|
|
body: {
|
|
|
|
state_event: 'close',
|
|
|
|
},
|
|
|
|
}
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
2017-10-17 05:15:01 +00:00
|
|
|
await get.delete(
|
2018-01-25 11:24:13 +00:00
|
|
|
`projects/${config.repository}/repository/branches/${urlEscape(branchName)}`
|
2017-06-22 09:56:23 +00:00
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2018-07-02 09:27:08 +00:00
|
|
|
async function mergeBranch(branchName) {
|
|
|
|
logger.debug(`mergeBranch(${branchName}`);
|
|
|
|
const branchURI = encodeURIComponent(branchName);
|
|
|
|
try {
|
|
|
|
await get.post(
|
|
|
|
`projects/${
|
|
|
|
config.repository
|
|
|
|
}/repository/commits/${branchURI}/cherry_pick?branch=${config.baseBranch}`
|
|
|
|
);
|
|
|
|
} catch (err) {
|
2018-09-05 08:31:21 +00:00
|
|
|
logger.info({ err }, `Error pushing branch merge for ${branchName}`);
|
2018-07-02 09:27:08 +00:00
|
|
|
throw new Error('Branch automerge failed');
|
|
|
|
}
|
|
|
|
// Update base commit
|
|
|
|
config.baseCommitSHA = null;
|
|
|
|
// Delete branch
|
|
|
|
await deleteBranch(branchName);
|
2017-11-05 07:18:20 +00:00
|
|
|
}
|
|
|
|
|
2017-08-28 09:37:09 +00:00
|
|
|
async function getBranchLastCommitTime(branchName) {
|
|
|
|
try {
|
2017-10-17 05:15:01 +00:00
|
|
|
const res = await get(
|
2018-01-25 11:24:13 +00:00
|
|
|
`projects/${config.repository}/repository/commits?ref_name=${urlEscape(
|
2017-12-14 05:19:24 +00:00
|
|
|
branchName
|
|
|
|
)}`
|
2017-08-28 09:37:09 +00:00
|
|
|
);
|
|
|
|
return new Date(res.body[0].committed_date);
|
|
|
|
} catch (err) {
|
|
|
|
logger.error({ err }, `getBranchLastCommitTime error`);
|
|
|
|
return new Date();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-02-11 07:14:19 +00:00
|
|
|
// Issue
|
|
|
|
|
2018-06-21 06:39:24 +00:00
|
|
|
async function getIssueList() {
|
|
|
|
if (!config.issueList) {
|
2018-07-05 07:52:31 +00:00
|
|
|
const res = await get(`projects/${config.repository}/issues?state=opened`, {
|
|
|
|
useCache: false,
|
|
|
|
});
|
2018-06-21 06:39:24 +00:00
|
|
|
// istanbul ignore if
|
|
|
|
if (!is.array(res.body)) {
|
|
|
|
logger.warn({ responseBody: res.body }, 'Could not retrieve issue list');
|
|
|
|
return [];
|
|
|
|
}
|
|
|
|
config.issueList = res.body.map(i => ({
|
|
|
|
iid: i.iid,
|
|
|
|
title: i.title,
|
|
|
|
}));
|
|
|
|
}
|
|
|
|
return config.issueList;
|
2017-12-18 08:39:52 +00:00
|
|
|
}
|
|
|
|
|
2018-06-21 06:39:24 +00:00
|
|
|
async function ensureIssue(title, body) {
|
|
|
|
logger.debug(`ensureIssue()`);
|
|
|
|
try {
|
|
|
|
const issueList = await getIssueList();
|
|
|
|
const issue = issueList.find(i => i.title === title);
|
|
|
|
if (issue) {
|
|
|
|
const issueBody = (await get(
|
|
|
|
`projects/${config.repository}/issues/${issue.iid}`
|
|
|
|
)).body.body;
|
|
|
|
if (issueBody !== body) {
|
|
|
|
logger.debug('Updating issue body');
|
|
|
|
await get.put(`projects/${config.repository}/issues/${issue.iid}`, {
|
|
|
|
body: { description: body },
|
|
|
|
});
|
|
|
|
return 'updated';
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
await get.post(`projects/${config.repository}/issues`, {
|
|
|
|
body: {
|
|
|
|
title,
|
|
|
|
description: body,
|
|
|
|
},
|
|
|
|
});
|
2018-07-05 07:52:31 +00:00
|
|
|
// delete issueList so that it will be refetched as necessary
|
|
|
|
delete config.issueList;
|
2018-06-21 06:39:24 +00:00
|
|
|
return 'created';
|
|
|
|
}
|
|
|
|
} catch (err) /* istanbul ignore next */ {
|
|
|
|
if (err.message.startsWith('Issues are disabled for this repo')) {
|
|
|
|
logger.info(`Could not create issue: ${err.message}`);
|
|
|
|
} else {
|
2018-09-05 08:31:21 +00:00
|
|
|
logger.warn({ err }, 'Could not ensure issue');
|
2018-06-21 06:39:24 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
|
|
|
async function ensureIssueClosing(title) {
|
|
|
|
logger.debug(`ensureIssueClosing()`);
|
|
|
|
const issueList = await getIssueList();
|
|
|
|
for (const issue of issueList) {
|
|
|
|
if (issue.title === title) {
|
|
|
|
logger.info({ issue }, 'Closing issue');
|
2018-07-30 09:32:06 +00:00
|
|
|
await get.put(`projects/${config.repository}/issues/${issue.iid}`, {
|
|
|
|
body: { state_event: 'close' },
|
2018-06-21 06:39:24 +00:00
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2017-12-18 08:39:52 +00:00
|
|
|
|
2017-11-01 12:55:36 +00:00
|
|
|
async function addAssignees(iid, assignees) {
|
|
|
|
logger.debug(`Adding assignees ${assignees} to #${iid}`);
|
2017-02-11 07:14:19 +00:00
|
|
|
if (assignees.length > 1) {
|
2017-11-10 08:59:12 +00:00
|
|
|
logger.warn('Cannot assign more than one assignee to Merge Requests');
|
|
|
|
}
|
|
|
|
try {
|
|
|
|
const assigneeId = (await get(`users?username=${assignees[0]}`)).body[0].id;
|
2018-01-25 11:24:13 +00:00
|
|
|
let url = `projects/${config.repository}/merge_requests/${iid}`;
|
2017-11-10 08:59:12 +00:00
|
|
|
url += `?assignee_id=${assigneeId}`;
|
|
|
|
await get.put(url);
|
|
|
|
} catch (err) {
|
|
|
|
logger.error({ iid, assignees }, 'Failed to add assignees');
|
2017-02-11 07:14:19 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-11-10 08:29:24 +00:00
|
|
|
function addReviewers(iid, reviewers) {
|
|
|
|
logger.debug(`addReviewers('${iid}, '${reviewers})`);
|
2018-04-06 09:31:34 +00:00
|
|
|
logger.warn('Unimplemented in GitLab: approvals');
|
2017-02-11 07:14:19 +00:00
|
|
|
}
|
|
|
|
|
2018-09-14 10:51:33 +00:00
|
|
|
// istanbul ignore next
|
|
|
|
function deleteLabel() {
|
|
|
|
throw new Error('deleteLabel not implemented');
|
|
|
|
}
|
|
|
|
|
2018-06-12 05:18:28 +00:00
|
|
|
async function getComments(issueNo) {
|
2018-06-27 08:15:15 +00:00
|
|
|
// GET projects/:owner/:repo/merge_requests/:number/notes
|
2018-06-12 05:18:28 +00:00
|
|
|
logger.debug(`Getting comments for #${issueNo}`);
|
2018-06-27 08:35:33 +00:00
|
|
|
const url = `projects/${config.repository}/merge_requests/${issueNo}/notes`;
|
2018-06-12 05:18:28 +00:00
|
|
|
const comments = (await get(url, { paginate: true })).body;
|
|
|
|
logger.debug(`Found ${comments.length} comments`);
|
|
|
|
return comments;
|
2017-10-18 13:28:51 +00:00
|
|
|
}
|
|
|
|
|
2018-06-12 05:18:28 +00:00
|
|
|
async function addComment(issueNo, body) {
|
2018-06-27 08:15:15 +00:00
|
|
|
// POST projects/:owner/:repo/merge_requests/:number/notes
|
2018-06-12 05:18:28 +00:00
|
|
|
await get.post(
|
2018-06-27 08:15:15 +00:00
|
|
|
`projects/${config.repository}/merge_requests/${issueNo}/notes`,
|
2018-06-12 05:18:28 +00:00
|
|
|
{
|
|
|
|
body: { body },
|
|
|
|
}
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
async function editComment(issueNo, commentId, body) {
|
2018-06-27 08:15:15 +00:00
|
|
|
// PATCH projects/:owner/:repo/merge_requests/:number/notes/:id
|
2018-06-12 05:18:28 +00:00
|
|
|
await get.patch(
|
2018-06-27 08:15:15 +00:00
|
|
|
`projects/${
|
2018-06-12 05:18:28 +00:00
|
|
|
config.repository
|
|
|
|
}/merge_requests/${issueNo}/notes/${commentId}`,
|
|
|
|
{
|
|
|
|
body: { body },
|
|
|
|
}
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
async function deleteComment(issueNo, commentId) {
|
2018-06-27 08:15:15 +00:00
|
|
|
// DELETE projects/:owner/:repo/merge_requests/:number/notes/:id
|
2018-06-12 05:18:28 +00:00
|
|
|
await get.delete(
|
2018-06-27 08:35:33 +00:00
|
|
|
`projects/${config.repository}/merge_requests/${issueNo}/notes/${commentId}`
|
2018-06-12 05:18:28 +00:00
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
async function ensureComment(issueNo, topic, content) {
|
|
|
|
const comments = await getComments(issueNo);
|
|
|
|
let body;
|
|
|
|
let commentId;
|
|
|
|
let commentNeedsUpdating;
|
|
|
|
if (topic) {
|
|
|
|
logger.debug(`Ensuring comment "${topic}" in #${issueNo}`);
|
|
|
|
body = `### ${topic}\n\n${content}`;
|
|
|
|
comments.forEach(comment => {
|
|
|
|
if (comment.body.startsWith(`### ${topic}\n\n`)) {
|
|
|
|
commentId = comment.id;
|
|
|
|
commentNeedsUpdating = comment.body !== body;
|
|
|
|
}
|
|
|
|
});
|
|
|
|
} else {
|
|
|
|
logger.debug(`Ensuring content-only comment in #${issueNo}`);
|
|
|
|
body = `${content}`;
|
|
|
|
comments.forEach(comment => {
|
|
|
|
if (comment.body === body) {
|
|
|
|
commentId = comment.id;
|
|
|
|
commentNeedsUpdating = false;
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
if (!commentId) {
|
|
|
|
await addComment(issueNo, body);
|
|
|
|
logger.info({ repository: config.repository, issueNo }, 'Added comment');
|
|
|
|
} else if (commentNeedsUpdating) {
|
|
|
|
await editComment(issueNo, commentId, body);
|
|
|
|
logger.info({ repository: config.repository, issueNo }, 'Updated comment');
|
|
|
|
} else {
|
|
|
|
logger.debug('Comment is already update-to-date');
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
async function ensureCommentRemoval(issueNo, topic) {
|
|
|
|
logger.debug(`Ensuring comment "${topic}" in #${issueNo} is removed`);
|
|
|
|
const comments = await getComments(issueNo);
|
|
|
|
let commentId;
|
|
|
|
comments.forEach(comment => {
|
|
|
|
if (comment.body.startsWith(`### ${topic}\n\n`)) {
|
|
|
|
commentId = comment.id;
|
|
|
|
}
|
|
|
|
});
|
|
|
|
if (commentId) {
|
|
|
|
await deleteComment(issueNo, commentId);
|
|
|
|
}
|
2017-10-19 11:30:26 +00:00
|
|
|
}
|
|
|
|
|
2017-11-14 08:55:05 +00:00
|
|
|
async function getPrList() {
|
|
|
|
if (!config.prList) {
|
2018-01-25 11:24:13 +00:00
|
|
|
const urlString = `projects/${
|
|
|
|
config.repository
|
|
|
|
}/merge_requests?per_page=100`;
|
2017-11-14 08:55:05 +00:00
|
|
|
const res = await get(urlString, { paginate: true });
|
|
|
|
config.prList = res.body.map(pr => ({
|
|
|
|
number: pr.iid,
|
|
|
|
branchName: pr.source_branch,
|
|
|
|
title: pr.title,
|
2017-11-24 06:31:20 +00:00
|
|
|
state: pr.state === 'opened' ? 'open' : pr.state,
|
2018-01-11 10:49:01 +00:00
|
|
|
createdAt: pr.created_at,
|
2017-11-14 08:55:05 +00:00
|
|
|
}));
|
|
|
|
}
|
|
|
|
return config.prList;
|
|
|
|
}
|
|
|
|
|
2017-11-24 06:31:20 +00:00
|
|
|
function matchesState(state, desiredState) {
|
|
|
|
if (desiredState === 'all') {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
if (desiredState[0] === '!') {
|
|
|
|
return state !== desiredState.substring(1);
|
|
|
|
}
|
|
|
|
return state === desiredState;
|
|
|
|
}
|
|
|
|
|
2017-02-11 07:14:19 +00:00
|
|
|
async function findPr(branchName, prTitle, state = 'all') {
|
|
|
|
logger.debug(`findPr(${branchName}, ${prTitle}, ${state})`);
|
2017-11-14 08:55:05 +00:00
|
|
|
const prList = await getPrList();
|
|
|
|
return prList.find(
|
|
|
|
p =>
|
|
|
|
p.branchName === branchName &&
|
|
|
|
(!prTitle || p.title === prTitle) &&
|
2017-11-24 06:31:20 +00:00
|
|
|
matchesState(p.state, state)
|
2017-11-14 08:55:05 +00:00
|
|
|
);
|
2017-02-11 07:14:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Pull Request
|
|
|
|
|
2017-11-08 10:09:26 +00:00
|
|
|
async function createPr(
|
|
|
|
branchName,
|
|
|
|
title,
|
|
|
|
description,
|
|
|
|
labels,
|
|
|
|
useDefaultBranch
|
|
|
|
) {
|
2017-07-06 12:12:52 +00:00
|
|
|
const targetBranch = useDefaultBranch
|
|
|
|
? config.defaultBranch
|
|
|
|
: config.baseBranch;
|
2017-02-11 07:14:19 +00:00
|
|
|
logger.debug(`Creating Merge Request: ${title}`);
|
2018-01-25 11:24:13 +00:00
|
|
|
const res = await get.post(`projects/${config.repository}/merge_requests`, {
|
2017-02-11 07:14:19 +00:00
|
|
|
body: {
|
|
|
|
source_branch: branchName,
|
2017-07-06 12:12:52 +00:00
|
|
|
target_branch: targetBranch,
|
2017-03-13 09:21:28 +00:00
|
|
|
remove_source_branch: true,
|
2017-02-11 07:14:19 +00:00
|
|
|
title,
|
2017-06-28 08:10:40 +00:00
|
|
|
description,
|
2018-06-04 18:07:22 +00:00
|
|
|
labels: is.array(labels) ? labels.join(',') : null,
|
2017-02-11 07:14:19 +00:00
|
|
|
},
|
|
|
|
});
|
|
|
|
const pr = res.body;
|
2017-11-10 08:29:24 +00:00
|
|
|
pr.number = pr.iid;
|
2018-02-19 20:23:37 +00:00
|
|
|
pr.branchName = branchName;
|
2017-02-11 07:14:19 +00:00
|
|
|
pr.displayNumber = `Merge Request #${pr.iid}`;
|
2018-10-03 13:08:34 +00:00
|
|
|
// istanbul ignore if
|
|
|
|
if (config.prList) {
|
|
|
|
config.prList.push(pr);
|
|
|
|
}
|
2017-02-11 07:14:19 +00:00
|
|
|
return pr;
|
|
|
|
}
|
|
|
|
|
2017-11-10 08:29:24 +00:00
|
|
|
async function getPr(iid) {
|
|
|
|
logger.debug(`getPr(${iid})`);
|
2018-01-25 11:24:13 +00:00
|
|
|
const url = `projects/${config.repository}/merge_requests/${iid}`;
|
2017-10-17 05:15:01 +00:00
|
|
|
const pr = (await get(url)).body;
|
2017-02-11 07:14:19 +00:00
|
|
|
// Harmonize fields with GitHub
|
2018-02-19 19:01:10 +00:00
|
|
|
pr.branchName = pr.source_branch;
|
2017-11-01 09:36:58 +00:00
|
|
|
pr.number = pr.iid;
|
2017-02-11 07:14:19 +00:00
|
|
|
pr.displayNumber = `Merge Request #${pr.iid}`;
|
|
|
|
pr.body = pr.description;
|
2018-06-30 21:07:37 +00:00
|
|
|
pr.state = pr.state === 'opened' ? 'open' : pr.state;
|
2017-02-11 07:14:19 +00:00
|
|
|
if (pr.merge_status === 'cannot_be_merged') {
|
|
|
|
logger.debug('pr cannot be merged');
|
2018-02-27 18:50:16 +00:00
|
|
|
pr.canMerge = false;
|
2018-09-14 18:02:51 +00:00
|
|
|
pr.isConflicted = true;
|
2018-02-27 18:50:16 +00:00
|
|
|
} else {
|
|
|
|
// Actually.. we can't be sure
|
|
|
|
pr.canMerge = true;
|
2017-02-11 07:14:19 +00:00
|
|
|
}
|
2017-06-22 09:56:23 +00:00
|
|
|
// Check if the most recent branch commit is by us
|
|
|
|
// If not then we don't allow it to be rebased, in case someone's changes would be lost
|
2017-11-07 10:52:15 +00:00
|
|
|
const branchUrl = `projects/${
|
2018-01-25 11:24:13 +00:00
|
|
|
config.repository
|
2017-12-14 05:19:24 +00:00
|
|
|
}/repository/branches/${urlEscape(pr.source_branch)}`;
|
2018-02-28 03:43:30 +00:00
|
|
|
try {
|
|
|
|
const branch = (await get(branchUrl)).body;
|
|
|
|
if (
|
|
|
|
branch &&
|
|
|
|
branch.commit &&
|
|
|
|
branch.commit.author_email === config.email
|
|
|
|
) {
|
|
|
|
pr.canRebase = true;
|
|
|
|
}
|
|
|
|
} catch (err) {
|
|
|
|
logger.warn({ err }, 'Error getting PR branch');
|
2018-09-14 18:02:51 +00:00
|
|
|
pr.isConflicted = true;
|
2017-06-22 09:56:23 +00:00
|
|
|
}
|
2017-02-11 07:14:19 +00:00
|
|
|
return pr;
|
|
|
|
}
|
|
|
|
|
2018-06-19 11:39:25 +00:00
|
|
|
// Return a list of all modified files in a PR
|
|
|
|
async function getPrFiles(mrNo) {
|
|
|
|
logger.debug({ mrNo }, 'getPrFiles');
|
|
|
|
if (!mrNo) {
|
|
|
|
return [];
|
|
|
|
}
|
|
|
|
const files = (await get(
|
2018-06-29 10:09:11 +00:00
|
|
|
`projects/${config.repository}/merge_requests/${mrNo}/changes`
|
2018-06-19 11:39:25 +00:00
|
|
|
)).body;
|
|
|
|
return files.map(f => f.filename);
|
2018-03-06 11:18:35 +00:00
|
|
|
}
|
|
|
|
|
2018-03-13 19:33:22 +00:00
|
|
|
// istanbul ignore next
|
|
|
|
async function reopenPr(iid) {
|
|
|
|
await get.put(`projects/${config.repository}/merge_requests/${iid}`, {
|
|
|
|
body: {
|
|
|
|
state_event: 'reopen',
|
|
|
|
},
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2017-11-10 08:29:24 +00:00
|
|
|
async function updatePr(iid, title, description) {
|
2018-01-25 11:24:13 +00:00
|
|
|
await get.put(`projects/${config.repository}/merge_requests/${iid}`, {
|
2017-02-11 07:14:19 +00:00
|
|
|
body: {
|
|
|
|
title,
|
2017-06-28 08:10:40 +00:00
|
|
|
description,
|
2017-02-11 07:14:19 +00:00
|
|
|
},
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2017-11-10 08:29:24 +00:00
|
|
|
async function mergePr(iid) {
|
2018-01-25 11:24:13 +00:00
|
|
|
await get.put(`projects/${config.repository}/merge_requests/${iid}/merge`, {
|
2017-11-10 08:29:24 +00:00
|
|
|
body: {
|
|
|
|
should_remove_source_branch: true,
|
|
|
|
},
|
|
|
|
});
|
2017-08-31 05:15:53 +00:00
|
|
|
return true;
|
2017-04-20 11:01:23 +00:00
|
|
|
}
|
|
|
|
|
2018-07-22 05:47:23 +00:00
|
|
|
function getPrBody(input) {
|
2018-09-22 18:01:18 +00:00
|
|
|
return input.replace(/Pull Request/g, 'Merge Request').replace(/PR/g, 'MR');
|
2018-07-22 05:47:23 +00:00
|
|
|
}
|
|
|
|
|
2017-02-11 07:14:19 +00:00
|
|
|
// Generic File operations
|
|
|
|
|
2017-11-08 11:23:32 +00:00
|
|
|
async function getFile(filePath, branchName) {
|
2017-12-23 07:03:16 +00:00
|
|
|
logger.debug(`getFile(filePath=${filePath}, branchName=${branchName})`);
|
|
|
|
if (!branchName || branchName === config.baseBranch) {
|
|
|
|
if (config.fileList && !config.fileList.includes(filePath)) {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
}
|
2017-02-11 07:14:19 +00:00
|
|
|
try {
|
2018-01-25 11:24:13 +00:00
|
|
|
const url = `projects/${config.repository}/repository/files/${urlEscape(
|
2017-12-14 05:19:24 +00:00
|
|
|
filePath
|
|
|
|
)}?ref=${branchName || config.baseBranch}`;
|
2017-11-08 11:23:32 +00:00
|
|
|
const res = await get(url);
|
|
|
|
return Buffer.from(res.body.content, 'base64').toString();
|
2017-02-11 07:14:19 +00:00
|
|
|
} catch (error) {
|
|
|
|
if (error.statusCode === 404) {
|
|
|
|
// If file not found, then return null JSON
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
// Propagate if it's any other error
|
|
|
|
throw error;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Add a new commit, create branch if not existing
|
|
|
|
async function commitFilesToBranch(
|
|
|
|
branchName,
|
|
|
|
files,
|
|
|
|
message,
|
2018-06-27 16:40:54 +00:00
|
|
|
parentBranch = config.baseBranch
|
2017-04-21 08:12:41 +00:00
|
|
|
) {
|
2017-05-10 07:26:09 +00:00
|
|
|
logger.debug(
|
|
|
|
`commitFilesToBranch('${branchName}', files, message, '${parentBranch})'`
|
|
|
|
);
|
2018-02-12 05:20:20 +00:00
|
|
|
const opts = {
|
|
|
|
body: {
|
|
|
|
branch: branchName,
|
|
|
|
commit_message: message,
|
|
|
|
start_branch: parentBranch,
|
|
|
|
actions: [],
|
|
|
|
},
|
|
|
|
};
|
2018-06-27 16:40:54 +00:00
|
|
|
// istanbul ignore if
|
|
|
|
if (config.gitAuthor) {
|
|
|
|
opts.body.author_name = config.gitAuthor.name;
|
|
|
|
opts.body.author_email = config.gitAuthor.address;
|
2018-02-12 12:31:41 +00:00
|
|
|
}
|
2017-02-11 07:14:19 +00:00
|
|
|
for (const file of files) {
|
2018-02-12 05:20:20 +00:00
|
|
|
const action = {
|
|
|
|
file_path: file.name,
|
|
|
|
content: Buffer.from(file.contents).toString('base64'),
|
|
|
|
encoding: 'base64',
|
|
|
|
};
|
|
|
|
action.action = (await getFile(file.name)) ? 'update' : 'create';
|
|
|
|
opts.body.actions.push(action);
|
2017-02-11 07:14:19 +00:00
|
|
|
}
|
2018-08-23 18:35:25 +00:00
|
|
|
let res = 'created';
|
2018-05-23 17:26:56 +00:00
|
|
|
try {
|
|
|
|
if (await branchExists(branchName)) {
|
|
|
|
logger.debug('Deleting existing branch');
|
|
|
|
await deleteBranch(branchName);
|
2018-08-23 18:35:25 +00:00
|
|
|
res = 'updated';
|
2018-05-23 17:26:56 +00:00
|
|
|
}
|
|
|
|
} catch (err) {
|
|
|
|
// istanbul ignore next
|
|
|
|
logger.info(`Ignoring branch deletion failure`);
|
2018-02-12 05:58:33 +00:00
|
|
|
}
|
2018-03-13 19:33:22 +00:00
|
|
|
logger.debug('Adding commits');
|
2018-02-12 05:20:20 +00:00
|
|
|
await get.post(`projects/${config.repository}/repository/commits`, opts);
|
2018-03-13 19:33:22 +00:00
|
|
|
// Reopen PR if it previousluy existed and was closed by GitLab when we deleted branch
|
|
|
|
const pr = await getBranchPr(branchName);
|
|
|
|
// istanbul ignore if
|
|
|
|
if (pr) {
|
|
|
|
logger.debug('Reopening PR');
|
|
|
|
await reopenPr(pr.number);
|
|
|
|
}
|
2018-08-23 18:35:25 +00:00
|
|
|
return res;
|
2017-02-11 07:14:19 +00:00
|
|
|
}
|
|
|
|
|
2017-07-07 05:54:09 +00:00
|
|
|
// GET /projects/:id/repository/commits
|
|
|
|
async function getCommitMessages() {
|
|
|
|
logger.debug('getCommitMessages');
|
2018-07-23 14:47:37 +00:00
|
|
|
const res = await get(`projects/${config.repository}/repository/commits`);
|
|
|
|
return res.body.map(commit => commit.title);
|
2017-07-07 05:54:09 +00:00
|
|
|
}
|
2018-04-14 19:47:22 +00:00
|
|
|
|
|
|
|
function getBranchDetails(branchName) {
|
|
|
|
const url = `/projects/${config.repository}/repository/branches/${urlEscape(
|
|
|
|
branchName
|
|
|
|
)}`;
|
|
|
|
return get(url);
|
|
|
|
}
|
|
|
|
|
|
|
|
async function getBaseCommitSHA() {
|
|
|
|
if (!config.baseCommitSHA) {
|
|
|
|
const branchDetails = await getBranchDetails(config.baseBranch);
|
|
|
|
config.baseCommitSHA = branchDetails.body.commit.id;
|
|
|
|
}
|
|
|
|
return config.baseCommitSHA;
|
|
|
|
}
|
2018-06-21 06:39:24 +00:00
|
|
|
|
2018-07-28 06:47:49 +00:00
|
|
|
function getVulnerabilityAlerts() {
|
|
|
|
return [];
|
|
|
|
}
|