321 lines
12 KiB
YAML
321 lines
12 KiB
YAML
name: Build macOS Packages
|
|
|
|
# Produces, per architecture (x86_64, arm64, universal):
|
|
# TargetPrint_<tag>-<sha>-macos-<arch>.app.zip — vendored into ICCery
|
|
# TargetPrint_<tag>-<sha>-macos-<arch>.dmg — installable disk image
|
|
# plus TargetPrint_<tag>-<sha>-vendor-iccery.zip — macos-x86_64 / macos-aarch64 / macos-universal layout
|
|
|
|
on:
|
|
push:
|
|
tags:
|
|
- "v*"
|
|
branches:
|
|
- main
|
|
pull_request:
|
|
workflow_dispatch:
|
|
|
|
jobs:
|
|
build-arch:
|
|
name: Build macOS (${{ matrix.platform.name }})
|
|
runs-on: ${{ matrix.platform.os }}
|
|
env:
|
|
XDG_CONFIG_HOME: ${{ runner.temp }}/.config
|
|
strategy:
|
|
fail-fast: false
|
|
matrix:
|
|
platform:
|
|
- name: Intel
|
|
os: macos
|
|
arch: x86_64
|
|
vendor_dir: macos-x86_64
|
|
- name: Apple Silicon
|
|
os: macos
|
|
arch: arm64
|
|
vendor_dir: macos-aarch64
|
|
|
|
steps:
|
|
- name: Checkout repository
|
|
uses: actions/checkout@v4
|
|
|
|
- name: Ensure workspace and git permissions
|
|
run: |
|
|
mkdir -p "${{ runner.temp }}/.config/git"
|
|
touch "${{ runner.temp }}/.config/git/ignore"
|
|
mkdir -p .git/info
|
|
touch .git/info/exclude
|
|
chmod -R u+rwX .git || true
|
|
git config --local core.excludesFile "${{ runner.temp }}/.config/git/ignore" || true
|
|
|
|
- name: Enter project root
|
|
run: |
|
|
if [ -f macos/TargetPrint.xcodeproj/project.pbxproj ]; then
|
|
echo "PROJECT_ROOT=macos" >> "$GITHUB_ENV"
|
|
else
|
|
echo "PROJECT_ROOT=." >> "$GITHUB_ENV"
|
|
fi
|
|
|
|
- name: Select Xcode
|
|
env:
|
|
XCODE_APP: ${{ vars.XCODE_APP }}
|
|
run: |
|
|
ROOT="${PROJECT_ROOT:-.}"
|
|
chmod +x "$ROOT/Scripts/select_xcode.sh"
|
|
"$ROOT/Scripts/select_xcode.sh"
|
|
|
|
- name: Show toolchain
|
|
run: |
|
|
echo "HAS_FULL_XCODE=${HAS_FULL_XCODE:-unset}"
|
|
echo "DEVELOPER_DIR=${DEVELOPER_DIR:-unset}"
|
|
echo "SDKROOT=${SDKROOT:-unset}"
|
|
echo "SWIFT=${SWIFT:-unset}"
|
|
echo "xcode-select -p: $(xcode-select -p 2>/dev/null || echo unknown)"
|
|
if [ "${HAS_FULL_XCODE:-0}" = "1" ]; then
|
|
XB="${XCODEBUILD:-xcodebuild}"
|
|
"$XB" -version
|
|
else
|
|
echo "Full Xcode.app not installed; will compile with swiftc."
|
|
"${SWIFT:-$(xcrun --find swiftc)}" --version
|
|
fi
|
|
sw_vers
|
|
uname -m
|
|
|
|
- name: Set release names
|
|
id: set_env
|
|
shell: bash
|
|
run: |
|
|
if [[ "${GITHUB_REF:-}" == refs/tags/* ]]; then
|
|
TAG="${GITHUB_REF_NAME}"
|
|
else
|
|
TAG="dev"
|
|
fi
|
|
SHORT_SHA="$(git rev-parse --short HEAD)"
|
|
PREFIX="TargetPrint_${TAG}-${SHORT_SHA}-macos-${{ matrix.platform.arch }}"
|
|
echo "TAG=${TAG}" >> "$GITHUB_ENV"
|
|
echo "SHORT_SHA=${SHORT_SHA}" >> "$GITHUB_ENV"
|
|
echo "PREFIX=${PREFIX}" >> "$GITHUB_ENV"
|
|
echo "prefix=${PREFIX}" >> "$GITHUB_OUTPUT"
|
|
|
|
- name: Make scripts executable
|
|
working-directory: ${{ env.PROJECT_ROOT }}
|
|
run: chmod +x Scripts/*.sh
|
|
|
|
- name: Run unit tests
|
|
working-directory: ${{ env.PROJECT_ROOT }}
|
|
run: |
|
|
if [ "${HAS_FULL_XCODE:-0}" != "1" ]; then
|
|
echo "Skipping XCTest — no Xcode.app (XCTest.framework is not part of CLT)."
|
|
exit 0
|
|
fi
|
|
XB="${XCODEBUILD:-xcodebuild}"
|
|
"$XB" test \
|
|
-project TargetPrint.xcodeproj \
|
|
-scheme TargetPrint \
|
|
-destination "platform=macOS" \
|
|
-only-testing:TargetPrintTests \
|
|
-jobs "$(sysctl -n hw.ncpu 2>/dev/null || echo 4)" \
|
|
-parallelizeTargets \
|
|
CODE_SIGNING_ALLOWED=NO \
|
|
ONLY_ACTIVE_ARCH=YES
|
|
|
|
- name: Build ${{ matrix.platform.arch }} .app
|
|
working-directory: ${{ env.PROJECT_ROOT }}
|
|
env:
|
|
MACOS_CODESIGN_IDENTITY: ${{ secrets.MACOS_CODESIGN_IDENTITY }}
|
|
run: |
|
|
IDENTITY="${MACOS_CODESIGN_IDENTITY:--}"
|
|
export MACOS_CODESIGN_IDENTITY="$IDENTITY"
|
|
./Scripts/build_macos.sh "${{ matrix.platform.arch }}" Release
|
|
|
|
- name: Package .app.zip and .dmg
|
|
working-directory: ${{ env.PROJECT_ROOT }}
|
|
env:
|
|
MACOS_CODESIGN_IDENTITY: ${{ secrets.MACOS_CODESIGN_IDENTITY }}
|
|
run: |
|
|
export MACOS_CODESIGN_IDENTITY="${MACOS_CODESIGN_IDENTITY:--}"
|
|
./Scripts/package_release.sh "${{ matrix.platform.arch }}" "${PREFIX}"
|
|
(cd build/release-assets && shasum -a 256 "${PREFIX}.app.zip" "${PREFIX}.dmg" | tee "${PREFIX}.SHA256.txt")
|
|
|
|
- name: Upload ${{ matrix.platform.arch }} .app (for universal lipo)
|
|
uses: actions/upload-artifact@v3
|
|
with:
|
|
name: app-${{ matrix.platform.arch }}
|
|
path: ${{ env.PROJECT_ROOT }}/build/apps/${{ matrix.platform.arch }}/TargetPrint.app
|
|
|
|
- name: Upload ${{ matrix.platform.arch }} packages
|
|
uses: actions/upload-artifact@v3
|
|
with:
|
|
name: ${{ env.PREFIX }}
|
|
path: ${{ env.PROJECT_ROOT }}/build/release-assets/${{ env.PREFIX }}.*
|
|
|
|
- name: Upload Release Assets to Gitea
|
|
if: ${{ startsWith(github.ref, 'refs/tags/') && !cancelled() }}
|
|
env:
|
|
GITEA_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
SERVER_URL: ${{ github.server_url }}
|
|
REPO: ${{ github.repository }}
|
|
working-directory: ${{ env.PROJECT_ROOT }}
|
|
run: |
|
|
echo "Finding release for tag ${TAG}..."
|
|
RELEASE_RESP=$(curl -s -H "Authorization: token ${GITEA_TOKEN}" \
|
|
"${SERVER_URL}/api/v1/repos/${REPO}/releases/tags/${TAG}")
|
|
RELEASE_ID=$(echo "${RELEASE_RESP}" | grep -o '"id":[0-9]*' | head -n 1 | cut -d: -f2)
|
|
if [ -n "${RELEASE_ID}" ]; then
|
|
echo "Found Release ID: ${RELEASE_ID}. Uploading ${PREFIX} assets..."
|
|
for f in build/release-assets/${PREFIX}.app.zip \
|
|
build/release-assets/${PREFIX}.dmg \
|
|
build/release-assets/${PREFIX}.SHA256.txt; do
|
|
if [ -f "$f" ]; then
|
|
FILENAME=$(basename "$f")
|
|
echo "Uploading $FILENAME..."
|
|
curl -s -X POST \
|
|
-H "Authorization: token ${GITEA_TOKEN}" \
|
|
-H "Content-Type: multipart/form-data" \
|
|
-F "attachment=@$f" \
|
|
"${SERVER_URL}/api/v1/repos/${REPO}/releases/${RELEASE_ID}/assets?name=${FILENAME}"
|
|
fi
|
|
done
|
|
else
|
|
echo "No existing release found for tag ${TAG}. Skipping asset upload."
|
|
fi
|
|
|
|
build-universal:
|
|
name: Build macOS (Universal)
|
|
needs: build-arch
|
|
runs-on: macos
|
|
env:
|
|
XDG_CONFIG_HOME: ${{ runner.temp }}/.config
|
|
steps:
|
|
- name: Checkout repository
|
|
uses: actions/checkout@v4
|
|
|
|
- name: Enter project root
|
|
run: |
|
|
if [ -f macos/TargetPrint.xcodeproj/project.pbxproj ]; then
|
|
echo "PROJECT_ROOT=macos" >> "$GITHUB_ENV"
|
|
else
|
|
echo "PROJECT_ROOT=." >> "$GITHUB_ENV"
|
|
fi
|
|
|
|
- name: Select Xcode
|
|
env:
|
|
XCODE_APP: ${{ vars.XCODE_APP }}
|
|
run: |
|
|
ROOT="${PROJECT_ROOT:-.}"
|
|
chmod +x "$ROOT/Scripts/select_xcode.sh"
|
|
"$ROOT/Scripts/select_xcode.sh"
|
|
|
|
- name: Set release names
|
|
shell: bash
|
|
run: |
|
|
if [[ "${GITHUB_REF:-}" == refs/tags/* ]]; then
|
|
TAG="${GITHUB_REF_NAME}"
|
|
else
|
|
TAG="dev"
|
|
fi
|
|
SHORT_SHA="$(git rev-parse --short HEAD)"
|
|
PREFIX="TargetPrint_${TAG}-${SHORT_SHA}-macos-universal"
|
|
echo "TAG=${TAG}" >> "$GITHUB_ENV"
|
|
echo "SHORT_SHA=${SHORT_SHA}" >> "$GITHUB_ENV"
|
|
echo "PREFIX=${PREFIX}" >> "$GITHUB_ENV"
|
|
echo "VENDOR_PREFIX=TargetPrint_${TAG}-${SHORT_SHA}-vendor-iccery" >> "$GITHUB_ENV"
|
|
|
|
- name: Download Intel .app
|
|
uses: actions/download-artifact@v3
|
|
with:
|
|
name: app-x86_64
|
|
path: ${{ env.PROJECT_ROOT }}/build/apps/x86_64
|
|
|
|
- name: Download Apple Silicon .app
|
|
uses: actions/download-artifact@v3
|
|
with:
|
|
name: app-arm64
|
|
path: ${{ env.PROJECT_ROOT }}/build/apps/arm64
|
|
|
|
- name: Make scripts executable
|
|
working-directory: ${{ env.PROJECT_ROOT }}
|
|
run: chmod +x Scripts/*.sh
|
|
|
|
- name: Lipo Universal 2 .app
|
|
working-directory: ${{ env.PROJECT_ROOT }}
|
|
env:
|
|
MACOS_CODESIGN_IDENTITY: ${{ secrets.MACOS_CODESIGN_IDENTITY }}
|
|
run: |
|
|
export MACOS_CODESIGN_IDENTITY="${MACOS_CODESIGN_IDENTITY:--}"
|
|
# upload-artifact may nest as TargetPrint.app/ or as Contents/ at the root
|
|
for arch in x86_64 arm64; do
|
|
base="build/apps/${arch}"
|
|
if [ ! -x "${base}/TargetPrint.app/Contents/MacOS/TargetPrint" ] \
|
|
&& [ -x "${base}/Contents/MacOS/TargetPrint" ]; then
|
|
mkdir -p "${base}/TargetPrint.app"
|
|
# Move bundle contents into TargetPrint.app
|
|
shopt -s dotglob
|
|
mv "${base}/Contents" "${base}/PkgInfo" "${base}/Resources" "${base}/Info.plist" \
|
|
"${base}/_CodeSignature" "${base}/TargetPrint.app/" 2>/dev/null || true
|
|
shopt -u dotglob
|
|
fi
|
|
test -x "${base}/TargetPrint.app/Contents/MacOS/TargetPrint"
|
|
lipo -info "${base}/TargetPrint.app/Contents/MacOS/TargetPrint"
|
|
done
|
|
./Scripts/make_universal.sh
|
|
lipo -info build/apps/universal/TargetPrint.app/Contents/MacOS/TargetPrint
|
|
|
|
- name: Package universal .app.zip, .dmg, and ICCery vendor zip
|
|
working-directory: ${{ env.PROJECT_ROOT }}
|
|
env:
|
|
MACOS_CODESIGN_IDENTITY: ${{ secrets.MACOS_CODESIGN_IDENTITY }}
|
|
run: |
|
|
export MACOS_CODESIGN_IDENTITY="${MACOS_CODESIGN_IDENTITY:--}"
|
|
./Scripts/package_release.sh x86_64 "TargetPrint_${TAG}-${SHORT_SHA}-macos-x86_64"
|
|
./Scripts/package_release.sh arm64 "TargetPrint_${TAG}-${SHORT_SHA}-macos-arm64"
|
|
./Scripts/package_release.sh universal "${PREFIX}"
|
|
./Scripts/vendor_bundle.sh "${VENDOR_PREFIX}"
|
|
(cd build/release-assets && shasum -a 256 \
|
|
"${PREFIX}.app.zip" "${PREFIX}.dmg" "${VENDOR_PREFIX}.zip" \
|
|
| tee "${PREFIX}.SHA256.txt")
|
|
|
|
- name: Upload universal packages
|
|
uses: actions/upload-artifact@v3
|
|
with:
|
|
name: ${{ env.PREFIX }}
|
|
path: |
|
|
${{ env.PROJECT_ROOT }}/build/release-assets/${{ env.PREFIX }}.*
|
|
${{ env.PROJECT_ROOT }}/build/release-assets/${{ env.VENDOR_PREFIX }}.zip
|
|
|
|
- name: Upload ICCery vendor tree
|
|
uses: actions/upload-artifact@v3
|
|
with:
|
|
name: ${{ env.VENDOR_PREFIX }}
|
|
path: ${{ env.PROJECT_ROOT }}/build/release-assets/vendor-iccery
|
|
|
|
- name: Upload Release Assets to Gitea
|
|
if: ${{ startsWith(github.ref, 'refs/tags/') && !cancelled() }}
|
|
env:
|
|
GITEA_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
SERVER_URL: ${{ github.server_url }}
|
|
REPO: ${{ github.repository }}
|
|
working-directory: ${{ env.PROJECT_ROOT }}
|
|
run: |
|
|
echo "Finding release for tag ${TAG}..."
|
|
RELEASE_RESP=$(curl -s -H "Authorization: token ${GITEA_TOKEN}" \
|
|
"${SERVER_URL}/api/v1/repos/${REPO}/releases/tags/${TAG}")
|
|
RELEASE_ID=$(echo "${RELEASE_RESP}" | grep -o '"id":[0-9]*' | head -n 1 | cut -d: -f2)
|
|
if [ -n "${RELEASE_ID}" ]; then
|
|
echo "Found Release ID: ${RELEASE_ID}. Uploading universal + vendor assets..."
|
|
for f in build/release-assets/${PREFIX}.app.zip \
|
|
build/release-assets/${PREFIX}.dmg \
|
|
build/release-assets/${PREFIX}.SHA256.txt \
|
|
build/release-assets/${VENDOR_PREFIX}.zip; do
|
|
if [ -f "$f" ]; then
|
|
FILENAME=$(basename "$f")
|
|
echo "Uploading $FILENAME..."
|
|
curl -s -X POST \
|
|
-H "Authorization: token ${GITEA_TOKEN}" \
|
|
-H "Content-Type: multipart/form-data" \
|
|
-F "attachment=@$f" \
|
|
"${SERVER_URL}/api/v1/repos/${REPO}/releases/${RELEASE_ID}/assets?name=${FILENAME}"
|
|
fi
|
|
done
|
|
else
|
|
echo "No existing release found for tag ${TAG}. Skipping asset upload."
|
|
fi
|