Release Client #16
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 Client | |
| # 当推送 tag 时触发,也可以手动触发 | |
| # 构建矩阵在多 runner 上产出二进制后,各 runner 直接 SCP 上传到服务器的 | |
| # ${DEPLOY_PATH}/client/<tag>/ 目录(版本隔离),不使用 Artifact 中转,避免存储配额问题 | |
| # 全部平台上传完成后由 finalize-client 在服务端生成校验和并更新 latest 软链接 | |
| # 行为对齐 release-server.yml(SCP 直传,不依赖 Releases/Artifacts 分发) | |
| on: | |
| push: | |
| tags: | |
| - 'v*' | |
| workflow_dispatch: | |
| # 最小权限:仅需 checkout 拉代码;缓存用 runtime token,上传走 SCP/SSH 密钥,均不依赖 GITHUB_TOKEN | |
| permissions: | |
| contents: read | |
| jobs: | |
| build-client: | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| include: | |
| - os: ubuntu-latest | |
| target: x86_64-unknown-linux-musl | |
| binary: rust-tunnel-client | |
| asset: rust-tunnel-client-linux-x86_64 | |
| - os: macos-latest | |
| target: x86_64-apple-darwin | |
| binary: rust-tunnel-client | |
| asset: rust-tunnel-client-macos-x86_64 | |
| - os: macos-latest | |
| target: aarch64-apple-darwin | |
| binary: rust-tunnel-client | |
| asset: rust-tunnel-client-macos-aarch64 | |
| - os: windows-latest | |
| target: x86_64-pc-windows-msvc | |
| binary: rust-tunnel-client.exe | |
| asset: rust-tunnel-client-windows-x86_64.exe | |
| runs-on: ${{ matrix.os }} | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v7 | |
| - name: Install Rust with target | |
| uses: dtolnay/rust-toolchain@stable | |
| with: | |
| toolchain: stable | |
| target: ${{ matrix.target }} | |
| - name: Setup Rust cache | |
| uses: Swatinem/rust-cache@v2 | |
| with: | |
| cache-targets: true | |
| cache-on-failure: true | |
| - name: Install musl tools (Linux only) | |
| if: runner.os == 'Linux' | |
| uses: awalsh128/cache-apt-pkgs-action@v1 | |
| with: | |
| packages: musl-tools | |
| version: 1.0 | |
| - name: Build client | |
| env: | |
| RUSTFLAGS: ${{ matrix.os == 'windows-latest' && '-C target-feature=+crt-static' || '' }} | |
| run: cargo build --release -p rust-tunnel-client --target ${{ matrix.target }} | |
| - name: Strip binary (non-Windows) | |
| if: runner.os != 'Windows' | |
| run: strip target/${{ matrix.target }}/release/${{ matrix.binary }} | |
| # 各平台自行 SCP 直传:appleboy/scp-action 是 Docker action,只能跑在 Linux runner, | |
| # 因此这里统一用原生 ssh/scp(Windows runner 走 git-bash,自带 OpenSSH 客户端) | |
| - name: Upload binary to remote server | |
| shell: bash | |
| env: | |
| SSH_KEY: ${{ secrets.SERVER_SSH_KEY }} | |
| SSH_HOST: ${{ secrets.SERVER_HOST }} | |
| SSH_USER: ${{ secrets.SERVER_USER }} | |
| SSH_PORT: ${{ secrets.SERVER_PORT }} | |
| DEPLOY_PATH: ${{ secrets.DEPLOY_PATH }} | |
| run: | | |
| set -euo pipefail | |
| mkdir -p "${HOME}/.ssh" | |
| KEY="${HOME}/.ssh/rt_deploy_key" | |
| printf '%s\n' "${SSH_KEY}" > "${KEY}" | |
| chmod 600 "${KEY}" | |
| PORT="${SSH_PORT:-22}" | |
| DEST="${DEPLOY_PATH}/client/${GITHUB_REF_NAME}" | |
| SSH_OPTS=(-i "${KEY}" -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -o LogLevel=ERROR) | |
| echo "Uploading ${{ matrix.asset }} -> ${DEST}/" | |
| ssh "${SSH_OPTS[@]}" -p "${PORT}" "${SSH_USER}@${SSH_HOST}" "mkdir -p '${DEST}'" | |
| scp "${SSH_OPTS[@]}" -P "${PORT}" \ | |
| "target/${{ matrix.target }}/release/${{ matrix.binary }}" \ | |
| "${SSH_USER}@${SSH_HOST}:${DEST}/${{ matrix.asset }}" | |
| rm -f "${KEY}" | |
| build-gui: | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| include: | |
| - os: ubuntu-latest | |
| target: x86_64-unknown-linux-gnu | |
| binary: rust-tunnel-client-gui | |
| asset: rust-tunnel-client-gui-linux-x86_64 | |
| - os: windows-latest | |
| target: x86_64-pc-windows-msvc | |
| binary: rust-tunnel-client-gui.exe | |
| asset: rust-tunnel-client-gui-windows-x86_64.exe | |
| runs-on: ${{ matrix.os }} | |
| steps: | |
| - uses: actions/checkout@v7 | |
| - uses: dtolnay/rust-toolchain@stable | |
| with: | |
| toolchain: stable | |
| target: ${{ matrix.target }} | |
| - uses: Swatinem/rust-cache@v2 | |
| with: | |
| cache-targets: true | |
| cache-on-failure: true | |
| - name: Install Linux GUI deps | |
| if: runner.os == 'Linux' | |
| run: sudo apt-get update && sudo apt-get install -y mold libgtk-3-dev librsvg2-dev libxcb-shape0-dev libxcb-xfixes0-dev libxkbcommon-dev pkg-config libdbus-1-dev libxdo-dev | |
| - name: Build GUI | |
| run: cargo build --release -p rust-tunnel-client-gui --target ${{ matrix.target }} | |
| - name: Upload GUI to remote | |
| shell: bash | |
| env: | |
| SSH_KEY: ${{ secrets.SERVER_SSH_KEY }} | |
| SSH_HOST: ${{ secrets.SERVER_HOST }} | |
| SSH_USER: ${{ secrets.SERVER_USER }} | |
| SSH_PORT: ${{ secrets.SERVER_PORT }} | |
| DEPLOY_PATH: ${{ secrets.DEPLOY_PATH }} | |
| run: | | |
| set -euo pipefail | |
| mkdir -p "${HOME}/.ssh" | |
| KEY="${HOME}/.ssh/rt_deploy_key" | |
| printf '%s\n' "${SSH_KEY}" > "${KEY}" | |
| chmod 600 "${KEY}" | |
| PORT="${SSH_PORT:-22}" | |
| DEST="${DEPLOY_PATH}/client/${GITHUB_REF_NAME}" | |
| SSH_OPTS=(-i "${KEY}" -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -o LogLevel=ERROR) | |
| ssh "${SSH_OPTS[@]}" -p "${PORT}" "${SSH_USER}@${SSH_HOST}" "mkdir -p '${DEST}'" | |
| scp "${SSH_OPTS[@]}" -P "${PORT}" "target/${{ matrix.target }}/release/${{ matrix.binary }}" "${SSH_USER}@${SSH_HOST}:${DEST}/${{ matrix.asset }}" | |
| rm -f "${KEY}" | |
| build-gui-macos: | |
| runs-on: macos-latest | |
| steps: | |
| - uses: actions/checkout@v7 | |
| - uses: dtolnay/rust-toolchain@stable | |
| with: | |
| toolchain: stable | |
| targets: aarch64-apple-darwin,x86_64-apple-darwin | |
| - uses: Swatinem/rust-cache@v2 | |
| with: | |
| cache-targets: true | |
| cache-on-failure: true | |
| - name: Build universal2 binary | |
| run: | | |
| cargo build --release -p rust-tunnel-client-gui --target aarch64-apple-darwin | |
| cargo build --release -p rust-tunnel-client-gui --target x86_64-apple-darwin | |
| mkdir -p target/universal2 | |
| lipo -create target/aarch64-apple-darwin/release/rust-tunnel-client-gui target/x86_64-apple-darwin/release/rust-tunnel-client-gui -output target/universal2/rust-tunnel-client-gui | |
| - name: Bundle .app and dmg | |
| env: | |
| VERSION: ${{ github.ref_name }} | |
| GUI_BIN: target/universal2/rust-tunnel-client-gui | |
| run: | | |
| bash scripts/bundle-macos.sh | |
| ls -lh dist/ | |
| - name: Upload dmg | |
| shell: bash | |
| env: | |
| SSH_KEY: ${{ secrets.SERVER_SSH_KEY }} | |
| SSH_HOST: ${{ secrets.SERVER_HOST }} | |
| SSH_USER: ${{ secrets.SERVER_USER }} | |
| SSH_PORT: ${{ secrets.SERVER_PORT }} | |
| DEPLOY_PATH: ${{ secrets.DEPLOY_PATH }} | |
| run: | | |
| set -euo pipefail | |
| mkdir -p "${HOME}/.ssh" | |
| KEY="${HOME}/.ssh/rt_deploy_key" | |
| printf '%s\n' "${SSH_KEY}" > "${KEY}" | |
| chmod 600 "${KEY}" | |
| PORT="${SSH_PORT:-22}" | |
| DEST="${DEPLOY_PATH}/client/${GITHUB_REF_NAME}" | |
| DMG="dist/RustTunnel-${GITHUB_REF_NAME}-macos-universal2.dmg" | |
| SSH_OPTS=(-i "${KEY}" -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -o LogLevel=ERROR) | |
| ssh "${SSH_OPTS[@]}" -p "${PORT}" "${SSH_USER}@${SSH_HOST}" "mkdir -p '${DEST}'" | |
| scp "${SSH_OPTS[@]}" -P "${PORT}" "$DMG" "${SSH_USER}@${SSH_HOST}:${DEST}/" | |
| rm -f "${KEY}" | |
| finalize-client: | |
| needs: [build-client, build-gui, build-gui-macos] | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checksum, permissions and latest symlink | |
| uses: appleboy/ssh-action@v1.2.5 | |
| with: | |
| host: ${{ secrets.SERVER_HOST }} | |
| username: ${{ secrets.SERVER_USER }} | |
| key: ${{ secrets.SERVER_SSH_KEY }} | |
| port: ${{ secrets.SERVER_PORT }} | |
| script: | | |
| set -e | |
| BASE="${{ secrets.DEPLOY_PATH }}/client" | |
| TAG="${{ github.ref_name }}" | |
| cd "${BASE}/${TAG}" | |
| chmod +x rust-tunnel-client-* RustTunnel-*.dmg 2>/dev/null || true | |
| sha256sum rust-tunnel-client-* RustTunnel-*.dmg 2>/dev/null > SHA256SUMS || sha256sum rust-tunnel-client-* > SHA256SUMS | |
| echo "--- ${BASE}/${TAG} ---" | |
| ls -lh | |
| echo "--- SHA256SUMS ---" | |
| cat SHA256SUMS | |
| ln -sfn "${TAG}" "${BASE}/latest" | |
| ls -ld "${BASE}/latest" | |
| echo "Client ${TAG} deployed successfully to ${BASE}/${TAG}/ (latest -> ${TAG})" |