From 31b2e238a03340caf82d3f3443434601ba0e4d8f Mon Sep 17 00:00:00 2001 From: "Petr \"Stone\" Hracek" Date: Mon, 22 Jul 2024 14:50:57 +0200 Subject: [PATCH] Create GitHub summary report from Testing Farm results Signed-off-by: Petr "Stone" Hracek --- src/action.ts | 10 +++++ src/metadata.ts | 92 +++++++++++++++++++++++++++++++++++++++++++++ src/pull-request.ts | 79 +++++++++++++++++++++++++++++++++++++- 3 files changed, 180 insertions(+), 1 deletion(-) create mode 100644 src/metadata.ts diff --git a/src/action.ts b/src/action.ts index f28917e..bcf8711 100644 --- a/src/action.ts +++ b/src/action.ts @@ -269,6 +269,16 @@ async function action(pr: PullRequest): Promise { ); } + // Create comment summary with Testing Farm request/result to Pull Request + if (getBooleanInput('comment_summary')) { + await pr.publishStatusComment( + getInput('pull_request_status_name'), + getInput('compose'), + finalState, + ${tfArtifactUrl} + ); + } + // Create Github Summary if (getBooleanInput('create_github_summary')) { await summary diff --git a/src/metadata.ts b/src/metadata.ts new file mode 100644 index 0000000..7f8ed57 --- /dev/null +++ b/src/metadata.ts @@ -0,0 +1,92 @@ +import { getInput } from '@actions/core'; +import { context } from '@actions/github'; +import MetadataController from 'issue-metadata'; +import { z } from 'zod'; + +let summary_info: { "pull_request_status_name": string, "compose": string, "results": string, "logs": string } + + +type MetadataObject = { + TFCommentID: string | undefined; + TFDatetime: string | undefined + TFSummaryInfo: unknown[]; +}; + + + +export class Metadata { + private _TFcommentID: MetadataObject['TFCommentID']; + + constructor( + readonly issueNumber: number, + readonly controller: MetadataController, + metadata: MetadataObject + ) { + this._TFcommentID = metadata?.TFCommentID ?? undefined; + this._TFDatetime = metadata?.TFDatetime ?? undefined; + this._TFSummaryInfo = metadata?._TFSummaryInfo ?? []; + } + + get commentID() { + return this._TFcommentID; + } + + get summaryInfo() { + return this._TFSummaryInfo; + } + + get dateTimeInfo() { + return this._TFDatetime; + } + + set commentID(value: MetadataObject['TFCommentID']) { + if (this._TFcommentID === undefined) { + this._TFcommentID = value; + } + } + + set dateTimeInfo(value: MetadataObject['TFDatetime']) { + this._TFDatetime = value; + } + + set updateSummaryInfo(value: MetadataObject['TFSummaryInfo']) { + this._TFSummaryInfo = value; + } + + static readonly metadataCommentID = 'tf-comment-id'; + + async setMetadata(): Promise { + if (this.TestingFarmCommentID !== undefined) { + await this.controller.setMetadata( + this.issueNumber, + Metadata.metadataCommentID, + this.commentID ?? '' + ); + } + + // TODO: clear tag when un-freezed + await this.controller.setMetadata( + this.issueNumber, + ); + } + + static async getMetadata(issueNumber: number): Promise { + const controller = new MetadataController('tf-comment-id', { + ...context.repo, + headers: { + authorization: `Bearer ${getInput('token', { required: true })}`, + }, + }); + + const parsedCommentID = z + .string() + .safeParse( + await controller.getMetadata(issueNumber, Metadata.metadataCommentID) + ); + + return new Metadata(issueNumber, controller, { + commentID: parsedCommentID.success ? parsedCommentID.data : undefined, + }); + } + +} \ No newline at end of file diff --git a/src/pull-request.ts b/src/pull-request.ts index 8cb4899..81d8efa 100644 --- a/src/pull-request.ts +++ b/src/pull-request.ts @@ -1,6 +1,7 @@ import { debug, getBooleanInput, getInput } from '@actions/core'; import { context } from '@actions/github'; import { Endpoints } from '@octokit/types'; +import { Metadata } from './metadata'; import { CustomOctokit } from './octokit'; @@ -14,12 +15,33 @@ export class PullRequest { * @param sha - The head sha of the Pull Request * @param octokit - The Octokit instance to use for interacting with the GitHub API */ + private _metadata: Metadata | undefined; private constructor( readonly number: number, readonly sha: string, - readonly octokit: CustomOctokit + readonly octokit: CustomOctokit, ) {} + set metadata(metadata: Metadata) { + this._metadata = metadata; + } + + get metadata() { + if (!this._metadata) { + raise('Metadata is not set.'); + } + + return this._metadata; + } + + isCommented(): boolean { + return !!this.metadata.commentID; + } + + async setMetadata() { + this.metadata = await Metadata.getMetadata(this.id); + } + /** * Set the Pull Request status using the GitHub API. * @param state - The state of the status, can be one of error, failure, pending or success @@ -95,4 +117,59 @@ export class PullRequest { return new this(data.number, data.head.sha, octokit); } + + async publishStatusComment(pull_request_status_name: string, compose: string, final_state: string): Promise { + const table_row = '|${pull_request_status_name}|${compose}|$[final_state}|test|' + if (this.metadata.commentID) { + this.updateStatusComment(table_row); + return; + } + const createTable = '### Testing Farm as a GitHub Action summary\n\n + | Compose | Version | Test result | link to logs |\n + |--------|--------|--------|--------|' + const commentPayload = await this.createStatusComment(createTable); + + if (!commentPayload) { + warning(`Failed to create comment.`); + return; + } + this.metadata.commentID = id === undefined ? id : commentPayload.id.toString(); + await this.metadata.setMetadata(); + } + + async createStatusComment(body: string) { + if (!body || body === '') return; + + debug(`Creating comment for PR: #${this.id}`); + + const { data } = await this.octokit.request( + 'POST /repos/{owner}/{repo}/issues/{issue_number}/comments', + { + ...context.repo, + issue_number: this.id, + body, + } + ); + + return data; + } + + private async updateStatusComment(body: string) { + if (!this.metadata.commentID) return; + + debug(`Updating comment with ID: ${this.metadata.commentID}`); + const createTable = '### Testing Farm as a GitHub Action summary\n\n + | Compose | Version | Test result | link to logs |\n + |--------|--------|--------|--------|' + const { data } = await this.octokit.request( + 'PATCH /repos/{owner}/{repo}/issues/comments/{comment_id}', + { + ...context.repo, + comment_id: +this.metadata.commentID, + body, + } + ); + + return data; + } }