fix(workflows): add manual tag creation for draft releases until release-please-action updates#538
Conversation
Dependency Review✅ No vulnerabilities or license issues or OpenSSF Scorecard issues found.OpenSSF Scorecard
Scanned Files
|
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #538 +/- ##
==========================================
- Coverage 85.36% 85.34% -0.03%
==========================================
Files 23 23
Lines 4475 4475
==========================================
- Hits 3820 3819 -1
- Misses 655 656 +1
Flags with carried forward coverage won't be shown. Click here to find out more. 🚀 New features to boost your workflow:
|
There was a problem hiding this comment.
Pull request overview
This PR adds a temporary workaround to manually create Git tags for draft releases generated by release-please. The change is needed because the current version of release-please-action (v4.4.0) does not yet bundle release-please >= 17.2.0, which would support the force-tag-creation configuration option natively. The workaround uses the GitHub API via gh api to create a lightweight tag immediately after release-please creates a draft release.
Changes:
- Added a new workflow step that creates tags for draft releases using the GitHub API
- Implemented error suppression to handle re-runs where the tag already exists
nguyena2
left a comment
There was a problem hiding this comment.
Looks like the release went through so this can be closed
No I forced it to go through so I could get the minor version number incremented @nguyena2 |
- set draft: true in release-please-config.json for mutable uploads - add manual tag creation step with version-anchoring for release-please - improve error handling with specific duplicate-tag detection - add contents: write permission for tag creation API call 🔧 - Generated by Copilot
4410e0e to
9f8ff2d
Compare
- add markdown-it 14.1.1 override to resolve GHSA-38c4-r59v-3vqw - patch fixes ReDoS in linkify.mjs regex (CVE-2026-2327) - follows existing undici override pattern for transitive vulns 🔒 - Generated by Copilot
🤖 I have created a release *beep* *boop* --- ## [2.3.3](hve-core-v2.3.2...hve-core-v2.3.3) (2026-02-13) ### 🐛 Bug Fixes * **workflows:** add manual tag creation for draft releases until release-please-action updates ([#538](#538)) ([4a6ef2c](4a6ef2c)) --- This PR was generated with [Release Please](https://github.com/googleapis/release-please). See [documentation](https://github.com/googleapis/release-please#release-please). Co-authored-by: hve-core-release-please[bot] <254602402+hve-core-release-please[bot]@users.noreply.github.com>
… conversion (#545) ## Description Fixes a race condition where release-please `"draft": true` configuration caused draft releases that are excluded from the GitHub Releases API "latest" query, making them invisible to release-please's own version anchoring within the same workflow invocation. Because the draft release is invisible, release-please scans the full commit history, finds an old breaking change (PR #277), and proposes erroneous v3.0.0 major version bumps. Also added auto-detection of version from the latest GitHub release tag in both extension publish workflows, removing the requirement for manual version input on every dispatch. **Proof the race condition fires in production:** after v2.3.4 merged, release-please created the v2.3.4 release as draft at 22:05:23 UTC. At 22:08:14 UTC — while v2.3.4 was still draft — release-please opened PR #547 proposing v3.0.0. The v2.3.4 release was not published until 22:10:08 UTC, confirming that release-please computed the next version while v2.3.4 was invisible to its own Releases API query. Additionally, v2.3.2 remains stuck in draft state, demonstrating that the `publish-release` job's `gh release edit --draft=false` is unreliable when it depends on upstream jobs that may not always run. ### Changes - fix(workflows): removed `"draft": true` from root and package level in `release-please-config.json` so release-please creates published releases that are immediately visible to the Releases API for version anchoring - fix(workflows): removed `"force-tag-creation": true` from `release-please-config.json` since it requires release-please v17.2.0+ and was silently ignored by the bundled v17.1.3 - fix(workflows): replaced 20-line tag bridge step in `main.yml` with a `gh release edit --draft=true` post-creation conversion, allowing assets to be uploaded to a mutable draft release while preserving release visibility for version anchoring - feat(workflows): added auto-detection of version from latest GitHub release tag in `extension-publish-prerelease.yml` when version input is empty, with ODD minor derivation for the pre-release channel - feat(workflows): added auto-detection of version from latest GitHub release tag in `extension-publish.yml` when version input is empty, with `hve-core-v` prefix stripping - fix(workflows): updated `extension-publish.yml` input description to match new auto-detect behavior (was incorrectly referencing `package.json`) ## Related Issue(s) Fixes #543 ## Type of Change Select all that apply: **Code & Documentation:** - [x] Bug fix (non-breaking change fixing an issue) - [ ] New feature (non-breaking change adding functionality) - [ ] Breaking change (fix or feature causing existing functionality to change) - [ ] Documentation update **Infrastructure & Configuration:** - [x] GitHub Actions workflow - [ ] Linting configuration (markdown, PowerShell, etc.) - [ ] Security configuration - [ ] DevContainer configuration - [ ] Dependency update **AI Artifacts:** - [ ] Reviewed contribution with `prompt-builder` agent and addressed all feedback - [ ] Copilot instructions (`.github/instructions/*.instructions.md`) - [ ] Copilot prompt (`.github/prompts/*.prompt.md`) - [ ] Copilot agent (`.github/agents/*.agent.md`) - [ ] Copilot skill (`.github/skills/*/SKILL.md`) **Other:** - [ ] Script/automation (`.ps1`, `.sh`, `.py`) - [ ] Other (please describe): ## Testing - Validated YAML linting passes via `npm run lint:yaml` — all 25 workflow files passed - Verified `release-please-config.json` is valid JSON with no schema errors - Confirmed the `publish-release` job already contains `gh release edit --draft=false` to finalize releases after asset upload - Confirmed `gh release view --json tagName` correctly returns the latest release tag format (`hve-core-v2.3.4`) ## Checklist ### Required Checks - [x] Documentation is updated (if applicable) - [x] Files follow existing naming conventions - [x] Changes are backwards compatible (if applicable) - [ ] Tests added for new functionality (if applicable) ### Required Automated Checks The following validation commands must pass before merging: - [x] Markdown linting: `npm run lint:md` - [ ] Spell checking: `npm run spell-check` - [ ] Frontmatter validation: `npm run lint:frontmatter` - [ ] Link validation: `npm run lint:md-links` - [ ] PowerShell analysis: `npm run lint:ps` ## Security Considerations - [x] This PR does not contain any sensitive or NDA information - [ ] Any new dependencies have been reviewed for security issues - [x] Security-related scripts follow the principle of least privilege ## Additional Notes The release lifecycle after this change follows a four-phase sequence: release-please creates a **published** release (tag created, visible to Releases API) → post-creation step converts to **draft** (mutable for asset upload) → package/attest/upload jobs attach assets → `publish-release` job converts back to **published**. This preserves the original HTTP 422 fix from PR #538 while eliminating the version anchoring race condition that caused PRs #530, #532, #534, #539, #540, #542, and #547. ### Why the tag bridge didn't work The tag bridge step from PR #538 manually created git tags after draft release creation. However, release-please anchors its version calculation on the GitHub **Releases** API (not the Tags API). Even though tag `hve-core-v2.3.4` existed at commit `9a72f2b`, release-please's query for the latest release excluded the draft, causing it to scan the full commit history and hit the old breaking change from PR #277.
## Description Published releases on this repository are immutable — the `gh release edit --draft=true` step introduced in PR #545 fails with `HTTP 422: state cannot be changed when release is immutable`. This PR replaces the edit approach with a delete-and-recreate cycle: capture the release metadata, delete the immutable published release, and recreate it as a mutable draft so downstream jobs can upload assets. The git tag persists across the delete/create cycle, and the `publish-release` job converts the draft back to published after upload completes. **Why prior approaches failed:** - PR #538 (`"draft": true` in config) — release-please cannot find draft releases via the Releases API, causing it to scan full history and propose a bogus v3.0.0 - PR #545 (`gh release edit --draft=true`) — published releases are immutable on this repo (HTTP 422) ## Related Issue(s) Fixes #543 ## Type of Change Select all that apply: **Code & Documentation:** - [x] Bug fix (non-breaking change fixing an issue) - [ ] New feature (non-breaking change adding functionality) - [ ] Breaking change (fix or feature causing existing functionality to change) - [ ] Documentation update **Infrastructure & Configuration:** - [x] GitHub Actions workflow - [ ] Linting configuration (markdown, PowerShell, etc.) - [ ] Security configuration - [ ] DevContainer configuration - [ ] Dependency update **AI Artifacts:** - [ ] Reviewed contribution with `prompt-builder` agent and addressed all feedback - [ ] Copilot instructions (`.github/instructions/*.instructions.md`) - [ ] Copilot prompt (`.github/prompts/*.prompt.md`) - [ ] Copilot agent (`.github/agents/*.agent.md`) - [ ] Copilot skill (`.github/skills/*/SKILL.md`) **Other:** - [ ] Script/automation (`.ps1`, `.sh`, `.py`) - [ ] Other (please describe): ## Testing - Validated YAML syntax of `main.yml` with `yamllint` - Confirmed `gh release delete` preserves the git tag (documented GitHub CLI behavior) - Confirmed `gh release create --draft --verify-tag` recreates a mutable draft tied to the existing tag - Verified `--notes-file` approach safely handles release body content with special characters ## Checklist ### Required Checks - [x] Documentation is updated (if applicable) - [x] Files follow existing naming conventions - [x] Changes are backwards compatible (if applicable) - [ ] Tests added for new functionality (if applicable) ### Required Automated Checks The following validation commands must pass before merging: - [ ] Markdown linting: `npm run lint:md` - [ ] Spell checking: `npm run spell-check` - [ ] Frontmatter validation: `npm run lint:frontmatter` - [ ] Link validation: `npm run lint:md-links` - [ ] PowerShell analysis: `npm run lint:ps` ## Security Considerations - [x] This PR does not contain any sensitive or NDA information - [x] Any new dependencies have been reviewed for security issues - [x] Security-related scripts follow the principle of least privilege ## Additional Notes The delete-and-recreate approach is safe because: 1. **Tag preservation** — `gh release delete` only removes the release object; the git tag remains intact 2. **Timing** — release-please has already completed version anchoring before this step runs, so the brief absence of the release object has no effect 3. **Metadata fidelity** — release title and body are captured before deletion and reapplied to the new draft via `--notes-file` (avoids shell interpolation issues) 4. **Downstream compatibility** — all subsequent jobs reference `steps.release.outputs.tag_name`, which is unaffected by the recreate
…rors (#554) # Pull Request ## Description Fixes the persistent `HTTP 422: tag_name was used by an immutable release` error in the `publish-release` job. This is the **fifth iteration** (PRs #538 → #545 → #550 → #552) — all previous approaches failed because they attempted to delete and recreate releases or tags after publication, which GitHub's immutability model permanently forbids. ### Root Cause GitHub's [immutable releases documentation](https://docs.github.com/en/repositories/releasing-projects-on-github/about-releases#about-immutable-releases) states: > *"Git tags cannot be moved or deleted"* for immutable releases. *"Even if you delete a repository and create a new one with the same name, you cannot reuse tags that were associated with immutable releases."* The tag name is **permanently tainted** at GitHub's infrastructure level once a release is published with immutability enabled. Every delete/recreate approach was fundamentally doomed: | PR | Approach | Failure Mode | |----|----------|-------------| | #538 | `"draft": true` in config | Race condition — release-please can't find draft releases (lazy tag) | | #545 | `gh release edit --draft=true` | Can't edit published immutable release | | #550 | Delete published, recreate as draft | Worked for upload, but publish step failed | | #552 | Delete draft, recreate as published | HTTP 422 — tag name permanently reserved | ### Solution: Draft-First Flow Follow [GitHub's recommended workflow](https://docs.github.com/en/repositories/releasing-projects-on-github/about-releases#creating-immutable-releases): 1. **release-please creates release as draft** (`"draft": true` in config) 2. **Explicit git tag creation** via API (workaround for release-please's lazy tag behavior) 3. **Upload assets to the mutable draft** (existing `attest-and-upload` and `upload-plugin-packages` jobs) 4. **Publish**: `gh release edit --draft=false` — release becomes immutable with all assets already attached ### Draft Race Condition Workaround release-please with `"draft": true` uses lazy tag creation — the git tag isn't materialized until publish. Without the tag, release-please's GraphQL query returns null for `tag` and `tagCommit`, causing it to skip the draft and propose a bogus version bump. This was fixed upstream in [googleapis/release-please#2627](googleapis/release-please#2627) (`force-tag-creation` option), but the fix is **not yet released** in release-please-action (latest: v4.4.0 → release-please 17.1.3). We work around this by explicitly creating the git tag via API after draft creation. When a new release-please-action ships with PR #2627, replace the manual tag creation step with `"force-tag-creation": true` in `release-please-config.json`. ## Related Issue(s) Supersedes PRs #538, #545, #550, #552 ## Type of Change Select all that apply: **Code & Documentation:** - [x] Bug fix (non-breaking change fixing an issue) **Infrastructure & Configuration:** - [x] GitHub Actions workflow ## Testing - Verified YAML and JSON syntax (no lint errors) - Logic validated against [GitHub REST API docs](https://docs.github.com/en/rest/releases/releases), [immutable releases concept](https://docs.github.com/en/repositories/releasing-projects-on-github/about-releases#about-immutable-releases), and [release-please issue #1650](googleapis/release-please#1650) - The draft-first approach avoids all immutability enforcement because assets are uploaded to mutable drafts, and publish is a single `--draft=false` edit (not a delete/create) ## Checklist ### Required Checks - [x] Documentation is updated (if applicable) - [x] Files follow existing naming conventions - [x] Changes are backwards compatible (if applicable) ## Security Considerations - [x] This PR does not contain any sensitive or NDA information - [x] Any new dependencies have been reviewed for security issues ## Additional Notes - **v2.3.7 remediation**: The v2.3.7 tag is permanently tainted. A manual release may be needed if v2.3.7 assets need to be published. The next release-please cycle (v2.3.8+) will use the draft-first flow and should succeed cleanly. - **Future upgrade**: Once `release-please-action` includes `force-tag-creation` support, the manual tag creation step can be replaced with a single config line. This is documented in a code comment referencing googleapis/release-please#2627.
fix(workflows): add draft release with manual tag bridge + markdown-it ReDoS patch
Description
Draft Release with Manual Tag Bridge
GitHub does not create git tags for draft releases, but
release-pleaseneeds the tag to anchor version calculations for subsequent release PRs. Without it,release-pleasescans the full commit history, may find an old breaking change, and proposes a wrong major bump (evidenced by bogus v3.0.0 PRs #530, #532, #534, #539).The
release-please-actionv4.4.0 bundlesrelease-pleasev17.1.3, which does not supportforce-tag-creation(introduced in v17.2.0). This PR adds a temporary bridge step that creates the tag via the GitHub API immediately after a draft release is created.Changes:
draft: trueinrelease-please-config.jsonso releases are mutable (fixes HTTP 422 on asset upload).github/workflows/main.ymlusinggh apito push a lightweight tagcontents: writepermission for the tag creation API callRemove the manual tag-creation step once
release-please-actionships withrelease-please >= 17.2.0and supportsforce-tag-creationnatively. See: googleapis/release-please#2423markdown-it ReDoS Remediation (GHSA-38c4-r59v-3vqw)
markdownlint-cli2@0.20.0depends onmarkdown-it@14.1.0, which has a moderate ReDoS vulnerability (CVE-2026-2327) in the linkify regex. No upstream fix is available yet.Changes:
markdown-it: 14.1.1tooverridesinpackage.json(follows existingundicioverride pattern)Validation:
npm auditreports 0 vulnerabilities,npm run lint:mdpasses with 0 errors on all 153 files.Related Issue(s)
Type of Change
Select all that apply:
Code & Documentation:
Infrastructure & Configuration:
AI Artifacts:
prompt-builderagent and addressed all feedback.github/instructions/*.instructions.md).github/prompts/*.prompt.md).github/agents/*.agent.md).github/skills/*/SKILL.md)Other:
.ps1,.sh,.py)Testing
npm audit— 0 vulnerabilitiesnpm run lint:md— 0 errors, 153 files lintedChecklist
Required Checks
AI Artifact Contributions
/prompt-analyzeto review contributionprompt-builderreviewRequired Automated Checks
The following validation commands must pass before merging:
npm run lint:mdnpm run spell-checknpm run lint:frontmatternpm run lint:md-linksnpm run lint:psSecurity Considerations
Additional Notes
Two independent fixes in this PR:
release-please-actionupgrades past v17.2.0markdownlint-cli2bumps itsmarkdown-itdependency to >=14.1.1🔧 - Generated by Copilot