Merge pull request #58 from TrueNine/dev #49
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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 |