mirror of
https://github.com/netbirdio/netbird.git
synced 2026-09-26 16:49:08 +02:00
Inline the job in release.yml, gated on a stable vX.Y.Z tag on the upstream repo so it stays out of main, release branches and pull requests. Its env and contents:read permission move to the job, keeping them off the rest of the workflow.
1079 lines
47 KiB
YAML
1079 lines
47 KiB
YAML
name: Release
|
|
|
|
on:
|
|
push:
|
|
tags:
|
|
- "v*"
|
|
branches:
|
|
- main
|
|
- "release-*"
|
|
pull_request:
|
|
|
|
env:
|
|
SIGN_PIPE_VER: "v0.1.8"
|
|
GORELEASER_VER: "v2.16.0"
|
|
PRODUCT_NAME: "NetBird"
|
|
COPYRIGHT: "NetBird GmbH"
|
|
flags: ""
|
|
SKIP_PUBLISH: "true"
|
|
SKIP_DOCKER_PUSH: "false"
|
|
|
|
concurrency:
|
|
group: ${{ github.workflow }}-${{ github.ref }}-${{ github.head_ref || github.actor_id }}
|
|
cancel-in-progress: true
|
|
|
|
jobs:
|
|
release_freebsd_port:
|
|
name: "FreeBSD Port / Build & Test"
|
|
runs-on: ubuntu-22.04
|
|
steps:
|
|
- name: Checkout
|
|
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
|
with:
|
|
persist-credentials: false
|
|
|
|
- name: Generate FreeBSD port diff
|
|
run: bash -x release_files/freebsd-port-diff.sh
|
|
|
|
- name: Generate FreeBSD port issue body
|
|
run: bash -x release_files/freebsd-port-issue-body.sh
|
|
|
|
- name: Check if diff was generated
|
|
id: check_diff
|
|
run: |
|
|
if ls netbird-*.diff 1> /dev/null 2>&1; then
|
|
echo "diff_exists=true" >> $GITHUB_OUTPUT
|
|
else
|
|
echo "diff_exists=false" >> $GITHUB_OUTPUT
|
|
echo "No diff file generated (port may already be up to date)"
|
|
fi
|
|
|
|
- name: Extract version
|
|
if: steps.check_diff.outputs.diff_exists == 'true'
|
|
id: version
|
|
run: |
|
|
VERSION=$(ls netbird-*.diff | sed 's/netbird-\(.*\)\.diff/\1/')
|
|
echo "version=$VERSION" >> $GITHUB_OUTPUT
|
|
echo "Generated files for version: $VERSION"
|
|
cat netbird-*.diff
|
|
|
|
- name: Read Go version from go.mod
|
|
id: goversion
|
|
run: echo "version=$(awk '/^go / {print $2}' go.mod)" >> "$GITHUB_OUTPUT"
|
|
|
|
- name: Test FreeBSD port
|
|
if: steps.check_diff.outputs.diff_exists == 'true'
|
|
env:
|
|
GO_VERSION: ${{ steps.goversion.outputs.version }}
|
|
uses: vmactions/freebsd-vm@b84ab5559b5a1bb4b8ee2737d2506a16e1737636 # v1.4.8
|
|
with:
|
|
usesh: true
|
|
copyback: false
|
|
release: "15.0"
|
|
envs: "GO_VERSION"
|
|
prepare: |
|
|
# Install required packages
|
|
pkg install -y git curl portlint
|
|
|
|
# Install Go for building
|
|
GO_TARBALL="go${GO_VERSION}.freebsd-amd64.tar.gz"
|
|
GO_URL="https://go.dev/dl/$GO_TARBALL"
|
|
curl -LO "$GO_URL"
|
|
tar -C /usr/local -xzf "$GO_TARBALL"
|
|
|
|
# Clone ports tree (shallow, only what we need)
|
|
git clone --depth 1 --filter=blob:none https://git.FreeBSD.org/ports.git /usr/ports
|
|
cd /usr/ports
|
|
|
|
run: |
|
|
set -e -x
|
|
export PATH=$PATH:/usr/local/go/bin
|
|
|
|
# Find the diff file
|
|
echo "Finding diff file..."
|
|
DIFF_FILE=$(find $PWD -name "netbird-*.diff" -type f 2>/dev/null | head -1)
|
|
echo "Found: $DIFF_FILE"
|
|
|
|
if [[ -z "$DIFF_FILE" ]]; then
|
|
echo "ERROR: Could not find diff file"
|
|
find ~ -name "*.diff" -type f 2>/dev/null || true
|
|
exit 1
|
|
fi
|
|
|
|
# Apply the generated diff from /usr/ports (diff has a/security/netbird/... paths)
|
|
cd /usr/ports
|
|
patch -p1 -V none < "$DIFF_FILE"
|
|
|
|
# Show patched Makefile
|
|
version=$(cat security/netbird/Makefile | grep -E '^DISTVERSION=' | awk '{print $NF}')
|
|
|
|
cd /usr/ports/security/netbird
|
|
export BATCH=yes
|
|
make package
|
|
pkg add ./work/pkg/netbird-*.pkg
|
|
|
|
netbird version | grep "$version"
|
|
|
|
echo "FreeBSD port test completed successfully!"
|
|
|
|
- name: Upload FreeBSD port files
|
|
if: steps.check_diff.outputs.diff_exists == 'true'
|
|
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a #v7.0.1
|
|
with:
|
|
name: freebsd-port-files
|
|
path: |
|
|
./netbird-*-issue.txt
|
|
./netbird-*.diff
|
|
retention-days: 30
|
|
|
|
release:
|
|
runs-on: ubuntu-24.04-8-core
|
|
outputs:
|
|
release_artifact_url: ${{ steps.upload_release.outputs.artifact-url }}
|
|
linux_packages_artifact_url: ${{ steps.upload_linux_packages.outputs.artifact-url }}
|
|
windows_packages_artifact_url: ${{ steps.upload_windows_packages.outputs.artifact-url }}
|
|
macos_packages_artifact_url: ${{ steps.upload_macos_packages.outputs.artifact-url }}
|
|
ghcr_images: ${{ steps.tag_and_push_images.outputs.images_markdown }}
|
|
steps:
|
|
- name: Checkout
|
|
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
|
with:
|
|
fetch-depth: 0 # It is required for GoReleaser to work properly
|
|
persist-credentials: false
|
|
|
|
- name: Parse semver string
|
|
id: semver_parser
|
|
uses: netbirdio/shared-actions/actions/parse-semver@be5df6047383da2236e02243cceb857d8567c27e # v0.0.2
|
|
|
|
- name: Set snapshot flag
|
|
if: ${{ !startsWith(github.ref, 'refs/tags/v') }}
|
|
run: |
|
|
echo "flags=--snapshot" >> $GITHUB_ENV
|
|
|
|
- name: Set build vars
|
|
if: ${{ startsWith(github.ref, 'refs/tags/v') }}
|
|
run: |
|
|
if [[ "x-${{ steps.semver_parser.outputs.prerelease }}" == "x-" && "x-${{ github.repository }}" == "x-netbirdio/netbird" ]]; then
|
|
echo "x-${{ github.repository }}"
|
|
echo "x-${{ steps.semver_parser.outputs.prerelease }}"
|
|
echo "SKIP_PUBLISH=false" >> $GITHUB_ENV
|
|
else
|
|
echo "x-${{ github.repository }}"
|
|
echo "x-${{ steps.semver_parser.outputs.prerelease }}"
|
|
fi
|
|
|
|
if [[ "x-${{ github.repository }}" != "x-netbirdio/netbird" ]]; then
|
|
echo "SKIP_DOCKER_PUSH=true" >> $GITHUB_ENV
|
|
fi
|
|
|
|
- name: Set up Go
|
|
uses: actions/setup-go@924ae3a1cded613372ab5595356fb5720e22ba16 # v6.5.0
|
|
with:
|
|
go-version-file: "go.mod"
|
|
cache: false
|
|
- name: Cache Go modules
|
|
uses: actions/cache/restore@2c8a9bd7457de244a408f35966fab2fb45fda9c8 # v6.0.0
|
|
with:
|
|
path: |
|
|
~/go/pkg/mod
|
|
~/.cache/go-build
|
|
key: ${{ runner.os }}-go-releaser-${{ hashFiles('**/go.sum') }}
|
|
restore-keys: |
|
|
${{ runner.os }}-go-releaser-
|
|
- name: Install modules
|
|
run: go mod tidy
|
|
- name: run openapi generator
|
|
run: bash shared/management/http/api/generate.sh
|
|
- name: check git status
|
|
run: git --no-pager diff --exit-code
|
|
- name: Generate RPM changelog from git tags
|
|
# nfpm embeds changelog.yml into the RPM; Red Hat software certification
|
|
# requires a changelog. Generated, not committed (see .gitignore).
|
|
# chglog is a go.mod tool directive, so go.sum pins it and its deps.
|
|
run: bash release_files/rpm-changelog.sh
|
|
- name: Fill the RPM ISA provide version
|
|
# nfpm cannot emit rpmbuild's ISA provide and GoReleaser cannot template it.
|
|
run: bash release_files/rpm-provides.sh
|
|
- name: Set up QEMU
|
|
uses: docker/setup-qemu-action@06116385d9baf250c9f4dcb4858b16962ea869c3 #v4.1.0
|
|
- name: Set up Docker Buildx
|
|
uses: docker/setup-buildx-action@d7f5e7f509e45cec5c76c4d5afdd7de93d0b3df5 #v4.1.0
|
|
- name: Login to Docker hub
|
|
if: github.event_name != 'pull_request'
|
|
uses: docker/login-action@650006c6eb7dba73a995cc03b0b2d7f5ca915bee # v4.2.0
|
|
with:
|
|
username: ${{ secrets.DOCKER_USER }}
|
|
password: ${{ secrets.DOCKER_TOKEN }}
|
|
- name: Log in to the GitHub container registry
|
|
if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository
|
|
uses: docker/login-action@650006c6eb7dba73a995cc03b0b2d7f5ca915bee # v4.2.0
|
|
with:
|
|
registry: ghcr.io
|
|
username: ${{ github.actor }}
|
|
password: ${{ secrets.CI_DOCKER_PUSH_GITHUB_TOKEN }}
|
|
- name: Install OS build dependencies
|
|
run: sudo apt update && sudo apt install -y -q gcc-arm-linux-gnueabihf gcc-aarch64-linux-gnu
|
|
|
|
- name: Decode GPG signing key
|
|
if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository
|
|
env:
|
|
GPG_RPM_PRIVATE_KEY: ${{ secrets.GPG_RPM_PRIVATE_KEY }}
|
|
run: |
|
|
echo "$GPG_RPM_PRIVATE_KEY" | base64 -d > /tmp/gpg-rpm-signing-key.asc
|
|
echo "GPG_RPM_KEY_FILE=/tmp/gpg-rpm-signing-key.asc" >> $GITHUB_ENV
|
|
|
|
- name: Install goversioninfo
|
|
run: go install github.com/josephspurrier/goversioninfo/cmd/goversioninfo@b66839b # v1.7.0
|
|
- name: Generate windows syso amd64
|
|
run: goversioninfo -icon client/ui/build/windows/icon.ico -manifest client/manifest.xml -product-name ${{ env.PRODUCT_NAME }} -copyright "${{ env.COPYRIGHT }}" -ver-major ${{ steps.semver_parser.outputs.major }} -ver-minor ${{ steps.semver_parser.outputs.minor }} -ver-patch ${{ steps.semver_parser.outputs.patch }} -ver-build 0 -file-version ${{ steps.semver_parser.outputs.fullversion }}.0 -product-version ${{ steps.semver_parser.outputs.fullversion }}.0 -o client/resources_windows_amd64.syso
|
|
- name: Generate windows syso arm64
|
|
run: goversioninfo -arm -64 -icon client/ui/build/windows/icon.ico -manifest client/manifest.xml -product-name ${{ env.PRODUCT_NAME }} -copyright "${{ env.COPYRIGHT }}" -ver-major ${{ steps.semver_parser.outputs.major }} -ver-minor ${{ steps.semver_parser.outputs.minor }} -ver-patch ${{ steps.semver_parser.outputs.patch }} -ver-build 0 -file-version ${{ steps.semver_parser.outputs.fullversion }}.0 -product-version ${{ steps.semver_parser.outputs.fullversion }}.0 -o client/resources_windows_arm64.syso
|
|
- name: Run GoReleaser
|
|
id: goreleaser
|
|
uses: goreleaser/goreleaser-action@5daf1e915a5f0af01ddbcd89a43b8061ff4f1a89 # v7.2.2
|
|
with:
|
|
version: ${{ env.GORELEASER_VER }}
|
|
args: release --config .goreleaser.generated.yaml --clean ${{ env.flags }}
|
|
env:
|
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
HOMEBREW_TAP_GITHUB_TOKEN: ${{ secrets.HOMEBREW_TAP_GITHUB_TOKEN }}
|
|
UPLOAD_DEBIAN_SECRET: ${{ secrets.PKG_UPLOAD_SECRET }}
|
|
UPLOAD_YUM_SECRET: ${{ secrets.PKG_UPLOAD_SECRET }}
|
|
GPG_RPM_KEY_FILE: ${{ env.GPG_RPM_KEY_FILE }}
|
|
# One per nfpm id: GoReleaser looks the passphrase up as NFPM_<ID>_PASSPHRASE.
|
|
NFPM_NETBIRD_RPM_AMD64_PASSPHRASE: ${{ secrets.GPG_RPM_PASSPHRASE }}
|
|
NFPM_NETBIRD_RPM_ARM64_PASSPHRASE: ${{ secrets.GPG_RPM_PASSPHRASE }}
|
|
NFPM_NETBIRD_RPM_ARM_PASSPHRASE: ${{ secrets.GPG_RPM_PASSPHRASE }}
|
|
NFPM_NETBIRD_RPM_386_PASSPHRASE: ${{ secrets.GPG_RPM_PASSPHRASE }}
|
|
SKIP_PUBLISH: ${{ env.SKIP_PUBLISH }}
|
|
SKIP_DOCKER_PUSH: ${{ env.SKIP_DOCKER_PUSH }}
|
|
- name: Verify RPM signatures
|
|
run: |
|
|
docker run --rm -v $(pwd)/dist:/dist fedora:41 bash -c '
|
|
dnf install -y -q rpm-sign curl >/dev/null 2>&1
|
|
curl -sSL https://pkgs.netbird.io/yum/repodata/repomd.xml.key -o /tmp/rpm-pub.key
|
|
rpm --import /tmp/rpm-pub.key
|
|
echo "=== Verifying RPM signatures ==="
|
|
for rpm_file in /dist/*amd64*.rpm; do
|
|
[ -f "$rpm_file" ] || continue
|
|
echo "--- $(basename $rpm_file) ---"
|
|
rpm -K "$rpm_file"
|
|
done
|
|
'
|
|
- name: Clean up GPG key
|
|
if: always()
|
|
run: rm -f /tmp/gpg-rpm-signing-key.asc
|
|
- name: Tag and push images (amd64 only)
|
|
id: tag_and_push_images
|
|
if: |
|
|
(github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name == github.repository) ||
|
|
(github.event_name == 'push' && (github.ref == 'refs/heads/main' || startsWith(github.ref, 'refs/heads/release-')))
|
|
run: |
|
|
set -euo pipefail
|
|
|
|
# $GITHUB_REF / $GITHUB_EVENT_NAME are read from the runner
|
|
# environment rather than substituted into this script with the
|
|
# workflow expression syntax: branch names may legally contain
|
|
# $(…), and interpolating github.ref would execute it.
|
|
resolve_tags() {
|
|
if [[ "$GITHUB_EVENT_NAME" == "pull_request" ]]; then
|
|
echo "pr-${{ github.event.pull_request.number }}"
|
|
elif [[ "$GITHUB_REF" == "refs/heads/main" ]]; then
|
|
echo "main sha-$(git rev-parse --short HEAD)"
|
|
else
|
|
# Release branches get an immutable sha-* tag only — the floating
|
|
# "main" tag must never move from a release branch.
|
|
echo "sha-$(git rev-parse --short HEAD)"
|
|
fi
|
|
}
|
|
|
|
ghcr_package_url() {
|
|
local image="$1" package encoded_package
|
|
package="${image#ghcr.io/}"
|
|
package="${package#*/}"
|
|
package="${package%%:*}"
|
|
encoded_package="${package//\//%2F}"
|
|
echo "https://github.com/orgs/netbirdio/packages/container/package/${encoded_package}"
|
|
}
|
|
|
|
image_refs=()
|
|
|
|
tag_and_push() {
|
|
local src="$1" img_name tag dst variant=""
|
|
img_name="${src%%:*}"
|
|
# Client variants share a repository, so keep their tag suffixes.
|
|
case "$src" in
|
|
*-rootless-ubi-amd64) variant="-rootless-ubi" ;;
|
|
*-rootless-amd64) variant="-rootless" ;;
|
|
esac
|
|
for tag in $(resolve_tags); do
|
|
dst="${img_name}:${tag}${variant}"
|
|
echo "Tagging ${src} -> ${dst}"
|
|
docker tag "$src" "$dst"
|
|
docker push "$dst"
|
|
image_refs+=("$dst")
|
|
done
|
|
}
|
|
|
|
cat > /tmp/goreleaser-artifacts.json <<'JSON'
|
|
${{ steps.goreleaser.outputs.artifacts }}
|
|
JSON
|
|
|
|
# dockers_v2 artifacts have no top-level goarch field, so match the
|
|
# per-platform -amd64 tag suffix instead; it works for both the old
|
|
# dockers and the new dockers_v2 image naming.
|
|
mapfile -t src_images < <(
|
|
jq -r '.[] | select(.type == "Docker Image") | .name | select(startswith("ghcr.io/") and endswith("-amd64"))' /tmp/goreleaser-artifacts.json
|
|
)
|
|
|
|
for src in "${src_images[@]}"; do
|
|
tag_and_push "$src"
|
|
done
|
|
|
|
{
|
|
echo "images_markdown<<EOF"
|
|
if [[ ${#image_refs[@]} -eq 0 ]]; then
|
|
echo "_No GHCR images were pushed._"
|
|
else
|
|
printf '%s\n' "${image_refs[@]}" | sort -u | while read -r image; do
|
|
printf -- '- [`%s`](%s)\n' "$image" "$(ghcr_package_url "$image")"
|
|
done
|
|
fi
|
|
echo "EOF"
|
|
} >> "$GITHUB_OUTPUT"
|
|
- name: upload non tags for debug purposes
|
|
id: upload_release
|
|
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a #v7.0.1
|
|
with:
|
|
name: release
|
|
path: dist/
|
|
retention-days: 7
|
|
- name: upload linux packages
|
|
id: upload_linux_packages
|
|
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a #v7.0.1
|
|
with:
|
|
name: linux-packages
|
|
path: dist/netbird_linux**
|
|
retention-days: 7
|
|
- name: upload windows packages
|
|
id: upload_windows_packages
|
|
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a #v7.0.1
|
|
with:
|
|
name: windows-packages
|
|
path: dist/netbird_windows**
|
|
retention-days: 7
|
|
- name: upload macos packages
|
|
id: upload_macos_packages
|
|
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a #v7.0.1
|
|
with:
|
|
name: macos-packages
|
|
path: dist/netbird_darwin**
|
|
retention-days: 7
|
|
|
|
# Certify and publish the rootless UBI client image in the Red Hat Ecosystem
|
|
# Catalog. Stable tags only: goreleaser pushes <version>-rootless-ubi to
|
|
# ghcr.io in the release job above, and preflight submits every architecture
|
|
# of that manifest list to Pyxis. Auto-publish on the component makes the new
|
|
# version public once certification passes.
|
|
redhat_certification:
|
|
name: "Red Hat / Certify rootless UBI image"
|
|
needs: release
|
|
if: |
|
|
github.repository == 'netbirdio/netbird' &&
|
|
startsWith(github.ref, 'refs/tags/v') &&
|
|
!contains(github.ref_name, '-')
|
|
runs-on: ubuntu-24.04
|
|
permissions:
|
|
contents: read
|
|
env:
|
|
PREFLIGHT_VERSION: "1.21.0"
|
|
# sha256 of preflight-linux-amd64 from the 1.21.0 GitHub release.
|
|
# Red Hat publishes no checksum file, so the value is pinned here.
|
|
PREFLIGHT_SHA256: "5e653135503c72f8702bbe31d7643197d12937c68086879133dd6b9650a9a449"
|
|
IMAGE_REPOSITORY: "ghcr.io/netbirdio/netbird"
|
|
# Component "NetBird Client Container Image (rootless)" in Partner Connect.
|
|
# Override with the REDHAT_CERT_COMPONENT_ID repository variable if it changes.
|
|
DEFAULT_COMPONENT_ID: "6aa3ca4b4676aefdf07aaa97"
|
|
steps:
|
|
- name: Resolve image reference
|
|
id: image
|
|
env:
|
|
INPUT_VERSION: ${{ github.ref_name }}
|
|
run: |
|
|
set -euo pipefail
|
|
version="${INPUT_VERSION#v}"
|
|
if [[ ! "$version" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
|
|
echo "::error::Only stable x.y.z versions are certified, got '${INPUT_VERSION}'"
|
|
exit 1
|
|
fi
|
|
echo "version=${version}" >> "$GITHUB_OUTPUT"
|
|
echo "ref=${IMAGE_REPOSITORY}:${version}-rootless-ubi" >> "$GITHUB_OUTPUT"
|
|
|
|
- name: Verify the multi-arch image is on ghcr.io
|
|
env:
|
|
IMAGE_REF: ${{ steps.image.outputs.ref }}
|
|
run: |
|
|
set -euo pipefail
|
|
docker buildx imagetools inspect "$IMAGE_REF" --raw > manifest.json
|
|
for arch in amd64 arm64; do
|
|
if ! jq -e --arg a "$arch" '.manifests[] | select(.platform.architecture == $a)' manifest.json > /dev/null; then
|
|
echo "::error::${IMAGE_REF} has no ${arch} manifest"
|
|
exit 1
|
|
fi
|
|
done
|
|
echo "Manifest list for ${IMAGE_REF}:"
|
|
jq -r '.manifests[] | "\(.platform.os)/\(.platform.architecture) \(.digest)"' manifest.json
|
|
|
|
- name: Install preflight
|
|
run: |
|
|
set -euo pipefail
|
|
curl -fsSL --proto '=https' --proto-redir '=https' -o preflight \
|
|
"https://github.com/redhat-openshift-ecosystem/openshift-preflight/releases/download/${PREFLIGHT_VERSION}/preflight-linux-amd64"
|
|
echo "${PREFLIGHT_SHA256} preflight" | sha256sum -c -
|
|
chmod +x preflight
|
|
./preflight --version
|
|
|
|
- name: Run preflight checks and submit to Red Hat
|
|
env:
|
|
IMAGE_REF: ${{ steps.image.outputs.ref }}
|
|
PFLT_PYXIS_API_TOKEN: ${{ secrets.PYXIS_API_TOKEN }}
|
|
PFLT_CERTIFICATION_COMPONENT_ID: ${{ vars.REDHAT_CERT_COMPONENT_ID || env.DEFAULT_COMPONENT_ID }}
|
|
PFLT_ARTIFACTS: artifacts
|
|
PFLT_LOGFILE: artifacts/preflight.log
|
|
PFLT_LOGLEVEL: info
|
|
PFLT_JUNIT: "true"
|
|
run: |
|
|
set -euo pipefail
|
|
# No --platform: preflight walks the manifest list and submits every
|
|
# architecture in one run, grouped under one manifest-list digest.
|
|
./preflight check container "$IMAGE_REF" --submit
|
|
|
|
- name: Fail if any check did not pass
|
|
run: |
|
|
set -euo pipefail
|
|
shopt -s nullglob
|
|
results=(artifacts/results.json artifacts/*/results.json)
|
|
if [[ ${#results[@]} -eq 0 ]]; then
|
|
echo "::error::preflight produced no results.json"
|
|
exit 1
|
|
fi
|
|
status=0
|
|
for f in "${results[@]}"; do
|
|
arch="$(basename "$(dirname "$f")")"
|
|
passed="$(jq -r '.passed' "$f")"
|
|
failed="$(jq -r '[.results.failed[]?.name] | join(", ")' "$f")"
|
|
echo "${arch}: passed=${passed} ${failed:+failed checks: ${failed}}"
|
|
[[ "$passed" == "true" ]] || status=1
|
|
done
|
|
exit $status
|
|
|
|
- name: Upload preflight artifacts
|
|
if: always()
|
|
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
|
|
with:
|
|
name: redhat-preflight-${{ steps.image.outputs.version }}
|
|
path: artifacts/
|
|
retention-days: 30
|
|
|
|
- name: Wait for Pyxis to mark both architectures certified
|
|
env:
|
|
VERSION: ${{ steps.image.outputs.version }}
|
|
PFLT_PYXIS_API_TOKEN: ${{ secrets.PYXIS_API_TOKEN }}
|
|
COMPONENT_ID: ${{ vars.REDHAT_CERT_COMPONENT_ID || env.DEFAULT_COMPONENT_ID }}
|
|
run: |
|
|
set -euo pipefail
|
|
tag="${VERSION}-rootless-ubi"
|
|
url="https://catalog.redhat.com/api/containers/v1/projects/certification/id/${COMPONENT_ID}/images?page_size=100"
|
|
for attempt in $(seq 1 20); do
|
|
certified="$(curl -fsS --proto '=https' --proto-redir '=https' -H "X-API-KEY: ${PFLT_PYXIS_API_TOKEN}" "$url" \
|
|
| jq -r --arg t "$tag" '[.data[] | select(.repositories[]?.tags[]?.name == $t) | select(.certified == true) | .architecture] | unique | join(",")')"
|
|
echo "attempt ${attempt}: certified architectures for ${tag}: ${certified:-none}"
|
|
if [[ "$certified" == "amd64,arm64" ]]; then
|
|
echo "Both architectures certified. Auto-publish is enabled on the component, so the catalog updates on its own."
|
|
exit 0
|
|
fi
|
|
sleep 30
|
|
done
|
|
echo "::warning::Pyxis has not marked both architectures certified after 10 minutes. Check https://connect.redhat.com/component/view/${COMPONENT_ID}/images"
|
|
|
|
release_ui:
|
|
runs-on: ubuntu-latest
|
|
outputs:
|
|
release_ui_artifact_url: ${{ steps.upload_release_ui.outputs.artifact-url }}
|
|
steps:
|
|
- name: Checkout
|
|
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
|
with:
|
|
fetch-depth: 0 # It is required for GoReleaser to work properly
|
|
persist-credentials: false
|
|
|
|
- name: Parse semver string
|
|
id: semver_parser
|
|
uses: netbirdio/shared-actions/actions/parse-semver@be5df6047383da2236e02243cceb857d8567c27e # v0.0.2
|
|
|
|
- name: Set snapshot flag
|
|
if: ${{ !startsWith(github.ref, 'refs/tags/v') }}
|
|
run: |
|
|
echo "flags=--snapshot" >> $GITHUB_ENV
|
|
|
|
- name: Set build vars
|
|
if: ${{ startsWith(github.ref, 'refs/tags/v') }}
|
|
run: |
|
|
if [[ "x-${{ steps.semver_parser.outputs.prerelease }}" == "x-" && "x-${{ github.repository }}" == "x-netbirdio/netbird" ]]; then
|
|
echo "x-${{ github.repository }}"
|
|
echo "x-${{ steps.semver_parser.outputs.prerelease }}"
|
|
echo "SKIP_PUBLISH=false" >> $GITHUB_ENV
|
|
else
|
|
echo "x-${{ github.repository }}"
|
|
echo "x-${{ steps.semver_parser.outputs.prerelease }}"
|
|
fi
|
|
|
|
- name: Set up Go
|
|
uses: actions/setup-go@924ae3a1cded613372ab5595356fb5720e22ba16 # v6.5.0
|
|
with:
|
|
go-version-file: "go.mod"
|
|
cache: false
|
|
- name: Cache Go modules
|
|
uses: actions/cache@2c8a9bd7457de244a408f35966fab2fb45fda9c8 # v6.0.0
|
|
with:
|
|
path: |
|
|
~/go/pkg/mod
|
|
~/.cache/go-build
|
|
key: ${{ runner.os }}-ui-go-releaser-${{ hashFiles('**/go.sum') }}
|
|
restore-keys: |
|
|
${{ runner.os }}-ui-go-releaser-
|
|
|
|
- name: Install modules
|
|
run: go mod tidy
|
|
|
|
- name: check git status
|
|
run: git --no-pager diff --exit-code
|
|
|
|
- name: Set up Node.js
|
|
uses: actions/setup-node@v7
|
|
with:
|
|
node-version: '22'
|
|
|
|
- name: Set up pnpm
|
|
uses: pnpm/action-setup@ea17c68df8912ef543352723c149a84f56e3d413 # v6.1.0
|
|
with:
|
|
version: 11
|
|
|
|
- name: Install dependencies
|
|
run: sudo apt update && sudo apt install -y -q libgtk-4-dev libwebkitgtk-6.0-dev libsoup-3.0-dev gcc-mingw-w64-x86-64
|
|
|
|
- name: Decode GPG signing key
|
|
if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository
|
|
env:
|
|
GPG_RPM_PRIVATE_KEY: ${{ secrets.GPG_RPM_PRIVATE_KEY }}
|
|
run: |
|
|
echo "$GPG_RPM_PRIVATE_KEY" | base64 -d > /tmp/gpg-rpm-signing-key.asc
|
|
echo "GPG_RPM_KEY_FILE=/tmp/gpg-rpm-signing-key.asc" >> $GITHUB_ENV
|
|
|
|
- name: Install LLVM-MinGW for ARM64 cross-compilation
|
|
run: |
|
|
cd /tmp
|
|
wget -q https://github.com/mstorsjo/llvm-mingw/releases/download/20250709/llvm-mingw-20250709-ucrt-ubuntu-22.04-x86_64.tar.xz
|
|
echo "60cafae6474c7411174cff1d4ba21a8e46cadbaeb05a1bace306add301628337 llvm-mingw-20250709-ucrt-ubuntu-22.04-x86_64.tar.xz" | sha256sum -c
|
|
tar -xf llvm-mingw-20250709-ucrt-ubuntu-22.04-x86_64.tar.xz
|
|
echo "/tmp/llvm-mingw-20250709-ucrt-ubuntu-22.04-x86_64/bin" >> $GITHUB_PATH
|
|
- name: Install goversioninfo
|
|
run: go install github.com/josephspurrier/goversioninfo/cmd/goversioninfo@b66839b # v1.7.0
|
|
- name: Install wails3 CLI
|
|
# Version derived from go.mod so the binding generator always matches
|
|
# the wails runtime the binary links against.
|
|
run: |
|
|
WAILS_VERSION=$(go list -m -f '{{.Version}}' github.com/wailsapp/wails/v3)
|
|
go install github.com/wailsapp/wails/v3/cmd/wails3@$WAILS_VERSION
|
|
- name: Generate windows syso amd64
|
|
run: goversioninfo -64 -icon client/ui/build/windows/icon.ico -manifest client/ui/build/windows/wails.exe.manifest -product-name ${{ env.PRODUCT_NAME }}-"UI" -copyright "${{ env.COPYRIGHT }}" -ver-major ${{ steps.semver_parser.outputs.major }} -ver-minor ${{ steps.semver_parser.outputs.minor }} -ver-patch ${{ steps.semver_parser.outputs.patch }} -ver-build 0 -file-version ${{ steps.semver_parser.outputs.fullversion }}.0 -product-version ${{ steps.semver_parser.outputs.fullversion }}.0 -o client/ui/resources_windows_amd64.syso
|
|
- name: Generate windows syso arm64
|
|
run: goversioninfo -arm -64 -icon client/ui/build/windows/icon.ico -manifest client/ui/build/windows/wails.exe.manifest -product-name ${{ env.PRODUCT_NAME }}-"UI" -copyright "${{ env.COPYRIGHT }}" -ver-major ${{ steps.semver_parser.outputs.major }} -ver-minor ${{ steps.semver_parser.outputs.minor }} -ver-patch ${{ steps.semver_parser.outputs.patch }} -ver-build 0 -file-version ${{ steps.semver_parser.outputs.fullversion }}.0 -product-version ${{ steps.semver_parser.outputs.fullversion }}.0 -o client/ui/resources_windows_arm64.syso
|
|
|
|
- name: Run GoReleaser
|
|
uses: goreleaser/goreleaser-action@5daf1e915a5f0af01ddbcd89a43b8061ff4f1a89 # v7.2.2
|
|
with:
|
|
version: ${{ env.GORELEASER_VER }}
|
|
args: release --config .goreleaser_ui.yaml --clean ${{ env.flags }}
|
|
env:
|
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
HOMEBREW_TAP_GITHUB_TOKEN: ${{ secrets.HOMEBREW_TAP_GITHUB_TOKEN }}
|
|
UPLOAD_DEBIAN_SECRET: ${{ secrets.PKG_UPLOAD_SECRET }}
|
|
UPLOAD_YUM_SECRET: ${{ secrets.PKG_UPLOAD_SECRET }}
|
|
GPG_RPM_KEY_FILE: ${{ env.GPG_RPM_KEY_FILE }}
|
|
NFPM_NETBIRD_UI_RPM_PASSPHRASE: ${{ secrets.GPG_RPM_PASSPHRASE }}
|
|
SKIP_PUBLISH: ${{ env.SKIP_PUBLISH }}
|
|
- name: Verify RPM signatures
|
|
run: |
|
|
docker run --rm -v $(pwd)/dist:/dist fedora:41 bash -c '
|
|
dnf install -y -q rpm-sign curl >/dev/null 2>&1
|
|
curl -sSL https://pkgs.netbird.io/yum/repodata/repomd.xml.key -o /tmp/rpm-pub.key
|
|
rpm --import /tmp/rpm-pub.key
|
|
echo "=== Verifying RPM signatures ==="
|
|
for rpm_file in /dist/*.rpm; do
|
|
[ -f "$rpm_file" ] || continue
|
|
echo "--- $(basename $rpm_file) ---"
|
|
rpm -K "$rpm_file"
|
|
done
|
|
'
|
|
- name: Clean up GPG key
|
|
if: always()
|
|
run: rm -f /tmp/gpg-rpm-signing-key.asc
|
|
- name: upload non tags for debug purposes
|
|
id: upload_release_ui
|
|
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a #v7.0.1
|
|
with:
|
|
name: release-ui
|
|
path: dist/
|
|
retention-days: 3
|
|
|
|
release_ui_gtk3:
|
|
# Legacy GTK3/WebKit2GTK 4.1 UI build for distros without WebKitGTK 6.0
|
|
# (Ubuntu 22.04, Debian 12, RHEL 9, Fedora <=39). Runs on ubuntu-22.04 so
|
|
# the binary links against the oldest supported glibc.
|
|
runs-on: ubuntu-22.04
|
|
outputs:
|
|
release_ui_gtk3_artifact_url: ${{ steps.upload_release_ui_gtk3.outputs.artifact-url }}
|
|
steps:
|
|
- name: Checkout
|
|
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
|
with:
|
|
fetch-depth: 0 # It is required for GoReleaser to work properly
|
|
persist-credentials: false
|
|
|
|
- name: Parse semver string
|
|
id: semver_parser
|
|
uses: netbirdio/shared-actions/actions/parse-semver@be5df6047383da2236e02243cceb857d8567c27e # v0.0.2
|
|
|
|
- name: Set snapshot flag
|
|
if: ${{ !startsWith(github.ref, 'refs/tags/v') }}
|
|
run: |
|
|
echo "flags=--snapshot" >> $GITHUB_ENV
|
|
|
|
- name: Set build vars
|
|
if: ${{ startsWith(github.ref, 'refs/tags/v') }}
|
|
run: |
|
|
if [[ "x-${{ steps.semver_parser.outputs.prerelease }}" == "x-" && "x-${{ github.repository }}" == "x-netbirdio/netbird" ]]; then
|
|
echo "x-${{ github.repository }}"
|
|
echo "x-${{ steps.semver_parser.outputs.prerelease }}"
|
|
echo "SKIP_PUBLISH=false" >> $GITHUB_ENV
|
|
else
|
|
echo "x-${{ github.repository }}"
|
|
echo "x-${{ steps.semver_parser.outputs.prerelease }}"
|
|
fi
|
|
|
|
- name: Set up Go
|
|
uses: actions/setup-go@924ae3a1cded613372ab5595356fb5720e22ba16 # v6.5.0
|
|
with:
|
|
go-version-file: "go.mod"
|
|
cache: false
|
|
- name: Cache Go modules
|
|
# Restore-only from the release_ui cache written by trusted runs; the
|
|
# module cache is identical (same go.sum) and stale build-cache
|
|
# entries just miss.
|
|
uses: actions/cache/restore@2c8a9bd7457de244a408f35966fab2fb45fda9c8 # v6.0.0
|
|
with:
|
|
path: |
|
|
~/go/pkg/mod
|
|
~/.cache/go-build
|
|
key: ${{ runner.os }}-ui-go-releaser-${{ hashFiles('**/go.sum') }}
|
|
restore-keys: |
|
|
${{ runner.os }}-ui-go-releaser-
|
|
|
|
- name: Install modules
|
|
run: go mod tidy
|
|
|
|
- name: check git status
|
|
run: git --no-pager diff --exit-code
|
|
|
|
- name: Set up Node.js
|
|
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
|
|
with:
|
|
node-version: '22'
|
|
|
|
- name: Set up pnpm
|
|
uses: pnpm/action-setup@ea17c68df8912ef543352723c149a84f56e3d413 # v6.1.0
|
|
with:
|
|
version: 11
|
|
|
|
- name: Install dependencies
|
|
run: sudo apt update && sudo apt install -y -q libgtk-3-dev libwebkit2gtk-4.1-dev
|
|
|
|
- name: Decode GPG signing key
|
|
if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository
|
|
env:
|
|
GPG_RPM_PRIVATE_KEY: ${{ secrets.GPG_RPM_PRIVATE_KEY }}
|
|
run: |
|
|
echo "$GPG_RPM_PRIVATE_KEY" | base64 -d > /tmp/gpg-rpm-signing-key.asc
|
|
echo "GPG_RPM_KEY_FILE=/tmp/gpg-rpm-signing-key.asc" >> $GITHUB_ENV
|
|
|
|
- name: Install wails3 CLI
|
|
# Version derived from go.mod so the binding generator always matches
|
|
# the wails runtime the binary links against.
|
|
# -tags gtk3: the CLI links the wails runtime's cgo packages, and the
|
|
# default tags request gtk4/webkitgtk-6.0 pkg-config entries that do
|
|
# not exist on ubuntu-22.04.
|
|
run: |
|
|
WAILS_VERSION=$(go list -m -f '{{.Version}}' github.com/wailsapp/wails/v3)
|
|
go install -tags gtk3 github.com/wailsapp/wails/v3/cmd/wails3@$WAILS_VERSION
|
|
|
|
- name: Run GoReleaser
|
|
uses: goreleaser/goreleaser-action@5daf1e915a5f0af01ddbcd89a43b8061ff4f1a89 # v7.2.2
|
|
with:
|
|
version: ${{ env.GORELEASER_VER }}
|
|
args: release --config .goreleaser_ui_gtk3.yaml --clean ${{ env.flags }}
|
|
env:
|
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
UPLOAD_DEBIAN_SECRET: ${{ secrets.PKG_UPLOAD_SECRET }}
|
|
UPLOAD_YUM_SECRET: ${{ secrets.PKG_UPLOAD_SECRET }}
|
|
GPG_RPM_KEY_FILE: ${{ env.GPG_RPM_KEY_FILE }}
|
|
NFPM_NETBIRD_UI_RPM_GTK3_PASSPHRASE: ${{ secrets.GPG_RPM_PASSPHRASE }}
|
|
SKIP_PUBLISH: ${{ env.SKIP_PUBLISH }}
|
|
- name: Verify RPM signatures
|
|
run: |
|
|
docker run --rm -v $(pwd)/dist:/dist fedora:41 bash -c '
|
|
dnf install -y -q rpm-sign curl >/dev/null 2>&1
|
|
curl -sSL https://pkgs.netbird.io/yum/repodata/repomd.xml.key -o /tmp/rpm-pub.key
|
|
rpm --import /tmp/rpm-pub.key
|
|
echo "=== Verifying RPM signatures ==="
|
|
for rpm_file in /dist/*.rpm; do
|
|
[ -f "$rpm_file" ] || continue
|
|
echo "--- $(basename $rpm_file) ---"
|
|
rpm -K "$rpm_file"
|
|
done
|
|
'
|
|
- name: Clean up GPG key
|
|
if: always()
|
|
run: rm -f /tmp/gpg-rpm-signing-key.asc
|
|
- name: upload non tags for debug purposes
|
|
id: upload_release_ui_gtk3
|
|
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a #v7.0.1
|
|
with:
|
|
name: release-ui-gtk3
|
|
path: dist/
|
|
retention-days: 3
|
|
|
|
release_ui_darwin:
|
|
runs-on: macos-latest
|
|
outputs:
|
|
release_ui_darwin_artifact_url: ${{ steps.upload_release_ui_darwin.outputs.artifact-url }}
|
|
steps:
|
|
- if: ${{ !startsWith(github.ref, 'refs/tags/v') }}
|
|
run: echo "flags=--snapshot" >> $GITHUB_ENV
|
|
- name: Checkout
|
|
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
|
with:
|
|
fetch-depth: 0 # It is required for GoReleaser to work properly
|
|
persist-credentials: false
|
|
- name: Set up Go
|
|
uses: actions/setup-go@924ae3a1cded613372ab5595356fb5720e22ba16 # v6.5.0
|
|
with:
|
|
go-version-file: "go.mod"
|
|
cache: false
|
|
- name: Cache Go modules
|
|
uses: actions/cache@2c8a9bd7457de244a408f35966fab2fb45fda9c8 # v6.0.0
|
|
with:
|
|
path: |
|
|
~/go/pkg/mod
|
|
~/.cache/go-build
|
|
key: ${{ runner.os }}-ui-go-releaser-darwin-${{ hashFiles('**/go.sum') }}
|
|
restore-keys: |
|
|
${{ runner.os }}-ui-go-releaser-darwin-
|
|
- name: Install modules
|
|
run: go mod tidy
|
|
- name: check git status
|
|
run: git --no-pager diff --exit-code
|
|
- name: Set up Node.js
|
|
uses: actions/setup-node@v7
|
|
with:
|
|
node-version: '22'
|
|
- name: Set up pnpm
|
|
uses: pnpm/action-setup@ea17c68df8912ef543352723c149a84f56e3d413 # v6.1.0
|
|
with:
|
|
version: 11
|
|
- name: Install wails3 CLI
|
|
# Version derived from go.mod so the binding generator always matches
|
|
# the wails runtime the binary links against.
|
|
run: |
|
|
WAILS_VERSION=$(go list -m -f '{{.Version}}' github.com/wailsapp/wails/v3)
|
|
go install github.com/wailsapp/wails/v3/cmd/wails3@$WAILS_VERSION
|
|
- name: Run GoReleaser
|
|
id: goreleaser
|
|
uses: goreleaser/goreleaser-action@5daf1e915a5f0af01ddbcd89a43b8061ff4f1a89 # v7.2.2
|
|
with:
|
|
version: ${{ env.GORELEASER_VER }}
|
|
args: release --config .goreleaser_ui_darwin.yaml --clean ${{ env.flags }}
|
|
env:
|
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
- name: upload non tags for debug purposes
|
|
id: upload_release_ui_darwin
|
|
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a #v7.0.1
|
|
with:
|
|
name: release-ui-darwin
|
|
path: dist/
|
|
retention-days: 3
|
|
|
|
test_windows_installer:
|
|
name: "Windows Installer / Build Test"
|
|
runs-on: windows-2022
|
|
needs: [release, release_ui]
|
|
strategy:
|
|
fail-fast: false
|
|
matrix:
|
|
include:
|
|
- arch: amd64
|
|
wintun_arch: amd64
|
|
- arch: arm64
|
|
wintun_arch: arm64
|
|
defaults:
|
|
run:
|
|
shell: powershell
|
|
env:
|
|
PackageWorkdir: netbird_windows_${{ matrix.arch }}
|
|
downloadPath: '${{ github.workspace }}\temp'
|
|
steps:
|
|
- name: Checkout
|
|
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
|
with:
|
|
persist-credentials: false
|
|
|
|
- name: Parse semver string
|
|
id: semver_parser
|
|
uses: netbirdio/shared-actions/actions/parse-semver@be5df6047383da2236e02243cceb857d8567c27e # v0.0.2
|
|
|
|
- name: Add 7-Zip to PATH
|
|
run: echo "C:\Program Files\7-Zip" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append
|
|
|
|
- name: Download release artifacts
|
|
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
|
|
with:
|
|
name: release
|
|
path: release
|
|
|
|
- name: Download UI release artifacts
|
|
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
|
|
with:
|
|
name: release-ui
|
|
path: release-ui
|
|
|
|
- name: Stage binaries into dist
|
|
run: |
|
|
$workdir = "dist\${{ env.PackageWorkdir }}"
|
|
New-Item -ItemType Directory -Force -Path $workdir | Out-Null
|
|
$client = Get-ChildItem -Recurse -Path release -Filter "netbird_*_windows_${{ matrix.arch }}.tar.gz" | Select-Object -First 1
|
|
$ui = Get-ChildItem -Recurse -Path release-ui -Filter "netbird-ui-windows_*_windows_${{ matrix.arch }}.tar.gz" | Select-Object -First 1
|
|
if (-not $client) { Write-Host "::error::client tarball not found for ${{ matrix.arch }}"; exit 1 }
|
|
if (-not $ui) { Write-Host "::error::ui tarball not found for ${{ matrix.arch }}"; exit 1 }
|
|
Write-Host "Client: $($client.FullName)"
|
|
Write-Host "UI: $($ui.FullName)"
|
|
tar -zvxf $client.FullName -C $workdir
|
|
tar -zvxf $ui.FullName -C $workdir
|
|
Get-ChildItem $workdir
|
|
|
|
- name: Download wintun
|
|
id: download-wintun
|
|
uses: netbirdio/shared-actions/actions/win-download-and-verify@be5df6047383da2236e02243cceb857d8567c27e # v0.0.2
|
|
with:
|
|
url: https://pkgs.netbird.io/wintun/wintun-0.14.1.zip
|
|
destination: ${{ env.downloadPath }}\wintun.zip
|
|
sha256: 07c256185d6ee3652e09fa55c0b673e2624b565e02c4b9091c79ca7d2f24ef51
|
|
|
|
- name: Decompress wintun files
|
|
run: tar -xvf "${{ env.downloadPath }}\wintun.zip" -C ${{ env.downloadPath }}
|
|
|
|
- name: Move wintun.dll into dist
|
|
run: mv ${{ env.downloadPath }}\wintun\bin\${{ matrix.wintun_arch }}\wintun.dll ${{ github.workspace }}\dist\${{ env.PackageWorkdir }}\
|
|
|
|
- name: Download EnVar plugin for NSIS
|
|
uses: netbirdio/shared-actions/actions/win-download-and-verify@be5df6047383da2236e02243cceb857d8567c27e # v0.0.2
|
|
with:
|
|
url: https://pkgs.netbird.io/nsis/EnVar_plugin.zip
|
|
destination: ${{ github.workspace }}\envar_plugin.zip
|
|
sha256: e9aa92de351345ed82795251d838f1ae9041ba35af9d381a5780c7843b01f56a
|
|
|
|
- name: Extract EnVar plugin
|
|
run: 7z x -o"${{ github.workspace }}/NSIS_Plugins" "${{ github.workspace }}/envar_plugin.zip"
|
|
|
|
- name: Download ShellExecAsUser plugin for NSIS (amd64 only)
|
|
if: matrix.arch == 'amd64'
|
|
uses: netbirdio/shared-actions/actions/win-download-and-verify@be5df6047383da2236e02243cceb857d8567c27e # v0.0.2
|
|
with:
|
|
url: https://pkgs.netbird.io/nsis/ShellExecAsUser_amd64-Unicode.7z
|
|
destination: ${{ github.workspace }}\ShellExecAsUser_amd64-Unicode.7z
|
|
sha256: 0a55ea25c7330a92cec028eda8afcaf1b1a7092e0dfb77c21c8f654564b4ff9d
|
|
|
|
- name: Extract ShellExecAsUser plugin (amd64 only)
|
|
if: matrix.arch == 'amd64'
|
|
run: 7z x -o"${{ github.workspace }}/NSIS_Plugins" "${{ github.workspace }}/ShellExecAsUser_amd64-Unicode.7z"
|
|
|
|
- name: Set up Go for wails3 CLI
|
|
uses: actions/setup-go@v6
|
|
with:
|
|
go-version-file: "go.mod"
|
|
cache: false
|
|
|
|
- name: Install wails3 CLI
|
|
# Version derived from go.mod so the bootstrapper payload always
|
|
# matches the wails runtime the binary links against.
|
|
shell: bash
|
|
run: |
|
|
WAILS_VERSION=$(go list -m -f '{{.Version}}' github.com/wailsapp/wails/v3)
|
|
go install github.com/wailsapp/wails/v3/cmd/wails3@$WAILS_VERSION
|
|
|
|
- name: Stage WebView2 bootstrapper for installers
|
|
# Both client/installer.nsis and client/netbird.wxs reference
|
|
# client/MicrosoftEdgeWebview2Setup.exe. wails3 writes it there.
|
|
# The signing pipeline (netbirdio/sign-pipelines) does the same
|
|
# step for release builds; this mirrors it for PR sanity testing.
|
|
shell: bash
|
|
run: wails3 generate webview2bootstrapper -dir client
|
|
|
|
- name: Build NSIS installer
|
|
shell: pwsh
|
|
env:
|
|
APPVER: ${{ steps.semver_parser.outputs.major }}.${{ steps.semver_parser.outputs.minor }}.${{ steps.semver_parser.outputs.patch }}.${{ github.run_id }}
|
|
run: |
|
|
$nsisPluginDir = "C:\Program Files (x86)\NSIS\Plugins\x86-unicode"
|
|
$srcPlugins = "${{ github.workspace }}\NSIS_Plugins\Plugins"
|
|
Get-ChildItem -Path $srcPlugins -Recurse -Filter *.dll |
|
|
Copy-Item -Destination $nsisPluginDir -Force
|
|
& "C:\Program Files (x86)\NSIS\makensis.exe" /V4 "/DARCH=${{ matrix.arch }}" client\installer.nsis
|
|
if ($LASTEXITCODE -ne 0) { throw "makensis failed with exit code $LASTEXITCODE" }
|
|
|
|
- name: Rename NSIS installer
|
|
run: mv netbird-installer.exe netbird_installer_test_windows_${{ matrix.arch }}.exe
|
|
|
|
- name: Install WiX
|
|
run: |
|
|
dotnet tool install --global wix --version 6.0.2
|
|
wix extension add WixToolset.Util.wixext/6.0.2
|
|
|
|
- name: Build MSI installer
|
|
env:
|
|
NETBIRD_VERSION: "${{ steps.semver_parser.outputs.fullversion }}"
|
|
run: wix build -arch ${{ matrix.arch == 'amd64' && 'x64' || 'arm64' }} -ext WixToolset.Util.wixext -o netbird_installer_test_windows_${{ matrix.arch }}.msi .\client\netbird.wxs -d ProcessorArchitecture=${{ matrix.arch == 'amd64' && 'x64' || 'arm64' }} -d ArchSuffix=${{ matrix.arch }}
|
|
|
|
- name: Upload installer artifacts
|
|
if: always()
|
|
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a #v7.0.1
|
|
with:
|
|
name: windows-installer-test-${{ matrix.arch }}
|
|
path: |
|
|
netbird_installer_test_windows_${{ matrix.arch }}.exe
|
|
netbird_installer_test_windows_${{ matrix.arch }}.msi
|
|
retention-days: 3
|
|
|
|
comment_release_artifacts:
|
|
name: Comment release artifacts
|
|
runs-on: ubuntu-latest
|
|
needs: [release, release_ui, release_ui_gtk3, release_ui_darwin]
|
|
if: ${{ always() && github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name == github.repository }}
|
|
permissions:
|
|
contents: read
|
|
issues: write
|
|
pull-requests: write
|
|
steps:
|
|
- name: Create or update PR comment
|
|
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
|
|
env:
|
|
RELEASE_RESULT: ${{ needs.release.result }}
|
|
RELEASE_UI_RESULT: ${{ needs.release_ui.result }}
|
|
RELEASE_UI_GTK3_RESULT: ${{ needs.release_ui_gtk3.result }}
|
|
RELEASE_UI_DARWIN_RESULT: ${{ needs.release_ui_darwin.result }}
|
|
RELEASE_ARTIFACT_URL: ${{ needs.release.outputs.release_artifact_url }}
|
|
LINUX_PACKAGES_ARTIFACT_URL: ${{ needs.release.outputs.linux_packages_artifact_url }}
|
|
WINDOWS_PACKAGES_ARTIFACT_URL: ${{ needs.release.outputs.windows_packages_artifact_url }}
|
|
MACOS_PACKAGES_ARTIFACT_URL: ${{ needs.release.outputs.macos_packages_artifact_url }}
|
|
RELEASE_UI_ARTIFACT_URL: ${{ needs.release_ui.outputs.release_ui_artifact_url }}
|
|
RELEASE_UI_GTK3_ARTIFACT_URL: ${{ needs.release_ui_gtk3.outputs.release_ui_gtk3_artifact_url }}
|
|
RELEASE_UI_DARWIN_ARTIFACT_URL: ${{ needs.release_ui_darwin.outputs.release_ui_darwin_artifact_url }}
|
|
GHCR_IMAGES_MARKDOWN: ${{ needs.release.outputs.ghcr_images }}
|
|
with:
|
|
github-token: ${{ secrets.GITHUB_TOKEN }}
|
|
script: |
|
|
const marker = '<!-- netbird-release-artifacts -->';
|
|
const { owner, repo } = context.repo;
|
|
const issue_number = context.payload.pull_request.number;
|
|
const runUrl = `${context.serverUrl}/${owner}/${repo}/actions/runs/${context.runId}`;
|
|
const shortSha = context.payload.pull_request.head.sha.slice(0, 7);
|
|
|
|
const artifactCell = (url, result) => {
|
|
if (url) return `[Download](${url})`;
|
|
return result && result !== 'success' ? `_Not available (${result})_` : '_Not available_';
|
|
};
|
|
|
|
const artifacts = [
|
|
['All release artifacts', process.env.RELEASE_ARTIFACT_URL, process.env.RELEASE_RESULT],
|
|
['Linux packages', process.env.LINUX_PACKAGES_ARTIFACT_URL, process.env.RELEASE_RESULT],
|
|
['Windows packages', process.env.WINDOWS_PACKAGES_ARTIFACT_URL, process.env.RELEASE_RESULT],
|
|
['macOS packages', process.env.MACOS_PACKAGES_ARTIFACT_URL, process.env.RELEASE_RESULT],
|
|
['UI artifacts', process.env.RELEASE_UI_ARTIFACT_URL, process.env.RELEASE_UI_RESULT],
|
|
['UI GTK3 artifacts', process.env.RELEASE_UI_GTK3_ARTIFACT_URL, process.env.RELEASE_UI_GTK3_RESULT],
|
|
['UI macOS artifacts', process.env.RELEASE_UI_DARWIN_ARTIFACT_URL, process.env.RELEASE_UI_DARWIN_RESULT],
|
|
];
|
|
|
|
const artifactRows = artifacts
|
|
.map(([name, url, result]) => `| ${name} | ${artifactCell(url, result)} |`)
|
|
.join('\n');
|
|
|
|
const ghcrImages = (process.env.GHCR_IMAGES_MARKDOWN || '').trim() || '_No GHCR images were pushed._';
|
|
|
|
const body = [
|
|
marker,
|
|
'## Release artifacts',
|
|
'',
|
|
`Built for PR head \`${shortSha}\` in [workflow run #${process.env.GITHUB_RUN_NUMBER}](${runUrl}).`,
|
|
'',
|
|
'| Artifact | Link |',
|
|
'| --- | --- |',
|
|
artifactRows,
|
|
'',
|
|
'### GHCR images (amd64)',
|
|
ghcrImages,
|
|
'',
|
|
'_This comment is updated by the Release workflow. Artifact links expire according to the workflow retention policy._',
|
|
].join('\n');
|
|
|
|
const comments = await github.paginate(github.rest.issues.listComments, {
|
|
owner,
|
|
repo,
|
|
issue_number,
|
|
per_page: 100,
|
|
});
|
|
|
|
const previous = comments.find(comment =>
|
|
comment.user?.type === 'Bot' && comment.body?.includes(marker)
|
|
);
|
|
|
|
if (previous) {
|
|
await github.rest.issues.updateComment({
|
|
owner,
|
|
repo,
|
|
comment_id: previous.id,
|
|
body,
|
|
});
|
|
core.info(`Updated release artifacts comment ${previous.id}`);
|
|
} else {
|
|
const { data } = await github.rest.issues.createComment({
|
|
owner,
|
|
repo,
|
|
issue_number,
|
|
body,
|
|
});
|
|
core.info(`Created release artifacts comment ${data.id}`);
|
|
}
|
|
|
|
trigger_signer:
|
|
runs-on: ubuntu-latest
|
|
needs: [release, release_ui, release_ui_gtk3, release_ui_darwin, test_windows_installer]
|
|
if: startsWith(github.ref, 'refs/tags/')
|
|
steps:
|
|
- name: Trigger binaries sign pipelines
|
|
uses: benc-uk/workflow-dispatch@31e2b3319479a63f0ab15bf800eff9e913504e26 # v1.3.2
|
|
with:
|
|
workflow: Sign bin and installer
|
|
repo: netbirdio/sign-pipelines
|
|
ref: ${{ env.SIGN_PIPE_VER }}
|
|
token: ${{ secrets.SIGN_GITHUB_TOKEN }}
|
|
inputs: '{ "tag": "${{ github.ref }}", "skipRelease": false }'
|