Skip to content

Merge pull request #103 from TrueNine/dev #93

Merge pull request #103 from TrueNine/dev

Merge pull request #103 from TrueNine/dev #93

Workflow file for this run

name: Release Packages
env:
NODE_VERSION: '25'
NPM_REGISTRY_URL: https://registry.npmjs.org/
NPM_PUBLISH_VERIFY_ATTEMPTS: '90'
NPM_PUBLISH_VERIFY_DELAY_SECONDS: '10'
CLI_NATIVE_MODULE_DIRS: |
libraries/logger
libraries/md-compiler
libraries/script-runtime
cli
CLI_NATIVE_BINDING_PREFIXES: |
napi-logger.
napi-md-compiler.
napi-script-runtime.
napi-memory-sync-cli.
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: false
on:
push:
branches:
- main
paths:
- .github/actions/**
- .github/workflows/build-gui-all.yml
- .github/workflows/release-*.yml
- assets/**
- cli/**
- mcp/**
- gui/**
- libraries/**
- scripts/**
- Cargo.toml
- Cargo.lock
- package.json
- pnpm-lock.yaml
- pnpm-workspace.yaml
- turbo.json
workflow_dispatch:
permissions:
contents: read
jobs:
# 1. 版本检查(快速,决定是否继续)
check-version:
runs-on: ubuntu-24.04
timeout-minutes: 10
outputs:
publish_cli: ${{ steps.check.outputs.publish_cli }}
publish_mcp: ${{ steps.check.outputs.publish_mcp }}
publish_npm: ${{ steps.check.outputs.publish_npm }}
version: ${{ steps.check.outputs.version }}
steps:
- uses: actions/checkout@v6
- uses: actions/setup-node@v6
with:
node-version: ${{ env.NODE_VERSION }}
- name: Check if should publish
id: check
run: |
check_publish_state() {
local package_json_path="$1"
local output_key="$2"
local version
local name
local published_version
version=$(jq -r '.version' "$package_json_path")
name=$(jq -r '.name' "$package_json_path")
published_version=$(npm view "${name}@${version}" version --registry "$NPM_REGISTRY_URL" 2>/dev/null || echo "")
if [[ "$version" != "$published_version" ]]; then
echo "$name@$version is not published to npm, will publish"
echo "${output_key}=true" >> "$GITHUB_OUTPUT"
return 0
fi
echo "$name@$version already published to npm, skipping"
echo "${output_key}=false" >> "$GITHUB_OUTPUT"
return 1
}
version=$(jq -r '.version' package.json)
echo "version=$version" >> "$GITHUB_OUTPUT"
cli_needs_publish=false
mcp_needs_publish=false
if check_publish_state cli/package.json publish_cli; then
cli_needs_publish=true
fi
if check_publish_state mcp/package.json publish_mcp; then
mcp_needs_publish=true
fi
if [[ "$cli_needs_publish" == "true" || "$mcp_needs_publish" == "true" ]]; then
echo "publish_npm=true" >> "$GITHUB_OUTPUT"
else
echo "publish_npm=false" >> "$GITHUB_OUTPUT"
fi
# 1.5. GUI 版本检查(独立于 npm,检查 GitHub Release)
check-gui-version:
runs-on: ubuntu-24.04
timeout-minutes: 10
outputs:
should_release: ${{ steps.check.outputs.should_release }}
version: ${{ steps.check.outputs.version }}
steps:
- uses: actions/checkout@v6
- 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_cli == 'true'
timeout-minutes: 45
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@v6
- 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: |
while IFS= read -r module_dir; do
if [ -z "$module_dir" ]; then
continue
fi
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 <<< "$CLI_NATIVE_MODULE_DIRS"
- 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
while IFS= read -r module_dir; do
if [ -z "$module_dir" ]; then
continue
fi
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 <<< "$CLI_NATIVE_MODULE_DIRS"
expected_count=0
while IFS= read -r binding_prefix; do
if [ -z "$binding_prefix" ]; then
continue
fi
expected_count=$((expected_count + 1))
matches=("$target_dir"/${binding_prefix}*.node)
if [ "${#matches[@]}" -eq 0 ]; then
echo "ERROR: missing binding with prefix ${binding_prefix} in ${target_dir}"
exit 1
fi
done <<< "$CLI_NATIVE_BINDING_PREFIXES"
actual_count=$(find "$target_dir" -maxdepth 1 -type f -name '*.node' | wc -l | tr -d ' ')
if [ "$actual_count" -ne "$expected_count" ]; then
echo "ERROR: expected ${expected_count} .node files in ${target_dir}, found ${actual_count}"
exit 1
fi
echo "Contents of $target_dir:"
ls -la "$target_dir/"
- name: Upload CLI platform package
uses: actions/upload-artifact@v7
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_cli == 'true'
runs-on: ubuntu-24.04
timeout-minutes: 45
steps:
- uses: actions/checkout@v6
- uses: ./.github/actions/setup-node-pnpm
with:
install: 'false'
- name: Setup npm registry
uses: actions/setup-node@v6
with:
node-version: ${{ env.NODE_VERSION }}
registry-url: https://registry.npmjs.org/
- name: Preflight npm auth
shell: bash
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
run: |
set -euo pipefail
if [[ -z "${NODE_AUTH_TOKEN:-}" ]]; then
echo "::error::NPM_TOKEN is missing. Configure a publish-capable npm token for @truenine/* before rerunning release."
exit 1
fi
pushd cli >/dev/null
npm config set //registry.npmjs.org/:_authToken "${NODE_AUTH_TOKEN}"
npm_user=$(npm whoami --registry "$NPM_REGISTRY_URL")
access_json=$(npm access list packages @truenine --json 2>/dev/null || true)
popd >/dev/null
echo "Authenticated to npm as ${npm_user}"
if [[ -z "${access_json}" || "${access_json}" == "{}" || "${access_json}" == "null" ]]; then
echo "::error::Authenticated as ${npm_user}, but npm did not report package access for @truenine. Replace NPM_TOKEN with a token that has publish permission for existing @truenine/* packages."
exit 1
fi
if ! jq -e . >/dev/null 2>&1 <<<"$access_json"; then
echo "::warning::npm access list packages returned non-JSON output for ${npm_user}. Falling back to publish-time authorization checks."
exit 0
fi
for package_json in cli/npm/*/package.json; do
package_name=$(jq -r '.name' "$package_json")
package_access=$(jq -r --arg package_name "$package_name" '.[$package_name] // empty' <<<"$access_json")
if [[ "$package_access" != "read-write" ]]; then
echo "::error::NPM_TOKEN authenticated as ${npm_user}, but ${package_name} access is '${package_access:-missing}'. Expected read-write."
exit 1
fi
done
- name: Download all platform artifacts
uses: actions/download-artifact@v8
with:
path: artifacts
pattern: cli-napi-*
- name: Distribute artifacts to cli/npm/ directories
shell: bash
run: |
shopt -s nullglob
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: Validate CLI platform packages
shell: bash
run: |
shopt -s nullglob
expected_count=0
while IFS= read -r binding_prefix; do
if [ -z "$binding_prefix" ]; then
continue
fi
expected_count=$((expected_count + 1))
done <<< "$CLI_NATIVE_BINDING_PREFIXES"
for target_dir in cli/npm/*/; do
if [ ! -f "${target_dir}package.json" ]; then
continue
fi
if [ ! -f "${target_dir}noop.cjs" ]; then
echo "ERROR: missing ${target_dir}noop.cjs"
exit 1
fi
if [ ! -f "${target_dir}noop.d.ts" ]; then
echo "ERROR: missing ${target_dir}noop.d.ts"
exit 1
fi
actual_count=$(find "${target_dir}" -maxdepth 1 -type f -name '*.node' | wc -l | tr -d ' ')
if [ "$actual_count" -ne "$expected_count" ]; then
echo "ERROR: expected ${expected_count} .node files in ${target_dir}, found ${actual_count}"
exit 1
fi
while IFS= read -r binding_prefix; do
if [ -z "$binding_prefix" ]; then
continue
fi
matches=("${target_dir}"${binding_prefix}*.node)
if [ "${#matches[@]}" -eq 0 ]; then
echo "ERROR: missing binding with prefix ${binding_prefix} in ${target_dir}"
exit 1
fi
done <<< "$CLI_NATIVE_BINDING_PREFIXES"
done
- name: Publish CLI platform sub-packages
shell: bash
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
run: |
set -euo pipefail
registry_version_exists() {
local package_name="$1"
local package_version="$2"
local encoded_package_name
local version_json
local published_version
encoded_package_name=$(node -e 'process.stdout.write(encodeURIComponent(process.argv[1]))' "$package_name")
version_json=$(curl --silent --show-error --fail "${NPM_REGISTRY_URL%/}/${encoded_package_name}/${package_version}" 2>/dev/null || true)
if [[ -z "$version_json" ]]; then
return 1
fi
published_version=$(jq -r '.version // empty' <<<"$version_json")
[[ "$published_version" == "$package_version" ]]
}
version_exists() {
local package_name="$1"
local package_version="$2"
local published_version
published_version=$(npm view "${package_name}@${package_version}" version --registry "$NPM_REGISTRY_URL" 2>/dev/null || true)
if [[ "$published_version" == "$package_version" ]]; then
return 0
fi
registry_version_exists "$package_name" "$package_version"
}
verify_version_exists() {
local package_name="$1"
local package_version="$2"
local attempts="${NPM_PUBLISH_VERIFY_ATTEMPTS}"
local delay_seconds="${NPM_PUBLISH_VERIFY_DELAY_SECONDS}"
for attempt in $(seq 1 "$attempts"); do
if version_exists "$package_name" "$package_version"; then
echo "Verified ${package_name}@${package_version} on npm"
return 0
fi
if [[ "$attempt" -eq "$attempts" ]]; then
break
fi
echo "Waiting for ${package_name}@${package_version} to appear on npm (${attempt}/${attempts})..."
sleep "$delay_seconds"
done
echo "::error::${package_name}@${package_version} is still missing from npm after publish."
return 1
}
publish_package() {
local package_dir="$1"
local package_name
local package_version
local publish_log
package_name=$(jq -r '.name' "${package_dir}package.json")
package_version=$(jq -r '.version' "${package_dir}package.json")
if version_exists "$package_name" "$package_version"; then
echo "${package_name}@${package_version} already exists on npm, skipping"
return 0
fi
publish_log=$(mktemp)
if (cd "$package_dir" && pnpm publish --access public --no-git-checks) 2>&1 | tee "$publish_log"; then
verify_version_exists "$package_name" "$package_version"
rm -f "$publish_log"
return 0
fi
if grep -Eiq 'cannot publish over the previously published versions|previously published versions' "$publish_log"; then
echo "${package_name}@${package_version} was already published according to npm, skipping"
rm -f "$publish_log"
return 0
fi
if version_exists "$package_name" "$package_version"; then
echo "${package_name}@${package_version} already exists on npm after publish attempt, skipping"
rm -f "$publish_log"
return 0
fi
echo "::error::Failed to publish ${package_name}@${package_version}. Exact version is still missing from npm."
rm -f "$publish_log"
return 1
}
for dir in cli/npm/*/; do
if [ -f "${dir}package.json" ]; then
publish_package "$dir"
fi
done
# 4. 架构包就绪后,发布主包到 npm
publish-cli:
needs: [check-version, publish-napi]
if: needs.check-version.outputs.publish_cli == 'true'
runs-on: ubuntu-24.04
timeout-minutes: 30
steps:
- uses: actions/checkout@v6
- uses: ./.github/actions/setup-node-pnpm
- name: Setup npm registry
uses: actions/setup-node@v6
with:
node-version: ${{ env.NODE_VERSION }}
registry-url: https://registry.npmjs.org/
- name: Preflight npm auth
shell: bash
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
run: |
set -euo pipefail
if [[ -z "${NODE_AUTH_TOKEN:-}" ]]; then
echo "::error::NPM_TOKEN is missing. Configure a publish-capable npm token for @truenine/memory-sync-cli before rerunning release."
exit 1
fi
pushd cli >/dev/null
npm config set //registry.npmjs.org/:_authToken "${NODE_AUTH_TOKEN}"
npm_user=$(npm whoami --registry "$NPM_REGISTRY_URL")
package_name=$(jq -r '.name' package.json)
popd >/dev/null
echo "Authenticated to npm as ${npm_user}"
echo "Deferring publish permission enforcement for ${package_name} to the publish step because npm access output is not stable in this workflow."
- name: Build
run: pnpm -F @truenine/memory-sync-cli run build
- name: Publish to npm
shell: bash
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
run: |
set -euo pipefail
package_name=$(jq -r '.name' cli/package.json)
package_version=$(jq -r '.version' cli/package.json)
registry_version_exists() {
local encoded_package_name
local version_json
local published_version
encoded_package_name=$(node -e 'process.stdout.write(encodeURIComponent(process.argv[1]))' "$package_name")
version_json=$(curl --silent --show-error --fail "${NPM_REGISTRY_URL%/}/${encoded_package_name}/${package_version}" 2>/dev/null || true)
if [[ -z "$version_json" ]]; then
return 1
fi
published_version=$(jq -r '.version // empty' <<<"$version_json")
[[ "$published_version" == "$package_version" ]]
}
version_exists() {
local published_version
published_version=$(npm view "${package_name}@${package_version}" version --registry "$NPM_REGISTRY_URL" 2>/dev/null || true)
if [[ "$published_version" == "$package_version" ]]; then
return 0
fi
registry_version_exists
}
verify_version_exists() {
local attempts="${NPM_PUBLISH_VERIFY_ATTEMPTS}"
local delay_seconds="${NPM_PUBLISH_VERIFY_DELAY_SECONDS}"
for attempt in $(seq 1 "$attempts"); do
if version_exists; then
echo "Verified ${package_name}@${package_version} on npm"
return 0
fi
if [[ "$attempt" -eq "$attempts" ]]; then
break
fi
echo "Waiting for ${package_name}@${package_version} to appear on npm (${attempt}/${attempts})..."
sleep "$delay_seconds"
done
echo "::error::${package_name}@${package_version} is still missing from npm after publish."
return 1
}
if version_exists; then
echo "${package_name}@${package_version} already exists on npm, skipping"
exit 0
fi
publish_log=$(mktemp)
if (cd cli && pnpm publish --access public --no-git-checks) 2>&1 | tee "$publish_log"; then
verify_version_exists
rm -f "$publish_log"
exit 0
fi
if grep -Eiq 'cannot publish over the previously published versions|previously published versions' "$publish_log"; then
echo "${package_name}@${package_version} was already published according to npm, skipping"
rm -f "$publish_log"
exit 0
fi
if version_exists; then
echo "${package_name}@${package_version} already exists on npm after publish attempt, skipping"
rm -f "$publish_log"
exit 0
fi
echo "::error::Failed to publish ${package_name}@${package_version}. Exact version is still missing from npm."
rm -f "$publish_log"
exit 1
# 4.5. CLI 可用后,发布 MCP 包到 npm
publish-mcp:
needs: [check-version, publish-cli]
if: |
needs.check-version.outputs.publish_mcp == 'true' &&
(needs.publish-cli.result == 'success' || needs.publish-cli.result == 'skipped')
runs-on: ubuntu-24.04
timeout-minutes: 30
steps:
- uses: actions/checkout@v6
- uses: ./.github/actions/setup-node-pnpm
- name: Setup npm registry
uses: actions/setup-node@v6
with:
node-version: ${{ env.NODE_VERSION }}
registry-url: https://registry.npmjs.org/
- name: Preflight npm auth
shell: bash
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
run: |
set -euo pipefail
if [[ -z "${NODE_AUTH_TOKEN:-}" ]]; then
echo "::error::NPM_TOKEN is missing. Configure a publish-capable npm token for @truenine/memory-sync-mcp before rerunning release."
exit 1
fi
pushd mcp >/dev/null
npm config set //registry.npmjs.org/:_authToken "${NODE_AUTH_TOKEN}"
npm_user=$(npm whoami --registry "$NPM_REGISTRY_URL")
package_name=$(jq -r '.name' package.json)
popd >/dev/null
echo "Authenticated to npm as ${npm_user}"
echo "Deferring publish permission enforcement for ${package_name} to the publish step because npm access output is not stable in this workflow."
- name: Build
run: pnpm exec turbo run build --filter=@truenine/memory-sync-mcp
- name: Publish to npm
shell: bash
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
run: |
set -euo pipefail
package_name=$(jq -r '.name' mcp/package.json)
package_version=$(jq -r '.version' mcp/package.json)
registry_version_exists() {
local encoded_package_name
local version_json
local published_version
encoded_package_name=$(node -e 'process.stdout.write(encodeURIComponent(process.argv[1]))' "$package_name")
version_json=$(curl --silent --show-error --fail "${NPM_REGISTRY_URL%/}/${encoded_package_name}/${package_version}" 2>/dev/null || true)
if [[ -z "$version_json" ]]; then
return 1
fi
published_version=$(jq -r '.version // empty' <<<"$version_json")
[[ "$published_version" == "$package_version" ]]
}
version_exists() {
local published_version
published_version=$(npm view "${package_name}@${package_version}" version --registry "$NPM_REGISTRY_URL" 2>/dev/null || true)
if [[ "$published_version" == "$package_version" ]]; then
return 0
fi
registry_version_exists
}
verify_version_exists() {
local attempts="${NPM_PUBLISH_VERIFY_ATTEMPTS}"
local delay_seconds="${NPM_PUBLISH_VERIFY_DELAY_SECONDS}"
for attempt in $(seq 1 "$attempts"); do
if version_exists; then
echo "Verified ${package_name}@${package_version} on npm"
return 0
fi
if [[ "$attempt" -eq "$attempts" ]]; then
break
fi
echo "Waiting for ${package_name}@${package_version} to appear on npm (${attempt}/${attempts})..."
sleep "$delay_seconds"
done
echo "::error::${package_name}@${package_version} is still missing from npm after publish."
return 1
}
if version_exists; then
echo "${package_name}@${package_version} already exists on npm, skipping"
exit 0
fi
publish_log=$(mktemp)
if (cd mcp && pnpm publish --access public --no-git-checks) 2>&1 | tee "$publish_log"; then
verify_version_exists
rm -f "$publish_log"
exit 0
fi
if grep -Eiq 'cannot publish over the previously published versions|previously published versions' "$publish_log"; then
echo "${package_name}@${package_version} was already published according to npm, skipping"
rm -f "$publish_log"
exit 0
fi
if version_exists; then
echo "${package_name}@${package_version} already exists on npm after publish attempt, skipping"
rm -f "$publish_log"
exit 0
fi
echo "::error::Failed to publish ${package_name}@${package_version}. Exact version is still missing from npm."
rm -f "$publish_log"
exit 1
# 5. 构建 CLI 独立二进制(仅 artifact,不发 Release)
build-binary:
needs: [check-version, check-gui-version, publish-napi]
if: |
(needs.check-version.outputs.publish_cli == 'true' || needs.check-gui-version.outputs.should_release == 'true') &&
(needs.publish-napi.result == 'success' || needs.publish-napi.result == 'skipped')
timeout-minutes: 60
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@v6
- 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@v7
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, build-binary]
if: needs.check-gui-version.outputs.should_release == 'true'
permissions:
contents: write
uses: ./.github/workflows/release-gui-collect.yml
with:
version: ${{ needs.check-gui-version.outputs.version }}
secrets: inherit