Build #793
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: Build | |
| on: | |
| workflow_dispatch: | |
| inputs: | |
| gp_branch: | |
| description: 'GlobalProtect-openconnect branch to use for the snapshot release' | |
| required: true | |
| default: dev | |
| gpgui_branch: | |
| description: 'gpgui branch to use for the snapshot release' | |
| required: true | |
| default: dev | |
| build_macos: | |
| description: 'Build Apple Silicon artifacts for the snapshot release' | |
| required: true | |
| default: false | |
| type: boolean | |
| build_bsd: | |
| description: 'Build FreeBSD/OpenBSD packages for the snapshot release' | |
| required: true | |
| default: false | |
| type: boolean | |
| build_bsd_arm64: | |
| description: 'Build optional FreeBSD/OpenBSD arm64 packages for the snapshot release. Slow and disabled by default' | |
| required: true | |
| default: false | |
| type: boolean | |
| push: | |
| paths-ignore: | |
| - LICENSE | |
| - "*.md" | |
| - .vscode | |
| - .devcontainer | |
| branches: | |
| - main | |
| - hotfix/* | |
| - feature/* | |
| - release/* | |
| tags: | |
| - v*.*.* | |
| concurrency: | |
| group: ${{ github.workflow }}-${{ github.ref }} | |
| cancel-in-progress: true | |
| jobs: | |
| test-gp: | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout GlobalProtect-openconnect | |
| uses: actions/checkout@v6 | |
| with: | |
| token: ${{ secrets.GH_PAT }} | |
| repository: yuezk/GlobalProtect-openconnect | |
| ref: ${{ github.event_name == 'workflow_dispatch' && inputs.gp_branch || github.ref }} | |
| submodules: recursive | |
| - name: Run Rust tests in Docker | |
| run: | | |
| docker run --rm \ | |
| --user root \ | |
| -e COREPACK_INTEGRITY_KEYS=0 \ | |
| -e LIBXML2_STATIC=1 \ | |
| -v "$(pwd):/workspace" \ | |
| -w /workspace \ | |
| yuezk/gpdev:binary-builder-tauri2 \ | |
| cargo test --workspace | |
| tarball: | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: pnpm/action-setup@v5 | |
| with: | |
| version: 9 | |
| - name: Prepare workspace | |
| run: rm -rf source && mkdir -p source/artifacts | |
| - name: Checkout GlobalProtect-openconnect | |
| uses: actions/checkout@v6 | |
| with: | |
| token: ${{ secrets.GH_PAT }} | |
| repository: yuezk/GlobalProtect-openconnect | |
| ref: ${{ github.event_name == 'workflow_dispatch' && inputs.gp_branch || github.ref }} | |
| path: source/gp | |
| submodules: recursive | |
| - name: Create tarball | |
| run: | | |
| cd source/gp | |
| # Generate the SNAPSHOT file for non-tagged commits | |
| if [[ "${{ github.ref }}" != "refs/tags/"* ]]; then | |
| touch SNAPSHOT | |
| fi | |
| make tarball | |
| mv -v .build/tarball/*.tar.gz ../artifacts/ | |
| - name: Generate RPM spec file | |
| env: | |
| RELEASE_TAG: ${{ github.event_name == 'workflow_dispatch' && 'snapshot' || github.ref_name }} | |
| run: | | |
| cd source/gp | |
| make init-rpm \ | |
| REVISION='1%{?dist}' \ | |
| RPM_SOURCE=https://github.com/yuezk/GlobalProtect-openconnect/releases/download/${RELEASE_TAG}/%{name}-%{version}.tar.gz | |
| mv -v .build/rpm/*.spec ../artifacts/ | |
| - name: Upload tarball | |
| uses: actions/upload-artifact@v7 | |
| with: | |
| name: artifact-source | |
| if-no-files-found: error | |
| path: | | |
| source/artifacts/* | |
| tarball-offline: | |
| if: ${{ github.event_name == 'workflow_dispatch' || startsWith(github.ref, 'refs/tags/') }} | |
| runs-on: ubuntu-latest | |
| needs: | |
| - tarball | |
| steps: | |
| - uses: pnpm/action-setup@v5 | |
| with: | |
| version: 9 | |
| - name: Prepare workspace | |
| run: rm -rf source-offline && mkdir source-offline | |
| - name: Download tarball | |
| uses: actions/download-artifact@v8 | |
| with: | |
| name: artifact-source | |
| path: source-offline | |
| - name: Create offline tarball | |
| run: | | |
| cd source-offline | |
| offline_tarball=$(basename *.tar.gz .tar.gz).offline.tar.gz | |
| # Extract the tarball | |
| tar -xzf *.tar.gz | |
| cd */ | |
| make tarball OFFLINE=1 | |
| # Rename the tarball to .offline.tar.gz | |
| mv -v .build/tarball/*.tar.gz ../$offline_tarball | |
| - name: Upload offline tarball | |
| uses: actions/upload-artifact@v7 | |
| with: | |
| path: source-offline/*.offline.tar.gz | |
| name: artifact-source-offline | |
| if-no-files-found: error | |
| build-gp: | |
| if: ${{ !startsWith(github.ref, 'refs/tags/') }} | |
| needs: | |
| - tarball | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| os: | |
| - runner: ubuntu-latest | |
| arch: amd64 | |
| - runner: ubuntu-24.04-arm | |
| arch: ubuntu-24.04-arm | |
| package: [deb, rpm, pkg, apk, binary, ubuntu-rolling] | |
| runs-on: ${{ matrix.os.runner }} | |
| name: build-gp (${{ matrix.package }}, ${{ matrix.os.arch }}) | |
| steps: | |
| - name: Prepare workspace | |
| run: | | |
| rm -rf build-gp-${{ matrix.package }} | |
| mkdir -p build-gp-${{ matrix.package }} | |
| - name: Download tarball | |
| uses: actions/download-artifact@v8 | |
| with: | |
| name: artifact-source | |
| path: build-gp-${{ matrix.package }} | |
| - name: Build ${{ matrix.package }} package in Docker | |
| # LIBXML2_STATIC is needed to avoid the dynamic linking issue on different distros | |
| run: | | |
| docker run --rm \ | |
| -e COREPACK_INTEGRITY_KEYS=0 \ | |
| -e LIBXML2_STATIC=1 \ | |
| -v $(pwd)/build-gp-${{ matrix.package }}:/workspace \ | |
| yuezk/gpdev:${{ matrix.package }}-builder-tauri2 | |
| - name: Install ${{ matrix.package }} package in Docker | |
| run: | | |
| docker run --rm \ | |
| -e COREPACK_INTEGRITY_KEYS=0 \ | |
| -e GPGUI_INSTALLED=0 \ | |
| -v $(pwd)/build-gp-${{ matrix.package }}:/workspace \ | |
| yuezk/gpdev:${{ matrix.package }}-builder-tauri2 \ | |
| bash install.sh | |
| # Don't upload package for ubuntu-rolling because it's duplicate of deb package | |
| - name: Upload ${{ matrix.package }} package | |
| if: ${{ matrix.package != 'ubuntu-rolling' }} | |
| uses: actions/upload-artifact@v7 | |
| with: | |
| name: artifact-gp-${{ matrix.package }}-${{ matrix.os.arch }} | |
| if-no-files-found: error | |
| path: | | |
| build-gp-${{ matrix.package }}/artifacts/* | |
| build-docker-image: | |
| if: ${{ !startsWith(github.ref, 'refs/tags/') }} | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| include: | |
| - runner: ubuntu-latest | |
| platform: linux/amd64 | |
| - runner: ubuntu-24.04-arm | |
| platform: linux/arm64 | |
| runs-on: ${{ matrix.runner }} | |
| steps: | |
| - name: Prepare | |
| run: | | |
| platform=${{ matrix.platform }} | |
| echo "PLATFORM_PAIR=${platform//\//-}" >> "$GITHUB_ENV" | |
| - name: Checkout GlobalProtect-openconnect | |
| uses: actions/checkout@v6 | |
| with: | |
| token: ${{ secrets.GH_PAT }} | |
| repository: yuezk/GlobalProtect-openconnect | |
| ref: ${{ github.event_name == 'workflow_dispatch' && inputs.gp_branch || github.ref }} | |
| submodules: recursive | |
| - name: Set up Docker Buildx | |
| uses: docker/setup-buildx-action@v4 | |
| - name: Login to Docker Hub | |
| uses: docker/login-action@v4 | |
| with: | |
| username: ${{ secrets.DOCKER_HUB_USERNAME }} | |
| password: ${{ secrets.DOCKER_HUB_TOKEN }} | |
| - name: Build and push by digest | |
| id: build | |
| uses: docker/build-push-action@v7 | |
| with: | |
| context: . | |
| file: packaging/docker/alpine/Dockerfile | |
| platforms: ${{ matrix.platform }} | |
| outputs: type=image,name=yuezk/globalprotect-openconnect,push-by-digest=true,name-canonical=true,push=true | |
| - name: Verify CLI tools | |
| env: | |
| IMAGE: yuezk/globalprotect-openconnect | |
| DIGEST: ${{ steps.build.outputs.digest }} | |
| run: | | |
| docker run --rm "$IMAGE@$DIGEST" --help | |
| docker run --rm --entrypoint gpauth "$IMAGE@$DIGEST" --help | |
| docker run --rm --entrypoint sh "$IMAGE@$DIGEST" -lc 'test "$(id -u gp)" = "1000" && test "$SUDO_UID" = "1000"' | |
| - name: Export digest | |
| run: | | |
| mkdir -p /tmp/digests | |
| digest="${{ steps.build.outputs.digest }}" | |
| touch "/tmp/digests/${digest#sha256:}" | |
| - name: Upload digest | |
| uses: actions/upload-artifact@v7 | |
| with: | |
| name: digests-${{ env.PLATFORM_PAIR }} | |
| path: /tmp/digests/* | |
| if-no-files-found: error | |
| retention-days: 1 | |
| build-gpgui: | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| os: | |
| - runner: ubuntu-latest | |
| arch: amd64 | |
| - runner: ubuntu-24.04-arm | |
| arch: ubuntu-24.04-arm | |
| libc: | |
| - name: glibc | |
| builder: gpgui-builder-tauri2 | |
| artifact_suffix: "" | |
| - name: musl | |
| builder: gpgui-alpine-builder-tauri2 | |
| artifact_suffix: "-musl" | |
| runs-on: ${{ matrix.os.runner }} | |
| name: build-gpgui (${{ matrix.libc.name }}, ${{ matrix.os.arch }}) | |
| steps: | |
| - uses: pnpm/action-setup@v5 | |
| with: | |
| version: 9 | |
| - name: Prepare workspace | |
| run: rm -rf gpgui-source && mkdir gpgui-source | |
| - name: Checkout GlobalProtect-openconnect | |
| uses: actions/checkout@v6 | |
| with: | |
| token: ${{ secrets.GH_PAT }} | |
| repository: yuezk/GlobalProtect-openconnect | |
| ref: ${{ github.event_name == 'workflow_dispatch' && inputs.gp_branch || github.ref }} | |
| path: gpgui-source/gp | |
| submodules: recursive | |
| - name: Checkout gpgui | |
| uses: actions/checkout@v6 | |
| with: | |
| token: ${{ secrets.GH_PAT }} | |
| repository: yuezk/gpgui | |
| ref: ${{ github.event_name == 'workflow_dispatch' && inputs.gpgui_branch || github.ref_name }} | |
| path: gpgui-source/gpgui | |
| - name: Verify Linux desktop assets | |
| if: matrix.os.arch == 'amd64' && matrix.libc.name == 'glibc' | |
| run: gpgui-source/gp/scripts/verify-linux-desktop-assets.sh gpgui-source/gpgui | |
| - name: Tarball | |
| run: | | |
| cd gpgui-source | |
| tar -czf gpgui.tar.gz gpgui gp | |
| - name: Build gpgui in Docker | |
| run: | | |
| docker run --rm \ | |
| -e COREPACK_INTEGRITY_KEYS=0 \ | |
| -v $(pwd)/gpgui-source:/workspace yuezk/gpdev:${{ matrix.libc.builder }} | |
| - name: Install gpgui in Docker | |
| run: | | |
| cd gpgui-source | |
| tar -xJf *.bin.tar.xz | |
| docker run --rm \ | |
| -e COREPACK_INTEGRITY_KEYS=0 \ | |
| -v $(pwd):/workspace yuezk/gpdev:${{ matrix.libc.builder }} \ | |
| bash -c "cd /workspace/gpgui_*/ && ./gpgui --version" | |
| - name: Upload gpgui | |
| uses: actions/upload-artifact@v7 | |
| with: | |
| name: artifact-gpgui${{ matrix.libc.artifact_suffix }}-${{ matrix.os.arch }} | |
| if-no-files-found: error | |
| path: | | |
| gpgui-source/*.bin.tar.xz | |
| gpgui-source/*.bin.tar.xz.sha256 | |
| build-gpgui-macos: | |
| if: ${{ startsWith(github.ref, 'refs/tags/') || (github.event_name == 'workflow_dispatch' && inputs.build_macos) }} | |
| runs-on: macos-26 | |
| environment: macos-release | |
| name: build-gpgui (macOS, arm64) | |
| outputs: | |
| archive_name: ${{ steps.release.outputs.archive_name }} | |
| steps: | |
| - name: Verify runner architecture | |
| run: test "$(uname -m)" = arm64 | |
| - uses: pnpm/action-setup@v5 | |
| with: | |
| version: 9.15.1 | |
| - name: Prepare workspace | |
| run: rm -rf gpgui-source && mkdir gpgui-source | |
| - name: Checkout GlobalProtect-openconnect | |
| uses: actions/checkout@v6 | |
| with: | |
| token: ${{ secrets.GH_PAT }} | |
| repository: yuezk/GlobalProtect-openconnect | |
| ref: ${{ github.event_name == 'workflow_dispatch' && inputs.gp_branch || github.ref }} | |
| path: gpgui-source/gp | |
| submodules: recursive | |
| - name: Checkout gpgui | |
| uses: actions/checkout@v6 | |
| with: | |
| token: ${{ secrets.GH_PAT }} | |
| repository: yuezk/gpgui | |
| ref: ${{ github.event_name == 'workflow_dispatch' && inputs.gpgui_branch || github.ref_name }} | |
| path: gpgui-source/gpgui | |
| - uses: actions/setup-node@v6 | |
| with: | |
| node-version: 22 | |
| cache: pnpm | |
| cache-dependency-path: gpgui-source/gpgui/app/pnpm-lock.yaml | |
| - name: Validate release versions | |
| id: release | |
| run: | | |
| set -euo pipefail | |
| gp_version="$(sed -n 's/^version = "\([^"]*\)"/\1/p' gpgui-source/gp/Cargo.toml | head -1)" | |
| gpgui_version="$(sed -n 's/^version = "\([^"]*\)"/\1/p' gpgui-source/gpgui/Cargo.toml | head -1)" | |
| if [[ -z "$gp_version" || "$gp_version" != "$gpgui_version" ]]; then | |
| echo "gp and gpgui versions must match: gp=$gp_version, gpgui=$gpgui_version" >&2 | |
| exit 1 | |
| fi | |
| build_number="${{ github.run_number }}.${{ github.run_attempt }}" | |
| if [[ "${{ github.event_name }}" == "workflow_dispatch" ]]; then | |
| channel="snapshot" | |
| release_tag="snapshot" | |
| artifact_version="$gpgui_version-snapshot.$build_number" | |
| feed_url="https://github.com/${{ github.repository }}/releases/download/snapshot/appcast.xml" | |
| else | |
| channel="stable" | |
| release_tag="${{ github.ref_name }}" | |
| artifact_version="$gpgui_version" | |
| feed_url="https://github.com/${{ github.repository }}/releases/latest/download/appcast.xml" | |
| if [[ "$release_tag" != "v$gpgui_version" ]]; then | |
| echo "Release tag $release_tag does not match gpgui version $gpgui_version" >&2 | |
| exit 1 | |
| fi | |
| fi | |
| archive_name="GPConnect_${artifact_version}_arm64.zip" | |
| { | |
| echo "MACOS_BUILD_NUMBER=$build_number" | |
| echo "MACOS_ARTIFACT_VERSION=$artifact_version" | |
| echo "SPARKLE_FEED_URL=$feed_url" | |
| echo "RELEASE_TAG=$release_tag" | |
| echo "UPDATE_CHANNEL=$channel" | |
| } >> "$GITHUB_ENV" | |
| echo "archive_name=$archive_name" >> "$GITHUB_OUTPUT" | |
| - name: Install build dependencies | |
| run: | | |
| brew install \ | |
| autoconf \ | |
| automake \ | |
| create-dmg \ | |
| dylibbundler \ | |
| gettext \ | |
| gmp \ | |
| gnutls \ | |
| libidn2 \ | |
| libtool \ | |
| libtasn1 \ | |
| libunistring \ | |
| lz4 \ | |
| nettle \ | |
| openssl@3 \ | |
| p11-kit \ | |
| pkgconf | |
| - name: Import signing identity | |
| env: | |
| MACOS_CERTIFICATE_P12: ${{ secrets.MACOS_CERTIFICATE_P12 }} | |
| MACOS_CERTIFICATE_PASSWORD: ${{ secrets.MACOS_CERTIFICATE_PASSWORD }} | |
| APPLE_NOTARY_KEY_P8: ${{ secrets.APPLE_NOTARY_KEY_P8 }} | |
| APPLE_NOTARY_KEY_ID: ${{ secrets.APPLE_NOTARY_KEY_ID }} | |
| APPLE_NOTARY_ISSUER_ID: ${{ secrets.APPLE_NOTARY_ISSUER_ID }} | |
| run: | | |
| set -euo pipefail | |
| for variable in \ | |
| MACOS_CERTIFICATE_P12 \ | |
| MACOS_CERTIFICATE_PASSWORD; do | |
| if [[ -z "${!variable:-}" ]]; then | |
| echo "$variable is not configured" >&2 | |
| exit 1 | |
| fi | |
| done | |
| if [[ "$UPDATE_CHANNEL" == "stable" ]]; then | |
| for variable in \ | |
| APPLE_NOTARY_KEY_P8 \ | |
| APPLE_NOTARY_KEY_ID \ | |
| APPLE_NOTARY_ISSUER_ID; do | |
| if [[ -z "${!variable:-}" ]]; then | |
| echo "$variable is not configured" >&2 | |
| exit 1 | |
| fi | |
| done | |
| fi | |
| keychain="$RUNNER_TEMP/gp-connect.keychain-db" | |
| keychain_password="$(openssl rand -hex 24)" | |
| certificate="$RUNNER_TEMP/signing-identity.p12" | |
| printf '%s' "$MACOS_CERTIFICATE_P12" | base64 -D > "$certificate" | |
| chmod 600 "$certificate" | |
| security create-keychain -p "$keychain_password" "$keychain" | |
| security set-keychain-settings -lut 21600 "$keychain" | |
| security unlock-keychain -p "$keychain_password" "$keychain" | |
| security import "$certificate" -k "$keychain" \ | |
| -P "$MACOS_CERTIFICATE_PASSWORD" -A -t cert -f pkcs12 | |
| security set-key-partition-list -S apple-tool:,apple: \ | |
| -s -k "$keychain_password" "$keychain" | |
| security list-keychains -d user -s "$keychain" login.keychain-db | |
| if [[ "$UPDATE_CHANNEL" == "stable" ]]; then | |
| identity="$(security find-identity -v -p codesigning "$keychain" \ | |
| | sed -n 's/.*"\(Developer ID Application:.*\)"/\1/p' | head -1)" | |
| else | |
| identity="$(security find-identity -v -p codesigning "$keychain" \ | |
| | sed -n \ | |
| -e 's/.*"\(Developer ID Application:.*\)"/\1/p' \ | |
| -e 's/.*"\(Apple Development:.*\)"/\1/p' \ | |
| | head -1)" | |
| fi | |
| if [[ -z "$identity" ]]; then | |
| echo "A compatible Apple code-signing identity was not found" >&2 | |
| exit 1 | |
| fi | |
| { | |
| echo "CI_KEYCHAIN=$keychain" | |
| echo "MACOS_SIGN_IDENTITY=$identity" | |
| } >> "$GITHUB_ENV" | |
| if [[ "$UPDATE_CHANNEL" == "stable" ]]; then | |
| notary_key="$RUNNER_TEMP/AuthKey.p8" | |
| notary_profile="gp-connect-ci" | |
| printf '%s' "$APPLE_NOTARY_KEY_P8" > "$notary_key" | |
| chmod 600 "$notary_key" | |
| xcrun notarytool store-credentials "$notary_profile" \ | |
| --key "$notary_key" \ | |
| --key-id "$APPLE_NOTARY_KEY_ID" \ | |
| --issuer "$APPLE_NOTARY_ISSUER_ID" \ | |
| --keychain "$keychain" | |
| { | |
| echo "APPLE_NOTARY_PROFILE=$notary_profile" | |
| echo "APPLE_NOTARY_KEYCHAIN=$keychain" | |
| } >> "$GITHUB_ENV" | |
| fi | |
| - name: Build macOS release artifacts | |
| env: | |
| SPARKLE_PUBLIC_KEY: ${{ vars.SPARKLE_PUBLIC_KEY }} | |
| run: | | |
| set -euo pipefail | |
| cd gpgui-source/gpgui | |
| if [[ "$UPDATE_CHANNEL" == "stable" ]]; then | |
| build_mode="release" | |
| else | |
| build_mode="development" | |
| export SPARKLE_CREATE_UPDATE_ARCHIVE=1 | |
| fi | |
| ./scripts/build-macos.sh dmg "$build_mode" | |
| - name: Prepare release assets | |
| run: | | |
| set -euo pipefail | |
| artifact_dir="gpgui-source/artifacts" | |
| mkdir -p "$artifact_dir" | |
| dmg_name="GPConnect_${MACOS_ARTIFACT_VERSION}_arm64.dmg" | |
| archive_name="GPConnect_${MACOS_ARTIFACT_VERSION}_arm64.zip" | |
| mv "gpgui-source/gpgui/target/release/bundle/dmg/GP Connect.dmg" \ | |
| "$artifact_dir/$dmg_name" | |
| mv "gpgui-source/gpgui/target/release/bundle/sparkle/$archive_name" \ | |
| "$artifact_dir/$archive_name" | |
| for file in "$artifact_dir"/*; do | |
| shasum -a 256 "$file" > "$file.sha256" | |
| done | |
| - name: Upload macOS artifacts | |
| uses: actions/upload-artifact@v7 | |
| with: | |
| name: artifact-gpgui-macos-arm64 | |
| if-no-files-found: error | |
| path: gpgui-source/artifacts/* | |
| - name: Remove signing keychain | |
| if: ${{ always() }} | |
| run: | | |
| if [[ -n "${CI_KEYCHAIN:-}" && -f "$CI_KEYCHAIN" ]]; then | |
| security delete-keychain "$CI_KEYCHAIN" | |
| fi | |
| setup-bsd-matrix: | |
| runs-on: ubuntu-latest | |
| outputs: | |
| enabled: ${{ steps.matrix.outputs.enabled }} | |
| matrix: ${{ steps.matrix.outputs.matrix }} | |
| steps: | |
| - name: Build matrix | |
| id: matrix | |
| env: | |
| IS_TAG: ${{ startsWith(github.ref, 'refs/tags/') }} | |
| BUILD_BSD: ${{ github.event_name == 'workflow_dispatch' && inputs.build_bsd }} | |
| BUILD_BSD_ARM64: ${{ github.event_name == 'workflow_dispatch' && inputs.build_bsd_arm64 }} | |
| run: | | |
| python3 - <<'PY' | |
| import json | |
| import os | |
| build_bsd = os.environ["IS_TAG"] == "true" or os.environ["BUILD_BSD"] == "true" | |
| build_bsd_arm64 = os.environ["BUILD_BSD_ARM64"] == "true" | |
| include = [] | |
| def add(os_name, arch): | |
| include.append({ | |
| "os": os_name, | |
| "arch": arch, | |
| "workspace": f"{os_name}-{arch}-source", | |
| "artifact": f"artifact-bsd-{os_name}-{arch}", | |
| "package_target": f"package-{os_name}", | |
| "artifact_dir": os_name, | |
| }) | |
| if build_bsd: | |
| add("freebsd", "x86_64") | |
| add("openbsd", "x86_64") | |
| if build_bsd_arm64: | |
| add("freebsd", "arm64") | |
| add("openbsd", "arm64") | |
| with open(os.environ["GITHUB_OUTPUT"], "a", encoding="utf-8") as output: | |
| output.write(f"enabled={str(bool(include)).lower()}\n") | |
| output.write(f"matrix={json.dumps({'include': include}, separators=(',', ':'))}\n") | |
| PY | |
| build-gpgui-frontend: | |
| needs: setup-bsd-matrix | |
| if: ${{ needs.setup-bsd-matrix.outputs.enabled == 'true' }} | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: pnpm/action-setup@v5 | |
| with: | |
| version: 9 | |
| - name: Prepare workspace | |
| run: rm -rf gpgui-frontend && mkdir gpgui-frontend | |
| - name: Checkout GlobalProtect-openconnect | |
| uses: actions/checkout@v6 | |
| with: | |
| token: ${{ secrets.GH_PAT }} | |
| repository: yuezk/GlobalProtect-openconnect | |
| ref: ${{ github.event_name == 'workflow_dispatch' && inputs.gp_branch || github.ref }} | |
| path: gpgui-frontend/gp | |
| submodules: recursive | |
| - name: Checkout gpgui | |
| uses: actions/checkout@v6 | |
| with: | |
| token: ${{ secrets.GH_PAT }} | |
| repository: yuezk/gpgui | |
| ref: ${{ github.event_name == 'workflow_dispatch' && inputs.gpgui_branch || github.ref_name }} | |
| path: gpgui-frontend/gpgui | |
| - name: Build gpgui frontend | |
| run: | | |
| cd gpgui-frontend/gpgui/app | |
| pnpm install --frozen-lockfile | |
| pnpm build | |
| - name: Upload gpgui frontend | |
| uses: actions/upload-artifact@v7 | |
| with: | |
| name: bsd-gpgui-frontend | |
| if-no-files-found: error | |
| path: gpgui-frontend/gpgui/app/dist/** | |
| build-bsd: | |
| needs: | |
| - setup-bsd-matrix | |
| - build-gpgui-frontend | |
| if: ${{ needs.setup-bsd-matrix.outputs.enabled == 'true' }} | |
| runs-on: ubuntu-latest | |
| name: build-${{ matrix.os }} (${{ matrix.arch }}) | |
| strategy: | |
| fail-fast: false | |
| matrix: ${{ fromJson(needs.setup-bsd-matrix.outputs.matrix) }} | |
| steps: | |
| - name: Prepare workspace | |
| run: rm -rf "${{ matrix.workspace }}" && mkdir "${{ matrix.workspace }}" | |
| - name: Checkout GlobalProtect-openconnect | |
| uses: actions/checkout@v6 | |
| with: | |
| token: ${{ secrets.GH_PAT }} | |
| repository: yuezk/GlobalProtect-openconnect | |
| ref: ${{ github.event_name == 'workflow_dispatch' && inputs.gp_branch || github.ref }} | |
| path: ${{ matrix.workspace }}/gp | |
| submodules: recursive | |
| - name: Checkout gpgui | |
| uses: actions/checkout@v6 | |
| with: | |
| token: ${{ secrets.GH_PAT }} | |
| repository: yuezk/gpgui | |
| ref: ${{ github.event_name == 'workflow_dispatch' && inputs.gpgui_branch || github.ref_name }} | |
| path: ${{ matrix.workspace }}/gpgui | |
| - name: Download gpgui frontend | |
| uses: actions/download-artifact@v8 | |
| with: | |
| name: bsd-gpgui-frontend | |
| path: ${{ matrix.workspace }}/gpgui/app/dist | |
| - name: Build on FreeBSD | |
| if: ${{ matrix.os == 'freebsd' }} | |
| uses: vmactions/freebsd-vm@v1 | |
| with: | |
| release: "14.3" | |
| arch: ${{ matrix.arch }} | |
| usesh: true | |
| prepare: | | |
| pkg install -y \ | |
| git \ | |
| rust \ | |
| libiconv \ | |
| gettext-tools \ | |
| autoconf \ | |
| automake \ | |
| libtool \ | |
| patch \ | |
| gmake \ | |
| pkgconf \ | |
| libxml2 \ | |
| gnutls \ | |
| p11-kit \ | |
| nettle \ | |
| gmp \ | |
| gnome-keyring \ | |
| libayatana-appindicator \ | |
| polkit \ | |
| webkit2-gtk_41 | |
| run: | | |
| set -eu | |
| cd "${{ matrix.workspace }}/gp" | |
| cargo build --release --workspace | |
| cd ../gpgui/app/src-tauri | |
| cargo build --release --workspace | |
| cd ../../../gp | |
| gmake "${{ matrix.package_target }}" GPGUI_BINARY=../gpgui/target/release/gpgui | |
| pkg install -y ".build/${{ matrix.artifact_dir }}"/artifacts/*.pkg | |
| gpclient --version | |
| gpauth --version | |
| gpgui --version | |
| rm -rf target ../gpgui/target | |
| find ".build/${{ matrix.artifact_dir }}" -mindepth 1 -maxdepth 1 ! -name artifacts -exec rm -rf {} + | |
| - name: Build on OpenBSD | |
| if: ${{ matrix.os == 'openbsd' }} | |
| uses: vmactions/openbsd-vm@v1 | |
| with: | |
| release: "7.9" | |
| arch: ${{ matrix.arch }} | |
| usesh: true | |
| prepare: | | |
| pkg_add -z \ | |
| git \ | |
| rust \ | |
| libiconv \ | |
| gettext-tools \ | |
| autoconf-2.72 \ | |
| automake-1.17 \ | |
| libtool \ | |
| patch \ | |
| gmake \ | |
| pkgconf \ | |
| libxml \ | |
| gnutls \ | |
| p11-kit \ | |
| nettle \ | |
| gmp \ | |
| gnome-keyring \ | |
| polkit \ | |
| webkitgtk41 | |
| ln -sf /usr/local/bin/autoreconf-2.72 /usr/local/bin/autoreconf | |
| ln -sf /usr/local/bin/autoconf-2.72 /usr/local/bin/autoconf | |
| ln -sf /usr/local/bin/autoheader-2.72 /usr/local/bin/autoheader | |
| ln -sf /usr/local/bin/autom4te-2.72 /usr/local/bin/autom4te | |
| ln -sf /usr/local/bin/aclocal-1.17 /usr/local/bin/aclocal | |
| ln -sf /usr/local/bin/automake-1.17 /usr/local/bin/automake | |
| run: | | |
| set -eu | |
| export AUTOCONF_VERSION=2.72 | |
| export AUTOMAKE_VERSION=1.17 | |
| cd "${{ matrix.workspace }}/gp" | |
| cargo build --release --workspace | |
| cd ../gpgui/app/src-tauri | |
| cargo build --release --workspace | |
| cd ../../../gp | |
| gmake "${{ matrix.package_target }}" GPGUI_BINARY=../gpgui/target/release/gpgui | |
| pkg_add -D unsigned ".build/${{ matrix.artifact_dir }}"/artifacts/*.tgz | |
| gpclient --version | |
| gpauth --version | |
| gpgui --version | |
| rm -rf target ../gpgui/target | |
| find ".build/${{ matrix.artifact_dir }}" -mindepth 1 -maxdepth 1 ! -name artifacts -exec rm -rf {} + | |
| - name: Upload BSD package | |
| uses: actions/upload-artifact@v7 | |
| with: | |
| name: ${{ matrix.artifact }} | |
| if-no-files-found: error | |
| path: | | |
| ${{ matrix.workspace }}/gp/.build/${{ matrix.artifact_dir }}/artifacts/* | |
| gh-release: | |
| if: ${{ always() && (github.event_name == 'workflow_dispatch' || startsWith(github.ref, 'refs/tags/')) }} | |
| runs-on: ubuntu-latest | |
| permissions: | |
| actions: read | |
| contents: read | |
| id-token: write | |
| attestations: write | |
| artifact-metadata: write | |
| needs: | |
| - tarball | |
| - tarball-offline | |
| - build-gp | |
| - build-docker-image | |
| - build-gpgui | |
| - build-gpgui-macos | |
| - setup-bsd-matrix | |
| - build-gpgui-frontend | |
| - build-bsd | |
| steps: | |
| - name: Check required jobs | |
| env: | |
| NEEDS_JSON: ${{ toJson(needs) }} | |
| BSD_MATRIX_ENABLED: ${{ needs.setup-bsd-matrix.outputs.enabled }} | |
| MACOS_BUILD_ENABLED: ${{ startsWith(github.ref, 'refs/tags/') || inputs.build_macos }} | |
| IS_TAG: ${{ startsWith(github.ref, 'refs/tags/') }} | |
| run: | | |
| python3 - <<'PY' | |
| import json | |
| import os | |
| import sys | |
| needs = json.loads(os.environ["NEEDS_JSON"]) | |
| bsd_matrix_enabled = os.environ["BSD_MATRIX_ENABLED"] == "true" | |
| macos_build_enabled = os.environ["MACOS_BUILD_ENABLED"] == "true" | |
| is_tag = os.environ["IS_TAG"] == "true" | |
| failed = [] | |
| for name, data in needs.items(): | |
| result = data["result"] | |
| if result in {"failure", "cancelled"}: | |
| failed.append(f"{name}: {result}") | |
| elif name in {"build-gp", "build-docker-image"} and result == "skipped" and is_tag: | |
| continue | |
| elif name in {"build-gpgui-frontend", "build-bsd"} and result == "skipped" and not bsd_matrix_enabled: | |
| continue | |
| elif name == "build-gpgui-macos" and result == "skipped" and not macos_build_enabled: | |
| continue | |
| elif result == "skipped": | |
| failed.append(f"{name}: {result}") | |
| if failed: | |
| print("Required jobs did not complete successfully:") | |
| for item in failed: | |
| print(f" - {item}") | |
| sys.exit(1) | |
| PY | |
| - name: Prepare workspace | |
| run: rm -rf gh-release && mkdir gh-release | |
| - name: Checkout GlobalProtect-openconnect | |
| uses: actions/checkout@v6 | |
| with: | |
| token: ${{ secrets.GH_PAT }} | |
| repository: yuezk/GlobalProtect-openconnect | |
| ref: ${{ github.event_name == 'workflow_dispatch' && inputs.gp_branch || github.ref }} | |
| path: gh-release/gp | |
| submodules: recursive | |
| - name: Download all artifacts | |
| uses: actions/download-artifact@v8 | |
| with: | |
| path: gh-release/gp/.build/artifacts | |
| - name: Rename APK artifacts | |
| run: | | |
| shopt -s nullglob | |
| for file in gh-release/gp/.build/artifacts/artifact-gp-apk-amd64/*.apk; do | |
| mv "$file" "${file%.apk}-x86_64.apk" | |
| done | |
| for file in gh-release/gp/.build/artifacts/artifact-gp-apk-ubuntu-24.04-arm/*.apk; do | |
| mv "$file" "${file%.apk}-aarch64.apk" | |
| done | |
| - name: Generate release asset checksums | |
| env: | |
| RELEASE_TAG: ${{ github.event_name == 'workflow_dispatch' && 'snapshot' || github.ref_name }} | |
| run: | | |
| cd gh-release/gp | |
| mkdir -p .build | |
| scripts/release-assets.sh "$RELEASE_TAG" > .build/release-assets.txt | |
| if [ ! -s .build/release-assets.txt ]; then | |
| echo "No release assets found" | |
| exit 1 | |
| fi | |
| while IFS= read -r file; do | |
| digest=$(sha256sum "$file" | cut -d ' ' -f 1) | |
| printf '%s %s\n' "$digest" "$(basename "$file")" | |
| done < .build/release-assets.txt > .build/release-assets.sha256 | |
| - name: Attest release assets | |
| uses: actions/attest-build-provenance@v4 | |
| with: | |
| subject-checksums: gh-release/gp/.build/release-assets.sha256 | |
| - name: Create GH release | |
| env: | |
| GH_TOKEN: ${{ secrets.GH_PAT }} | |
| RELEASE_TAG: ${{ github.event_name == 'workflow_dispatch' && 'snapshot' || github.ref_name }} | |
| run: | | |
| cd gh-release/gp/scripts && ./gh-release.sh "$RELEASE_TAG" | |
| publish-macos-appcast: | |
| if: ${{ always() && needs.gh-release.result == 'success' && needs.build-gpgui-macos.result == 'success' }} | |
| permissions: | |
| contents: write | |
| needs: | |
| - gh-release | |
| - build-gpgui-macos | |
| uses: ./.github/workflows/publish-macos-appcast.yaml | |
| with: | |
| channel: ${{ github.event_name == 'workflow_dispatch' && 'snapshot' || 'stable' }} | |
| release_tag: ${{ github.event_name == 'workflow_dispatch' && 'snapshot' || github.ref_name }} | |
| archive_name: ${{ needs.build-gpgui-macos.outputs.archive_name }} | |
| secrets: inherit | |
| publish-docker-image: | |
| needs: | |
| - build-docker-image | |
| if: ${{ github.event_name == 'workflow_dispatch' || startsWith(github.ref, 'refs/tags/') }} | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Download digests | |
| uses: actions/download-artifact@v8 | |
| with: | |
| path: /tmp/digests | |
| pattern: digests-* | |
| merge-multiple: true | |
| - name: Set up Docker Buildx | |
| uses: docker/setup-buildx-action@v4 | |
| - name: Login to Docker Hub | |
| uses: docker/login-action@v4 | |
| with: | |
| username: ${{ secrets.DOCKER_HUB_USERNAME }} | |
| password: ${{ secrets.DOCKER_HUB_TOKEN }} | |
| - name: Publish Docker manifest | |
| working-directory: /tmp/digests | |
| env: | |
| IMAGE: yuezk/globalprotect-openconnect | |
| RELEASE_TAG: ${{ github.event_name == 'workflow_dispatch' && 'snapshot' || github.ref_name }} | |
| run: | | |
| docker buildx imagetools create -t "$IMAGE:$RELEASE_TAG" \ | |
| $(printf "$IMAGE@sha256:%s " *) | |
| docker buildx imagetools inspect "$IMAGE:$RELEASE_TAG" |