1import { Octokit } from "@octokit/rest"; 2import fs from "fs"; 3import ado from "azure-devops-node-api"; 4import fetch from "node-fetch"; 5import assert from "assert"; 6 7 8async function main() { 9 const source = process.env.SOURCE_ISSUE; 10 if (!source) throw new Error("SOURCE_ISSUE environment variable not set."); 11 12 const requester = process.env.REQUESTING_USER; 13 if (!requester) throw new Error("REQUESTING_USER environment variable not set."); 14 15 const buildId = process.env.BUILD_BUILDID; 16 if (!buildId) throw new Error("BUILD_BUILDID environment variable not set."); 17 18 const postedComment = process.env.STATUS_COMMENT; 19 if (!postedComment) throw new Error("STATUS_COMMENT environment variable not set."); 20 21 const [auth, fragment, includeArtifact] = process.argv.slice(2); 22 if (!auth) throw new Error("First argument must be a GitHub auth token."); 23 if (!fragment) throw new Error("Second argument must be a path to an HTML fragment."); 24 25 const gh = new Octokit({ auth }); 26 try { 27 console.log(`Loading fragment from ${fragment}...`); 28 const outputTableText = fs.readFileSync(fragment, { encoding: "utf8" }); 29 console.log(`Fragment contents:\n${outputTableText}`); 30 31 let benchmarkText = ""; 32 if (includeArtifact === "--include-artifact") { 33 // post a link to the benchmark file 34 const cli = new ado.WebApi("https://typescript.visualstudio.com/defaultcollection", ado.getHandlerFromToken("")); // Empty token, anon auth 35 const build = await cli.getBuildApi(); 36 const artifact = await build.getArtifact("typescript", +buildId, "benchmark"); 37 assert(artifact.resource?.url); 38 const updatedUrl = new URL(artifact.resource.url); 39 updatedUrl.search = `artifactName=benchmark&fileId=${artifact.resource.data}&fileName=manifest`; 40 const resp = await (await fetch(`${updatedUrl}`)).json(); 41 for (const file of /** @type {any} */ (resp).items) { 42 if (/[\\/]linux\.benchmark$/.test(file.path)) { 43 const benchmarkUrl = new URL(artifact.resource.url); 44 benchmarkUrl.search = `artifactName=benchmark&fileId=${file.blob.id}&fileName=linux.benchmark`; 45 benchmarkText = `\n<details><summary>Developer Information:</summary><p><a href="${benchmarkUrl.href}">Download Benchmark</a></p></details>\n`; 46 break; 47 } 48 } 49 } 50 51 const data = await gh.issues.createComment({ 52 issue_number: +source, 53 owner: "Microsoft", 54 repo: "TypeScript", 55 body: `@${requester}\nThe results of the perf run you requested are in!\n<details><summary> Here they are:</summary><p>\n${outputTableText}\n</p>${benchmarkText}</details>` 56 }); 57 58 console.log(`Results posted!`); 59 const newCommentUrl = data.data.html_url; 60 const comment = await gh.issues.getComment({ 61 owner: "Microsoft", 62 repo: "TypeScript", 63 comment_id: +postedComment 64 }); 65 const newBody = `${comment.data.body}\n\nUpdate: [The results are in!](${newCommentUrl})`; 66 await gh.issues.updateComment({ 67 owner: "Microsoft", 68 repo: "TypeScript", 69 comment_id: +postedComment, 70 body: newBody 71 }); 72 } 73 catch (e) { 74 const gh = new Octokit({ auth }); 75 await gh.issues.createComment({ 76 issue_number: +source, 77 owner: "Microsoft", 78 repo: "TypeScript", 79 body: `Hey @${requester}, something went wrong when publishing results. ([You can check the log here](https://typescript.visualstudio.com/TypeScript/_build/index?buildId=${buildId}&_a=summary)).` 80 }); 81 } 82} 83 84main().catch(e => { 85 console.error(e); 86 process.exit(1); 87}); 88