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
21 changes: 0 additions & 21 deletions .github/workflows/e2e-request.yml

This file was deleted.

7 changes: 3 additions & 4 deletions .github/workflows/fallow.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ jobs:
timeout-minutes: 10
permissions:
contents: read
pull-requests: write
pull-requests: read
checks: write
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
Expand All @@ -25,14 +25,13 @@ jobs:
persist-credentials: false

- name: Setup Vite+ and install dependencies
uses: ./
uses: $/.
with:
node-version-file: .node-version

- name: Audit pull request
uses: fallow-rs/fallow@fccff887da0d83db1711379e0a3696dfc2460fdd # v3.33.1
with:
command: audit
# Fork and Dependabot PRs keep annotations and the job summary.
comment: ${{ github.event.pull_request.head.repo.full_name == github.repository && github.actor != 'dependabot[bot]' }}
comment: false
branded-token: false
257 changes: 70 additions & 187 deletions .github/workflows/gitlab-e2e.yml
Original file line number Diff line number Diff line change
@@ -1,13 +1,18 @@
name: GitLab E2E
run-name: "GitLab E2E: ${{ github.event.pull_request.head.sha || inputs.setup_ref || github.sha }} / ${{ inputs.suite || 'full' }}"

on:
workflow_run:
workflows: [GitLab E2E request]
types: [completed]
pull_request:
branches: [main]
types: [labeled]
workflow_dispatch:
inputs:
pull_request:
description: "Optional PR number. Requires setup_ref to be its reviewed head SHA."
required: false
default: ""
setup_ref:
description: "Enter an exact setup-vp commit SHA or release tag. If empty, the workflow uses this commit."
description: "Exact commit SHA or release tag. If empty, test this workflow commit."
required: false
default: ""
suite:
Expand All @@ -28,128 +33,94 @@ jobs:
gitlab-e2e:
name: GitLab E2E
if: >-
github.event_name == 'workflow_dispatch' ||
(github.event_name == 'workflow_run' &&
github.event.workflow_run.event == 'pull_request' &&
github.event.workflow_run.conclusion == 'success' &&
github.event.workflow_run.path == '.github/workflows/e2e-request.yml')
(github.event_name == 'workflow_dispatch' && github.ref == 'refs/heads/main') ||
(github.event_name == 'pull_request' && github.event.action == 'labeled' &&
github.event.label.name == 'run-e2e' &&
github.event.pull_request.head.repo.full_name == github.repository)
runs-on: ubuntu-latest
timeout-minutes: 35
outputs:
pr_number: ${{ steps.parameters.outputs.pr_number }}
setup_vp_ref: ${{ steps.parameters.outputs.setup_vp_ref }}
suite: ${{ steps.parameters.outputs.suite }}
vite_plus_version: ${{ steps.parameters.outputs.vite_plus_version }}
pipeline_url: ${{ steps.trigger.outputs.pipeline_url }}
# Keep this privileged job API-only: no PR checkout, artifacts, or caches.
# Fork PRs use manual dispatch on main. Never check out or execute PR files.
steps:
- name: Resolve test parameters
id: parameters
env:
EVENT_NAME: ${{ github.event_name }}
REQUEST_EVENT: ${{ github.event.workflow_run.event }}
REQUEST_CONCLUSION: ${{ github.event.workflow_run.conclusion }}
REQUEST_PATH: ${{ github.event.workflow_run.path }}
REQUEST_TITLE: ${{ github.event.workflow_run.display_title }}
REQUEST_ACTOR: ${{ github.event.workflow_run.actor.login }}
REQUEST_HEAD_SHA: ${{ github.event.workflow_run.head_sha }}
REQUEST_HEAD_REPOSITORY: ${{ github.event.workflow_run.head_repository.full_name }}
MANUAL_SETUP_REF: ${{ inputs.setup_ref }}
MANUAL_SUITE: ${{ inputs.suite }}
MANUAL_VITE_PLUS_VERSION: ${{ inputs.vite_plus_version }}
EVENT_ACTION: ${{ github.event.action }}
EVENT_LABEL: ${{ github.event.label.name }}
LABEL_ACTOR: ${{ github.event.sender.login }}
PR_NUMBER: ${{ github.event.pull_request.number || inputs.pull_request }}
SETUP_REF: ${{ github.event.pull_request.head.sha || inputs.setup_ref }}
TEST_SUITE: ${{ inputs.suite }}
VITE_PLUS_VERSION: ${{ inputs.vite_plus_version }}
GH_TOKEN: ${{ github.token }}
run: |
set -euo pipefail

should_run=false
setup_vp_ref=""
suite=full
vite_plus_version=latest
report_pr_number=""
skip_reason='GitLab E2E requires a successful run-e2e label request for a PR or a manual workflow_dispatch run.'

resolve_pr_request() {
local request_pattern='^PR #([1-9][0-9]*): labeled run-e2e at ([0-9a-f]{40})$'
if [ "$EVENT_NAME" != "workflow_run" ] || [ "$REQUEST_EVENT" != "pull_request" ] ||
[ "$REQUEST_CONCLUSION" != "success" ] ||
[ "$REQUEST_PATH" != ".github/workflows/e2e-request.yml" ] ||
! [[ "$REQUEST_TITLE" =~ $request_pattern ]]; then
return
fi
case "$EVENT_NAME" in
workflow_dispatch) ;;
pull_request)
if [ "$EVENT_ACTION" != labeled ] || [ "$EVENT_LABEL" != run-e2e ] ||
! [[ "$PR_NUMBER" =~ ^[1-9][0-9]*$ && "$SETUP_REF" =~ ^[0-9a-f]{40}$ ]]; then
echo "::error::GitLab E2E requires a run-e2e label event with an exact PR head SHA."
exit 1
fi
# Check the original labeler, including when someone reruns this job.
permission="$(gh api "repos/${GITHUB_REPOSITORY}/collaborators/${LABEL_ACTOR}/permission" --jq '.permission')"
case "$permission" in
admin | write) ;;
*) echo "::error::Adding run-e2e requires repository write access."; exit 1 ;;
esac
TEST_SUITE=full
VITE_PLUS_VERSION=latest
;;
*) echo "::error::Unsupported GitLab E2E event."; exit 1 ;;
esac

setup_vp_ref="${SETUP_REF:-$GITHUB_SHA}"
suite="${TEST_SUITE:-full}"
vite_plus_version="${VITE_PLUS_VERSION:-latest}"
ref_pattern='^([0-9a-f]{40}|v[0-9]+\.[0-9]+\.[0-9]+([-+][0-9A-Za-z.-]+)?)$'
if ! [[ "$setup_vp_ref" =~ $ref_pattern ]]; then
echo "::error::setup_ref must be an exact commit SHA or release tag."
exit 1
fi
case "$suite" in
full | required) ;;
*) echo "::error::Select the full or required suite."; exit 1 ;;
esac
if [[ "$vite_plus_version" == *$'\n'* || "$vite_plus_version" == *$'\r'* ]]; then
echo "::error::vite_plus_version must be a single line."
exit 1
fi

local pr_number="${BASH_REMATCH[1]}"
if [ "${BASH_REMATCH[2]}" != "$REQUEST_HEAD_SHA" ]; then
echo "::error::The request title does not match the workflow run's head SHA."
if [ -n "$PR_NUMBER" ]; then
if ! [[ "$PR_NUMBER" =~ ^[1-9][0-9]*$ && "$SETUP_REF" =~ ^[0-9a-f]{40}$ ]]; then
echo "::error::Enter a valid PR number and its reviewed 40-character head SHA."
exit 1
fi

# Check the original labeler's access, even on reruns.
# GitHub maps the maintain role to write.
local permission
permission="$(gh api "repos/${GITHUB_REPOSITORY}/collaborators/${REQUEST_ACTOR}/permission" --jq '.permission')"
case "$permission" in
admin | write) ;;
*)
echo "::error::Adding run-e2e requires repository write access to approve a test run."
exit 1
;;
esac

# Compare Git blobs to reject altered request triggers or run names.
local workflow_url="repos/${GITHUB_REPOSITORY}/contents/${REQUEST_PATH}"
local trusted_blob request_blob
trusted_blob="$(gh api "${workflow_url}?ref=${GITHUB_SHA}" --jq '.sha')"
if ! request_blob="$(gh api "${workflow_url}?ref=${REQUEST_HEAD_SHA}" --jq '.sha')" ||
[ "$request_blob" != "$trusted_blob" ]; then
echo "::error::The PR must include e2e-request.yml unchanged from main. Update the branch, then remove and re-add run-e2e."
pull_request="$(gh api "repos/${GITHUB_REPOSITORY}/pulls/${PR_NUMBER}")"
if ! jq -e --arg sha "$SETUP_REF" --arg repo "$GITHUB_REPOSITORY" \
'.state == "open" and .head.sha == $sha and .head.repo != null and
.base.repo.full_name == $repo and .base.ref == "main"' \
<<< "$pull_request" > /dev/null; then
echo "::error::The PR changed or no longer targets main. Review its current head and start a new run."
exit 1
fi

# Fork runs can have an empty workflow_run.pull_requests array.
# Resolve the PR from the verified title and cross-check its head.
local pull_request
pull_request="$(gh api "repos/${GITHUB_REPOSITORY}/pulls/${pr_number}")"
if ! jq -e --arg sha "$REQUEST_HEAD_SHA" --arg head_repo "$REQUEST_HEAD_REPOSITORY" --arg repo "$GITHUB_REPOSITORY" \
'.state == "open" and .head.sha == $sha and .head.repo.full_name == $head_repo and
.base.repo.full_name == $repo and .base.ref == "main" and any(.labels[]; .name == "run-e2e")' \
if [ "$EVENT_NAME" = pull_request ] && ! jq -e --arg repo "$GITHUB_REPOSITORY" \
'.head.repo.full_name == $repo and any(.labels[]; .name == "run-e2e")' \
<<< "$pull_request" > /dev/null; then
skip_reason='This approval is stale or does not match the PR: check its head, base, and run-e2e label. Review the current commit, then remove and re-add run-e2e to test it.'
return
echo "::error::Label requests require a same-repository PR with run-e2e. Use manual dispatch on main for forks."
exit 1
fi

should_run=true
setup_vp_ref="$REQUEST_HEAD_SHA"
report_pr_number="$pr_number"
}

if [ "$EVENT_NAME" = "workflow_dispatch" ]; then
should_run=true
setup_vp_ref="${MANUAL_SETUP_REF:-$GITHUB_SHA}"
suite="${MANUAL_SUITE:-full}"
vite_plus_version="${MANUAL_VITE_PLUS_VERSION:-latest}"
else
resolve_pr_request
fi

{
echo "should_run=$should_run"
echo "setup_vp_ref=$setup_vp_ref"
echo "suite=$suite"
echo "vite_plus_version=$vite_plus_version"
echo "pr_number=$report_pr_number"
} >> "$GITHUB_OUTPUT"

if [ "$should_run" = "false" ]; then
echo "$skip_reason"
{
echo "### GitLab E2E"
echo
echo "$skip_reason"
} >> "$GITHUB_STEP_SUMMARY"
fi

- name: Trigger GitLab pipeline
if: steps.parameters.outputs.should_run == 'true'
id: trigger
env:
GITLAB_PROJECT_ID: "85578524"
Expand Down Expand Up @@ -193,7 +164,6 @@ jobs:
} >> "$GITHUB_STEP_SUMMARY"

- name: Wait for GitLab pipeline
if: steps.parameters.outputs.should_run == 'true'
env:
GITLAB_PROJECT_ID: "85578524"
GITLAB_PIPELINE_ID: ${{ steps.trigger.outputs.pipeline_id }}
Expand Down Expand Up @@ -246,90 +216,3 @@ jobs:
fi
echo "::error::GitLab pipeline finished with status $final_status."
exit 1

report-result:
name: Report GitLab E2E result
needs: gitlab-e2e
if: always() && needs.gitlab-e2e.outputs.pr_number != ''
runs-on: ubuntu-latest
permissions:
pull-requests: write
concurrency:
group: gitlab-e2e-comment-${{ needs.gitlab-e2e.outputs.pr_number }}
cancel-in-progress: false
steps:
- name: Update PR comment
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
env:
PR_NUMBER: ${{ needs.gitlab-e2e.outputs.pr_number }}
SETUP_VP_REF: ${{ needs.gitlab-e2e.outputs.setup_vp_ref }}
TEST_SUITE: ${{ needs.gitlab-e2e.outputs.suite }}
VITE_PLUS_VERSION: ${{ needs.gitlab-e2e.outputs.vite_plus_version }}
PIPELINE_URL: ${{ needs.gitlab-e2e.outputs.pipeline_url }}
RESULT: ${{ needs.gitlab-e2e.result }}
with:
script: |
const { PR_NUMBER, SETUP_VP_REF, TEST_SUITE, VITE_PLUS_VERSION, PIPELINE_URL, RESULT } = process.env;
const issue = { ...context.repo, issue_number: Number(PR_NUMBER) };
const { data: pr } = await github.rest.pulls.get({ ...context.repo, pull_number: issue.issue_number });
if (pr.head.sha !== SETUP_VP_REF) {
core.info('The PR head changed; skip this result.');
return;
}

const marker = '<!-- setup-vp-gitlab-e2e -->';
const comments = await github.paginate(github.rest.issues.listComments, { ...issue, per_page: 100 });
let previous;
for (const comment of comments) {
if (!comment.body?.startsWith(marker)) continue;
if (comment.user?.login === 'github-actions[bot]') {
previous = comment;
break;
}
// Reuse a result posted by a maintainer, including before automation was added.
if (!comment.user) continue;
let permission;
try {
const { data } = await github.rest.repos.getCollaboratorPermissionLevel({
...context.repo, username: comment.user.login,
});
permission = data.permission;
} catch (error) {
if (error.status === 404) continue;
throw error;
}
if (permission === 'admin' || permission === 'write') {
previous = comment;
break;
}
}

const attempt = Number(process.env.GITHUB_RUN_ATTEMPT);
const previousRun = previous?.body.match(/<!-- setup-vp-gitlab-e2e-run:(\d+):(\d+) -->/);
if (previousRun && (Number(previousRun[1]) > context.runId ||
(Number(previousRun[1]) === context.runId && Number(previousRun[2]) > attempt))) {
core.info('A newer run already reported its result.');
return;
}

let title;
if (RESULT === 'success') title = '✅ GitLab E2E passed';
else if (RESULT === 'cancelled') title = '⚠️ GitLab E2E run cancelled';
else if (!PIPELINE_URL) title = '❌ GitLab E2E could not start';
else title = '❌ GitLab E2E did not complete successfully';

const runUrl = `${context.serverUrl}/${context.repo.owner}/${context.repo.repo}/actions/runs/${context.runId}/attempts/${attempt}`;
const links = [PIPELINE_URL && `[GitLab pipeline](${PIPELINE_URL})`, `[GitHub Actions run](${runUrl})`].filter(Boolean);
const body = [
marker,
`<!-- setup-vp-gitlab-e2e-run:${context.runId}:${attempt} -->`,
'', `### ${title}`, '',
`Commit: \`${SETUP_VP_REF}\` `,
`Suite: \`${TEST_SUITE}\` · Vite+ version: \`${VITE_PLUS_VERSION}\``,
'', links.join(' · '),
].join('\n');
if (previous) {
await github.rest.issues.updateComment({ ...context.repo, comment_id: previous.id, body });
} else {
await github.rest.issues.createComment({ ...issue, body });
}
Loading
Loading