# Sparkle Quick Reference Card

## Essential Commands

```bash
# Generate signing keys (ONCE)
./generate_keys

# Create a release
./release.sh VERSION "Release notes"

# Sign an update manually
./sign_update build/Tasq.app.zip

# Get file size
stat -f%z build/Tasq.app.zip

# Get current date for appcast
date -R

# Create GitHub release
gh release create vVERSION --title "Tasq VERSION" build/Tasq.app.zip
```

## File Locations

| File | Path | Purpose |
|------|------|---------|
| UpdaterController.swift | `Tasq/UpdaterController.swift` | Sparkle wrapper |
| Info.plist | `Tasq/Info.plist` | Configuration |
| Entitlements | `Tasq/Tasq.entitlements` | Permissions |
| Appcast | `appcast.xml` | Update feed |
| Release Script | `release.sh` | Automation |

## Configuration Keys (Info.plist)

```xml
<key>SUFeedURL</key>
<string>https://raw.githubusercontent.com/USER/Tasq/main/appcast.xml</string>

<key>SUPublicEDKey</key>
<string>YOUR_PUBLIC_KEY</string>

<key>SUEnableAutomaticChecks</key>
<true/>

<key>SUScheduledCheckInterval</key>
<integer>86400</integer>  <!-- 24 hours -->
```

## Appcast Item Template

```xml
<item>
    <title>Version X.Y.Z</title>
    <sparkle:version>BUILD_NUMBER</sparkle:version>
    <sparkle:shortVersionString>X.Y.Z</sparkle:shortVersionString>
    <pubDate>DATE_IN_RFC_822</pubDate>
    <enclosure 
        url="https://github.com/USER/Tasq/releases/download/vX.Y.Z/Tasq.app.zip"
        length="FILE_SIZE"
        sparkle:edSignature="SIGNATURE" />
</item>
```

## Version Numbers

```
Marketing Version: 0.2.4  (CFBundleShortVersionString)
Build Number: 3           (CFBundleVersion)

MUST increment build number each release!
```

## Release Workflow

```
1. Bump version in Xcode
2. ./release.sh 0.2.4 "Notes"
3. Copy signature output
4. Update appcast.xml
5. git commit & push
6. Done!
```

## URLs to Replace

Find and replace these in:
- `Tasq/Info.plist`
- `appcast.xml`

```
YOUR_GITHUB_USERNAME → your-actual-username
YOUR_PUBLIC_KEY_HERE → abc123... (from generate_keys)
```

## Xcode Settings

**Build Settings:**
- Info.plist File: `Tasq/Info.plist`
- Code Signing Entitlements: `Tasq/Tasq.entitlements`

**Package Dependencies:**
- Add: `https://github.com/sparkle-project/Sparkle`
- Version: 2.6.0+

## Testing

```bash
# Lower version to test
# In Xcode: Set Marketing Version to 0.2.2, Build to 1

# Run app
# Right-click icon → About → Check for Updates
# Should offer update to latest version
```

## Common Issues

| Problem | Fix |
|---------|-----|
| "No such module 'Sparkle'" | Add package, clean build |
| "Info.plist not found" | Check Build Settings path |
| "Update improperly signed" | Regenerate keys, re-sign |
| "Cannot find updates" | Check SUFeedURL, verify appcast accessible |

## Security Checklist

- [ ] Private key in GitHub Secrets
- [ ] Private key in password manager (backup)
- [ ] Private key NOT in git
- [ ] Public key in Info.plist
- [ ] .gitignore includes *.privatekey

## File Sizes Reference

```bash
# Get size for appcast
stat -f%z file.zip

# Common sizes (example):
Tasq.app.zip: ~2-5 MB
Tasq.xcarchive: ~10-20 MB
```

## Signature Format

```bash
./sign_update build/Tasq.app.zip

# Output:
sparkle:edSignature="AbCd123..." length="2567890"

# Add both to appcast.xml <enclosure>
```

## Date Format

```bash
date -R
# Output: Mon, 12 Feb 2026 14:30:00 +0000

# Use in appcast <pubDate>
```

## GitHub CLI

```bash
# Install
brew install gh

# Login
gh auth login

# Create release
gh release create v0.2.4 \
  --title "Tasq 0.2.4" \
  --notes "Release notes" \
  build/Tasq.app.zip

# List releases
gh release list

# View release
gh release view v0.2.4
```

## Menu Structure

```
Right-click Tasq icon
├─ Recently Completed
│  └─ (history items)
├─ Clear History
├─ Launch at Login
└─ About
   ├─ Version X.Y.Z (Build N)
   └─ Check for Updates...      ← NEW!
```

## Build Number Logic

```
Current: Build 2
Update:  Build 3

IF update.build > current.build THEN
    Show update notification
ELSE
    "You're up to date"
```

## Network Flow

```
App → Checks → https://raw.githubusercontent.com/.../appcast.xml
              ↓
         Finds update
              ↓
    Downloads → https://github.com/.../releases/download/.../Tasq.app.zip
              ↓
         Verifies signature
              ↓
         Installs & relaunches
```

## Important Notes

⚠️ **Never commit private key**
⚠️ **Always increment build number**
⚠️ **Test updates before releasing**
✅ **Keep Sparkle updated**
✅ **Back up private key securely**

## Useful Links

- Sparkle: https://sparkle-project.org
- Docs: https://sparkle-project.org/documentation/
- GitHub: https://github.com/sparkle-project/Sparkle
- Releases: https://github.com/sparkle-project/Sparkle/releases

## Environment Variables (Optional)

```bash
# For CI/CD
export SPARKLE_PRIVATE_KEY="your-key"
export GITHUB_TOKEN="your-token"
```

## Files to .gitignore

```
build/
*.xcarchive
*.app.zip
*.privatekey
*.pem
sign_update
generate_keys
```

## Troubleshooting Commands

```bash
# Check Info.plist syntax
plutil -lint Tasq/Info.plist

# Validate appcast
xmllint --noout appcast.xml

# Check file permissions
ls -la *.sh

# Make script executable
chmod +x release.sh

# View app version
defaults read /path/to/Tasq.app/Contents/Info CFBundleShortVersionString
defaults read /path/to/Tasq.app/Contents/Info CFBundleVersion
```

## Success Indicators

✅ Build completes without errors
✅ "Check for Updates..." appears in menu
✅ Manual check works
✅ Appcast XML validates
✅ Signature verification succeeds
✅ GitHub release has ZIP attached
✅ Test update installs correctly

---

**Print this or bookmark for quick access!**
