Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# CI — thin wrapper that calls the reusable test workflow.

name: CI

on:
pull_request:
branches: [main]
types: [opened, synchronize, reopened, ready_for_review]
workflow_dispatch:
workflow_call:

concurrency:
group: ci-${{ github.ref }}
cancel-in-progress: true

permissions:
contents: read

jobs:
test:
if: github.event.pull_request.draft == false
name: Test Suite
uses: ./.github/workflows/test.yml
275 changes: 275 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,275 @@
name: Release
run-name: Release ${{ github.ref_name }}

on:
push:
tags:
- "v*"

concurrency:
group: release
cancel-in-progress: false

permissions:
contents: read

env:
CARGO_TERM_COLOR: always

jobs:
# ── Validate tag ─────────────────────────────────────────────────────────────
validate-version:
name: Validate Version Tag
runs-on: ubuntu-latest
outputs:
version: ${{ steps.version.outputs.version }}
is_full_release: ${{ steps.version.outputs.is_full_release }}
steps:
- uses: actions/checkout@v6

- name: Install Rust
uses: dtolnay/rust-toolchain@stable

- name: Validate tag against Cargo.toml
id: version
run: |
TAG="${GITHUB_REF_NAME}"
TAG_VERSION="${TAG#v}"

CARGO_VERSION=$(cargo metadata --no-deps --format-version=1 \
| jq -r '.packages[] | select(.name == "venus") | .version')
CARGO_BASE=$(echo "$CARGO_VERSION" | grep -oP '^\d+\.\d+\.\d+')

echo "Tag version: $TAG_VERSION"
echo "Cargo.toml version: $CARGO_VERSION"
echo "Cargo.toml base: $CARGO_BASE"

if [[ ! "$TAG_VERSION" =~ ^([0-9]+\.[0-9]+\.[0-9]+)(-[a-zA-Z]+\.[0-9]+)?$ ]]; then
echo "::error::Invalid tag format '$TAG'. Expected: vX.Y.Z or vX.Y.Z-label.N"
exit 1
fi

TAG_BASE="${BASH_REMATCH[1]}"

if [[ "$TAG_BASE" != "$CARGO_BASE" ]]; then
echo "::error::Base version mismatch! Tag '$TAG_BASE' != Cargo.toml '$CARGO_BASE'"
exit 1
fi

# Full release = no hyphen suffix (v0.1.0, not v0.1.0-beta.1)
if [[ "$TAG_VERSION" == *-* ]]; then
echo "is_full_release=false" >> "$GITHUB_OUTPUT"
else
echo "is_full_release=true" >> "$GITHUB_OUTPUT"
fi

echo "version=$TAG_VERSION" >> "$GITHUB_OUTPUT"

# ── CI gate ──────────────────────────────────────────────────────────────────
ci:
name: CI Gate
needs: validate-version
uses: ./.github/workflows/ci.yml

# ── Publish crates to crates.io ──────────────────────────────────────────────
publish-crates:
name: Publish to crates.io
needs: [validate-version, ci]
runs-on: ubuntu-latest
environment: crates.io
permissions:
contents: read
steps:
- uses: actions/checkout@v6

- name: Install Rust
uses: dtolnay/rust-toolchain@stable

- name: Set version from tag
run: |
VERSION="${{ needs.validate-version.outputs.version }}"
CURRENT=$(cargo metadata --no-deps --format-version=1 \
| jq -r '.packages[] | select(.name == "venus") | .version')
if [[ "$VERSION" != "$CURRENT" ]]; then
sed -i "0,/^version = \".*\"/s//version = \"$VERSION\"/" Cargo.toml

if [[ "$VERSION" == *-* ]]; then
sed -i -E 's/(venus(-(macros|core|sync|server))? = \{ [^}]*version = )"[^"]*"/\1"='"$VERSION"'"/' Cargo.toml
echo "Updated internal dep versions to =$VERSION"
fi

echo "Updated workspace version: $CURRENT -> $VERSION"
else
echo "Version already matches, no change needed"
fi

- name: Publish crates
env:
CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }}
run: |
# Tier 1: no internal venus dependencies
TIER1="venus-macros venus-core"
# Tier 2: depends on venus-core
TIER2="venus-sync"
# Tier 3: depends on venus-core + venus-sync
TIER3="venus-server"
# Tier 4: top-level CLI binary
TIER4="venus"

is_published() {
curl -sf \
-H "User-Agent: venus-ci (github.com/ml-rust/venus)" \
"https://crates.io/api/v1/crates/$1/$2" > /dev/null 2>&1
}

wait_for() {
local crate="$1" version="$2"
echo -n " Waiting for $crate@$version..."
for i in $(seq 1 30); do
if is_published "$crate" "$version"; then
echo " ready"
return 0
fi
sleep 5
done
echo " timed out!"
return 1
}

publish_tier() {
local tier_name="$1"; shift
local crates=("$@")
local need_wait=()

echo "::group::Tier: $tier_name"
for crate in "${crates[@]}"; do
VERSION=$(cargo metadata --no-deps --format-version=1 \
| jq -r --arg name "$crate" '.packages[] | select(.name == $name) | .version')
if is_published "$crate" "$VERSION"; then
echo " $crate@$VERSION already published — skipping"
else
echo " Publishing $crate@$VERSION..."
cargo publish -p "$crate" --allow-dirty
need_wait+=("$crate:$VERSION")
fi
done

for entry in "${need_wait[@]}"; do
wait_for "${entry%%:*}" "${entry##*:}"
done
echo "::endgroup::"
}

publish_tier "1 (no internal deps)" $TIER1
publish_tier "2 (depends on tier 1)" $TIER2
publish_tier "3 (depends on tier 2)" $TIER3
publish_tier "4 (CLI binary)" $TIER4

# ── Build CLI binaries ───────────────────────────────────────────────────────
build-cli:
name: Build CLI (${{ matrix.label }})
needs: [validate-version, ci]
runs-on: ${{ matrix.runs-on }}
strategy:
fail-fast: false
matrix:
include:
- runs-on: ubuntu-latest
target: x86_64-unknown-linux-gnu
label: linux-x64
- runs-on: ubuntu-24.04-arm
target: aarch64-unknown-linux-gnu
label: linux-arm64
- runs-on: macos-latest
target: aarch64-apple-darwin
label: macos-arm64
- runs-on: macos-15-large
target: x86_64-apple-darwin
label: macos-x64
- runs-on: windows-latest
target: x86_64-pc-windows-msvc
label: windows-x64
steps:
- uses: actions/checkout@v6

- name: Install Rust
uses: dtolnay/rust-toolchain@stable
with:
targets: ${{ matrix.target }}

- uses: Swatinem/rust-cache@v2
with:
prefix-key: release-${{ matrix.target }}

- name: Set version from tag
shell: bash
run: |
VERSION="${{ needs.validate-version.outputs.version }}"
CURRENT=$(cargo metadata --no-deps --format-version=1 \
| jq -r '.packages[] | select(.name == "venus") | .version')
if [[ "$VERSION" != "$CURRENT" ]]; then
perl -i -pe "if (!\$done && /^version = \"/) { s/^version = \".*\"/version = \"$VERSION\"/; \$done=1 }" Cargo.toml

# For pre-release versions, pin internal dep requirements so semver
# "0.1.0" doesn't fail to match "0.1.0-beta.1"
if [[ "$VERSION" == *-* ]]; then
perl -i -pe 's/(venus(?:-(macros|core|sync|server))? = \{ [^}]*version = )"[^"]*"/\1"='"$VERSION"'"/' Cargo.toml
echo "Updated internal dep versions to =$VERSION"
fi

echo "Updated workspace version: $CURRENT -> $VERSION"
fi

- name: Build release binary
run: cargo build -p venus --release --target ${{ matrix.target }}

- name: Package (unix)
if: runner.os != 'Windows'
run: |
cd target/${{ matrix.target }}/release
chmod +x venus
tar czf venus-${{ needs.validate-version.outputs.version }}-${{ matrix.label }}.tar.gz venus
ls -lh venus-*.tar.gz

- name: Package (windows)
if: runner.os == 'Windows'
shell: pwsh
run: |
cd target/${{ matrix.target }}/release
Compress-Archive -Path venus.exe -DestinationPath venus-${{ needs.validate-version.outputs.version }}-${{ matrix.label }}.zip

- uses: actions/upload-artifact@v7
with:
name: cli-${{ matrix.label }}
path: |
target/${{ matrix.target }}/release/venus-*.tar.gz
target/${{ matrix.target }}/release/venus-*.zip
retention-days: 1

# ── Create GitHub Release ─────────────────────────────────────────────────────
github-release:
name: Create GitHub Release
needs: [validate-version, publish-crates, build-cli]
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- uses: actions/checkout@v6

- name: Download binary artifacts
uses: actions/download-artifact@v8
with:
path: ./artifacts
pattern: "cli-*"
merge-multiple: true

- name: Create GitHub Release
uses: softprops/action-gh-release@v3
with:
tag_name: v${{ needs.validate-version.outputs.version }}
name: Venus ${{ needs.validate-version.outputs.version }}
generate_release_notes: true
draft: false
prerelease: ${{ contains(needs.validate-version.outputs.version, '-') }}
files: artifacts/*
fail_on_unmatched_files: true
51 changes: 51 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
# Reusable test workflow: fmt, clippy, and full test suite across platforms.

name: Test

on:
workflow_call:

permissions:
contents: read

env:
CARGO_TERM_COLOR: always

jobs:
lint:
name: Lint & Check
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- name: Install Rust
uses: dtolnay/rust-toolchain@stable
with:
components: rustfmt, clippy
- uses: Swatinem/rust-cache@v2
with:
prefix-key: lint
- name: Check formatting
run: cargo fmt --all -- --check
- name: Run clippy
run: cargo clippy --workspace --all-targets -- -D warnings

test:
name: Test (${{ matrix.os }})
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, macos-latest, windows-latest]
steps:
- uses: actions/checkout@v6
- name: Install Rust (stable)
uses: dtolnay/rust-toolchain@stable
- name: Install Rust (nightly + cranelift)
uses: dtolnay/rust-toolchain@nightly
with:
components: rustc-codegen-cranelift-preview
- uses: Swatinem/rust-cache@v2
with:
prefix-key: test-${{ matrix.os }}
- name: Run tests
run: cargo +stable test --workspace
10 changes: 5 additions & 5 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading