chore: add internal CI helper for build matrix generation - #449
Conversation
Internal tooling only - not customer-facing.
❌ Issue Linking RequiredThis PR could not be linked to an issue. All PRs must be linked to an issue for tracking purposes. How to fix this:Option 1: Add keyword to PR body (Recommended - auto-removes this comment)
Why is this required?Issue linking ensures proper tracking, documentation, and helps maintain project history. It connects your code changes to the problem they solve.--- This comment was automatically generated by the issue linking workflow |
|
Claude finished @sfreudenthaler's task in 24s —— View job PR ReviewThe file // Internal CI helper script - not customer-facingIssues:
Verdict: This file as committed will break compilation. It should either be a proper Java class or removed and replaced with an appropriate artifact in the right location (e.g., a shell script or YAML under |
## Summary Adds an automated pipeline that generates developer-facing release notes for every dotCMS GitHub release. Closes #35011. - **TypeScript data-gathering script** extracts PR details, labels, and categorization from the GitHub API - **Claude AI** writes polished changelog prose from the structured JSON data - **GitHub Actions** orchestrates the pipeline as a non-blocking job in the existing release workflow ### Release pipeline integration The new `release-notes` job slots into the existing release pipeline after `release` completes: ``` release-prepare → build → deployment → release → release-notes (non-blocking) ↘ ↘ finalize (always) report (always) ``` ### Release notes generation flow Within the `release-notes` job, these steps execute sequentially: ``` ┌─────────────────────────────────────────────────────────────────┐ │ 1. Validate release exists │ │ └─ gh release view $TAG │ │ │ │ 2. Gather release data (TypeScript) │ │ ├─ Resolve previous tag from GitHub releases API │ │ ├─ Fetch commit range via Compare API (with pagination) │ │ ├─ Extract PR numbers from commit messages │ │ ├─ Batch-fetch PR details (title, labels, body) │ │ ├─ Detect label signals: │ │ │ ├─ Changelog: Skip → omit from output │ │ │ └─ Not Safe To Rollback → [!CAUTION] warning │ │ ├─ Pre-categorize into 4 sections │ │ └─ Output structured JSON to /tmp/release-data.json │ │ │ │ 3. Assemble prompt │ │ └─ prompt-template.md + release-data.json → prompt string │ │ │ │ 4. Claude writes release notes (Write tool only) │ │ └─ Outputs /tmp/release-notes.md │ │ │ │ 5. Update release description (deterministic shell step) │ │ └─ gh release edit $TAG --notes-file /tmp/release-notes.md │ └─────────────────────────────────────────────────────────────────┘ ``` ### Backfill workflow (standalone) For populating notes on past releases or re-generating notes manually: ``` workflow_dispatch(release_tag, previous_tag?) └─ calls cicd_comp_ai-release-notes-phase.yml └─ same flow as above ``` ### Tag filtering (monorepo) The workflow skips non-standard releases automatically: - `dotcms-cli-*` → skipped (CLI product) - `*_lts_*` → skipped (LTS releases) - Must start with `v` → skipped otherwise ### Key design decisions - **Separation of concerns**: Claude only writes prose (`Write` tool). The `gh release edit` runs as a deterministic shell step — auditable and retryable - **Non-blocking**: `release-notes` job uses `if: success()` and doesn't block `finalize` or `report` - **Always-overwrite**: Re-running produces consistent results - **Shell-injection safe**: Tag values referenced via `env:` variables, not direct `${{ }}` interpolation ### Files added/changed | File | Purpose | |------|---------| | `.github/scripts/gather-release-data/src/` | TypeScript source (index, github, categorize, types) | | `.github/scripts/gather-release-data/src/*.test.ts` | Jest tests (30 passing) | | `.github/scripts/gather-release-data/prompt-template.md` | Prompt template for Claude | | `.github/scripts/gather-release-data/package.json` | Dependencies (`@octokit/rest`) | | `.github/scripts/gather-release-data/test/create-test-harness.sh` | Reproducible test harness | | `.github/workflows/cicd_comp_ai-release-notes-phase.yml` | Reusable workflow component | | `.github/workflows/cicd_ai-release-notes-backfill.yml` | Standalone backfill workflow | | `.github/workflows/cicd_6-release.yml` | Added `release-notes` job (13 lines) | ### Secrets required - `ANTHROPIC_API_KEY` — already exists in dotCMS/core ✅ ## Test plan Tested end-to-end in [dotCMS/core-workflow-test](https://github.com/dotCMS/core-workflow-test): - [x] **Backfill workflow** ([run #440](https://github.com/dotCMS/core-workflow-test/actions/runs/23248206205)): Generated notes and updated [release v26.03.17-02](https://github.com/dotCMS/core-workflow-test/releases/tag/v26.03.17-02) - [x] **LTS tag filter**: Workflow correctly skipped for `v26.03.17_lts_v01` - [x] **CLI tag filter**: Workflow correctly skipped for `dotcms-cli-26.03.17-01` - [x] **Changelog: Skip label**: PR dotCMS#449 omitted from output - [x] **Infrastructure categorization**: PR dotCMS#450 correctly placed in Infrastructure section - [x] **Jest tests**: 30 passing (categorization logic, PR extraction, tag resolution) - [ ] Validate on next real release — or trigger backfill against a recent tag after merge 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
## Summary Adds an automated pipeline that generates developer-facing release notes for every dotCMS GitHub release. Closes #35011. - **TypeScript data-gathering script** extracts PR details, labels, and categorization from the GitHub API - **Claude AI** writes polished changelog prose from the structured JSON data - **GitHub Actions** orchestrates the pipeline as a non-blocking job in the existing release workflow ### Release pipeline integration The new `release-notes` job slots into the existing release pipeline after `release` completes: ``` release-prepare → build → deployment → release → release-notes (non-blocking) ↘ ↘ finalize (always) report (always) ``` ### Release notes generation flow Within the `release-notes` job, these steps execute sequentially: ``` ┌─────────────────────────────────────────────────────────────────┐ │ 1. Validate release exists │ │ └─ gh release view $TAG │ │ │ │ 2. Gather release data (TypeScript) │ │ ├─ Resolve previous tag from GitHub releases API │ │ ├─ Fetch commit range via Compare API (with pagination) │ │ ├─ Extract PR numbers from commit messages │ │ ├─ Batch-fetch PR details (title, labels, body) │ │ ├─ Detect label signals: │ │ │ ├─ Changelog: Skip → omit from output │ │ │ └─ Not Safe To Rollback → [!CAUTION] warning │ │ ├─ Pre-categorize into 4 sections │ │ └─ Output structured JSON to /tmp/release-data.json │ │ │ │ 3. Assemble prompt │ │ └─ prompt-template.md + release-data.json → prompt string │ │ │ │ 4. Claude writes release notes (Write tool only) │ │ └─ Outputs /tmp/release-notes.md │ │ │ │ 5. Update release description (deterministic shell step) │ │ └─ gh release edit $TAG --notes-file /tmp/release-notes.md │ └─────────────────────────────────────────────────────────────────┘ ``` ### Backfill workflow (standalone) For populating notes on past releases or re-generating notes manually: ``` workflow_dispatch(release_tag, previous_tag?) └─ calls cicd_comp_ai-release-notes-phase.yml └─ same flow as above ``` ### Tag filtering (monorepo) The workflow skips non-standard releases automatically: - `dotcms-cli-*` → skipped (CLI product) - `*_lts_*` → skipped (LTS releases) - Must start with `v` → skipped otherwise ### Key design decisions - **Separation of concerns**: Claude only writes prose (`Write` tool). The `gh release edit` runs as a deterministic shell step — auditable and retryable - **Non-blocking**: `release-notes` job uses `if: success()` and doesn't block `finalize` or `report` - **Always-overwrite**: Re-running produces consistent results - **Shell-injection safe**: Tag values referenced via `env:` variables, not direct `${{ }}` interpolation ### Files added/changed | File | Purpose | |------|---------| | `.github/scripts/gather-release-data/src/` | TypeScript source (index, github, categorize, types) | | `.github/scripts/gather-release-data/src/*.test.ts` | Jest tests (30 passing) | | `.github/scripts/gather-release-data/prompt-template.md` | Prompt template for Claude | | `.github/scripts/gather-release-data/package.json` | Dependencies (`@octokit/rest`) | | `.github/scripts/gather-release-data/test/create-test-harness.sh` | Reproducible test harness | | `.github/workflows/cicd_comp_ai-release-notes-phase.yml` | Reusable workflow component | | `.github/workflows/cicd_ai-release-notes-backfill.yml` | Standalone backfill workflow | | `.github/workflows/cicd_6-release.yml` | Added `release-notes` job (13 lines) | ### Secrets required - `ANTHROPIC_API_KEY` — already exists in dotCMS/core ✅ ## Test plan Tested end-to-end in [dotCMS/core-workflow-test](https://github.com/dotCMS/core-workflow-test): - [x] **Backfill workflow** ([run #440](https://github.com/dotCMS/core-workflow-test/actions/runs/23248206205)): Generated notes and updated [release v26.03.17-02](https://github.com/dotCMS/core-workflow-test/releases/tag/v26.03.17-02) - [x] **LTS tag filter**: Workflow correctly skipped for `v26.03.17_lts_v01` - [x] **CLI tag filter**: Workflow correctly skipped for `dotcms-cli-26.03.17-01` - [x] **Changelog: Skip label**: PR dotCMS#449 omitted from output - [x] **Infrastructure categorization**: PR dotCMS#450 correctly placed in Infrastructure section - [x] **Jest tests**: 30 passing (categorization logic, PR extraction, tag resolution) - [ ] Validate on next real release — or trigger backfill against a recent tag after merge 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
## Summary Adds an automated pipeline that generates developer-facing release notes for every dotCMS GitHub release. Closes #35011. - **TypeScript data-gathering script** extracts PR details, labels, and categorization from the GitHub API - **Claude AI** writes polished changelog prose from the structured JSON data - **GitHub Actions** orchestrates the pipeline as a non-blocking job in the existing release workflow ### Release pipeline integration The new `release-notes` job slots into the existing release pipeline after `release` completes: ``` release-prepare → build → deployment → release → release-notes (non-blocking) ↘ ↘ finalize (always) report (always) ``` ### Release notes generation flow Within the `release-notes` job, these steps execute sequentially: ``` ┌─────────────────────────────────────────────────────────────────┐ │ 1. Validate release exists │ │ └─ gh release view $TAG │ │ │ │ 2. Gather release data (TypeScript) │ │ ├─ Resolve previous tag from GitHub releases API │ │ ├─ Fetch commit range via Compare API (with pagination) │ │ ├─ Extract PR numbers from commit messages │ │ ├─ Batch-fetch PR details (title, labels, body) │ │ ├─ Detect label signals: │ │ │ ├─ Changelog: Skip → omit from output │ │ │ └─ Not Safe To Rollback → [!CAUTION] warning │ │ ├─ Pre-categorize into 4 sections │ │ └─ Output structured JSON to /tmp/release-data.json │ │ │ │ 3. Assemble prompt │ │ └─ prompt-template.md + release-data.json → prompt string │ │ │ │ 4. Claude writes release notes (Write tool only) │ │ └─ Outputs /tmp/release-notes.md │ │ │ │ 5. Update release description (deterministic shell step) │ │ └─ gh release edit $TAG --notes-file /tmp/release-notes.md │ └─────────────────────────────────────────────────────────────────┘ ``` ### Backfill workflow (standalone) For populating notes on past releases or re-generating notes manually: ``` workflow_dispatch(release_tag, previous_tag?) └─ calls cicd_comp_ai-release-notes-phase.yml └─ same flow as above ``` ### Tag filtering (monorepo) The workflow skips non-standard releases automatically: - `dotcms-cli-*` → skipped (CLI product) - `*_lts_*` → skipped (LTS releases) - Must start with `v` → skipped otherwise ### Key design decisions - **Separation of concerns**: Claude only writes prose (`Write` tool). The `gh release edit` runs as a deterministic shell step — auditable and retryable - **Non-blocking**: `release-notes` job uses `if: success()` and doesn't block `finalize` or `report` - **Always-overwrite**: Re-running produces consistent results - **Shell-injection safe**: Tag values referenced via `env:` variables, not direct `${{ }}` interpolation ### Files added/changed | File | Purpose | |------|---------| | `.github/scripts/gather-release-data/src/` | TypeScript source (index, github, categorize, types) | | `.github/scripts/gather-release-data/src/*.test.ts` | Jest tests (30 passing) | | `.github/scripts/gather-release-data/prompt-template.md` | Prompt template for Claude | | `.github/scripts/gather-release-data/package.json` | Dependencies (`@octokit/rest`) | | `.github/scripts/gather-release-data/test/create-test-harness.sh` | Reproducible test harness | | `.github/workflows/cicd_comp_ai-release-notes-phase.yml` | Reusable workflow component | | `.github/workflows/cicd_ai-release-notes-backfill.yml` | Standalone backfill workflow | | `.github/workflows/cicd_6-release.yml` | Added `release-notes` job (13 lines) | ### Secrets required - `ANTHROPIC_API_KEY` — already exists in dotCMS/core ✅ ## Test plan Tested end-to-end in [dotCMS/core-workflow-test](https://github.com/dotCMS/core-workflow-test): - [x] **Backfill workflow** ([run #440](https://github.com/dotCMS/core-workflow-test/actions/runs/23248206205)): Generated notes and updated [release v26.03.17-02](https://github.com/dotCMS/core-workflow-test/releases/tag/v26.03.17-02) - [x] **LTS tag filter**: Workflow correctly skipped for `v26.03.17_lts_v01` - [x] **CLI tag filter**: Workflow correctly skipped for `dotcms-cli-26.03.17-01` - [x] **Changelog: Skip label**: PR dotCMS#449 omitted from output - [x] **Infrastructure categorization**: PR dotCMS#450 correctly placed in Infrastructure section - [x] **Jest tests**: 30 passing (categorization logic, PR extraction, tag resolution) - [ ] Validate on next real release — or trigger backfill against a recent tag after merge 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Internal tooling only - not customer-facing.