in functions/src/plugins/size.ts [50:214]
async checkSize(context: Context): Promise<void> {
const appConfig = await this.getAppConfig(context);
if(!appConfig.size || appConfig.size.disabled) {
return;
}
const config: SizeConfig = {
...defaultAppConfig.size,
...appConfig.size,
status: { ...defaultAppConfig.size.status, ...appConfig.size.status },
};
const statusEvent = context.payload;
// only check on PRs the status has that artifacts
if(statusEvent.context !== config.circleCiStatusName) {
return;
}
if(statusEvent.state === STATUS_STATE.Pending) {
await this.setStatus(
STATUS_STATE.Pending,
`Waiting for "${config.circleCiStatusName}"...`,
config.status.context,
context,
);
return;
} else if(statusEvent.state === STATUS_STATE.Failure) {
await this.setStatus(
STATUS_STATE.Error,
`Unable to calculate sizes. Failure: "${config.circleCiStatusName}"`,
config.status.context,
context,
);
return;
}
const {owner, repo} = context.repo();
const buildNumber = this.getBuildNumberFromCircleCIUrl(statusEvent.target_url);
let newArtifacts;
try {
newArtifacts = await this.getCircleCIArtifacts(owner, repo, buildNumber, config.exclude, config.include);
} catch(e) {
this.logError('CircleCI Artifact retrieval error: ' + e.message);
await this.setStatus(
STATUS_STATE.Error,
`Unable to retrieve artifacts from "${config.circleCiStatusName}".`,
config.status.context,
context,
);
return;
}
const pr = await this.findPrBySha(statusEvent.sha, statusEvent.repository.id);
if(!pr) {
// this status doesn't have a PR therefore it's probably a commit to a branch
// so we want to store any changes from that commit
await this.upsertNewArtifacts(context, newArtifacts);
await this.setStatus(
STATUS_STATE.Success,
`Baseline saved for ${statusEvent.sha}`,
config.status.context,
context,
);
return;
}
this.logDebug(`[size] Processing PR: ${pr.title}`);
// set to pending since we are going to do a full run through
await this.setStatus(
STATUS_STATE.Pending,
'Calculating artifact sizes...',
config.status.context,
context,
);
const targetBranchArtifacts = await this.getTargetBranchArtifacts(pr);
if(targetBranchArtifacts.length === 0) {
await this.setStatus(
STATUS_STATE.Success,
`No baseline available for ${pr.base.ref} / ${pr.base.sha}`,
config.status.context,
context,
);
return;
}
const comparisons = this.generateArtifactComparisons(targetBranchArtifacts, newArtifacts, config);
const largestIncrease = comparisons.length > 0 ? comparisons[0] : null;
const failure = largestIncrease && largestIncrease.failed;
let description;
if(!largestIncrease) {
description = 'No matching artifacts to compare.';
} else if(largestIncrease.delta === 0) {
description = 'No size change against base branch.';
} else {
const direction = largestIncrease.delta > 0 ? 'increased' : 'decreased';
const formattedBytes = formatBytes(Math.abs(largestIncrease.delta));
description = `${largestIncrease.current.path} ${direction} by ${formattedBytes}.`;
// Add comment if enabled
if (config.comment) {
let body = '|| Artifact | Baseline | Current | Change |\n|-|-|-|-|-|\n';
for (const comparison of comparisons) {
const emoji = comparison.delta <= 0 ? ':white_check_mark:' : ':grey_exclamation:';
body += `| ${comparison.failed ? ':x:' : emoji}|${comparison.baseline.path}`;
body += `|[${formatBytes(comparison.baseline.size)}](${comparison.baseline.url})`;
body += `|[${formatBytes(comparison.current.size)}](${comparison.current.url})`;
body += `|${comparison.delta > 0 ? '+' : ''}${formatBytes(comparison.delta)}|`;
}
try {
const prDoc = await this.pullRequests.doc(pr.id.toString()).get();
let commentId = prDoc.exists ? prDoc.data().sizeCheckComment : undefined;
if (commentId !== undefined) {
try {
await context.github.issues.updateComment({
owner,
repo,
comment_id: commentId,
body,
});
} catch {
// Comment may have been deleted
commentId = undefined;
}
}
if (commentId === undefined) {
const response = await context.github.issues.createComment({
owner,
repo,
number: pr.number,
body,
});
await prDoc.ref.update({ sizeCheckComment: response.data.id });
}
} catch (e) {
this.logError(`Unable to add size comment [${e.message}]`);
}
}
}
return this.setStatus(
failure ? STATUS_STATE.Failure : STATUS_STATE.Success,
description,
config.status.context,
context,
);
}