Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 20 additions & 4 deletions .github/workflows/cicd_comp_changelog-site-publish-phase.yml
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,16 @@ on:
description: 'Space-separated docker image tags produced by the deployment phase'
required: true
type: string
force:
description: 'Override human-edit protection and update in place. Manual operator use only — the release pipeline never sets this.'
required: false
type: boolean
default: false
released_date:
description: 'Availability date (yyyy-MM-dd). Defaults to today, which is correct for a live release; a manual backfill of an older release should pass that release''s own date.'
required: false
type: string
default: ''
allow_failure:
description: 'If true, job failures are non-blocking (used by release pipeline). Defaults to false.'
required: false
Expand Down Expand Up @@ -109,10 +119,12 @@ jobs:
DOTCMS_DEVSITE_URL: ${{ vars.DOTCMS_DEVSITE_URL }}
# Read once by the tool; never echoed to logs / GITHUB_OUTPUT / step summary.
DOTCMS_DEVSITE_RELEASENOTES_TOKEN: ${{ secrets.DOTCMS_DEVSITE_RELEASENOTES_TOKEN }}
# Service-account modUser id for human-edit protection (FR-011). --force is never
# passed here — override is a manual operator re-run only.
# Service-account modUser id for human-edit protection (FR-011). The release
# pipeline never sets force; only a manual operator re-run does.
DOTCMS_DEVSITE_RELEASENOTES_ACCOUNT: ${{ vars.DOTCMS_DEVSITE_RELEASENOTES_ACCOUNT }}
DOCKER_TAGS: ${{ inputs.docker_tags }}
FORCE: ${{ inputs.force }}
RELEASED_DATE: ${{ inputs.released_date }}
run: |
# Pick the sha-tagged dotcms/dotcms image (version_sha form, e.g.
# dotcms/dotcms:26.07.10-01_84b0486). The `_` in the glob excludes the floating
Expand All @@ -130,13 +142,17 @@ jobs:
# T005 contract (0 = success/skip via ::changelog-skip:: marker; non-zero = failure).
# This step itself always exits 0 so the branch steps run and the release is never
# blocked (FR-008); the job is also allow_failure as belt-and-suspenders.
# ponytail: empty force/released_date are the pipeline's path — same command as before.
FORCE_FLAG=""
[ "$FORCE" = "true" ] && FORCE_FLAG="--force"

set +e
OUTPUT=$(uv run changelog-publisher publish \
--version "$RELEASE_VERSION" \
--notes-file /tmp/site-release-notes.md \
--docker-image "$DOCKER_IMAGE" \
--released-date "$(date -u +%F)" \
--apply 2>&1)
--released-date "${RELEASED_DATE:-$(date -u +%F)}" \
--apply $FORCE_FLAG 2>&1)
RC=$?
set -e
echo "$OUTPUT"
Expand Down
112 changes: 112 additions & 0 deletions .github/workflows/cicd_manual_changelog-site-publish.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
#
# Changelog Site Publish — Manual Trigger
#
# Standalone workflow for (re-)publishing a release's changelog to dev.dotcms.com.
# Calls the same reusable component used by the release pipeline, so the credentials
# (DOTCMS_DEVSITE_URL / _RELEASENOTES_TOKEN / _RELEASENOTES_ACCOUNT) stay in repo
# vars+secrets — an operator needs only the release tag.
#
# Use cases:
# - A release whose site publish never ran (deployment failed, so the phase was skipped)
# - Re-syncing the site after hand-editing a GitHub release body
# - Overriding human-edit protection (`force`) after a skip names a human editor
#
# Prerequisite: the GitHub release body must already hold the changelog. Generate it
# first with cicd_ai-release-notes-backfill.yml — this workflow only copies, never writes.
#

name: 'Changelog Site Publish (Manual)'
run-name: "Changelog Site: ${{ inputs.release_tag }}"

on:
workflow_dispatch:
inputs:
release_tag:
description: 'Release tag to publish (e.g., v26.08.19-04)'
required: true
type: string
force:
description: 'Override human-edit protection — only after a dry run names a human editor'
required: false
type: boolean
default: false

concurrency:
group: changelog-site-publish-${{ inputs.release_tag }}
cancel-in-progress: false

jobs:
# The release pipeline gets release_version and docker_tags from upstream jobs. A manual
# run has neither, so derive both from the tag rather than making an operator hunt for a sha.
resolve:
name: Resolve Version and Image
runs-on: ubuntu-${{ vars.UBUNTU_RUNNER_VERSION || '24.04' }}
outputs:
release_version: ${{ steps.r.outputs.release_version }}
docker_tags: ${{ steps.r.outputs.docker_tags }}
released_date: ${{ steps.r.outputs.released_date }}
steps:
- name: Resolve
id: r
env:
RELEASE_TAG: ${{ inputs.release_tag }}
GH_TOKEN: ${{ secrets.CI_MACHINE_TOKEN || github.token }}
REPO: ${{ github.repository }}
run: |
set -euo pipefail
# The phase gates its publish job on startsWith(release_tag, 'v'). Without this
# check a tag typed without the prefix resolves fine, gets approved at the gate,
# and is then silently skipped -- a green run that published nothing.
case "$RELEASE_TAG" in
v*) ;;
*) echo "Error: release_tag must start with 'v' (got '$RELEASE_TAG')"; exit 1;;
esac

VERSION="${RELEASE_TAG#v}"
echo "release_version=${VERSION}" >> "$GITHUB_OUTPUT"

# Backfilling an older release must stamp that release's date, not today's.
PUBLISHED=$(gh release view "$RELEASE_TAG" --repo "$REPO" --json publishedAt --jq '.publishedAt[0:10]')
echo "released_date=${PUBLISHED}" >> "$GITHUB_OUTPUT"

# Prefer the sha-tagged image (e.g. 26.08.19-04_a0181f9) so a manual entry matches
# what the pipeline would have written. Hub is public; no auth needed.
TAG=$(curl -fsSL \
"https://hub.docker.com/v2/repositories/dotcms/dotcms/tags/?name=${VERSION}_&page_size=100" \
| jq -r --arg v "$VERSION" \
'[.results[].name | select(test("^" + $v + "_[0-9a-f]+$"))] | first // empty')
# ponytail: sha-less fallback keeps a publish possible if Hub paging ever changes shape.
echo "docker_tags=dotcms/dotcms:${TAG:-$VERSION}" >> "$GITHUB_OUTPUT"
echo "Resolved ${VERSION} -> dotcms/dotcms:${TAG:-$VERSION}"

# This writes to the public docs site with a service-account token, and workflow_dispatch
# is open to every account with write access on this repo (45 today). Reviewer approval
# is the access control — same pattern as cicd_evergreen-tracks-promote.yml's apply gate.
# The environment must carry required_reviewers; GitHub auto-creates it UNPROTECTED on
# first use if it is missing, which would silently remove this gate.
gate:
name: Approve Site Publish
needs: resolve
runs-on: ubuntu-${{ vars.UBUNTU_RUNNER_VERSION || '24.04' }}
environment: changelog-site-publish
steps:
- run: |
echo "Approved: publish ${{ inputs.release_tag }} to the changelog site"
echo "Image: ${{ needs.resolve.outputs.docker_tags }}"
echo "Date: ${{ needs.resolve.outputs.released_date }}"
echo "Force: ${{ inputs.force }}"

publish:
name: Publish Site Changelog
needs: [resolve, gate]
uses: ./.github/workflows/cicd_comp_changelog-site-publish-phase.yml
with:
release_tag: ${{ inputs.release_tag }}
release_version: ${{ needs.resolve.outputs.release_version }}
docker_tags: ${{ needs.resolve.outputs.docker_tags }}
released_date: ${{ needs.resolve.outputs.released_date }}
force: ${{ inputs.force }}
secrets:
DOTCMS_DEVSITE_RELEASENOTES_TOKEN: ${{ secrets.DOTCMS_DEVSITE_RELEASENOTES_TOKEN }}
SLACK_BOT_TOKEN: ${{ secrets.SLACK_BOT_TOKEN }}
CI_MACHINE_TOKEN: ${{ secrets.CI_MACHINE_TOKEN }}
Loading