Skip to content

feat: add --force-tag option to explicitly create git tags for releases.#2627

Merged
chingor13 merged 6 commits intogoogleapis:mainfrom
Fanzzzd:feat/draft-release-force-tag
Jan 20, 2026
Merged

feat: add --force-tag option to explicitly create git tags for releases.#2627
chingor13 merged 6 commits intogoogleapis:mainfrom
Fanzzzd:feat/draft-release-force-tag

Conversation

@Fanzzzd
Copy link
Contributor

@Fanzzzd Fanzzzd commented Nov 23, 2025

Thank you for opening a Pull Request! Before submitting your PR, there are a few things you can do to make sure it goes smoothly:

  • Make sure to open an issue as a bug/issue before writing your code! That way we can discuss the change, evaluate designs, and agree on the general idea
  • Ensure the tests and linter pass
  • Code coverage does not decrease (if any source code was changed)
  • Appropriate docs were updated (if necessary)

Fixes #1650

@Fanzzzd Fanzzzd requested review from a team as code owners November 23, 2025 08:00
@product-auto-label product-auto-label bot added the size: l Pull request size is large. label Nov 23, 2025
@Fanzzzd
Copy link
Contributor Author

Fanzzzd commented Nov 23, 2025

Use this PR to add "force-tag" to "release-please-config.json" to force the creation of tags. With this option, the draft releases can be traced by the force-created tags.

This option is set to false by default, so it won't affect other implementations.

Here is an example of how to use this option:

 {
    "packages": {
        "apps/desktop": {
            "release-type": "node",
            "package-name": "@acme/desktop",
            "draft": true,
            "force-tag": true, <---Set "force-tag" to true
            "extra-files": [
                "src-tauri/Cargo.toml",
                "src-tauri/Cargo.lock"
            ]
        },
        "apps/web": {
            "release-type": "node",
            "package-name": "@acme/web",
            "draft": true,
            "force-tag": true, <---Set "force-tag" to true
        }
    },
    "$schema": "https://raw.githubusercontent.com/googleapis/release-please/main/schemas/config.json"
}

@Fanzzzd
Copy link
Contributor Author

Fanzzzd commented Nov 23, 2025

And I also forked the release-please action to test this branch more easily.

You can replace:

-  uses: googleapis/release-please-action@v4

in your release-please.yml with:

-  uses: Fanzzzd/release-please-action@release-with-force-tag

to try this new feature.

Here is the link for your interest: [Fanzzzd/release-please-action]

Copy link
Collaborator

@ferrarimarco ferrarimarco left a comment

Choose a reason for hiding this comment

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

Thanks for this PR. A few things to check, then I'll have a look at testing this.

…iption across code, schema, and documentation.
@Fanzzzd
Copy link
Contributor Author

Fanzzzd commented Dec 20, 2025

@ferrarimarco Thank you for the thorough review! I've addressed all your feedback:

  1. Renamed --force-tag to --force-tag-creation to better convey what the option does.
  2. Updated the description to "Force the creation of a Git tag for the release."
  3. Extended the documentation to explain why this is useful when draft is enabled - GitHub does not create tags for draft releases until they are published, which causes release-please to fail to find the previous release.

Please let me know if there's anything else you'd like me to adjust.

Copy link
Collaborator

@ferrarimarco ferrarimarco left a comment

Choose a reason for hiding this comment

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

Thanks. Added two minor comments.

@erka
Copy link

erka commented Jan 19, 2026

Hey @Fanzzzd and @ferrarimarco. Any progress with this? How could we help to push it forward?

Fanzzzd and others added 2 commits January 20, 2026 08:21
- add debug log on 422 when creating the tag
- revert unrelated formatting changes in config schema
@Fanzzzd
Copy link
Contributor Author

Fanzzzd commented Jan 20, 2026

@ferrarimarco , thank you for the review. I have addressed the two issues you mentioned.

@Fanzzzd Fanzzzd force-pushed the feat/draft-release-force-tag branch from 2c78dff to 5dfb877 Compare January 20, 2026 08:46
@chingor13 chingor13 merged commit e3eba37 into googleapis:main Jan 20, 2026
11 of 12 checks passed
@erka
Copy link

erka commented Jan 20, 2026

Thank you all so much!

sou06912-design

This comment was marked as spam.

WilliamBerryiii added a commit to microsoft/hve-core that referenced this pull request Feb 14, 2026
…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.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size: l Pull request size is large.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Using draft: true causes release-pr to fail to find the previous release.

6 participants