CI CD Setup - nself-org/nchat GitHub Wiki
Complete continuous integration and deployment automation for all platforms.
The CI/CD system provides:
- Automated builds for all platforms (Web, iOS, Android, Windows, macOS, Linux)
- Automated testing on every PR
- Automated deployments to TestFlight, Play Store, and GitHub Releases
- Build caching for faster builds
- Notifications via Slack and email
- Version management with automated changelog generation
- Code signing for all platforms
| Platform | Framework | Build Time | Cache | Signing |
|---|---|---|---|---|
| iOS | Capacitor | ~15 min | pnpm, CocoaPods | Apple Certificate |
| Android | Capacitor | ~10 min | pnpm, Gradle | Android Keystore |
| macOS | Electron/Tauri | ~20 min | pnpm, Electron, Rust | Apple Certificate + Notarization |
| Windows | Electron/Tauri | ~15 min | pnpm, Electron, Rust | Code Signing Certificate |
| Linux | Electron/Tauri | ~15 min | pnpm, Electron, Rust | GPG Signature |
| Web | Next.js | ~5 min | pnpm | N/A |
| Docker | Multi-arch | ~10 min | Docker buildx | N/A |
Triggers: Pull requests to main or develop
Jobs:
- โ Lint & Format - ESLint + Prettier
- โ Type Check - TypeScript validation
- โ Unit Tests - Jest tests with coverage
- โ Build Check - Web app build verification
- โ Mobile Build Check - Android debug build (if mobile files changed)
- โ Desktop Build Check - Electron build (if desktop files changed)
- โ Security Scan - npm audit + Snyk
- โ Bundle Size - Bundle analysis
- โ Accessibility - a11y tests
- โ Lighthouse - Performance metrics
Features:
- Smart change detection (only run relevant checks)
- Parallel execution for speed
- PR comments with status summary
- Coverage reporting to Codecov
Example PR Comment:
## PR Checks Summary
| Check | Status |
| ------------- | ---------- |
| Lint & Format | โ
success |
| Type Check | โ
success |
| Unit Tests | โ
success |
| Build | โ
success |
โ
All checks passed! Ready for review.Triggers:
- Push to
mainordevelop(iOS files changed) - Pull requests
- Manual dispatch
Build Types:
- Debug: Simulator build, automatic signing
- Release: Device build, manual signing, IPA export
Caching:
- pnpm store
- CocoaPods (Pods directory + cache)
Deployment:
- Automatic upload to TestFlight (main branch, release builds)
- Requires Apple ID + App-Specific Password
Notifications:
- Slack on success/failure
- Build summary in GitHub Actions
Manual Trigger:
gh workflow run ios-build.yml \
-f build_type=release \
-f deploy_testflight=trueTriggers:
- Push to
mainordevelop(Android files changed) - Pull requests
- Manual dispatch
Build Types:
- Debug APK: Unsigned, for testing
- Release APK: Signed, for direct distribution
- Release AAB: Signed, for Play Store
Caching:
- pnpm store
- Gradle cache (~/.gradle)
Deployment:
- Automatic upload to Play Store (internal track)
- Configurable rollout percentage
- Multiple tracks: internal, alpha, beta, production
Manual Trigger:
gh workflow run android-build.yml \
-f build_type=release \
-f output_format=aab \
-f deploy_playstore=true \
-f playstore_track=internalTriggers:
- Push to
mainordevelop(desktop files changed) - Pull requests
- Manual dispatch
Platforms:
- macOS: Universal binary (.dmg), Apple signed & notarized
- Windows: x64 + ia32 (.exe, .msi), code signed
- Linux: x64 (.deb, .rpm, .AppImage, .snap), GPG signed
Frameworks:
- Electron (default)
- Tauri (optional)
- Both (build with both frameworks)
Caching:
- pnpm store
- Electron cache
- Rust cache (for Tauri)
Signing:
- macOS: Apple Certificate + Notarization
- Windows: Code Signing Certificate (.pfx)
- Linux: GPG signature
Manual Trigger:
gh workflow run desktop-build.yml \
-f platform=all \
-f framework=electron \
-f create_release=trueTriggers:
- Git tags (e.g.,
v0.8.0) - Manual dispatch
Jobs:
- Prepare: Version bump, changelog generation
- Build Web: Next.js production build
- Build Docker: Multi-arch images (amd64, arm64)
- Build Mobile: iOS + Android (optional)
- Build Desktop: All platforms (optional)
- Create Release: GitHub Release with all artifacts
- Deploy Production: Vercel deployment
- Notify: Slack, email, Twitter announcements
Artifacts:
- Web tarball
- Docker images (ghcr.io)
- iOS IPA (if mobile enabled)
- Android APK/AAB (if mobile enabled)
- Desktop installers (if desktop enabled)
Changelog: Automatically generated from commit messages using conventional commits:
-
feat:โ โจ Features -
fix:โ ๐ Bug Fixes -
perf:โ โก Performance -
security:โ ๐ Security -
docs:โ ๐ Documentation -
refactor:โ โป๏ธ Refactoring -
test:โ ๐งช Tests -
build:โ ๐จ Build -
ci:โ ๐ท CI/CD
Manual Trigger:
# Automatic version bump
gh workflow run release-v080.yml \
-f version=0.8.0 \
-f version_type=minor \
-f deploy_mobile=true \
-f deploy_desktop=true
# Or create a tag
git tag v0.8.0
git push origin v0.8.0All scripts are located in /scripts/ and are executable.
Generates CHANGELOG.md from git commits using conventional commits.
./scripts/generate-changelog.sh 0.8.0Features:
- Categorizes commits by type
- Supports emoji prefixes
- Handles breaking changes
- Links to commit hashes
Updates version across all platform configurations.
./scripts/version-bump.sh 0.8.0Updates:
package.jsonplatforms/tauri/tauri.conf.jsonplatforms/tauri/Cargo.toml- iOS
Info.plist - Android
build.gradle
Uploads iOS app to TestFlight.
./scripts/deploy-testflight.sh \
--ipa path/to/App.ipa \
--beta-group "Internal Testers" \
--notifyRequirements:
-
APPLE_ID- Apple ID email -
APPLE_PASSWORD- App-specific password -
APPLE_TEAM_ID- Team ID
Uploads Android app to Google Play Store.
./scripts/deploy-playstore.sh \
--track internal \
--rollout 50 \
--aab path/to/app-release.aabRequirements:
-
PLAY_STORE_JSON_KEY- Base64-encoded service account JSON
Tracks:
-
internal- Internal testing -
alpha- Closed alpha -
beta- Open/closed beta -
production- Production release
Signs desktop applications for all platforms.
# macOS
./scripts/sign-desktop.sh macos dist/nchat.app
# Windows
./scripts/sign-desktop.sh windows dist/nchat.exe
# Linux (GPG)
./scripts/sign-desktop.sh linux dist/nchat.AppImageRequirements:
-
macOS:
CSC_LINK,CSC_KEY_PASSWORD,APPLE_TEAM_ID -
Windows:
WIN_CSC_LINK,WIN_CSC_KEY_PASSWORD -
Linux:
GPG_PRIVATE_KEY,GPG_PASSPHRASE
Notarizes macOS applications with Apple.
./scripts/notarize-macos.sh dist/nchat.dmgRequirements:
APPLE_IDAPPLE_APP_SPECIFIC_PASSWORDAPPLE_TEAM_ID
Process:
- Submit to Apple notarization service
- Wait for approval (5-15 minutes)
- Staple ticket to app
- Verify notarization
All secrets must be configured in GitHub repository settings: Settings โ Secrets and variables โ Actions โ New repository secret
# Apple Developer
[email protected]
APPLE_PASSWORD=xxxx-xxxx-xxxx-xxxx # App-specific password
APPLE_APP_SPECIFIC_PASSWORD=xxxx-xxxx-xxxx-xxxx
APPLE_TEAM_ID=XXXXXXXXXX
# Certificates (base64-encoded)
CERTIFICATES_P12=<base64-encoded .p12 file>
CERTIFICATES_PASSWORD=certificate-password
PROVISIONING_PROFILE=<base64-encoded .mobileprovision>
KEYCHAIN_PASSWORD=temporary-keychain-password
# macOS Desktop
MAC_CERTS=<base64-encoded .p12 file>
MAC_CERTS_PASSWORD=certificate-passwordGenerate base64-encoded certificates:
# iOS/macOS certificate
base64 -i Certificates.p12 -o certificates.txt
cat certificates.txt # Copy to CERTIFICATES_P12 secret
# Provisioning profile
base64 -i AppStore.mobileprovision -o profile.txt
cat profile.txt # Copy to PROVISIONING_PROFILE secret# Keystore (base64-encoded)
KEYSTORE_FILE=<base64-encoded .jks file>
KEYSTORE_PASSWORD=keystore-password
KEY_ALIAS=release-key
KEY_PASSWORD=key-password
# Play Store API
PLAY_STORE_JSON_KEY=<base64-encoded service-account.json>Generate Android keystore:
# Create keystore
keytool -genkey -v -keystore nchat-release.jks \
-alias release-key \
-keyalg RSA -keysize 2048 -validity 10000
# Encode to base64
base64 -i nchat-release.jks -o keystore.txt
cat keystore.txt # Copy to KEYSTORE_FILE secretCreate Play Store service account:
- Go to Google Play Console
- Setup โ API access
- Create new service account
- Download JSON key
- Encode:
base64 -i service-account.json
# Code signing certificate (base64-encoded .pfx)
WIN_CERTS=<base64-encoded .pfx file>
WIN_CSC_KEY_PASSWORD=certificate-password# GPG key (base64-encoded)
GPG_PRIVATE_KEY=<base64-encoded private key>
GPG_PASSPHRASE=key-passphraseExport GPG key:
# Export private key
gpg --export-secret-keys --armor KEY_ID > private-key.asc
# Encode to base64
base64 -i private-key.asc -o gpg-key.txt
cat gpg-key.txt # Copy to GPG_PRIVATE_KEY secret# Slack
SLACK_WEBHOOK_URL=https://hooks.slack.com/services/T00000000/B00000000/XXXXXXXXXXXXXXXXXXXX
# Email (SendGrid)
SENDGRID_API_KEY=SG.xxxxxxxxxxxxxxxxxxxxxxxx
[email protected]
# Twitter/X (optional)
TWITTER_API_KEY=xxxxxxxxxxxxxxxxxxxxxxxx
TWITTER_API_SECRET=xxxxxxxxxxxxxxxxxxxxxxxx
TWITTER_ACCESS_TOKEN=xxxxxxxxxxxxxxxxxxxxxxxx
TWITTER_ACCESS_SECRET=xxxxxxxxxxxxxxxxxxxxxxxx# Codecov
CODECOV_TOKEN=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
# Snyk
SNYK_TOKEN=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
# Vercel (optional)
VERCEL_TOKEN=xxxxxxxxxxxxxxxxxxxxxxxx
VERCEL_ORG_ID=team_xxxxxxxxxxxxxxxxxxxxxxxx
VERCEL_PROJECT_ID=prj_xxxxxxxxxxxxxxxxxxxxxxxx
# Lighthouse CI (optional)
LHCI_GITHUB_APP_TOKEN=xxxxxxxxxxxxxxxxxxxxxxxx-
Prepare code:
git checkout main git pull origin main
-
Run release workflow:
# Option 1: Manual workflow dispatch gh workflow run release-v080.yml \ -f version=0.8.0 \ -f version_type=minor \ -f deploy_mobile=true \ -f deploy_desktop=true # Option 2: Create tag git tag v0.8.0 git push origin v0.8.0
-
Monitor workflow:
gh run watch
-
Verify release:
- Check GitHub Releases page
- Verify Docker image:
docker pull ghcr.io/YOUR_ORG/nself-chat:0.8.0 - Test iOS build in TestFlight
- Test Android build in Play Console
-
Create PR:
git checkout -b feature/my-feature # Make changes git commit -m "feat: add new feature" git push origin feature/my-feature gh pr create
-
PR checks run automatically:
- Lint & Format
- Type Check
- Unit Tests
- Build Check
-
Monitor PR checks:
gh pr checks
-
Fix failures:
pnpm lint:fix pnpm format pnpm type-check pnpm test
iOS only:
gh workflow run ios-build.yml \
-f build_type=release \
-f deploy_testflight=trueAndroid only:
gh workflow run android-build.yml \
-f build_type=release \
-f output_format=aab \
-f deploy_playstore=trueDesktop (macOS only):
gh workflow run desktop-build.yml \
-f platform=macos \
-f framework=electronDesktop (all platforms):
gh workflow run desktop-build.yml \
-f platform=all \
-f framework=electron \
-f create_release=trueProblem: Certificate import fails
Error: The specified item could not be found in the keychain
Solution:
- Verify
CERTIFICATES_P12is valid base64 - Check
CERTIFICATES_PASSWORDmatches certificate - Ensure certificate is not expired
Problem: Provisioning profile mismatch
Error: No matching provisioning profile found
Solution:
- Regenerate provisioning profile in Apple Developer portal
- Include correct devices for development
- Re-encode and update
PROVISIONING_PROFILEsecret
Problem: Keystore not found
Error: Keystore file not found
Solution:
- Verify
KEYSTORE_FILEsecret is set - Check base64 encoding is valid
- Ensure keystore was created with correct alias
Problem: Play Store upload fails
Error: Invalid service account JSON
Solution:
- Verify service account has correct permissions
- Re-download JSON key from Play Console
- Re-encode and update
PLAY_STORE_JSON_KEY
Problem: macOS notarization fails
Error: Notarization failed with status: invalid
Solution:
- Check notarization log:
cat notarization-log.json - Common issues:
- App not signed with Developer ID
- Hardened runtime not enabled
- Invalid entitlements
- Re-sign with correct settings
Problem: Windows signing fails
Error: No Windows signing tool found
Solution:
- Install osslsigncode:
brew install osslsigncode - Or use Windows runner with signtool.exe
Problem: Workflow not triggering
No workflow runs found
Solution:
- Check workflow file syntax:
gh workflow view - Verify trigger conditions match
- Check branch protection rules
Problem: Cache not restoring
Cache not found
Solution:
- Delete cache:
gh cache delete <cache-key> - Wait for new cache to be created
- Check cache key matches lock file hash
Problem: Slack notifications not sending
Slack webhook failed
Solution:
- Verify
SLACK_WEBHOOK_URLis valid - Test webhook:
curl -X POST -H 'Content-type: application/json' --data '{"text":"Test"}' $SLACK_WEBHOOK_URL - Check Slack app permissions
-
Always test locally first:
pnpm lint pnpm type-check pnpm test pnpm build -
Use conventional commits:
feat: add new feature fix: resolve bug docs: update documentation chore: update dependencies
-
Keep secrets secure:
- Never commit secrets to repository
- Rotate secrets regularly
- Use environment-specific secrets
-
Monitor build times:
- Use caching effectively
- Parallelize independent jobs
- Skip unnecessary builds
-
Version management:
- Follow semantic versioning
- Update CHANGELOG.md
- Tag releases properly
- ๐ง Email: [email protected]
- ๐ฌ Discord: https://discord.gg/nself
- ๐ Docs: https://docs.nself.org
- ๐ Issues: https://github.com/nself-chat/issues
Last Updated: 2026-01-31 Version: 0.8.0