Skip to content

Merge pull request #58 from TrueNine/dev #49

Merge pull request #58 from TrueNine/dev

Merge pull request #58 from TrueNine/dev #49

Workflow file for this run

name: Release CLI
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: false
on:
push:
branches:
- main
workflow_dispatch:
permissions:
contents: write
jobs:
# 1. 版本检查(快速,决定是否继续)
check-version:
runs-on: ubuntu-24.04
outputs:
publish: ${{ steps.check.outputs.publish }}
version: ${{ steps.check.outputs.version }}
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 25
- name: Check if should publish
id: check
run: |
version=$(jq -r '.version' cli/package.json)
name=$(jq -r '.name' cli/package.json)
npm_version=$(npm view "$name" version --registry https://registry.npmjs.org/ 2>/dev/null || echo "")
if [[ "$version" != "$npm_version" ]]; then
echo "Version $version not published to npm, will publish"
echo "publish=true" >> "$GITHUB_OUTPUT"
echo "version=$version" >> "$GITHUB_OUTPUT"
else
echo "Version $version already published to npm, skipping"
echo "publish=false" >> "$GITHUB_OUTPUT"
fi
# 1.5. GUI 版本检查(独立于 npm,检查 GitHub Release)
check-gui-version:
runs-on: ubuntu-24.04
outputs:
should_release: ${{ steps.check.outputs.should_release }}
version: ${{ steps.check.outputs.version }}
steps:
- uses: actions/checkout@v4
- name: Check if GUI should be released
id: check
env:
GH_TOKEN: ${{ github.token }}
run: |
version=$(jq -r '.version' gui/package.json)
echo "GUI version: $version"
# Check if this version tag exists on GitHub
if gh release view "v${version}" >/dev/null 2>&1; then
echo "Release v${version} already exists on GitHub, skipping GUI"
echo "should_release=false" >> "$GITHUB_OUTPUT"
else
echo "Release v${version} does not exist, will build GUI"
echo "should_release=true" >> "$GITHUB_OUTPUT"
echo "version=$version" >> "$GITHUB_OUTPUT"
fi
# 2. 构建 NAPI 二进制(5 平台矩阵)
build-napi:
needs: check-version
if: needs.check-version.outputs.publish == 'true'
strategy:
fail-fast: false
matrix:
target:
- os: ubuntu-24.04
rust: x86_64-unknown-linux-gnu
suffix: linux-x64-gnu
- os: ubuntu-24.04
rust: aarch64-unknown-linux-gnu
suffix: linux-arm64-gnu
cross: true
- os: macos-14
rust: aarch64-apple-darwin
suffix: darwin-arm64
- os: macos-14
rust: x86_64-apple-darwin
suffix: darwin-x64
- os: windows-latest
rust: x86_64-pc-windows-msvc
suffix: win32-x64-msvc
runs-on: ${{ matrix.target.os }}
steps:
- uses: actions/checkout@v4
- uses: ./.github/actions/setup-node-pnpm
- uses: ./.github/actions/setup-rust
with:
targets: ${{ matrix.target.rust }}
cache-key: napi-${{ matrix.target.rust }}
- name: Install cross-compilation tools (aarch64-linux)
if: matrix.target.cross
run: |
sudo apt-get update
sudo apt-get install -y gcc-aarch64-linux-gnu g++-aarch64-linux-gnu
echo "CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_LINKER=aarch64-linux-gnu-gcc" >> $GITHUB_ENV
- name: Build all napi native modules
shell: bash
run: |
module_dirs=(libraries/logger libraries/md-compiler cli)
for module_dir in "${module_dirs[@]}"; do
echo "Building napi in ${module_dir}..."
(
cd "${module_dir}" && \
pnpm exec napi build --platform --release --target ${{ matrix.target.rust }} --output-dir dist -- --features napi
)
done
- name: Collect .node files into CLI platform package
shell: bash
run: |
target_dir="cli/npm/${{ matrix.target.suffix }}"
mkdir -p "$target_dir"
shopt -s nullglob
module_dirs=(libraries/logger libraries/md-compiler cli)
for module_dir in "${module_dirs[@]}"; do
node_files=("${module_dir}"/dist/*.node)
if [ "${#node_files[@]}" -eq 0 ]; then
echo "ERROR: no .node files found in ${module_dir}/dist"
exit 1
fi
cp "${node_files[@]}" "$target_dir/"
done
echo "Contents of $target_dir:"
ls -la "$target_dir/"
- name: Upload CLI platform package
uses: actions/upload-artifact@v4
with:
name: cli-napi-${{ matrix.target.suffix }}
path: cli/npm/${{ matrix.target.suffix }}/
if-no-files-found: error
# 3. 收集并发布 NAPI 平台子包到 npm
publish-napi:
needs: [check-version, build-napi]
if: needs.check-version.outputs.publish == 'true'
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v4
- uses: ./.github/actions/setup-node-pnpm
with:
install: 'false'
- name: Setup npm registry
uses: actions/setup-node@v4
with:
node-version: 25
registry-url: https://registry.npmjs.org/
- name: Download all platform artifacts
uses: actions/download-artifact@v4
with:
path: artifacts
pattern: cli-napi-*
- name: Distribute artifacts to cli/npm/ directories
shell: bash
run: |
for artifact_dir in artifacts/cli-napi-*/; do
suffix=$(basename "$artifact_dir" | sed 's/cli-napi-//')
target_dir="cli/npm/${suffix}"
mkdir -p "$target_dir"
echo "Copying from ${artifact_dir} to ${target_dir}"
cp "${artifact_dir}"*.node "$target_dir/" || { echo "ERROR: no .node files found in ${artifact_dir}"; exit 1; }
done
- name: Publish CLI platform sub-packages
shell: bash
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
run: |
for dir in cli/npm/*/; do
if [ -f "${dir}package.json" ]; then
echo "Publishing ${dir}..."
(cd "$dir" && pnpm publish --access public --no-git-checks) || echo "⚠️ Failed to publish ${dir}, may already exist"
fi
done
# 4. 架构包就绪后,发布主包到 npm
publish-cli:
needs: [check-version, publish-napi]
if: needs.check-version.outputs.publish == 'true'
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v4
with:
token: ${{ secrets.GH_PAT }}
- uses: ./.github/actions/setup-node-pnpm
- name: Setup npm registry
uses: actions/setup-node@v4
with:
node-version: 25
registry-url: https://registry.npmjs.org/
- name: Build
run: pnpm -F @truenine/memory-sync-cli run build
- name: Publish to npm
working-directory: ./cli
run: pnpm publish --access public --no-git-checks
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
# 5. 构建 CLI 独立二进制(仅 artifact,不发 Release)
build-binary:
needs: [check-version, publish-napi]
if: needs.check-version.outputs.publish == 'true'
strategy:
fail-fast: false
matrix:
include:
- platform: ubuntu-24.04
target: x86_64-unknown-linux-gnu
binary: tnmsc
archive: tnmsc-linux-x86_64.tar.gz
- platform: ubuntu-24.04
target: aarch64-unknown-linux-gnu
binary: tnmsc
archive: tnmsc-linux-aarch64.tar.gz
cross: true
- platform: macos-14
target: aarch64-apple-darwin
binary: tnmsc
archive: tnmsc-darwin-aarch64.tar.gz
- platform: macos-14
target: x86_64-apple-darwin
binary: tnmsc
archive: tnmsc-darwin-x86_64.tar.gz
- platform: windows-latest
target: x86_64-pc-windows-msvc
binary: tnmsc.exe
archive: tnmsc-windows-x86_64.zip
runs-on: ${{ matrix.platform }}
steps:
- uses: actions/checkout@v4
- uses: ./.github/actions/setup-node-pnpm
- name: Build plugin-runtime
shell: bash
run: |
pnpm -F @truenine/memory-sync-cli run build
ls -la cli/dist/plugin-runtime.mjs
- uses: ./.github/actions/setup-rust
with:
targets: ${{ matrix.target }}
cache-key: cli-${{ matrix.target }}
- name: Install cross-compilation tools (aarch64-linux)
if: matrix.cross
run: |
sudo apt-get update
sudo apt-get install -y gcc-aarch64-linux-gnu g++-aarch64-linux-gnu
echo "CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_LINKER=aarch64-linux-gnu-gcc" >> $GITHUB_ENV
- name: Build tnmsc binary (release, with embedded runtime)
run: cargo build --release --target ${{ matrix.target }} -p tnmsc --features embedded-runtime
- name: Run tests (native only)
if: ${{ !matrix.cross }}
run: cargo test --release --target ${{ matrix.target }} -p tnmsc --features embedded-runtime
- name: Package (unix)
if: runner.os != 'Windows'
shell: bash
run: |
mkdir -p staging
cp target/${{ matrix.target }}/release/${{ matrix.binary }} staging/
cp cli/dist/plugin-runtime.mjs staging/
cd staging
tar czf ../${{ matrix.archive }} *
- name: Package (windows)
if: runner.os == 'Windows'
shell: pwsh
run: |
New-Item -ItemType Directory -Force -Path staging
Copy-Item "target/${{ matrix.target }}/release/${{ matrix.binary }}" staging/
Copy-Item "cli/dist/plugin-runtime.mjs" staging/
Compress-Archive -Path staging/* -DestinationPath ${{ matrix.archive }}
- name: Upload artifact
uses: actions/upload-artifact@v4
with:
name: cli-${{ matrix.target }}
path: ${{ matrix.archive }}
if-no-files-found: error
# 6. 构建 GUI — 三平台并行(fail-fast: 任一失败则全部取消)
build-gui-all:
needs: [check-gui-version]
if: needs.check-gui-version.outputs.should_release == 'true'
uses: ./.github/workflows/build-gui-all.yml
with:
version: ${{ needs.check-gui-version.outputs.version }}
secrets: inherit
# 7. 收集三平台产物,创建 GitHub Release + tag
release-gui-collect:
needs: [check-gui-version, build-gui-all]
if: needs.check-gui-version.outputs.should_release == 'true'
uses: ./.github/workflows/release-gui-collect.yml
with:
version: ${{ needs.check-gui-version.outputs.version }}
secrets: inherit