Skip to content

How to support RC builds and keep a grouped changelog for the final release? #1440

@cookielevanna5

Description

@cookielevanna5

How to support RC builds and keep a grouped changelog for the final release?

I’m struggling to design a correct CI/release workflow using python-semantic-release together with Woodpecker CI, and I feel like I’m mixing concepts incorrectly.

My goals are:

  • Accumulate multiple commits (feat/fix/chore/etc.)
  • Have them appear under a single grouped version in the changelog (e.g. v2.1.0)
  • Still be able to generate and use versioned RC builds (v2.1.0-rc.1, rc.2, etc.) for testing before release
  • Maintain a clean and predictable CI/CD flow

What I tried

1. dev + main with semantic-release on both

  • Feature branches → squash merge into dev
  • Run semantic-release on dev → generates vX.Y.Z-rc.N
  • Then merge dev → main and run semantic-release again

Problem:

  • Each RC bumps version and updates the changelog
  • When merging to main, commits are already “consumed”
  • Final changelog is fragmented across multiple RC entries instead of grouped

2. Rebase + squash workflow

  • Squash commits into dev
  • Rebase dev onto main

Problem:

  • Breaks git history
  • semantic-release cannot properly detect previous tags
  • Version calculation becomes incorrect (falls back to older versions)

3. Adding a release/* branch

  • dev → release/x.y (merge commit)
  • Run semantic-release on release/x.y → RC versions
  • Merge release/x.y → main

Problem:

  • RC releases still update changelog and consume commits
  • Final release on main does not regroup all changes under one version
  • Changelog remains split across multiple RC entries

Core issue

It seems like running semantic-release on prerelease branches (dev or release/*):

  • “Consumes” commits by generating versions and changelog entries
  • Prevents those commits from being grouped later in the final release on main

At the same time, I still need:

  • Versioned artifacts for testing (e.g. Docker images for a FastAPI app)
  • Ability to test individual features or combinations before a stable release

Additional constraint

If I stop using RC versions on dev:

  • I lose structured versioning for test deployments
  • I can only rely on commit SHA-based builds
  • This makes version tracking less clear compared to semantic versions

What I want to achieve

An ideal workflow would:

  • Allow continuous feature integration on dev
  • Allow creation of versioned RC builds for testing (e.g. v2.1.0-rc.1)
  • Ensure that when releasing to main, the changelog is fully grouped:
## v2.1.0

### Features
- feature A
- feature B

### Fixes
- fix C

and not split across multiple RC entries.

Questions

  1. What is the correct way to structure branches and CI with python-semantic-release to support both:
  • RC builds
  • grouped final changelog?
  1. Should semantic-release be:
  • run only on main?
  • or also on prerelease branches but with limited plugins (e.g. no changelog)?
  1. How should test deployments be handled properly?
  • Use commit SHA-based images?
  • Or rely on RC versions?
  1. Is there a recommended pattern for this (especially with Woodpecker CI), or am I fundamentally misusing semantic-release?

Tech stack

  • python-semantic-release
  • Woodpecker CI
  • FastAPI app (Dockerized)
  • Conventional commits

Any guidance or real-world examples would be highly appreciated 🙏

Configuration

Pretty basic config for now, I'm open to changes, perhaps I did something wrong

Semantic Release Configuration
[semantic_release]
commit_message = "{version} [skip ci]\n\nAutomatically generated by python-semantic-release"
commit_parser = "conventional"
tag_format = "v{version}"

[semantic_release.branches.main]
match = "(main|master)"
prerelease = false

[semantic_release.branches.dev]
match = "dev"
prerelease_token = "rc"
prerelease = true
.woodpecker.yaml
when:
  event: push
  branch:
    - dev
    - main

skip_clone: true

steps:
  semantic-release:
    image: python:3.14.3-slim
    environment:
      GH_TOKEN:
        from_secret: cookie-github-token
    commands:
      - apt-get update && apt-get install -y git
      - git clone "$CI_REPO_CLONE_URL" && cd "$CI_REPO_NAME" && git checkout "$CI_COMMIT_BRANCH"
      - pip install python-semantic-release
      - semantic-release -vv --config releaserc.toml version --skip-build --no-vcs-release

Additional context

I tried lots of things before but right now it looks like this

git log --oneline --decorate --graph --all -n 50
* 46896df (tag: v2.2.0, origin/main, origin/HEAD, main) 2.2.0 [skip ci]
*   33af00a Dev (#33)
|\
| * effc434 (HEAD -> feat/letssee, tag: v2.2.0-rc.2, origin/dev, dev) 2.2.0-rc.2 [skip ci]
| * 44893d2 fix: huh what the heck why not (#32)
| * e468fb7 (tag: v2.2.0-rc.1) 2.2.0-rc.1 [skip ci]
| * 0212f35 feat: trying something interesting (#30)
| | * 18a82a8 (origin/feature/diff, feature/diff) huh what the heck why not
| |/
| | * 0223404 (origin/feature/newone, feature/newone) lets try
| |/
| *   7682309 finale? [skip ci]
| |\
| |/
|/|
* | 1f992d4 (tag: v2.1.0) 2.1.0 [skip ci]
* | 8084339 feat: finale supposedly lmao (#28)
* | 13bea6f (tag: v2.0.1) 2.0.1 [skip ci]
* | 7c8651e fix: try fixie fix (#25)
* | df53a68 (tag: v2.0.0) 2.0.0 [skip ci]
* |   df54475 Dev (#24)
|\ \
* | | db66d0c (tag: v1.0.0) 1.0.0 [skip ci]
* | |   d3c9292 Dev (#19)
|\ \ \
| | | *   4f0ebbe Merge branch 'dev' of github.com:cookielevanna5/computer-networks into dev
| | | |\
| | | | * 8d6d7f8 (tag: v1.0.0-rc.3) feat: finale supposedly lmao (#28)
| | | | | * cab06a4 (origin/feature/finale, feature/finale) finale?
| | | | |/
| | | |/|
| | | * | 76003e1 Merge branch 'dev' of github.com:cookielevanna5/computer-networks into dev
| | | |\|
| | | | * bf46a02 lets see [skip ci] (#27)
| | | | * 6f491b5 (tag: v1.0.0-rc.2) fix: try fixie fix (#25)
| | | |/
| | |/|
| | | | * ef9b155 (origin/feature/ohno, feature/ohno) alalal
| | | |/
| | | *   743a365 Merge branch 'dev' of github.com:cookielevanna5/computer-networks into dev
| | | |\
| | | |/
| | |/|
| | * | 9ad36ac (tag: v1.0.0-rc.1) feat: completely oops (#23)
| | * | fcc6e5d fix: oops (#22)
| | | | * 947dc92 (origin/feature/oops, feature/oops) princewwwwww
| | | | * 26d1138 prince
| | | |/
| | | *   ed883b7 Merge branch 'dev' of github.com:cookielevanna5/computer-networks into dev
| | | |\
| | | |/
| | |/|
| | * | f74d7f5 feat(wow)!: amazing wowowow (#21)
| | | | *   8c6ebe2 (origin/feature/another) Merge branch 'dev' into feature/another
| | | | |\
| | | |_|/
| | |/| |
| | * | | fd0a973 fix(semantic-release): lets see (#20)
| |/ / /
| | | * 7d01a1a (feature/another) fadiha rezah
| | |/
| | | * 2851a4b (origin/feature/see, feature/see) major_on_zero ssstrue
| | |/
| | *   019824b Merge branch 'dev' of github.com:cookielevanna5/computer-networks into dev
| | |\
| | |/
| |/|
| * | 57dfcf2 (tag: v0.1.0-rc.7) feat(conf): major_on_zero set to true (#18)
| | | * d5ee345 (origin/feature/major) major_on_zero true
| | |/
| | *   05f2d53 Merge branch 'dev' of github.com:cookielevanna5/computer-networks into dev
| | |\
| | |/
| |/|
| * | 6351115 (tag: v0.1.0-rc.6) feat(api)!: something incredibly different wowowow (#17)
| * | 4776420 (tag: v0.1.0-rc.5) feat(trying): interesting (#16)
| | | * 9d8a477 (origin/feature/sheraton) lolol 67
| | |/
| | | * 9fed372 (origin/feature/lol) lolol
| | |/
| | *   3226331 Merge branch 'dev' of github.com:cookielevanna5/computer-networks into dev
| | |\
| | |/
| |/|
| * | 80c90e7 (tag: v0.1.0-rc.4) fix(api): found something great in api wow (#15)
| | | * 33f14d0 (origin/feature/try) added distinguishing between stuff
| | | *   55a413e Merge branch 'dev' into feature/try
| | | |\
| | | |/
| | |/|
| | * |   d0700ec Merge branch 'main' into dev
| | |\ \
| |_|/ /
|/| | |
| | * | 1cfb03a try lololo 67
| |/ /
| | *   ad636e1 Merge branch 'main' into feature/try
| | |\
| |_|/
|/| |

Metadata

Metadata

Assignees

No one assigned

    Labels

    duplicateThis issue or pull request already existsquestion

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions