azure-pipelines-wrapper/check_run.js (196 lines of code) (raw):

const azp = require('./azp'); require('dotenv').config(); const converage_property_prefix = "codediff."; const check_prefix = 'coverage.'; // The context can be issue_comment or check_run async function create_checks_by_azp_check_run(context, azp_check_run){ if (azp_check_run.app.name != "Azure Pipelines"){ context.log(`Skip the check_run:${azp_check_run.id}, for the app name: ${azp_check_run.app.name}`); return null; } var properties = await azp.getProperties(azp_check_run); if (! properties){ context.log(`Skipped the check_run:${azp_check_run.id}, for no properties`); return null; } var coverages = {}; for (const [key, value] of Object.entries(properties)) { if (key.startsWith(converage_property_prefix)){ coverages[key] = value; } } if (! coverages){ context.log(`Skipped for no coverages`); return null; } // Query existing checks by commit id var checkUrl = new URL(azp_check_run.url); var urlPaths = checkUrl.pathname.split('/'); var owner = urlPaths[2]; var repo = urlPaths[3]; var check_runs = await context.octokit.checks.listForRef({ owner: owner, repo: repo, ref: azp_check_run.head_sha, app_id: process.env.APP_ID, }); if (check_runs.status != 200){ console.error(`Failed to list checks of ${owner}/${repo}/${azp_check_run.head_sha} for app ${process.env.APP_ID}`); return null; } context.log(`Succeeded to list checks for of ${owner}/${repo}/${azp_check_run.head_sha} for app ${process.env.APP_ID}`); var checks = {}; for (check of check_runs.data.check_runs){ if (!check.started_at){ continue; } if (check.name in checks){ var existingCheck = checks[check.name]; if (check.started_at > existingCheck.started_at){ checks[check.name] = check; } } else{ checks[check.name] = check; } } var created_checks = []; context.log(`Found coverages count ${Object.keys(coverages).length}`); for (const [key, value] of Object.entries(coverages)){ var coverageInfo = JSON.parse(value); var definitionName = coverageInfo.definitionName; var jobName = coverageInfo.jobName; var checkName = `${check_prefix}${definitionName}.${jobName}`; var pullRequestId = coverageInfo.pullRequestId; var jobId = coverageInfo.jobId; var external_id = `${pullRequestId}|${coverageInfo.timestamp}`; if (checkName in checks){ var check = checks[checkName]; if (check.external_id == external_id){ console.log(`Skipped the check ${checkName}, for external_id ${external_id} existing.`); continue; } } var info = azp.getAzDevInfoFromCheckPayload(azp_check_run); var details_url = `https://dev.azure.com/${info.org}/${info.projectId}/_build/results?buildId=${info.buildId}&view=logs&jobId=${jobId}`; var coverage_url = `https://dev.azure.com/${info.org}/${info.projectId}/_build/results?buildId=${info.buildId}&view=codecoverage-tab`; context.log(`Creating check ${checkName}`); var num_lines = coverageInfo["cover.num_lines"]; var num_violations = coverageInfo["cover.num_violations"]; var percent_covered = coverageInfo["cover.percent_covered"]; var threshold = coverageInfo["cover.threshold"]; if (threshold > 100){ threshold = 100; } if (threshold < 0){ threshold = 0; } var conclusion = percent_covered >= threshold ? 'success' : 'failure'; var check = await context.octokit.rest.checks.create({ owner: owner, repo: repo, head_sha: azp_check_run.head_sha, name: checkName, conclusion: conclusion, status: 'completed', external_id: external_id, details_url: details_url, output: { title: "Pull Request Coverage", summary: `Total: ${num_lines} lines\nMissing: ${num_violations} lines\nCoverage: ${percent_covered}%\nThreshold: ${threshold}%\n[Diff coverage](${coverage_url})`, } }); if (check.status != 200 && check.status != 201){ context.error(`Return ${check.status}, failed to create the check for ${owner}/${repo}/commit/${azp_check_run.head_sha}`); continue; } created_checks.push(check.data); context.log(`Created check ${checkName}, id: ${check.data.id}`); } return created_checks; } async function check_run_completed_handler(context) { var payload = context.payload; if (!'check_run' in payload){ return null; } var check_run = payload.check_run; var checkUrl = new URL(check_run.url); var urlPaths = checkUrl.pathname.split('/'); var owner = urlPaths[2]; var repo = urlPaths[3]; await create_checks_by_azp_check_run(context, check_run); } async function create_checks_by_pullRequest(context, owner, repo, pullRequestId){ var payload = context.payload; var pullRequest = await context.octokit.pulls.get({ owner: owner, repo: repo, pull_number: pullRequestId, }); if (pullRequest.status != 200){ console.error(`Failed to get pull request for ${owner}/${repo}/${pullRequestId}`); return null; } context.log(`Succeeded to get pull request for ${owner}/${repo}/${pullRequestId}`); var check_runs = await context.octokit.checks.listForRef({ owner: owner, repo: repo, ref: pullRequest.data.head.sha, app_id: process.env.AZP_APP_ID, }); if (check_runs.status != 200){ console.error(`Failed to list checks for ${owner}/${repo}/${payload.check_run.head_sha} for app ${process.env.AZP_APP_ID}`); return null; } if (check_runs.data.check_runs.length <= 0){ console.log(`No checks found for ${owner}/${repo}/${payload.check_run.head_sha} for app ${process.env.AZP_APP_ID}`); return null; } console.log(`Succeeded to list checks for ${owner}/${repo}/${pullRequest.data.head.sha}, checks count: ${check_runs.data.check_runs.length}`); var azp_check_run = check_runs.data.check_runs[0]; await create_checks_by_azp_check_run(context, azp_check_run); } async function create_checks_by_comment(context){ var payload = context.payload; if (!'issue' in payload){ return null; } if (!'pull_request' in payload.issue){ return null; } if (!'url' in payload.issue.pull_request){ return null; } var owner = payload.repository.owner.login; var repo = payload.repository.name; return create_checks_by_pullRequest(context, owner, repo, payload.issue.number); } async function create_checks_by_rerequested(context){ var payload = context.payload; if (!'check_run' in payload){ return null; } var check_run = payload.check_run; if (check_run.app.id != process.env.APP_ID){ console.log(`Skip the check_run:${check_run.id}, for the app name: ${check_run.app.name}`); return null; } var owner = payload.repository.owner.login; var repo = payload.repository.name; var pullRequestId = check_run.external_id.split('|')[0]; return create_checks_by_pullRequest(context, owner, repo, pullRequestId); } function init(app) { app.log.info("Init check_run!"); app.on("check_run.completed", async (context) => { console.log("check run completed"); await check_run_completed_handler(context); }); app.on("check_run.rerequested", async (context) => { console.log("check run rerequested"); await create_checks_by_rerequested(context); }); }; module.exports = Object.freeze({ init: init, create_checks_by_comment: create_checks_by_comment, });