diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml new file mode 100644 index 0000000..7304212 --- /dev/null +++ b/.github/workflows/main.yml @@ -0,0 +1,139 @@ +name: Build + +# Pushes build only on main; other branches are built through their pull request. +# This avoids duplicate runs: concurrency groups are per ref, and a push +# (refs/heads/x) and a pull_request (refs/pull/N/merge) never share a ref. +on: + push: + branches: [main] + paths-ignore: + - '**.md' + - 'LICENSE' + - '.github/ISSUE_TEMPLATE/**' + pull_request: + paths-ignore: + - '**.md' + - 'LICENSE' + - '.github/ISSUE_TEMPLATE/**' + workflow_dispatch: + +# Least privilege by default; only the prerelease job elevates to contents: write. +permissions: + contents: read + +concurrency: + group: build-${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: false + +jobs: + build: + name: VoodooHDA + runs-on: macos-15-intel + timeout-minutes: 45 + steps: + - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1 + - name: Install MacKernelSDK + uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1 + with: + repository: acidanthera/MacKernelSDK + ref: 3f750085caa17ec3a7880f11c11bf4f48cd6a164 + path: MacKernelSDK + - name: Build VoodooHDA for macOS + env: + CONFIGURATION: Release + run: | + set -euo pipefail + mkdir -p logs + xcodebuild -project tranc/VoodooHDA_BS.xcodeproj -target VoodooHDA \ + -configuration "$CONFIGURATION" -jobs 3 ARCHS=x86_64 \ + SYMROOT="$PWD/build/products" OBJROOT="$PWD/build/obj" \ + CODE_SIGNING_ALLOWED=NO GIT_COMMIT="_$(git rev-parse --short HEAD)" \ + build > logs/VoodooHDA.log 2>&1 || { tail -100 logs/VoodooHDA.log; exit 1; } + - name: Package VoodooHDA kernel extension + env: + CONFIGURATION: Release + run: | + set -euo pipefail + mkdir -p artifacts + products="$PWD/build/products/$CONFIGURATION" + version=$(awk '/CURRENT_PROJECT_VERSION =/ {gsub(/;/, "", $3); print $3; exit}' tranc/VoodooHDA_BS.xcodeproj/project.pbxproj) + if [[ -z "$version" ]]; then + echo "::error::Could not determine CURRENT_PROJECT_VERSION from project.pbxproj" + exit 1 + fi + short_sha=$(git rev-parse --short HEAD) + configuration=$(printf '%s' "$CONFIGURATION" | tr '[:lower:]' '[:upper:]') + suffix="v$version-$configuration-alpha-$short_sha" + ditto -c -k --keepParent "$products/VoodooHDA.kext" "artifacts/VoodooHDA-$suffix.zip" + - uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 + with: + name: VoodooHDA + path: artifacts/VoodooHDA-*.zip + if-no-files-found: error + - uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 + if: always() + with: + name: build-logs + path: logs + + prerelease: + name: Publish development build + needs: build + # Only publish from trusted triggers on main. Pull requests (including from + # forks) never reach this job, so untrusted code cannot get a write token. + if: github.ref == 'refs/heads/main' && (github.event_name == 'push' || github.event_name == 'workflow_dispatch') + runs-on: ubuntu-latest + timeout-minutes: 15 + permissions: + contents: write + steps: + - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1 + with: + # Keep in sync with `git log -5` in the release notes step below. + fetch-depth: 5 + - uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0 + with: + name: VoodooHDA + path: artifacts + - name: Publish alpha artifacts + env: + GH_TOKEN: ${{ github.token }} + run: | + set -euo pipefail + version=$(awk '/CURRENT_PROJECT_VERSION =/ {gsub(/;/, "", $3); print $3; exit}' tranc/VoodooHDA_BS.xcodeproj/project.pbxproj) + if [[ -z "$version" ]]; then + echo "::error::Could not determine CURRENT_PROJECT_VERSION from project.pbxproj" + exit 1 + fi + tag="v${version}-alpha" + printf '%s\n\n' 'Development build. Hardware validation is required before daily use.' > ReleaseNotes.md + # -5 intentionally matches fetch-depth: 5 in the checkout step. + git log -5 --format='- %h %s' >> ReleaseNotes.md + if gh release view "$tag" --json isPrerelease > current-release.json 2>/dev/null; then + # Never replace a stable release with development artifacts. + jq -e '.isPrerelease == true' current-release.json > /dev/null + gh api --method PATCH "repos/$GITHUB_REPOSITORY/git/refs/tags/$tag" \ + -f sha="$GITHUB_SHA" -F force=true + gh release edit "$tag" --prerelease --notes-file ReleaseNotes.md + else + gh release create "$tag" --target "$GITHUB_SHA" --prerelease --title "$tag" --notes-file ReleaseNotes.md + fi + gh release upload "$tag" artifacts/VoodooHDA-*.zip --clobber + + # Remove obsolete assets only after the replacement set has uploaded. + gh api "repos/$GITHUB_REPOSITORY/releases/tags/$tag" \ + --jq '.assets[] | [.id, .name] | @tsv' > release-assets.tsv + while IFS=$'\t' read -r asset_id asset_name; do + if [[ ! -f "artifacts/$asset_name" ]]; then + gh api --method DELETE "repos/$GITHUB_REPOSITORY/releases/assets/$asset_id" + fi + done < release-assets.tsv + + # Keep exactly one prerelease; stable releases are retained. + gh api --paginate "repos/$GITHUB_REPOSITORY/releases" \ + --jq '.[] | select(.prerelease and (.draft | not)) | .tag_name' > prereleases.txt + while IFS= read -r old_tag; do + if [[ "$old_tag" != "$tag" ]]; then + gh release delete "$old_tag" --yes --cleanup-tag + fi + done < prereleases.txt