mirror of https://github.com/openclaw/openclaw.git
384 lines
13 KiB
YAML
384 lines
13 KiB
YAML
name: Docker Release
|
|
|
|
on:
|
|
push:
|
|
branches:
|
|
- main
|
|
tags:
|
|
- "v*"
|
|
paths-ignore:
|
|
- "docs/**"
|
|
- "**/*.md"
|
|
- "**/*.mdx"
|
|
- ".agents/**"
|
|
- "skills/**"
|
|
workflow_dispatch:
|
|
inputs:
|
|
tag:
|
|
description: Existing release tag to backfill (for example v2026.3.13)
|
|
required: true
|
|
type: string
|
|
|
|
concurrency:
|
|
group: docker-release-${{ github.workflow }}-${{ github.event_name == 'workflow_dispatch' && inputs.tag || github.ref }}
|
|
cancel-in-progress: false
|
|
|
|
env:
|
|
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: "true"
|
|
REGISTRY: ghcr.io
|
|
IMAGE_NAME: ${{ github.repository }}
|
|
|
|
jobs:
|
|
validate_manual_backfill:
|
|
if: github.event_name == 'workflow_dispatch'
|
|
runs-on: ubuntu-24.04
|
|
permissions:
|
|
contents: read
|
|
steps:
|
|
- name: Validate tag input format
|
|
env:
|
|
RELEASE_TAG: ${{ inputs.tag }}
|
|
run: |
|
|
set -euo pipefail
|
|
if [[ ! "${RELEASE_TAG}" =~ ^v[0-9]{4}\.[1-9][0-9]*\.[1-9][0-9]*(-beta\.[1-9][0-9]*)?$ ]]; then
|
|
echo "Invalid release tag: ${RELEASE_TAG}"
|
|
exit 1
|
|
fi
|
|
|
|
- name: Checkout selected tag
|
|
uses: actions/checkout@v6
|
|
with:
|
|
ref: refs/tags/${{ inputs.tag }}
|
|
fetch-depth: 0
|
|
|
|
approve_manual_backfill:
|
|
if: github.event_name == 'workflow_dispatch'
|
|
needs: validate_manual_backfill
|
|
# WARNING: KEEP MANUAL BACKFILLS GATED BY THE docker-release ENVIRONMENT.
|
|
runs-on: ubuntu-24.04
|
|
environment: docker-release
|
|
steps:
|
|
- name: Approve Docker backfill
|
|
env:
|
|
RELEASE_TAG: ${{ inputs.tag }}
|
|
run: echo "Approved Docker backfill for $RELEASE_TAG"
|
|
|
|
# KEEP THIS WORKFLOW ON GITHUB-HOSTED RUNNERS.
|
|
# DO NOT MOVE IT BACK TO BLACKSMITH WITHOUT RE-VALIDATING TAG BUILDS AND BACKFILLS.
|
|
# Build amd64 images (default + slim share the build stage cache)
|
|
build-amd64:
|
|
needs: [approve_manual_backfill]
|
|
if: ${{ always() && (github.event_name != 'workflow_dispatch' || needs.approve_manual_backfill.result == 'success') }}
|
|
# WARNING: DO NOT REVERT THIS TO A BLACKSMITH RUNNER WITHOUT RE-VALIDATING TAG BACKFILLS.
|
|
runs-on: ubuntu-24.04
|
|
permissions:
|
|
packages: write
|
|
contents: read
|
|
outputs:
|
|
digest: ${{ steps.build.outputs.digest }}
|
|
slim-digest: ${{ steps.build-slim.outputs.digest }}
|
|
steps:
|
|
- name: Checkout
|
|
uses: actions/checkout@v6
|
|
with:
|
|
ref: ${{ github.event_name == 'workflow_dispatch' && format('refs/tags/{0}', inputs.tag) || github.ref }}
|
|
fetch-depth: 0
|
|
|
|
- name: Set up Docker Builder
|
|
uses: docker/setup-buildx-action@v4
|
|
|
|
- name: Login to GitHub Container Registry
|
|
uses: docker/login-action@v4
|
|
with:
|
|
registry: ${{ env.REGISTRY }}
|
|
username: ${{ github.repository_owner }}
|
|
password: ${{ secrets.GITHUB_TOKEN }}
|
|
|
|
- name: Resolve image tags (amd64)
|
|
id: tags
|
|
shell: bash
|
|
env:
|
|
IMAGE: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
|
|
SOURCE_REF: ${{ github.event_name == 'workflow_dispatch' && format('refs/tags/{0}', inputs.tag) || github.ref }}
|
|
run: |
|
|
set -euo pipefail
|
|
tags=()
|
|
slim_tags=()
|
|
if [[ "${SOURCE_REF}" == "refs/heads/main" ]]; then
|
|
tags+=("${IMAGE}:main-amd64")
|
|
slim_tags+=("${IMAGE}:main-slim-amd64")
|
|
fi
|
|
if [[ "${SOURCE_REF}" == refs/tags/v* ]]; then
|
|
version="${SOURCE_REF#refs/tags/v}"
|
|
tags+=("${IMAGE}:${version}-amd64")
|
|
slim_tags+=("${IMAGE}:${version}-slim-amd64")
|
|
fi
|
|
if [[ ${#tags[@]} -eq 0 ]]; then
|
|
echo "::error::No amd64 tags resolved for ref ${SOURCE_REF}"
|
|
exit 1
|
|
fi
|
|
{
|
|
echo "value<<EOF"
|
|
printf "%s\n" "${tags[@]}"
|
|
echo "EOF"
|
|
} >> "$GITHUB_OUTPUT"
|
|
{
|
|
echo "slim<<EOF"
|
|
printf "%s\n" "${slim_tags[@]}"
|
|
echo "EOF"
|
|
} >> "$GITHUB_OUTPUT"
|
|
|
|
- name: Resolve OCI labels (amd64)
|
|
id: labels
|
|
shell: bash
|
|
env:
|
|
SOURCE_REF: ${{ github.event_name == 'workflow_dispatch' && format('refs/tags/{0}', inputs.tag) || github.ref }}
|
|
run: |
|
|
set -euo pipefail
|
|
source_sha="$(git rev-parse HEAD)"
|
|
version="${source_sha}"
|
|
if [[ "${SOURCE_REF}" == "refs/heads/main" ]]; then
|
|
version="main"
|
|
fi
|
|
if [[ "${SOURCE_REF}" == refs/tags/v* ]]; then
|
|
version="${SOURCE_REF#refs/tags/v}"
|
|
fi
|
|
created="$(date -u +%Y-%m-%dT%H:%M:%SZ)"
|
|
{
|
|
echo "value<<EOF"
|
|
echo "org.opencontainers.image.revision=${source_sha}"
|
|
echo "org.opencontainers.image.version=${version}"
|
|
echo "org.opencontainers.image.created=${created}"
|
|
echo "EOF"
|
|
} >> "$GITHUB_OUTPUT"
|
|
|
|
- name: Build and push amd64 image
|
|
id: build
|
|
# WARNING: KEEP THE OFFICIAL DOCKER ACTION HERE; DO NOT SWITCH THIS BACK TO BLACKSMITH BLINDLY.
|
|
uses: docker/build-push-action@v6
|
|
with:
|
|
context: .
|
|
platforms: linux/amd64
|
|
tags: ${{ steps.tags.outputs.value }}
|
|
labels: ${{ steps.labels.outputs.value }}
|
|
provenance: false
|
|
push: true
|
|
|
|
- name: Build and push amd64 slim image
|
|
id: build-slim
|
|
# WARNING: KEEP THE OFFICIAL DOCKER ACTION HERE; DO NOT SWITCH THIS BACK TO BLACKSMITH BLINDLY.
|
|
uses: docker/build-push-action@v6
|
|
with:
|
|
context: .
|
|
platforms: linux/amd64
|
|
build-args: |
|
|
OPENCLAW_VARIANT=slim
|
|
tags: ${{ steps.tags.outputs.slim }}
|
|
labels: ${{ steps.labels.outputs.value }}
|
|
provenance: false
|
|
push: true
|
|
|
|
# Build arm64 images (default + slim share the build stage cache)
|
|
build-arm64:
|
|
needs: [approve_manual_backfill]
|
|
if: ${{ always() && (github.event_name != 'workflow_dispatch' || needs.approve_manual_backfill.result == 'success') }}
|
|
# WARNING: DO NOT REVERT THIS TO A BLACKSMITH RUNNER WITHOUT RE-VALIDATING TAG BACKFILLS.
|
|
runs-on: ubuntu-24.04-arm
|
|
permissions:
|
|
packages: write
|
|
contents: read
|
|
outputs:
|
|
digest: ${{ steps.build.outputs.digest }}
|
|
slim-digest: ${{ steps.build-slim.outputs.digest }}
|
|
steps:
|
|
- name: Checkout
|
|
uses: actions/checkout@v6
|
|
with:
|
|
ref: ${{ github.event_name == 'workflow_dispatch' && format('refs/tags/{0}', inputs.tag) || github.ref }}
|
|
fetch-depth: 0
|
|
|
|
- name: Set up Docker Builder
|
|
uses: docker/setup-buildx-action@v4
|
|
|
|
- name: Login to GitHub Container Registry
|
|
uses: docker/login-action@v4
|
|
with:
|
|
registry: ${{ env.REGISTRY }}
|
|
username: ${{ github.repository_owner }}
|
|
password: ${{ secrets.GITHUB_TOKEN }}
|
|
|
|
- name: Resolve image tags (arm64)
|
|
id: tags
|
|
shell: bash
|
|
env:
|
|
IMAGE: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
|
|
SOURCE_REF: ${{ github.event_name == 'workflow_dispatch' && format('refs/tags/{0}', inputs.tag) || github.ref }}
|
|
run: |
|
|
set -euo pipefail
|
|
tags=()
|
|
slim_tags=()
|
|
if [[ "${SOURCE_REF}" == "refs/heads/main" ]]; then
|
|
tags+=("${IMAGE}:main-arm64")
|
|
slim_tags+=("${IMAGE}:main-slim-arm64")
|
|
fi
|
|
if [[ "${SOURCE_REF}" == refs/tags/v* ]]; then
|
|
version="${SOURCE_REF#refs/tags/v}"
|
|
tags+=("${IMAGE}:${version}-arm64")
|
|
slim_tags+=("${IMAGE}:${version}-slim-arm64")
|
|
fi
|
|
if [[ ${#tags[@]} -eq 0 ]]; then
|
|
echo "::error::No arm64 tags resolved for ref ${SOURCE_REF}"
|
|
exit 1
|
|
fi
|
|
{
|
|
echo "value<<EOF"
|
|
printf "%s\n" "${tags[@]}"
|
|
echo "EOF"
|
|
} >> "$GITHUB_OUTPUT"
|
|
{
|
|
echo "slim<<EOF"
|
|
printf "%s\n" "${slim_tags[@]}"
|
|
echo "EOF"
|
|
} >> "$GITHUB_OUTPUT"
|
|
|
|
- name: Resolve OCI labels (arm64)
|
|
id: labels
|
|
shell: bash
|
|
env:
|
|
SOURCE_REF: ${{ github.event_name == 'workflow_dispatch' && format('refs/tags/{0}', inputs.tag) || github.ref }}
|
|
run: |
|
|
set -euo pipefail
|
|
source_sha="$(git rev-parse HEAD)"
|
|
version="${source_sha}"
|
|
if [[ "${SOURCE_REF}" == "refs/heads/main" ]]; then
|
|
version="main"
|
|
fi
|
|
if [[ "${SOURCE_REF}" == refs/tags/v* ]]; then
|
|
version="${SOURCE_REF#refs/tags/v}"
|
|
fi
|
|
created="$(date -u +%Y-%m-%dT%H:%M:%SZ)"
|
|
{
|
|
echo "value<<EOF"
|
|
echo "org.opencontainers.image.revision=${source_sha}"
|
|
echo "org.opencontainers.image.version=${version}"
|
|
echo "org.opencontainers.image.created=${created}"
|
|
echo "EOF"
|
|
} >> "$GITHUB_OUTPUT"
|
|
|
|
- name: Build and push arm64 image
|
|
id: build
|
|
# WARNING: KEEP THE OFFICIAL DOCKER ACTION HERE; DO NOT SWITCH THIS BACK TO BLACKSMITH BLINDLY.
|
|
uses: docker/build-push-action@v6
|
|
with:
|
|
context: .
|
|
platforms: linux/arm64
|
|
tags: ${{ steps.tags.outputs.value }}
|
|
labels: ${{ steps.labels.outputs.value }}
|
|
provenance: false
|
|
push: true
|
|
|
|
- name: Build and push arm64 slim image
|
|
id: build-slim
|
|
# WARNING: KEEP THE OFFICIAL DOCKER ACTION HERE; DO NOT SWITCH THIS BACK TO BLACKSMITH BLINDLY.
|
|
uses: docker/build-push-action@v6
|
|
with:
|
|
context: .
|
|
platforms: linux/arm64
|
|
build-args: |
|
|
OPENCLAW_VARIANT=slim
|
|
tags: ${{ steps.tags.outputs.slim }}
|
|
labels: ${{ steps.labels.outputs.value }}
|
|
provenance: false
|
|
push: true
|
|
|
|
# Create multi-platform manifests
|
|
create-manifest:
|
|
needs: [approve_manual_backfill, build-amd64, build-arm64]
|
|
if: ${{ always() && needs.build-amd64.result == 'success' && needs.build-arm64.result == 'success' && (github.event_name != 'workflow_dispatch' || needs.approve_manual_backfill.result == 'success') }}
|
|
# WARNING: DO NOT REVERT THIS TO A BLACKSMITH RUNNER WITHOUT RE-VALIDATING TAG BACKFILLS.
|
|
runs-on: ubuntu-24.04
|
|
permissions:
|
|
packages: write
|
|
contents: read
|
|
steps:
|
|
- name: Checkout
|
|
uses: actions/checkout@v6
|
|
with:
|
|
ref: ${{ github.event_name == 'workflow_dispatch' && format('refs/tags/{0}', inputs.tag) || github.ref }}
|
|
fetch-depth: 0
|
|
|
|
- name: Login to GitHub Container Registry
|
|
uses: docker/login-action@v4
|
|
with:
|
|
registry: ${{ env.REGISTRY }}
|
|
username: ${{ github.repository_owner }}
|
|
password: ${{ secrets.GITHUB_TOKEN }}
|
|
|
|
- name: Resolve manifest tags
|
|
id: tags
|
|
shell: bash
|
|
env:
|
|
IMAGE: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
|
|
SOURCE_REF: ${{ github.event_name == 'workflow_dispatch' && format('refs/tags/{0}', inputs.tag) || github.ref }}
|
|
IS_MANUAL_BACKFILL: ${{ github.event_name == 'workflow_dispatch' && '1' || '0' }}
|
|
run: |
|
|
set -euo pipefail
|
|
tags=()
|
|
slim_tags=()
|
|
if [[ "${SOURCE_REF}" == "refs/heads/main" ]]; then
|
|
tags+=("${IMAGE}:main")
|
|
slim_tags+=("${IMAGE}:main-slim")
|
|
fi
|
|
if [[ "${SOURCE_REF}" == refs/tags/v* ]]; then
|
|
version="${SOURCE_REF#refs/tags/v}"
|
|
tags+=("${IMAGE}:${version}")
|
|
slim_tags+=("${IMAGE}:${version}-slim")
|
|
# Manual backfills should only republish the requested version tags.
|
|
if [[ "${IS_MANUAL_BACKFILL}" != "1" && "$version" =~ ^[0-9]+\.[0-9]+\.[0-9]+(-[0-9]+)?$ ]]; then
|
|
tags+=("${IMAGE}:latest")
|
|
slim_tags+=("${IMAGE}:slim")
|
|
fi
|
|
fi
|
|
if [[ ${#tags[@]} -eq 0 ]]; then
|
|
echo "::error::No manifest tags resolved for ref ${SOURCE_REF}"
|
|
exit 1
|
|
fi
|
|
{
|
|
echo "value<<EOF"
|
|
printf "%s\n" "${tags[@]}"
|
|
echo "EOF"
|
|
} >> "$GITHUB_OUTPUT"
|
|
{
|
|
echo "slim<<EOF"
|
|
printf "%s\n" "${slim_tags[@]}"
|
|
echo "EOF"
|
|
} >> "$GITHUB_OUTPUT"
|
|
|
|
- name: Create and push default manifest
|
|
shell: bash
|
|
run: |
|
|
set -euo pipefail
|
|
mapfile -t tags <<< "${{ steps.tags.outputs.value }}"
|
|
args=()
|
|
for tag in "${tags[@]}"; do
|
|
[ -z "$tag" ] && continue
|
|
args+=("-t" "$tag")
|
|
done
|
|
docker buildx imagetools create "${args[@]}" \
|
|
${{ needs.build-amd64.outputs.digest }} \
|
|
${{ needs.build-arm64.outputs.digest }}
|
|
|
|
- name: Create and push slim manifest
|
|
shell: bash
|
|
run: |
|
|
set -euo pipefail
|
|
mapfile -t tags <<< "${{ steps.tags.outputs.slim }}"
|
|
args=()
|
|
for tag in "${tags[@]}"; do
|
|
[ -z "$tag" ] && continue
|
|
args+=("-t" "$tag")
|
|
done
|
|
docker buildx imagetools create "${args[@]}" \
|
|
${{ needs.build-amd64.outputs.slim-digest }} \
|
|
${{ needs.build-arm64.outputs.slim-digest }}
|