Skip to content

Release (auto patch bump) + latest #98

Release (auto patch bump) + latest

Release (auto patch bump) + latest #98

Workflow file for this run

name: Release
run-name: >-
Release
${{ inputs.releaseTag != '' && inputs.releaseTag || format('(auto {0} bump)', inputs.bumpType || 'patch') }}
${{ inputs.pushLatest && ' + latest' || '' }}
on:
workflow_dispatch:
inputs:
bumpType:
description: "Version bump type (ignored when releaseTag is provided)"
required: false
type: choice
options:
- patch
- minor
- major
default: "patch"
releaseTag:
description: "Explicit release tag — overrides auto-bump (e.g., v1.2.3)"
required: false
type: string
pushLatest:
description: "Tag images produced by this job as latest"
required: false
type: boolean
default: false
llamaServerVersion:
description: "llama-server version"
required: false
type: string
default: "latest"
vllmVersion:
description: "vLLM version"
required: false
type: string
default: "0.17.0"
sglangVersion:
description: "SGLang version"
required: false
type: string
default: "0.4.0"
# This can be removed once we have llama.cpp built for MUSA and CANN.
buildMusaCann:
description: "Build MUSA and CANN images"
required: false
type: boolean
default: false
imagesOnly:
description: "Only build and push Docker images (skip CLI releases, pinata bump, docs update, and CE packaging)"
required: false
type: boolean
default: false
jobs:
# ---------------------------------------------------------------------------
# Determine or create the release tag.
# Auto-bumps the latest tag (or uses explicit releaseTag if provided).
# ---------------------------------------------------------------------------
prepare:
runs-on: ubuntu-latest
permissions:
contents: write
outputs:
release_tag: ${{ steps.resolve.outputs.release_tag }}
version: ${{ steps.resolve.outputs.version }}
previous_tag: ${{ steps.resolve.outputs.previous_tag }}
steps:
- name: Checkout code
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd
with:
fetch-depth: 0
- name: Resolve release tag
id: resolve
env:
EXPLICIT_TAG: ${{ inputs.releaseTag }}
BUMP_TYPE: ${{ inputs.bumpType || 'patch' }}
run: |
# --- Find the latest existing v* tag ---
LATEST_TAG=$(git tag --list 'v*' --sort=-v:refname | head -1)
echo "Latest existing tag: ${LATEST_TAG:-<none>}"
if [ -n "$EXPLICIT_TAG" ]; then
# Validate explicit tag format
if ! echo "$EXPLICIT_TAG" | grep -qE '^v[0-9]+\.[0-9]+\.[0-9]+$'; then
echo "::error::Invalid release tag format: '$EXPLICIT_TAG'. Expected format: v<MAJOR>.<MINOR>.<PATCH> (e.g., v1.2.3)"
exit 1
fi
# Explicit tag provided — use it directly
RELEASE_TAG="$EXPLICIT_TAG"
VERSION="${EXPLICIT_TAG#v}"
PREVIOUS_TAG="$LATEST_TAG"
echo "Explicit tag provided: $RELEASE_TAG"
else
# Auto-bump from latest tag
if [ -z "$LATEST_TAG" ]; then
echo "No existing tags found — starting at v0.1.0"
RELEASE_TAG="v0.1.0"
VERSION="0.1.0"
PREVIOUS_TAG=""
else
PREVIOUS_TAG="$LATEST_TAG"
# Strip leading 'v' for parsing
VERSION="${LATEST_TAG#v}"
MAJOR=$(echo "$VERSION" | cut -d. -f1)
MINOR=$(echo "$VERSION" | cut -d. -f2)
PATCH=$(echo "$VERSION" | cut -d. -f3)
case "$BUMP_TYPE" in
major)
MAJOR=$((MAJOR + 1))
MINOR=0
PATCH=0
;;
minor)
MINOR=$((MINOR + 1))
PATCH=0
;;
patch)
PATCH=$((PATCH + 1))
;;
esac
VERSION="${MAJOR}.${MINOR}.${PATCH}"
RELEASE_TAG="v${VERSION}"
echo "Auto-bumped $BUMP_TYPE: $LATEST_TAG → $RELEASE_TAG"
fi
fi
echo "release_tag=$RELEASE_TAG" >> "$GITHUB_OUTPUT"
echo "version=$VERSION" >> "$GITHUB_OUTPUT"
echo "previous_tag=${PREVIOUS_TAG:-}" >> "$GITHUB_OUTPUT"
echo "🏷️ Release tag: $RELEASE_TAG"
echo "🏷️ Version: $VERSION"
echo "🏷️ Previous tag: ${PREVIOUS_TAG:-<none>}"
- name: Create and push tag
env:
RELEASE_TAG: ${{ steps.resolve.outputs.release_tag }}
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
# Check if the tag already exists
if git rev-parse "$RELEASE_TAG" >/dev/null 2>&1; then
echo "⚠️ Tag $RELEASE_TAG already exists — skipping creation"
exit 0
fi
echo "Creating tag $RELEASE_TAG on $(git rev-parse --short HEAD)"
git tag "$RELEASE_TAG"
git push origin "$RELEASE_TAG"
echo "✅ Tag $RELEASE_TAG created and pushed"
# ---------------------------------------------------------------------------
# Generate release notes using cagent AI agent (runs in parallel with test)
# ---------------------------------------------------------------------------
release-notes:
needs: prepare
runs-on: ubuntu-latest
permissions:
contents: read
steps:
- name: Checkout code
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd
with:
fetch-depth: 0
- name: Generate release notes
uses: docker/cagent-action@3a12dbd0c6cd7dda3d4e05f24f0143c9701456de
with:
agent: .github/agents/release-notes-generator.yaml
anthropic-api-key: ${{ secrets.ANTHROPIC_API_KEY }}
prompt: |
**Release Tag:** ${{ needs.prepare.outputs.release_tag }}
**Previous Tag:** ${{ needs.prepare.outputs.previous_tag }}
**Repository:** docker/model-runner
- name: Verify release notes
env:
RELEASE_TAG: ${{ needs.prepare.outputs.release_tag }}
PREVIOUS_TAG: ${{ needs.prepare.outputs.previous_tag }}
run: |
if [ ! -f "release-notes.md" ]; then
echo "::warning::Release notes were not generated. Using fallback."
echo "## What's Changed" > release-notes.md
echo "" >> release-notes.md
if [ -n "$PREVIOUS_TAG" ]; then
echo "**Full Changelog**: https://github.com/docker/model-runner/compare/${PREVIOUS_TAG}...${RELEASE_TAG}" >> release-notes.md
else
echo "**Full Changelog**: https://github.com/docker/model-runner/tree/${RELEASE_TAG}" >> release-notes.md
fi
fi
echo "✅ Release notes:"
cat release-notes.md
- name: Upload release notes
uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f
with:
name: release-notes
path: release-notes.md
# ---------------------------------------------------------------------------
# Run tests
# ---------------------------------------------------------------------------
test:
needs: prepare
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd
- name: Set up Go
uses: actions/setup-go@4b73464bb391d4059bd26b0524d20df3927bd417
with:
go-version: 1.25.8
cache: true
- name: Run tests
run: go test -race ./...
# ---------------------------------------------------------------------------
# Build and push Docker images
# ---------------------------------------------------------------------------
build:
needs: [prepare, test]
runs-on: ubuntu-latest
permissions:
contents: read
env:
RELEASE_TAG: ${{ needs.prepare.outputs.release_tag }}
LLAMA_SERVER_VERSION: ${{ inputs.llamaServerVersion || 'latest' }}
VLLM_VERSION: ${{ inputs.vllmVersion }}
SGLANG_VERSION: ${{ inputs.sglangVersion || '0.4.0' }}
PUSH_LATEST: ${{ inputs.pushLatest || 'false' }}
BUILD_MUSA_CANN: ${{ inputs.buildMusaCann || 'false' }}
steps:
- name: Checkout repo
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd
- name: Format tags
id: tags
shell: bash
run: |
echo "cpu<<EOF" >> "$GITHUB_OUTPUT"
echo "docker/model-runner:$RELEASE_TAG" >> "$GITHUB_OUTPUT"
if [ "$PUSH_LATEST" == "true" ]; then
echo "docker/model-runner:latest" >> "$GITHUB_OUTPUT"
fi
echo 'EOF' >> "$GITHUB_OUTPUT"
echo "cuda<<EOF" >> "$GITHUB_OUTPUT"
echo "docker/model-runner:$RELEASE_TAG-cuda" >> "$GITHUB_OUTPUT"
if [ "$PUSH_LATEST" == "true" ]; then
echo "docker/model-runner:latest-cuda" >> "$GITHUB_OUTPUT"
fi
echo 'EOF' >> "$GITHUB_OUTPUT"
echo "vllm-cuda<<EOF" >> "$GITHUB_OUTPUT"
echo "docker/model-runner:$RELEASE_TAG-vllm-cuda" >> "$GITHUB_OUTPUT"
if [ "$PUSH_LATEST" == "true" ]; then
echo "docker/model-runner:latest-vllm-cuda" >> "$GITHUB_OUTPUT"
fi
echo 'EOF' >> "$GITHUB_OUTPUT"
echo "sglang-cuda<<EOF" >> "$GITHUB_OUTPUT"
echo "docker/model-runner:$RELEASE_TAG-sglang-cuda" >> "$GITHUB_OUTPUT"
if [ "$PUSH_LATEST" == "true" ]; then
echo "docker/model-runner:latest-sglang-cuda" >> "$GITHUB_OUTPUT"
fi
echo 'EOF' >> "$GITHUB_OUTPUT"
echo "rocm<<EOF" >> "$GITHUB_OUTPUT"
echo "docker/model-runner:$RELEASE_TAG-rocm" >> "$GITHUB_OUTPUT"
if [ "$PUSH_LATEST" == "true" ]; then
echo "docker/model-runner:latest-rocm" >> "$GITHUB_OUTPUT"
fi
echo 'EOF' >> "$GITHUB_OUTPUT"
echo "musa<<EOF" >> "$GITHUB_OUTPUT"
echo "docker/model-runner:$RELEASE_TAG-musa" >> "$GITHUB_OUTPUT"
if [ "$PUSH_LATEST" == "true" ]; then
echo "docker/model-runner:latest-musa" >> "$GITHUB_OUTPUT"
fi
echo 'EOF' >> "$GITHUB_OUTPUT"
echo "cann<<EOF" >> "$GITHUB_OUTPUT"
echo "docker/model-runner:$RELEASE_TAG-cann" >> "$GITHUB_OUTPUT"
if [ "$PUSH_LATEST" == "true" ]; then
echo "docker/model-runner:latest-cann" >> "$GITHUB_OUTPUT"
fi
echo 'EOF' >> "$GITHUB_OUTPUT"
- name: Log in to DockerHub
uses: docker/login-action@b45d80f862d83dbcd57f89517bcf500b2ab88fb2
with:
username: "docker"
password: ${{ secrets.ORG_ACCESS_TOKEN }}
- name: Set up Buildx
uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # v4.0.0
with:
version: "lab:latest"
driver: cloud
endpoint: "docker/make-product-smarter"
install: true
- name: Build CPU image
uses: docker/build-push-action@d08e5c354a6adb9ed34480a06d141179aa583294
with:
file: Dockerfile
target: final-llamacpp
platforms: linux/amd64, linux/arm64
build-args: |
"LLAMA_SERVER_VERSION=${{ env.LLAMA_SERVER_VERSION }}"
"VERSION=${{ env.RELEASE_TAG }}"
push: true
sbom: true
provenance: mode=max
tags: ${{ steps.tags.outputs.cpu }}
- name: Build CUDA image
uses: docker/build-push-action@d08e5c354a6adb9ed34480a06d141179aa583294
with:
file: Dockerfile
target: final-llamacpp
platforms: linux/amd64, linux/arm64
build-args: |
"LLAMA_SERVER_VERSION=${{ env.LLAMA_SERVER_VERSION }}"
"LLAMA_SERVER_VARIANT=cuda"
"BASE_IMAGE=nvidia/cuda:12.9.0-runtime-ubuntu24.04"
"VERSION=${{ env.RELEASE_TAG }}"
push: true
sbom: true
provenance: mode=max
tags: ${{ steps.tags.outputs.cuda }}
- name: Build vLLM CUDA image
uses: docker/build-push-action@d08e5c354a6adb9ed34480a06d141179aa583294
with:
file: Dockerfile
target: final-vllm
platforms: linux/amd64, linux/arm64
build-args: |
"LLAMA_SERVER_VERSION=${{ env.LLAMA_SERVER_VERSION }}"
"LLAMA_SERVER_VARIANT=cuda"
"BASE_IMAGE=nvidia/cuda:13.0.2-runtime-ubuntu24.04"
"VLLM_VERSION=${{ env.VLLM_VERSION }}"
"VERSION=${{ env.RELEASE_TAG }}"
push: true
sbom: true
provenance: mode=max
tags: ${{ steps.tags.outputs.vllm-cuda }}
- name: Build SGLang CUDA image
uses: docker/build-push-action@d08e5c354a6adb9ed34480a06d141179aa583294
with:
file: Dockerfile
target: final-sglang
platforms: linux/amd64
build-args: |
"LLAMA_SERVER_VERSION=${{ env.LLAMA_SERVER_VERSION }}"
"LLAMA_SERVER_VARIANT=cuda"
"BASE_IMAGE=nvidia/cuda:12.9.0-runtime-ubuntu24.04"
"SGLANG_VERSION=${{ env.SGLANG_VERSION }}"
"VERSION=${{ env.RELEASE_TAG }}"
push: true
sbom: true
provenance: mode=max
tags: ${{ steps.tags.outputs.sglang-cuda }}
- name: Build ROCm image
uses: docker/build-push-action@d08e5c354a6adb9ed34480a06d141179aa583294
with:
file: Dockerfile
target: final-llamacpp
platforms: linux/amd64
build-args: |
"LLAMA_SERVER_VERSION=${{ env.LLAMA_SERVER_VERSION }}"
"LLAMA_SERVER_VARIANT=rocm"
"BASE_IMAGE=rocm/dev-ubuntu-22.04"
"VERSION=${{ env.RELEASE_TAG }}"
push: true
sbom: true
provenance: mode=max
tags: ${{ steps.tags.outputs.rocm }}
- name: Build MUSA image
if: ${{ env.BUILD_MUSA_CANN == 'true' }}
uses: docker/build-push-action@d08e5c354a6adb9ed34480a06d141179aa583294
with:
file: Dockerfile
target: final-llamacpp
platforms: linux/amd64
build-args: |
"LLAMA_SERVER_VERSION=${{ env.LLAMA_SERVER_VERSION }}"
"LLAMA_SERVER_VARIANT=musa"
"BASE_IMAGE=mthreads/musa:rc4.3.0-runtime-ubuntu22.04-amd64"
"VERSION=${{ env.RELEASE_TAG }}"
push: true
sbom: true
provenance: mode=max
tags: ${{ steps.tags.outputs.musa }}
- name: Build CANN image
if: ${{ env.BUILD_MUSA_CANN == 'true' }}
uses: docker/build-push-action@d08e5c354a6adb9ed34480a06d141179aa583294
with:
file: Dockerfile
target: final-llamacpp
platforms: linux/arm64, linux/amd64
build-args: |
"LLAMA_SERVER_VERSION=${{ env.LLAMA_SERVER_VERSION }}"
"LLAMA_SERVER_VARIANT=cann"
"BASE_IMAGE=ascendai/cann:8.2.rc2-910b-ubuntu22.04-py3.11"
"VERSION=${{ env.RELEASE_TAG }}"
push: true
sbom: true
provenance: mode=max
tags: ${{ steps.tags.outputs.cann }}
# ---------------------------------------------------------------------------
# Release CLI for Docker Desktop — build, sign & push CLI + Desktop module image
# ---------------------------------------------------------------------------
release-cli-desktop:
if: ${{ !inputs.imagesOnly }}
needs: [prepare, test]
runs-on: ubuntu-latest
permissions:
contents: read
steps:
- name: Trigger Desktop CLI release and wait for completion
env:
GH_TOKEN: ${{ secrets.CLI_RELEASE_PAT }}
RELEASE_TAG: ${{ needs.prepare.outputs.release_tag }}
VERSION: ${{ needs.prepare.outputs.version }}
run: |
echo "🚀 Triggering Desktop CLI release workflow"
# gh workflow run returns run URL on stdout (gh v2.87.0+)
OUTPUT=$(gh workflow run release-cli-dd.yml \
--repo docker/inference-engine-llama.cpp \
-f model-cli-ref="$RELEASE_TAG" \
-f tag="v$VERSION")
RUN_URL=$(echo "$OUTPUT" \
| grep -o 'https://github.com/[^ ]*/actions/runs/[0-9]*') || true
if [ -z "$RUN_URL" ]; then
echo "⚠️ Could not extract run URL from gh output, querying latest run..."
sleep 5
RUN_ID=$(gh run list \
--repo docker/inference-engine-llama.cpp \
--workflow release-cli-dd.yml \
--limit 1 \
--json databaseId \
--jq '.[0].databaseId')
else
RUN_ID=$(echo "$RUN_URL" | grep -o '[0-9]*$')
fi
if [ -z "$RUN_ID" ]; then
echo "::error::Failed to determine workflow run ID"
exit 1
fi
echo "::add-mask::$RUN_ID"
echo "::add-mask::$RUN_URL"
echo "✅ Desktop CLI release workflow triggered"
echo "⏳ Waiting for Desktop CLI release to complete..."
gh run watch "$RUN_ID" \
--repo docker/inference-engine-llama.cpp \
--exit-status
echo "✅ Desktop CLI release completed successfully"
# ---------------------------------------------------------------------------
# Bump docker-model version in pinata and open a PR
# ---------------------------------------------------------------------------
bump-pinata:
if: ${{ !inputs.imagesOnly }}
needs: [prepare, release-cli-desktop]
runs-on: ubuntu-latest
permissions:
contents: read
steps:
- name: Checkout pinata
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd
with:
repository: docker/pinata
token: ${{ secrets.CLI_RELEASE_PAT }}
fetch-depth: 0
- name: Bump docker-model version in build.json
env:
VERSION: ${{ needs.prepare.outputs.version }}
run: |
NEW_VERSION="v${VERSION}"
jq --arg v "$NEW_VERSION" '.["docker-model"].version = $v' build.json > build.json.tmp
mv build.json.tmp build.json
- name: Create pull request
uses: peter-evans/create-pull-request@c0f553fe549906ede9cf27b5156039d195d2ece0
with:
token: ${{ secrets.CLI_RELEASE_PAT }}
base: main
commit-message: "chore: bump docker-model to v${{ needs.prepare.outputs.version }}"
branch: bump-docker-model-v${{ needs.prepare.outputs.version }}
title: "Bump docker-model to v${{ needs.prepare.outputs.version }}"
body: |
### Ticket(s)
N/A — automated version bump
### What this PR does
Bumps docker-model version to v${{ needs.prepare.outputs.version }} in build.json.
### Notes for the reviewer
Automated PR created by the model-runner release workflow.
draft: true
# ---------------------------------------------------------------------------
# Update CLI reference docs in docker/docs
# ---------------------------------------------------------------------------
update-docs:
if: ${{ !inputs.imagesOnly }}
needs: [prepare]
runs-on: ubuntu-latest
permissions:
contents: read
steps:
- name: Check if CLI docs changed
id: check-docs
env:
GH_TOKEN: ${{ secrets.CLI_RELEASE_PAT }}
RELEASE_TAG: ${{ needs.prepare.outputs.release_tag }}
PREVIOUS_TAG: ${{ needs.prepare.outputs.previous_tag }}
run: |
if [ -z "$PREVIOUS_TAG" ]; then
echo "No previous tag — assuming docs changed"
echo "changed=true" >> "$GITHUB_OUTPUT"
exit 0
fi
CHANGED=$(gh api repos/docker/model-runner/compare/${PREVIOUS_TAG}...${RELEASE_TAG} \
--jq '[.files[].filename | select(startswith("cmd/cli/docs/reference/"))] | length')
if [ "$CHANGED" -gt 0 ]; then
echo "CLI docs changed ($CHANGED files)"
echo "changed=true" >> "$GITHUB_OUTPUT"
else
echo "No CLI docs changes between $PREVIOUS_TAG and $RELEASE_TAG — skipping"
echo "changed=false" >> "$GITHUB_OUTPUT"
fi
- name: Checkout docs
if: steps.check-docs.outputs.changed == 'true'
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd
with:
repository: docker/docs
token: ${{ secrets.CLI_RELEASE_PAT }}
fetch-depth: 0
- name: Set up Go
if: steps.check-docs.outputs.changed == 'true'
uses: actions/setup-go@4b73464bb391d4059bd26b0524d20df3927bd417
with:
go-version: 1.25.8
cache: true
- name: Vendor model-runner CLI docs
if: steps.check-docs.outputs.changed == 'true'
env:
RELEASE_TAG: ${{ needs.prepare.outputs.release_tag }}
run: |
VENDOR_MODULE=github.com/docker/model-runner@${RELEASE_TAG} make vendor
# Remove the second require block added by `go get` — the docs repo
# only needs the direct dependency in the first require block.
awk '/^require \(/{n++} n==2{if(/^\)/) n=3; next} n!=2' go.mod > go.mod.tmp && mv go.mod.tmp go.mod
- name: Create pull request
if: steps.check-docs.outputs.changed == 'true'
uses: peter-evans/create-pull-request@c0f553fe549906ede9cf27b5156039d195d2ece0
with:
token: ${{ secrets.DOCKER_DOCS }}
base: main
push-to-fork: ilopezluna/docs
commit-message: |
vendor: github.com/docker/model-runner ${{ needs.prepare.outputs.release_tag }}
See changes in https://github.com/docker/model-runner/compare/${{ needs.prepare.outputs.previous_tag }}...${{ needs.prepare.outputs.release_tag }}.
branch: update-model-runner-${{ needs.prepare.outputs.release_tag }}
title: "vendor: github.com/docker/model-runner ${{ needs.prepare.outputs.release_tag }}"
body: |
## Description
Update Model Runner CLI docs.
See changes in https://github.com/docker/model-runner/compare/${{ needs.prepare.outputs.previous_tag }}...${{ needs.prepare.outputs.release_tag }}.
```
VENDOR_MODULE=github.com/docker/model-runner@${{ needs.prepare.outputs.release_tag }} make vendor
```
## Reviews
<!-- Notes for reviewers here -->
<!-- List applicable reviews (optionally @tag reviewers) -->
- [ ] Technical review
- [ ] Editorial review
- [ ] Product review
draft: true
# ---------------------------------------------------------------------------
# Release CLI for Docker CE — build .deb/.rpm packages and deploy
#
# Triggers packaging, waits for it, then triggers the deploy workflow.
# The verify-docker-ce job (which requires manual approval via the
# "release-repo-deploy" environment) runs after this to confirm the
# deploy completed successfully.
# ---------------------------------------------------------------------------
release-cli-docker-ce-trigger:
if: ${{ !inputs.imagesOnly }}
needs: [prepare, release-cli-desktop]
runs-on: ubuntu-latest
permissions:
contents: read
outputs:
packaging_image: ${{ steps.packaging.outputs.packaging_image }}
steps:
- name: Trigger packaging and wait for completion
id: packaging
env:
GH_TOKEN: ${{ secrets.CLI_RELEASE_PAT }}
RELEASE_TAG: ${{ needs.prepare.outputs.release_tag }}
VERSION: ${{ needs.prepare.outputs.version }}
run: |
echo "📦 Triggering packaging workflow"
# gh workflow run returns run URL on stdout (gh v2.87.0+)
OUTPUT=$(gh workflow run release-model.yml \
--repo docker/packaging \
-f ref="$RELEASE_TAG")
RUN_URL=$(echo "$OUTPUT" \
| grep -o 'https://github.com/[^ ]*/actions/runs/[0-9]*') || true
if [ -z "$RUN_URL" ]; then
echo "⚠️ Could not extract run URL from gh output, querying latest run..."
sleep 5
RUN_ID=$(gh run list \
--repo docker/packaging \
--workflow release-model.yml \
--limit 1 \
--json databaseId \
--jq '.[0].databaseId')
else
RUN_ID=$(echo "$RUN_URL" | grep -o '[0-9]*$')
fi
if [ -z "$RUN_ID" ]; then
echo "::error::Failed to determine packaging workflow run ID"
exit 1
fi
echo "::add-mask::$RUN_ID"
echo "::add-mask::$RUN_URL"
echo "✅ Packaging workflow triggered"
echo "⏳ Waiting for packaging to complete..."
gh run watch "$RUN_ID" \
--repo docker/packaging \
--exit-status
# Get the run number to construct the image tag
RUN_NUMBER=$(gh run view "$RUN_ID" \
--repo docker/packaging \
--json number \
--jq '.number')
PACKAGING_IMAGE="dockereng/packaging:model-v${VERSION}-${RUN_NUMBER}"
echo "::add-mask::$PACKAGING_IMAGE"
echo "packaging_image=$PACKAGING_IMAGE" >> "$GITHUB_OUTPUT"
echo "✅ Packaging workflow completed successfully"
- name: Trigger deploy workflow
env:
GH_TOKEN: ${{ secrets.CLI_RELEASE_PAT }}
VERSION: ${{ needs.prepare.outputs.version }}
PACKAGING_IMAGE: ${{ steps.packaging.outputs.packaging_image }}
run: |
echo "🚀 Triggering deploy workflow"
gh workflow run plugin.yml \
--repo docker/release-repo \
--ref production \
-f packaging_image="$PACKAGING_IMAGE" \
-f model_version="$VERSION" \
-f channel=stable \
-f release_live=true
echo "✅ Deploy workflow triggered"
# ---------------------------------------------------------------------------
# Verify Docker CE installation and server version — requires manual
# approval via the "release-repo-deploy" environment. Before approving,
# ensure the deploy workflow in docker/release-repo completed successfully.
#
# Once approved, installs Docker CE, starts the released model-runner
# image, and uses `docker model version` to confirm both client and
# server versions match the release tag.
# ---------------------------------------------------------------------------
verify-docker-ce:
if: ${{ !inputs.imagesOnly }}
needs: [prepare, release-cli-docker-ce-trigger, build]
runs-on: ubuntu-latest
environment: release-repo-deploy
steps:
- name: Checkout code
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd
- name: Verify client and server versions
run: |
chmod +x scripts/test-docker-ce-installation.sh
./scripts/test-docker-ce-installation.sh "${{ needs.prepare.outputs.release_tag }}"
# ---------------------------------------------------------------------------
# Create GitHub Release with AI-generated release notes
# ---------------------------------------------------------------------------
github-release:
needs: [prepare, release-notes, build, release-cli-desktop, bump-pinata, update-docs, verify-docker-ce]
if: ${{ !cancelled() && !contains(needs.*.result, 'failure') }}
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- name: Download release notes
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c
with:
name: release-notes
- name: Create GitHub Release
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
RELEASE_TAG: ${{ needs.prepare.outputs.release_tag }}
VERSION: ${{ needs.prepare.outputs.version }}
run: |
echo "Creating GitHub Release for $RELEASE_TAG"
gh release create "$RELEASE_TAG" \
--repo docker/model-runner \
--title "Docker Model Runner $RELEASE_TAG" \
--notes-file release-notes.md
- name: Send Slack notification
if: success()
env:
RELEASE_TAG: ${{ needs.prepare.outputs.release_tag }}
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}
run: |
BUILD_URL="${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}"
RELEASE_URL="https://github.com/docker/model-runner/releases/tag/${RELEASE_TAG}"
SLACK_MESSAGE=$(cat <<EOF
{
"text": "🚀 Docker Model Runner ${RELEASE_TAG} has been released!",
"blocks": [
{
"type": "header",
"text": {
"type": "plain_text",
"text": "🚀 Docker Model Runner Released"
}
},
{
"type": "section",
"fields": [
{
"type": "mrkdwn",
"text": "*Version:*\n${RELEASE_TAG}"
},
{
"type": "mrkdwn",
"text": "*Repository:*\ndocker/model-runner"
}
]
},
{
"type": "actions",
"elements": [
{
"type": "button",
"text": {
"type": "plain_text",
"text": "View Release"
},
"url": "${RELEASE_URL}",
"style": "primary"
},
{
"type": "button",
"text": {
"type": "plain_text",
"text": "View Build"
},
"url": "${BUILD_URL}"
}
]
}
]
}
EOF
)
curl -X POST -H 'Content-type: application/json' \
--data "${SLACK_MESSAGE}" \
"${SLACK_WEBHOOK_URL}"