Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
89 changes: 89 additions & 0 deletions .github/workflows/package-resolved.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
name: Package.resolved check

# Xcode Cloud resolves packages from the committed workspace Package.resolved and
# refuses to update it, so a Package.swift requirement the file no longer satisfies
# fails every deploy at resolution, while local Xcode re-resolves silently. That is
# how the flipcash2 0.14.x bump broke Deploy Flipcash. This resolves with the same
# restriction, so the mismatch fails the PR instead. A stale file fails in under a
# minute, before anything is cloned.
#
# "Package.resolved is current" is a required check on main, so the workflow runs
# on every PR: a workflow-level `paths:` filter would leave PRs that skip it
# waiting on a check that never reports. The cheap `changes` job decides instead,
# and a job skipped by its `if:` counts as passing.

on:
pull_request:
branches: [main]
push:
branches: [main]

concurrency:
group: package-resolved-${{ github.head_ref || github.ref }}
cancel-in-progress: true

jobs:
changes:
name: Package files changed
runs-on: ubuntu-latest
outputs:
packages: ${{ steps.diff.outputs.packages }}
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0

- name: Diff against the base
id: diff
env:
BASE: ${{ github.event.pull_request.base.sha || github.event.before }}
run: |
set -euo pipefail
# A new branch push has an all-zero `before`, and a base that is not
# reachable can't be diffed; check rather than guess in both cases.
if [ -z "$BASE" ] || ! git cat-file -e "$BASE^{commit}" 2>/dev/null; then
echo "packages=true" >> "$GITHUB_OUTPUT"
exit 0
fi
if git diff --name-only "$BASE" HEAD | grep -qE '(^|/)Package\.(swift|resolved)$|^Code\.xcodeproj/project\.pbxproj$|^\.github/workflows/package-resolved\.yml$'; then
echo "packages=true" >> "$GITHUB_OUTPUT"
else
echo "packages=false" >> "$GITHUB_OUTPUT"
fi

resolved:
name: Package.resolved is current
needs: changes
if: needs.changes.outputs.packages == 'true'
runs-on: macos-15
timeout-minutes: 20
steps:
- uses: actions/checkout@v4

# FlipcashCore is swift-tools 6.1, which the image's default Xcode may
# predate. Same selection as vectors.yml.
- name: Select the newest installed Xcode
run: |
set -euo pipefail
XCODE=$(ls -d /Applications/Xcode_*.app 2>/dev/null | sort -V | tail -1 || true)
if [ -n "$XCODE" ]; then
sudo xcode-select -s "$XCODE"
fi
xcodebuild -version

- name: Resolve without updating Package.resolved
run: |
set -euo pipefail
if ! xcodebuild -resolvePackageDependencies \
-project Code.xcodeproj \
-scheme Flipcash \
-disableAutomaticPackageResolution; then
echo "::error file=Code.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved::Package.resolved does not satisfy the Package.swift requirements. Run 'xcodebuild -resolvePackageDependencies -project Code.xcodeproj -scheme Flipcash' and commit the updated file."
exit 1
fi

# Resolution can succeed while still rewriting a pin, which Xcode Cloud
# would see as a change it is not allowed to make.
- name: Package.resolved is unchanged
run: |
git diff --exit-code -- Code.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved
Loading