Skip to content

fix: make release workflow resilient to re-runs [skip changelog] - #577

Merged
avifenesh merged 4 commits into
mainfrom
fix/release-workflow-resilience
Feb 27, 2026
Merged

fix: make release workflow resilient to re-runs [skip changelog]#577
avifenesh merged 4 commits into
mainfrom
fix/release-workflow-resilience

Conversation

@avifenesh

Copy link
Copy Markdown
Collaborator

Summary

  • crates.io publish steps now tolerate "already exists" errors, allowing failed workflow re-runs to skip already-published crates and continue with remaining ones
  • Version docs job creates a PR instead of pushing directly to main, respecting branch protection rules

Context

v0.14.0 release workflow had 4 failures:

  1. crates.io: agnix-rules published but indexing timed out, re-run failed because agnix-rules was "already exists"
  2. Version Docs: Branch protection blocked direct push to main
  3. JetBrains: Plugin Developer agreement not accepted (separate issue)
  4. Zed: Extension action compatibility issue (separate issue)

This PR fixes issues 1 and 2. Issues 3 and 4 will be tracked separately.

Test plan

  • Re-run the v0.14.0 release workflow failed jobs after this is merged
  • Verify crates.io publish skips already-published crates and publishes remaining ones
  • Verify version docs creates a PR instead of pushing directly

- crates.io publish steps now tolerate "already exists" errors,
  allowing failed workflow re-runs to skip already-published crates
- Version docs job creates a PR instead of pushing directly to main,
  respecting branch protection rules
Copilot AI review requested due to automatic review settings February 27, 2026 00:29
@avifenesh avifenesh added the skip-changelog Skip changelog verification label Feb 27, 2026

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Improves the release workflow’s ability to recover from failures by making crates.io publishing more tolerant to re-runs and updating the versioned-docs job to work with branch protection.

Changes:

  • Make each cargo publish step tolerate “already exists” errors to support workflow re-runs.
  • Update the versioned docs job to push to a version branch and open a PR instead of pushing directly to main.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread .github/workflows/release.yml Outdated
Comment on lines +254 to +261
VERSION="${{ steps.version.outputs.version }}"
cargo publish -p agnix-rules 2>&1 || {
if cargo search agnix-rules --limit 1 | grep -qF "agnix-rules = \"$VERSION\""; then
echo "agnix-rules $VERSION already published, skipping"
else
echo "Publish failed and crate not found on crates.io"
exit 1
fi

Copilot AI Feb 27, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The “already published” detection relies on cargo search <crate> --limit 1 containing the exact version string. cargo search only returns the latest version, so this can false-negative when re-running older tags after a newer release exists (the older version is published but won’t appear in search output), and it can also false-negative during crates.io indexing lag. Consider instead keying off the cargo publish error output (match the known “already uploaded/exists” message), or querying the crates.io HTTP API for the specific version (/api/v1/crates/<crate>/<version>) with retries before deciding to fail.

Copilot uses AI. Check for mistakes.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed. Extracted into /tmp/publish-crate.sh helper that uses the crates.io HTTP API for reliable version detection instead of cargo search.

Comment thread .github/workflows/release.yml Outdated
Comment on lines +251 to +262
- name: Publish agnix-rules
run: cargo publish -p agnix-rules
run: |
set -euo pipefail
VERSION="${{ steps.version.outputs.version }}"
cargo publish -p agnix-rules 2>&1 || {
if cargo search agnix-rules --limit 1 | grep -qF "agnix-rules = \"$VERSION\""; then
echo "agnix-rules $VERSION already published, skipping"
else
echo "Publish failed and crate not found on crates.io"
exit 1
fi
}

Copilot AI Feb 27, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This publish/skip logic is duplicated across all crates, which makes it easy for the steps to drift over time (and it’s already long in YAML). Consider generating a small helper script (e.g., /tmp/publish-crate.sh <name> <version>) and calling it for each crate to keep the behavior consistent in one place.

Copilot uses AI. Check for mistakes.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed. All 5 publish steps now call the shared /tmp/publish-crate.sh helper, keeping behavior in one place.

Comment thread .github/workflows/release.yml Outdated
Comment on lines +508 to +517
BRANCH="docs/version-${{ steps.version.outputs.version }}"
git checkout -b "$BRANCH"
git commit -m "docs: version ${{ steps.version.outputs.version }} docs and update site data"
git push origin main
git push origin "$BRANCH"
gh pr create \
--base main \
--head "$BRANCH" \
--title "docs: version ${{ steps.version.outputs.version }} docs" \
--body "Auto-generated versioned docs snapshot for v${{ steps.version.outputs.version }}." \
--label "documentation"

Copilot AI Feb 27, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This docs step still isn’t resilient to re-runs: git checkout -b "$BRANCH" will fail if the branch already exists locally/remotely, and gh pr create will fail if a PR for that head branch already exists. To make re-runs safe, consider using git checkout -B (or git switch -C) and either updating the existing PR (detect via gh pr view --head "$BRANCH") or treating “PR already exists” as a non-fatal outcome.

Copilot uses AI. Check for mistakes.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed. Now uses git checkout -B (force-create), git push --force-with-lease, and checks for existing PRs via gh pr view --head before creating.

@avifenesh avifenesh changed the title fix: make release workflow resilient to re-runs fix: make release workflow resilient to re-runs [skip changelog] Feb 27, 2026
- Extract publish logic into /tmp/publish-crate.sh helper to avoid
  duplication across 5 crate publish steps
- Use crates.io HTTP API (/api/v1/crates/<name>/<version>) instead of
  cargo search for reliable version detection on re-runs
- Make docs branch/PR creation idempotent: use git checkout -B and
  detect existing PRs before creating new ones
Copilot AI review requested due to automatic review settings February 27, 2026 00:53

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 1 out of 1 changed files in this pull request and generated 4 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread .github/workflows/release.yml Outdated
if cargo publish -p "$crate" 2>&1; then
echo "$crate $version published successfully"
else
# Check crates.io API for the specific version (handles older tags, indexing lag)

Copilot AI Feb 27, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The comment on line 265 mentions "handles older tags, indexing lag", but this check is specifically for detecting if a crate version is already published. The comment is misleading because the check happens during a publish failure, not as a general check for existence.

Consider clarifying: "Check if crate version already exists on crates.io (handles re-runs after partial failures)"

Suggested change
# Check crates.io API for the specific version (handles older tags, indexing lag)
# Check if crate version already exists on crates.io (handles re-runs after partial failures)

Copilot uses AI. Check for mistakes.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed. Updated the comment to clarify it handles re-runs after partial failures.

else
BRANCH="docs/version-${{ steps.version.outputs.version }}"
git checkout -B "$BRANCH"
git commit -m "docs: version ${{ steps.version.outputs.version }} docs and update site data"

Copilot AI Feb 27, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using git push --force-with-lease on line 488 is safer than regular force-push, but in this context where the branch is created fresh on line 486 with git checkout -B, the force-with-lease provides limited protection. If this is a re-run and the branch already exists remotely, force-with-lease will prevent overwriting if someone else pushed to it in the meantime.

This is correct behavior for the use case, but consider adding a comment explaining that force-push is intentional for re-runs.

Suggested change
git commit -m "docs: version ${{ steps.version.outputs.version }} docs and update site data"
git commit -m "docs: version ${{ steps.version.outputs.version }} docs and update site data"
# Intentionally force-push to update the auto-generated docs branch on workflow re-runs.

Copilot uses AI. Check for mistakes.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added a comment explaining force-push is intentional for re-runs of the auto-generated docs branch.

Comment thread .github/workflows/release.yml Outdated
--base main \
--head "$BRANCH" \
--title "docs: version ${{ steps.version.outputs.version }} docs" \
--body "Auto-generated versioned docs snapshot for v${{ steps.version.outputs.version }}." \

Copilot AI Feb 27, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The PR body on line 497 could be more informative by mentioning that it includes rule docs regeneration and site data updates (as evidenced by the files added on line 481). This would help reviewers understand the full scope of changes.

Consider: "Auto-generated versioned docs snapshot for v${{ steps.version.outputs.version }}, including updated rule docs and site data."

Suggested change
--body "Auto-generated versioned docs snapshot for v${{ steps.version.outputs.version }}." \
--body "Auto-generated versioned docs snapshot for v${{ steps.version.outputs.version }}, including updated rule docs and site data." \

Copilot uses AI. Check for mistakes.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated to mention rule docs and site data updates.

Comment thread .github/workflows/release.yml Outdated
Comment on lines +490 to +499
if gh pr view --head "$BRANCH" --json number --jq '.number' 2>/dev/null; then
echo "PR already exists for $BRANCH, updated with force push"
else
gh pr create \
--base main \
--head "$BRANCH" \
--title "docs: version ${{ steps.version.outputs.version }} docs" \
--body "Auto-generated versioned docs snapshot for v${{ steps.version.outputs.version }}." \
--label "documentation"
fi

Copilot AI Feb 27, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The PR existence check on line 490 suppresses all errors with 2>/dev/null, which means network failures or API errors will be treated the same as "PR doesn't exist" and will attempt to create a duplicate PR. While gh pr create will likely fail in those cases, it's more robust to check the exit code and stderr explicitly.

Consider: if gh pr view --head "$BRANCH" --json number --jq '.number' >/dev/null 2>&1; then
Or add error handling to distinguish between "not found" and other errors.

Suggested change
if gh pr view --head "$BRANCH" --json number --jq '.number' 2>/dev/null; then
echo "PR already exists for $BRANCH, updated with force push"
else
gh pr create \
--base main \
--head "$BRANCH" \
--title "docs: version ${{ steps.version.outputs.version }} docs" \
--body "Auto-generated versioned docs snapshot for v${{ steps.version.outputs.version }}." \
--label "documentation"
fi
PR_CHECK_ERR="$(mktemp)"
if gh pr view --head "$BRANCH" --json number --jq '.number' >/dev/null 2>"$PR_CHECK_ERR"; then
echo "PR already exists for $BRANCH, updated with force push"
else
if grep -qiE 'not[[:space:]]+found|could not find pull request|no pull requests' "$PR_CHECK_ERR"; then
gh pr create \
--base main \
--head "$BRANCH" \
--title "docs: version ${{ steps.version.outputs.version }} docs" \
--body "Auto-generated versioned docs snapshot for v${{ steps.version.outputs.version }}." \
--label "documentation"
else
echo "Error checking for existing PR for $BRANCH:"
cat "$PR_CHECK_ERR"
rm -f "$PR_CHECK_ERR"
exit 1
fi
fi
rm -f "$PR_CHECK_ERR"

Copilot uses AI. Check for mistakes.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed. Now uses a temp file for stderr and distinguishes 'not found' from API errors before attempting PR creation.

- Clarify publish helper comment to describe re-run context
- Add comment explaining force-push is intentional for re-runs
- Improve PR existence check to distinguish "not found" from API errors
- Improve PR body to mention rule docs and site data updates
@avifenesh
avifenesh merged commit cd2de7a into main Feb 27, 2026
15 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

skip-changelog Skip changelog verification

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants