dotCMS / dotCMS/core

Release pipeline silently clobbers the release branch when a published version is re-dispatched

Open
#37,380 1 comment 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Team : Enablement
Dominant language
Java
Stars
970
Forks
486
Avg merge
3d 33m
Merged PRs (30d)
170

Description

What happened

Release 26.09.02-01 shipped successfully on 2026-09-02 (run 33659151567) — tag v26.09.02-01 @ 7fe2ff5, GitHub release published, dotcms/dotcms:26.09.02-01 pushed to Docker Hub.

On 2026-09-03 the same version string was dispatched again (run 33780197124), this time against a main that was 54 commits ahead. The run got 24 minutes in — through Prepare and a full 15-minute artifact build — before being cancelled by hand at the Docker deploy step.

By then Prepare had already force-recreated release-26.09.02-01 at 81563d9, a commit 54 commits newer than the tag the branch is supposed to match. Had the run not been cancelled, it would have published Docker and Maven artifacts for 26.09.02-01 containing entirely different code than what already shipped under that version.

Root cause

.github/workflows/cicd_comp_release-prepare-phase.yml has two "already exists" guards, and they don't agree:

# line 148 — tag guard, checked against the LOCAL clone
if git rev-parse "${release_tag}" >/dev/null 2>&1; then
  echo "Tag ${release_tag} exists, removing it"
  git push origin :refs/tags/${release_tag}
fi

# line 165 — branch guard, checked against the REMOTE
remote=$(git ls-remote --heads https://github.com/dotCMS/core.git "${release_branch}" | wc -l | tr -d '[:space:]')
if [[ "${remote}" == '1' ]]; then
  echo "Release branch ${release_branch} already exists, removing it"
  git push origin :${release_branch}
fi

The checkout at line 103 is fetch-depth: 1 and pulls no tags, so git rev-parse "${release_tag}" is always false — the tag guard is dead code that can never fire. The branch guard queries the remote and works correctly.

That asymmetry is the whole bug: the branch was deleted and recreated, the tag was left alone. It broke in the safe direction purely by accident. If that rev-parse ever did resolve, the workflow would silently delete a published release tag — which is worse.

Neither guard is the right behavior anyway. Deleting and recreating a published release's branch/tag is never correct; the run should refuse to start.

Impact

  • release-26.09.02-01 misrepresented what shipped for ~2 hours (manually reset to 7fe2ff5).
  • 24 minutes of runner time and a full artifact build burned before a human caught it.
  • Nothing was published — QEMU setup was cancelled, so Docker build/push and the Release / Release Notes / Changelog jobs never ran.
  • Changelog generation was not affected: gather-release-data resolves its range from the releases API (findPreviousTag in .github/scripts/gather-release-data/src/github.ts), never from release branches.

Proposed fix

Fail fast in Prepare, immediately after Set Version Variables and before anything is mutated: if a GitHub Release already exists for release_tag, error out and tell the operator to bump the counter. Delete the dead git rev-parse tag block.

No force escape hatch. Bumping the counter on a failed attempt is already the established convention — 26.08.19-01, -02 and -03 all left behind empty-bodied releases before -04 shipped, and findPreviousTag already skips undocumented releases so the changelog range stays correct.

Acceptance criteria

  • Dispatching a release_version whose v<version> release already exists fails within the first minute with an actionable error.
  • The failure happens before the release branch is touched.
  • Dispatching a fresh version is unaffected.
  • The dead git rev-parse tag-deletion block is gone.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start in .github/workflows/cicd_comp_release-prepare-phase.yml, immediately after Set Version Variables, and inspect the existing tag and branch guards. Check the release-dispatch path and confirm the change preserves fresh-version runs while stopping before branch mutation when the GitHub Release already exists; verify the dead git rev-parse block is removed.

Written by the indexing model from the issue text.

Assessment

Tech stack
git, github-actions, shell
Domain
ci-cd, devops, release
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Active
Clarity
Clearly specified
Newbie friendliness
78/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.