diff --git a/README.md b/README.md
index ec6c2f6..b9a2d0b 100644
--- a/README.md
+++ b/README.md
@@ -85,6 +85,7 @@ This action requires the `pull-request: write` permission to add a comment to yo
| `file-coverage-mode` | Defines how file-based coverage is reported. Possible values are `all`, `changes` or `none`. | `changes` |
| `name` | Give the report a custom name. This is useful if you want multiple reports for different test suites within the same PR. Needs to be unique. | '' |
| `json-summary-compare-path` | The path to the json summary file to compare against. If given, will display a trend indicator and the difference in the summary. Respects the `working-directory` option. | undefined |
+| `pr-number` | The number of the PR to post a comment to (if any) | If in the context of a PR, the number of that PR.
If in the context of a triggered workflow, the PR of the triggering workflow.
If no PR context is found, it defaults to `undefined` |
#### File Coverage Mode
diff --git a/action.yml b/action.yml
index 496fbf3..e0c0542 100644
--- a/action.yml
+++ b/action.yml
@@ -32,6 +32,10 @@ inputs:
required: false
description: 'The name of the coverage report. Can be used to execute this action multiple times. '
default: ''
+ pr-number:
+ required: false
+ description: 'An optional, user-defined pull request number.'
+ default: ''
runs:
using: 'node20'
main: 'dist/index.js'
diff --git a/src/index.ts b/src/index.ts
index ec48bb4..cf92f5b 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -18,13 +18,14 @@ const run = async () => {
jsonSummaryComparePath,
name,
thresholds,
- workingDirectory
+ workingDirectory,
+ processedPrNumber
} = await readOptions();
const jsonSummary = await parseVitestJsonSummary(jsonSummaryPath);
-
+
let jsonSummaryCompare;
- if(jsonSummaryComparePath) {
+ if (jsonSummaryComparePath) {
jsonSummaryCompare = await parseVitestJsonSummary(jsonSummaryComparePath);
}
@@ -48,7 +49,8 @@ const run = async () => {
try {
await writeSummaryToPR({
summary,
- markerPostfix: getMarkerPostfix({ name, workingDirectory })
+ markerPostfix: getMarkerPostfix({ name, workingDirectory }),
+ userDefinedPrNumber: processedPrNumber
});
} catch (error) {
if (error instanceof RequestError && (error.status === 404 || error.status === 403)) {
diff --git a/src/inputs/options.ts b/src/inputs/options.ts
index 096717f..b74c099 100644
--- a/src/inputs/options.ts
+++ b/src/inputs/options.ts
@@ -15,18 +15,28 @@ async function readOptions() {
const jsonFinalPath = path.resolve(workingDirectory, core.getInput('json-final-path'));
- const jsonSummaryCompareInput = core.getInput('json-summary-compare-path');
+ const jsonSummaryCompareInput = core.getInput('json-summary-compare-path');
let jsonSummaryComparePath;
- if(jsonSummaryCompareInput) {
+ if (jsonSummaryCompareInput) {
jsonSummaryComparePath = path.resolve(workingDirectory, jsonSummaryCompareInput);
}
const name = core.getInput('name');
- // ViteConfig is optional, as it is only required for thresholds. If no vite config is provided, we will not include thresholds in the final report.
+ // Get the user-defined pull-request number and perform input validation
+ const prNumber = core.getInput('pr-number');
+ let processedPrNumber: number | undefined = Number(prNumber);
+ if (!Number.isSafeInteger(processedPrNumber) || processedPrNumber <= 0) {
+ processedPrNumber = undefined;
+ }
+ if (processedPrNumber) {
+ core.info(`Received pull-request number: ${processedPrNumber}`);
+ }
+
+ // ViteConfig is optional, as it is only required for thresholds. If no vite config is provided, we will not include thresholds in the final report.
const viteConfigPath = await getViteConfigPath(workingDirectory, core.getInput("vite-config-path"));
const thresholds = viteConfigPath ? await parseCoverageThresholds(viteConfigPath) : {};
-
+
return {
fileCoverageMode,
jsonFinalPath,
@@ -35,6 +45,7 @@ async function readOptions() {
name,
thresholds,
workingDirectory,
+ processedPrNumber,
}
}
diff --git a/src/writeSummaryToPR.ts b/src/writeSummaryToPR.ts
index 1e6577b..a13b26b 100644
--- a/src/writeSummaryToPR.ts
+++ b/src/writeSummaryToPR.ts
@@ -5,17 +5,23 @@ const gitHubToken = core.getInput('github-token').trim();
const octokit: Octokit = github.getOctokit(gitHubToken);
const COMMENT_MARKER = (markerPostfix = 'root') => ``;
-type Octokit = ReturnType;
-const writeSummaryToPR = async ({ summary, markerPostfix }: {
- summary: typeof core.summary;
- markerPostfix?: string;
+type Octokit = ReturnType;
+const writeSummaryToPR = async ({ summary, markerPostfix, userDefinedPrNumber }: {
+ summary: typeof core.summary;
+ markerPostfix?: string;
+ userDefinedPrNumber?: number;
}) => {
- // If in the context of a pull-request, get the pull-request number
- let pullRequestNumber = github.context.payload.pull_request?.number;
+ // The user-defined pull request number takes precedence
+ let pullRequestNumber = userDefinedPrNumber;
- // This is to allow commenting on pull_request from forks
- if (github.context.eventName === 'workflow_run') {
- pullRequestNumber = await getPullRequestNumberFromTriggeringWorkflow(octokit);
+ if (!pullRequestNumber) {
+ // If in the context of a pull-request, get the pull-request number
+ pullRequestNumber = github.context.payload.pull_request?.number;
+
+ // This is to allow commenting on pull_request from forks
+ if (github.context.eventName === 'workflow_run') {
+ pullRequestNumber = await getPullRequestNumberFromTriggeringWorkflow(octokit);
+ }
}
if (!pullRequestNumber) {
@@ -71,23 +77,23 @@ async function getPullRequestNumberFromTriggeringWorkflow(octokit: Octokit): Pro
run_id: originalWorkflowRunId,
});
- if(originalWorkflowRun.event !== 'pull_request') {
+ if (originalWorkflowRun.event !== 'pull_request') {
core.info('The triggering workflow is not a pull-request. Skipping comment creation.');
return undefined;
}
// When the actual pull-request is not coming from a fork, the pull_request object is correctly populated and we can shortcut here
- if(originalWorkflowRun.pull_requests && originalWorkflowRun.pull_requests.length > 0) {
+ if (originalWorkflowRun.pull_requests && originalWorkflowRun.pull_requests.length > 0) {
return originalWorkflowRun.pull_requests[0].number;
}
// When the actual pull-request is coming from a fork, the pull_request object is not populated (see https://github.com/orgs/community/discussions/25220)
core.info(`Trying to find the pull-request for the triggering workflow run with id: ${originalWorkflowRunId} (${originalWorkflowRun.url}) with HEAD_SHA ${originalWorkflowRun.head_sha}...`)
-
+
// The way to find the pull-request in this scenario is to query all existing pull_requests on the target repository and find the one with the same HEAD_SHA as the original workflow run
const pullRequest = await findPullRequest(octokit, originalWorkflowRun.head_sha);
- if(!pullRequest) {
+ if (!pullRequest) {
core.info('Could not find the pull-request for the triggering workflow run. Skipping comment creation.');
return undefined;
}
@@ -100,11 +106,11 @@ async function findPullRequest(octokit: Octokit, headSha: string) {
core.startGroup(`Querying REST API for Pull-Requests.`);
const pullRequestsIterator = octokit.paginate.iterator(
octokit.rest.pulls.list, {
- owner: github.context.repo.owner,
- repo: github.context.repo.repo,
- per_page: 30
+ owner: github.context.repo.owner,
+ repo: github.context.repo.repo,
+ per_page: 30
});
-
+
for await (const { data: pullRequests } of pullRequestsIterator) {
core.info(`Found ${pullRequests.length} pull-requests in this page.`)
for (const pullRequest of pullRequests) {