Skip to content

feat(release): patch release process for active release branches #35613

@sfreudenthaler

Description

@sfreudenthaler

User Story

As a release engineer, I want to apply targeted fixes to an active release branch and cut a patch release without including unrelated changes from `main`, so that customers on a supported version can receive critical updates without being forced onto a newer major release.

Problem

Two related gaps were discovered when executing a patch release against `v26.04.28-02`:

1. No documented patch release process
There was no repeatable workflow for isolating specific commits from `main`, verifying them against an existing release baseline, and cutting a numbered patch (e.g. `26.04.28-03`) from that baseline.

2. No reliable way to run the full test suite against a patch branch
The LTS Auto-run Tests workflow (`cicd_5-lts.yml`) fires automatically on any `release-*` push, but Postman tests require a Docker image tagged `dotcms/dotcms-test:{version}`. This image is only built as a local GitHub Actions artifact — it is never published to Docker Hub. The publicly-released image (`dotcms/dotcms:{version}`) IS on Docker Hub after the release workflow completes, but the test infrastructure ignores it because `docker.output.image.name` in `parent/pom.xml` and `dotcms-integration/pom.xml` is hardcoded to `dotcms/dotcms-test`.

This creates a fragile ordering dependency: if the LTS workflow fires before the release build finishes, the locally-built artifact doesn't exist yet and tests fail with a 404. Even after the release completes, there is no first-class way to re-run the full test suite against the now-available image without manually re-triggering failed CI jobs.

Additionally, the LTS workflow had a hardcoded `version: '24.12.27'` in the build phase causing the artifact to always be tagged with that version, while the test phase derived the image name from `maven.config` at runtime — so they never agreed on release branches.

Solution

Patch release workflow (established & validated, PR #35608)

  • Create `release-{version}-{patch}` from the existing `release-{version}` tag
  • Cherry-pick only substantive commits (skip merge-from-main noise commits)
  • Push branch, open PR against previous release branch for CI + reviews
  • Trigger `cicd_6-release.yml` in parallel via `workflow_dispatch` — release build and CI run concurrently, cutting total wall-clock time significantly
  • Re-run failed Postman jobs once release workflow completes: `gh run rerun --failed`

LTS workflow fix (PR #35612)

  • Replaced hardcoded `version: '24.12.27'` with a `setup` job that reads `-Drevision` + `-Dchangelist` from `.mvn/maven.config` at runtime — Docker artifact tag now matches what Maven computes for `project.version`
  • Added `workflow_dispatch` trigger with optional `version` input for manual re-triggers
  • Removed stale `pull_request.number` reference from concurrency group

Known gap — future work

The root issue is that the Postman and integration test infrastructure is coupled to a locally-built `dotcms/dotcms-test` image that only exists inside a CI run. The published `dotcms/dotcms:{version}` image is already available on Docker Hub after any release, but the test runner never uses it.

Recommended fix: When running against a release branch, configure the test infrastructure to pull `dotcms/dotcms:{version}` directly from Docker Hub instead of requiring the locally-built artifact. This means updating `docker.output.image.name` in `parent/pom.xml` / `dotcms-integration/pom.xml` (or making it a configurable property) and updating the LTS workflow to skip the build/artifact phase and instead pass the Hub image tag to the test phase directly. This would eliminate the timing dependency entirely and allow the test suite to be re-run on demand against any released version.

Implementation Status

✅ Patch release shipped as `v26.04.28-03`
✅ LTS workflow version fix in PR #35612

Patch Release Runbook

# 1. Branch from the existing release
git checkout -b release-{yy.mm.dd}-{patch} origin/release-{yy.mm.dd}-{prev}

# 2. Cherry-pick substantive commits (skip merge-from-main commits)
git cherry-pick <sha1> <sha2> ... <shaN>

# 3. Push — LTS workflow starts automatically
git push -u origin release-{yy.mm.dd}-{patch}

# 4. Open PR against the previous release branch (for CI + reviews)
gh pr create --base release-{yy.mm.dd}-{prev} --head release-{yy.mm.dd}-{patch}

# 5. Trigger the release in parallel
gh workflow run cicd_6-release.yml \
  --field release_version={yy.mm.dd}-{patch} \
  --field release_commit=$(git rev-parse HEAD)

# 6. Once release build completes, re-run any Postman failures
gh run rerun <lts-run-id> --failed

References

Metadata

Metadata

Labels

No labels
No labels
No fields configured for Feature.

Projects

Status
Done

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions