This is an automated email from the ASF dual-hosted git repository.

piotr pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/iggy.git


The following commit(s) were added to refs/heads/master by this push:
     new d7afbb60e feat(ci): add automatic crates.io publishing for edge/rc 
versions (#2508)
d7afbb60e is described below

commit d7afbb60eb911f6b040ae0d84c2d6988002ba019
Author: Hubert Gruszecki <[email protected]>
AuthorDate: Sun Dec 21 10:35:44 2025 +0100

    feat(ci): add automatic crates.io publishing for edge/rc versions (#2508)
    
    Extract Rust crate publishing into reusable workflow and add auto-publish
    to post-merge for versions containing `-edge` or `-rc` suffix.
    
    - Add _publish_rust_crates.yml reusable workflow
    - Add check-auto-publish job to detect edge/rc versions
    - Skip publishing if git tag already exists
    - Refactor publish.yml to use the new reusable workflow
---
 .github/workflows/_publish_rust_crates.yml | 214 +++++++++++++++++++++++++++++
 .github/workflows/post-merge.yml           |  74 ++++++++++
 .github/workflows/publish.yml              | 149 ++------------------
 3 files changed, 297 insertions(+), 140 deletions(-)

diff --git a/.github/workflows/_publish_rust_crates.yml 
b/.github/workflows/_publish_rust_crates.yml
new file mode 100644
index 000000000..d2e7db074
--- /dev/null
+++ b/.github/workflows/_publish_rust_crates.yml
@@ -0,0 +1,214 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+name: _publish_rust_crates
+on:
+  workflow_call:
+    inputs:
+      crates:
+        type: string
+        required: true
+        description: "Comma-separated list of crates to publish: 
rust-common,rust-binary-protocol,rust-sdk,rust-cli"
+      dry_run:
+        type: boolean
+        required: false
+        default: false
+        description: "Dry run mode - validate without publishing"
+      create_tags:
+        type: boolean
+        required: false
+        default: true
+        description: "Create git tags after successful publishing"
+      commit:
+        type: string
+        required: false
+        default: ""
+        description: "Specific commit to checkout (defaults to github.sha)"
+      use_latest_ci:
+        type: boolean
+        required: false
+        default: false
+        description: "Use latest CI configuration from master branch"
+    secrets:
+      CARGO_REGISTRY_TOKEN:
+        required: true
+    outputs:
+      status:
+        description: "Publishing status"
+        value: ${{ jobs.publish.outputs.status }}
+
+permissions:
+  contents: write
+
+env:
+  IGGY_CI_BUILD: true
+
+jobs:
+  publish:
+    name: Publish Rust crates
+    runs-on: ubuntu-latest
+    env:
+      CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }}
+    outputs:
+      status: ${{ steps.final-status.outputs.status }}
+    steps:
+      - name: Download latest copy script from master
+        if: inputs.use_latest_ci
+        run: |
+          curl -sSL "https://raw.githubusercontent.com/${{ github.repository 
}}/master/scripts/copy-latest-from-master.sh" \
+            -o /tmp/copy-latest-from-master.sh
+          chmod +x /tmp/copy-latest-from-master.sh
+          echo "✅ Downloaded latest copy script from master"
+
+      - name: Checkout
+        uses: actions/checkout@v4
+        with:
+          ref: ${{ inputs.commit || github.sha }}
+          fetch-depth: 0
+
+      - name: Save and apply latest CI from master
+        if: inputs.use_latest_ci
+        run: |
+          /tmp/copy-latest-from-master.sh save \
+            .github \
+            scripts \
+            web/Dockerfile \
+            core/server/Dockerfile \
+            core/ai/mcp/Dockerfile \
+            core/connectors/runtime/Dockerfile \
+            core/bench/dashboard/server/Dockerfile
+
+          /tmp/copy-latest-from-master.sh apply
+
+      - name: Setup Rust with cache
+        uses: ./.github/actions/utils/setup-rust-with-cache
+        with:
+          cache-targets: false
+          show-stats: false
+
+      - name: Extract versions
+        id: versions
+        run: |
+          chmod +x scripts/extract-version.sh
+          echo "common=$(scripts/extract-version.sh rust-common)" >> 
"$GITHUB_OUTPUT"
+          echo "protocol=$(scripts/extract-version.sh rust-binary-protocol)" 
>> "$GITHUB_OUTPUT"
+          echo "sdk=$(scripts/extract-version.sh rust-sdk)" >> "$GITHUB_OUTPUT"
+          echo "cli=$(scripts/extract-version.sh rust-cli)" >> "$GITHUB_OUTPUT"
+
+          echo "📦 Versions to publish:"
+          echo "  iggy_common: $(scripts/extract-version.sh rust-common)"
+          echo "  iggy_binary_protocol: $(scripts/extract-version.sh 
rust-binary-protocol)"
+          echo "  iggy: $(scripts/extract-version.sh rust-sdk)"
+          echo "  iggy-cli: $(scripts/extract-version.sh rust-cli)"
+
+      # Step 1: Publish iggy_common
+      - name: Publish iggy_common
+        if: contains(inputs.crates, 'rust-common')
+        uses: ./.github/actions/rust/post-merge
+        with:
+          package: iggy_common
+          version: ${{ steps.versions.outputs.common }}
+          dry_run: ${{ inputs.dry_run }}
+
+      - name: Wait for iggy_common to be available
+        if: contains(inputs.crates, 'rust-common') && inputs.dry_run == false
+        run: |
+          echo "⏳ Waiting for iggy_common to be available on crates.io..."
+          for i in {1..30}; do
+            if cargo search iggy_common --limit 1 | grep -q "^iggy_common = 
\"${{ steps.versions.outputs.common }}\""; then
+              echo "✅ iggy_common is now available"
+              break
+            fi
+            echo "Waiting... (attempt $i/30)"
+            sleep 10
+          done
+
+      # Step 2: Publish iggy_binary_protocol (depends on common)
+      - name: Publish iggy_binary_protocol
+        if: contains(inputs.crates, 'rust-binary-protocol')
+        uses: ./.github/actions/rust/post-merge
+        with:
+          package: iggy_binary_protocol
+          version: ${{ steps.versions.outputs.protocol }}
+          dry_run: ${{ inputs.dry_run }}
+
+      - name: Wait for iggy_binary_protocol to be available
+        if: contains(inputs.crates, 'rust-binary-protocol') && inputs.dry_run 
== false
+        run: |
+          echo "⏳ Waiting for iggy_binary_protocol to be available on 
crates.io..."
+          for i in {1..30}; do
+            if cargo search iggy_binary_protocol --limit 1 | grep -q 
"^iggy_binary_protocol = \"${{ steps.versions.outputs.protocol }}\""; then
+              echo "✅ iggy_binary_protocol is now available"
+              break
+            fi
+            echo "Waiting... (attempt $i/30)"
+            sleep 10
+          done
+
+      # Step 3: Publish iggy SDK (depends on common and protocol)
+      - name: Publish iggy SDK
+        if: contains(inputs.crates, 'rust-sdk')
+        uses: ./.github/actions/rust/post-merge
+        with:
+          package: iggy
+          version: ${{ steps.versions.outputs.sdk }}
+          dry_run: ${{ inputs.dry_run }}
+
+      - name: Wait for iggy SDK to be available
+        if: contains(inputs.crates, 'rust-sdk') && inputs.dry_run == false
+        run: |
+          echo "⏳ Waiting for iggy to be available on crates.io..."
+          for i in {1..30}; do
+            if cargo search iggy --limit 1 | grep -q "^iggy = \"${{ 
steps.versions.outputs.sdk }}\""; then
+              echo "✅ iggy SDK is now available"
+              break
+            fi
+            echo "Waiting... (attempt $i/30)"
+            sleep 10
+          done
+
+      # Step 4: Publish iggy-cli (depends on SDK and protocol)
+      - name: Publish iggy-cli
+        if: contains(inputs.crates, 'rust-cli')
+        uses: ./.github/actions/rust/post-merge
+        with:
+          package: iggy-cli
+          version: ${{ steps.versions.outputs.cli }}
+          dry_run: ${{ inputs.dry_run }}
+
+      # Create git tags
+      - name: Create git tags
+        if: inputs.create_tags && inputs.dry_run == false
+        run: |
+          git config user.name "github-actions[bot]"
+          git config user.email "github-actions[bot]@users.noreply.github.com"
+
+          for crate in $(echo "${{ inputs.crates }}" | tr ',' ' '); do
+            TAG=$(scripts/extract-version.sh "$crate" --tag)
+            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"
+            fi
+          done
+
+      - name: Set final status output
+        id: final-status
+        if: always()
+        run: echo "status=${{ job.status }}" >> "$GITHUB_OUTPUT"
diff --git a/.github/workflows/post-merge.yml b/.github/workflows/post-merge.yml
index c47091e41..9d38472e7 100644
--- a/.github/workflows/post-merge.yml
+++ b/.github/workflows/post-merge.yml
@@ -309,3 +309,77 @@ jobs:
             - Commit: ${{ github.sha }}
 
             **Not an official ASF release** - for development/testing only.
+
+  # 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 e5c02f49b..646955d19 100644
--- a/.github/workflows/publish.yml
+++ b/.github/workflows/publish.yml
@@ -486,151 +486,20 @@ jobs:
 
   # Sequential Rust crate publishing to handle dependencies properly
   publish-rust-crates:
-    name: Publish Rust Crates
+    name: Publish Rust crates
     needs: [validate, plan, check-tags]
     if: |
       needs.validate.outputs.has_targets == 'true' &&
       contains(inputs.publish_crates, 'rust-')
-    runs-on: ubuntu-latest
-    env:
+    uses: ./.github/workflows/_publish_rust_crates.yml
+    with:
+      crates: ${{ inputs.publish_crates }}
+      dry_run: ${{ inputs.dry_run }}
+      create_tags: false  # publish.yml handles tags separately in create-tags 
job
+      commit: ${{ needs.validate.outputs.commit }}
+      use_latest_ci: ${{ inputs.use_latest_ci }}
+    secrets:
       CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }}
-      DRY_RUN: ${{ inputs.dry_run }}
-    outputs:
-      status: ${{ steps.final-status.outputs.status }}
-    steps:
-      - name: Download latest copy script from master
-        if: inputs.use_latest_ci
-        run: |
-          curl -sSL "https://raw.githubusercontent.com/${{ github.repository 
}}/master/scripts/copy-latest-from-master.sh" \
-            -o /tmp/copy-latest-from-master.sh
-          chmod +x /tmp/copy-latest-from-master.sh
-          echo "✅ Downloaded latest copy script from master"
-
-      - name: Checkout at commit
-        uses: actions/checkout@v4
-        with:
-          ref: ${{ needs.validate.outputs.commit }}
-          fetch-depth: 0
-
-      - name: Save and apply latest CI from master
-        if: inputs.use_latest_ci
-        run: |
-          /tmp/copy-latest-from-master.sh save \
-            .github \
-            scripts \
-            web/Dockerfile \
-            core/server/Dockerfile \
-            core/ai/mcp/Dockerfile \
-            core/connectors/runtime/Dockerfile \
-            core/bench/dashboard/server/Dockerfile
-
-          /tmp/copy-latest-from-master.sh apply
-
-      - name: Setup Rust with cache
-        uses: ./.github/actions/utils/setup-rust-with-cache
-        with:
-          cache-targets: false
-          show-stats: false
-
-      - name: Extract versions
-        id: versions
-        run: |
-          # Extract version for each crate
-          chmod +x scripts/extract-version.sh
-
-          echo "common_version=$(scripts/extract-version.sh rust-common)" >> 
$GITHUB_OUTPUT
-          echo "protocol_version=$(scripts/extract-version.sh 
rust-binary-protocol)" >> $GITHUB_OUTPUT
-          echo "sdk_version=$(scripts/extract-version.sh rust-sdk)" >> 
$GITHUB_OUTPUT
-          echo "cli_version=$(scripts/extract-version.sh rust-cli)" >> 
$GITHUB_OUTPUT
-
-      # Step 1: Publish iggy_common first
-      - name: Publish iggy_common
-        if: contains(inputs.publish_crates, 'rust-common')
-        uses: ./.github/actions/rust/post-merge
-        with:
-          package: iggy_common
-          version: ${{ steps.versions.outputs.common_version }}
-          dry_run: ${{ inputs.dry_run }}
-
-      # Wait for crates.io to index (only in non-dry-run mode)
-      - name: Wait for iggy_common to be available
-        if: |
-          contains(inputs.publish_crates, 'rust-common') &&
-          inputs.dry_run == 'false'
-        run: |
-          echo "⏳ Waiting for iggy_common to be available on crates.io..."
-          for i in {1..30}; do
-            if cargo search iggy_common --limit 1 | grep -q "^iggy_common = 
\"${{ steps.versions.outputs.common_version }}\""; then
-              echo "✅ iggy_common is now available"
-              break
-            fi
-            echo "Waiting... (attempt $i/30)"
-            sleep 10
-          done
-
-      # Step 2: Publish iggy_binary_protocol (depends on common)
-      - name: Publish iggy_binary_protocol
-        if: contains(inputs.publish_crates, 'rust-binary-protocol')
-        uses: ./.github/actions/rust/post-merge
-        with:
-          package: iggy_binary_protocol
-          version: ${{ steps.versions.outputs.protocol_version }}
-          dry_run: ${{ inputs.dry_run }}
-
-      # Wait for crates.io to index
-      - name: Wait for iggy_binary_protocol to be available
-        if: |
-          contains(inputs.publish_crates, 'rust-binary-protocol') &&
-          inputs.dry_run == 'false'
-        run: |
-          echo "⏳ Waiting for iggy_binary_protocol to be available on 
crates.io..."
-          for i in {1..30}; do
-            if cargo search iggy_binary_protocol --limit 1 | grep -q 
"^iggy_binary_protocol = \"${{ steps.versions.outputs.protocol_version }}\""; 
then
-              echo "✅ iggy_binary_protocol is now available"
-              break
-            fi
-            echo "Waiting... (attempt $i/30)"
-            sleep 10
-          done
-
-      # Step 3: Publish iggy SDK (depends on common and protocol)
-      - name: Publish iggy SDK
-        if: contains(inputs.publish_crates, 'rust-sdk')
-        uses: ./.github/actions/rust/post-merge
-        with:
-          package: iggy
-          version: ${{ steps.versions.outputs.sdk_version }}
-          dry_run: ${{ inputs.dry_run }}
-
-      # Wait for crates.io to index
-      - name: Wait for iggy SDK to be available
-        if: |
-          contains(inputs.publish_crates, 'rust-sdk') &&
-          inputs.dry_run == 'false'
-        run: |
-          echo "⏳ Waiting for iggy to be available on crates.io..."
-          for i in {1..30}; do
-            if cargo search iggy --limit 1 | grep -q "^iggy = \"${{ 
steps.versions.outputs.sdk_version }}\""; then
-              echo "✅ iggy SDK is now available"
-              break
-            fi
-            echo "Waiting... (attempt $i/30)"
-            sleep 10
-          done
-
-      # Step 4: Publish iggy-cli (depends on SDK and protocol)
-      - name: Publish iggy-cli
-        if: contains(inputs.publish_crates, 'rust-cli')
-        uses: ./.github/actions/rust/post-merge
-        with:
-          package: iggy-cli
-          version: ${{ steps.versions.outputs.cli_version }}
-          dry_run: ${{ inputs.dry_run }}
-
-      - name: Set final status output
-        id: final-status
-        if: always()
-        run: echo "status=${{ job.status }}" >> "$GITHUB_OUTPUT"
 
   # Docker publishing on native runners (no QEMU emulation)
   publish-docker:

Reply via email to