diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 59fd6096b..ceb5463ae 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -432,68 +432,57 @@ jobs: # --------------------------------------------------------------------------- # Release CLI for Docker Desktop — build, sign & push CLI + Desktop module image - # (triggers docker/inference-engine-llama.cpp: signs macOS/Windows binaries, - # pushes docker/docker-model-cli-desktop-module to Docker Hub) # --------------------------------------------------------------------------- release-cli-desktop: needs: [prepare, test] runs-on: ubuntu-latest - timeout-minutes: 60 permissions: contents: read steps: - - name: Trigger release-cli-dd workflow - id: trigger + - 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: | - TRIGGER_TIME=$(date -u +%Y-%m-%dT%H:%M:%SZ) - echo "trigger_time=$TRIGGER_TIME" >> "$GITHUB_OUTPUT" - echo "🚀 Triggering release-cli-dd workflow at $TRIGGER_TIME" - echo " model-cli-ref: $RELEASE_TAG" - echo " tag: v$VERSION" - gh workflow run release-cli-dd.yml \ + 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" - echo "✅ release-cli-dd workflow triggered" + -f tag="v$VERSION") - - name: Wait for release-cli-dd to complete - env: - GH_TOKEN: ${{ secrets.CLI_RELEASE_PAT }} - TRIGGER_TIME: ${{ steps.trigger.outputs.trigger_time }} - run: | - echo "⏳ Waiting for release-cli-dd workflow to appear (triggered at $TRIGGER_TIME)..." - sleep 15 + RUN_URL=$(echo "$OUTPUT" \ + | grep -o 'https://github.com/[^ ]*/actions/runs/[0-9]*') || true - # Find the run created after our trigger time to avoid picking up unrelated runs - for i in $(seq 1 30); do + 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 5 \ - --json databaseId,createdAt \ - --jq "[.[] | select(.createdAt >= \"$TRIGGER_TIME\")] | sort_by(.createdAt) | last | .databaseId") - if [ -n "$RUN_ID" ] && [ "$RUN_ID" != "null" ]; then - echo "Found release-cli-dd run: $RUN_ID" - break - fi - echo " Retry $i/30..." - sleep 10 - done + --limit 1 \ + --json databaseId \ + --jq '.[0].databaseId') + else + RUN_ID=$(echo "$RUN_URL" | grep -o '[0-9]*$') + fi - if [ -z "$RUN_ID" ] || [ "$RUN_ID" = "null" ]; then - echo "::error::Could not find release-cli-dd workflow run created after $TRIGGER_TIME" + if [ -z "$RUN_ID" ]; then + echo "::error::Failed to determine workflow run ID" exit 1 fi - echo "⏳ Waiting for release-cli-dd run $RUN_ID to complete..." + 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 "✅ release-cli-dd workflow completed successfully" + echo "✅ Desktop CLI release completed successfully" # --------------------------------------------------------------------------- # Bump docker-model version in pinata and open a PR @@ -501,7 +490,6 @@ jobs: bump-pinata: needs: [prepare, release-cli-desktop] runs-on: ubuntu-latest - timeout-minutes: 10 permissions: contents: read steps: @@ -544,64 +532,62 @@ jobs: draft: true # --------------------------------------------------------------------------- - # Release CLI for Docker CE — build .deb/.rpm packages and deploy to download.docker.com - # (triggers docker/packaging → docker/release-repo) + # 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: + release-cli-docker-ce-trigger: if: ${{ !inputs.skipPackaging }} needs: [prepare, release-cli-desktop] runs-on: ubuntu-latest - timeout-minutes: 360 permissions: contents: read + outputs: + packaging_image: ${{ steps.packaging.outputs.packaging_image }} steps: - - name: Trigger release-model workflow in packaging repo - id: trigger + - 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: | - TRIGGER_TIME=$(date -u +%Y-%m-%dT%H:%M:%SZ) - echo "trigger_time=$TRIGGER_TIME" >> "$GITHUB_OUTPUT" - echo "📦 Triggering release-model workflow in docker/packaging at $TRIGGER_TIME" - echo " ref: $RELEASE_TAG" - gh workflow run release-model.yml \ + 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" - echo "✅ release-model workflow triggered in docker/packaging" + -f ref="$RELEASE_TAG") - - name: Wait for packaging workflow to complete - id: packaging - env: - GH_TOKEN: ${{ secrets.CLI_RELEASE_PAT }} - VERSION: ${{ needs.prepare.outputs.version }} - TRIGGER_TIME: ${{ steps.trigger.outputs.trigger_time }} - run: | - echo "⏳ Waiting for packaging workflow to appear (triggered at $TRIGGER_TIME)..." - sleep 15 + RUN_URL=$(echo "$OUTPUT" \ + | grep -o 'https://github.com/[^ ]*/actions/runs/[0-9]*') || true - # Find the run created after our trigger time to avoid picking up unrelated runs - for i in $(seq 1 30); do + 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 5 \ - --json databaseId,createdAt \ - --jq "[.[] | select(.createdAt >= \"$TRIGGER_TIME\")] | sort_by(.createdAt) | last | .databaseId") - if [ -n "$RUN_ID" ] && [ "$RUN_ID" != "null" ]; then - echo "Found packaging run: $RUN_ID" - break - fi - echo " Retry $i/30..." - sleep 10 - done + --limit 1 \ + --json databaseId \ + --jq '.[0].databaseId') + else + RUN_ID=$(echo "$RUN_URL" | grep -o '[0-9]*$') + fi - if [ -z "$RUN_ID" ] || [ "$RUN_ID" = "null" ]; then - echo "::error::Could not find packaging workflow run created after $TRIGGER_TIME" + if [ -z "$RUN_ID" ]; then + echo "::error::Failed to determine packaging workflow run ID" exit 1 fi - echo "⏳ Waiting for packaging run $RUN_ID to complete..." + 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 @@ -613,24 +599,17 @@ jobs: --jq '.number') PACKAGING_IMAGE="dockereng/packaging:model-v${VERSION}-${RUN_NUMBER}" - echo "📦 Packaging image: $PACKAGING_IMAGE" + echo "::add-mask::$PACKAGING_IMAGE" echo "packaging_image=$PACKAGING_IMAGE" >> "$GITHUB_OUTPUT" echo "✅ Packaging workflow completed successfully" - - name: Trigger release-repo plugin workflow - id: trigger_release_repo + - name: Trigger deploy workflow env: GH_TOKEN: ${{ secrets.CLI_RELEASE_PAT }} VERSION: ${{ needs.prepare.outputs.version }} PACKAGING_IMAGE: ${{ steps.packaging.outputs.packaging_image }} run: | - TRIGGER_TIME=$(date -u +%Y-%m-%dT%H:%M:%SZ) - echo "trigger_time=$TRIGGER_TIME" >> "$GITHUB_OUTPUT" - echo "🚀 Triggering plugin release in docker/release-repo at $TRIGGER_TIME" - echo " packaging_image: $PACKAGING_IMAGE" - echo " model_version: $VERSION" - echo " channel: stable" - echo " release_live: true" + echo "🚀 Triggering deploy workflow" gh workflow run plugin.yml \ --repo docker/release-repo \ --ref production \ @@ -638,72 +617,21 @@ jobs: -f model_version="$VERSION" \ -f channel=stable \ -f release_live=true - echo "✅ Plugin release workflow triggered in docker/release-repo" - - - name: Wait for release-repo plugin workflow to complete - env: - GH_TOKEN: ${{ secrets.CLI_RELEASE_PAT }} - TRIGGER_TIME: ${{ steps.trigger_release_repo.outputs.trigger_time }} - run: | - echo "⏳ Waiting for release-repo plugin workflow to appear (triggered at $TRIGGER_TIME)..." - sleep 15 - - # Find the run created after our trigger time to avoid picking up unrelated runs - for i in $(seq 1 30); do - RUN_ID=$(gh run list \ - --repo docker/release-repo \ - --workflow plugin.yml \ - --limit 5 \ - --json databaseId,createdAt \ - --jq "[.[] | select(.createdAt >= \"$TRIGGER_TIME\")] | sort_by(.createdAt) | last | .databaseId") - if [ -n "$RUN_ID" ] && [ "$RUN_ID" != "null" ]; then - echo "Found release-repo run: $RUN_ID" - break - fi - echo " Retry $i/30..." - sleep 10 - done - - if [ -z "$RUN_ID" ] || [ "$RUN_ID" = "null" ]; then - echo "::error::Could not find release-repo plugin workflow run created after $TRIGGER_TIME" - exit 1 - fi - - echo "⏳ Waiting for release-repo run $RUN_ID to complete (includes manual deploy-to-live approval)..." - gh run watch "$RUN_ID" \ - --repo docker/release-repo \ - --exit-status - echo "✅ Release-repo plugin workflow completed successfully" - - - name: Post summary - env: - VERSION: ${{ needs.prepare.outputs.version }} - RELEASE_TAG: ${{ needs.prepare.outputs.release_tag }} - PACKAGING_IMAGE: ${{ steps.packaging.outputs.packaging_image }} - run: | - cat >> "$GITHUB_STEP_SUMMARY" <<-SUMMARY - ## 📦 Docker CE Packaging & Release - - | Step | Status | - |------|--------| - | Packaging image | \`${PACKAGING_IMAGE}\` | - | Model version | \`${VERSION}\` | - | Release channel | \`stable\` | - | Deploy to live | ✅ Yes | - | Release tag | \`${RELEASE_TAG}\` | - - The plugin release workflow has been triggered in [docker/release-repo](https://github.com/docker/release-repo/actions/workflows/plugin.yml). - SUMMARY + echo "✅ Deploy workflow triggered" # --------------------------------------------------------------------------- - # Verify Docker CE installation and server version — install Docker CE, - # start the released model-runner image, and use `docker model version` - # to confirm both client and server versions match the release tag. + # 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: - needs: [prepare, release-cli-docker-ce, build] + needs: [prepare, release-cli-docker-ce-trigger, build] runs-on: ubuntu-latest - timeout-minutes: 15 + environment: release-repo-deploy steps: - name: Checkout code uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd @@ -717,7 +645,8 @@ jobs: # Create GitHub Release with AI-generated release notes # --------------------------------------------------------------------------- github-release: - needs: [prepare, release-notes, build, release-cli-desktop] + needs: [prepare, release-notes, build, release-cli-desktop, bump-pinata, verify-docker-ce] + if: ${{ !cancelled() && !contains(needs.*.result, 'failure') }} runs-on: ubuntu-latest permissions: contents: write