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