Files
openclaw/.github/workflows/docker-image-refresh.yml
T
Peter Steinberger b376b13fec feat(docker): weekly refresh of published moving image tags (#123348)
* feat(docker): schedule image refreshes

* docs(docker): explain weekly image refreshes

* test(scripts): gate workflow-step execution on bash 4 mapfile support

Stock macOS bash 3.2 lacks mapfile; CI truth is Linux bash 5.

* test: cover docker-release suffix threading and sanctioned second caller

* test(codex): wire run-attempt-state into the attempt-extra project

#123345 added the file without a project owner; the full-suite coverage
guard fails for any PR that runs it.

* fix(ci): run build-artifacts PR validation on hosted runners

ci-build-artifacts-testbox.yml pinned PR runs to blacksmith-16vcpu and
ran Testbox lifecycle steps unconditionally, so the prepare-run landing
gate starved for every PR during a Blacksmith outage even with
OPENCLAW_CI_RUNNER_BACKEND=github. PR events now build on ubuntu-24.04
with dispatch-only Testbox steps, mirroring ci-check-testbox.yml.

* test(ci): align build-artifacts dispatch guard
2026-08-13 19:20:05 -07:00

139 lines
4.5 KiB
YAML

name: Docker Image Refresh
on:
workflow_dispatch:
inputs:
channel:
description: Release channel to rebuild
required: false
default: both
type: choice
options:
- stable
- extended-stable
- both
dry_run:
description: Resolve and summarize without publishing
required: false
default: false
type: boolean
schedule:
- cron: "17 3 * * 1"
permissions:
contents: read
env:
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: "true"
jobs:
plan:
runs-on: ubuntu-24.04
permissions:
contents: read
outputs:
dry_run: ${{ steps.plan.outputs.dry_run }}
image_tag_suffix: ${{ steps.plan.outputs.image_tag_suffix }}
matrix: ${{ steps.plan.outputs.matrix }}
steps:
- name: Require a main-branch run
env:
WORKFLOW_REF: ${{ github.ref }}
run: |
set -euo pipefail
if [[ "${WORKFLOW_REF}" != "refs/heads/main" ]]; then
echo "::error::Docker image refresh must run from main; got ${WORKFLOW_REF}."
exit 1
fi
- name: Checkout trusted refresh tooling
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
with:
ref: ${{ github.sha }}
fetch-depth: 0
persist-credentials: false
- name: Resolve refresh plan
id: plan
shell: bash
env:
CHANNEL: ${{ github.event_name == 'schedule' && 'both' || inputs.channel }}
DRY_RUN: ${{ github.event_name == 'schedule' && 'false' || inputs.dry_run }}
run: |
set -euo pipefail
current="$(git tag --list 'v*' | node scripts/lib/docker-release-policy.mjs --current)"
stable_tag="$(jq -er '.stable.tag' <<< "${current}")"
extended_stable_tag="$(jq -er '.extendedStable.tag' <<< "${current}")"
stable_sha="$(git rev-parse "refs/tags/${stable_tag}^{commit}")"
extended_stable_sha="$(git rev-parse "refs/tags/${extended_stable_tag}^{commit}")"
suffix="-r$(date -u +%Y%m%d)"
stable_entry="$(
jq -cn \
--arg channel stable \
--arg tag "${stable_tag}" \
--arg release_sha "${stable_sha}" \
'{channel: $channel, tag: $tag, release_sha: $release_sha}'
)"
extended_stable_entry="$(
jq -cn \
--arg channel extended-stable \
--arg tag "${extended_stable_tag}" \
--arg release_sha "${extended_stable_sha}" \
'{channel: $channel, tag: $tag, release_sha: $release_sha}'
)"
case "${CHANNEL}" in
stable)
matrix="$(jq -cn --argjson stable "${stable_entry}" '[$stable]')"
;;
extended-stable)
matrix="$(jq -cn --argjson extended "${extended_stable_entry}" '[$extended]')"
;;
both)
matrix="$(
jq -cn \
--argjson stable "${stable_entry}" \
--argjson extended "${extended_stable_entry}" \
'[$stable, $extended]'
)"
;;
*)
echo "::error::Unsupported Docker refresh channel: ${CHANNEL}"
exit 1
;;
esac
{
echo "dry_run=${DRY_RUN}"
echo "image_tag_suffix=${suffix}"
echo "matrix=${matrix}"
} >> "${GITHUB_OUTPUT}"
{
echo "## Docker image refresh plan"
echo "- Stable: ${stable_tag} (${stable_sha})"
echo "- Extended stable: ${extended_stable_tag} (${extended_stable_sha})"
echo "- Image tag suffix: ${suffix}"
echo "- Selected channel: ${CHANNEL}"
echo "- Dry run: ${DRY_RUN}"
} >> "${GITHUB_STEP_SUMMARY}"
publish:
name: Refresh ${{ matrix.channel }} Docker images
needs: plan
if: needs.plan.outputs.dry_run != 'true'
strategy:
fail-fast: false
matrix:
include: ${{ fromJSON(needs.plan.outputs.matrix) }}
uses: ./.github/workflows/docker-release.yml
with:
tag: ${{ matrix.tag }}
release_sha: ${{ matrix.release_sha }}
image_tag_suffix: ${{ needs.plan.outputs.image_tag_suffix }}
secrets:
DOCKERHUB_USERNAME: ${{ secrets.DOCKERHUB_USERNAME }}
DOCKERHUB_TOKEN: ${{ secrets.DOCKERHUB_TOKEN }}
permissions:
contents: read
packages: write