Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
265fa41
feat(ios-fastlane): Add GitHub Actions for beta, release, and test wo…
Oct 16, 2025
d1087ad
refactor(ios-selfhosted-build): Streamline workflow and introduce ded…
Oct 16, 2025
71656d8
ci(ios-selfhosted-test): Refactor to use `ios-fastlane-test` action a…
Oct 16, 2025
d6a7159
refactor(ios-release): Use dedicated action for Fastlane release
Oct 16, 2025
83640f9
feat: add iOS self-hosted nightly build workflow
Oct 16, 2025
7255c55
ci(ios-nightly-build): Optimize workflow execution and update action …
Oct 17, 2025
b698cf8
fix: Pass action inputs as environment variables to Fastlane scripts
Oct 17, 2025
be5d9c8
refactor(ios-kmp-build): Use ios-fastlane-beta action for Fastlane Be…
Oct 17, 2025
63d258a
chore: Temporarily switch iOS workflows to refactor branch
Oct 17, 2025
8b78f45
fix: Add execute permissions to bash scripts and add refactor plan
Oct 17, 2025
41c787f
chore(ios-fastlane): Remove redundant `cd iosApp` from Fastlane scripts
Oct 17, 2025
7495058
Revert "chore: Temporarily switch iOS workflows to refactor branch"
Oct 24, 2025
e3e9e0f
refactor(workflow): rename ios-selfhosted-nightlyBuild.yml to use hyp…
Oct 24, 2025
f255e12
refactor(ci): Deprecate ios-selfhosted-build.yml and introduce ios-se…
Oct 24, 2025
d289d8a
docs: Deprecate `ios-selfhosted-build` and introduce new build workflows
Oct 24, 2025
148713c
chore: Quote $GITHUB_OUTPUT in iOS workflow files
Oct 24, 2025
b962669
feat: Add deprecation warning to ios-selfhosted-build.yml
Oct 24, 2025
c364d86
refactor(ios-fastlane-actions): Simplify environment variable handling
Oct 29, 2025
b70a44e
chore(ci): Make GitHub tokens optional in iOS test workflows
Oct 29, 2025
93254cc
fix(ci): Use PR_TITLE for TestFlight changelog
Oct 29, 2025
6d8bccb
Merge remote-tracking branch 'origin/main' into feature/refactor-iOS-…
Nov 3, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 38 additions & 0 deletions .github/actions/ios-fastlane-beta/action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
name: 'Fastlane Beta'
description: 'Runs Fastlane beta'
inputs:
match_password:
description: 'Match password'
required: true
testflight_changelog:
description: 'Testflight changelog'
required: false
app_store_connect_api_key_key:
description: 'App Store Connect API Key'
required: true
app_store_connect_api_key_key_id:
description: 'App Store Connect API Key ID'
required: true
app_store_connect_api_key_issuer_id:
description: 'App Store Connect API Key Issuer ID'
required: true
custom_values:
description: 'Custom values'
required: false
custom_build_path:
description: 'Custom build path'
required: false
runs:
using: 'composite'
steps:
- name: Run beta script
shell: bash
run: ${{ github.action_path }}/beta.sh
env:
MATCH_PASSWORD: ${{ inputs.match_password }}
PR_TITLE: ${{ inputs.testflight_changelog }}
APP_STORE_CONNECT_API_KEY_KEY: ${{ inputs.app_store_connect_api_key_key }}
APP_STORE_CONNECT_API_KEY_KEY_ID: ${{ inputs.app_store_connect_api_key_key_id }}
APP_STORE_CONNECT_API_KEY_ISSUER_ID: ${{ inputs.app_store_connect_api_key_issuer_id }}
CUSTOM_VALUES: ${{ inputs.custom_values }}
CUSTOM_BUILD_PATH: ${{ inputs.custom_build_path }}
13 changes: 13 additions & 0 deletions .github/actions/ios-fastlane-beta/beta.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
#!/bin/bash
set -e

gem install bundler
bundle install --jobs 4 --retry 3

# Environment variables are already set by action.yml
# No need to re-export them
if [ -n "$CUSTOM_BUILD_PATH" ]; then
cd $CUSTOM_BUILD_PATH
fi

bundle exec fastlane beta
34 changes: 34 additions & 0 deletions .github/actions/ios-fastlane-release/action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
name: 'Fastlane Release'
description: 'Runs Fastlane release'
inputs:
match_password:
description: 'Match password'
required: true
version_number:
description: 'Version number'
required: false
app_store_connect_api_key_key:
description: 'App Store Connect API Key'
required: true
app_store_connect_api_key_key_id:
description: 'App Store Connect API Key ID'
required: true
app_store_connect_api_key_issuer_id:
description: 'App Store Connect API Key Issuer ID'
required: true
custom_values:
description: 'Custom values'
required: false
runs:
using: 'composite'
steps:
- name: Run release script
shell: bash
run: ${{ github.action_path }}/release.sh
env:
MATCH_PASSWORD: ${{ inputs.match_password }}
VERSION_NUMBER: ${{ inputs.version_number }}
APP_STORE_CONNECT_API_KEY_KEY: ${{ inputs.app_store_connect_api_key_key }}
APP_STORE_CONNECT_API_KEY_KEY_ID: ${{ inputs.app_store_connect_api_key_key_id }}
APP_STORE_CONNECT_API_KEY_ISSUER_ID: ${{ inputs.app_store_connect_api_key_issuer_id }}
CUSTOM_VALUES: ${{ inputs.custom_values }}
10 changes: 10 additions & 0 deletions .github/actions/ios-fastlane-release/release.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
#!/bin/bash
set -e

gem install bundler
bundle install --jobs 4 --retry 3

# Environment variables are already set by action.yml
# No need to re-export them

bundle exec fastlane release
18 changes: 18 additions & 0 deletions .github/actions/ios-fastlane-test/action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
name: 'Fastlane Test'
description: 'Runs Fastlane test'
inputs:
github_token:
description: 'GitHub token'
required: false
custom_values:
description: 'Custom values'
required: false
runs:
using: 'composite'
steps:
- name: Run test script
shell: bash
run: ${{ github.action_path }}/test.sh
env:
GITHUB_TOKEN: ${{ inputs.github_token }}
CUSTOM_VALUES: ${{ inputs.custom_values }}
10 changes: 10 additions & 0 deletions .github/actions/ios-fastlane-test/test.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
#!/bin/bash
set -e

gem install bundler
bundle install --jobs 4 --retry 3

# Environment variables are already set by action.yml
# No need to re-export them

bundle exec fastlane test
24 changes: 9 additions & 15 deletions .github/actions/ios-kmp-build/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -64,21 +64,15 @@ runs:
make build
- name: Fastlane Beta
working-directory: iosApp
shell: bash
run: |
gem install bundler
bundle install --jobs 4 --retry 3
if [ -n "${{ inputs.ios_custom_build_path }}" ]; then
cd "${{ inputs.ios_custom_build_path }}"
fi
bundle exec fastlane beta
env:
MATCH_PASSWORD: ${{ inputs.match_password }}
PR_TITLE: ${{ inputs.testflight_changelog }}
APP_STORE_CONNECT_API_KEY_KEY: ${{ inputs.app_store_connect_api_key_key }}
APP_STORE_CONNECT_API_KEY_KEY_ID: ${{ inputs.app_store_connect_api_key_key_id }}
APP_STORE_CONNECT_API_KEY_ISSUER_ID: ${{ inputs.app_store_connect_api_key_issuer_id }}
CUSTOM_VALUES: ${{ inputs.custom_values }}
uses: futuredapp/.github/.github/actions/ios-fastlane-beta@main
with:
match_password: ${{ inputs.match_password }}
testflight_changelog: ${{ inputs.testflight_changelog }}
app_store_connect_api_key_key: ${{ inputs.app_store_connect_api_key_key }}
app_store_connect_api_key_key_id: ${{ inputs.app_store_connect_api_key_key_id }}
app_store_connect_api_key_issuer_id: ${{ inputs.app_store_connect_api_key_issuer_id }}
custom_values: ${{ inputs.custom_values }}
custom_build_path: ${{ inputs.ios_custom_build_path }}
- name: Upload IPA
uses: actions/upload-artifact@v4
with:
Expand Down
165 changes: 46 additions & 119 deletions .github/workflows/ios-selfhosted-build.yml
Original file line number Diff line number Diff line change
@@ -1,154 +1,81 @@
name: Self-hosted Build
name: Deprecated Build (use ios-selfhosted-nightly-build)

on:
workflow_call:
inputs:
use_git_lfs:
description: Whether to download Git-LFS files.
description: 'Whether to download Git-LFS files.'
type: boolean
required: false
default: false
custom_values:
description: "Custom string that can contains values specified in your workflow file. Those values will be placed into environment variable. Example: \"CUSTOM-1: 1; CUSTOM-2: 2\""
description: 'Custom string that can contains values specified in your workflow file. Those values will be placed into environment variable. Example: "CUSTOM-1: 1; CUSTOM-2: 2"'
type: string
required: false
runner_label:
description: 'The custom label for the self-hosted runner to use for the build job.'
type: string
required: false
default: 'self-hosted' # Default if you don't specify a particular runner
changelog_debug:
description: Enable debug mode for changelog generation. Default is false.
type: boolean
required: false
default: false
changelog_checkout_depth:
description: The depth of the git history to fetch for changelog generation. Default is 100.
default: 'self-hosted'
timeout_minutes:
description: 'Job timeout in minutes'
type: number
required: false
default: 100
changelog_fallback_lookback:
description: The amount of time to look back for merge commits when no previous build commit is found. Default is 24 hours.
default: 30
xcconfig_path:
description: 'Path to the .xcconfig file. Selected secret properties will be appended to the end of this file.'
type: string
required: false
default: "24 hours"
force_build:
description: "If true, skip change detection and force a build."
type: boolean
required: false
default: false
xcconfig_path:
description: Path to the .xcconfig file. Selected secret properties will be appended to the end of this file.
secret_properties:
description: 'Secrets in the format KEY = VALUE (one per line).'
type: string
required: false
default: ""
required_keys:
description: Comma-separated list of required keys.
description: 'Comma-separated list of required keys.'
type: string
required: false
changelog_fallback_lookback:
description: 'The amount of time to look back for merge commits when no previous build commit is found. Default is 24 hours.'
type: string
required: false
default: ""
default: '24 hours'

secrets:
MATCH_PASSWORD:
required: true
description: >
Password for decrypting of certificates and provisioning profiles.
description: 'Password for decrypting of certificates and provisioning profiles.'
APP_STORE_CONNECT_API_KEY_KEY:
required: true
description: >
Private App Store Connect API key for submitting build to App Store.
description: 'Private App Store Connect API key for submitting build to App Store.'
APP_STORE_CONNECT_API_KEY_KEY_ID:
required: true
description: >
Private App Store Connect API key for submitting build to App Store.
description: 'Private App Store Connect API key for submitting build to App Store.'
APP_STORE_CONNECT_API_KEY_ISSUER_ID:
required: true
description: >
Private App Store Connect API issuer key for submitting build to App Store.
description: 'Private App Store Connect API issuer key for submitting build to App Store.'
SECRET_PROPERTIES:
required: false
description: >
Secrets in the format KEY = VALUE (one per line).
description: 'Secrets in the format KEY = VALUE (one per line).'

jobs:

build:
runs-on: ${{ fromJson(format('["self-hosted", "{0}"]', inputs.runner_label)) }}
timeout-minutes: 30

deprecation-warning:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
with:
lfs: ${{ inputs.use_git_lfs }}
fetch-depth: ${{ inputs.changelog_checkout_depth }}

- name: Use Composite Action - Detect changes and get changelog
id: detect_changes
uses: futuredapp/.github/.github/actions/universal-detect-changes-and-generate-changelog@main
with:
debug: ${{ inputs.changelog_debug }}
fallback_lookback: ${{ inputs.changelog_fallback_lookback }}

- name: Set changelog for forced build
if: ${{ inputs.force_build == true }}
id: changelog
run: |
echo "changelog=Forced build" >> "$GITHUB_OUTPUT"

- name: Checkout
if: ${{ steps.detect_changes.outputs.skip_build != 'true' && inputs.use_git_lfs == 'true' }}
uses: actions/checkout@v4
with:
lfs: ${{ inputs.use_git_lfs }}

- name: Export secrets to .xcconfig file
if: ${{ inputs.xcconfig_path != '' }}
uses: futuredapp/.github/.github/actions/ios-export-secrets@main
with:
XCCONFIG_PATH: ${{ inputs.xcconfig_path }}
SECRET_PROPERTIES: ${{ secrets.SECRET_PROPERTIES }}
REQUIRED_KEYS: ${{ inputs.required_keys }}

- name: Fastlane Beta
if: ${{ steps.detect_changes.outputs.skip_build != 'true' || inputs.force_build == true }}
run: |
gem install bundler
bundle install --jobs 4 --retry 3
bundle exec fastlane beta
env:
MATCH_PASSWORD: ${{ secrets.MATCH_PASSWORD }}
PR_TITLE: ${{ steps.detect_changes.outputs.changelog || steps.changelog.outputs.changelog }}
APP_STORE_CONNECT_API_KEY_KEY: ${{ secrets.APP_STORE_CONNECT_API_KEY_KEY }}
APP_STORE_CONNECT_API_KEY_KEY_ID: ${{ secrets.APP_STORE_CONNECT_API_KEY_KEY_ID }}
APP_STORE_CONNECT_API_KEY_ISSUER_ID: ${{ secrets.APP_STORE_CONNECT_API_KEY_ISSUER_ID }}
CUSTOM_VALUES: ${{ inputs.custom_values }}

- name: Upload IPA
if: ${{ steps.detect_changes.outputs.skip_build != 'true' || inputs.force_build == true }}
uses: actions/upload-artifact@v4
with:
name: Build.ipa
path: build_output/*.ipa

- name: Upload dSYM
if: ${{ steps.detect_changes.outputs.skip_build != 'true' || inputs.force_build == true }}
uses: actions/upload-artifact@v4
with:
name: Build.app.dSYM.zip
path: build_output/*.app.dSYM.zip

- name: Save latest build commit SHA to file
if: success() && steps.detect_changes.outputs.skip_build != 'true' && inputs.force_build != true
shell: bash
run: |
echo "${{ github.sha }}" > latest_builded_commit.txt
if [ "${{ inputs.changelog_debug }}" == 'true' ]; then
echo "[DEBUG] Saved commit SHA ${{ github.sha }} to latest_builded_commit.txt"
fi

- name: Store latest build commit SHA in cache
if: success() && steps.detect_changes.outputs.skip_build != 'true' && inputs.force_build != true
uses: actions/cache/save@v4
with:
path: latest_builded_commit.txt
key: ${{ steps.detect_changes.outputs.cache_key }}
- name: Show deprecation warning
run: |
echo "::warning::This workflow ('ios-selfhosted-build.yml') is deprecated and will be removed in the future."
echo "::warning::Please use 'ios-selfhosted-nightly-build.yml' instead."
build:
uses: futuredapp/.github/.github/workflows/ios-selfhosted-nightly-build.yml@main
with:
use_git_lfs: ${{ inputs.use_git_lfs }}
custom_values: ${{ inputs.custom_values }}
runner_label: ${{ inputs.runner_label }}
timeout_minutes: ${{ inputs.timeout_minutes }}
xcconfig_path: ${{ inputs.xcconfig_path }}
secret_properties: ${{ inputs.secret_properties }}
required_keys: ${{ inputs.required_keys }}
changelog_fallback_lookback: ${{ inputs.changelog_fallback_lookback }}
secrets:
MATCH_PASSWORD: ${{ secrets.MATCH_PASSWORD }}
APP_STORE_CONNECT_API_KEY_KEY: ${{ secrets.APP_STORE_CONNECT_API_KEY_KEY }}
APP_STORE_CONNECT_API_KEY_KEY_ID: ${{ secrets.APP_STORE_CONNECT_API_KEY_KEY_ID }}
APP_STORE_CONNECT_API_KEY_ISSUER_ID: ${{ secrets.APP_STORE_CONNECT_API_KEY_ISSUER_ID }}
SECRET_PROPERTIES: ${{ secrets.SECRET_PROPERTIES }}
Loading