Build and Release Client #180
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
| # build.yml | |
| name: Build and Release Client | |
| on: | |
| workflow_dispatch: | |
| inputs: | |
| version: | |
| description: "Version number (e.g., v1.0.0)" | |
| required: true | |
| type: string | |
| build_debug: | |
| description: Build debug version | |
| required: false | |
| default: false | |
| type: boolean | |
| product_name: | |
| description: "Custom product name for manual builds (e.g., MyClient)" | |
| required: false | |
| default: "" | |
| type: string | |
| push: | |
| branches: | |
| - master | |
| tags: | |
| - "v*" # 只有正式版本标签才触发构建 | |
| env: | |
| VERSION: ${{ github.event_name == 'workflow_dispatch' && github.event.inputs.version || github.ref_name }} | |
| permissions: | |
| contents: write | |
| jobs: | |
| pre-build: | |
| name: pre-build go client | |
| runs-on: ubuntu-latest | |
| outputs: | |
| go-client-artifacts: ${{ steps.upload-go-client.outputs.artifact-name }} | |
| steps: | |
| - name: Check out git repository | |
| uses: actions/checkout@v4 | |
| - name: Setup Go | |
| uses: actions/setup-go@v4 | |
| with: | |
| go-version: "1.21" | |
| - name: Build Go client for all platforms | |
| run: make build-all | |
| working-directory: go-client | |
| - name: Upload Go client artifacts | |
| id: upload-go-client | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: go-client-binaries | |
| path: go-client/build/ | |
| retention-days: 1 | |
| create-release-draft: | |
| name: create latest.json | |
| runs-on: ubuntu-latest | |
| if: startsWith(github.ref, 'refs/tags/') || github.event_name == 'workflow_dispatch' | |
| outputs: | |
| release-draft-created: ${{ steps.create-release-draft.outputs.release-draft-created }} | |
| steps: | |
| - name: Check out git repository | |
| uses: actions/checkout@v4 | |
| - name: Generate latest.json | |
| shell: bash | |
| run: | | |
| echo '{ | |
| "version": "${{ env.VERSION }}", | |
| "notes": "Release ${{ env.VERSION }}", | |
| "pub_date": "'$(date -u +%Y-%m-%dT%H:%M:%SZ)'", | |
| "platforms": { | |
| "darwin-x86_64": { | |
| "signature": "", | |
| "url": "https://github.com/jumpserver/clients/releases/download/${{ env.VERSION }}/JumpServerClient_${{ env.VERSION }}_x86_64.dmg" | |
| }, | |
| "darwin-aarch64": { | |
| "signature": "", | |
| "url": "https://github.com/jumpserver/clients/releases/download/${{ env.VERSION }}/JumpServerClient_${{ env.VERSION }}_aarch64.dmg" | |
| }, | |
| "windows-x86_64": { | |
| "signature": "", | |
| "url": "https://github.com/jumpserver/clients/releases/download/${{ env.VERSION }}/JumpServerClient_${{ env.VERSION }}_x64.exe" | |
| }, | |
| "windows-x86_64-msi": { | |
| "signature": "", | |
| "url": "https://github.com/jumpserver/clients/releases/download/${{ env.VERSION }}/JumpServerClient_${{ env.VERSION }}_x64.msi" | |
| } | |
| } | |
| }' > latest.json | |
| - name: Upload latest.json to release | |
| uses: softprops/action-gh-release@v1 | |
| with: | |
| tag_name: ${{ env.VERSION }} | |
| files: latest.json | |
| fail_on_unmatched_files: true | |
| draft: true | |
| prerelease: false | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| build: | |
| name: build tauri app (${{ matrix.target || matrix.platform }}) | |
| needs: pre-build | |
| permissions: | |
| contents: write | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| include: | |
| - platform: macos-latest # for Arm based macs (M1 and above). | |
| target: aarch64-apple-darwin | |
| - platform: macos-latest # for Intel based macs. | |
| target: x86_64-apple-darwin | |
| - platform: ubuntu-22.04 # for Tauri v1 you could replace this with ubuntu-20.04. | |
| target: "" | |
| - platform: ubuntu-22.04-arm | |
| target: "" | |
| - platform: windows-latest | |
| target: "" | |
| runs-on: ${{ matrix.platform }} | |
| env: | |
| APPLE_ID: ${{ secrets.APPLE_ID }} | |
| APPLE_PASSWORD: ${{ secrets.APPLE_PASSWORD }} | |
| APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }} | |
| steps: | |
| - name: Check out git repository | |
| uses: actions/checkout@v4 | |
| - name: Download Go client artifacts | |
| uses: actions/download-artifact@v4 | |
| with: | |
| name: go-client-binaries | |
| path: go-client/build/ | |
| - name: Install Go client for current platform | |
| run: make install TARGET="${{ matrix.target }}" | |
| working-directory: go-client | |
| - uses: pnpm/action-setup@v4 | |
| name: Install pnpm | |
| with: | |
| run_install: false | |
| - name: Setup Node.js | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: "23" | |
| cache: pnpm | |
| - name: Setup Apple Certificate | |
| if: startsWith(matrix.platform, 'macos') | |
| env: | |
| APPLE_CERTIFICATE: ${{ secrets.APPLE_CERTIFICATE }} | |
| APPLE_CERTIFICATE_PASSWORD: ${{ secrets.APPLE_CERTIFICATE_PASSWORD }} | |
| KEYCHAIN_PASSWORD: ${{ secrets.KEYCHAIN_PASSWORD }} | |
| run: npm run setup_apple_cert | |
| - name: Sign embedded Go client binary (macOS only) | |
| if: startsWith(matrix.platform, 'macos') | |
| env: | |
| APPLE_SIGNING_IDENTITY: ${{ env.APPLE_SIGNING_IDENTITY }} | |
| TARGET_ARCH: ${{ matrix.target == 'aarch64-apple-darwin' && 'arm64' || 'amd64' }} | |
| run: pnpm run sign_go_binary | |
| - name: Install Rust stable | |
| uses: dtolnay/rust-toolchain@stable | |
| with: | |
| # Those targets are only used on macos runners so it's in an `if` to slightly speed up windows and linux builds. | |
| targets: ${{ startsWith(matrix.platform, 'macos') && matrix.target || '' }} | |
| - name: Install system dependencies (Ubuntu) | |
| if: startsWith(matrix.platform, 'ubuntu') | |
| run: | | |
| sudo apt-get update | |
| sudo apt-get install -y libwebkit2gtk-4.1-dev libssl-dev libgtk-3-dev libayatana-appindicator3-dev librsvg2-dev patchelf xdg-utils desktop-file-utils | |
| - name: Install frontend dependencies | |
| run: pnpm install | |
| - name: Sync app version from workflow version | |
| env: | |
| VERSION: ${{ env.VERSION }} | |
| run: pnpm run set_version | |
| # Manual builds: use tauri-action for signing/notarization, but upload to workflow artifacts (temporary download) | |
| - name: Set product name (manual only) | |
| if: github.event_name == 'workflow_dispatch' && github.event.inputs.product_name != '' | |
| run: node scripts/set-product-name.mjs --name "${{ github.event.inputs.product_name }}" | |
| - name: Apply brand assets (manual only) | |
| if: github.event_name == 'workflow_dispatch' && github.event.inputs.product_name != '' | |
| env: | |
| CLIENT_BRAND_ASSETS_PASSPHRASE: ${{ secrets.CLIENT_BRAND_ASSETS_PASSPHRASE }} | |
| shell: bash | |
| run: | | |
| encrypted_assets=".github/brand-assets/client-brand-assets.tgz.enc" | |
| if [ ! -f "$encrypted_assets" ]; then | |
| echo "No encrypted brand assets found; using repository default assets." | |
| exit 0 | |
| fi | |
| if [ -z "$CLIENT_BRAND_ASSETS_PASSPHRASE" ]; then | |
| echo "CLIENT_BRAND_ASSETS_PASSPHRASE is required to decrypt brand assets." | |
| exit 1 | |
| fi | |
| # Keep these paths relative so Git Bash on Windows does not pass a | |
| # drive-letter path like "D:\..." to tar, which tar treats as remote. | |
| assets_root=".brand-assets-tmp" | |
| assets_dir="$assets_root/client-brand-assets" | |
| archive_path="$assets_root/client-brand-assets.tgz" | |
| rm -rf "$assets_root" | |
| rm -rf "$assets_dir" | |
| mkdir -p "$assets_dir" | |
| openssl enc -d -aes-256-cbc -pbkdf2 -iter 200000 \ | |
| -in "$encrypted_assets" \ | |
| -out "$archive_path" \ | |
| -pass env:CLIENT_BRAND_ASSETS_PASSPHRASE | |
| tar -xzf "$archive_path" -C "$assets_dir" | |
| node scripts/apply-brand-assets.mjs --dir "$assets_dir" | |
| - name: Build Tauri app | |
| id: tauri_build | |
| uses: tauri-apps/tauri-action@v0 | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| TAURI_PRIVATE_KEY: ${{ secrets.TAURI_PRIVATE_KEY }} | |
| TAURI_KEY_PASSWORD: ${{ secrets.TAURI_KEY_PASSWORD }} | |
| APPLE_CERTIFICATE: ${{ secrets.APPLE_CERTIFICATE }} | |
| APPLE_CERTIFICATE_PASSWORD: ${{ secrets.APPLE_CERTIFICATE_PASSWORD }} | |
| APPLE_SIGNING_IDENTITY: ${{ env.APPLE_SIGNING_IDENTITY }} | |
| CLIENT_NAME: ${{ github.event_name == 'workflow_dispatch' && github.event.inputs.product_name || '' }} | |
| VITE_APP_NAME: ${{ github.event_name == 'workflow_dispatch' && github.event.inputs.product_name || '' }} | |
| with: | |
| # Create/update release draft on both tag/push and manual dispatch. | |
| tagName: ${{ env.VERSION }} | |
| args: ${{ matrix.target != '' && '--target ' || '' }}${{ matrix.target }} | |
| releaseName: JumpServer Client v__VERSION__ | |
| releaseBody: See the assets to download this version and install. | |
| releaseDraft: true | |
| prerelease: false | |
| includeDebug: ${{ github.event_name == 'workflow_dispatch' && fromJSON(github.event.inputs.build_debug || 'false') || false }} | |
| includeRelease: ${{ github.event_name != 'workflow_dispatch' || !fromJSON(github.event.inputs.build_debug || 'false') }} |