Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -1153,7 +1153,7 @@ jobs:

# - We skip optional tests on release branches
# - The tests run in optional-e2e.yml, so their failures do not mark the PR as failed. This job only waits for
# them and reports failures in a PR comment.
# them. optional-e2e.yml reports the results in a PR comment.
job_optional_e2e_tests:
name: E2E Tests (optional)
# We only run E2E tests for non-fork PRs because the E2E tests require secrets to work and they can't be accessed from forks
Expand All @@ -1171,7 +1171,6 @@ jobs:
permissions:
contents: read
actions: write
pull-requests: write
steps:
- name: Check out current commit (${{ needs.job_get_metadata.outputs.commit_label }})
uses: actions/checkout@v7
Expand Down
33 changes: 33 additions & 0 deletions .github/workflows/optional-e2e.yml
Original file line number Diff line number Diff line change
Expand Up @@ -115,3 +115,36 @@ jobs:
working-directory: ${{ runner.temp }}/test-application
timeout-minutes: 10
run: ${{ matrix.assert-command || 'pnpm test:assert' }}

# A separate job in this workflow, so that a re-run of this run (all jobs or only the failed ones) also updates the
# comment. GitHub re-runs the jobs that depend on a re-run job.
job_report:
name: Report in PR comment
needs: [job_optional_e2e_tests]
# Not for a cancelled run: a new push cancels the old run, and the new run reports.
if: ${{ !cancelled() && github.event_name == 'workflow_dispatch' && inputs.pr_number != '' }}
runs-on: ubuntu-24.04
timeout-minutes: 5
permissions:
contents: read
actions: read
pull-requests: write
steps:
- name: Check out commit ${{ env.HEAD_COMMIT }}
uses: actions/checkout@v7
with:
ref: ${{ env.HEAD_COMMIT }}
- name: Set up Node
uses: actions/setup-node@v7
with:
node-version-file: 'package.json'
- name: Install pnpm
uses: ./.github/actions/install-pnpm
- name: Install action dependencies
run: pnpm install --frozen-lockfile --filter @sentry-internal/optional-e2e-gh-action
- name: Report optional E2E results
uses: ./dev-packages/optional-e2e-gh-action
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
mode: report
pr_number: ${{ inputs.pr_number }}
18 changes: 13 additions & 5 deletions dev-packages/optional-e2e-gh-action/action.yml
Original file line number Diff line number Diff line change
@@ -1,15 +1,23 @@
name: 'optional-e2e-gh-action'
description: 'Run the optional E2E tests in their own workflow, wait for them and report failures in a PR comment'
description:
'Run the optional E2E tests in their own workflow and wait for them, or report their results in a PR comment'
inputs:
github_token:
required: true
description: 'a github access token'
mode:
required: false
default: 'dispatch'
description: '`dispatch` to run the tests and wait for them, `report` to report the current run in a PR comment'
commit:
required: true
description: 'The commit that the tarballs were built from'
required: false
description: 'The commit that the tarballs were built from (dispatch mode)'
matrix:
required: true
description: 'The optional E2E test matrix as JSON'
required: false
description: 'The optional E2E test matrix as JSON (dispatch mode)'
pr_number:
required: false
description: 'The PR to report in (report mode)'
runs:
using: 'node24'
main: 'index.mjs'
39 changes: 25 additions & 14 deletions dev-packages/optional-e2e-gh-action/index.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,12 @@ const sleep = ms => new Promise(resolve => setTimeout(resolve, ms));
async function run() {
const octokit = getOctokit(core.getInput('github_token'));
const { repo } = context;

if (core.getInput('mode') === 'report') {
await report(octokit, repo);
return;
}

const pr = context.payload.pull_request;
const correlationId = `${context.runId}-${process.env.GITHUB_RUN_ATTEMPT}`;

Expand Down Expand Up @@ -41,14 +47,20 @@ async function run() {
if (workflowRun.conclusion !== 'success') {
core.warning(`Optional E2E tests ${workflowRun.conclusion}: ${workflowRun.html_url}`);
}
}

if (pr) {
// A failed report must not fail this job, because that marks the PR as failed.
try {
await reportInComment(octokit, repo, pr.number, workflowRun);
} catch (error) {
core.warning(`Could not report the optional E2E results in a PR comment: ${error.message}`);
}
// Runs as the last job of the optional E2E run itself, so a re-run of that run also updates the comment.
async function report(octokit, repo) {
const prNumber = Number(core.getInput('pr_number'));
if (!prNumber) {
return;
}

try {
const { data: workflowRun } = await octokit.rest.actions.getWorkflowRun({ ...repo, run_id: context.runId });
await reportInComment(octokit, repo, prNumber, workflowRun);
} catch (error) {
core.warning(`Could not report the optional E2E results in a PR comment: ${error.message}`);
}
}

Expand Down Expand Up @@ -80,18 +92,21 @@ async function waitForRun(octokit, repo, workflowId, correlationId) {
return workflowRun;
}

// Keeps one comment per PR up to date, so new pushes do not add more comments. The comment is only
// created when a check fails.
// Keeps one comment per PR up to date, so new pushes and re-runs do not add more comments.
async function reportInComment(octokit, repo, prNumber, workflowRun) {
const jobs = await octokit.paginate(octokit.rest.actions.listJobsForWorkflowRun, {
...repo,
run_id: workflowRun.id,
filter: 'latest',
per_page: 100,
});
const ran = jobs.filter(({ conclusion }) => conclusion !== 'skipped');
// The report job itself is still in progress.
const ran = jobs.filter(({ status, conclusion }) => status === 'completed' && conclusion !== 'skipped');
const failing = ran.filter(({ conclusion }) => conclusion !== 'success');
const successful = ran.filter(({ conclusion }) => conclusion === 'success');
if (!ran.length) {
return;
}

const comments = await octokit.paginate(octokit.rest.issues.listComments, {
...repo,
Expand All @@ -102,10 +117,6 @@ async function reportInComment(octokit, repo, prNumber, workflowRun) {
({ user, body }) => user?.login === 'github-actions[bot]' && body?.startsWith(COMMENT_MARKER),
);

if (!failing.length && !previousComment) {
return;
}

const counts = [
failing.length && `${failing.length} failing`,
successful.length && `${successful.length} successful`,
Expand Down
Loading