Files
openclaw/.github/workflows/docker-channel-promote.yml
2026-07-24 12:05:51 -07:00

183 lines
6.7 KiB
YAML

name: Docker Channel Promotion
on:
workflow_dispatch:
inputs:
tag:
description: Existing stable or extended-stable release tag
required: true
type: string
env:
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: "true"
REGISTRY: ghcr.io
IMAGE_NAME: ${{ github.repository }}
DOCKERHUB_REGISTRY: docker.io
DOCKERHUB_IMAGE_NAME: openclaw/openclaw
jobs:
resolve:
runs-on: ubuntu-24.04
permissions:
contents: read
outputs:
version: ${{ steps.policy.outputs.version }}
channel: ${{ steps.policy.outputs.channel }}
default_aliases: ${{ steps.policy.outputs.default_aliases }}
slim_aliases: ${{ steps.policy.outputs.slim_aliases }}
browser_aliases: ${{ steps.policy.outputs.browser_aliases }}
steps:
- name: Require a main-branch dispatch
env:
WORKFLOW_REF: ${{ github.ref }}
run: |
set -euo pipefail
if [[ "${WORKFLOW_REF}" != "refs/heads/main" ]]; then
echo "::error::Docker channel promotion must be dispatched from main; got ${WORKFLOW_REF}."
exit 1
fi
- name: Checkout trusted promotion tooling
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
with:
ref: ${{ github.sha }}
fetch-depth: 0
persist-credentials: false
- name: Resolve release channel policy
id: policy
shell: bash
env:
RELEASE_TAG: ${{ inputs.tag }}
run: |
set -euo pipefail
if [[ ! "${RELEASE_TAG}" =~ ^v[0-9]{4}\.[1-9][0-9]*\.[1-9][0-9]*(-[1-9][0-9]*)?$ ]]; then
echo "::error::Expected a final stable or extended-stable release tag; got ${RELEASE_TAG}."
exit 1
fi
git rev-parse --verify "refs/tags/${RELEASE_TAG}^{commit}" >/dev/null
version="${RELEASE_TAG#v}"
policy="$(node scripts/lib/docker-release-policy.mjs "${version}")"
channel="$(jq -r '.channel' <<< "${policy}")"
default_aliases="$(jq -r '.movingAliases.default | join(" ")' <<< "${policy}")"
slim_aliases="$(jq -r '.movingAliases.slim | join(" ")' <<< "${policy}")"
browser_aliases="$(jq -r '.movingAliases.browser | join(" ")' <<< "${policy}")"
{
echo "version=${version}"
echo "channel=${channel}"
echo "default_aliases=${default_aliases}"
echo "slim_aliases=${slim_aliases}"
echo "browser_aliases=${browser_aliases}"
} >> "$GITHUB_OUTPUT"
{
echo "## Docker channel promotion plan"
echo "- Version: ${version}"
echo "- Channel: ${channel}"
echo "- Default aliases: ${default_aliases}"
echo "- Slim aliases: ${slim_aliases}"
echo "- Browser aliases: ${browser_aliases}"
} >> "$GITHUB_STEP_SUMMARY"
approve:
name: Approve ${{ inputs.tag }} to ${{ needs.resolve.outputs.channel }} (${{ needs.resolve.outputs.default_aliases }})
needs: resolve
# Keep human approval outside the queued writer so waiting for approval
# cannot block a tag-driven Docker release in docker-release-publish.
# WARNING: KEEP CHANNEL PROMOTION GATED BY THE docker-release ENVIRONMENT.
runs-on: ubuntu-24.04
environment: docker-release
permissions: {}
steps:
- name: Record approval
env:
RELEASE_TAG: ${{ inputs.tag }}
DEFAULT_ALIASES: ${{ needs.resolve.outputs.default_aliases }}
SLIM_ALIASES: ${{ needs.resolve.outputs.slim_aliases }}
BROWSER_ALIASES: ${{ needs.resolve.outputs.browser_aliases }}
run: |
echo "Approved Docker channel promotion for ${RELEASE_TAG}"
echo "Default aliases: ${DEFAULT_ALIASES}"
echo "Slim aliases: ${SLIM_ALIASES}"
echo "Browser aliases: ${BROWSER_ALIASES}"
promote:
needs: [resolve, approve]
runs-on: ubuntu-24.04
concurrency:
group: docker-release-publish
cancel-in-progress: false
queue: max
permissions:
contents: read
packages: write
steps:
- name: Validate Docker Hub publish credentials
env:
DOCKERHUB_USERNAME: ${{ secrets.DOCKERHUB_USERNAME }}
DOCKERHUB_TOKEN: ${{ secrets.DOCKERHUB_TOKEN }}
run: |
set -euo pipefail
if [[ -z "${DOCKERHUB_USERNAME}" || -z "${DOCKERHUB_TOKEN}" ]]; then
echo "::error::Docker Hub publishing requires DOCKERHUB_USERNAME and DOCKERHUB_TOKEN secrets."
exit 1
fi
- name: Checkout trusted promotion tooling
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
with:
ref: ${{ github.sha }}
persist-credentials: false
- name: Pre-pull BuildKit image
shell: bash
env:
BUILDKIT_IMAGE: moby/buildkit:buildx-stable-1
run: |
set -euo pipefail
for attempt in 1 2 3 4; do
if docker pull "${BUILDKIT_IMAGE}"; then
exit 0
fi
if [[ "${attempt}" -eq 4 ]]; then
echo "::error::Failed to pull ${BUILDKIT_IMAGE} after ${attempt} attempts."
exit 1
fi
sleep "$((attempt * 5))"
done
- name: Set up Docker Builder
uses: docker/setup-buildx-action@d7f5e7f509e45cec5c76c4d5afdd7de93d0b3df5 # v4.1.0
- name: Login to GitHub Container Registry
uses: docker/login-action@650006c6eb7dba73a995cc03b0b2d7f5ca915bee # v4.2.0
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.repository_owner }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Login to Docker Hub
uses: docker/login-action@650006c6eb7dba73a995cc03b0b2d7f5ca915bee # v4.2.0
with:
registry: ${{ env.DOCKERHUB_REGISTRY }}
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Promote and verify channel aliases
env:
VERSION: ${{ needs.resolve.outputs.version }}
GHCR_IMAGE: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
DOCKERHUB_IMAGE: ${{ env.DOCKERHUB_REGISTRY }}/${{ env.DOCKERHUB_IMAGE_NAME }}
run: |
set -euo pipefail
node scripts/docker-channel-promote.mjs \
--version "${VERSION}" \
--image "${GHCR_IMAGE}" \
--image "${DOCKERHUB_IMAGE}" \
--allow-rollback
{
echo "## Docker channel promotion"
echo "- Version: ${VERSION}"
echo "- Registries: ${GHCR_IMAGE}, ${DOCKERHUB_IMAGE}"
echo "- Rollback: explicitly approved"
} >> "$GITHUB_STEP_SUMMARY"