fix(ci): harden tags.yaml changelog job against agent misbehavior

Three changes to the generate-changelog job to fix the v1.3.0
release pipeline failure (run 24765377017) and make the job robust
to whatever state the Copilot step leaves behind.

1. Add `timeout-minutes: 30` to the Generate changelog using AI
   step. On the v1.3.0 re-run the step hung silently for 10+
   minutes; with no timeout a hung Copilot would hold a self-hosted
   runner for up to 6 hours (job default). The previous successful
   run took ~26 minutes, so 30 is a reasonable ceiling.

2. Replace the terse, ambiguous Copilot prompt with a one-liner
   that invokes docs/agents/changelog.md directly. The "Scope and
   boundaries" section added to that doc in the previous commit is
   now the single source of truth for what the agent may and may
   not do, so the workflow only needs to pass the version and
   point at the relevant doc. VERSION is moved to step env: to
   match GitHub's workflow-injection hardening guidance.

3. Rewrite the Create changelog branch and commit step:
   - add `set -euo pipefail` so any failure is visible
   - validate the file exists up front and fail loud with
     `::error::` if not
   - copy the file to a tempfile BEFORE `git checkout -b`, so the
     checkout to `origin/main` cannot remove it (this is the fix
     for the original pathspec error the v1.3.0 run hit)
   - use `trap` to clean up the tempfile on any exit path
   - move VERSION to env
   - drop the dead "no changes to commit" branch: the check_changelog
     step earlier in the job gates this step on the file being
     absent from origin/main, so `git add` + `git commit` must
     produce a diff. If they don't (e.g. Copilot emitted an empty
     file), fail loud instead of pushing an empty branch.

Signed-off-by: Myasnikov Daniil <myasnikovdaniil2001@gmail.com>
This commit is contained in:
Myasnikov Daniil 2026-04-23 10:22:26 +05:00
parent e1c6f9c029
commit 3720f0f3f2
No known key found for this signature in database
GPG key ID: FA953A439C637F04

View file

@ -303,51 +303,56 @@ jobs:
- name: Generate changelog using AI
if: steps.check_changelog.outputs.exists == 'false'
timeout-minutes: 30
env:
COPILOT_GITHUB_TOKEN: ${{ secrets.COPILOT_GITHUB_TOKEN }}
GH_TOKEN: ${{ steps.app-token.outputs.token }}
VERSION: ${{ steps.tag.outputs.version }}
run: |
copilot --prompt "prepare changelog file for tagged release v${{ steps.tag.outputs.version }}, use @docs/agents/changelog.md for it. Create the changelog file at docs/changelogs/v${{ steps.tag.outputs.version }}.md" \
copilot \
--prompt "Generate the release changelog for tag v${VERSION}. Follow the instructions in @docs/agents/changelog.md exactly, including the 'Scope and boundaries' section at the top. Your deliverable is the single file docs/changelogs/v${VERSION}.md — write it and exit; this workflow handles branching, committing, pushing, and opening the PR." \
--allow-all-tools --allow-all-paths < /dev/null
- name: Create changelog branch and commit
if: steps.check_changelog.outputs.exists == 'false'
env:
APP_TOKEN: ${{ steps.app-token.outputs.token }}
VERSION: ${{ steps.tag.outputs.version }}
run: |
git config user.name "cozystack-ci[bot]"
git config user.email "274107086+cozystack-ci[bot]@users.noreply.github.com"
git remote set-url origin https://x-access-token:${APP_TOKEN}@github.com/${GITHUB_REPOSITORY}
CHANGELOG_FILE="docs/changelogs/v${{ steps.tag.outputs.version }}.md"
CHANGELOG_BRANCH="changelog-v${{ steps.tag.outputs.version }}"
if [ -f "$CHANGELOG_FILE" ]; then
# Fetch latest main branch
git fetch origin main
# Delete local branch if it exists
git branch -D "$CHANGELOG_BRANCH" 2>/dev/null || true
# Create and checkout new branch from main
git checkout -b "$CHANGELOG_BRANCH" origin/main
# Add and commit changelog
git add "$CHANGELOG_FILE"
if git diff --staged --quiet; then
echo "⚠️ No changes to commit (file may already be committed)"
else
git commit -m "docs: add changelog for v${{ steps.tag.outputs.version }}" -s
echo "✅ Changelog committed to branch $CHANGELOG_BRANCH"
fi
# Push the branch (force push to update if it exists)
git push -f origin "$CHANGELOG_BRANCH"
else
echo "⚠️ Changelog file was not generated"
set -euo pipefail
CHANGELOG_FILE="docs/changelogs/v${VERSION}.md"
CHANGELOG_BRANCH="changelog-v${VERSION}"
if [ ! -f "$CHANGELOG_FILE" ]; then
echo "::error::Changelog file $CHANGELOG_FILE was not produced by the Generate changelog using AI step"
exit 1
fi
# Snapshot the file across the branch switch — the checkout below
# resets tracked files to match origin/main.
TEMP_FILE="$(mktemp)"
trap 'rm -f "$TEMP_FILE"' EXIT
cp "$CHANGELOG_FILE" "$TEMP_FILE"
git config user.name "cozystack-ci[bot]"
git config user.email "274107086+cozystack-ci[bot]@users.noreply.github.com"
git remote set-url origin "https://x-access-token:${APP_TOKEN}@github.com/${GITHUB_REPOSITORY}"
git fetch origin main
git branch -D "$CHANGELOG_BRANCH" 2>/dev/null || true
git checkout -b "$CHANGELOG_BRANCH" origin/main
mkdir -p "$(dirname "$CHANGELOG_FILE")"
cp "$TEMP_FILE" "$CHANGELOG_FILE"
# The `check_changelog` step gated this job on the file being absent
# from origin/main, so `git add` + `git commit` must produce a diff.
# If they don't, something is wrong (e.g. empty file) — fail loud.
git add "$CHANGELOG_FILE"
git commit -m "docs: add changelog for v${VERSION}" -s
git push -f origin "$CHANGELOG_BRANCH"
- name: Create PR for changelog
if: steps.check_changelog.outputs.exists == 'false'
uses: actions/github-script@v7