diff --git a/.github/actions/ios-fastlane-beta/action.yml b/.github/actions/ios-fastlane-beta/action.yml new file mode 100644 index 0000000..998ee4e --- /dev/null +++ b/.github/actions/ios-fastlane-beta/action.yml @@ -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 }} \ No newline at end of file diff --git a/.github/actions/ios-fastlane-beta/beta.sh b/.github/actions/ios-fastlane-beta/beta.sh new file mode 100755 index 0000000..d61a50c --- /dev/null +++ b/.github/actions/ios-fastlane-beta/beta.sh @@ -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 diff --git a/.github/actions/ios-fastlane-release/action.yml b/.github/actions/ios-fastlane-release/action.yml new file mode 100644 index 0000000..52b0d37 --- /dev/null +++ b/.github/actions/ios-fastlane-release/action.yml @@ -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 }} diff --git a/.github/actions/ios-fastlane-release/release.sh b/.github/actions/ios-fastlane-release/release.sh new file mode 100755 index 0000000..b497378 --- /dev/null +++ b/.github/actions/ios-fastlane-release/release.sh @@ -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 diff --git a/.github/actions/ios-fastlane-test/action.yml b/.github/actions/ios-fastlane-test/action.yml new file mode 100644 index 0000000..02b6cc1 --- /dev/null +++ b/.github/actions/ios-fastlane-test/action.yml @@ -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 }} diff --git a/.github/actions/ios-fastlane-test/test.sh b/.github/actions/ios-fastlane-test/test.sh new file mode 100755 index 0000000..b64ed00 --- /dev/null +++ b/.github/actions/ios-fastlane-test/test.sh @@ -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 diff --git a/.github/actions/ios-kmp-build/action.yml b/.github/actions/ios-kmp-build/action.yml index 66e7294..0fb0461 100644 --- a/.github/actions/ios-kmp-build/action.yml +++ b/.github/actions/ios-kmp-build/action.yml @@ -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: diff --git a/.github/workflows/ios-selfhosted-build.yml b/.github/workflows/ios-selfhosted-build.yml index 2b4fe14..ca36f2a 100644 --- a/.github/workflows/ios-selfhosted-build.yml +++ b/.github/workflows/ios-selfhosted-build.yml @@ -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 }} diff --git a/.github/workflows/ios-selfhosted-nightly-build.yml b/.github/workflows/ios-selfhosted-nightly-build.yml new file mode 100644 index 0000000..a66c32c --- /dev/null +++ b/.github/workflows/ios-selfhosted-nightly-build.yml @@ -0,0 +1,125 @@ +name: iOS Self-hosted Nightly Build + +on: + workflow_call: + inputs: + use_git_lfs: + description: 'Whether to download Git-LFS files.' + type: boolean + 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"' + type: string + required: false + runner_label: + description: 'The custom label for the self-hosted runner to use for the build job.' + type: string + default: 'self-hosted' + timeout_minutes: + description: 'Job timeout in minutes' + type: number + 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 + secret_properties: + description: 'Secrets in the format KEY = VALUE (one per line).' + type: string + required: false + 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: '24 hours' + + secrets: + MATCH_PASSWORD: + required: true + 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.' + APP_STORE_CONNECT_API_KEY_KEY_ID: + required: true + 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.' + SECRET_PROPERTIES: + required: false + description: 'Secrets in the format KEY = VALUE (one per line).' + +jobs: + build: + runs-on: ${{ fromJson(format('["self-hosted", "{0}"]', inputs.runner_label)) }} + timeout-minutes: ${{ inputs.timeout_minutes }} + + steps: + - name: Detect changes and generate changelog + id: detect_changes + uses: futuredapp/.github/.github/actions/universal-detect-changes-and-generate-changelog@main + with: + fallback_lookback: ${{ inputs.changelog_fallback_lookback }} + + - name: Checkout + if: ${{ steps.detect_changes.outputs.skip_build == 'false' && inputs.use_git_lfs == 'true' }} + uses: actions/checkout@v4 + with: + lfs: ${{ inputs.use_git_lfs }} + + - name: Set changelog + if: ${{ steps.detect_changes.outputs.skip_build == 'false' }} + id: set_changelog + run: | + echo "changelog=${{ steps.detect_changes.outputs.changelog }}" >> "$GITHUB_OUTPUT" + + - name: Export secrets + if: ${{ steps.detect_changes.outputs.skip_build == 'false' && 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 == 'false' }} + uses: futuredapp/.github/.github/actions/ios-fastlane-beta@main + with: + MATCH_PASSWORD: ${{ secrets.MATCH_PASSWORD }} + testflight_changelog: ${{ steps.set_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 == 'false' }} + uses: actions/upload-artifact@v4 + with: + name: Build.ipa + path: build_output/*.ipa + + - name: Upload dSYM + if: ${{ steps.detect_changes.outputs.skip_build == 'false' }} + 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 == 'false' + shell: bash + run: | + echo "${{ github.sha }}" > latest_builded_commit.txt + + - name: Store latest build commit SHA in cache + if: success() && steps.detect_changes.outputs.skip_build == 'false' + uses: actions/cache/save@v4 + with: + path: latest_builded_commit.txt + key: ${{ steps.detect_changes.outputs.cache_key }} diff --git a/.github/workflows/ios-selfhosted-on-demand-build.yml b/.github/workflows/ios-selfhosted-on-demand-build.yml new file mode 100644 index 0000000..8d16855 --- /dev/null +++ b/.github/workflows/ios-selfhosted-on-demand-build.yml @@ -0,0 +1,130 @@ +name: iOS Self-hosted On-Demand Build + +on: + workflow_call: + inputs: + use_git_lfs: + description: 'Whether to download Git-LFS files.' + type: boolean + 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"' + type: string + required: false + runner_label: + description: 'The custom label for the self-hosted runner to use for the build job.' + type: string + default: 'self-hosted' + timeout_minutes: + description: 'Job timeout in minutes' + type: number + 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 + secret_properties: + description: 'Secrets in the format KEY = VALUE (one per line).' + type: string + required: false + required_keys: + description: 'Comma-separated list of required keys.' + type: string + required: false + changelog: + description: 'Will be used as TestFlight changelog' + 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: '24 hours' + + secrets: + MATCH_PASSWORD: + required: true + 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.' + APP_STORE_CONNECT_API_KEY_KEY_ID: + required: true + 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.' + SECRET_PROPERTIES: + required: false + description: 'Secrets in the format KEY = VALUE (one per line).' + +jobs: + build: + runs-on: ${{ fromJson(format('["self-hosted", "{0}"]', inputs.runner_label)) }} + timeout-minutes: ${{ inputs.timeout_minutes }} + + steps: + - name: Generate changelog if not provided + if: ${{ inputs.changelog == '' }} + id: detect_changes + uses: futuredapp/.github/.github/actions/universal-detect-changes-and-generate-changelog@main + with: + fallback_lookback: ${{ inputs.changelog_fallback_lookback }} + + - name: Checkout + if: ${{ inputs.use_git_lfs == 'true' || inputs.changelog != '' }} + uses: actions/checkout@v4 + with: + lfs: ${{ inputs.use_git_lfs }} + + - name: Set changelog + id: set_changelog + run: | + if [ -n "${{ inputs.changelog }}" ]; then + echo "changelog=${{ inputs.changelog }}" >> "$GITHUB_OUTPUT" + else + echo "changelog=${{ steps.detect_changes.outputs.changelog }}" >> "$GITHUB_OUTPUT" + fi + + - name: Export secrets + 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 + uses: futuredapp/.github/.github/actions/ios-fastlane-beta@main + with: + MATCH_PASSWORD: ${{ secrets.MATCH_PASSWORD }} + testflight_changelog: ${{ steps.set_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 + uses: actions/upload-artifact@v4 + with: + name: Build.ipa + path: build_output/*.ipa + + - name: Upload dSYM + 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() + shell: bash + run: | + echo "${{ github.sha }}" > latest_builded_commit.txt + + - name: Store latest build commit SHA in cache + if: success() + uses: actions/cache/save@v4 + with: + path: latest_builded_commit.txt + key: ${{ steps.detect_changes.outputs.cache_key }} \ No newline at end of file diff --git a/.github/workflows/ios-selfhosted-release.yml b/.github/workflows/ios-selfhosted-release.yml index e9cab24..c0b462b 100644 --- a/.github/workflows/ios-selfhosted-release.yml +++ b/.github/workflows/ios-selfhosted-release.yml @@ -1,90 +1,91 @@ -name: Self-hosted Release +name: iOS Self-hosted Release 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 + default: 'self-hosted' + timeout_minutes: + description: 'Job timeout in minutes' + type: number + default: 30 xcconfig_path: - description: Path to the .xcconfig file. Selected secret properties will be appended to the end of this file. + description: 'Path to the .xcconfig file. Selected secret properties will be appended to the end of this file.' + type: string + required: false + 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 - default: "" + 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: release: runs-on: ${{ fromJson(format('["self-hosted", "{0}"]', inputs.runner_label)) }} - timeout-minutes: 30 + timeout-minutes: ${{ inputs.timeout_minutes }} steps: - - name: Checkout - 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 Release - run: | - gem install bundler - bundle install --jobs 4 --retry 3 - bundle exec fastlane release - env: - MATCH_PASSWORD: ${{ secrets.MATCH_PASSWORD }} - VERSION_NUMBER: ${{ github.ref_name }} - 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 - uses: actions/upload-artifact@v4 - with: - name: Build.ipa - path: build_output/*.ipa - - name: Upload dSYM - uses: actions/upload-artifact@v4 - with: - name: Build.app.dSYM.zip - path: build_output/*.app.dSYM.zip + - name: Checkout + uses: actions/checkout@v4 + with: + lfs: ${{ inputs.use_git_lfs }} + + - name: Export secrets + 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 Release + uses: futuredapp/.github/.github/actions/ios-fastlane-release@main + with: + match_password: ${{ secrets.MATCH_PASSWORD }} + version_number: ${{ github.ref_name }} + 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 + uses: actions/upload-artifact@v4 + with: + name: Build.ipa + path: build_output/*.ipa + + - name: Upload dSYM + uses: actions/upload-artifact@v4 + with: + name: Build.app.dSYM.zip + path: build_output/*.app.dSYM.zip \ No newline at end of file diff --git a/.github/workflows/ios-selfhosted-test.yml b/.github/workflows/ios-selfhosted-test.yml index 702a821..b617f6c 100644 --- a/.github/workflows/ios-selfhosted-test.yml +++ b/.github/workflows/ios-selfhosted-test.yml @@ -1,23 +1,29 @@ -name: Self-hosted Test +name: iOS Self-hosted Test 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 + default: 'self-hosted' + timeout_minutes: + description: 'Job timeout in minutes' + type: number + default: 30 + secrets: + GITHUB_TOKEN_DANGER: + required: false + description: 'GitHub token for Danger. Must have permissions to read and write issues and pull requests.' concurrency: group: ${{ github.workflow }}-${{ github.head_ref }} @@ -26,18 +32,16 @@ concurrency: jobs: test: runs-on: ${{ fromJson(format('["self-hosted", "{0}"]', inputs.runner_label)) }} - timeout-minutes: 30 + timeout-minutes: ${{ inputs.timeout_minutes }} steps: - - name: Checkout - uses: actions/checkout@v4 - with: - lfs: ${{ inputs.use_git_lfs }} - - name: Fastlane Test - run: | - gem install bundler - bundle install --jobs 4 --retry 3 - bundle exec fastlane test - env: - DANGER_GITHUB_API_TOKEN: ${{ secrets.GITHUB_TOKEN }} - CUSTOM_VALUES: ${{ inputs.custom_values }} + - name: Checkout + uses: actions/checkout@v4 + with: + lfs: ${{ inputs.use_git_lfs }} + + - name: Fastlane Test + uses: futuredapp/.github/.github/actions/ios-fastlane-test@main + with: + github_token: ${{ secrets.GITHUB_TOKEN_DANGER }} + custom_values: ${{ inputs.custom_values }} \ No newline at end of file diff --git a/.gitignore b/.gitignore index 723ef36..4a6f485 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ -.idea \ No newline at end of file +.idea +*.DS_Store diff --git a/README.md b/README.md index 0b03544..1ef465c 100644 --- a/README.md +++ b/README.md @@ -29,7 +29,9 @@ All the available reusable workflows are listed in the following table. | Universal | Cloud | Backup | [`universal-cloud-backup`](.github/workflows/universal-cloud-backup.yml) | Backups currently checked out ref to a remote repository. | | Universal | Self-hosted | Backup | [`universal-selfhosted-backup`](.github/workflows/universal-selfhosted-backup.yml) | Backups currently checked out ref to a remote repository. | | iOS | Self-hosted | Test | [`ios-selfhosted-test`](.github/workflows/ios-selfhosted-test.yml) | Lints and tests the PR. | -| iOS | Self-hosted | Build | [`ios-selfhosted-build`](.github/workflows/ios-selfhosted-build.yml) | Creates enterprise release build and submits the build to Futured App Store Connect. | +| iOS | Self-hosted | Build | [`ios-selfhosted-build`](.github/workflows/ios-selfhosted-build.yml) | **Deprecated.** Use `ios-selfhosted-nightly-build` or `ios-selfhosted-on-demand-build`.| +| iOS | Self-hosted | Nightly Build | [`ios-selfhosted-nightly-build`](.github/workflows/ios-selfhosted-nightly-build.yml) | Creates a nightly enterprise build and submits it to App Store Connect. | +| iOS | Self-hosted | On-Demand Build | [`ios-selfhosted-on-demand-build`](.github/workflows/ios-selfhosted-on-demand-build.yml) | Creates an on-demand enterprise build and submits it to App Store Connect. | | iOS | Self-hosted | Release | [`ios-selfhosted-release`](.github/workflows/ios-selfhosted-release.yml) | Creates release build and submits it to App Store Connect. | | iOS (KMP) | Self-hosted | Test | [`ios-kmp-selfhosted-test`](.github/workflows/ios-kmp-selfhosted-test.yml) | Lints and tests the PR. | | iOS (KMP) | Self-hosted | Build | [`ios-kmp-selfhosted-build`](.github/workflows/ios-kmp-selfhosted-build.yml) | Creates enterprise release build and submits the build to Futured App Store Connect. |