feat: updater tracks all 6 CI-built images (#64) #138
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Build & Deploy | |
| on: | |
| workflow_dispatch: | |
| inputs: | |
| tag: | |
| description: 'Image tag override (default: branch-based)' | |
| required: false | |
| type: string | |
| openclaw_version: | |
| description: 'OpenClaw npm version for worker image (default: Dockerfile ARG)' | |
| required: false | |
| type: string | |
| ironclaw_version: | |
| description: 'IronClaw version for worker image (default: Dockerfile ARG)' | |
| required: false | |
| type: string | |
| push: | |
| branches: | |
| - main | |
| tags: | |
| - "v*" | |
| env: | |
| REGISTRY: docker.io | |
| jobs: | |
| build: | |
| name: Build ${{ matrix.name }} | |
| permissions: | |
| contents: read | |
| packages: write | |
| attestations: write | |
| id-token: write | |
| runs-on: ubuntu-latest | |
| strategy: | |
| matrix: | |
| include: | |
| - name: openclaw-nearai-worker | |
| context: worker | |
| dockerfile: worker/Dockerfile | |
| build_script: true | |
| - name: openclaw-compose-api | |
| context: compose-api | |
| dockerfile: compose-api/Dockerfile | |
| build_script: false | |
| - name: openclaw-updater | |
| context: . | |
| dockerfile: updater/Dockerfile | |
| build_script: false | |
| - name: ironclaw-nearai-worker | |
| context: ironclaw-worker | |
| dockerfile: ironclaw-worker/Dockerfile | |
| build_script: false | |
| - name: openclaw-ingress | |
| context: ingress | |
| dockerfile: ingress/Dockerfile | |
| build_script: false | |
| - name: openclaw-ssh-bastion | |
| context: ssh-bastion | |
| dockerfile: ssh-bastion/Dockerfile | |
| build_script: false | |
| steps: | |
| - name: Checkout repository | |
| uses: actions/checkout@v4 | |
| - name: Log in to Docker registry | |
| uses: docker/login-action@65b78e6e13532edd9afa3aa52ac7964289d1a9c1 | |
| with: | |
| registry: ${{ env.REGISTRY }} | |
| username: ${{ vars.DOCKER_REGISTRY_USER }} | |
| password: ${{ secrets.DOCKER_REGISTRY_TOKEN }} | |
| - name: Set image repository | |
| run: echo "IMAGE_REPOSITORY=${{ vars.DOCKER_REGISTRY_USER }}/${{ matrix.name }}" >> "$GITHUB_ENV" | |
| - name: Extract image tag from GitHub ref (branch or tag) | |
| run: | | |
| # Use manual input tag if provided via workflow_dispatch | |
| if [[ -n "${{ inputs.tag }}" ]]; then | |
| TAG="${{ inputs.tag }}" | |
| echo "Using '${TAG}' image tag from workflow_dispatch input" | |
| elif [[ "${GITHUB_REF_TYPE}" == 'tag' ]]; then | |
| TAG=${GITHUB_REF_NAME#v} | |
| echo "Using '${TAG}' image tag for ${GITHUB_REF_NAME} tag" | |
| elif [[ "${GITHUB_REF_TYPE}" == 'branch' ]]; then | |
| TAG=$(if [[ "${GITHUB_REF_NAME}" == 'main' ]]; then echo 'latest'; else echo 'dev'; fi) | |
| echo "Using '${TAG}' image tag for ${GITHUB_REF_NAME} branch" | |
| else | |
| echo "Unsupported ref type: ${GITHUB_REF_TYPE}" >&2 | |
| exit 1 | |
| fi | |
| if [ -z "${TAG}" ]; then | |
| echo "Unable to parse image tag from ${GITHUB_REF_TYPE}: ${GITHUB_REF_NAME}" >&2 | |
| exit 1 | |
| fi | |
| echo "IMAGE_REFERENCE=${{ env.REGISTRY }}/${IMAGE_REPOSITORY}:${TAG}" >> "$GITHUB_ENV" | |
| - name: Install build dependencies | |
| if: matrix.build_script | |
| run: | | |
| sudo apt-get update | |
| sudo apt-get install -y skopeo jq | |
| # Reproducible build path (worker only — uses build-image.sh) | |
| - name: Build and push reproducible image | |
| if: matrix.build_script | |
| run: | | |
| ./deploy/build-image.sh --push "${{ env.IMAGE_REFERENCE }}" | |
| env: | |
| OPENCLAW_VERSION: ${{ inputs.openclaw_version }} | |
| - name: Get image digest (reproducible) | |
| if: matrix.build_script | |
| run: | | |
| DIGEST=$(skopeo inspect oci-archive:./oci.tar | jq -r '.Digest') | |
| if [ -z "${DIGEST}" ]; then | |
| echo "Failed to get image digest from OCI archive" >&2 | |
| exit 1 | |
| fi | |
| echo "IMAGE_DIGEST=${DIGEST}" >> "$GITHUB_ENV" | |
| # Standard Docker build path (compose-api, updater) | |
| - name: Build and push image | |
| if: ${{ !matrix.build_script }} | |
| uses: docker/build-push-action@v6 | |
| id: docker_build | |
| with: | |
| context: ${{ matrix.context }} | |
| file: ${{ matrix.dockerfile }} | |
| push: true | |
| tags: ${{ env.IMAGE_REFERENCE }} | |
| build-args: | | |
| GIT_COMMIT=${{ github.sha }} | |
| ${{ inputs.ironclaw_version && format('IRONCLAW_VERSION={0}', inputs.ironclaw_version) || '' }} | |
| - name: Get image digest (standard) | |
| if: ${{ !matrix.build_script }} | |
| run: echo "IMAGE_DIGEST=${{ steps.docker_build.outputs.digest }}" >> "$GITHUB_ENV" | |
| - name: Generate artifact attestation (GitHub) | |
| uses: actions/attest-build-provenance@v3 | |
| with: | |
| subject-name: ${{ env.REGISTRY }}/${{ env.IMAGE_REPOSITORY }} | |
| subject-digest: ${{ env.IMAGE_DIGEST }} | |
| push-to-registry: true | |
| - name: Install cosign | |
| uses: sigstore/cosign-installer@v3 | |
| - name: Sign image with cosign (keyless) | |
| run: | | |
| cosign sign --yes "${{ env.REGISTRY }}/${{ env.IMAGE_REPOSITORY }}@${{ env.IMAGE_DIGEST }}" | |
| - name: Generate build summary | |
| run: | | |
| { | |
| echo "## ${{ env.IMAGE_REPOSITORY }} docker image" | |
| echo "" | |
| echo "- tag: \`${{ env.IMAGE_REFERENCE }}\`" | |
| echo "- digest: \`${{ env.IMAGE_DIGEST }}\`" | |
| echo "- sigstore: https://search.sigstore.dev/?hash=${{ env.IMAGE_DIGEST }}" | |
| } >> "$GITHUB_STEP_SUMMARY" |