From 80d0160f8e2710e31e0e90249254cc51b2686cd7 Mon Sep 17 00:00:00 2001 From: Claude Date: Sun, 13 Sep 2026 09:02:41 +0000 Subject: [PATCH 1/2] ci: build macOS app on GitHub Actions and publish it to releases Adds a workflow that generates the Xcode project, runs the GuerkchenCore tests and builds a universal Release app on a macOS runner. Pushes to main refresh a rolling "latest" prerelease, v* tags publish a versioned release; pull requests only build and upload an artifact. The app bundle now picks up MARKETING_VERSION / CURRENT_PROJECT_VERSION so released builds carry the right version, and the target gets an explicit scheme for xcodebuild. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01CUUe9N3J5UxHNpfDfpRetV --- .github/workflows/build.yml | 135 ++++++++++++++++++++++++++++++++++++ project.yml | 4 ++ 2 files changed, 139 insertions(+) create mode 100644 .github/workflows/build.yml diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 0000000..6582585 --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,135 @@ +name: Build + +on: + push: + branches: [main] + tags: ["v*"] + pull_request: + workflow_dispatch: + +concurrency: + group: build-${{ github.ref }} + cancel-in-progress: true + +jobs: + build: + name: Build, test and release + runs-on: macos-26 + permissions: + contents: write + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Show toolchain + run: | + xcodebuild -version + swift --version + + - name: Install build tools + run: brew install xcodegen xcbeautify + + - name: Determine version + id: version + run: | + set -euo pipefail + marketing=$(sed -nE 's/^[[:space:]]*MARKETING_VERSION:[[:space:]]*"?([^"[:space:]]+)"?.*/\1/p' project.yml | head -1) + if [ "${GITHUB_REF_TYPE}" = "tag" ]; then + version="${GITHUB_REF_NAME#v}" + asset="guerkchen-${version}.zip" + else + version="${marketing}" + asset="guerkchen-latest.zip" + fi + { + echo "version=${version}" + echo "build=${GITHUB_RUN_NUMBER}" + echo "asset=${asset}" + } >> "$GITHUB_OUTPUT" + + - name: Generate Xcode project + run: xcodegen generate + + - name: Test GuerkchenCore + run: swift test --package-path Core + + - name: Build app (Release) + run: | + set -euo pipefail + xcodebuild build \ + -project guerkchen.xcodeproj \ + -scheme guerkchen \ + -configuration Release \ + -destination 'generic/platform=macOS' \ + -derivedDataPath build \ + MARKETING_VERSION='${{ steps.version.outputs.version }}' \ + CURRENT_PROJECT_VERSION='${{ steps.version.outputs.build }}' \ + | xcbeautify + + - name: Package app + run: | + set -euo pipefail + app="build/Build/Products/Release/guerkchen.app" + test -d "$app" + codesign --verify --verbose "$app" + mkdir -p dist + ditto -c -k --keepParent --sequesterRsrc "$app" "dist/${{ steps.version.outputs.asset }}" + shasum -a 256 "dist/${{ steps.version.outputs.asset }}" + + - name: Upload build artifact + uses: actions/upload-artifact@v4 + with: + name: guerkchen-app + path: dist/*.zip + if-no-files-found: error + + - name: Write release notes + if: github.event_name != 'pull_request' + run: | + set -euo pipefail + cat > release-notes.md </dev/null 2>&1 || true + gh release create latest \ + --target "${GITHUB_SHA}" \ + --title "Latest build (${{ steps.version.outputs.version }})" \ + --notes-file release-notes.md \ + --prerelease \ + "dist/${{ steps.version.outputs.asset }}" + + - name: Publish tagged release + if: github.ref_type == 'tag' + env: + GH_TOKEN: ${{ github.token }} + run: | + set -euo pipefail + if gh release view "${GITHUB_REF_NAME}" >/dev/null 2>&1; then + gh release upload "${GITHUB_REF_NAME}" "dist/${{ steps.version.outputs.asset }}" --clobber + else + gh release create "${GITHUB_REF_NAME}" \ + --title "guerkchen ${{ steps.version.outputs.version }}" \ + --notes-file release-notes.md \ + "dist/${{ steps.version.outputs.asset }}" + fi diff --git a/project.yml b/project.yml index 8c2a7a5..676a63a 100644 --- a/project.yml +++ b/project.yml @@ -27,6 +27,10 @@ targets: LSMinimumSystemVersion: $(MACOSX_DEPLOYMENT_TARGET) LSApplicationCategoryType: public.app-category.developer-tools NSHumanReadableCopyright: "© 2026 René Fürstenberg" + CFBundleShortVersionString: $(MARKETING_VERSION) + CFBundleVersion: $(CURRENT_PROJECT_VERSION) + scheme: + testTargets: [] entitlements: path: Config/guerkchen.entitlements properties: From 6056cfc4faedd0a4d4ebfcfa048f101d57b2984a Mon Sep 17 00:00:00 2001 From: Claude Date: Sun, 13 Sep 2026 09:10:43 +0000 Subject: [PATCH 2/2] ci: bump checkout and upload-artifact to v5 The v4 actions still target Node 20, which the runner now forces onto Node 24 with a deprecation warning. The v5 releases target Node 24 natively. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01CUUe9N3J5UxHNpfDfpRetV --- .github/workflows/build.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 6582585..f2d0a3e 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -20,7 +20,7 @@ jobs: steps: - name: Checkout - uses: actions/checkout@v4 + uses: actions/checkout@v5 - name: Show toolchain run: | @@ -78,7 +78,7 @@ jobs: shasum -a 256 "dist/${{ steps.version.outputs.asset }}" - name: Upload build artifact - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v5 with: name: guerkchen-app path: dist/*.zip