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
4 changes: 4 additions & 0 deletions .github/actionlint.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,7 @@ paths:
ignore:
- 'unexpected key "cache-mode" for "workflow" section'
- 'cannot save caches with effective cache-mode "read"'
.github/workflows/caller-platform-run.yaml:
ignore:
- 'unexpected key "cache-mode" for "workflow" section'
- 'cannot save caches with effective cache-mode "read"'
36 changes: 31 additions & 5 deletions .github/workflows/caller-platform-command.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -18,18 +18,20 @@ jobs:
checks: write
pull-requests: write
outputs:
should-run: ${{ steps.command.outputs.should-run }}
should-run: ${{ steps.command.outputs.should-run == 'true' && steps.contract.outcome == 'success' }}
filter: ${{ steps.command.outputs.filter }}
focus: ${{ steps.command.outputs.focus }}
is-fork: ${{ steps.command.outputs.is-fork }}
head-ref: ${{ steps.command.outputs.head-ref }}
base-ref: ${{ steps.command.outputs.base-ref }}
head-sha: ${{ steps.command.outputs.head-sha }}
key: ${{ steps.command.outputs.concurrency-key }}
check-run-id: ${{ steps.command.outputs.check-run-id }}

steps:
- name: Parse command and open check
id: command
uses: loft-sh/github-actions/.github/actions/comment-triggered-check@comment-triggered-check/v1
uses: loft-sh/github-actions/.github/actions/comment-triggered-check@80d63f2a76ef1b6bd2e4d2e07cdd465c04594303 # github-actions#276 head until comment-triggered-check/v1 moves
with:
mode: start
command: /test-platform-e2e
Expand All @@ -38,10 +40,32 @@ jobs:
comment-body: ${{ github.event.comment.body }}
comment-author: ${{ github.event.comment.user.login }}
author-association: ${{ github.event.comment.author_association }}
allow-forks: true
pr-number: ${{ github.event.issue.number }}
run-id: ${{ github.run_id }}
server-url: ${{ github.server_url }}

# The contract lives on the workflow that will run: the PR head for
# same-repository PRs, the target branch for forks.
- name: Verify the branch supports command dispatch
id: contract
if: ${{ steps.command.outputs.should-run == 'true' }}
continue-on-error: true
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
CONTRACT_REF: ${{ steps.command.outputs.is-fork == 'true' && steps.command.outputs.base-ref || steps.command.outputs.head-sha }}
run: gh api "repos/${GITHUB_REPOSITORY}/contents/.github/e2e-command-contract-v2?ref=${CONTRACT_REF}" >/dev/null

- name: Close the check if the branch has no contract
if: ${{ always() && steps.command.outputs.should-run == 'true' && steps.contract.outcome != 'success' }}
uses: loft-sh/github-actions/.github/actions/comment-triggered-check@80d63f2a76ef1b6bd2e4d2e07cdd465c04594303 # github-actions#276 head until comment-triggered-check/v1 moves
with:
mode: finish
check-run-id: ${{ steps.command.outputs.check-run-id }}
report-conclusion: neutral
summary: This branch does not support /test-platform-e2e.
details-url: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}

- name: Explain refusal
if: ${{ steps.command.outputs.matched == 'true' && steps.command.outputs.should-run != 'true' }}
uses: loft-sh/github-actions/.github/actions/sticky-pr-comment@sticky-pr-comment/v1
Expand All @@ -64,7 +88,9 @@ jobs:
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
GH_REPO: ${{ github.repository }}
HEAD_REF: ${{ needs.prepare.outputs.head-ref }}
# Same-repository PRs run their branch's workflow. Forks use the target
# branch's workflow because their branch does not exist in this repo.
WORKFLOW_REF: ${{ needs.prepare.outputs.is-fork == 'true' && needs.prepare.outputs.base-ref || needs.prepare.outputs.head-ref }}
HEAD_SHA: ${{ needs.prepare.outputs.head-sha }}
FILTER: ${{ needs.prepare.outputs.filter }}
FOCUS: ${{ needs.prepare.outputs.focus }}
Expand All @@ -78,7 +104,7 @@ jobs:
continue-on-error: true
run: |
gh workflow run caller-platform-run.yaml \
--ref "$HEAD_REF" \
--ref "$WORKFLOW_REF" \
-f "ginkgo-label=$FILTER" \
-f "ginkgo-focus=$FOCUS" \
-f "head-sha=$HEAD_SHA" \
Expand All @@ -88,7 +114,7 @@ jobs:

- name: Close check if dispatch failed
if: ${{ always() && steps.dispatch.outcome == 'failure' }}
uses: loft-sh/github-actions/.github/actions/comment-triggered-check@comment-triggered-check/v1
uses: loft-sh/github-actions/.github/actions/comment-triggered-check@80d63f2a76ef1b6bd2e4d2e07cdd465c04594303 # github-actions#276 head until comment-triggered-check/v1 moves
with:
mode: finish
check-run-id: ${{ needs.prepare.outputs.check-run-id }}
Expand Down
31 changes: 27 additions & 4 deletions .github/workflows/caller-platform-run.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,9 @@ on:

permissions: {}

# A fork run can restore caches but never save them.
cache-mode: read

jobs:
suite:
name: Mock Platform suite
Expand All @@ -41,22 +44,42 @@ jobs:
outputs:
check-conclusion: ${{ steps.conclusion.outputs.check-conclusion }}
steps:
# The workflow comes from a trusted branch, the code from the captured SHA.
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
ref: ${{ inputs.head-sha }}
persist-credentials: false

- name: Verify head SHA
env:
EXPECTED_HEAD_SHA: ${{ inputs.head-sha }}
ACTUAL_HEAD_SHA: ${{ github.sha }}
run: |
[[ "$EXPECTED_HEAD_SHA" == "$ACTUAL_HEAD_SHA" ]] || exit 1
ACTUAL_HEAD_SHA="$(git rev-parse HEAD)"
if [[ "$EXPECTED_HEAD_SHA" != "$ACTUAL_HEAD_SHA" ]]; then
echo "::error::expected ${EXPECTED_HEAD_SHA}, checked out ${ACTUAL_HEAD_SHA}"
exit 1
fi

- name: Simulate suite
env:
FILTER: ${{ inputs.ginkgo-label }}
FOCUS: ${{ inputs.ginkgo-focus }}
run: |
sleep 20
echo "tested commit: $(git log -1 --format='%H %s')"
if [[ -f fork-marker.txt ]]; then echo "fork marker: $(cat fork-marker.txt)"; fi
sleep 60
printf 'filter=%s\nfocus=%s\n' "$FILTER" "$FOCUS"
[[ "$FILTER" != *fail* ]] || exit 1

# Expected to be skipped by cache-mode: read. repro/fork-command checks
# afterwards that no cache with this key exists.
- name: Try to save a cache
continue-on-error: true
uses: actions/cache/save@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
with:
path: fork-marker.txt
key: fork-cache-probe-platform-${{ github.run_id }}

- name: Derive result
id: conclusion
if: ${{ !cancelled() }}
Expand All @@ -81,7 +104,7 @@ jobs:
checks: write
steps:
- name: Complete check
uses: loft-sh/github-actions/.github/actions/comment-triggered-check@comment-triggered-check/v1
uses: loft-sh/github-actions/.github/actions/comment-triggered-check@80d63f2a76ef1b6bd2e4d2e07cdd465c04594303 # github-actions#276 head until comment-triggered-check/v1 moves
with:
mode: finish
check-run-id: ${{ inputs.check-run-id }}
Expand Down
8 changes: 5 additions & 3 deletions repro/fork-command/README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# Fork `/test-e2e` scenarios

Live checks for running `/test-e2e` on pull requests from forks (DEVOPS-1541).
The caller workflows here mirror `vcluster-pro#2478` with stand-in suites:
The caller workflows here mirror `vcluster-pro#2478` (two trees) and the matching loft-enterprise change (`caller-platform-*`, one tree) with stand-in suites:

- Fork commands dispatch the target branch's workflow and check out the PR SHA
captured when the comment was posted.
Expand All @@ -10,7 +10,7 @@ The caller workflows here mirror `vcluster-pro#2478` with stand-in suites:
- The contract check runs on the workflow that will run, so a branch without
`.github/e2e-command-contract-v2` is refused before dispatch.

`caller-comment-triggered-check.yaml` and both suite runs pin
The command callers (`caller-comment-triggered-check.yaml`, `caller-platform-command.yaml`) and their suite runs pin
`comment-triggered-check` to the `loft-sh/github-actions#276` head. Move them
back to `@comment-triggered-check/v1` once that tag is advanced.

Expand All @@ -35,7 +35,9 @@ It leaves `release-no-contract` in place for the next run.
| 4 | Push to the fork branch after commenting | The check on the commented commit succeeds. The new commit gets none |
| 5 | Same-repository PR | Both trees succeed |
| 6 | Fork PR into `release-no-contract` | Both checks are `neutral` without a dispatch |
| 7 | After the runs | No `fork-cache-probe` cache exists |
| 7 | `/test-platform-e2e` on two fork PRs (single-check harness, mirrors loft-enterprise) | Both succeed |
| 8 | `/test-platform-e2e` on the fork PR into `release-no-contract` | `neutral` without a dispatch |
| 9 | After the runs | No `fork-cache-probe` cache exists |

A commenter without write access is not scripted, because it needs a second
account. Check it by hand: the command should reply with `insufficient-permission`.
13 changes: 12 additions & 1 deletion repro/fork-command/run.sh
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,10 @@ gh pr comment "$PR_A" -R "$UPSTREAM" --body "/test-e2e fork-repeat --target pro"
gh pr comment "$PR_PUSH" -R "$UPSTREAM" --body "/test-e2e fork-push --target oss" >/dev/null
gh pr comment "$PR_SAME" -R "$UPSTREAM" --body "/test-e2e same-repo" >/dev/null
gh pr comment "$PR_OLD" -R "$UPSTREAM" --body "/test-e2e fork-old" >/dev/null
# The single-check Platform harness, mirroring loft-enterprise.
gh pr comment "$PR_A" -R "$UPSTREAM" --body "/test-platform-e2e platform-smoke" >/dev/null
gh pr comment "$PR_B" -R "$UPSTREAM" --body "/test-platform-e2e platform-smoke" >/dev/null
gh pr comment "$PR_OLD" -R "$UPSTREAM" --body "/test-platform-e2e platform-old" >/dev/null

log "Pushing to the fork-push PR once its check exists"
deadline=$((SECONDS + TIMEOUT))
Expand Down Expand Up @@ -148,7 +152,14 @@ log "6. Fork PR into a branch without the contract is refused before dispatch"
wait_checks "$SHA_OLD" "e2e-pro: fork-old" 1 && expect neutral "$(checks "$SHA_OLD" "e2e-pro: fork-old")" "old-branch pro"
wait_checks "$SHA_OLD" "e2e-oss: fork-old" 1 && expect neutral "$(checks "$SHA_OLD" "e2e-oss: fork-old")" "old-branch oss"

log "7. cache-mode: read blocked every cache save"
log "7. Platform: fork PRs run, and the same request on two PRs does not cancel"
wait_checks "$SHA_A" "e2e-platform: platform-smoke" 1 && expect success "$(checks "$SHA_A" "e2e-platform: platform-smoke")" "platform fork A"
wait_checks "$SHA_B" "e2e-platform: platform-smoke" 1 && expect success "$(checks "$SHA_B" "e2e-platform: platform-smoke")" "platform fork B"

log "8. Platform: fork PR into a branch without the contract is refused"
wait_checks "$SHA_OLD" "e2e-platform: platform-old" 1 && expect neutral "$(checks "$SHA_OLD" "e2e-platform: platform-old")" "platform old branch"

log "9. cache-mode: read blocked every cache save"
expect 0 "$(gh api "repos/${UPSTREAM}/actions/caches?key=fork-cache-probe" --jq .total_count)" "fork-cache-probe caches"

log "Done: ${FAILED} failed"
Expand Down
Loading