mirror of
https://github.com/samsonjs/vibetunnel.git
synced 2026-03-26 09:35:52 +00:00
330 lines
No EOL
8.6 KiB
Markdown
330 lines
No EOL
8.6 KiB
Markdown
# VibeTunnel Release Process
|
|
|
|
This document describes the complete release process for VibeTunnel, including all prerequisites, steps, and troubleshooting information.
|
|
|
|
## Table of Contents
|
|
|
|
1. [Prerequisites](#prerequisites)
|
|
2. [Pre-Release Checklist](#pre-release-checklist)
|
|
3. [Release Process](#release-process)
|
|
4. [Post-Release Steps](#post-release-steps)
|
|
5. [Troubleshooting](#troubleshooting)
|
|
6. [Lessons Learned](#lessons-learned)
|
|
|
|
## Prerequisites
|
|
|
|
### Required Tools
|
|
|
|
- **Xcode** (latest stable version)
|
|
- **GitHub CLI** (`brew install gh`)
|
|
- **Apple Developer Account** with valid certificates
|
|
- **Sparkle EdDSA Keys** (see [Sparkle Key Management](#sparkle-key-management))
|
|
|
|
### Environment Variables
|
|
|
|
```bash
|
|
# Required for notarization
|
|
export APP_STORE_CONNECT_API_KEY_P8="<your-api-key>"
|
|
export APP_STORE_CONNECT_KEY_ID="<your-key-id>"
|
|
export APP_STORE_CONNECT_ISSUER_ID="<your-issuer-id>"
|
|
|
|
# Optional - will be auto-detected if not set
|
|
export SIGN_IDENTITY="Developer ID Application: Your Name (TEAMID)"
|
|
```
|
|
|
|
### Sparkle Key Management
|
|
|
|
VibeTunnel uses EdDSA signatures for secure updates via Sparkle framework.
|
|
|
|
#### Key Storage
|
|
|
|
- **Private Key**: `private/sparkle_private_key` (NEVER commit this!)
|
|
- **Public Key**: `VibeTunnel/sparkle-public-ed-key.txt` (committed to repo)
|
|
|
|
#### Generating New Keys
|
|
|
|
If you need to generate new keys:
|
|
|
|
```bash
|
|
# Generate keys using Sparkle's tool
|
|
./build/SourcePackages/artifacts/sparkle/Sparkle/bin/generate_keys
|
|
|
|
# This creates a key pair - save the private key securely!
|
|
```
|
|
|
|
#### Restoring Keys
|
|
|
|
To restore keys from backup:
|
|
|
|
```bash
|
|
# Create private directory
|
|
mkdir -p private
|
|
|
|
# Copy your private key (base64 encoded, no comments)
|
|
echo "YOUR_PRIVATE_KEY_BASE64" > private/sparkle_private_key
|
|
|
|
# Ensure it's in .gitignore
|
|
echo "private/" >> .gitignore
|
|
```
|
|
|
|
## Pre-Release Checklist
|
|
|
|
Before starting a release, ensure:
|
|
|
|
1. **Version Configuration**
|
|
- [ ] Update `MARKETING_VERSION` in `VibeTunnel/version.xcconfig`
|
|
- [ ] Increment `CURRENT_PROJECT_VERSION` (build number)
|
|
- [ ] Ensure version follows semantic versioning
|
|
|
|
2. **Code Quality**
|
|
- [ ] All tests pass: `npm run test` (in web/) and Swift tests
|
|
- [ ] Linting passes: `npm run lint`
|
|
- [ ] Typechecking passes: `npm run typecheck`
|
|
- [ ] No uncommitted changes: `git status`
|
|
|
|
3. **Documentation**
|
|
- [ ] Update `CHANGELOG.md` with release notes
|
|
- [ ] Version header format: `## X.Y.Z (YYYY-MM-DD)`
|
|
- [ ] Include sections: Features, Improvements, Bug Fixes
|
|
|
|
4. **Authentication**
|
|
- [ ] GitHub CLI authenticated: `gh auth status`
|
|
- [ ] Signing certificates valid: `security find-identity -v -p codesigning`
|
|
- [ ] Notarization credentials set (environment variables)
|
|
|
|
## Release Process
|
|
|
|
### Automated Release
|
|
|
|
The easiest way to create a release is using the automated script:
|
|
|
|
```bash
|
|
# For stable release
|
|
./scripts/release.sh stable
|
|
|
|
# For pre-release (beta, alpha, rc)
|
|
./scripts/release.sh beta 1 # Creates 1.0.0-beta.1
|
|
./scripts/release.sh rc 2 # Creates 1.0.0-rc.2
|
|
```
|
|
|
|
The script will:
|
|
1. Run pre-flight checks
|
|
2. Build the application
|
|
3. Sign and notarize
|
|
4. Create DMG
|
|
5. Upload to GitHub
|
|
6. Update appcast files
|
|
|
|
### Manual Release Steps
|
|
|
|
If you need to run steps manually:
|
|
|
|
1. **Run Pre-flight Checks**
|
|
```bash
|
|
./scripts/preflight-check.sh
|
|
```
|
|
|
|
2. **Build Application**
|
|
```bash
|
|
# For stable release
|
|
./scripts/build.sh --configuration Release
|
|
|
|
# For pre-release
|
|
IS_PRERELEASE_BUILD=YES ./scripts/build.sh --configuration Release
|
|
```
|
|
|
|
3. **Sign and Notarize**
|
|
```bash
|
|
./scripts/sign-and-notarize.sh --sign-and-notarize
|
|
```
|
|
|
|
4. **Create DMG**
|
|
```bash
|
|
./scripts/create-dmg.sh build/Build/Products/Release/VibeTunnel.app
|
|
```
|
|
|
|
5. **Notarize DMG**
|
|
```bash
|
|
./scripts/notarize-dmg.sh build/VibeTunnel-X.Y.Z.dmg
|
|
```
|
|
|
|
6. **Create GitHub Release**
|
|
```bash
|
|
# Create tag
|
|
git tag -a "vX.Y.Z" -m "Release X.Y.Z"
|
|
git push origin "vX.Y.Z"
|
|
|
|
# Create release
|
|
gh release create "vX.Y.Z" \
|
|
--title "VibeTunnel X.Y.Z" \
|
|
--notes "Release notes here" \
|
|
build/VibeTunnel-X.Y.Z.dmg
|
|
```
|
|
|
|
7. **Update Appcast**
|
|
```bash
|
|
./scripts/generate-appcast.sh
|
|
git add appcast*.xml
|
|
git commit -m "Update appcast for vX.Y.Z"
|
|
git push
|
|
```
|
|
|
|
## Post-Release Steps
|
|
|
|
1. **Verify Release**
|
|
- [ ] Check GitHub release page
|
|
- [ ] Download and test the DMG
|
|
- [ ] Verify auto-update works from previous version
|
|
|
|
2. **Clean Up**
|
|
```bash
|
|
# Clean build artifacts (keeps DMG)
|
|
./scripts/clean.sh --keep-dmg
|
|
|
|
# Restore development version if needed
|
|
git checkout -- VibeTunnel/version.xcconfig
|
|
```
|
|
|
|
3. **Announce Release**
|
|
- [ ] Update website/documentation
|
|
- [ ] Send release announcement
|
|
- [ ] Update issue tracker milestones
|
|
|
|
## Troubleshooting
|
|
|
|
### Common Issues
|
|
|
|
#### "Update isn't properly signed" Error
|
|
|
|
This indicates an EdDSA signature mismatch. Causes:
|
|
- Wrong private key used for signing
|
|
- Appcast not updated after DMG creation
|
|
- Cached signatures from different key
|
|
|
|
Solution:
|
|
1. Ensure correct private key in `private/sparkle_private_key`
|
|
2. Regenerate appcast: `./scripts/generate-appcast.sh`
|
|
3. Commit and push appcast changes
|
|
|
|
#### Build Number Already Exists
|
|
|
|
Error: "Build number X already exists in appcast"
|
|
|
|
Solution:
|
|
1. Increment `CURRENT_PROJECT_VERSION` in `version.xcconfig`
|
|
2. Each release must have a unique build number
|
|
|
|
#### Notarization Fails
|
|
|
|
Common causes:
|
|
- Invalid or expired certificates
|
|
- Missing API credentials
|
|
- Network issues
|
|
|
|
Solution:
|
|
1. Check credentials: `xcrun notarytool history`
|
|
2. Verify certificates: `security find-identity -v`
|
|
3. Check console logs for specific errors
|
|
|
|
#### Xcode Project Version Mismatch
|
|
|
|
If build shows wrong version:
|
|
1. Ensure Xcode project uses `$(CURRENT_PROJECT_VERSION)`
|
|
2. Not hardcoded values
|
|
3. Clean and rebuild
|
|
|
|
### Verification Commands
|
|
|
|
```bash
|
|
# Check signing
|
|
codesign -dv --verbose=4 build/VibeTunnel.app
|
|
|
|
# Check notarization
|
|
spctl -a -t exec -vv build/VibeTunnel.app
|
|
|
|
# Verify DMG
|
|
hdiutil verify build/VibeTunnel-X.Y.Z.dmg
|
|
|
|
# Test EdDSA signature
|
|
./build/SourcePackages/artifacts/sparkle/Sparkle/bin/sign_update \
|
|
build/VibeTunnel-X.Y.Z.dmg \
|
|
-f private/sparkle_private_key
|
|
```
|
|
|
|
## Lessons Learned
|
|
|
|
### Critical Points
|
|
|
|
1. **Always Use Correct Sparkle Keys**
|
|
- The private key must match the public key in the app
|
|
- Store private key securely, never in version control
|
|
- Test signature generation before release
|
|
|
|
2. **Timestamp All Code Signatures**
|
|
- Required for Sparkle components
|
|
- Use `--timestamp` flag on all codesign operations
|
|
- Prevents "update isn't properly signed" errors
|
|
|
|
3. **Version Management**
|
|
- Use xcconfig for centralized version control
|
|
- Never hardcode versions in Xcode project
|
|
- Increment build number for every release
|
|
|
|
4. **Pre-flight Validation**
|
|
- Always run pre-flight checks
|
|
- Ensure clean git state
|
|
- Verify all credentials before starting
|
|
|
|
5. **Appcast Synchronization**
|
|
- Push appcast updates immediately after release
|
|
- GitHub serves as the appcast host
|
|
- Users fetch from raw.githubusercontent.com
|
|
|
|
### Best Practices
|
|
|
|
- **Automate Everything**: Use the release script for consistency
|
|
- **Test Updates**: Always test auto-update from previous version
|
|
- **Keep Logs**: Save notarization logs for debugging
|
|
- **Document Issues**: Update this guide when new issues arise
|
|
- **Clean Regularly**: Use `clean.sh` to manage disk space
|
|
|
|
## Script Reference
|
|
|
|
| Script | Purpose | Key Options |
|
|
|--------|---------|-------------|
|
|
| `release.sh` | Complete automated release | `stable`, `beta N`, `alpha N`, `rc N` |
|
|
| `preflight-check.sh` | Validate release readiness | None |
|
|
| `build.sh` | Build application | `--configuration Release/Debug` |
|
|
| `sign-and-notarize.sh` | Sign and notarize app | `--sign-and-notarize` |
|
|
| `create-dmg.sh` | Create DMG installer | `<app_path> [output_path]` |
|
|
| `notarize-dmg.sh` | Notarize DMG | `<dmg_path>` |
|
|
| `generate-appcast.sh` | Update appcast files | None |
|
|
| `verify-appcast.sh` | Verify appcast validity | None |
|
|
| `clean.sh` | Clean build artifacts | `--all`, `--keep-dmg`, `--dry-run` |
|
|
| `lint.sh` | Run code linters | None |
|
|
|
|
## Environment Setup
|
|
|
|
For team members setting up for releases:
|
|
|
|
```bash
|
|
# 1. Install dependencies
|
|
brew install gh
|
|
npm install -g swiftformat swiftlint
|
|
|
|
# 2. Authenticate GitHub CLI
|
|
gh auth login
|
|
|
|
# 3. Set up notarization credentials
|
|
# Add to ~/.zshrc or ~/.bash_profile:
|
|
export APP_STORE_CONNECT_API_KEY_P8="..."
|
|
export APP_STORE_CONNECT_KEY_ID="..."
|
|
export APP_STORE_CONNECT_ISSUER_ID="..."
|
|
|
|
# 4. Get Sparkle private key from secure storage
|
|
# Contact team lead for access
|
|
```
|
|
|
|
---
|
|
|
|
For questions or issues, consult the script headers or create an issue in the repository. |