Repository navigation
style(plugin): fix import ordering for Enabled re-export #3877
Workflow file for this run
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
| # Test workflow — exercises `cargo xtask release prepare` and the prep-PR | ||
| # flow on a GitHub Actions runner. Designed to graduate to `dev` later | ||
| # (renamed and minus the push trigger), so the inputs and shape match what | ||
| # the eventual `release-dispatch.yml` will expect. | ||
| # | ||
| # Two trigger paths: | ||
| # | ||
| # - `workflow_dispatch` — the future graduation path. Won't actually fire | ||
| # until this file lands on the default branch (`dev`). Keeps the inputs | ||
| # in place so the call shape is locked in. | ||
| # | ||
| # - `push` to `abernix/test-prep-action-*` — the current sandbox. Picks | ||
| # `version` from the branch-name suffix and `dry_run` from a commit | ||
| # message marker (`[execute]` opts in to actually opening a PR). | ||
| # | ||
| # Defaults to **dry-run**: prepares, diffs, logs auto-tag would-do — does | ||
| # not commit, push, or open a PR unless explicitly opted in. | ||
| name: Release: prep | ||
| on: | ||
| workflow_dispatch: | ||
| inputs: | ||
| version: | ||
| description: "Target version (e.g., 2.14.0)" | ||
| required: true | ||
| type: string | ||
| dry_run: | ||
| description: "Read-only run — don't commit, push, or open the prep PR" | ||
| required: false | ||
| default: true | ||
| type: boolean | ||
| pre_release: | ||
| description: "Pre-release prep — skip CHANGELOG generation; push the version-bump commit directly to the dispatched branch (no prep PR)" | ||
| required: false | ||
| default: false | ||
| type: boolean | ||
| push: | ||
| branches: | ||
| - "abernix/test-prep-action-*" | ||
| jobs: | ||
| test-prep: | ||
| runs-on: ubuntu-latest | ||
| permissions: | ||
| contents: write # to push the prep branch (when not dry-run) | ||
| pull-requests: write # to open the prep PR (when not dry-run) | ||
| steps: | ||
| - name: Checkout | ||
| uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 | ||
| with: | ||
| fetch-depth: 0 | ||
| # No persisted credentials — keeps apollo-bot2's PAT out of the | ||
| # default remote URL so it isn't implicitly available to every | ||
| # subsequent step. The one step that needs write access to a | ||
| # protected branch (pre-release prep push) supplies the PAT | ||
| # inline via env at push time. | ||
| persist-credentials: false | ||
| - name: Resolve version + mode | ||
| id: vars | ||
| run: | | ||
| set -euo pipefail | ||
| if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then | ||
| VERSION='${{ inputs.version }}' | ||
| DRY_RUN='${{ inputs.dry_run }}' | ||
| PRE_RELEASE='${{ inputs.pre_release }}' | ||
| else | ||
| # Branch name like abernix/test-prep-action-2.14.0 → version 2.14.0 | ||
| VERSION="${GITHUB_REF_NAME##*-}" | ||
| # Default dry-run unless commit message contains `[execute]`. | ||
| if git log -1 --format=%B "$GITHUB_SHA" | grep -qF '[execute]'; then | ||
| DRY_RUN=false | ||
| else | ||
| DRY_RUN=true | ||
| fi | ||
| # Auto-detect pre-release from semver suffix (e.g. 2.14.2-rc.0). | ||
| if echo "$VERSION" | grep -q -- '-'; then | ||
| PRE_RELEASE=true | ||
| else | ||
| PRE_RELEASE=false | ||
| fi | ||
| fi | ||
| echo "Resolved: version=$VERSION dry_run=$DRY_RUN pre_release=$PRE_RELEASE" | ||
| echo "version=$VERSION" >> "$GITHUB_OUTPUT" | ||
| echo "dry_run=$DRY_RUN" >> "$GITHUB_OUTPUT" | ||
| echo "pre_release=$PRE_RELEASE" >> "$GITHUB_OUTPUT" | ||
| # --------------------------------------------------------------------- | ||
| # Diagnostic: list available env var NAMES (values redacted by GHA for | ||
| # secrets) so we can confirm what's plumbed in. Helpful for sanity- | ||
| # checking that secrets like APOLLO_BOT2_GITHUB_PAT are wired up. | ||
| # --------------------------------------------------------------------- | ||
| - name: Log env variable names (values redacted) | ||
| env: | ||
| # Surface the secret here so it shows up in the env list when set. | ||
| # GHA still redacts the actual value in logs. | ||
| APOLLO_BOT2_GITHUB_PAT: ${{ secrets.APOLLO_BOT2_GITHUB_PAT }} | ||
| run: | | ||
| echo "::group::Environment variable names" | ||
| env | cut -d= -f1 | sort | ||
| echo "::endgroup::" | ||
| echo | ||
| if [ -n "${APOLLO_BOT2_GITHUB_PAT:-}" ]; then | ||
| echo "✓ APOLLO_BOT2_GITHUB_PAT is set (token length: ${#APOLLO_BOT2_GITHUB_PAT})" | ||
| else | ||
| echo "✗ APOLLO_BOT2_GITHUB_PAT is NOT set — add it as a repo secret to enable apollo-bot2 auth." | ||
| fi | ||
| # --------------------------------------------------------------------- | ||
| # Auth check: prove APOLLO_BOT2_GITHUB_PAT actually authenticates as | ||
| # the apollo-bot2 user. Read-only — just calls /user. This is the | ||
| # gate before we can trust this PAT for tag-push in a future workflow. | ||
| # --------------------------------------------------------------------- | ||
| - name: Authenticate as apollo-bot2 | ||
| env: | ||
| GH_TOKEN: ${{ secrets.APOLLO_BOT2_GITHUB_PAT }} | ||
| run: | | ||
| set -euo pipefail | ||
| if [ -z "${GH_TOKEN:-}" ]; then | ||
| echo "::warning::APOLLO_BOT2_GITHUB_PAT secret not configured — skipping auth check." | ||
| echo " Configure it (Settings → Secrets and variables → Actions) to enable this step." | ||
| exit 0 | ||
| fi | ||
| echo "Attempting to authenticate as apollo-bot2..." | ||
| IDENTITY=$(gh api user --jq '"login=\(.login) id=\(.id) type=\(.type)"') | ||
| echo "✓ Authenticated: $IDENTITY" | ||
| # Loud failure if it's NOT apollo-bot2 — catches the wrong-PAT case. | ||
| case "$IDENTITY" in | ||
| *login=apollo-bot2*) echo " Identity matches expectation (apollo-bot2)." ;; | ||
| *) echo "::error::Authenticated user is not apollo-bot2. Check the PAT owner." ; exit 1 ;; | ||
| esac | ||
| - name: Install dev environment (mise) | ||
| uses: jdx/mise-action@v4 | ||
| - name: Show toolchain | ||
| run: | | ||
| rustc --version | ||
| cargo --version | ||
| helm version --short | ||
| helm-docs --version || true | ||
| cargo about --version || true | ||
| cargo deny --version || true | ||
| - name: Run release prepare (no commit, no push) | ||
| run: | | ||
| set -euo pipefail | ||
| if [ '${{ steps.vars.outputs.pre_release }}' = 'true' ]; then | ||
| cargo xtask release prepare --pre-release '${{ steps.vars.outputs.version }}' | ||
| else | ||
| cargo xtask release prepare '${{ steps.vars.outputs.version }}' | ||
| fi | ||
| - name: Show resulting diff | ||
| run: | | ||
| echo "::group::git diff" | ||
| git diff | ||
| echo "::endgroup::" | ||
| echo "::group::git status" | ||
| git status --short | ||
| echo "::endgroup::" | ||
| - name: Verify diff is non-empty | ||
| run: | | ||
| if [ -z "$(git status --porcelain)" ]; then | ||
| echo "::error::release prepare produced no changes — that's suspicious." | ||
| exit 1 | ||
| fi | ||
| - name: Verify CHANGELOG.md gained a v${{ steps.vars.outputs.version }} entry | ||
| if: steps.vars.outputs.pre_release != 'true' | ||
| run: | | ||
| VERSION='${{ steps.vars.outputs.version }}' | ||
| if ! grep -q "^# \[${VERSION}\]" CHANGELOG.md; then | ||
| echo "::error::CHANGELOG.md is missing the v${VERSION} heading." | ||
| exit 1 | ||
| fi | ||
| echo "Found v${VERSION} heading in CHANGELOG.md" | ||
| - name: Verify CHANGELOG.md was NOT modified (pre-release) | ||
| if: steps.vars.outputs.pre_release == 'true' | ||
| run: | | ||
| if ! git diff --quiet -- CHANGELOG.md; then | ||
| echo "::error::Pre-release prep should not modify CHANGELOG.md, but it did." | ||
| echo " This usually means the --pre-release flag was lost or the xtask changed behavior." | ||
| git diff -- CHANGELOG.md | head -40 | ||
| exit 1 | ||
| fi | ||
| echo "CHANGELOG.md untouched, as expected for a pre-release." | ||
| # --------------------------------------------------------------------- | ||
| # Auto-tag observability (logs only — does not push tags). | ||
| # | ||
| # The eventual `auto-tag-release.yml` workflow (M2) fires on push to | ||
| # `main`/`main-v*` and tags the merge commit's second parent. Auth for | ||
| # actual tag pushes likely needs `apollo-bot2`, not the default | ||
| # github-actions[bot] — that's a separate M2 problem. | ||
| # | ||
| # For now: log what auto-tag WOULD do, including the exact commit SHA. | ||
| # --------------------------------------------------------------------- | ||
| - name: Log what auto-tag would do (including exact SHA) | ||
| run: | | ||
| set -euo pipefail | ||
| VERSION='${{ steps.vars.outputs.version }}' | ||
| # `release prepare` has set apollo-router/Cargo.toml to the target | ||
| # version. In production, auto-tag reads this from the version | ||
| # branch's tip (the merge commit's second parent on main). | ||
| PREPARED_VERSION=$(grep '^version = ' apollo-router/Cargo.toml | head -1 | cut -d'"' -f2) | ||
| PREPARED_SHA=$(git rev-parse HEAD) | ||
| echo "::group::Auto-tag would-do analysis" | ||
| echo "Prepared apollo-router version: $PREPARED_VERSION" | ||
| echo "Prepared commit SHA: $PREPARED_SHA" | ||
| echo "Branch ref: ${GITHUB_REF_NAME}" | ||
| echo "Triggering commit ($GITHUB_SHA): $(git log -1 --format='%s' "$GITHUB_SHA")" | ||
| echo | ||
| # Latest released tag on origin — proxy for "main's current version" | ||
| # since we're not running on main directly. Use `for-each-ref --count=1` | ||
| # instead of `git tag ... | head -1` to avoid SIGPIPE under pipefail | ||
| # when the tag list is long. | ||
| LATEST_TAG=$(git for-each-ref --count=1 --sort=-v:refname \ | ||
| --format='%(refname:short)' \ | ||
| 'refs/tags/v*' --no-contains HEAD) | ||
| LATEST_VERSION="${LATEST_TAG#v}" | ||
| echo "Latest release tag (proxy for main's current version): ${LATEST_TAG:-<none>}" | ||
| if [ -z "$LATEST_VERSION" ]; then | ||
| DECISION="WOULD TAG v$PREPARED_VERSION (first release on this line)" | ||
| elif [ "$PREPARED_VERSION" = "$LATEST_VERSION" ]; then | ||
| DECISION="WOULD SKIP — prepared version equals latest tag (no version change)" | ||
| else | ||
| if git rev-parse "v$PREPARED_VERSION" >/dev/null 2>&1; then | ||
| EXISTING_SHA=$(git rev-parse "v$PREPARED_VERSION") | ||
| DECISION="WOULD SKIP — tag v$PREPARED_VERSION already exists at $EXISTING_SHA (idempotent)" | ||
| else | ||
| DECISION="WOULD TAG v$PREPARED_VERSION" | ||
| fi | ||
| fi | ||
| echo | ||
| echo "Decision: $DECISION" | ||
| echo | ||
| # The actual tag-target SHA for the future merge to main is NOT this | ||
| # commit — it's the second parent of the merge commit on main. After | ||
| # the prep PR squash-merges to ${VERSION}, that branch's HEAD becomes | ||
| # a new SHA, and that new SHA is what gets tagged when the release | ||
| # PR (${VERSION} → main) merges. | ||
| echo "Note on tag-target SHA:" | ||
| echo " - In production, auto-tag tags the SECOND PARENT of the merge" | ||
| echo " commit on main: \$(git rev-parse \$MERGE_COMMIT^2)." | ||
| echo " - That SHA equals ${VERSION}'s HEAD at merge time, which can" | ||
| echo " only be known after the prep PR squash-merges and any other" | ||
| echo " backports land. The current HEAD ($PREPARED_SHA) is just" | ||
| echo " a preview snapshot, not the final tag target." | ||
| echo "::endgroup::" | ||
| echo | ||
| echo "Reminder: actual tag push from CI requires apollo-bot2's PAT," | ||
| echo "not the default github-actions[bot]. Until that's wired up," | ||
| echo "a human pushes the tag manually after the merge to main." | ||
| # --------------------------------------------------------------------- | ||
| # Below this point: only runs when explicitly opted in. | ||
| # --------------------------------------------------------------------- | ||
| - name: Stop here in dry-run mode | ||
| if: steps.vars.outputs.dry_run == 'true' | ||
| run: | | ||
| echo "Dry-run mode — not committing, pushing, or opening the prep PR." | ||
| echo " - workflow_dispatch: pass dry_run=false to actually run" | ||
| echo " - push trigger: include '[execute]' in commit message" | ||
| # ===================================================================== | ||
| # Pre-release path: push the version-bump commit directly to the | ||
| # dispatched branch. Used for RC/preview cuts where there's nothing | ||
| # for a human reviewer to look at — just version bumps, no CHANGELOG | ||
| # changes — and a separate prep PR is just ceremony. | ||
| # | ||
| # The push step is the only place apollo-bot2's PAT is exposed: a | ||
| # fresh remote URL with the token baked in is used for that single | ||
| # `git push` and the token is left out of any persistent config. | ||
| # ===================================================================== | ||
| - name: Commit prep on the dispatched branch (pre-release) | ||
| if: steps.vars.outputs.dry_run != 'true' && steps.vars.outputs.pre_release == 'true' | ||
| run: | | ||
| set -euo pipefail | ||
| git config user.name "apollo-bot2" | ||
| git config user.email "apollo-bot2@users.noreply.github.com" | ||
| git add -A | ||
| git commit -m "prep release: v${{ steps.vars.outputs.version }}" | ||
| - name: Push prep commit directly to ${{ github.ref_name }} (pre-release) | ||
| if: steps.vars.outputs.dry_run != 'true' && steps.vars.outputs.pre_release == 'true' | ||
| env: | ||
| APOLLO_BOT2_GITHUB_PAT: ${{ secrets.APOLLO_BOT2_GITHUB_PAT }} | ||
| run: | | ||
| set -euo pipefail | ||
| if [ -z "${APOLLO_BOT2_GITHUB_PAT:-}" ]; then | ||
| echo "::error::APOLLO_BOT2_GITHUB_PAT secret is required to push to a protected release branch." | ||
| exit 1 | ||
| fi | ||
| # PAT-bearing URL only used for this single push command — never | ||
| # persisted into the local repo's git config. | ||
| git push \ | ||
| "https://x-access-token:${APOLLO_BOT2_GITHUB_PAT}@github.com/${GITHUB_REPOSITORY}.git" \ | ||
| "HEAD:${GITHUB_REF_NAME}" | ||
| echo "Pushed prep commit directly to ${GITHUB_REF_NAME} as apollo-bot2." | ||
| # ===================================================================== | ||
| # Final-release path: existing fresh-branch + open-PR flow. Reviewers | ||
| # need to look at the CHANGELOG entries before they hit the release | ||
| # branch, so we don't push direct here. | ||
| # ===================================================================== | ||
| - name: Commit prep on a fresh branch (final release) | ||
| if: steps.vars.outputs.dry_run != 'true' && steps.vars.outputs.pre_release != 'true' | ||
| run: | | ||
| git config user.name "github-actions[bot]" | ||
| git config user.email "41898282+github-actions[bot]@users.noreply.github.com" | ||
| PREP_BRANCH="prep-${{ steps.vars.outputs.version }}" | ||
| git checkout -b "$PREP_BRANCH" | ||
| git add -A | ||
| git commit -m "prep release: v${{ steps.vars.outputs.version }}" | ||
| echo "PREP_BRANCH=$PREP_BRANCH" >> "$GITHUB_ENV" | ||
| - name: Push prep branch (final release) | ||
| if: steps.vars.outputs.dry_run != 'true' && steps.vars.outputs.pre_release != 'true' | ||
| env: | ||
| APOLLO_BOT2_GITHUB_PAT: ${{ secrets.APOLLO_BOT2_GITHUB_PAT }} | ||
| run: | | ||
| set -euo pipefail | ||
| # New prep branch — workflow token is enough if its `contents: | ||
| # write` permission covers branch creation; fall through to bot2 | ||
| # PAT if not. Either way, no PAT persisted in local git config. | ||
| if [ -n "${APOLLO_BOT2_GITHUB_PAT:-}" ]; then | ||
| REMOTE_URL="https://x-access-token:${APOLLO_BOT2_GITHUB_PAT}@github.com/${GITHUB_REPOSITORY}.git" | ||
| else | ||
| REMOTE_URL="https://x-access-token:${{ github.token }}@github.com/${GITHUB_REPOSITORY}.git" | ||
| fi | ||
| git push "$REMOTE_URL" "$PREP_BRANCH" | ||
| - name: Open prep PR (final release) | ||
| if: steps.vars.outputs.dry_run != 'true' && steps.vars.outputs.pre_release != 'true' | ||
| env: | ||
| GH_TOKEN: ${{ github.token }} | ||
| run: | | ||
| VERSION='${{ steps.vars.outputs.version }}' | ||
| CHANGELOG_URL="${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}/blob/${PREP_BRANCH}/CHANGELOG.md" | ||
| BODY=$(cat <<EOF | ||
| > **Note** | ||
| > | ||
| > When approved, this PR will merge into **the \`$VERSION\` branch** which will — upon being approved itself — merge into \`main\`. | ||
| > | ||
| > **Things to review in this PR**: | ||
| > - **[Rendered \`CHANGELOG.md\` on this branch]($CHANGELOG_URL)** — the new \`v$VERSION\` section is at the top | ||
| > - Version bumps (see _Files Changed_ for the true reality) | ||
| > - That it targets the right release branch (\`$VERSION\` in this case!) | ||
| > | ||
| > Opened automatically by the \`test-release-prep\` workflow. | ||
| EOF | ||
| ) | ||
| gh pr create \ | ||
| --repo "$GITHUB_REPOSITORY" \ | ||
| --base "$VERSION" \ | ||
| --head "$PREP_BRANCH" \ | ||
| --title "prep release: v$VERSION" \ | ||
| --body "$BODY" | ||
| - name: Done | ||
| run: | | ||
| if [ '${{ steps.vars.outputs.dry_run }}' = 'true' ]; then | ||
| echo "Dry-run complete. No commit, push, or PR." | ||
| elif [ '${{ steps.vars.outputs.pre_release }}' = 'true' ]; then | ||
| echo "Pre-release prep pushed directly to ${GITHUB_REF_NAME} as apollo-bot2." | ||
| else | ||
| echo "Prep PR opened from $PREP_BRANCH into ${{ steps.vars.outputs.version }}." | ||
| fi | ||