in functions/src/plugins/merge.ts [405:547]
private async updateStatus(context: Context, config?: MergeConfig, updateStatus = true, labels?: Github.PullRequestsGetResponseLabelsItem[], statuses?: GithubGQL.StatusContext[]): Promise<void> {
let updateG3Status = false;
if(context.payload.action === "synchronize") {
updateG3Status = true;
}
if(!updateStatus && !updateG3Status) {
return;
}
config = config || await this.getConfig(context);
if(config.status.disabled) {
return;
}
let sha, pr;
const {owner, repo} = context.repo();
switch(context.name) {
case 'pull_request':
case 'pull_request_review':
sha = context.payload.pull_request.head.sha;
pr = context.payload.pull_request;
pr = await this.updateDbPR(context.github, owner, repo, pr.number, context.payload.repository.id, pr).catch(err => {
throw err;
});
if(!labels) {
labels = pr.labels || await this.getPRLabels(context);
}
break;
case 'status':
// Ignore status update events that are coming from this bot
if(context.payload.context === config.status.context) {
this.logDebug({context}, `Update status coming from this bot, ignored`);
return;
}
// Ignore status events for commits coming directly from the default branch (most likely using github edit)
// because they are not coming from a PR (e.g. travis runs for all commits and triggers a status update)
if(context.payload.branches.name === context.payload.repository.default_branch) {
this.logDebug({context}, `Update status coming directly from the default branch (${context.payload.branches.name}), ignored`);
return;
}
sha = context.payload.sha;
pr = await this.findPrBySha(sha, context.payload.repository.id);
if(!pr) {
// The repository data was previously stored as a simple id, checking if this PR still has old data
const matches = (await this.pullRequests.where('head.sha', '==', sha)
.where('repository', '==', context.payload.repository.id)
.get());
matches.forEach(async doc => {
pr = doc.data();
});
}
// Either init has not finished yet and we don't have this PR in the DB, or it's a status update for a commit
// made directly on a branch without a PR (e.g. travis runs for all commits and triggers a status update)
if(!pr) {
this.logWarn({context}, `Update status for unknown PR, ignored. Head sha == ${sha}, repository == ${context.payload.repository.id}`);
return;
} else {
// make sure that we have updated data
pr = await this.updateDbPR(context.github, owner, repo, pr.number, context.payload.repository.id);
}
if(!labels) {
labels = pr.labels || await getGhPRLabels(context.github, owner, repo, pr.number);
}
break;
default:
throw new Error(`Unhandled event ${context.name} in updateStatus`);
}
statuses = statuses || await this.getStatuses(context, pr.number, config);
if(config.g3Status && !config.g3Status.disabled && (updateG3Status ||
// Check if the g3status is missing
!statuses.some(status => status.context === config.g3Status.context)
)) {
// Checking if we need to add g3 status
const files: Github.PullRequestsListFilesResponse = await context.github.paginate(
context.github.pullRequests.listFiles({owner, repo, number: pr.number}),
pages => (pages as any).data) as Github.PullRequestsListFilesResponse;
(await context.github.pullRequests.listFiles({owner, repo, number: pr.number})).data;
if(this.matchAnyFile(files.map(file => file.filename), config.g3Status.include, config.g3Status.exclude)) {
// Only update g3 status if a commit was just pushed, or there was no g3 status
if(context.payload.action === "synchronize" || !statuses.some(status => status.context === config.g3Status.context)) {
const status = (await context.github.repos.createStatus({
owner,
repo,
sha: sha,
context: config.g3Status.context,
state: STATUS_STATE.Pending,
description: config.g3Status.pendingDesc.replace("{{PRNumber}}", pr.number),
target_url: config.g3Status.url
})).data as any as GithubGQL.StatusContext;
statuses.push(status);
this.log({context}, `Updated g3 status to pending`);
}
} else {
const status = (await context.github.repos.createStatus({
owner,
repo,
sha: pr.head.sha,
context: config.g3Status.context,
state: STATUS_STATE.Success,
description: config.g3Status.successDesc
})).data as any as GithubGQL.StatusContext;
statuses.push(status);
this.log({context}, `Updated g3 status to success`);
}
}
if(updateStatus) {
const statusParams: Github.ReposCreateStatusParams = {
owner,
repo,
sha: sha,
context: config.status.context,
state: STATUS_STATE.Success
};
const failedChecks = await this.getChecksStatus(context, pr, config, labels, statuses);
if(failedChecks.failure.length > 0) {
statusParams.state = STATUS_STATE.Failure;
statusParams.description = failedChecks.failure.concat(failedChecks.pending).join(', ');
} else if(failedChecks.pending.length > 0) {
statusParams.state = STATUS_STATE.Pending;
statusParams.description = failedChecks.pending.join(', ');
} else {
statusParams.state = STATUS_STATE.Success;
statusParams.description = config.status.successText;
}
// Capitalize first letter
statusParams.description = statusParams.description.replace(statusParams.description[0], statusParams.description[0].toUpperCase());
const desc = statusParams.description;
// TODO(ocombe): add a link to a dynamic page with the complete status & some description of what's required
if(statusParams.description.length > 140) {
statusParams.description = statusParams.description.substring(0, 137) + '...';
}
await context.github.repos.createStatus(statusParams);
this.log({context}, `Updated status to "${statusParams.state}": ${desc}`);
}
}