Skip to content

build-nym-vpn-apple #55

build-nym-vpn-apple

build-nym-vpn-apple #55

name: build-nym-vpn-apple
on:
pull_request:
types: [opened, synchronize, reopened, ready_for_review]
paths:
- ".github/workflows/build-nym-vpn-apple.yml"
- "nym-vpn-apple/**"
workflow_dispatch:
inputs:
release_type:
description: "Select build mode"
type: choice
options:
- "pr — Pull Request (unsigned debug build)"
- "qa — QA Release (signed, automatic, TestFlight/App Store export)"
- "ship — Ship Release (signed, automatic, App Store distribution)"
default: "pr — Pull Request (unsigned debug build)"
workflow_call:
inputs:
release_type:
description: "Build type: pr | qa | ship (raw or labeled)"
type: string
default: "pr"
outputs:
RUST_VERSION:
value: ${{ jobs.build-apple.outputs.RUST_VERSION }}
env:
CARGO_TERM_COLOR: always
UPLOAD_DIR_IOS: ios_artifacts
RAW_RELEASE_TYPE: ${{ (github.event_name == 'pull_request' && 'pr') || inputs.release_type || 'pr' }}
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true
jobs:
build-apple:
if: github.actor != 'dependabot[bot]'
runs-on: AppleSilicon
timeout-minutes: 60
outputs:
UPLOAD_DIR_IOS: ${{ env.UPLOAD_DIR_IOS }}
RUST_VERSION: ${{ steps.rust-version.outputs.rustc }}
steps:
- name: Checkout repo
uses: actions/checkout@v4
- name: Normalize release_type
run: |
sel="${{ env.RAW_RELEASE_TYPE }}"
case "$sel" in
pr*|PR*) mode=pr ;;
qa*|QA*) mode=qa ;;
ship*|SHIP*) mode=ship ;;
*) mode=pr ;;
esac
echo "RELEASE_TYPE=$mode" >> "$GITHUB_ENV"
- name: Show selected release type
run: echo "RELEASE_TYPE=${{ env.RELEASE_TYPE }}"
- name: Install rust toolchain
uses: dtolnay/rust-toolchain@master
with:
toolchain: ${{ vars.REQUIRED_RUSTC_VERSION }}
components: rustfmt, clippy
targets: x86_64-apple-darwin aarch64-apple-ios x86_64-apple-ios aarch64-apple-ios-sim
- name: Install cargo-swift
run: |
cargo install \
--git https://github.com/antoniusnaumann/cargo-swift \
--rev 53b948e8f37dd018300ae3fee2d0fd5ece59e2cd \
cargo-swift
- name: Install cargo-license
if: ${{ env.RELEASE_TYPE == 'qa' || env.RELEASE_TYPE == 'ship' }}
run: |
cargo install cargo-license
- name: Install Protoc
uses: arduino/setup-protoc@v3
with:
repo-token: ${{ secrets.GITHUB_TOKEN }}
- name: Install Go
uses: actions/setup-go@v5
with:
go-version: ${{ vars.REQUIRED_GOLANG_VERSION }}
cache: false
- name: Get workspace version
id: workspace-version
uses: nicolaiunrein/cargo-get@master
with:
subcommand: workspace.package.version --entry nym-vpn-core
- name: Install cargo-edit
uses: baptiste0928/cargo-install@v3
with:
crate: cargo-edit
- name: Add existing Homebrew to PATH (no install)
run: |
set -euxo pipefail
for HB in /opt/homebrew/bin/brew /usr/local/bin/brew; do
if [ -x "$HB" ]; then
echo "$(dirname "$HB")" >> "$GITHUB_PATH" # future steps
export PATH="$(dirname "$HB"):$PATH" # this step
eval "$("$HB" shellenv)" # set Homebrew env vars
{
echo "HOMEBREW_PREFIX=$HOMEBREW_PREFIX"
echo "HOMEBREW_CELLAR=$HOMEBREW_CELLAR"
echo "HOMEBREW_REPOSITORY=$HOMEBREW_REPOSITORY"
} >> "$GITHUB_ENV"
"$HB" --version
exit 0
fi
done
echo "❌ Homebrew binary not found at /opt/homebrew/bin/brew or /usr/local/bin/brew" >&2
exit 1
- name: Update prebundled servers
if: ${{ env.RELEASE_TYPE == 'qa' || env.RELEASE_TYPE == 'ship' }}
working-directory: nym-vpn-apple/scripts
run: |
sh UpdatePrebundledServers.sh
- name: Enable QA mode
if: env.RELEASE_TYPE == 'qa'
working-directory: nym-vpn-apple
run: |
sed -E ':a;N;$!ba; s|(</dict>[[:space:]]*</plist>)| <key>EnvironmentVariables</key>\n <dict>\n <key>RUST_LOG</key>\n <string>debug</string>\n </dict>\n\1|' "Daemon/net.nymtech.vpn.helper.plist"
- name: Update licences
if: ${{ env.RELEASE_TYPE == 'qa' || env.RELEASE_TYPE == 'ship' }}
run: |
cargo license -j --avoid-dev-deps --current-dir ./nym-vpn-core --filter-platform x86_64-apple-darwin --avoid-build-deps > ./nym-vpn-apple/NymVPN/Resources/LibLicences.json
- name: Install Fastlane
if: ${{ env.RELEASE_TYPE == 'qa' || env.RELEASE_TYPE == 'ship' }}
run: |
brew install fastlane
- name: Build core
working-directory: nym-vpn-apple/scripts
env:
VPNLIB_SENTRY_DSN: ${{ secrets.VPND_SENTRY_DSN }}
run: |
sh BuildCore.sh
- name: Build iOS (PR, unsigned Debug)
if: env.RELEASE_TYPE == 'pr'
working-directory: nym-vpn-apple
env:
IPHONEOS_DEPLOYMENT_TARGET: 16.0
run: |
set -euxo pipefail
DERIVED_DATA="$PWD/.DerivedData-iOS"
xcodebuild \
-workspace NymVPN.xcworkspace \
-scheme NymVPN \
-configuration Debug \
-destination 'generic/platform=iOS' \
-sdk iphoneos \
-derivedDataPath "$DERIVED_DATA" \
CODE_SIGNING_ALLOWED=NO \
DEVELOPMENT_TEAM= \
build
find "$DERIVED_DATA/Build/Products" -maxdepth 3 -name '*.app' -print || true
- name: Prepare App Store Connect API key
if: env.RELEASE_TYPE != 'pr'
id: asc-key
working-directory: nym-vpn-apple
env:
ASC_KEY_ID: ${{ secrets.APP_STORE_CONNECT_API_KEY }}
ASC_ISSUER_ID: ${{ secrets.APP_STORE_CONNECT_API_ISSUER_ID }}
ASC_KEY_BASE64: ${{ secrets.APP_STORE_CONNECT_API_PRIVATE_KEY_BASE64 }}
run: |
set -euo pipefail
KEY_PATH="$RUNNER_TEMP/AuthKey_${ASC_KEY_ID}.p8"
echo "$ASC_KEY_BASE64" | base64 --decode > "$KEY_PATH"
chmod 600 "$KEY_PATH"
echo "key_path=$KEY_PATH" >> "$GITHUB_OUTPUT"
- name: Archive iOS (QA/Ship, Distribution, Automatic, ASC auth)
if: env.RELEASE_TYPE != 'pr'
id: ios-archive
working-directory: nym-vpn-apple
env:
IPHONEOS_DEPLOYMENT_TARGET: 16.0
DEVELOPMENT_TEAM: ${{ secrets.APPLE_TEAM_ID }}
run: |
set -euxo pipefail
ARCHIVE_PATH="$PWD/build/NymVPN-iOS.xcarchive"
xcrun xcodebuild \
-workspace NymVPN.xcworkspace \
-scheme NymVPN \
-configuration Release \
-destination 'generic/platform=iOS' \
-sdk iphoneos \
-archivePath "$ARCHIVE_PATH" \
CODE_SIGN_STYLE=Automatic \
CODE_SIGNING_ALLOWED=YES \
DEVELOPMENT_TEAM="${DEVELOPMENT_TEAM}" \
-allowProvisioningUpdates \
-authenticationKeyIssuerID "${{ secrets.APP_STORE_CONNECT_API_ISSUER_ID }}" \
-authenticationKeyID "${{ secrets.APP_STORE_CONNECT_API_KEY }}" \
-authenticationKeyPath "${{ steps.asc-key.outputs.key_path }}" \
clean archive
echo "archive_path=$ARCHIVE_PATH" >> "$GITHUB_OUTPUT"
- name: Export IPA (QA/Ship – App Store Connect, ASC auth)
if: env.RELEASE_TYPE != 'pr'
working-directory: nym-vpn-apple
run: |
set -euxo pipefail
EXPORT_DIR="$PWD/build/export-${{ env.RELEASE_TYPE }}"
mkdir -p "$EXPORT_DIR"
cat > exportOptions.plist <<'EOF'
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>method</key><string>app-store-connect</string>
<key>signingStyle</key><string>automatic</string>
<key>destination</key><string>export</string>
<key>stripSwiftSymbols</key><true/>
<key>compileBitcode</key><false/>
</dict>
</plist>
EOF
xcrun xcodebuild -exportArchive \
-archivePath "${{ steps.ios-archive.outputs.archive_path }}" \
-exportOptionsPlist exportOptions.plist \
-exportPath "$EXPORT_DIR" \
-allowProvisioningUpdates \
-authenticationKeyIssuerID "${{ secrets.APP_STORE_CONNECT_API_ISSUER_ID }}" \
-authenticationKeyID "${{ secrets.APP_STORE_CONNECT_API_KEY }}" \
-authenticationKeyPath "${{ steps.asc-key.outputs.key_path }}"
echo "Exported files:"; ls -lah "$EXPORT_DIR"
- name: Upload to TestFlight (QA)
if: env.RELEASE_TYPE == 'qa'
working-directory: nym-vpn-apple
env:
ASC_KEY_ID: ${{ secrets.APP_STORE_CONNECT_API_KEY }}
ASC_ISSUER_ID: ${{ secrets.APP_STORE_CONNECT_API_ISSUER_ID }}
ASC_KEY_BASE64: ${{ secrets.APP_STORE_CONNECT_API_PRIVATE_KEY }}
run: |
set -euxo pipefail
IPA="$(ls build/export-qa/*.ipa | head -n1)"
fastlane ios upload_testflight ipa_path:"$IPA" changelog:"QA build ${GITHUB_SHA}"
- name: Archive macOS (QA/Ship, signed Release, automatic)
if: ${{ env.RELEASE_TYPE == 'qa' || env.RELEASE_TYPE == 'ship' }}
id: mac-archive
working-directory: nym-vpn-apple
env:
MACOSX_DEPLOYMENT_TARGET: 13.0
DEVELOPMENT_TEAM: ${{ secrets.APPLE_TEAM_ID }}
run: |
set -euxo pipefail
ARCHIVE_PATH="$PWD/build/NymVPNDaemon-macOS.xcarchive"
xcodebuild \
-workspace NymVPN.xcworkspace \
-scheme NymVPNDaemon \
-configuration Release \
-destination 'generic/platform=macOS' \
-archivePath "$ARCHIVE_PATH" \
DEVELOPMENT_TEAM="${DEVELOPMENT_TEAM}" \
CODE_SIGN_STYLE=Automatic \
CODE_SIGNING_ALLOWED=YES \
-allowProvisioningUpdates \
clean archive
echo "archive_path=$ARCHIVE_PATH" >> "$GITHUB_OUTPUT"
- name: Build macOS (PR, unsigned Debug)
if: env.RELEASE_TYPE == 'pr'
working-directory: nym-vpn-apple
env:
MACOSX_DEPLOYMENT_TARGET: 13.0
run: |
set -euxo pipefail
DERIVED_DATA="$PWD/.DerivedData-macOS"
xcodebuild \
-workspace NymVPN.xcworkspace \
-scheme NymVPNDaemon \
-configuration Debug \
-destination 'generic/platform=macOS' \
-derivedDataPath "$DERIVED_DATA" \
CODE_SIGNING_ALLOWED=NO \
DEVELOPMENT_TEAM= \
build
find "$DERIVED_DATA/Build/Products" -maxdepth 3 -name '*.app' -print || true
# # ---------- Artifacts (helpful for QA/Ship) ----------
# - name: Upload artifacts
# if: always()
# uses: actions/upload-artifact@v4
# with:
# name: apple-builds-${{ env.RELEASE_TYPE }}-${{ github.run_id }}
# path: |
# nym-vpn-apple/build/**/*.xcarchive
# nym-vpn-apple/build/**/export-qa/*.ipa
# nym-vpn-apple/build/**/export-ship/*.ipa
# nym-vpn-apple/.DerivedData*/Build/Products/**/*.app
# if-no-files-found: ignore
# retention-days: 5