/** * Copyright (c) Microsoft Corporation. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ import { context, getOctokit } from '@actions/github'; import * as core from '@actions/core'; import MarkdownReporter from '../../packages/playwright/src/reporters/markdown'; import type { MetadataWithCommitInfo } from 'playwright/src/isomorphic/types'; import type { IssueCommentEdge, Repository } from '@octokit/graphql-schema'; function getGithubToken() { const token = process.env.GITHUB_TOKEN || core.getInput('github-token'); if (!token) { core.setFailed('Missing "github-token" input'); throw new Error('Missing "github-token" input'); } return token; } const octokit = getOctokit(getGithubToken()); class GHAMarkdownReporter extends MarkdownReporter { override async publishReport(report: string) { core.info('Publishing report to PR.'); const { prNumber, prHref } = this.pullRequestFromMetadata(); if (!prNumber) { core.info(`No PR number found, skipping GHA comment. PR href: ${prHref}`); return; } core.info(`Posting comment to PR ${prHref}`); const prNodeId = await this.collapsePreviousComments(prNumber); if (!prNodeId) { core.warning(`No PR node ID found, skipping GHA comment. PR href: ${prHref}`); return; } await this.addNewReportComment(prNodeId, report); } private async collapsePreviousComments(prNumber: number) { const { owner, repo } = context.repo; const data = await octokit.graphql<{ repository: Repository }>(` query { repository(owner: "${owner}", name: "${repo}") { pullRequest(number: ${prNumber}) { id comments(last: 100) { nodes { id body author { __typename login } } } } } } `); const comments = data.repository.pullRequest?.comments.nodes?.filter(comment => comment?.author?.__typename === 'Bot' && comment?.author?.login === 'github-actions' && comment.body?.includes(this._magicComment())); const prId = data.repository.pullRequest?.id; if (!comments?.length) return prId; const mutations = comments.map((comment, i) => `m${i}: minimizeComment(input: { subjectId: "${comment!.id}", classifier: OUTDATED }) { clientMutationId }`); await octokit.graphql(` mutation { ${mutations.join('\n')} } `); return prId; } private _magicComment() { return ``; } private _workflowRunName() { // When used via 'workflow_run' event. const workflowRunName = context.payload.workflow_run?.name; if (workflowRunName) return workflowRunName; // When used via 'pull_request'/'push' event. // This is the name of the workflow file, e.g. 'ci.yml' or name if set. return process.env.GITHUB_WORKFLOW; } private async addNewReportComment(prNodeId: string, report: string) { const reportUrl = process.env.HTML_REPORT_URL; const mergeWorkflowUrl = `${context.serverUrl}/${context.repo.owner}/${context.repo.repo}/actions/runs/${context.runId}`; const body = formatComment([ this._magicComment(), `### ${reportUrl ? `[Test results](${reportUrl})` : 'Test results'} for "${this._workflowRunName()}"`, report, '', `Merge [workflow run](${mergeWorkflowUrl}).` ]); const response = await octokit.graphql<{ addComment: { commentEdge: IssueCommentEdge } }>(` mutation { addComment(input: {subjectId: "${prNodeId}", body: """${body}"""}) { commentEdge { node { ... on IssueComment { url } } } } } `); core.info(`Posted comment: ${response.addComment.commentEdge.node?.url}`); } private pullRequestFromMetadata() { const metadata = this._config.metadata as MetadataWithCommitInfo; const prHref = metadata.ci?.prHref; return { prNumber: parseInt(prHref?.split('/').pop() ?? '', 10), prHref }; } } function formatComment(lines: string[]) { let body = lines.join('\n'); if (body.length > 65535) body = body.substring(0, 65000) + `... ${body.length - 65000} more characters`; return body; } export default GHAMarkdownReporter;