This is an automated email from the ASF dual-hosted git repository.
Seven-Streams pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/tvm-ffi.git
The following commit(s) were added to refs/heads/main by this push:
new 54a51b2d [CI][Rust] Publish crates manually from release tags (#837)
54a51b2d is described below
commit 54a51b2df86a5024dc0c9d8908aab81fd4ecbd71
Author: Linzhang Li <[email protected]>
AuthorDate: Mon Oct 5 19:34:12 2026 -0400
[CI][Rust] Publish crates manually from release tags (#837)
Add a manually triggered workflow to build, test, package, and publish
all
three Rust crates. The required `tag` must already exist in the remote
repository; the workflow checks out its corresponding commit. Match the
PyPI matrix: Linux x86_64/aarch64, Windows AMD64, and macOS arm64.
Derive crate and internal dependency versions from the selected Git tag
(e.g. `v0.1.14`, `v0.1.14-post1`), replacing the development
placeholders
in the CI checkout.
Default to `dry_run=true`: run publication checks on every platform and
retain
crate artifacts without uploading to crates.io or requiring a token.
With
`dry_run=false`, publish in dependency order after all matrix jobs pass,
using `CARGO_REGISTRY_TOKEN`.
Validation: pre-commit, actionlint, local Linux release builds/tests,
version
mapping, crate packaging, and publication dry-runs passed. No live
upload.
---------
Signed-off-by: yuchuan <[email protected]>
---
.github/workflows/publish_crates.yml | 202 +++++++++++++++++++++++++++++++++++
pyproject.toml | 3 +-
rust/tvm-ffi-macros/Cargo.toml | 1 +
rust/tvm-ffi-sys/Cargo.toml | 1 +
rust/tvm-ffi/Cargo.toml | 2 +
5 files changed, 208 insertions(+), 1 deletion(-)
diff --git a/.github/workflows/publish_crates.yml
b/.github/workflows/publish_crates.yml
new file mode 100644
index 00000000..a8f0afff
--- /dev/null
+++ b/.github/workflows/publish_crates.yml
@@ -0,0 +1,202 @@
+# 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 crates
+
+on:
+ workflow_dispatch:
+ inputs:
+ tag:
+ description: "Tag to publish (manual run)"
+ required: true
+ type: string
+ dry_run:
+ description: "Build and verify crates without publishing to crates.io"
+ required: true
+ type: boolean
+ default: true
+
+permissions:
+ contents: read
+
+concurrency:
+ group: publish-crates-${{ inputs.tag }}
+ cancel-in-progress: false
+
+env:
+ CARGO_TERM_COLOR: always
+ RELEASE_TAG: ${{ inputs.tag }}
+
+jobs:
+ build_crates:
+ name: ${{ matrix.os }} (${{ matrix.arch }})
+ runs-on: ${{ matrix.os }}
+ strategy:
+ fail-fast: false
+ matrix:
+ # Keep the OS/architecture matrix in sync with publish_wheel.yml.
+ include:
+ - {os: ubuntu-latest, arch: x86_64}
+ - {os: ubuntu-24.04-arm, arch: aarch64}
+ - {os: windows-latest, arch: AMD64}
+ - {os: macos-14, arch: arm64}
+
+ steps:
+ - name: Check out release source
+ uses: actions/checkout@v5
+ with:
+ ref: refs/tags/${{ inputs.tag }}
+ submodules: recursive
+ fetch-depth: 0
+ fetch-tags: true
+
+ - name: Set up uv
+ uses: astral-sh/setup-uv@c18668ad3cf93ea998bef934396af7bb5c839dc7 #
v10.2.0
+ with:
+ python-version: "3.13"
+ activate-environment: true
+
+ # Workspace publishing and dry-runs require Cargo 1.90 or newer.
+ - name: Set up Rust
+ run: rustup toolchain install stable --profile minimal
+
+ - uses: ./.github/actions/detect-env-vars
+ id: env_vars
+
+ # tvm-ffi-sys locates libtvm_ffi through tvm-ffi-config on PATH.
+ - name: Build and install TVM FFI
+ env:
+ CMAKE_BUILD_PARALLEL_LEVEL: ${{ steps.env_vars.outputs.cpu_count }}
+ run: uv pip install --verbose .
+
+ # Apply the release version after the Python build so setuptools-scm
sees a clean tree.
+ - name: Set crate versions from Git
+ shell: bash
+ run: &set_crate_versions |
+ # The crate version is the tag without its "v": 0.1.15, 0.1.15-rc0
or 0.1.14-post1.
+ if [[ ! "$RELEASE_TAG" =~
^v[0-9]+\.[0-9]+\.[0-9]+(-(rc|post)[0-9]+)?$ ]]; then
+ echo "::error::unsupported release tag '$RELEASE_TAG': expected
vX.Y.Z, vX.Y.Z-rcN or vX.Y.Z-postN"
+ exit 1
+ fi
+ export CRATE_VERSION="${RELEASE_TAG#v}"
+ echo "CRATE_VERSION=$CRATE_VERSION" >> "$GITHUB_ENV"
+ uv run --no-project --with tomlkit python - <<'PY'
+ import os
+ from pathlib import Path
+
+ import tomlkit
+
+ version = os.environ["CRATE_VERSION"]
+ crates = ("tvm-ffi", "tvm-ffi-sys", "tvm-ffi-macros")
+ for crate in crates:
+ path = Path("rust") / crate / "Cargo.toml"
+ manifest = tomlkit.parse(path.read_text(encoding="utf-8"))
+ manifest["package"]["version"] = version
+ for section in ("dependencies", "dev-dependencies",
"build-dependencies"):
+ for name, dependency in manifest.get(section, {}).items():
+ if name in crates:
+ # Exact pin: the three crates ship together.
+ dependency["version"] = f"={version}"
+ path.write_text(tomlkit.dumps(manifest), encoding="utf-8")
+ print(f"{crate}: {version}")
+ PY
+ # Cargo validates the derived SemVer and the updated dependency
requirements.
+ cargo +stable metadata --manifest-path rust/Cargo.toml --no-deps
--format-version 1 > /dev/null
+
+ - name: Test crates
+ working-directory: rust
+ run: cargo +stable test --release --workspace
+
+ # Packages and verifies the crates; only the release-version edits above
are uncommitted.
+ - name: Dry-run crate publication
+ working-directory: rust
+ run: cargo +stable publish --dry-run --workspace --registry crates-io
--allow-dirty
+
+ # The dry run keeps its .crate files in a temporary directory; write
them out again,
+ # without re-verifying, for the artifact upload.
+ - name: Package crates
+ working-directory: rust
+ run: cargo +stable package --workspace --registry crates-io
--allow-dirty --no-verify
+
+ - name: Upload crate artifacts
+ uses: actions/upload-artifact@v4
+ with:
+ name: crates-${{ matrix.os }}-${{ matrix.arch }}
+ path: rust/target/package/*.crate
+ if-no-files-found: error
+
+ upload_crates:
+ needs: [build_crates]
+ runs-on: ubuntu-latest
+ environment: crates-io
+ if: github.event_name == 'workflow_dispatch' && !inputs.dry_run
+ steps:
+ - name: Check out release source
+ uses: actions/checkout@v5
+ with:
+ ref: refs/tags/${{ inputs.tag }}
+ submodules: recursive
+ fetch-depth: 0
+ fetch-tags: true
+
+ - name: Set up uv
+ uses: astral-sh/setup-uv@c18668ad3cf93ea998bef934396af7bb5c839dc7 #
v10.2.0
+ with:
+ python-version: "3.13"
+ activate-environment: true
+
+ - name: Set up Rust
+ run: rustup toolchain install stable --profile minimal
+
+ - uses: ./.github/actions/detect-env-vars
+ id: env_vars
+
+ - name: Build and install TVM FFI
+ env:
+ CMAKE_BUILD_PARALLEL_LEVEL: ${{ steps.env_vars.outputs.cpu_count }}
+ run: uv pip install --verbose .
+
+ - name: Set crate versions from Git
+ shell: bash
+ run: *set_crate_versions
+
+ # Verify all three crates before anything is uploaded; the publishes
below skip re-verifying.
+ - name: Package and verify crates
+ working-directory: rust
+ run: cargo +stable package --workspace --registry crates-io
--allow-dirty
+
+ # Publish in dependency order, skipping versions already on crates.io so
a partial run can be
+ # repeated. Needs a crates.io token with publish access to all three
crates.
+ - name: Publish crates to crates.io
+ working-directory: rust
+ shell: bash
+ env:
+ CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }}
+ run: |
+ for crate in tvm-ffi-macros tvm-ffi-sys tvm-ffi; do
+ if lookup=$(cargo +stable info --registry crates-io
"${crate}@${CRATE_VERSION}" 2>&1); then
+ echo "${crate}@${CRATE_VERSION} is already on crates.io;
skipping."
+ continue
+ elif ! grep -q "could not find" <<< "${lookup}"; then
+ # Only a definite "not found" may fall through to publishing.
+ echo "${lookup}"
+ echo "::error::Could not determine whether
${crate}@${CRATE_VERSION} is on crates.io"
+ exit 1
+ fi
+ echo "Publishing ${crate}@${CRATE_VERSION}"
+ cargo +stable publish --package "${crate}" --registry crates-io
--allow-dirty --no-verify
+ done
diff --git a/pyproject.toml b/pyproject.toml
index 68c9480a..105953b2 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -73,7 +73,8 @@ dev = [
]
docs = [
"autodocsumm",
- "breathe",
+ # 5.0.0 breaks C++ template specializations and constexpr constructors.
+ "breathe!=5.0.0",
"exhale",
"linkify-it-py",
"matplotlib",
diff --git a/rust/tvm-ffi-macros/Cargo.toml b/rust/tvm-ffi-macros/Cargo.toml
index f8d29d40..6c646904 100644
--- a/rust/tvm-ffi-macros/Cargo.toml
+++ b/rust/tvm-ffi-macros/Cargo.toml
@@ -19,6 +19,7 @@
name = "tvm-ffi-macros"
description = "Procedural macro crate for tvm-ffi"
+# Development placeholder; publish_crates.yml sets the release version from
the Git tag.
version = "0.1.0-alpha.0"
edition = "2021"
license = "Apache-2.0"
diff --git a/rust/tvm-ffi-sys/Cargo.toml b/rust/tvm-ffi-sys/Cargo.toml
index 5ae2d954..04ad1744 100644
--- a/rust/tvm-ffi-sys/Cargo.toml
+++ b/rust/tvm-ffi-sys/Cargo.toml
@@ -19,6 +19,7 @@
name = "tvm-ffi-sys"
description = "Low-level sys crate for tvm-ffi"
+# Development placeholder; publish_crates.yml sets the release version from
the Git tag.
version = "0.1.0-alpha.0"
edition = "2021"
license = "Apache-2.0"
diff --git a/rust/tvm-ffi/Cargo.toml b/rust/tvm-ffi/Cargo.toml
index 3df4eaf9..1fbd1c8a 100644
--- a/rust/tvm-ffi/Cargo.toml
+++ b/rust/tvm-ffi/Cargo.toml
@@ -19,6 +19,7 @@
name = "tvm-ffi"
description = "tvm-ffi rust support"
+# Development placeholder; publish_crates.yml sets the release version from
the Git tag.
version = "0.1.0-alpha.0"
edition = "2021"
license = "Apache-2.0"
@@ -30,6 +31,7 @@ crate-type = ["lib"]
[dependencies]
paste = "1.0"
+# Release CI also updates the internal dependency versions, including
dev-dependencies.
tvm-ffi-sys = { version = "0.1.0-alpha.0", path = "../tvm-ffi-sys" }
tvm-ffi-macros = { version = "0.1.0-alpha.0", path = "../tvm-ffi-macros" }