Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
24 changes: 20 additions & 4 deletions .github/workflows/bank-sdk.publish.example.app.testflight.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ name: Upload GiniBankSDKExample to TestFlight
permissions:
contents: read
on:
# schedule:
# - cron: '0 0 1 1,4,7,10 *' # 1st of Jan, Apr, Jul, Oct at midnight UTC
schedule:
- cron: '0 9 * 2,5,8,11 1' # Every Monday in Feb, May, Aug, Nov at 09:00 UTC
workflow_dispatch:

concurrency:
Expand All @@ -13,10 +13,26 @@ concurrency:


jobs:
check-schedule:
runs-on: ubuntu-latest
outputs:
should_run: ${{ steps.check.outputs.should_run }}
steps:
- id: check
run: |
day=$(date +%d | sed 's/^0//')
if [ "$day" -ge 8 ] && [ "$day" -le 14 ]; then
echo "should_run=true" >> $GITHUB_OUTPUT
else
echo "should_run=false" >> $GITHUB_OUTPUT
fi

upload-testflight:
needs: check-schedule
if: needs.check-schedule.outputs.should_run == 'true' || github.event_name == 'workflow_dispatch'
uses: ./.github/workflows/publish.example.app.testflight.yml
with:
xcode_version: '16.3'
xcode_version: '26.2'
project_path: 'BankSDK/GiniBankSDKExample/GiniBankSDKExample.xcodeproj'
scheme: 'GiniBankSDKExample'
bundle_identifier: 'net.gini.banksdk.example'
Expand All @@ -28,4 +44,4 @@ jobs:
KEYCHAIN_PASSWORD: ${{ secrets.KEYCHAIN_PASSWORD }}
APP_STORE_CONNECT_API_KEY: ${{ secrets.APP_STORE_CONNECT_API_KEY_BASE64}}
APP_STORE_API_KEY_ID: ${{ secrets.APP_STORE_API_KEY_ID }}
APP_STORE_API_ISSUER_ID: ${{ secrets.APP_STORE_API_ISSUER_ID }}
APP_STORE_API_KEY_ISSUER_ID: ${{ secrets.APP_STORE_API_KEY_ISSUER_ID }}
46 changes: 46 additions & 0 deletions .github/workflows/health-sdk.publish.example.app.testflight.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
name: Upload GiniHealthSDKExample to TestFlight

permissions:
contents: read
on:
schedule:
- cron: '0 9 * 2,5,8,11 1' # Every Monday in Feb, May, Aug, Nov at 09:00 UTC
workflow_dispatch:

concurrency:
group: ${{ github.workflow }}-${{ github.ref }}-publish
cancel-in-progress: ${{ !contains(github.ref, 'refs/tags/')}}


jobs:
check-schedule:
runs-on: ubuntu-latest
outputs:
should_run: ${{ steps.check.outputs.should_run }}
steps:
- id: check
run: |
day=$(date +%d | sed 's/^0//')
if [ "$day" -ge 8 ] && [ "$day" -le 14 ]; then
echo "should_run=true" >> $GITHUB_OUTPUT
else
echo "should_run=false" >> $GITHUB_OUTPUT
fi

upload-testflight:
needs: check-schedule
if: needs.check-schedule.outputs.should_run == 'true' || github.event_name == 'workflow_dispatch'
uses: ./.github/workflows/publish.example.app.testflight.yml
with:
xcode_version: '26.2'
project_path: 'HealthSDK/GiniHealthSDKExample/GiniHealthSDKExample.xcodeproj'
scheme: 'GiniHealthSDKExample'
bundle_identifier: 'net.gini.healthsdk.example'
ipa_name: 'GiniHealthSDKExample'
secrets:
MATCH_GIT_URL: ${{ secrets.MATCH_GIT_URL }}
MATCH_PASSWORD: ${{ secrets.MATCH_PASSWORD }}
KEYCHAIN_PASSWORD: ${{ secrets.KEYCHAIN_PASSWORD }}
APP_STORE_CONNECT_API_KEY: ${{ secrets.APP_STORE_CONNECT_API_KEY_BASE64}}
APP_STORE_API_KEY_ID: ${{ secrets.APP_STORE_API_KEY_ID }}
APP_STORE_API_KEY_ISSUER_ID: ${{ secrets.APP_STORE_API_KEY_ISSUER_ID }}
21 changes: 8 additions & 13 deletions .github/workflows/publish.example.app.testflight.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ on:
xcode_version:
description: 'Xcode version to use'
required: false
default: '16.3'
default: '26.2'

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Suggestion]: Can we use a dynamic value from config for Xcode version?

type: string
project_path:
description: 'Relative path to the .xcodeproj file'
Expand Down Expand Up @@ -61,7 +61,7 @@ on:
required: true
APP_STORE_API_KEY_ID:
required: true
APP_STORE_API_ISSUER_ID:
APP_STORE_API_KEY_ISSUER_ID:
required: true

jobs:
Expand Down Expand Up @@ -90,11 +90,12 @@ jobs:
inputs.bundle_identifier_extension != '' &&
format(',{0}', inputs.bundle_identifier_extension) || ''
}}
DISTRIBUTION_TYPE: appstore
GIT_URL: ${{ secrets.MATCH_GIT_URL }}
MATCH_PASSWORD: ${{ secrets.MATCH_PASSWORD }}
KEYCHAIN_PASSWORD: ${{ secrets.KEYCHAIN_PASSWORD }}
run: bundle exec fastlane download_profiles
run: |
DISTRIBUTION_TYPE=appstore bundle exec fastlane download_profiles
DISTRIBUTION_TYPE=adhoc APP_IDENTIFIER=${{ inputs.bundle_identifier }} bundle exec fastlane download_profiles

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Clarification]: Do we still need to download adhoc?


Comment on lines +96 to 99

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Clarification]: @ValentinaIancu-Gini are we downloading somewhere a profile for our app extension?

- name: Archive Xcode Project
run: |
Expand All @@ -107,6 +108,7 @@ jobs:
CODE_SIGN_IDENTITY="Apple Distribution" \
CODE_SIGN_STYLE=Manual \
DEVELOPMENT_TEAM=${{ inputs.team_id }} \
CURRENT_PROJECT_VERSION=${{ github.run_number }} \
ONLY_ACTIVE_ARCH=NO

- name: Export .ipa File
Expand All @@ -122,16 +124,9 @@ jobs:
files: "${{ inputs.ipa_name }}.ipa"
fail: true

- name: Decode App Store Connect API Key
env:
APP_STORE_CONNECT_API_KEY: ${{ secrets.APP_STORE_CONNECT_API_KEY }}
run: |
mkdir -p build_artifacts
echo "$APP_STORE_CONNECT_API_KEY" | base64 --decode > build_artifacts/AppStoreConnectAPIKey.p8

- name: Upload to TestFlight
env:
APP_STORE_CONNECT_API_KEY_ID: ${{ secrets.APP_STORE_API_KEY_ID }}
APP_STORE_CONNECT_API_ISSUER_ID: ${{ secrets.APP_STORE_API_ISSUER_ID }}
APP_STORE_CONNECT_API_KEY_PATH: build_artifacts/AppStoreConnectAPIKey.p8
APP_STORE_CONNECT_API_ISSUER_ID: ${{ secrets.APP_STORE_API_KEY_ISSUER_ID }}
APP_STORE_CONNECT_API_KEY: ${{ secrets.APP_STORE_CONNECT_API_KEY }}
run: bundle exec fastlane publish_to_testflight ipa_path:"${{ inputs.ipa_name }}.ipa"
2 changes: 1 addition & 1 deletion BankSDK/GiniBankSDKExample/GiniBankSDKExample/Info.plist

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Suggestion]: I think we need to update also plist for Health SDK Example

Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@
</dict>
</array>
<key>CFBundleVersion</key>
<string>1</string>
<string>$(CURRENT_PROJECT_VERSION)</string>
<key>ITSAppUsesNonExemptEncryption</key>
<false/>
<key>LSRequiresIPhoneOS</key>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,25 +2,12 @@
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>compileBitcode</key>
<false/>
<key>iCloudContainerEnvironment</key>
<string>Production</string>
<key>manifest</key>
<dict>
<key>appURL</key>
<string>https://</string>
<key>displayImageURL</key>
<string>https://</string>
<key>fullSizeImageURL</key>
<string>https://</string>
</dict>
<key>method</key>
<string>ad-hoc</string>
<string>app-store-connect</string>
<key>provisioningProfiles</key>
<dict>
<key>net.gini.healthsdk.example</key>
<string>Gini Health SDK Example App Ad-Hoc Distribution</string>
<string>match AppStore net.gini.healthsdk.example</string>
</dict>
<key>signingCertificate</key>
<string>Apple Distribution</string>
Expand All @@ -31,6 +18,6 @@
<key>teamID</key>
<string>JA825X8F7Z</string>
<key>thinning</key>
<string>&lt;none&gt;</string>
<string>none</string>
</dict>
</plist>
55 changes: 20 additions & 35 deletions fastlane/Fastfile
Original file line number Diff line number Diff line change
Expand Up @@ -665,7 +665,7 @@ end
Environment Variables:
APP_STORE_CONNECT_API_KEY_ID - App Store Connect API key ID
APP_STORE_CONNECT_API_ISSUER_ID - App Store Connect API issuer ID
APP_STORE_CONNECT_API_KEY_PATH - Path to the .p8 API key file
APP_STORE_CONNECT_API_KEY - App Store Connect API key content (base64-encoded .p8)
DOC
lane :build_and_upload_to_testflight do |options|
ipa_name = options[:ipa_name] || options[:scheme] || UI.user_error!("Missing required option: ipa_name or scheme")
Expand All @@ -676,57 +676,42 @@ end
end

desc <<~DOC
Upload an .ipa to TestFlight via xcrun altool.
Upload an .ipa to TestFlight via the App Store Connect API.

Parameters:
ipa_path - Path to the .ipa file (default: "./GiniBankSDKExample.ipa")

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Suggestion]: modify the comment comment and mention that it might be ./GiniHealthSDKExample.ipa as well


Environment Variables:
APP_STORE_CONNECT_API_KEY_ID - App Store Connect API key ID
APP_STORE_CONNECT_API_ISSUER_ID - App Store Connect API issuer ID
APP_STORE_CONNECT_API_KEY_PATH - Path to the .p8 API key file
(default: build_artifacts/AppStoreConnectAPIKey.p8)
APP_STORE_CONNECT_API_KEY - App Store Connect API key content (base64-encoded .p8)
DOC
lane :publish_to_testflight do |options|
ipa_path = options[:ipa_path] || "./GiniBankSDKExample.ipa"
key_id = ENV['APP_STORE_CONNECT_API_KEY_ID']
issuer_id = ENV['APP_STORE_CONNECT_API_ISSUER_ID']
key_path = ENV['APP_STORE_CONNECT_API_KEY_PATH'] || "build_artifacts/AppStoreConnectAPIKey.p8"
ipa_path = options[:ipa_path] || "./GiniBankSDKExample.ipa"

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Suggestion]: add a comment comment and mention that it might be ./GiniHealthSDKExample.ipa as well

key_id = ENV['APP_STORE_CONNECT_API_KEY_ID']
issuer_id = ENV['APP_STORE_CONNECT_API_ISSUER_ID']
key_base64 = ENV['APP_STORE_CONNECT_API_KEY']

repo_root = File.expand_path("..", __dir__)
resolved_key_path = File.expand_path(key_path, repo_root)
resolved_ipa_path = File.expand_path(ipa_path, repo_root)

UI.user_error!("APP_STORE_CONNECT_API_KEY_ID is not set") if key_id.nil? || key_id.empty?
UI.user_error!("APP_STORE_CONNECT_API_ISSUER_ID is not set") if issuer_id.nil? || issuer_id.empty?
UI.user_error!("API key not found at: #{resolved_key_path}") unless File.exist?(resolved_key_path)
UI.user_error!("APP_STORE_CONNECT_API_KEY is not set") if key_base64.nil? || key_base64.empty?
UI.user_error!("IPA not found at: #{resolved_ipa_path}") unless File.exist?(resolved_ipa_path)

# xcrun altool reads .p8 keys from ~/.appstoreconnect/private_keys/AuthKey_<ID>.p8
private_keys_dir = File.expand_path("~/.appstoreconnect/private_keys")
expected_key_path = "#{private_keys_dir}/AuthKey_#{key_id}.p8"
created_temporary_key = false
sh("mkdir -p '#{private_keys_dir}'")
unless resolved_key_path == expected_key_path
sh("cp '#{resolved_key_path}' '#{expected_key_path}'")
created_temporary_key = true
end
# Ensure restrictive permissions on the API key file
sh("chmod 600 '#{expected_key_path}'") if File.exist?(expected_key_path)

begin
UI.message "🚀 Uploading #{resolved_ipa_path} to TestFlight..."
sh(
"xcrun altool --upload-app" \
" --file '#{resolved_ipa_path}'" \
" --type ios" \
" --apiKey '#{key_id}'" \
" --apiIssuer '#{issuer_id}'"
)
ensure
# Remove the temporary key copy to avoid leaving credentials on disk
sh("rm -f '#{expected_key_path}'") if created_temporary_key
end
api_key = app_store_connect_api_key(
key_id: key_id,
issuer_id: issuer_id,
key_content: key_base64,
is_key_content_base64: true
)

upload_to_testflight(
ipa: resolved_ipa_path,
api_key: api_key,
skip_waiting_for_build_processing: true
)
end

end
Loading