Skip to content

Commit

Permalink
Merge pull request #3 from niyajali/update-action
Browse files Browse the repository at this point in the history
refactor: Streamline iOS Firebase App Distribution workflow
  • Loading branch information
niyajali authored Dec 30, 2024
2 parents bd16190 + ae2a74f commit 848de26
Show file tree
Hide file tree
Showing 2 changed files with 122 additions and 156 deletions.
193 changes: 111 additions & 82 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,106 +1,135 @@
# KMP Build & Publish iOS App on Firebase
# KMP Publish iOS App on Firebase Action

This GitHub Action automates the process of building an iOS application, generating release notes, and distributing the build to Firebase App Distribution. It includes version management and comprehensive caching for optimized build times.
This GitHub Action automates the process of building and publishing iOS applications to Firebase App Distribution. It handles the build process, signing, and deployment using Fastlane.

## Features

- Automated iOS app building
- Version number generation
- Automated release notes generation
- Firebase App Distribution integration
- Gradle and Konan caching
- Java development environment setup
- Fastlane integration
- Automated Firebase App Distribution deployment
- iOS IPA build and signing
- Build artifact archiving
- Gradle and Ruby dependency caching
- Firebase tester group management

## Prerequisites

- iOS project with Xcode configuration
- Firebase project setup
- GitHub repository with release history
- Fastlane setup in the repository
- Valid iOS certificates and provisioning profiles
Before using this action, ensure you have:

## Inputs
1. A Firebase project with App Distribution enabled
2. Firebase service account credentials
3. An iOS app set up in Firebase
4. Xcode project configured with proper signing

## Setup

### Fastlane Setup

Create a `Gemfile` in your project root:

```ruby
source "https://rubygems.org"

gem "fastlane"
gem "firebase_app_distribution"
```

| Input | Description | Required |
|--------------------|-------------------------------------------|----------|
| `ios_package_name` | Name of the iOS project module | Yes |
| `firebase_creds` | Firebase service account credentials JSON | Yes |
| `github_token` | GitHub token for API access | Yes |
| `target_branch` | Target branch for deployment | Yes |
Create a `fastlane/Fastfile` with the following content:

```ruby
default_platform(:ios)

platform :ios do
desc "Deploy to Firebase App Distribution"
lane :deploy_on_firebase do |options|
build_ios_app(
scheme: ENV["IOS_PACKAGE_NAME"],
export_method: "ad-hoc"
)

firebase_app_distribution(
app: ENV["FIREBASE_APP_ID"],
groups: options[:groups],
service_credentials_file: options[:serviceCredsFile],
release_notes: "New build from GitHub Actions"
)
end
end
```

## Usage

Add the following workflow to your GitHub Actions:

```yaml
name: KMP iOS deploy to Firebase
name: Deploy to Firebase

on:
workflow_dispatch:
inputs:
ios_package_name:
description: 'Name of the iOS project module'
required: true
default: 'mifospay-ios'


permissions:
contents: write
push:
branches: [ main ]
# Or trigger on release
release:
types: [created]

jobs:
deploy_ios_app:
name: Deploy iOS App
deploy:
runs-on: macos-latest
steps:
- name: Checkout Repository
uses: actions/checkout@v4
with:
fetch-depth: 0

- name: Deploy iOS App to Firebase
- uses: actions/checkout@v3

- name: Deploy to Firebase
uses: openMF/kmp-publish-ios-on-firebase-action@v1.0.0
with:
ios_package_name: ${{ inputs.ios_package_name }}
github_token: ${{ secrets.GITHUB_TOKEN }}
firebase_creds: ${{ secrets.FIREBASECREDS }}
target_branch: 'dev'
ios_package_name: 'YourAppName'
firebase_creds: ${{ secrets.FIREBASE_CREDS }}
tester_groups: 'qa-team,beta-testers'
```
## Inputs
| Input | Description | Required |
|--------------------|-----------------------------------------------------|----------|
| `ios_package_name` | Name of your iOS app/scheme | Yes |
| `firebase_creds` | Base64 encoded Firebase service account credentials | Yes |
| `tester_groups` | Comma-separated list of Firebase tester groups | Yes |

## Setting up Secrets

1. Encode your Firebase credentials file to base64:
```bash
base64 -i path/to/firebase-credentials.json -o firebase-creds.txt
```

## Workflow Details

1. **Environment Setup**
- Configures Java 17 (Zulu distribution)
- Sets up Gradle with caching
- Configures Ruby and Fastlane
- Sets up dependency caching for Gradle, Konan, and build outputs

2. **Version Management**
- Generates version codes based on commits and tags
- Reads version name from version.txt
- Formula: `version-code = (commits + tags) << 1`

3. **Release Notes Generation**
- Fetches latest release tag
- Generates release notes using GitHub API
- Creates two changelog files:
- `changelogGithub`: Comprehensive release notes
- `changelogBeta`: Changes since last commit

4. **Build Process**
- Configures Firebase credentials
- Builds iOS application using Fastlane
- Generates IPA file

5. **Distribution**
- Uploads build artifacts with high compression
- Distributes to Firebase App Distribution

## Dependencies

- Java 17 (Zulu distribution)
- Gradle
- Ruby
- Bundler 2.2.27
- Fastlane plugins:
- firebase_app_distribution
- increment_build_number
2. Add the following secret to your GitHub repository:
- `FIREBASE_CREDS`: Content of firebase-creds.txt

## Build Artifacts

The action uploads the built IPA file as an artifact with:
- Name: 'ios-app'
- Retention period: 1 day
- Maximum compression (level 9)

You can find the IPA file in your GitHub Actions run artifacts.

This helps reduce build times in subsequent runs.

## Firebase App Setup

1. Go to the Firebase Console
2. Navigate to App Distribution
3. Create a new iOS app or select an existing one
4. Set up tester groups under App Distribution
5. Create a service account with appropriate permissions
6. Download the service account JSON key file

## Troubleshooting

Common issues and solutions:

1. Build fails due to signing
- Ensure your Xcode project has proper signing configuration
- Verify the export method matches your provisioning profile

2. Firebase deployment fails
- Check if the service account has sufficient permissions
- Verify the Firebase app ID is correct
- Ensure tester groups exist in Firebase console
85 changes: 11 additions & 74 deletions action.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -12,25 +12,13 @@ inputs:
firebase_creds:
description: 'Firebase credentials'
required: true
github_token:
description: 'GitHub token'
required: true
target_branch:
description: 'Target branch for deployment'
tester_groups:
description: 'Firebase Tester Group'
required: true

runs:
using: composite
steps:
- name: Set up Java development environment
uses: actions/setup-java@v4.2.2
with:
distribution: 'zulu' # Use Zulu distribution of OpenJDK
java-version: '17' # Use Java 17 version

- name: Setup Gradle
uses: gradle/actions/setup-gradle@v4

# Cache Gradle dependencies to speed up builds
- uses: actions/cache@v3
with:
Expand All @@ -54,70 +42,23 @@ runs:
bundle exec fastlane add_plugin firebase_app_distribution
bundle exec fastlane add_plugin increment_build_number
# Generate version number
- name: Generate Release Number
id: rel_number
shell: bash
run: |
./gradlew versionFile
COMMITS=`git rev-list --count HEAD`
TAGS=`git tag | grep -v beta | wc -l`
VC=$(((COMMITS+TAGS) << 1))
echo "version-code=$VC" >> $GITHUB_OUTPUT
VERSION=`cat version.txt`
echo "version=$VERSION" >> $GITHUB_OUTPUT
- name: Generate Release Notes
uses: actions/github-script@v7
id: release-notes
with:
github-token: ${{ inputs.github_token }}
script: |
try {
// Get latest release tag
const latestRelease = await github.rest.repos.getLatestRelease({
owner: context.repo.owner,
repo: context.repo.repo,
});
const previousTag = latestRelease.data.tag_name;
// Generate release notes
const params = {
owner: context.repo.owner,
repo: context.repo.repo,
tag_name: '${{ steps.rel_number.outputs.version }}',
target_commitish: '${{ inputs.target_branch }}'
};
const { data } = await github.rest.repos.generateReleaseNotes(params);
const changelog = data.body.replaceAll('`', '\'').replaceAll('"', '\'');
// Write changelog files
const fs = require('fs');
fs.writeFileSync('${{ inputs.ios_package_name }}/changelogGithub', changelog);
// Generate beta changelog
const { execSync } = require('child_process');
execSync('git log --format="* %s" HEAD^..HEAD > ${{ inputs.ios_package_name }}/changelogBeta');
return changelog;
} catch (error) {
console.error('Error generating release notes:', error);
return '';
}
- name: Inflate Secrets
shell: bash
env:
GOOGLE_SERVICES: ${{ inputs.google_services }}
FIREBASE_CREDS: ${{ inputs.firebase_creds }}
run: |
mkdir -p secrets
# Inflate Firebase credentials
touch ${{ inputs.ios_package_name }}/firebaseAppDistributionServiceCredentialsFile.json
echo $FIREBASE_CREDS > ${{ inputs.ios_package_name }}/firebaseAppDistributionServiceCredentialsFile.json
touch secrets/firebaseAppDistributionServiceCredentialsFile.json
echo $FIREBASE_CREDS | base64 --decode > secrets/firebaseAppDistributionServiceCredentialsFile.json
- name: Build iOS App
- name: Upload iOS App to Firebase Distribution
shell: bash
run: bundle exec fastlane ios build_ios
run: bundle exec fastlane ios deploy_on_firebase \
serviceCredsFile:secrets/firebaseAppDistributionServiceCredentialsFile.json \
groups:${{ inputs.tester_groups }}

- name: Upload iOS Artifact
uses: actions/upload-artifact@v4
Expand All @@ -126,7 +67,3 @@ runs:
retention-days: 1
compression-level: 9
path: '**/*.ipa'

- name: Upload iOS App to Firebase Distribution
shell: bash
run: bundle exec fastlane ios deploy_on_firebase

0 comments on commit 848de26

Please sign in to comment.