ReMe/.github/workflows/docker.yml
jinliyl 4c54c2b650
Some checks failed
CI / Python packages / Build and verify distributions (push) Waiting to run
CI / Python quality / GitHub Actions (push) Waiting to run
CI / Python quality / Pre-commit (push) Waiting to run
CI / Python tests / Unit Tests - py3.11 (push) Waiting to run
CI / Python tests / Unit Tests - py3.12 (push) Waiting to run
CI / Python tests / Unit Tests - py3.13 (push) Waiting to run
CI / Python tests / Unit Tests - py3.14 (push) Waiting to run
CI / Windows / CLI smoke - py3.11 (push) Waiting to run
Deploy / Documentation / Build documentation (push) Waiting to run
Deploy / Documentation / deploy (push) Blocked by required conditions
CI and Release / Docker / Build and test / amd64 (push) Waiting to run
CI and Release / Docker / Build and test / arm64 (push) Waiting to run
CI and Release / Docker / Publish multi-platform tags (push) Blocked by required conditions
Security / CodeQL / Analyze javascript-typescript (push) Waiting to run
Security / CodeQL / Analyze python (push) Waiting to run
CI / ReMe Studio / Studio checks (push) Has been cancelled
feat(docker): add container deployment and multi-platform release workflow (#582)
* feat(docker): add container deployment and multi-platform release workflow

* fix(llm): initialize providers on model access and preserve runtime injection

* test(llm): keep rejected model updates independent of credentials
2026-10-03 23:54:58 +08:00

221 lines
7.5 KiB
YAML

name: CI and Release / Docker
on:
pull_request:
branches: [main]
paths:
- '.github/workflows/docker.yml'
- 'Dockerfile'
- '.dockerignore'
- 'docker-compose.yml'
- 'deploy/docker/**'
- 'pyproject.toml'
- 'README.md'
- 'LICENSE'
- 'reme/**'
- 'reme_studio/**'
- 'scripts/package_studio.py'
- 'scripts/test_docker_image.py'
push:
branches: [main]
paths:
- '.github/workflows/docker.yml'
- 'Dockerfile'
- '.dockerignore'
- 'docker-compose.yml'
- 'deploy/docker/**'
- 'pyproject.toml'
- 'README.md'
- 'LICENSE'
- 'reme/**'
- 'reme_studio/**'
- 'scripts/package_studio.py'
- 'scripts/test_docker_image.py'
release:
types: [published]
workflow_dispatch:
permissions:
contents: read
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: ${{ github.event_name == 'pull_request' }}
env:
PUBLISH_IMAGE: ${{ github.event_name == 'release' || (github.event_name != 'pull_request' && github.ref == 'refs/heads/main') }}
jobs:
build:
name: Build and test / ${{ matrix.arch }}
runs-on: ${{ matrix.runner }}
timeout-minutes: 60
permissions:
contents: read
packages: write
strategy:
fail-fast: false
matrix:
include:
- arch: amd64
runner: ubuntu-24.04
- arch: arm64
runner: ubuntu-24.04-arm
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
with:
python-version: '3.11'
- name: Validate package version
env:
RELEASE_VERSION: ${{ github.event.release.tag_name }}
run: |
python -m pip install packaging
if [ -n "$RELEASE_VERSION" ]; then
python scripts/bump_version.py --check --expected-version "$RELEASE_VERSION"
else
python scripts/bump_version.py --check
fi
- name: Normalize image name
id: image
env:
REPOSITORY: ${{ github.repository }}
run: echo "name=ghcr.io/${REPOSITORY,,}" >> "$GITHUB_OUTPUT"
- name: Validate Compose
run: docker compose config --quiet
- uses: docker/setup-buildx-action@f87e5991a6d7451dcb8d9637bfbc97413f497069 # v4
- uses: docker/metadata-action@dc802804100637a589fabce1cb79ff13a1411302 # v6
id: metadata
with:
images: ${{ steps.image.outputs.name }}
flavor: latest=${{ github.event_name == 'release' && !github.event.release.prerelease && 'auto' || 'false' }}
tags: |
type=raw,value=main,enable=${{ github.ref == 'refs/heads/main' }}
type=pep440,pattern={{version}},value=${{ github.event.release.tag_name }},enable=${{ github.event_name == 'release' }}
type=sha
- name: Build local image
uses: docker/build-push-action@c3c9e263c25d99ce0380d002d59b67737d91b0dc # v7
with:
context: .
platforms: linux/${{ matrix.arch }}
load: true
tags: reme:smoke
labels: ${{ steps.metadata.outputs.labels }}
cache-from: type=gha,scope=reme-${{ matrix.arch }}
cache-to: type=gha,mode=max,scope=reme-${{ matrix.arch }}
- name: Test installed image and persistent workspace
run: python scripts/test_docker_image.py --image reme:smoke
- name: Log in to GHCR
if: env.PUBLISH_IMAGE == 'true'
uses: docker/login-action@dbcb813823bdd20940b903addbd779551569679f # v4
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Publish tested architecture by digest
id: publish
if: env.PUBLISH_IMAGE == 'true'
uses: docker/build-push-action@c3c9e263c25d99ce0380d002d59b67737d91b0dc # v7
with:
context: .
platforms: linux/${{ matrix.arch }}
outputs: type=image,name=${{ steps.image.outputs.name }},push-by-digest=true,name-canonical=true,push=true
labels: ${{ steps.metadata.outputs.labels }}
cache-from: type=gha,scope=reme-${{ matrix.arch }}
provenance: mode=max
sbom: true
- name: Record image digest
if: env.PUBLISH_IMAGE == 'true'
env:
IMAGE_DIGEST: ${{ steps.publish.outputs.digest }}
run: |
mkdir -p "$RUNNER_TEMP/digests"
touch "$RUNNER_TEMP/digests/${IMAGE_DIGEST#sha256:}"
- uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
if: env.PUBLISH_IMAGE == 'true'
with:
name: docker-digest-${{ matrix.arch }}
path: ${{ runner.temp }}/digests/*
if-no-files-found: error
retention-days: 1
manifest:
name: Publish multi-platform tags
needs: build
if: github.event_name == 'release' || (github.event_name != 'pull_request' && github.ref == 'refs/heads/main')
runs-on: ubuntu-24.04
timeout-minutes: 15
permissions:
contents: read
packages: write
steps:
- uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
pattern: docker-digest-*
merge-multiple: true
path: ${{ runner.temp }}/digests
- name: Normalize image name
id: image
env:
REPOSITORY: ${{ github.repository }}
run: echo "name=ghcr.io/${REPOSITORY,,}" >> "$GITHUB_OUTPUT"
- uses: docker/setup-buildx-action@f87e5991a6d7451dcb8d9637bfbc97413f497069 # v4
- uses: docker/login-action@dbcb813823bdd20940b903addbd779551569679f # v4
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- uses: docker/metadata-action@dc802804100637a589fabce1cb79ff13a1411302 # v6
id: metadata
with:
images: ${{ steps.image.outputs.name }}
flavor: latest=${{ github.event_name == 'release' && !github.event.release.prerelease && 'auto' || 'false' }}
tags: |
type=raw,value=main,enable=${{ github.ref == 'refs/heads/main' }}
type=pep440,pattern={{version}},value=${{ github.event.release.tag_name }},enable=${{ github.event_name == 'release' }}
type=sha
- name: Assemble and verify tags
env:
IMAGE_NAME: ${{ steps.image.outputs.name }}
IMAGE_TAGS: ${{ steps.metadata.outputs.tags }}
run: |
set -euo pipefail
image_refs=()
for digest_file in "$RUNNER_TEMP"/digests/*; do
image_refs+=("${IMAGE_NAME}@sha256:$(basename "$digest_file")")
done
[ "${#image_refs[@]}" -eq 2 ]
tag_args=()
while IFS= read -r tag; do
tag_args+=(--tag "$tag")
done <<< "$IMAGE_TAGS"
docker buildx imagetools create "${tag_args[@]}" "${image_refs[@]}"
while IFS= read -r tag; do
manifest=$(docker buildx imagetools inspect "$tag" --raw)
IMAGE_MANIFEST="$manifest" python - <<'PY'
import json
import os
manifest = json.loads(os.environ["IMAGE_MANIFEST"])
platforms = {(item["platform"]["os"], item["platform"]["architecture"]) for item in manifest["manifests"]}
assert {("linux", "amd64"), ("linux", "arm64")} <= platforms, platforms
PY
done <<< "$IMAGE_TAGS"