Skip to content

fix(cicd): publish the site changelog from the release-notes backfill - #37389

Open
sfreudenthaler wants to merge 2 commits into
mainfrom
issue-37388-backfill-publishes-site-changelog
Open

fix(cicd): publish the site changelog from the release-notes backfill#37389
sfreudenthaler wants to merge 2 commits into
mainfrom
issue-37388-backfill-publishes-site-changelog

Conversation

@sfreudenthaler

Copy link
Copy Markdown
Member

Closes: #37388

Problem

Four entries on the public changelog render with a title, date and docker tag but no notes26.08.28-01, 26.08.31-01, 26.08.31-02, 26.09.02-01. Their GitHub release bodies are fine (2.2k–6.8k chars). The site never got them.

flowchart TD
    subgraph before["before"]
        R1[Release run] --> N1["Generate notes<br/>❌ failed"]
        N1 --> E1["GitHub release body:<br/>empty"]
        E1 --> P1["Site publish<br/>✅ 'succeeded'<br/>published empty"]
        B1[Backfill] --> F1["GitHub release body:<br/>repaired"]
        F1 -.->|no path| P1
    end
    subgraph after["after"]
        B2[Backfill] --> F2["GitHub release body:<br/>repaired"]
        F2 --> RS[Resolve site inputs]
        RS --> P2["Site publish<br/>entry repaired"]
    end
    style P1 fill:#ffdddd,stroke:#cc0000
    style P2 fill:#ddffdd,stroke:#00aa00
Loading

cicd_ai-release-notes-backfill.yml had exactly one job — Generate Notes. It wrote the GitHub release body and stopped, so once an entry was published empty nothing could ever repair it.

(The reason they published empty in the first place is a separate defect: the phase's [ ! -s ] guard doesn't fire because --jq .body writes a bare newline for an empty body — 1 byte, not 0. Tracked separately, deliberately not fixed here.)

Change

A resolve-site-inputs job recovers the two things a backfill can't inherit from a deployment phase, then hands off to the existing publish phase. Net +78 / −1 across two files, no new tooling.

Docker image — selected on a 7-hex sha suffix, not a bare _:

.results[].name | select(startswith($v + "_")) | select(test("_[0-9a-f]{7}$"))

26.08.28-01_tainted and 26.08.31-01_tainted both exist and a looser match prefers them. Verified the selector reproduces exactly what each original run passed:

Version Resolved Original run's docker_tags
26.08.28-01 26.08.28-01_d5ab3fd dotcms/dotcms:26.08.28-01_d5ab3fd ...
26.08.31-01 26.08.31-01_a6d1271 dotcms/dotcms:26.08.31-01_a6d1271 ...
26.08.31-02 26.08.31-02_b1a33f2 dotcms/dotcms:26.08.31-02_b1a33f2 ...
26.09.02-01 26.09.02-01_2460a36 dotcms/dotcms:26.09.02-01_2460a36 ...

Negative case checked too — _tainted is not selected.

Availability date — from the release's published_at. publisher.py:154 writes released_date through verbatim on the update path, so the phase's $(date -u +%F) default would have relabelled 26.08.28-01 as "Available: Sep 3, 2026". The phase gains an optional released_date input; omitted, it still defaults to today, so the release pipeline is behaviourally unchanged.

Deliberate choices

  • No allow_failure. The release pipeline sets it so a changelog hiccup can never fail a software release (FR-008). A backfill has no release to protect, and a silent failure is the exact condition this PR ends.
  • CLI / LTS excluded, matching the notes phase's own gate.
  • Hard fail when no sha-tagged image is found rather than falling back to the bare :<version> tag — the site entry records the deployed image, and a backfill has no deployment to vouch for a guess.

Repairing the existing four

Not done by this PR. Once merged, dispatching the backfill for each of the four tags repairs them; the publisher upserts, so it updates the existing entries in place rather than duplicating.

🤖 Generated with Claude Code

The backfill workflow had one job: it regenerated the GitHub release body
and stopped. Nothing carried that body to dev.dotcms.com, so a release
whose notes generation failed published an empty site entry that no later
backfill could repair. Four entries are sitting empty right now
(26.08.28-01, 26.08.31-01, 26.08.31-02, 26.09.02-01) with correct GitHub
release bodies behind them.

Add a resolve job that recovers the two inputs a backfill can't inherit
from a deployment phase, then call the existing publish phase:

- Docker image, from Docker Hub. Selected on a 7-hex sha suffix rather than
  a bare "_", because <version>_tainted tags exist and a looser match
  prefers them. Verified to reproduce exactly what all four original runs
  passed.
- Availability date, from the release's published_at. publisher.py writes
  released_date through verbatim on the update path, so the phase's
  $(date -u +%F) default would relabel an old entry with today.

The publish phase gains an optional released_date input for that; omitted,
it still defaults to today, so the release pipeline is unchanged.

Closes: #37388

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@claude

claude Bot commented Sep 3, 2026

Copy link
Copy Markdown
Contributor

Claude finished @sfreudenthaler's task in 23s —— View job


Claude finished @sfreudenthaler's task in 2m 18s —— View job


Code Review

Reviewed the two workflow changes against origin/main. Focused on failure paths, job gating semantics, and the image/date resolution logic. Two non-blocking findings.

New Issues

  • 🟡 Medium: .github/workflows/cicd_ai-release-notes-backfill.yml:94 — The released_date resolution has no error guard, and a failure here silently re-introduces the exact bug this PR exists to prevent. The step runs without set -e/set -o pipefail, so if gh api .../releases/tags/${RELEASE_TAG} fails (transient error, token scope, wrong tag) released_date ends up empty, gets written to $GITHUB_OUTPUT, and the publish phase then falls back to ${RELEASED_DATE:-$(date -u +%F)} → today's date → relabels the old entry. The sha-tag path is hard-failed on empty (line 86), but the date path is not. Also, a release with a null published_at (e.g. draft) makes --jq .published_at emit null, so cut yields the literal string null as the date. Suggest failing hard when published_at is empty/null, mirroring the sha_tag guard. Fix this →

  • 🟡 Medium: .github/workflows/cicd_ai-release-notes-backfill.yml:82head -1 picks an arbitrary image when a version was rebuilt and has more than one sha-tagged tag. Assumption: the Docker Hub tags/?name= response is ordered newest-first. What to verify: that ordering isn't contractually guaranteed by the Docker Hub v2 API, so on a rebuilt version this could resolve to a stale (or non-deployed) sha and stamp the wrong image onto the site entry. For the four target tags you verified this is correct; the concern is future/rebuilt versions. Consider selecting deterministically (e.g. by last_updated) rather than relying on default order.

Notes (non-blocking, verified correct)

  • ✅ Gating is sound: resolve-site-inputs correctly includes success() alongside its custom if (a needs job with a custom if must state its own status gate), and changelog-site-publish has no if, so when resolve-site-inputs is skipped (CLI/LTS/non-v tags) the default success() semantics skip the publish job too — no empty publish.
  • ✅ The _[0-9a-f]{7}$ selector correctly rejects _tainted (non-hex), and the publish phase's own *_* loop then picks the sha-tagged token from docker_tags before the bare :<version> fallback.
  • ✅ Not passing allow_failure on the backfill is the right call and matches the PR rationale (no release to protect; a silent no-op is the bug being fixed).
  • ✅ Adding released_date as optional with default: '' keeps the release pipeline behaviourally unchanged, as claimed.

Neither finding is blocking. The first is the more meaningful one — worth closing the date path's failure gap so it matches the (already-hard-failing) image path.

• branch issue-37388-backfill-publishes-site-changelog

wezell
wezell previously approved these changes Sep 3, 2026

@wezell wezell left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

good, though you could have just had claude do it from your local

@sfreudenthaler

Copy link
Copy Markdown
Member Author

good, though you could have just had claude do it from your local

that’s how i did it cuz i wasn’t sure who’d be around to approve. This is so that I don’t have to do it next time ;)

resolve-site-inputs carried a custom `if` with no status function, leaving
it dependent on GitHub's implicit-success() behaviour for jobs. State it
explicitly: a backfill whose notes regeneration failed must not go on to
republish the site.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

@wezell wezell left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Now with more working

@sfreudenthaler
sfreudenthaler added this pull request to the merge queue Sep 4, 2026
@github-merge-queue
github-merge-queue Bot removed this pull request from the merge queue due to failed status checks Sep 4, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

AI: Safe To Rollback Area : CI/CD PR changes GitHub Actions/workflows

Projects

Status: No status

Development

Successfully merging this pull request may close these issues.

Release-notes backfill doesn't republish the devsite changelog, leaving entries permanently empty

2 participants