From e2f2348326c7920c4cf89a84c56b50c240796717 Mon Sep 17 00:00:00 2001 From: Hubert Gruszecki Date: Fri, 30 Jan 2026 23:08:32 +0100 Subject: [PATCH] ci: unify publishing via workflow_call in publish.yml post-merge.yml duplicated Docker building, manifest creation, crate publishing, and tag management that already existed in publish.yml. Maintaining parallel implementations risked drift and complicated adding new components. Refactored publish.yml to accept workflow_call trigger with inputs for component selection and edge mode. post-merge.yml now delegates to publish.yml via call-publish job, preserving exact behavior: - Docker :edge tags always created on merge - Versioned tags only for pre-release versions - :latest never touched by auto-publish --- .github/workflows/post-merge.yml | 439 +++++-------------------------- .github/workflows/publish.yml | 168 ++++++++++-- 2 files changed, 213 insertions(+), 394 deletions(-) diff --git a/.github/workflows/post-merge.yml b/.github/workflows/post-merge.yml index 3f7be680e..4f6ea5c73 100644 --- a/.github/workflows/post-merge.yml +++ b/.github/workflows/post-merge.yml @@ -22,7 +22,7 @@ on: branches: [master] permissions: - contents: read + contents: write packages: write id-token: write @@ -34,152 +34,20 @@ env: IGGY_CI_BUILD: true jobs: - plan: - name: Plan dockerhub components + check-auto-publish: + name: Check auto-publish runs-on: ubuntu-latest + if: ${{ !github.event.repository.fork }} outputs: - matrix: ${{ steps.mk.outputs.matrix }} - components: ${{ steps.mk.outputs.components }} + docker_components: ${{ steps.check.outputs.docker_components }} + crates_to_publish: ${{ steps.check.outputs.crates_to_publish }} + sdks_to_publish: ${{ steps.check.outputs.sdks_to_publish }} steps: - uses: actions/checkout@v4 - - - name: Load publish config (base64) - id: cfg - shell: bash - run: | - if ! command -v yq >/dev/null 2>&1; then - YQ_VERSION="v4.47.1" - YQ_CHECKSUM="0fb28c6680193c41b364193d0c0fc4a03177aecde51cfc04d506b1517158c2fb" - curl -sSL -o /usr/local/bin/yq https://github.com/mikefarah/yq/releases/download/${YQ_VERSION}/yq_linux_amd64 - echo "${YQ_CHECKSUM} /usr/local/bin/yq" | sha256sum -c - || exit 1 - chmod +x /usr/local/bin/yq - fi - echo "components_b64=$(yq -o=json -I=0 '.components' .github/config/publish.yml | base64 -w0)" >> "$GITHUB_OUTPUT" - - - name: Build matrix - id: mk - uses: actions/github-script@v7 with: - script: | - const b64 = `${{ steps.cfg.outputs.components_b64 }}` || ''; - if (!b64) { - core.setOutput('matrix', JSON.stringify({ include: [{ component: 'noop' }] })); - core.setOutput('components', JSON.stringify({ include: [{ component: 'noop' }] })); - return; - } - const comps = JSON.parse(Buffer.from(b64, 'base64').toString('utf8')); - const components = Object.entries(comps) - .filter(([_, v]) => v && v.registry === 'dockerhub') - .map(([k]) => k); - const uniqComponents = [...new Set(components)]; - - // Output just the component list for manifest creation - const componentMatrix = uniqComponents.length - ? { include: uniqComponents.map(c => ({ component: c })) } - : { include: [{ component: 'noop' }] }; - core.setOutput('components', JSON.stringify(componentMatrix)); - - // Build cross-product matrix: components × platforms - const platforms = [ - { platform: 'linux/amd64', arch: 'amd64', runner: 'ubuntu-latest' }, - { platform: 'linux/arm64', arch: 'arm64', runner: 'ubuntu-24.04-arm' } - ]; - - const matrix = []; - for (const comp of uniqComponents) { - for (const p of platforms) { - matrix.push({ component: comp, ...p }); - } - } - - core.setOutput('matrix', JSON.stringify(matrix.length ? { include: matrix } : { include: [{ component: 'noop' }] })); - console.log(`Components: ${uniqComponents.join(', ')}`); - console.log(`Matrix size: ${matrix.length} jobs (${uniqComponents.length} components × 2 platforms)`); - - docker-edge: - name: ${{ matrix.component }} (${{ matrix.arch }}) - needs: plan - if: ${{ fromJson(needs.plan.outputs.matrix).include[0].component != 'noop' }} - runs-on: ${{ matrix.runner }} - timeout-minutes: 60 - strategy: - fail-fast: false - matrix: ${{ fromJson(needs.plan.outputs.matrix) }} - env: - DOCKERHUB_USER: ${{ secrets.DOCKERHUB_USER }} - DOCKERHUB_TOKEN: ${{ secrets.DOCKERHUB_TOKEN }} - steps: - - uses: actions/checkout@v4 - - - name: Extract version - id: ver - run: | - chmod +x scripts/extract-version.sh - VERSION=$(scripts/extract-version.sh "${{ matrix.component }}") - echo "version=$VERSION" >> "$GITHUB_OUTPUT" - echo "✅ Resolved ${{ matrix.component }} -> version=$VERSION" - - - name: Determine libc for component - id: libc - run: | - # Connectors runtime must use glibc because it dlopen()s glibc plugins - if [ "${{ matrix.component }}" = "rust-connectors" ]; then - echo "libc=glibc" >> "$GITHUB_OUTPUT" - else - echo "libc=musl" >> "$GITHUB_OUTPUT" - fi - - - uses: ./.github/actions/utils/docker-buildx - id: docker - with: - task: publish - libc: ${{ steps.libc.outputs.libc }} - component: ${{ matrix.component }} - version: ${{ steps.ver.outputs.version }} - platform: ${{ matrix.platform }} - dry_run: ${{ github.event.repository.fork }} - gha-cache: "false" # Use registry cache only to save GHA cache space - - - name: Export digest - if: ${{ !github.event.repository.fork }} - shell: bash - run: | - mkdir -p ${{ runner.temp }}/digests - digest="${{ steps.docker.outputs.digest }}" - if [ -n "$digest" ]; then - touch "${{ runner.temp }}/digests/${digest#sha256:}" - echo "Exported digest: $digest" - else - echo "::error::No digest available" - exit 1 - fi - - - name: Upload digest - if: ${{ !github.event.repository.fork }} - uses: actions/upload-artifact@v4 - with: - name: docker-digest-${{ matrix.component }}-${{ matrix.arch }} - path: ${{ runner.temp }}/digests/* - if-no-files-found: error - retention-days: 1 - - docker-manifests: - name: Create manifests - needs: [plan, docker-edge, check-docker-auto-publish] - if: ${{ !github.event.repository.fork && fromJson(needs.plan.outputs.components).include[0].component != 'noop' }} - runs-on: ubuntu-latest - strategy: - fail-fast: false - matrix: ${{ fromJson(needs.plan.outputs.components) }} - env: - DOCKERHUB_USER: ${{ secrets.DOCKERHUB_USER }} - DOCKERHUB_TOKEN: ${{ secrets.DOCKERHUB_TOKEN }} - steps: - - uses: actions/checkout@v4 + fetch-depth: 0 - - name: Resolve image from config - id: config - shell: bash + - name: Setup yq run: | if ! command -v yq >/dev/null 2>&1; then YQ_VERSION="v4.47.1" @@ -188,104 +56,82 @@ jobs: echo "${YQ_CHECKSUM} /usr/local/bin/yq" | sha256sum -c - || exit 1 chmod +x /usr/local/bin/yq fi - image=$(yq ".components.${{ matrix.component }}.image" .github/config/publish.yml) - echo "image=$image" >> "$GITHUB_OUTPUT" - echo "đŸ“Ļ Image: $image" - - name: Download amd64 digest - uses: actions/download-artifact@v4 - with: - name: docker-digest-${{ matrix.component }}-amd64 - path: ${{ runner.temp }}/digests - - - name: Download arm64 digest - uses: actions/download-artifact@v4 - with: - name: docker-digest-${{ matrix.component }}-arm64 - path: ${{ runner.temp }}/digests - - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v3 - - - name: Login to Docker Hub - uses: docker/login-action@v3 - with: - username: ${{ env.DOCKERHUB_USER }} - password: ${{ env.DOCKERHUB_TOKEN }} - - - name: Extract version - id: ver + # TODO(hubcio): Add sdk-python (it has to contain `dev`), sdk-node, sdk-java (SNAPSHOT?), sdk-go (store version in file?) when ready for edge auto-publish + - name: Check all components + id: check run: | chmod +x scripts/extract-version.sh - VERSION=$(scripts/extract-version.sh "${{ matrix.component }}") - echo "version=$VERSION" >> "$GITHUB_OUTPUT" - - name: Create and push manifest - working-directory: ${{ runner.temp }}/digests - env: - COMPONENTS_TO_PUBLISH: ${{ needs.check-docker-auto-publish.outputs.components_to_publish }} - run: | - IMAGE="${{ steps.config.outputs.image }}" - COMPONENT="${{ matrix.component }}" - VERSION="${{ steps.ver.outputs.version }}" - - echo "Creating manifests for $IMAGE from digests:" - ls -la + # Get all Docker components (always publish :edge) + DOCKER_COMPONENTS=$(yq -r '.components | to_entries | .[] | select(.value.registry == "dockerhub") | .key' .github/config/publish.yml | tr '\n' ',' | sed 's/,$//') + echo "docker_components=$DOCKER_COMPONENTS" >> "$GITHUB_OUTPUT" + echo "Docker components: $DOCKER_COMPONENTS" - # Always create the rolling 'edge' tag - docker buildx imagetools create \ - -t "${IMAGE}:edge" \ - $(printf "${IMAGE}@sha256:%s " *) - - echo "✅ Pushed manifest: ${IMAGE}:edge" + # Check Rust crates for pre-release versions without tags + CRATES_TO_PUBLISH="" + for crate in rust-common rust-binary-protocol rust-sdk rust-cli; do + VERSION=$(scripts/extract-version.sh "$crate") + TAG=$(scripts/extract-version.sh "$crate" --tag) - # Also create versioned tag if this component needs it - if echo "$COMPONENTS_TO_PUBLISH" | grep -qE "(^|,)${COMPONENT}(,|$)"; then - echo "Creating versioned manifest for $IMAGE:$VERSION" - docker buildx imagetools create \ - -t "${IMAGE}:${VERSION}" \ - $(printf "${IMAGE}@sha256:%s " *) + echo "Checking $crate: version=$VERSION, tag=$TAG" - echo "✅ Pushed manifest: ${IMAGE}:${VERSION}" - fi + if [[ ! "$VERSION" =~ -(edge|rc) ]]; then + echo " â­ī¸ Stable version - skipping" + continue + fi - - name: Inspect manifest - run: | - docker buildx imagetools inspect "${{ steps.config.outputs.image }}:edge" + if git rev-parse "$TAG" >/dev/null 2>&1; then + echo " â­ī¸ Tag exists - skipping" + continue + fi - # Create git tags for Docker images with versioned edge/rc releases - create-docker-tags: - name: Create Docker git tags - runs-on: ubuntu-latest - needs: [docker-manifests, check-docker-auto-publish] - if: needs.check-docker-auto-publish.outputs.should_publish == 'true' - permissions: - contents: write - steps: - - uses: actions/checkout@v4 - with: - fetch-depth: 0 + echo " ✅ Will publish" + CRATES_TO_PUBLISH="${CRATES_TO_PUBLISH:+$CRATES_TO_PUBLISH,}$crate" + done + echo "crates_to_publish=$CRATES_TO_PUBLISH" >> "$GITHUB_OUTPUT" + echo "Crates to publish: ${CRATES_TO_PUBLISH:-}" - - name: Create git tags - env: - COMPONENTS_TO_PUBLISH: ${{ needs.check-docker-auto-publish.outputs.components_to_publish }} - run: | - git config user.name "github-actions[bot]" - git config user.email "github-actions[bot]@users.noreply.github.com" + # Check SDKs for pre-release versions without tags + SDKS_TO_PUBLISH="" + for sdk in sdk-csharp; do + VERSION=$(scripts/extract-version.sh "$sdk") + TAG=$(scripts/extract-version.sh "$sdk" --tag) - chmod +x scripts/extract-version.sh + echo "Checking $sdk: version=$VERSION, tag=$TAG" - for component in $(echo "$COMPONENTS_TO_PUBLISH" | tr ',' ' '); do - TAG=$(scripts/extract-version.sh "$component" --tag) + if [[ ! "$VERSION" =~ -(edge|rc) ]]; then + echo " â­ī¸ Stable version - skipping" + continue + fi - if ! git rev-parse "$TAG" >/dev/null 2>&1; then - git tag -a "$TAG" -m "Release $TAG" - git push origin "$TAG" - echo "✅ Created tag: $TAG" - else - echo "â­ī¸ Tag $TAG already exists" + if git rev-parse "$TAG" >/dev/null 2>&1; then + echo " â­ī¸ Tag exists - skipping" + continue fi + + echo " ✅ Will publish" + # Convert sdk-csharp to csharp for publish.yml input format + SDK_NAME="${sdk#sdk-}" + SDKS_TO_PUBLISH="${SDKS_TO_PUBLISH:+$SDKS_TO_PUBLISH,}$SDK_NAME" done + echo "sdks_to_publish=$SDKS_TO_PUBLISH" >> "$GITHUB_OUTPUT" + echo "SDKs to publish: ${SDKS_TO_PUBLISH:-}" + + call-publish: + name: Publish components + needs: check-auto-publish + uses: ./.github/workflows/publish.yml + with: + commit: ${{ github.sha }} + dry_run: false + use_latest_ci: false + skip_tag_creation: false + publish_crates: ${{ needs.check-auto-publish.outputs.crates_to_publish }} + publish_dockerhub: ${{ needs.check-auto-publish.outputs.docker_components }} + publish_other: ${{ needs.check-auto-publish.outputs.sdks_to_publish }} + create_edge_docker_tag: true + secrets: inherit build-artifacts: name: Build artifacts @@ -373,148 +219,3 @@ jobs: - Commit: ${{ github.sha }} **Not an official ASF release** - for development/testing only. - - # Check if auto-publish should run for Docker edge/rc versions - check-docker-auto-publish: - name: Check Docker auto-publish - runs-on: ubuntu-latest - if: ${{ !github.event.repository.fork }} - outputs: - should_publish: ${{ steps.check.outputs.should_publish }} - components_to_publish: ${{ steps.check.outputs.components_to_publish }} - steps: - - uses: actions/checkout@v4 - with: - fetch-depth: 0 - - - name: Setup yq - run: | - if ! command -v yq >/dev/null 2>&1; then - YQ_VERSION="v4.47.1" - YQ_CHECKSUM="0fb28c6680193c41b364193d0c0fc4a03177aecde51cfc04d506b1517158c2fb" - curl -sSL -o /usr/local/bin/yq https://github.com/mikefarah/yq/releases/download/${YQ_VERSION}/yq_linux_amd64 - echo "${YQ_CHECKSUM} /usr/local/bin/yq" | sha256sum -c - || exit 1 - chmod +x /usr/local/bin/yq - fi - - - name: Check versions and tags for Docker components - id: check - run: | - chmod +x scripts/extract-version.sh - - # Get Docker components from config (same source as plan job) - DOCKER_COMPONENTS=$(yq -r '.components | to_entries | .[] | select(.value.registry == "dockerhub") | .key' .github/config/publish.yml) - - COMPONENTS_TO_PUBLISH="" - - for component in $DOCKER_COMPONENTS; do - VERSION=$(scripts/extract-version.sh "$component") - TAG=$(scripts/extract-version.sh "$component" --tag) - - echo "Checking $component: version=$VERSION, tag=$TAG" - - # Skip if version doesn't contain edge or rc - if [[ ! "$VERSION" =~ -(edge|rc) ]]; then - echo " â­ī¸ Stable version - skipping" - continue - fi - - # Skip if git tag already exists - if git rev-parse "$TAG" >/dev/null 2>&1; then - echo " â­ī¸ Tag exists - skipping" - continue - fi - - echo " ✅ Will publish versioned tag" - if [ -n "$COMPONENTS_TO_PUBLISH" ]; then - COMPONENTS_TO_PUBLISH="$COMPONENTS_TO_PUBLISH,$component" - else - COMPONENTS_TO_PUBLISH="$component" - fi - done - - if [ -z "$COMPONENTS_TO_PUBLISH" ]; then - echo "" - echo "No Docker components need versioned publishing" - echo "should_publish=false" >> "$GITHUB_OUTPUT" - echo "components_to_publish=" >> "$GITHUB_OUTPUT" - else - echo "" - echo "Components to publish: $COMPONENTS_TO_PUBLISH" - echo "should_publish=true" >> "$GITHUB_OUTPUT" - echo "components_to_publish=$COMPONENTS_TO_PUBLISH" >> "$GITHUB_OUTPUT" - fi - - # Check if auto-publish should run for edge/rc versions - check-auto-publish: - name: Check auto-publish - runs-on: ubuntu-latest - if: ${{ !github.event.repository.fork }} - outputs: - should_publish: ${{ steps.check.outputs.should_publish }} - crates_to_publish: ${{ steps.check.outputs.crates_to_publish }} - steps: - - uses: actions/checkout@v4 - with: - fetch-depth: 0 - - - name: Check versions and tags for each crate - id: check - run: | - chmod +x scripts/extract-version.sh - - CRATES_TO_PUBLISH="" - - # Check each crate individually - for crate in rust-common rust-binary-protocol rust-sdk rust-cli; do - VERSION=$(scripts/extract-version.sh "$crate") - TAG=$(scripts/extract-version.sh "$crate" --tag) - - echo "Checking $crate: version=$VERSION, tag=$TAG" - - # Skip if version doesn't contain edge or rc - if [[ ! "$VERSION" =~ -(edge|rc) ]]; then - echo " â­ī¸ Stable version - skipping" - continue - fi - - # Skip if tag already exists - if git rev-parse "$TAG" >/dev/null 2>&1; then - echo " â­ī¸ Tag exists - skipping" - continue - fi - - echo " ✅ Will publish" - if [ -n "$CRATES_TO_PUBLISH" ]; then - CRATES_TO_PUBLISH="$CRATES_TO_PUBLISH,$crate" - else - CRATES_TO_PUBLISH="$crate" - fi - done - - if [ -z "$CRATES_TO_PUBLISH" ]; then - echo "" - echo "No crates need publishing" - echo "should_publish=false" >> "$GITHUB_OUTPUT" - echo "crates_to_publish=" >> "$GITHUB_OUTPUT" - else - echo "" - echo "Crates to publish: $CRATES_TO_PUBLISH" - echo "should_publish=true" >> "$GITHUB_OUTPUT" - echo "crates_to_publish=$CRATES_TO_PUBLISH" >> "$GITHUB_OUTPUT" - fi - - # Auto-publish Rust crates for edge/rc versions - publish-rust-crates: - name: Auto-publish Rust crates - needs: check-auto-publish - if: needs.check-auto-publish.outputs.should_publish == 'true' - permissions: - contents: write # Required for git tag push - uses: ./.github/workflows/_publish_rust_crates.yml - with: - crates: ${{ needs.check-auto-publish.outputs.crates_to_publish }} - dry_run: false - create_tags: true - secrets: - CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }} diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index dbbc4ced4..11cf8669a 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -54,6 +54,62 @@ on: required: false default: "" + workflow_call: + inputs: + dry_run: + description: "Dry run (build/test only, no actual publish)" + type: boolean + default: false + commit: + description: "Commit SHA (defaults to github.sha)" + type: string + default: "" + publish_crates: + description: "Rust crates to publish (comma-separated)" + type: string + default: "" + publish_dockerhub: + description: "Docker images to publish (comma-separated)" + type: string + default: "" + publish_other: + description: "Other SDKs to publish (comma-separated)" + type: string + default: "" + skip_tag_creation: + description: "Skip git tag creation" + type: boolean + default: false + use_latest_ci: + description: "Use latest CI from master" + type: boolean + default: false + create_edge_docker_tag: + description: "Create rolling :edge Docker tag" + type: boolean + default: false + secrets: + CARGO_REGISTRY_TOKEN: + required: false + DOCKERHUB_USER: + required: false + DOCKERHUB_TOKEN: + required: false + PYPI_API_TOKEN: + required: false + NPM_TOKEN: + required: false + NEXUS_USER: + required: false + NEXUS_PW: + required: false + JAVA_GPG_SIGNING_KEY: + required: false + JAVA_GPG_PASSWORD: + required: false + NUGET_API_KEY: + required: false + env: IGGY_CI_BUILD: true @@ -73,11 +129,24 @@ jobs: outputs: commit: ${{ steps.resolve.outputs.commit }} has_targets: ${{ steps.check.outputs.has_targets }} + is_workflow_call: ${{ steps.detect.outputs.is_workflow_call }} steps: - uses: actions/checkout@v4 with: fetch-depth: 0 + - name: Detect trigger type + id: detect + run: | + # workflow_call sets github.event_name to 'workflow_call' + if [ "${{ github.event_name }}" = "workflow_call" ]; then + echo "is_workflow_call=true" >> "$GITHUB_OUTPUT" + echo "📞 Triggered via workflow_call" + else + echo "is_workflow_call=false" >> "$GITHUB_OUTPUT" + echo "đŸ–ąī¸ Triggered via workflow_dispatch" + fi + - name: Check if any targets specified id: check run: | @@ -94,8 +163,8 @@ jobs: run: | COMMIT="${{ inputs.commit }}" if [ -z "$COMMIT" ]; then - echo "❌ No commit specified" - exit 1 + COMMIT="${{ github.sha }}" + echo "â„šī¸ No commit specified, using github.sha: $COMMIT" fi if ! git rev-parse --verify "$COMMIT^{commit}" >/dev/null 2>&1; then @@ -103,23 +172,27 @@ jobs: exit 1 fi - # Verify commit is on master branch - echo "🔍 Verifying commit is on master branch..." - git fetch origin master --depth=1000 - - if ${{ inputs.dry_run }}; then + # Skip master branch check for workflow_call (caller already verified on master) + if [ "${{ steps.detect.outputs.is_workflow_call }}" = "true" ]; then + echo "✅ Called from workflow, skipping master check" + elif ${{ inputs.dry_run }}; then echo "đŸŒĩ Dry run, skipping master branch check" - elif git merge-base --is-ancestor "$COMMIT" origin/master; then - echo "✅ Commit is on master branch" else - echo "❌ ERROR: Commit $COMMIT is not on the master branch!" - echo "" - echo "Publishing is only allowed from commits on the master branch." - echo "Please ensure your commit has been merged to master before publishing." - echo "" - echo "To check which branch contains this commit, run:" - echo " git branch -r --contains $COMMIT" - exit 1 + echo "🔍 Verifying commit is on master branch..." + git fetch origin master --depth=1000 + + if git merge-base --is-ancestor "$COMMIT" origin/master; then + echo "✅ Commit is on master branch" + else + echo "❌ ERROR: Commit $COMMIT is not on the master branch!" + echo "" + echo "Publishing is only allowed from commits on the master branch." + echo "Please ensure your commit has been merged to master before publishing." + echo "" + echo "To check which branch contains this commit, run:" + echo " git branch -r --contains $COMMIT" + exit 1 + fi fi echo "commit=$COMMIT" >> "$GITHUB_OUTPUT" @@ -680,17 +753,40 @@ jobs: IMAGE="${{ steps.config.outputs.image }}" VERSION="${{ steps.ver.outputs.version }}" - echo "Creating manifest for $IMAGE:$VERSION from digests:" + echo "Creating manifests for $IMAGE from digests:" ls -la - docker buildx imagetools create \ - -t "${IMAGE}:${VERSION}" \ - $(printf "${IMAGE}@sha256:%s " *) + # Create :edge tag if requested (for auto-publish from post-merge) + if [ "${{ inputs.create_edge_docker_tag }}" = "true" ]; then + docker buildx imagetools create \ + -t "${IMAGE}:edge" \ + $(printf "${IMAGE}@sha256:%s " *) + echo "✅ Pushed manifest: ${IMAGE}:edge" + fi - echo "✅ Pushed manifest: ${IMAGE}:${VERSION}" + # Create versioned tag + # When called from auto-publish (create_edge_docker_tag=true), only create + # versioned tag for pre-release versions to match original post-merge behavior. + # Manual publish always creates versioned tag. + if [ "${{ inputs.create_edge_docker_tag }}" = "true" ]; then + if [[ "$VERSION" =~ -(edge|rc) ]]; then + docker buildx imagetools create \ + -t "${IMAGE}:${VERSION}" \ + $(printf "${IMAGE}@sha256:%s " *) + echo "✅ Pushed manifest: ${IMAGE}:${VERSION}" + else + echo "â„šī¸ Skipping versioned tag for stable version in auto-publish mode" + fi + else + docker buildx imagetools create \ + -t "${IMAGE}:${VERSION}" \ + $(printf "${IMAGE}@sha256:%s " *) + echo "✅ Pushed manifest: ${IMAGE}:${VERSION}" + fi - # Also create 'latest' tag for stable releases (not edge/rc/alpha/beta) - if [[ ! "$VERSION" =~ (edge|rc|alpha|beta) ]]; then + # Create :latest for stable releases (not edge/rc) + # Only create :latest in manual publish mode - auto-publish should never update :latest + if [ "${{ inputs.create_edge_docker_tag }}" != "true" ] && [[ ! "$VERSION" =~ -(edge|rc) ]]; then echo "Creating 'latest' manifest" docker buildx imagetools create \ -t "${IMAGE}:latest" \ @@ -700,7 +796,16 @@ jobs: - name: Inspect manifest run: | - docker buildx imagetools inspect "${{ steps.config.outputs.image }}:${{ steps.ver.outputs.version }}" + IMAGE="${{ steps.config.outputs.image }}" + VERSION="${{ steps.ver.outputs.version }}" + + # In auto-publish mode with stable version, we only pushed :edge + if [ "${{ inputs.create_edge_docker_tag }}" = "true" ] && [[ ! "$VERSION" =~ -(edge|rc) ]]; then + echo "Inspecting :edge manifest (versioned tag was skipped for stable version)" + docker buildx imagetools inspect "${IMAGE}:edge" + else + docker buildx imagetools inspect "${IMAGE}:${VERSION}" + fi # Non-Docker, non-Rust publishing (Python, Node, Java, C#, Go SDKs) # Note: This job runs in parallel with Docker publishing - no dependency between them @@ -915,6 +1020,7 @@ jobs: set -euo pipefail TARGETS_JSON='${{ needs.plan.outputs.targets }}' GO_SDK_VERSION='${{ needs.plan.outputs.go_sdk_version }}' + CREATE_EDGE_DOCKER_TAG="${{ inputs.create_edge_docker_tag }}" echo "$TARGETS_JSON" | jq -r '.include[] | select(.key!="noop") | @base64' | while read -r row; do _jq() { echo "$row" | base64 -d | jq -r "$1"; } @@ -922,6 +1028,7 @@ jobs: KEY=$(_jq '.key') NAME=$(_jq '.name') TAG_PATTERN=$(_jq '.tag_pattern') + REGISTRY=$(_jq '.registry') # Only components that define tag_pattern will be tagged if [ -z "$TAG_PATTERN" ] || [ "$TAG_PATTERN" = "null" ]; then @@ -933,8 +1040,19 @@ jobs: GO_FLAG="--go-sdk-version $GO_SDK_VERSION" fi + VERSION=$(scripts/extract-version.sh "$KEY" $GO_FLAG) TAG=$(scripts/extract-version.sh "$KEY" $GO_FLAG --tag) + # In auto-publish mode (create_edge_docker_tag=true), skip Docker components + # with stable versions - only pre-release versions should get versioned tags. + # This matches the behavior where versioned Docker manifests are also skipped. + if [ "$CREATE_EDGE_DOCKER_TAG" = "true" ] && [ "$REGISTRY" = "dockerhub" ]; then + if [[ ! "$VERSION" =~ -(edge|rc) ]]; then + echo "â„šī¸ Skipping git tag for $NAME (stable Docker version in auto-publish mode)" + continue + fi + fi + echo "Creating tag: $TAG for $NAME" if git rev-parse "$TAG" >/dev/null 2>&1; then