name: build on: workflow_dispatch: inputs: version: description: "版本号(例如 1.2.3 或 v1.2.3)" required: true build: description: "构建命令标记(build:win|build:mac|build:linux|build:all)" required: true permissions: contents: write jobs: parse: runs-on: ubuntu-latest outputs: version: ${{ steps.parse.outputs.version }} tag: ${{ steps.parse.outputs.tag }} build_script: ${{ steps.parse.outputs.build_script }} run_win: ${{ steps.parse.outputs.run_win }} run_mac: ${{ steps.parse.outputs.run_mac }} run_linux: ${{ steps.parse.outputs.run_linux }} run_android: ${{ steps.parse.outputs.run_android }} steps: - uses: actions/checkout@v4 with: fetch-depth: 0 - name: 读取提交信息 id: msg shell: bash run: | { echo "message<<__EOF__" echo "${{ github.event.inputs.version }} ${{ github.event.inputs.build }}" echo "__EOF__" } >> "$GITHUB_OUTPUT" - uses: actions/setup-node@v4 with: node-version: 22 - name: 解析版本与构建命令 id: parse env: RELEASE_MESSAGE: ${{ steps.msg.outputs.message }} run: node scripts/ci/parse-commit.mjs build_win: needs: parse if: ${{ needs.parse.outputs.run_win == 'true' }} runs-on: windows-latest steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 with: node-version: 22 - uses: pnpm/action-setup@v4 with: version: 10 - name: 安装 Rust uses: dtolnay/rust-toolchain@stable with: targets: x86_64-pc-windows-msvc - name: 应用版本号 run: node scripts/ci/apply-version.mjs ${{ needs.parse.outputs.version }} - name: 设置 OAuth 环境变量 run: | echo "VITE_OAUTH_PLATFORM_ID=${{ secrets.OAUTH_PLATFORM_ID }}" >> $env:GITHUB_ENV echo "VITE_OAUTH_PLATFORM_SECRET=${{ secrets.OAUTH_PLATFORM_SECRET }}" >> $env:GITHUB_ENV echo "VITE_OAUTH_CALLBACK_URL=secscore://oauth/callback" >> $env:GITHUB_ENV shell: pwsh - name: 安装依赖 run: pnpm install --frozen-lockfile - name: 构建(Windows) run: pnpm tauri build --target x86_64-pc-windows-msvc - uses: actions/upload-artifact@v4 with: name: dist-win path: | src-tauri/target/x86_64-pc-windows-msvc/release/bundle/** src-tauri/target/release/bundle/** build_mac: needs: parse if: ${{ needs.parse.outputs.run_mac == 'true' }} runs-on: macos-latest steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 with: node-version: 22 - uses: pnpm/action-setup@v4 with: version: 10 - name: 安装 Rust uses: dtolnay/rust-toolchain@stable with: targets: x86_64-apple-darwin - name: 应用版本号 run: node scripts/ci/apply-version.mjs ${{ needs.parse.outputs.version }} - name: 设置 OAuth 环境变量 run: | echo "VITE_OAUTH_PLATFORM_ID=${{ secrets.OAUTH_PLATFORM_ID }}" >> $GITHUB_ENV echo "VITE_OAUTH_PLATFORM_SECRET=${{ secrets.OAUTH_PLATFORM_SECRET }}" >> $GITHUB_ENV echo "VITE_OAUTH_CALLBACK_URL=secscore://oauth/callback" >> $GITHUB_ENV - name: 安装依赖 run: pnpm install --frozen-lockfile - name: 构建(macOS) run: pnpm tauri build --target x86_64-apple-darwin - uses: actions/upload-artifact@v4 with: name: dist-mac path: | src-tauri/target/x86_64-apple-darwin/release/bundle/** src-tauri/target/aarch64-apple-darwin/release/bundle/** src-tauri/target/universal-apple-darwin/release/bundle/** src-tauri/target/release/bundle/** build_linux: needs: parse if: ${{ needs.parse.outputs.run_linux == 'true' }} runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 with: node-version: 22 - uses: pnpm/action-setup@v4 with: version: 10 - name: 安装 Rust uses: dtolnay/rust-toolchain@stable - name: 安装系统依赖 run: | sudo apt-get update sudo apt-get install -y libgtk-3-dev libwebkit2gtk-4.1-dev libappindicator3-dev librsvg2-dev patchelf - name: 应用版本号 run: node scripts/ci/apply-version.mjs ${{ needs.parse.outputs.version }} - name: 设置 OAuth 环境变量 run: | echo "VITE_OAUTH_PLATFORM_ID=${{ secrets.OAUTH_PLATFORM_ID }}" >> $GITHUB_ENV echo "VITE_OAUTH_PLATFORM_SECRET=${{ secrets.OAUTH_PLATFORM_SECRET }}" >> $GITHUB_ENV echo "VITE_OAUTH_CALLBACK_URL=secscore://oauth/callback" >> $GITHUB_ENV - name: 安装依赖 run: pnpm install --frozen-lockfile - name: 构建(Linux) run: pnpm tauri build --target x86_64-unknown-linux-gnu - uses: actions/upload-artifact@v4 with: name: dist-linux path: | src-tauri/target/x86_64-unknown-linux-gnu/release/bundle/** src-tauri/target/release/bundle/** build_android: needs: parse if: ${{ needs.parse.outputs.run_android == 'true' }} runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 with: node-version: 22 - uses: pnpm/action-setup@v4 with: version: 10 - name: 安装 Rust uses: dtolnay/rust-toolchain@stable with: targets: aarch64-linux-android, armv7-linux-androideabi, x86_64-linux-android, i686-linux-android - name: 安装 NDK uses: nttld/setup-ndk@v1 with: ndk-version: r25c - name: 安装 Java uses: actions/setup-java@v4 with: distribution: "temurin" java-version: "17" - name: 应用版本号 run: node scripts/ci/apply-version.mjs ${{ needs.parse.outputs.version }} - name: 安装依赖 run: pnpm install --frozen-lockfile - name: 初始化 Android 项目 run: pnpm tauri android init - name: 构建 Android Universal APK run: pnpm tauri android build --target aarch64 --target armv7 --target x86_64 - name: 签名 APK env: ANDROID_SIGNING_KEY: ${{ secrets.ANDROID_SIGNING_KEY }} ANDROID_KEY_ALIAS: ${{ secrets.ANDROID_KEY_ALIAS }} ANDROID_KEY_PASSWORD: ${{ secrets.ANDROID_KEY_PASSWORD }} ANDROID_STORE_PASSWORD: ${{ secrets.ANDROID_STORE_PASSWORD }} if: ${{ env.ANDROID_SIGNING_KEY != '' }} run: | # 找到 Android SDK 中的 apksigner APKSIGNER=$(find ${ANDROID_SDK_ROOT} -name "apksigner" -type f 2>/dev/null | head -1) if [ -z "$APKSIGNER" ]; then echo "错误: 未找到 apksigner" exit 1 fi echo "使用 apksigner: $APKSIGNER" # 创建临时密钥库文件 echo "$ANDROID_SIGNING_KEY" | base64 -d > /tmp/android_keystore.jks # 找到所有未签名的 APK 文件 find src-tauri/gen/android/app/build/outputs -name "*-unsigned.apk" -type f | while read -r apk; do # 生成签名后的文件名 signed_apk="${apk/-unsigned/-signed}" # 使用 apksigner 签名 "$APKSIGNER" sign \ --ks /tmp/android_keystore.jks \ --ks-key-alias "$ANDROID_KEY_ALIAS" \ --ks-pass pass:"$ANDROID_STORE_PASSWORD" \ --key-pass pass:"$ANDROID_KEY_PASSWORD" \ --out "$signed_apk" \ "$apk" echo "已签名: $signed_apk" # 验证签名 "$APKSIGNER" verify "$signed_apk" # 删除未签名版本,重命名签名版本 rm "$apk" mv "$signed_apk" "${apk/-unsigned/}" done # 清理密钥库 rm -f /tmp/android_keystore.jks - uses: actions/upload-artifact@v4 with: name: dist-android path: | src-tauri/gen/android/app/build/outputs/**/*.apk !src-tauri/gen/android/app/build/outputs/**/*-unsigned.apk release: needs: [parse, build_win, build_mac, build_linux, build_android] if: ${{ always() && needs.parse.outputs.tag != '' && (needs.build_win.result == 'success' || needs.build_win.result == 'skipped') && (needs.build_mac.result == 'success' || needs.build_mac.result == 'skipped') && (needs.build_linux.result == 'success' || needs.build_linux.result == 'skipped') && (needs.build_android.result == 'success' || needs.build_android.result == 'skipped') }} runs-on: ubuntu-latest steps: - uses: actions/download-artifact@v4 with: path: artifacts merge-multiple: true - name: 列出产物文件 run: | echo "Artifacts found:" find artifacts -type f -name "*.msi" -o -name "*.exe" -o -name "*.dmg" -o -name "*.app.tar.gz" -o -name "*.deb" -o -name "*.rpm" -o -name "*.AppImage" -o -name "*.apk" 2>/dev/null || true - name: 发布 Release uses: softprops/action-gh-release@v2 with: tag_name: ${{ needs.parse.outputs.tag }} name: SecScore ${{ needs.parse.outputs.tag }} draft: True prerelease: ${{ contains(needs.parse.outputs.version, '-') }} files: | artifacts/**/*.msi artifacts/**/*.exe artifacts/**/*.dmg artifacts/**/*.app.tar.gz artifacts/**/*.deb artifacts/**/*.rpm artifacts/**/*.AppImage artifacts/**/*.apk