Promote commit to viable/strict #31
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Promote commit to viable/strict | |
| # Grants a commit eligibility for viable/strict by pushing a | |
| # `ciflow/trunk/<sha>` tag at it, which: | |
| # 1. Runs `pull.yml` / `trunk.yml` against that commit with | |
| # ``is-full-run = true``, so every gated job runs regardless of the | |
| # path filter. | |
| # 2. Runs `viable-strict-gate.yml`, whose presence is what | |
| # `update-viablestrict` requires before it will advance. | |
| # | |
| # This runs on a schedule, because landing a commit does not make it | |
| # eligible on its own. Without a periodic promotion the tip of main | |
| # would sit outside viable/strict until somebody promoted it by hand. | |
| # | |
| # The schedule includes a tick several hours before the nightly branch | |
| # is cut, so the last commits of a quiet night still have time to run | |
| # full CI and reach that day's nightly build. | |
| # | |
| # Can also be dispatched by hand for a specific commit, for example to | |
| # force full CI on one commit while bisecting a regression. Note that | |
| # promoting a commit that is only on a release branch runs CI for it but | |
| # will never advance viable/strict: the updater only considers commits | |
| # reachable from the branch it checks out, which is main. (The | |
| # `main-branch: main` line in update-viablestrict.yml looks like it | |
| # controls this, but the action does not declare that input and passes a | |
| # hardcoded value, so it has no effect either way.) | |
| on: | |
| schedule: | |
| # Every 4 hours. The 08:00 UTC tick is the one that lands ahead of | |
| # the nightly branch cut. | |
| - cron: "0 0,4,8,12,16,20 * * *" | |
| workflow_dispatch: | |
| inputs: | |
| sha: | |
| description: "Full 40-char SHA on main / release/* to promote. Defaults to the tip of main." | |
| required: false | |
| type: string | |
| concurrency: | |
| # One in-flight promotion at a time; safer than racing tag pushes. | |
| group: promote-to-viable-strict | |
| cancel-in-progress: false | |
| jobs: | |
| push-ciflow-tag: | |
| if: ${{ github.repository_owner == 'pytorch' }} | |
| runs-on: ubuntu-22.04 | |
| # GH_PYTORCHBOT_TOKEN is an environment secret, not a repository | |
| # secret, so a job that does not name the environment cannot read it | |
| # and would see an empty string. Same pattern as | |
| # weekly-pytorch-pin-bump.yml. | |
| # | |
| # This environment's deployment branch policy allows `main` only, so | |
| # a hand dispatch from any other ref is refused before the first | |
| # step. That also means this job cannot be exercised from a pull | |
| # request branch; it is first live after merge. | |
| environment: update-commit-hash | |
| permissions: | |
| # Both the checkout and the tag push use the bot token below, so no | |
| # step uses GITHUB_TOKEN at all. Declared read-only rather than | |
| # omitted so that a future step cannot silently inherit write. | |
| contents: read | |
| steps: | |
| # Checked before the tag is pushed rather than after, so a missing | |
| # secret is reported as itself instead of as an opaque checkout | |
| # error or, worse, a tag that silently starts nothing. | |
| - name: Check the bot token is configured | |
| env: | |
| BOT_TOKEN: ${{ secrets.GH_PYTORCHBOT_TOKEN }} | |
| run: | | |
| set -eu | |
| if [ -z "${BOT_TOKEN:-}" ]; then | |
| echo "::error::GH_PYTORCHBOT_TOKEN resolved to an empty string. It is an environment secret on the 'update-commit-hash' environment, so check that this job still declares that environment and that the secret is still present on it. Promotion needs a bot token with contents write access, because a ref pushed with the default GITHUB_TOKEN does not start any workflow run and the tag would do nothing." | |
| exit 1 | |
| fi | |
| - uses: actions/checkout@v4 | |
| with: | |
| fetch-depth: 0 | |
| # A ref pushed with the default GITHUB_TOKEN does not start any | |
| # workflow run, which would leave the tag below doing nothing. | |
| # Push as the bot so the tag triggers full CI and the gate, | |
| # which is the entire point of promoting a commit. | |
| token: ${{ secrets.GH_PYTORCHBOT_TOKEN }} | |
| - name: Validate SHA and push ciflow tag | |
| env: | |
| INPUT_SHA: ${{ inputs.sha }} | |
| run: | | |
| set -euo pipefail | |
| # A scheduled run has no inputs, so promote the tip of main. | |
| SHA="${INPUT_SHA:-}" | |
| if [ -z "$SHA" ]; then | |
| SHA=$(git rev-parse origin/main) | |
| echo "No SHA given; promoting the tip of main: $SHA" | |
| fi | |
| # Reject anything that isn't a full 40-char lowercase hex SHA. | |
| if [[ ! "$SHA" =~ ^[0-9a-f]{40}$ ]]; then | |
| echo "::error::Input must be a full 40-char lowercase hex SHA; got: '$SHA'" | |
| exit 1 | |
| fi | |
| # The commit must exist locally (fetch-depth: 0 above pulls | |
| # everything, but defensively confirm it's an object). | |
| if ! git cat-file -e "$SHA^{commit}" 2>/dev/null; then | |
| echo "::error::SHA $SHA is not a commit in this repository." | |
| exit 1 | |
| fi | |
| # Restrict promotion to commits reachable from a release-track | |
| # branch. Prevents tagging arbitrary commits (PR heads, | |
| # rewritten branches, etc.) that aren't part of the official | |
| # main/release history. | |
| REACHABLE=false | |
| # `git for-each-ref` produces clean refnames (no leading | |
| # whitespace, no `origin/HEAD ->` lines), unlike `git branch -r`. | |
| BRANCHES="main" | |
| while IFS= read -r RELEASE_BRANCH; do | |
| BRANCHES="$BRANCHES $RELEASE_BRANCH" | |
| done < <(git for-each-ref --format='%(refname:lstrip=3)' refs/remotes/origin/release/) | |
| for branch in $BRANCHES; do | |
| if git merge-base --is-ancestor "$SHA" "origin/$branch" 2>/dev/null; then | |
| echo "SHA is reachable from origin/$branch" | |
| REACHABLE=true | |
| break | |
| fi | |
| done | |
| if [ "$REACHABLE" = "false" ]; then | |
| echo "::error::SHA $SHA is not reachable from main or any release/* branch." | |
| exit 1 | |
| fi | |
| # Nothing to promote if viable/strict already contains the | |
| # commit. This is the common case for a scheduled tick that | |
| # finds main unchanged since the last one. | |
| # | |
| # Only applied when we picked the SHA ourselves. Almost all of | |
| # main is already an ancestor of viable/strict, so applying it | |
| # to a hand-dispatched SHA would turn nearly every deliberate | |
| # request into a silent no-op that still reports success. | |
| if [ -z "${INPUT_SHA:-}" ] \ | |
| && git merge-base --is-ancestor "$SHA" origin/viable/strict 2>/dev/null; then | |
| echo "$SHA is already contained in viable/strict; nothing to do." | |
| exit 0 | |
| fi | |
| TAG="ciflow/trunk/$SHA" | |
| # If the tag already exists (e.g. an earlier tick promoted | |
| # this same commit), exit cleanly. This is what keeps repeated | |
| # ticks over a quiet period from re-running CI. | |
| if git ls-remote --tags --exit-code origin "refs/tags/$TAG" >/dev/null 2>&1; then | |
| echo "Tag $TAG already exists on origin; nothing to do." | |
| exit 0 | |
| fi | |
| git config user.name "pytorchbot" | |
| git config user.email "pytorchbot@users.noreply.github.com" | |
| git tag "$TAG" "$SHA" | |
| git push origin "$TAG" | |
| # Only the workflows that list ciflow/trunk/* under `on.push.tags` | |
| # start from this tag. Four of them are in update-viablestrict's | |
| # required set; the other three run but do not gate. `lint` and | |
| # `Build documentation` are required too, and neither has a | |
| # ciflow/trunk trigger, so their rows come from the earlier push | |
| # to main; if either was cancelled on that push, this tag cannot | |
| # revive it. | |
| echo "::notice::Pushed $TAG. Workflow runs started by this tag: pull, trunk, Apple, viable-strict-gate, Windows MSVC Build, Test RISC-V Backend, Test QNN Windows MSVC build. Of those, update-viablestrict only requires pull, trunk, Apple and viable-strict-gate; the other three do not gate advancement. The two remaining required checks, lint and Build documentation, do not start from a ciflow/trunk tag and must already be green from the push to main. Once all six required checks are green, the next update-viablestrict cron (every 30 min) will advance viable/strict." |