# Assign sequential numbers to prd-new-*.md files on merge to main. # # When a PR merges to main and includes prd-new-*.md files this workflow: # 1. Finds the next available NNNN number by scanning existing PRDs. # 2. Renames each prd-new-*.md to NNNN-.md. # 3. Updates the title header (# PRD prd-new: → # PRD NNNN:). # 4. Flips Status: Draft → Active when the push touched files outside # docs/prds/ anywhere in its commit range (i.e. the implementation # shipped together with the PRD). # 5. Commits the renaming back to main. # # No-op if the working tree contains no prd-new-*.md files. # # NOTE: The workflow scans the working tree (not just HEAD~1..HEAD) because # PRs land as multi-commit pushes and the prd-new file is often added in an # earlier commit on the branch, not in the final squash/merge commit. name: prd-number on: push: branches: - main paths: - 'docs/prds/prd-new-*.md' jobs: assign-numbers: runs-on: ubuntu-latest permissions: contents: write steps: - name: Checkout uses: actions/checkout@v4 with: fetch-depth: 0 token: ${{ secrets.GITHUB_TOKEN }} - name: Set up Python uses: actions/setup-python@v5 with: python-version: "3.12" - name: Configure git run: | git config user.name "github-actions[bot]" git config user.email "github-actions[bot]@users.noreply.github.com" - name: Assign PRD numbers run: | python3 - <<'EOF' import os import re import subprocess import sys from pathlib import Path prds_dir = Path("docs/prds") # Scan the working tree — prd-new files may have landed in any # commit of a multi-commit push, not just HEAD. new_prds = sorted(prds_dir.glob("prd-new-*.md")) if not new_prds: print("No prd-new-*.md files found — nothing to do.") sys.exit(0) # Determine whether non-PRD files were also changed anywhere in # the push range (BEFORE_SHA → HEAD). Falls back to HEAD~1 when # the env var isn't set (e.g. local act runs). before_sha = os.environ.get("GITHUB_EVENT_BEFORE", "HEAD~1") all_changed = subprocess.run( ["git", "diff", "--name-only", before_sha, "HEAD"], capture_output=True, text=True, check=True, ).stdout.splitlines() non_prd_changed = any( not f.startswith("docs/prds/") for f in all_changed ) # Find next available number. existing = sorted( int(m.group(1)) for p in prds_dir.glob("*.md") if (m := re.match(r"^(\d{4})-", p.name)) ) next_num = (max(existing) + 1) if existing else 1 for prd_path in sorted(new_prds): slug = re.sub(r"^prd-new-", "", prd_path.stem) new_name = f"{next_num:04d}-{slug}.md" new_path = prds_dir / new_name print(f" {prd_path.name} → {new_name}") content = prd_path.read_text() # Update title header. content = re.sub( r"^(#\s+PRD\s+)prd-new(:)", rf"\g<1>{next_num:04d}\2", content, count=1, flags=re.MULTILINE, ) # Conditionally flip Status. if non_prd_changed: content = re.sub( r"(\*\*Status:\*\*\s*)Draft", r"\g<1>Active", content, count=1, ) new_path.write_text(content) subprocess.run(["git", "rm", str(prd_path)], check=True) subprocess.run(["git", "add", str(new_path)], check=True) next_num += 1 subprocess.run( ["git", "commit", "-m", "ci(prd): assign sequential numbers to new PRDs"], check=True, ) subprocess.run(["git", "push"], check=True) EOF