Implement GitOps workflows with ArgoCD and Flux for automated, declarative Kubernetes...
npx skills add Cap-go/capacitor-skills --skill "capacitor-ci-cd"
Install specific skill from multi-skill repository
# Description
Complete CI/CD guide for Capacitor apps covering GitHub Actions, GitLab CI, build automation, app signing, and deployment pipelines. Use this skill when users need to automate their build and release process.
# SKILL.md
name: capacitor-ci-cd
description: Complete CI/CD guide for Capacitor apps covering GitHub Actions, GitLab CI, build automation, app signing, and deployment pipelines. Use this skill when users need to automate their build and release process.
CI/CD for Capacitor Applications
Automate building, testing, and deploying Capacitor apps.
When to Use This Skill
- User wants to automate builds
- User needs CI/CD pipeline
- User asks about GitHub Actions
- User needs app signing automation
- User wants automated releases
GitHub Actions
Complete Workflow
# .github/workflows/build.yml
name: Build and Deploy
on:
push:
branches: [main, develop]
pull_request:
branches: [main]
env:
NODE_VERSION: '20'
jobs:
# Run tests and linting
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: oven-sh/setup-bun@v1
- name: Install dependencies
run: bun install
- name: Lint
run: bun run lint
- name: Type check
run: bun run typecheck
- name: Unit tests
run: bun test --coverage
- name: Upload coverage
uses: codecov/codecov-action@v4
# Security scan
security:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: oven-sh/setup-bun@v1
- run: bunx capsec scan --ci
# Build web assets
build-web:
runs-on: ubuntu-latest
needs: [test, security]
steps:
- uses: actions/checkout@v4
- uses: oven-sh/setup-bun@v1
- name: Install dependencies
run: bun install
- name: Build
run: bun run build
- name: Upload build artifacts
uses: actions/upload-artifact@v4
with:
name: web-build
path: dist/
# Build iOS
build-ios:
runs-on: macos-latest
needs: build-web
steps:
- uses: actions/checkout@v4
- uses: oven-sh/setup-bun@v1
- name: Download web build
uses: actions/download-artifact@v4
with:
name: web-build
path: dist/
- name: Install dependencies
run: bun install
- name: Sync Capacitor
run: bunx cap sync ios
- name: Setup Ruby
uses: ruby/setup-ruby@v1
with:
ruby-version: '3.2'
bundler-cache: true
working-directory: ios/App
- name: Install CocoaPods
run: cd ios/App && pod install
- name: Import certificates
env:
CERTIFICATE_P12: ${{ secrets.CERTIFICATE_P12 }}
CERTIFICATE_PASSWORD: ${{ secrets.CERTIFICATE_PASSWORD }}
PROVISIONING_PROFILE: ${{ secrets.PROVISIONING_PROFILE }}
run: |
# Create keychain
security create-keychain -p "" build.keychain
security default-keychain -s build.keychain
security unlock-keychain -p "" build.keychain
security set-keychain-settings -t 3600 -u build.keychain
# Import certificate
echo "$CERTIFICATE_P12" | base64 --decode > certificate.p12
security import certificate.p12 -k build.keychain -P "$CERTIFICATE_PASSWORD" -T /usr/bin/codesign
security set-key-partition-list -S apple-tool:,apple:,codesign: -s -k "" build.keychain
# Install provisioning profile
mkdir -p ~/Library/MobileDevice/Provisioning\ Profiles
echo "$PROVISIONING_PROFILE" | base64 --decode > ~/Library/MobileDevice/Provisioning\ Profiles/profile.mobileprovision
- name: Build iOS
run: |
cd ios/App
xcodebuild -workspace App.xcworkspace \
-scheme App \
-configuration Release \
-archivePath build/App.xcarchive \
archive
- name: Export IPA
run: |
cd ios/App
xcodebuild -exportArchive \
-archivePath build/App.xcarchive \
-exportPath build/ \
-exportOptionsPlist ExportOptions.plist
- name: Upload IPA
uses: actions/upload-artifact@v4
with:
name: ios-build
path: ios/App/build/*.ipa
# Build Android
build-android:
runs-on: ubuntu-latest
needs: build-web
steps:
- uses: actions/checkout@v4
- uses: oven-sh/setup-bun@v1
- name: Download web build
uses: actions/download-artifact@v4
with:
name: web-build
path: dist/
- name: Setup Java
uses: actions/setup-java@v4
with:
java-version: '17'
distribution: 'temurin'
- name: Setup Android SDK
uses: android-actions/setup-android@v3
- name: Install dependencies
run: bun install
- name: Sync Capacitor
run: bunx cap sync android
- name: Decode keystore
env:
KEYSTORE_BASE64: ${{ secrets.KEYSTORE_BASE64 }}
run: |
echo "$KEYSTORE_BASE64" | base64 --decode > android/app/release.keystore
- name: Build APK
env:
KEYSTORE_PASSWORD: ${{ secrets.KEYSTORE_PASSWORD }}
KEY_ALIAS: ${{ secrets.KEY_ALIAS }}
KEY_PASSWORD: ${{ secrets.KEY_PASSWORD }}
run: |
cd android
./gradlew assembleRelease \
-Pandroid.injected.signing.store.file=release.keystore \
-Pandroid.injected.signing.store.password=$KEYSTORE_PASSWORD \
-Pandroid.injected.signing.key.alias=$KEY_ALIAS \
-Pandroid.injected.signing.key.password=$KEY_PASSWORD
- name: Build AAB
env:
KEYSTORE_PASSWORD: ${{ secrets.KEYSTORE_PASSWORD }}
KEY_ALIAS: ${{ secrets.KEY_ALIAS }}
KEY_PASSWORD: ${{ secrets.KEY_PASSWORD }}
run: |
cd android
./gradlew bundleRelease \
-Pandroid.injected.signing.store.file=release.keystore \
-Pandroid.injected.signing.store.password=$KEYSTORE_PASSWORD \
-Pandroid.injected.signing.key.alias=$KEY_ALIAS \
-Pandroid.injected.signing.key.password=$KEY_PASSWORD
- name: Upload APK
uses: actions/upload-artifact@v4
with:
name: android-apk
path: android/app/build/outputs/apk/release/*.apk
- name: Upload AAB
uses: actions/upload-artifact@v4
with:
name: android-aab
path: android/app/build/outputs/bundle/release/*.aab
# Deploy to Capgo
deploy-capgo:
runs-on: ubuntu-latest
needs: build-web
if: github.ref == 'refs/heads/main'
steps:
- uses: actions/checkout@v4
- uses: oven-sh/setup-bun@v1
- name: Download web build
uses: actions/download-artifact@v4
with:
name: web-build
path: dist/
- name: Deploy to Capgo
run: bunx @capgo/cli upload
env:
CAPGO_TOKEN: ${{ secrets.CAPGO_TOKEN }}
# Deploy to App Store
deploy-ios:
runs-on: macos-latest
needs: build-ios
if: github.ref == 'refs/heads/main'
steps:
- uses: actions/checkout@v4
- name: Download IPA
uses: actions/download-artifact@v4
with:
name: ios-build
path: build/
- name: Upload to App Store Connect
env:
APP_STORE_CONNECT_API_KEY: ${{ secrets.APP_STORE_CONNECT_API_KEY }}
run: |
xcrun altool --upload-app \
--type ios \
--file build/*.ipa \
--apiKey ${{ secrets.API_KEY_ID }} \
--apiIssuer ${{ secrets.API_ISSUER_ID }}
# Deploy to Play Store
deploy-android:
runs-on: ubuntu-latest
needs: build-android
if: github.ref == 'refs/heads/main'
steps:
- uses: actions/checkout@v4
- name: Download AAB
uses: actions/download-artifact@v4
with:
name: android-aab
path: build/
- name: Upload to Play Store
uses: r0adkll/upload-google-play@v1
with:
serviceAccountJsonPlainText: ${{ secrets.PLAY_SERVICE_ACCOUNT }}
packageName: com.yourapp.id
releaseFiles: build/*.aab
track: internal
Fastlane Integration
# .github/workflows/fastlane.yml
name: Fastlane Build
on:
push:
tags: ['v*']
jobs:
ios:
runs-on: macos-latest
steps:
- uses: actions/checkout@v4
- uses: ruby/setup-ruby@v1
with:
ruby-version: '3.2'
bundler-cache: true
- name: Install Fastlane
run: gem install fastlane
- name: Build and Deploy
run: fastlane ios release
env:
MATCH_PASSWORD: ${{ secrets.MATCH_PASSWORD }}
APP_STORE_CONNECT_API_KEY: ${{ secrets.APP_STORE_CONNECT_API_KEY }}
android:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: ruby/setup-ruby@v1
with:
ruby-version: '3.2'
bundler-cache: true
- name: Install Fastlane
run: gem install fastlane
- name: Build and Deploy
run: fastlane android release
env:
PLAY_STORE_JSON_KEY: ${{ secrets.PLAY_SERVICE_ACCOUNT }}
Fastlane Setup
iOS Fastfile
# ios/App/fastlane/Fastfile
default_platform(:ios)
platform :ios do
desc "Build and deploy to TestFlight"
lane :release do
setup_ci
# Match for code signing
match(
type: "appstore",
readonly: true
)
# Increment build number
increment_build_number(
build_number: ENV["GITHUB_RUN_NUMBER"]
)
# Build
build_app(
workspace: "App.xcworkspace",
scheme: "App",
export_method: "app-store"
)
# Upload to TestFlight
upload_to_testflight(
skip_waiting_for_build_processing: true
)
end
desc "Build for development"
lane :build do
match(type: "development", readonly: true)
build_app(
workspace: "App.xcworkspace",
scheme: "App",
export_method: "development"
)
end
end
Android Fastfile
# android/fastlane/Fastfile
default_platform(:android)
platform :android do
desc "Build and deploy to Play Store"
lane :release do
# Increment version code
increment_version_code(
version_code: ENV["GITHUB_RUN_NUMBER"].to_i
)
# Build AAB
gradle(
task: "bundle",
build_type: "Release"
)
# Upload to Play Store
upload_to_play_store(
track: "internal",
aab: lane_context[SharedValues::GRADLE_AAB_OUTPUT_PATH]
)
end
desc "Build APK"
lane :build do
gradle(
task: "assemble",
build_type: "Release"
)
end
end
GitLab CI
# .gitlab-ci.yml
stages:
- test
- build
- deploy
variables:
BUN_VERSION: "1.0"
.bun-cache: &bun-cache
cache:
key: ${CI_COMMIT_REF_SLUG}
paths:
- node_modules/
- ~/.bun/install/cache
test:
stage: test
image: oven/bun:${BUN_VERSION}
<<: *bun-cache
script:
- bun install
- bun run lint
- bun test --coverage
coverage: '/All files[^|]*\|[^|]*\s+([\d\.]+)/'
artifacts:
reports:
coverage_report:
coverage_format: cobertura
path: coverage/cobertura-coverage.xml
security:
stage: test
image: oven/bun:${BUN_VERSION}
script:
- bunx capsec scan --ci --output json --output-file security.json
artifacts:
reports:
security: security.json
build-web:
stage: build
image: oven/bun:${BUN_VERSION}
<<: *bun-cache
script:
- bun install
- bun run build
artifacts:
paths:
- dist/
expire_in: 1 day
build-ios:
stage: build
tags:
- macos
needs: [build-web]
script:
- bun install
- bunx cap sync ios
- cd ios/App && fastlane build
artifacts:
paths:
- ios/App/build/*.ipa
only:
- main
- tags
build-android:
stage: build
image: thyrlian/android-sdk
needs: [build-web]
script:
- bun install
- bunx cap sync android
- cd android && ./gradlew assembleRelease
artifacts:
paths:
- android/app/build/outputs/apk/release/*.apk
only:
- main
- tags
deploy-capgo:
stage: deploy
image: oven/bun:${BUN_VERSION}
needs: [build-web]
script:
- bunx @capgo/cli upload --channel production
only:
- main
environment:
name: production
Secrets Management
Required Secrets
| Secret | Description |
|---|---|
CERTIFICATE_P12 |
iOS distribution certificate (base64) |
CERTIFICATE_PASSWORD |
Certificate password |
PROVISIONING_PROFILE |
iOS provisioning profile (base64) |
KEYSTORE_BASE64 |
Android keystore (base64) |
KEYSTORE_PASSWORD |
Keystore password |
KEY_ALIAS |
Signing key alias |
KEY_PASSWORD |
Signing key password |
CAPGO_TOKEN |
Capgo API token |
APP_STORE_CONNECT_API_KEY |
App Store Connect API key |
PLAY_SERVICE_ACCOUNT |
Play Store service account JSON |
Encoding Secrets
# iOS certificate
base64 -i certificate.p12 | pbcopy
# iOS provisioning profile
base64 -i profile.mobileprovision | pbcopy
# Android keystore
base64 -i release.keystore | pbcopy
Version Management
Semantic Release
bun add -D semantic-release @semantic-release/git @semantic-release/changelog
// .releaserc.json
{
"branches": ["main"],
"plugins": [
"@semantic-release/commit-analyzer",
"@semantic-release/release-notes-generator",
"@semantic-release/changelog",
[
"@semantic-release/npm",
{ "npmPublish": false }
],
[
"@semantic-release/git",
{
"assets": ["package.json", "CHANGELOG.md"],
"message": "chore(release): ${nextRelease.version}"
}
],
"@semantic-release/github"
]
}
Version Bumping
# .github/workflows/release.yml
name: Release
on:
push:
branches: [main]
jobs:
release:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
persist-credentials: false
- uses: oven-sh/setup-bun@v1
- run: bun install
- name: Release
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: bunx semantic-release
Build Caching
Gradle Cache
- name: Cache Gradle
uses: actions/cache@v4
with:
path: |
~/.gradle/caches
~/.gradle/wrapper
key: gradle-${{ runner.os }}-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }}
restore-keys: gradle-${{ runner.os }}-
CocoaPods Cache
- name: Cache CocoaPods
uses: actions/cache@v4
with:
path: ios/App/Pods
key: pods-${{ runner.os }}-${{ hashFiles('ios/App/Podfile.lock') }}
restore-keys: pods-${{ runner.os }}-
Resources
- GitHub Actions: https://docs.github.com/actions
- Fastlane: https://fastlane.tools
- Capgo CLI: https://capgo.app/docs/cli
- App Store Connect API: https://developer.apple.com/documentation/appstoreconnectapi
- Google Play API: https://developers.google.com/android-publisher
# Supported AI Coding Agents
This skill is compatible with the SKILL.md standard and works with all major AI coding agents:
Learn more about the SKILL.md standard and how to use these skills with your preferred AI coding agent.