Skip to content
Merged
Show file tree
Hide file tree
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
21 changes: 21 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -59,3 +59,24 @@ jobs:
-derivedDataPath "$RUNNER_TEMP/DerivedData" \
CODE_SIGNING_ALLOWED=NO \
CODE_SIGNING_REQUIRED=NO

mas-build:
name: Mac App Store Build
runs-on: macos-26

steps:
- name: Checkout
uses: actions/checkout@v7

# Keeps the Sparkle-free target compiling: this build has no Sparkle
# package linked, so every canImport(Sparkle) guard must hold.
- name: Build app (Mac App Store target)
run: |
xcodebuild build \
-project ComputerSolitaire.xcodeproj \
-scheme ComputerSolitaireAppStore \
-configuration Debug \
-destination "platform=macOS" \
-derivedDataPath "$RUNNER_TEMP/DerivedData" \
CODE_SIGNING_ALLOWED=NO \
CODE_SIGNING_REQUIRED=NO
145 changes: 136 additions & 9 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,16 +20,15 @@ jobs:
env:
RELEASE_TAG: ${{ github.ref_name }}
run: |
MARKETING_VERSIONS="$(
BUILD_SETTINGS="$(
xcodebuild \
-project ComputerSolitaire.xcodeproj \
-scheme ComputerSolitaire \
-configuration Release \
-destination "generic/platform=macOS" \
-showBuildSettings |
awk '$1 == "MARKETING_VERSION" && $2 == "=" { print $3 }' |
sort -u
-showBuildSettings
)"
MARKETING_VERSIONS="$(printf '%s\n' "$BUILD_SETTINGS" | awk '$1 == "MARKETING_VERSION" && $2 == "=" { print $3 }' | sort -u)"
VERSION_COUNT="$(printf '%s\n' "$MARKETING_VERSIONS" | awk 'NF { count++ } END { print count + 0 }')"

if [[ "$VERSION_COUNT" -ne 1 ]]; then
Expand All @@ -45,6 +44,13 @@ jobs:
exit 1
fi

BUILD_VERSIONS="$(printf '%s\n' "$BUILD_SETTINGS" | awk '$1 == "CURRENT_PROJECT_VERSION" && $2 == "=" { print $3 }' | sort -u)"
if [[ "$BUILD_VERSIONS" != "$MARKETING_VERSIONS" ]]; then
echo "CURRENT_PROJECT_VERSION must equal MARKETING_VERSION ($MARKETING_VERSIONS), but found: $BUILD_VERSIONS"
echo "Sparkle compares CFBundleVersion to decide whether an update is newer, so the build version must advance with every release."
exit 1
fi

- name: Import Apple signing certificate
env:
P12_BASE64: ${{ secrets.APPLE_CERT_P12_BASE64 }}
Expand Down Expand Up @@ -169,13 +175,33 @@ jobs:
- name: Create GitHub Release
env:
GH_TOKEN: ${{ github.token }}
RELEASE_TAG: ${{ github.ref_name }}
run: |
DMG_PATH="ComputerSolitaire-${{ github.ref_name }}-arm64.dmg"
if gh release view "${{ github.ref_name }}" >/dev/null 2>&1; then
gh release upload "${{ github.ref_name }}" "$DMG_PATH" --clobber
DMG_PATH="ComputerSolitaire-$RELEASE_TAG-arm64.dmg"
if gh release view "$RELEASE_TAG" >/dev/null 2>&1; then
gh release upload "$RELEASE_TAG" "$DMG_PATH" --clobber
exit 0
fi

# Release notes come from this version's CHANGELOG.md section — the
# same text the Sparkle update dialog shows. Fall back to GitHub's
# PR-based notes if the section is missing.
NOTES_FILE="$RUNNER_TEMP/release-notes.md"
awk -v version="${RELEASE_TAG#v}" '
$1 == "##" && $2 == version { in_section = 1; next }
$1 == "##" { in_section = 0 }
in_section { print }
' CHANGELOG.md > "$NOTES_FILE"

if [[ -s "$NOTES_FILE" ]]; then
gh release create "$RELEASE_TAG" \
--title "$RELEASE_TAG" \
--notes-file "$NOTES_FILE" \
"$DMG_PATH"
else
gh release create "${{ github.ref_name }}" \
--title "${{ github.ref_name }}" \
echo "::warning::CHANGELOG.md has no section for ${RELEASE_TAG#v}; using GitHub-generated notes."
gh release create "$RELEASE_TAG" \
--title "$RELEASE_TAG" \
--generate-notes \
"$DMG_PATH"
fi
Expand All @@ -189,3 +215,104 @@ jobs:
if [[ -n "${NOTARY_API_KEY_PATH:-}" ]]; then
rm -f "$NOTARY_API_KEY_PATH"
fi

appcast:
needs: release
runs-on: macos-26
permissions:
contents: read

env:
# Releases older than this predate Sparkle (their CFBundleVersion is
# stuck at 1), so they never appear in the appcast.
FIRST_SPARKLE_TAG: v0.8.3
SPARKLE_VERSION: 2.9.4
SPARKLE_TOOLS_SHA256: ce89daf967db1e1893ed3ebd67575ed82d3902563e3191ca92aaec9164fbdef9

steps:
- name: Checkout
uses: actions/checkout@v7

- name: Download release archives
env:
GH_TOKEN: ${{ github.token }}
run: |
mkdir -p archives
for TAG in $(gh release list --limit 100 --json tagName --jq '.[].tagName'); do
OLDEST="$(printf '%s\n%s\n' "$FIRST_SPARKLE_TAG" "$TAG" | sort -V | head -1)"
Comment thread
austin-smith marked this conversation as resolved.
Comment thread
austin-smith marked this conversation as resolved.
if [[ "$OLDEST" == "$FIRST_SPARKLE_TAG" ]]; then
gh release download "$TAG" --pattern '*.dmg' --dir archives
fi
done
ls archives

- name: Extract release notes from CHANGELOG.md
run: |
for DMG in archives/*.dmg; do
BASENAME="$(basename "$DMG" .dmg)"
VERSION="$(printf '%s' "$BASENAME" | sed -E 's/^ComputerSolitaire-v([0-9.]+)-arm64$/\1/')"
awk -v version="$VERSION" '
$1 == "##" && $2 == version { in_section = 1; next }
$1 == "##" { in_section = 0 }
in_section { print }
' CHANGELOG.md > "archives/$BASENAME.md"
if [[ ! -s "archives/$BASENAME.md" ]]; then
echo "::warning::CHANGELOG.md has no section for $VERSION; its appcast entry will have no release notes."
rm "archives/$BASENAME.md"
fi
done

- name: Fetch Sparkle tools
run: |
curl -sL -o sparkle-tools.tar.xz \
"https://github.com/sparkle-project/Sparkle/releases/download/$SPARKLE_VERSION/Sparkle-$SPARKLE_VERSION.tar.xz"
echo "$SPARKLE_TOOLS_SHA256 sparkle-tools.tar.xz" | shasum -a 256 -c -
mkdir -p sparkle-tools
tar -xf sparkle-tools.tar.xz -C sparkle-tools

- name: Generate appcast
env:
SPARKLE_ED_PRIVATE_KEY: ${{ secrets.SPARKLE_ED_PRIVATE_KEY }}
run: |
if [[ -z "${SPARKLE_ED_PRIVATE_KEY:-}" ]]; then
echo "Missing required secret: SPARKLE_ED_PRIVATE_KEY"
exit 1
fi

mkdir -p site
printf '%s' "$SPARKLE_ED_PRIVATE_KEY" | ./sparkle-tools/bin/generate_appcast archives \
--ed-key-file - \
--download-url-prefix "https://github.com/austin-smith/ComputerSolitaire/releases/download/" \
--link "https://github.com/austin-smith/ComputerSolitaire" \
--embed-release-notes \
--maximum-versions 5 \
--maximum-deltas 0 \
-o site/appcast.xml

# Each DMG lives under its release's download path, not a flat
# directory; the tag is recoverable from the filename.
sed -i '' -E \
's|(releases/download/)(ComputerSolitaire-(v[0-9.]+)-arm64\.dmg)|\1\3/\2|g' \
site/appcast.xml

cat site/appcast.xml

- name: Upload Pages artifact
uses: actions/upload-pages-artifact@v4
with:
path: site

deploy-appcast:
needs: appcast
runs-on: ubuntu-latest
permissions:
pages: write
id-token: write
environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}

steps:
- name: Deploy to GitHub Pages
id: deployment
uses: actions/deploy-pages@v4
153 changes: 153 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
# Changelog

## 0.8.2 - 2026-07-15

### Added

- Animation Speed setting with Normal, Fast, and Instant options; Reduce Motion now suppresses gameplay animations and the win cascade. ([#76](https://github.com/austin-smith/ComputerSolitaire/pull/76), [#77](https://github.com/austin-smith/ComputerSolitaire/pull/77))
- Blue and Pink alternate app icons. ([#74](https://github.com/austin-smith/ComputerSolitaire/pull/74))

### Changed

- Updated the primary app icon from blue to teal. ([#74](https://github.com/austin-smith/ComputerSolitaire/pull/74))

### Fixed

- Restored card-flight animations for tap-to-move, drag-and-drop, auto-finish, and invalid-drop returns. ([#75](https://github.com/austin-smith/ComputerSolitaire/pull/75))

**Full Changelog**: https://github.com/austin-smith/ComputerSolitaire/compare/v0.8.1...v0.8.2

## 0.8.1 - 2026-07-14

### Fixed

#### Performance

- Reduced per-move rendering across all ten games by limiting animation transactions to affected board regions and skipping unchanged cards, piles, and top rows. ([#70](https://github.com/austin-smith/ComputerSolitaire/pull/70), [#72](https://github.com/austin-smith/ComputerSolitaire/pull/72))
- Moved saved-game sanitization and JSON encoding off the main thread and skipped superseded autosaves. ([#70](https://github.com/austin-smith/ComputerSolitaire/pull/70))
- Limited per-frame drag and win-cascade updates to their overlays instead of re-evaluating the entire board, while preserving structural SwiftUI diffing through the main scene. ([#71](https://github.com/austin-smith/ComputerSolitaire/pull/71))
- Short-circuited FreeCell auto-finish availability checks when cascade ordering cannot complete, avoiding a full win simulation on most moves. ([#70](https://github.com/austin-smith/ComputerSolitaire/pull/70))

**Full Changelog**: https://github.com/austin-smith/ComputerSolitaire/compare/v0.8.0...v0.8.1

## 0.8.0 - 2026-07-14

### Added

#### Eight new game variants

Each variant includes its own solver-backed hints, persistence, rules and scoring, statistics, and accessibility support.

- Spider ([#48](https://github.com/austin-smith/ComputerSolitaire/pull/48))
- Pyramid ([#47](https://github.com/austin-smith/ComputerSolitaire/pull/47))
- TriPeaks ([#52](https://github.com/austin-smith/ComputerSolitaire/pull/52))
- Golf ([#58](https://github.com/austin-smith/ComputerSolitaire/pull/58))
- Yukon ([#42](https://github.com/austin-smith/ComputerSolitaire/pull/42))
- Scorpion ([#60](https://github.com/austin-smith/ComputerSolitaire/pull/60))
- Forty Thieves ([#61](https://github.com/austin-smith/ComputerSolitaire/pull/61))
- Canfield ([#63](https://github.com/austin-smith/ComputerSolitaire/pull/63))

#### Settings and feedback

- Option to disable haptic feedback on iOS ([#66](https://github.com/austin-smith/ComputerSolitaire/pull/66))
- Option to hide in-game statistics ([#66](https://github.com/austin-smith/ComputerSolitaire/pull/66))
- Option to hide stock counts ([#66](https://github.com/austin-smith/ComputerSolitaire/pull/66))
- Haptic feedback for starting auto-finish and winning games ([#62](https://github.com/austin-smith/ComputerSolitaire/pull/62))

### Changed

- Replaced Settings-based game selection with an on-board game picker. ([#53](https://github.com/austin-smith/ComputerSolitaire/pull/53))
- Each game mode now keeps its own saved session and statistics; switching modes pauses the current game instead of ending it. ([#53](https://github.com/austin-smith/ComputerSolitaire/pull/53))
- The game picker now indicates overflow with edge fades and opens with the current game in view. ([#68](https://github.com/austin-smith/ComputerSolitaire/pull/68))
- Redesigned Statistics as a cross-game overview with per-game detail and mode-specific breakdowns. ([#53](https://github.com/austin-smith/ComputerSolitaire/pull/53))
- Reorganized the iOS toolbar to keep Hint and Undo visible, show Auto Finish only when available, and move other actions into the More menu. ([#62](https://github.com/austin-smith/ComputerSolitaire/pull/62))
- Reorganized the macOS toolbar with contextual Auto Finish, grouped Hint and Undo controls, and a combined New Game and Redeal menu. ([#62](https://github.com/austin-smith/ComputerSolitaire/pull/62))
- Reorganized Settings into focused sections with dedicated appearance pages. ([#66](https://github.com/austin-smith/ComputerSolitaire/pull/66))
- Replaced the macOS settings sheet with a standard Settings window. ([#66](https://github.com/austin-smith/ComputerSolitaire/pull/66))
- Rules & Scoring can now display any game instead of only the game in progress. ([#66](https://github.com/austin-smith/ComputerSolitaire/pull/66))
- Added macOS keyboard shortcuts for switching directly between games. ([#64](https://github.com/austin-smith/ComputerSolitaire/pull/64))
- Moved statistics reset actions from the iOS toolbar into the statistics form. ([#64](https://github.com/austin-smith/ComputerSolitaire/pull/64))
- Revised the Rules & Scoring text across all ten games for consistent terminology. ([#64](https://github.com/austin-smith/ComputerSolitaire/pull/64))
- Added staggered stock-to-tableau deal animations and in-flight card flips for Spider and Scorpion. ([#60](https://github.com/austin-smith/ComputerSolitaire/pull/60), [#61](https://github.com/austin-smith/ComputerSolitaire/pull/61))

### Fixed

- Restoring a saved game no longer replaces its board when the saved variant differs from the stored game setting. ([#47](https://github.com/austin-smith/ComputerSolitaire/pull/47))
- Undoing Klondike stock draws and waste recycles now flips returning cards during their flights instead of snapping their face state at landing. ([#60](https://github.com/austin-smith/ComputerSolitaire/pull/60))

**Full Changelog**: https://github.com/austin-smith/ComputerSolitaire/compare/v0.7.0...v0.8.0

## 0.7.0 - 2026-07-12

### Added

- New FreeCell game mode, including supermoves, hints, auto-finish, persistence, rules, and statistics. ([#26](https://github.com/austin-smith/ComputerSolitaire/pull/26))
- Per-variant and combined statistics for Klondike and FreeCell. ([#26](https://github.com/austin-smith/ComputerSolitaire/pull/26))
- Pixel and Simple card styles. ([#26](https://github.com/austin-smith/ComputerSolitaire/pull/26), [#32](https://github.com/austin-smith/ComputerSolitaire/pull/32))
- Configurable card-back colors. ([#32](https://github.com/austin-smith/ComputerSolitaire/pull/32))
- Alternate app icons. ([#28](https://github.com/austin-smith/ComputerSolitaire/pull/28))
- About page on iOS. ([#34](https://github.com/austin-smith/ComputerSolitaire/pull/34))

### Changed

- Redesigned the hint and move-advisor system with variant-specific logic, improved Klondike planning, solver-backed FreeCell hints, and updated tap-to-move behavior. ([#26](https://github.com/austin-smith/ComputerSolitaire/pull/26))
- Redesigned Settings. ([#30](https://github.com/austin-smith/ComputerSolitaire/pull/30), [#32](https://github.com/austin-smith/ComputerSolitaire/pull/32))
- Updated card rendering, board sizing, draw animations, and felt rendering. ([#32](https://github.com/austin-smith/ComputerSolitaire/pull/32))
- Improved VoiceOver labels, selected states, and card/pile exposure. ([#39](https://github.com/austin-smith/ComputerSolitaire/pull/39))

### Fixed

- Draw-one recycle penalties now use the draw mode selected when the game was dealt. ([#29](https://github.com/austin-smith/ComputerSolitaire/pull/29))

**Full Changelog**: https://github.com/austin-smith/ComputerSolitaire/compare/v0.6.0...v0.7.0

## 0.6.0 - 2026-02-23

### What's Changed

* Enhance statistics view in https://github.com/austin-smith/ComputerSolitaire/pull/18
* Add macOS menu bar game controls in https://github.com/austin-smith/ComputerSolitaire/pull/19
* Add comprehensive unit tests in https://github.com/austin-smith/ComputerSolitaire/pull/20

**Full Changelog**: https://github.com/austin-smith/ComputerSolitaire/compare/v0.5.0...v0.6.0

## 0.5.0 - 2026-02-21

### What's Changed

* Fix iOS SFX playback in silent mode in https://github.com/austin-smith/ComputerSolitaire/pull/4
* Haptic feedback for iOS in https://github.com/austin-smith/ComputerSolitaire/pull/5
* Replace AppKit & UIKit usage with SwiftUI in https://github.com/austin-smith/ComputerSolitaire/pull/6
* Code cleanup & optimization in https://github.com/austin-smith/ComputerSolitaire/pull/7
* Prevent board clipping with responsive board scaling in https://github.com/austin-smith/ComputerSolitaire/pull/8
* Add hint system in https://github.com/austin-smith/ComputerSolitaire/pull/9
* Cache hint availability to reduce recycle lag in https://github.com/austin-smith/ComputerSolitaire/pull/10
* Add win cascade celebration animation in https://github.com/austin-smith/ComputerSolitaire/pull/11
* Hint system improvements and macOS CI test workflow in https://github.com/austin-smith/ComputerSolitaire/pull/12

**Full Changelog**: https://github.com/austin-smith/ComputerSolitaire/compare/v0.4.1...v0.5.0

## 0.4.1 - 2026-02-16

### What's Changed

* Add code signing & notary steps to GitHub release action in https://github.com/austin-smith/ComputerSolitaire/pull/3

**Full Changelog**: https://github.com/austin-smith/ComputerSolitaire/compare/v0.4.0...v0.4.1

## 0.4.0 - 2026-02-16

### What's Changed

* Ensure timer is paused when menus are open in https://github.com/austin-smith/ComputerSolitaire/pull/2

**Full Changelog**: https://github.com/austin-smith/ComputerSolitaire/compare/v0.3.0...v0.4.0

## 0.3.0 - 2026-02-16

### What's Changed

* Base game functionality
* Scoring and stats in https://github.com/austin-smith/ComputerSolitaire/pull/1

**Full Changelog**: https://github.com/austin-smith/ComputerSolitaire/commits/v0.3.0
Loading