name: Release
on:
push:
tags:
- 'v*'
permissions:
contents: write
jobs:
create-release:
name: Create Release
runs-on: ubuntu-latest
outputs:
upload_url: ${{ steps.create_release.outputs.upload_url }}
version: ${{ steps.get_version.outputs.version }}
steps:
- name: Get version from tag
id: get_version
run: echo "version=${GITHUB_REF#refs/tags/v}" >> $GITHUB_OUTPUT
- name: Create Release
id: create_release
uses: actions/create-release@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
tag_name: ${{ github.ref }}
release_name: Release ${{ github.ref }}
draft: false
prerelease: false
build:
name: Build for ${{ matrix.os }} (${{ matrix.target }})
needs: create-release
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
include:
- os: windows-latest
target: x86_64-pc-windows-msvc
artifact_name: hbsx.exe
asset_name: hbsx-windows-x86_64.exe
- os: windows-latest
target: aarch64-pc-windows-msvc
artifact_name: hbsx.exe
asset_name: hbsx-windows-aarch64.exe
- os: ubuntu-latest
target: x86_64-unknown-linux-gnu
artifact_name: hbsx
asset_name: hbsx-linux-x86_64
- os: ubuntu-24.04-arm
target: aarch64-unknown-linux-gnu
artifact_name: hbsx
asset_name: hbsx-linux-aarch64
- os: ubuntu-latest
target: x86_64-unknown-linux-musl
artifact_name: hbsx
asset_name: hbsx-linux-x86_64-musl
- os: macos-latest
target: x86_64-apple-darwin
artifact_name: hbsx
asset_name: hbsx-macos-x86_64
- os: macos-latest
target: aarch64-apple-darwin
artifact_name: hbsx
asset_name: hbsx-macos-aarch64
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Update Cargo.toml version
shell: python
run: |
import re
version = "${{ needs.create-release.outputs.version }}"
print(f"Updating Cargo.toml to version {version}")
with open('Cargo.toml', 'r', encoding='utf-8') as f:
content = f.read()
# 更新 version 字段(在 [package] 部分)
content = re.sub(
r'^version\s*=\s*"[^"]*"',
f'version = "{version}"',
content,
count=1,
flags=re.MULTILINE
)
with open('Cargo.toml', 'w', encoding='utf-8') as f:
f.write(content)
# 验证更新
with open('Cargo.toml', 'r', encoding='utf-8') as f:
for line in f:
if line.startswith('version ='):
print(f"Updated: {line.strip()}")
break
- name: Install Rust
uses: dtolnay/rust-toolchain@stable
with:
targets: ${{ matrix.target }}
- name: Install musl tools (Linux musl)
if: matrix.target == 'x86_64-unknown-linux-musl'
run: |
sudo apt-get update
sudo apt-get install -y musl-tools
- name: Cache cargo registry
uses: actions/cache@v4
with:
path: ~/.cargo/registry
key: ${{ runner.os }}-cargo-registry-${{ hashFiles('**/Cargo.lock') }}
- name: Cache cargo index
uses: actions/cache@v4
with:
path: ~/.cargo/git
key: ${{ runner.os }}-cargo-git-${{ hashFiles('**/Cargo.lock') }}
- name: Cache target directory
uses: actions/cache@v4
with:
path: target
key: ${{ runner.os }}-${{ matrix.target }}-cargo-target-${{ hashFiles('**/Cargo.lock') }}
- name: Show build environment
run: |
echo "Target: ${{ matrix.target }}"
echo "OS: ${{ matrix.os }}"
echo "Architecture: $(uname -m)"
echo "Rust version:"
rustc --version
cargo --version
- name: Build
run: cargo build --release --target ${{ matrix.target }} --verbose
- name: Strip binary (Linux and macOS)
if: matrix.os != 'windows-latest'
run: strip target/${{ matrix.target }}/release/${{ matrix.artifact_name }}
- name: Compress binary (Linux and macOS)
if: matrix.os != 'windows-latest'
run: |
cd target/${{ matrix.target }}/release
tar czf ${{ matrix.asset_name }}.tar.gz ${{ matrix.artifact_name }}
mv ${{ matrix.asset_name }}.tar.gz ../../../
- name: Compress binary (Windows)
if: matrix.os == 'windows-latest'
shell: pwsh
run: |
cd target/${{ matrix.target }}/release
Compress-Archive -Path ${{ matrix.artifact_name }} -DestinationPath ../../../${{ matrix.asset_name }}.zip
- name: Upload Release Asset (Linux and macOS)
if: matrix.os != 'windows-latest'
uses: actions/upload-release-asset@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
upload_url: ${{ needs.create-release.outputs.upload_url }}
asset_path: ./${{ matrix.asset_name }}.tar.gz
asset_name: ${{ matrix.asset_name }}.tar.gz
asset_content_type: application/gzip
- name: Upload Release Asset (Windows)
if: matrix.os == 'windows-latest'
uses: actions/upload-release-asset@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
upload_url: ${{ needs.create-release.outputs.upload_url }}
asset_path: ./${{ matrix.asset_name }}.zip
asset_name: ${{ matrix.asset_name }}.zip
asset_content_type: application/zip
- name: Generate SHA256 checksums (Linux and macOS)
if: matrix.os != 'windows-latest'
run: |
sha256sum ${{ matrix.asset_name }}.tar.gz > ${{ matrix.asset_name }}.tar.gz.sha256
- name: Generate SHA256 checksums (Windows)
if: matrix.os == 'windows-latest'
shell: pwsh
run: |
$hash = (Get-FileHash -Path ${{ matrix.asset_name }}.zip -Algorithm SHA256).Hash.ToLower()
"$hash ${{ matrix.asset_name }}.zip" | Out-File -FilePath ${{ matrix.asset_name }}.zip.sha256 -Encoding utf8 -NoNewline
- name: Upload SHA256 checksum (Linux and macOS)
if: matrix.os != 'windows-latest'
uses: actions/upload-release-asset@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
upload_url: ${{ needs.create-release.outputs.upload_url }}
asset_path: ./${{ matrix.asset_name }}.tar.gz.sha256
asset_name: ${{ matrix.asset_name }}.tar.gz.sha256
asset_content_type: text/plain
- name: Upload SHA256 checksum (Windows)
if: matrix.os == 'windows-latest'
uses: actions/upload-release-asset@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
upload_url: ${{ needs.create-release.outputs.upload_url }}
asset_path: ./${{ matrix.asset_name }}.zip.sha256
asset_name: ${{ matrix.asset_name }}.zip.sha256
asset_content_type: text/plain
- name: Upload artifact for npm publishing
uses: actions/upload-artifact@v4
with:
name: binary-${{ matrix.target }}
path: target/${{ matrix.target }}/release/${{ matrix.artifact_name }}
retention-days: 1
publish-npm:
name: Publish to npm
needs: [create-release, build]
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
registry-url: 'https://registry.npmjs.org'
- name: Download all artifacts
uses: actions/download-artifact@v4
with:
path: artifacts
- name: List downloaded artifacts
run: |
echo "Downloaded artifacts:"
ls -R artifacts/
- name: Copy binaries to platform packages
run: |
# 创建 bin 目录
mkdir -p package/npm/platform-packages/win32-x64/bin
mkdir -p package/npm/platform-packages/win32-arm64/bin
mkdir -p package/npm/platform-packages/linux-x64/bin
mkdir -p package/npm/platform-packages/linux-arm64/bin
mkdir -p package/npm/platform-packages/darwin-x64/bin
mkdir -p package/npm/platform-packages/darwin-arm64/bin
# 复制 Windows 二进制
cp artifacts/binary-x86_64-pc-windows-msvc/hbsx.exe package/npm/platform-packages/win32-x64/bin/
cp artifacts/binary-aarch64-pc-windows-msvc/hbsx.exe package/npm/platform-packages/win32-arm64/bin/
# 复制 Linux 二进制 (使用 musl 版本作为主要版本)
cp artifacts/binary-x86_64-unknown-linux-musl/hbsx package/npm/platform-packages/linux-x64/bin/
cp artifacts/binary-aarch64-unknown-linux-gnu/hbsx package/npm/platform-packages/linux-arm64/bin/
# 复制 macOS 二进制
cp artifacts/binary-x86_64-apple-darwin/hbsx package/npm/platform-packages/darwin-x64/bin/
cp artifacts/binary-aarch64-apple-darwin/hbsx package/npm/platform-packages/darwin-arm64/bin/
# 设置执行权限
chmod +x package/npm/platform-packages/*/bin/hbsx
- name: Update package versions
run: |
VERSION="${{ needs.create-release.outputs.version }}"
echo "Updating packages to version $VERSION"
# 使用 Node.js 脚本直接修改 JSON 文件,避免 npm version 的问题
cd package/npm
# 更新主包版本
node -e "
const fs = require('fs');
const pkg = JSON.parse(fs.readFileSync('package.json', 'utf8'));
const version = process.env.VERSION;
pkg.version = version;
for (const dep in pkg.optionalDependencies) {
pkg.optionalDependencies[dep] = version;
}
fs.writeFileSync('package.json', JSON.stringify(pkg, null, 2) + '\n');
console.log('✓ Main package updated to', version);
" VERSION="$VERSION"
# 更新平台包版本
for platform in win32-x64 win32-arm64 linux-x64 linux-arm64 darwin-x64 darwin-arm64; do
node -e "
const fs = require('fs');
const pkg = JSON.parse(fs.readFileSync('platform-packages/$platform/package.json', 'utf8'));
pkg.version = process.env.VERSION;
fs.writeFileSync('platform-packages/$platform/package.json', JSON.stringify(pkg, null, 2) + '\n');
console.log('✓ Platform package $platform updated to', process.env.VERSION);
" VERSION="$VERSION" platform="$platform"
done
echo "✓ All package versions updated to $VERSION"
- name: Setup npm authentication
run: |
echo "//registry.npmjs.org/:_authToken=${{ secrets.NPM_TOKEN }}" > ~/.npmrc
echo "registry=https://registry.npmjs.org/" >> ~/.npmrc
echo "always-auth=true" >> ~/.npmrc
- name: Publish platform packages
run: |
cd package/npm
# 发布平台包
for platform in win32-x64 win32-arm64 linux-x64 linux-arm64 darwin-x64 darwin-arm64; do
echo "Publishing @jihuayu/hbsx-$platform..."
cd platform-packages/$platform
npm publish --access public
cd ../..
done
- name: Publish main package
run: |
cd package/npm
echo "Publishing @jihuayu/hbsx..."
npm publish --access public
- name: Summary
run: |
echo "✓ All npm packages published successfully!"
echo "Version: ${{ needs.create-release.outputs.version }}"
echo ""
echo "Install with:"
echo " npm install -g @jihuayu/hbsx@${{ needs.create-release.outputs.version }}"
publish-crates:
name: Publish to crates.io
needs: [create-release, build]
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Install Rust
uses: dtolnay/rust-toolchain@stable
- name: Update Cargo.toml version
shell: python
run: |
import re
version = "${{ needs.create-release.outputs.version }}"
print(f"Updating Cargo.toml to version {version}")
with open('Cargo.toml', 'r', encoding='utf-8') as f:
content = f.read()
# 更新 version 字段
content = re.sub(
r'^version\s*=\s*"[^"]*"',
f'version = "{version}"',
content,
count=1,
flags=re.MULTILINE
)
with open('Cargo.toml', 'w', encoding='utf-8') as f:
f.write(content)
print(f"✓ Cargo.toml updated to version {version}")
- name: Verify package
run: cargo package --allow-dirty
- name: Publish to crates.io
env:
CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }}
run: |
echo "Publishing hbsx to crates.io..."
cargo publish --allow-dirty --token "$CARGO_REGISTRY_TOKEN"
echo "✓ Published to crates.io"
- name: Summary
run: |
echo "✓ Package published to crates.io successfully!"
echo "Version: ${{ needs.create-release.outputs.version }}"
echo ""
echo "Install with:"
echo " cargo install hbsx"