Skip to content

test: rename cli -> headless (fork re-test) #4

test: rename cli -> headless (fork re-test)

test: rename cli -> headless (fork re-test) #4

Workflow file for this run

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_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:
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/*
# GUI-free variant, for the headless servers README.md names as the audience
# for `--browser remote`. Same source and same builder images as build-gp;
# only the three GUI flags differ, which #638 made effective for `depends=`.
#
# Scoped to apk and deb: those are the two formats whose depends= is gated on
# the flags today (Makefile `init-apk` / `init-debian`). An rpm built this way
# would still declare the GUI dependencies, so a "CLI" rpm would mislead.
build-gp-headless:
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: [apk, deb]
runs-on: ${{ matrix.os.runner }}
name: build-gp-headless (${{ matrix.package }}, ${{ matrix.os.arch }})
steps:
- name: Prepare workspace
run: |
rm -rf build-gp-headless-${{ matrix.package }}
mkdir -p build-gp-headless-${{ matrix.package }}
- name: Download tarball
uses: actions/download-artifact@v8
with:
name: artifact-source
path: build-gp-headless-${{ matrix.package }}
- name: Build GUI-free ${{ matrix.package }} package in Docker
run: |
docker run --rm \
-e COREPACK_INTEGRITY_KEYS=0 \
-e LIBXML2_STATIC=1 \
-e INCLUDE_GUI=0 \
-e BUILD_GUI_HELPER=0 \
-e BUILD_WEBVIEW_AUTH=0 \
-v $(pwd)/build-gp-headless-${{ matrix.package }}:/workspace \
yuezk/gpdev:${{ matrix.package }}-builder-tauri2
# Not `bash install.sh`: that script checks `gpgui-helper --version`
# unconditionally, and BUILD_GUI_HELPER=0 means it isn't built. Its
# GPGUI_INSTALLED knob covers gpgui but not the helper. Rather than ask for
# a new knob in the builder image, this asserts the property that actually
# matters for the variant — the CLI binaries work and no GUI binary shipped.
- name: Verify GUI-free ${{ matrix.package }} package in Docker
run: |
docker run --rm \
-e COREPACK_INTEGRITY_KEYS=0 \
-v $(pwd)/build-gp-headless-${{ matrix.package }}:/workspace \
--entrypoint /bin/bash \
yuezk/gpdev:${{ matrix.package }}-builder-tauri2 -lc '
set -eux
if command -v apk >/dev/null; then
sudo apk add --allow-untrusted /workspace/artifacts/*.apk
else
sudo apt-get install -y /workspace/artifacts/*.deb
fi
gpclient --version
gpservice --version
gpauth --version
! command -v gpgui-helper
! command -v gpgui
'
- name: Upload GUI-free ${{ matrix.package }} package
uses: actions/upload-artifact@v7
with:
name: artifact-gp-headless-${{ matrix.package }}-${{ matrix.os.arch }}
if-no-files-found: error
path: |
build-gp-headless-${{ 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: 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
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.4"
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
- 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 }}
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"
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 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-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"