|
| 1 | +name: SPM dependency pin |
| 2 | + |
| 3 | +# scripts/{bash,zsh,fish}/spm.sh generate a throwaway Package.swift that depends on |
| 4 | +# this repository. It used to track `branch: "main"`, so every scan resolved |
| 5 | +# whatever HEAD of main was at that moment (DEVA11Y-477 / F-005, CWE-829). It is |
| 6 | +# now pinned to an immutable `revision:` SHA, and this workflow keeps that pin |
| 7 | +# current without going back to a mutable ref: |
| 8 | +# |
| 9 | +# bump — when plugin code (Package.swift / Plugins/) lands on main, runs |
| 10 | +# .github/scripts/update-spm-pin.sh and opens (or refreshes) a PR moving |
| 11 | +# the pin to that commit. The bump goes through review like any other |
| 12 | +# change, so a bad commit on main does not reach users automatically. |
| 13 | +# Bump PRs only touch scripts/, so merging one never moves the pin again. |
| 14 | +# guard — on PRs touching scripts/, fails if any spm.sh stops pinning to a full |
| 15 | +# 40-char revision (e.g. a revert back to `branch: "main"`). |
| 16 | +# |
| 17 | +# PRs opened with the default GITHUB_TOKEN do not trigger other workflows, so the |
| 18 | +# required checks will not start on them on their own. Set a PIN_BUMP_TOKEN secret |
| 19 | +# (GitHub App installation token or fine-grained PAT with contents + pull-requests |
| 20 | +# write) to have them run; without it, close/reopen the bump PR to start checks. |
| 21 | + |
| 22 | +on: |
| 23 | + push: |
| 24 | + branches: [main] |
| 25 | + paths: |
| 26 | + - 'Package.swift' |
| 27 | + - 'Plugins/**' |
| 28 | + pull_request: |
| 29 | + paths: |
| 30 | + - 'scripts/**' |
| 31 | + - '.github/scripts/update-spm-pin.sh' |
| 32 | + - '.github/workflows/spm-pin-bump.yml' |
| 33 | + schedule: |
| 34 | + - cron: '0 6 * * 1' # weekly safety net in case a push run was missed |
| 35 | + workflow_dispatch: |
| 36 | + |
| 37 | +permissions: |
| 38 | + contents: read |
| 39 | + |
| 40 | +jobs: |
| 41 | + bump: |
| 42 | + name: Open PR bumping the SPM pin |
| 43 | + if: github.event_name != 'pull_request' |
| 44 | + runs-on: ubuntu-latest |
| 45 | + timeout-minutes: 5 |
| 46 | + permissions: |
| 47 | + contents: write |
| 48 | + pull-requests: write |
| 49 | + concurrency: |
| 50 | + group: spm-pin-bump |
| 51 | + cancel-in-progress: false |
| 52 | + env: |
| 53 | + BUMP_BRANCH: ci/spm-pin-bump |
| 54 | + GH_TOKEN: ${{ secrets.PIN_BUMP_TOKEN || github.token }} |
| 55 | + steps: |
| 56 | + - name: Checkout main (full history to find the latest plugin commit) |
| 57 | + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 |
| 58 | + with: |
| 59 | + ref: main |
| 60 | + fetch-depth: 0 |
| 61 | + token: ${{ secrets.PIN_BUMP_TOKEN || github.token }} |
| 62 | + |
| 63 | + - name: Update pin in spm.sh scripts and sidecars |
| 64 | + id: pin |
| 65 | + run: | |
| 66 | + set -euo pipefail |
| 67 | + old=$(grep -oE 'AccessibilityDevTools\.git", revision: "[0-9a-f]{40}"' scripts/bash/spm.sh \ |
| 68 | + | grep -oE '[0-9a-f]{40}' || true) |
| 69 | + new=$(.github/scripts/update-spm-pin.sh) |
| 70 | + echo "old=${old}" >> "$GITHUB_OUTPUT" |
| 71 | + echo "new=${new}" >> "$GITHUB_OUTPUT" |
| 72 | + if git diff --quiet; then |
| 73 | + echo "Pin already at ${new}; nothing to do." |
| 74 | + echo "changed=false" >> "$GITHUB_OUTPUT" |
| 75 | + else |
| 76 | + echo "changed=true" >> "$GITHUB_OUTPUT" |
| 77 | + fi |
| 78 | +
|
| 79 | + - name: Push bump branch and open/update PR |
| 80 | + if: steps.pin.outputs.changed == 'true' |
| 81 | + env: |
| 82 | + OLD: ${{ steps.pin.outputs.old }} |
| 83 | + NEW: ${{ steps.pin.outputs.new }} |
| 84 | + run: | |
| 85 | + set -euo pipefail |
| 86 | + short="${NEW:0:12}" |
| 87 | + git config user.name 'github-actions[bot]' |
| 88 | + git config user.email '41898282+github-actions[bot]@users.noreply.github.com' |
| 89 | + git switch -C "$BUMP_BRANCH" |
| 90 | + git commit -qam "chore(spm): pin AccessibilityDevTools dependency to ${short} (DEVA11Y-477)" |
| 91 | + # The bump branch is bot-owned and always rebuilt from main. |
| 92 | + git push --force origin "HEAD:refs/heads/${BUMP_BRANCH}" |
| 93 | +
|
| 94 | + { |
| 95 | + echo "Moves the \`revision:\` pin in the Package.swift generated by \`scripts/{bash,zsh,fish}/spm.sh\` to \`${NEW}\`, the latest commit on \`main\` that changed the plugin, and regenerates the \`.sha256\` self-update sidecars." |
| 96 | + echo |
| 97 | + if [ -n "$OLD" ]; then |
| 98 | + echo "Plugin changes since the previous pin \`${OLD:0:12}\`:" |
| 99 | + echo |
| 100 | + echo '```' |
| 101 | + git log --first-parent --format='%h %s' "${OLD}..${NEW}" -- Package.swift Plugins |
| 102 | + echo '```' |
| 103 | + echo |
| 104 | + fi |
| 105 | + echo "Review those changes before merging: once merged, every \`spm.sh\` scan resolves the plugin at this commit." |
| 106 | + echo |
| 107 | + echo "Opened automatically by \`.github/workflows/spm-pin-bump.yml\` (DEVA11Y-477)." |
| 108 | + } > "$RUNNER_TEMP/pr-body.md" |
| 109 | +
|
| 110 | + pr=$(gh pr list --head "$BUMP_BRANCH" --base main --state open --json number --jq '.[0].number // empty') |
| 111 | + if [ -n "$pr" ]; then |
| 112 | + gh pr edit "$pr" --title "chore(spm): pin AccessibilityDevTools dependency to ${short}" --body-file "$RUNNER_TEMP/pr-body.md" |
| 113 | + echo "Updated PR #${pr}" |
| 114 | + else |
| 115 | + gh pr create --base main --head "$BUMP_BRANCH" \ |
| 116 | + --title "chore(spm): pin AccessibilityDevTools dependency to ${short}" \ |
| 117 | + --body-file "$RUNNER_TEMP/pr-body.md" |
| 118 | + fi |
| 119 | +
|
| 120 | + guard: |
| 121 | + name: spm.sh pins a full commit SHA |
| 122 | + if: github.event_name == 'pull_request' |
| 123 | + runs-on: ubuntu-latest |
| 124 | + timeout-minutes: 5 |
| 125 | + steps: |
| 126 | + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 |
| 127 | + |
| 128 | + - name: Require revision pin in every spm.sh |
| 129 | + run: | |
| 130 | + set -uo pipefail |
| 131 | + status=0 |
| 132 | + for script in scripts/bash/spm.sh scripts/zsh/spm.sh scripts/fish/spm.sh; do |
| 133 | + if grep -Eq '\.package\(url: "https://github\.com/browserstack/AccessibilityDevTools\.git", revision: "[0-9a-f]{40}"\)' "$script"; then |
| 134 | + echo "OK $script" |
| 135 | + else |
| 136 | + echo "FAILED $script must pin AccessibilityDevTools with revision: \"<40-char sha>\" (DEVA11Y-477); run .github/scripts/update-spm-pin.sh" |
| 137 | + status=1 |
| 138 | + fi |
| 139 | + done |
| 140 | + exit "$status" |
0 commit comments