mirror of
https://github.com/BlueWallet/BlueWallet.git
synced 2024-11-19 01:40:12 +01:00
FIX:: IPA output dir (#7149)
This commit is contained in:
parent
bfb69b87fb
commit
d6376afbb4
137
.github/workflows/build-ios-release-pullrequest.yml
vendored
137
.github/workflows/build-ios-release-pullrequest.yml
vendored
@ -17,65 +17,88 @@ jobs:
|
|||||||
outputs:
|
outputs:
|
||||||
new_build_number: ${{ steps.generate_build_number.outputs.build_number }}
|
new_build_number: ${{ steps.generate_build_number.outputs.build_number }}
|
||||||
project_version: ${{ steps.determine_marketing_version.outputs.project_version }}
|
project_version: ${{ steps.determine_marketing_version.outputs.project_version }}
|
||||||
|
ipa_output_path: ${{ steps.build_app.outputs.ipa_output_path }}
|
||||||
latest_commit_message: ${{ steps.get_latest_commit_message.outputs.commit_message }}
|
latest_commit_message: ${{ steps.get_latest_commit_message.outputs.commit_message }}
|
||||||
env:
|
env:
|
||||||
APPLE_ID: ${{ secrets.APPLE_ID }}
|
APPLE_ID: ${{ secrets.APPLE_ID }}
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout project
|
- name: Checkout Project
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
with:
|
with:
|
||||||
fetch-depth: 0 # Fetches all history
|
fetch-depth: 0 # Fetches all history
|
||||||
|
|
||||||
|
- name: Specify Node.js Version
|
||||||
- name: Specify node version
|
|
||||||
uses: actions/setup-node@v4
|
uses: actions/setup-node@v4
|
||||||
with:
|
with:
|
||||||
node-version: 20
|
node-version: 20
|
||||||
|
|
||||||
- uses: maxim-lobanov/setup-xcode@v1
|
- uses: maxim-lobanov/setup-xcode@v1
|
||||||
with:
|
with:
|
||||||
xcode-version: 16.0
|
xcode-version: 16.0
|
||||||
|
|
||||||
- name: Set up Ruby
|
- name: Set Up Ruby
|
||||||
uses: ruby/setup-ruby@v1
|
uses: ruby/setup-ruby@v1
|
||||||
with:
|
with:
|
||||||
ruby-version: 3.1.6
|
ruby-version: 3.1.6
|
||||||
bundler-cache: true
|
bundler-cache: true
|
||||||
|
|
||||||
- name: Install dependencies with Bundler
|
- name: Install Dependencies with Bundler
|
||||||
run: |
|
run: |
|
||||||
bundle config path vendor/bundle
|
bundle config path vendor/bundle
|
||||||
bundle install --jobs 4 --retry 3 --quiet
|
bundle install --jobs 4 --retry 3 --quiet
|
||||||
|
|
||||||
- name: Install node_modules
|
- name: Install Node Modules
|
||||||
run: npm install --omit=dev --yes
|
run: npm install --omit=dev --yes
|
||||||
|
|
||||||
- name: Install CocoaPods Dependencies
|
- name: Install CocoaPods Dependencies
|
||||||
run: |
|
run: |
|
||||||
bundle exec fastlane ios install_pods
|
bundle exec fastlane ios install_pods
|
||||||
|
|
||||||
- name: Cache CocoaPods Pods
|
- name: Cache CocoaPods Pods
|
||||||
uses: actions/cache@v4
|
uses: actions/cache@v4
|
||||||
with:
|
with:
|
||||||
path: ios/Pods
|
path: ios/Pods
|
||||||
key: ${{ runner.os }}-pods-${{ hashFiles('**/Podfile.lock') }}
|
key: ${{ runner.os }}-pods-${{ hashFiles('**/Podfile.lock') }}
|
||||||
- name: Display release-notes.txt
|
restore-keys: |
|
||||||
run: cat release-notes.txt
|
${{ runner.os }}-pods-
|
||||||
|
|
||||||
- name: Get Latest Commit Message
|
- name: Get Latest Commit Message
|
||||||
id: get_latest_commit_message
|
id: get_latest_commit_message
|
||||||
run: |
|
run: |
|
||||||
LATEST_COMMIT_MESSAGE=$(git log -1 --pretty=format:"%s")
|
LATEST_COMMIT_MESSAGE=$(git log -1 --pretty=format:"%s")
|
||||||
echo "LATEST_COMMIT_MESSAGE=${LATEST_COMMIT_MESSAGE}" >> $GITHUB_ENV
|
echo "LATEST_COMMIT_MESSAGE=${LATEST_COMMIT_MESSAGE}" >> $GITHUB_ENV
|
||||||
echo "::set-output name=commit_message::$LATEST_COMMIT_MESSAGE"
|
echo "commit_message=$LATEST_COMMIT_MESSAGE" >> $GITHUB_OUTPUT
|
||||||
- name: Set up Git Authentication
|
|
||||||
|
- name: Generate Build Number Based on Timestamp
|
||||||
|
id: generate_build_number
|
||||||
|
run: |
|
||||||
|
NEW_BUILD_NUMBER=$(date +%s)
|
||||||
|
echo "NEW_BUILD_NUMBER=$NEW_BUILD_NUMBER" >> $GITHUB_ENV
|
||||||
|
echo "build_number=$NEW_BUILD_NUMBER" >> $GITHUB_OUTPUT
|
||||||
|
|
||||||
|
- name: Set Build Number
|
||||||
|
run: bundle exec fastlane ios increment_build_number_lane
|
||||||
|
|
||||||
|
- name: Determine Marketing Version
|
||||||
|
id: determine_marketing_version
|
||||||
|
run: |
|
||||||
|
MARKETING_VERSION=$(grep MARKETING_VERSION BlueWallet.xcodeproj/project.pbxproj | awk -F '= ' '{print $2}' | tr -d ' ;' | head -1)
|
||||||
|
echo "PROJECT_VERSION=$MARKETING_VERSION" >> $GITHUB_ENV
|
||||||
|
echo "project_version=$MARKETING_VERSION" >> $GITHUB_OUTPUT
|
||||||
|
working-directory: ios
|
||||||
|
|
||||||
|
- name: Set Up Git Authentication
|
||||||
env:
|
env:
|
||||||
ACCESS_TOKEN: ${{ secrets.GIT_ACCESS_TOKEN }}
|
ACCESS_TOKEN: ${{ secrets.GIT_ACCESS_TOKEN }}
|
||||||
run: |
|
run: |
|
||||||
git config --global credential.helper 'cache --timeout=3600'
|
git config --global credential.helper 'cache --timeout=3600'
|
||||||
git config --global http.https://github.com/.extraheader "AUTHORIZATION: basic $(echo -n x-access-token:${ACCESS_TOKEN} | base64)"
|
git config --global http.https://github.com/.extraheader "AUTHORIZATION: basic $(echo -n x-access-token:${ACCESS_TOKEN} | base64)"
|
||||||
|
|
||||||
- name: Create Temporary Keychain
|
- name: Create Temporary Keychain
|
||||||
run: bundle exec fastlane ios create_temp_keychain
|
run: bundle exec fastlane ios create_temp_keychain
|
||||||
env:
|
env:
|
||||||
KEYCHAIN_PASSWORD: ${{ secrets.KEYCHAIN_PASSWORD }}
|
KEYCHAIN_PASSWORD: ${{ secrets.KEYCHAIN_PASSWORD }}
|
||||||
|
|
||||||
- name: Setup Provisioning Profiles
|
- name: Setup Provisioning Profiles
|
||||||
env:
|
env:
|
||||||
MATCH_PASSWORD: ${{ secrets.MATCH_PASSWORD }}
|
MATCH_PASSWORD: ${{ secrets.MATCH_PASSWORD }}
|
||||||
@ -86,14 +109,16 @@ jobs:
|
|||||||
KEYCHAIN_PASSWORD: ${{ secrets.KEYCHAIN_PASSWORD }}
|
KEYCHAIN_PASSWORD: ${{ secrets.KEYCHAIN_PASSWORD }}
|
||||||
run: |
|
run: |
|
||||||
bundle exec fastlane ios setup_provisioning_profiles
|
bundle exec fastlane ios setup_provisioning_profiles
|
||||||
|
|
||||||
- name: Cache Provisioning Profiles
|
- name: Cache Provisioning Profiles
|
||||||
id: cache_provisioning_profiles
|
id: cache_provisioning_profiles
|
||||||
uses: actions/cache@v4
|
uses: actions/cache@v4
|
||||||
with:
|
with:
|
||||||
path: ~/Library/MobileDevice/Provisioning Profiles
|
path: ~/Library/MobileDevice/Provisioning\ Profiles
|
||||||
key: ${{ runner.os }}-provisioning-profiles-${{ github.sha }}
|
key: ${{ runner.os }}-provisioning-profiles-${{ github.sha }}
|
||||||
restore-keys: |
|
restore-keys: |
|
||||||
${{ runner.os }}-provisioning-profiles-
|
${{ runner.os }}-provisioning-profiles-
|
||||||
|
|
||||||
- name: Check Cache Status for Provisioning Profiles
|
- name: Check Cache Status for Provisioning Profiles
|
||||||
run: |
|
run: |
|
||||||
if [ -n "${{ steps.cache_provisioning_profiles.outputs.cache-hit }}" ]; then
|
if [ -n "${{ steps.cache_provisioning_profiles.outputs.cache-hit }}" ]; then
|
||||||
@ -101,41 +126,36 @@ jobs:
|
|||||||
else
|
else
|
||||||
echo "No cache found for provisioning profiles. A new cache will be created."
|
echo "No cache found for provisioning profiles. A new cache will be created."
|
||||||
fi
|
fi
|
||||||
|
|
||||||
- name: Verify Provisioning Profiles Exist
|
- name: Verify Provisioning Profiles Exist
|
||||||
run: |
|
run: |
|
||||||
if [ -d "~/Library/MobileDevice/Provisioning Profiles" ]; then
|
if [ -d "~/Library/MobileDevice/Provisioning Profiles" ]; then
|
||||||
echo "Provisioning profiles are available in the cache."
|
echo "Provisioning profiles are available in the cache."
|
||||||
ls -la ~/Library/MobileDevice/Provisioning Profiles
|
ls -la ~/Library/MobileDevice/Provisioning\ Profiles
|
||||||
else
|
else
|
||||||
echo "Provisioning profiles directory does not exist."
|
echo "Provisioning profiles directory does not exist."
|
||||||
fi
|
fi
|
||||||
- name: Generate Build Number based on timestamp
|
|
||||||
id: generate_build_number
|
|
||||||
run: |
|
|
||||||
NEW_BUILD_NUMBER=$(date +%s)
|
|
||||||
echo "NEW_BUILD_NUMBER=$NEW_BUILD_NUMBER" >> $GITHUB_ENV
|
|
||||||
echo "::set-output name=build_number::$NEW_BUILD_NUMBER"
|
|
||||||
- name: Set Build Number
|
|
||||||
run: bundle exec fastlane ios increment_build_number_lane
|
|
||||||
- name: Determine Marketing Version
|
|
||||||
id: determine_marketing_version
|
|
||||||
run: |
|
|
||||||
MARKETING_VERSION=$(grep MARKETING_VERSION BlueWallet.xcodeproj/project.pbxproj | awk -F '= ' '{print $2}' | tr -d ' ;' | head -1)
|
|
||||||
echo "PROJECT_VERSION=$MARKETING_VERSION" >> $GITHUB_ENV
|
|
||||||
echo "::set-output name=project_version::$MARKETING_VERSION"
|
|
||||||
working-directory: ios
|
|
||||||
|
|
||||||
- name: Expected IPA file name
|
|
||||||
run: |
|
|
||||||
echo "IPA file name: BlueWallet_${{env.PROJECT_VERSION}}(${{env.NEW_BUILD_NUMBER}}).ipa"
|
|
||||||
- name: Build App
|
- name: Build App
|
||||||
run: bundle exec fastlane ios build_app_lane
|
id: build_app
|
||||||
|
run: |
|
||||||
|
bundle exec fastlane ios build_app_lane --verbose
|
||||||
|
echo "ipa_output_path=$IPA_OUTPUT_PATH" >> $GITHUB_OUTPUT # Set the IPA output path for future jobs
|
||||||
|
|
||||||
|
- name: Upload Build Logs
|
||||||
|
if: always()
|
||||||
|
uses: actions/upload-artifact@v4
|
||||||
|
with:
|
||||||
|
name: build_logs
|
||||||
|
path: ./ios/build_logs/
|
||||||
|
|
||||||
- name: Upload IPA as Artifact
|
- name: Upload IPA as Artifact
|
||||||
|
if: success()
|
||||||
uses: actions/upload-artifact@v4
|
uses: actions/upload-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: BlueWallet_${{env.PROJECT_VERSION}}_${{env.NEW_BUILD_NUMBER}}.ipa
|
name: BlueWallet_${{env.PROJECT_VERSION}}_${{env.NEW_BUILD_NUMBER}}.ipa
|
||||||
path: ./build/BlueWallet_${{env.PROJECT_VERSION}}_${{env.NEW_BUILD_NUMBER}}.ipa
|
path: ${{ env.IPA_OUTPUT_PATH }} # Directly from Fastfile `IPA_OUTPUT_PATH`
|
||||||
|
|
||||||
testflight-upload:
|
testflight-upload:
|
||||||
needs: build
|
needs: build
|
||||||
runs-on: macos-latest
|
runs-on: macos-latest
|
||||||
@ -146,13 +166,15 @@ jobs:
|
|||||||
PROJECT_VERSION: ${{ needs.build.outputs.project_version }}
|
PROJECT_VERSION: ${{ needs.build.outputs.project_version }}
|
||||||
LATEST_COMMIT_MESSAGE: ${{ needs.build.outputs.latest_commit_message }}
|
LATEST_COMMIT_MESSAGE: ${{ needs.build.outputs.latest_commit_message }}
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout project
|
- name: Checkout Project
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
- name: Set up Ruby
|
|
||||||
|
- name: Set Up Ruby
|
||||||
uses: ruby/setup-ruby@v1
|
uses: ruby/setup-ruby@v1
|
||||||
with:
|
with:
|
||||||
ruby-version: 3.1.6
|
ruby-version: 3.1.6
|
||||||
bundler-cache: true
|
bundler-cache: true
|
||||||
|
|
||||||
- name: Cache Ruby Gems
|
- name: Cache Ruby Gems
|
||||||
uses: actions/cache@v4
|
uses: actions/cache@v4
|
||||||
with:
|
with:
|
||||||
@ -160,19 +182,43 @@ jobs:
|
|||||||
key: ${{ runner.os }}-gems-${{ hashFiles('**/Gemfile.lock') }}
|
key: ${{ runner.os }}-gems-${{ hashFiles('**/Gemfile.lock') }}
|
||||||
restore-keys: |
|
restore-keys: |
|
||||||
${{ runner.os }}-gems-
|
${{ runner.os }}-gems-
|
||||||
- name: Install dependencies with Bundler
|
|
||||||
|
- name: Install Dependencies with Bundler
|
||||||
run: |
|
run: |
|
||||||
bundle config path vendor/bundle
|
bundle config path vendor/bundle
|
||||||
bundle install --jobs 4 --retry 3 --quiet
|
bundle install --jobs 4 --retry 3 --quiet
|
||||||
|
|
||||||
- name: Download IPA from Artifact
|
- name: Download IPA from Artifact
|
||||||
uses: actions/download-artifact@v4
|
uses: actions/download-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: BlueWallet_${{ needs.build.outputs.project_version }}_${{ needs.build.outputs.new_build_number }}.ipa
|
name: BlueWallet_${{ needs.build.outputs.project_version }}_${{ needs.build.outputs.new_build_number }}.ipa
|
||||||
path: ./
|
path: ./ # Download the IPA file to the current working directory
|
||||||
|
|
||||||
- name: Create App Store Connect API Key JSON
|
- name: Create App Store Connect API Key JSON
|
||||||
run: echo '${{ secrets.APP_STORE_CONNECT_API_KEY_CONTENT }}' > ./appstore_api_key.json
|
run: echo '${{ secrets.APP_STORE_CONNECT_API_KEY_CONTENT }}' > ./appstore_api_key.json
|
||||||
|
|
||||||
|
- name: Verify IPA File Download
|
||||||
|
run: |
|
||||||
|
echo "Current directory:"
|
||||||
|
pwd
|
||||||
|
echo "Files in current directory:"
|
||||||
|
ls -la ./
|
||||||
|
|
||||||
|
- name: Set IPA Path Environment Variable
|
||||||
|
run: echo "IPA_OUTPUT_PATH=$(pwd)/BlueWallet_${{ needs.build.outputs.project_version }}_${{ needs.build.outputs.new_build_number }}.ipa" >> $GITHUB_ENV
|
||||||
|
|
||||||
|
- name: Verify IPA Path Before Upload
|
||||||
|
run: |
|
||||||
|
if [ ! -f "$IPA_OUTPUT_PATH" ]; then
|
||||||
|
echo "IPA file not found at path: $IPA_OUTPUT_PATH"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
- name: Upload to TestFlight
|
- name: Upload to TestFlight
|
||||||
env:
|
run: |
|
||||||
|
ls -la $IPA_OUTPUT_PATH
|
||||||
|
bundle exec fastlane ios upload_to_testflight_lane
|
||||||
|
env:
|
||||||
APP_STORE_CONNECT_API_KEY_PATH: $(pwd)/appstore_api_key.p8
|
APP_STORE_CONNECT_API_KEY_PATH: $(pwd)/appstore_api_key.p8
|
||||||
MATCH_PASSWORD: ${{ secrets.MATCH_PASSWORD }}
|
MATCH_PASSWORD: ${{ secrets.MATCH_PASSWORD }}
|
||||||
GIT_ACCESS_TOKEN: ${{ secrets.GIT_ACCESS_TOKEN }}
|
GIT_ACCESS_TOKEN: ${{ secrets.GIT_ACCESS_TOKEN }}
|
||||||
@ -182,7 +228,8 @@ jobs:
|
|||||||
APP_STORE_CONNECT_API_KEY_KEY_ID: ${{ secrets.APP_STORE_CONNECT_API_KEY_KEY_ID }}
|
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 }}
|
APP_STORE_CONNECT_API_KEY_ISSUER_ID: ${{ secrets.APP_STORE_CONNECT_API_KEY_ISSUER_ID }}
|
||||||
KEYCHAIN_PASSWORD: ${{ secrets.KEYCHAIN_PASSWORD }}
|
KEYCHAIN_PASSWORD: ${{ secrets.KEYCHAIN_PASSWORD }}
|
||||||
run: bundle exec fastlane ios upload_to_testflight_lane
|
IPA_OUTPUT_PATH: ${{ env.IPA_OUTPUT_PATH }}
|
||||||
|
|
||||||
- name: Post PR Comment
|
- name: Post PR Comment
|
||||||
if: success() && github.event_name == 'pull_request'
|
if: success() && github.event_name == 'pull_request'
|
||||||
uses: actions/github-script@v6
|
uses: actions/github-script@v6
|
||||||
@ -199,4 +246,4 @@ jobs:
|
|||||||
...repo,
|
...repo,
|
||||||
issue_number: prNumber,
|
issue_number: prNumber,
|
||||||
body: message,
|
body: message,
|
||||||
});
|
});
|
39
Gemfile.lock
39
Gemfile.lock
@ -24,20 +24,20 @@ GEM
|
|||||||
artifactory (3.0.17)
|
artifactory (3.0.17)
|
||||||
atomos (0.1.3)
|
atomos (0.1.3)
|
||||||
aws-eventstream (1.3.0)
|
aws-eventstream (1.3.0)
|
||||||
aws-partitions (1.973.0)
|
aws-partitions (1.989.0)
|
||||||
aws-sdk-core (3.204.0)
|
aws-sdk-core (3.209.1)
|
||||||
aws-eventstream (~> 1, >= 1.3.0)
|
aws-eventstream (~> 1, >= 1.3.0)
|
||||||
aws-partitions (~> 1, >= 1.651.0)
|
aws-partitions (~> 1, >= 1.651.0)
|
||||||
aws-sigv4 (~> 1.9)
|
aws-sigv4 (~> 1.9)
|
||||||
jmespath (~> 1, >= 1.6.1)
|
jmespath (~> 1, >= 1.6.1)
|
||||||
aws-sdk-kms (1.90.0)
|
aws-sdk-kms (1.94.0)
|
||||||
aws-sdk-core (~> 3, >= 3.203.0)
|
aws-sdk-core (~> 3, >= 3.207.0)
|
||||||
aws-sigv4 (~> 1.5)
|
aws-sigv4 (~> 1.5)
|
||||||
aws-sdk-s3 (1.161.0)
|
aws-sdk-s3 (1.167.0)
|
||||||
aws-sdk-core (~> 3, >= 3.203.0)
|
aws-sdk-core (~> 3, >= 3.207.0)
|
||||||
aws-sdk-kms (~> 1)
|
aws-sdk-kms (~> 1)
|
||||||
aws-sigv4 (~> 1.5)
|
aws-sigv4 (~> 1.5)
|
||||||
aws-sigv4 (1.9.1)
|
aws-sigv4 (1.10.0)
|
||||||
aws-eventstream (~> 1, >= 1.0.2)
|
aws-eventstream (~> 1, >= 1.0.2)
|
||||||
babosa (1.0.4)
|
babosa (1.0.4)
|
||||||
base64 (0.2.0)
|
base64 (0.2.0)
|
||||||
@ -96,8 +96,8 @@ GEM
|
|||||||
escape (0.0.4)
|
escape (0.0.4)
|
||||||
ethon (0.16.0)
|
ethon (0.16.0)
|
||||||
ffi (>= 1.15.0)
|
ffi (>= 1.15.0)
|
||||||
excon (0.111.0)
|
excon (0.112.0)
|
||||||
faraday (1.10.3)
|
faraday (1.10.4)
|
||||||
faraday-em_http (~> 1.0)
|
faraday-em_http (~> 1.0)
|
||||||
faraday-em_synchrony (~> 1.0)
|
faraday-em_synchrony (~> 1.0)
|
||||||
faraday-excon (~> 1.1)
|
faraday-excon (~> 1.1)
|
||||||
@ -123,10 +123,10 @@ GEM
|
|||||||
faraday-patron (1.0.0)
|
faraday-patron (1.0.0)
|
||||||
faraday-rack (1.0.0)
|
faraday-rack (1.0.0)
|
||||||
faraday-retry (1.0.3)
|
faraday-retry (1.0.3)
|
||||||
faraday_middleware (1.2.0)
|
faraday_middleware (1.2.1)
|
||||||
faraday (~> 1.0)
|
faraday (~> 1.0)
|
||||||
fastimage (2.3.1)
|
fastimage (2.3.1)
|
||||||
fastlane (2.222.0)
|
fastlane (2.224.0)
|
||||||
CFPropertyList (>= 2.3, < 4.0.0)
|
CFPropertyList (>= 2.3, < 4.0.0)
|
||||||
addressable (>= 2.8, < 3.0.0)
|
addressable (>= 2.8, < 3.0.0)
|
||||||
artifactory (~> 3.0)
|
artifactory (~> 3.0)
|
||||||
@ -214,16 +214,17 @@ GEM
|
|||||||
http-cookie (1.0.7)
|
http-cookie (1.0.7)
|
||||||
domain_name (~> 0.5)
|
domain_name (~> 0.5)
|
||||||
httpclient (2.8.3)
|
httpclient (2.8.3)
|
||||||
i18n (1.14.5)
|
i18n (1.14.6)
|
||||||
concurrent-ruby (~> 1.0)
|
concurrent-ruby (~> 1.0)
|
||||||
jmespath (1.6.2)
|
jmespath (1.6.2)
|
||||||
json (2.7.2)
|
json (2.7.2)
|
||||||
jwt (2.8.2)
|
jwt (2.9.3)
|
||||||
base64
|
base64
|
||||||
logger (1.6.1)
|
logger (1.6.1)
|
||||||
mime-types (3.5.2)
|
mime-types (3.6.0)
|
||||||
|
logger
|
||||||
mime-types-data (~> 3.2015)
|
mime-types-data (~> 3.2015)
|
||||||
mime-types-data (3.2024.0903)
|
mime-types-data (3.2024.1001)
|
||||||
mini_magick (4.13.2)
|
mini_magick (4.13.2)
|
||||||
mini_mime (1.1.5)
|
mini_mime (1.1.5)
|
||||||
minitest (5.25.1)
|
minitest (5.25.1)
|
||||||
@ -250,7 +251,7 @@ GEM
|
|||||||
mime-types (>= 1.16, < 4.0)
|
mime-types (>= 1.16, < 4.0)
|
||||||
netrc (~> 0.8)
|
netrc (~> 0.8)
|
||||||
retriable (3.1.2)
|
retriable (3.1.2)
|
||||||
rexml (3.3.7)
|
rexml (3.3.8)
|
||||||
rouge (2.0.7)
|
rouge (2.0.7)
|
||||||
ruby-macho (2.5.1)
|
ruby-macho (2.5.1)
|
||||||
ruby2_keywords (0.0.5)
|
ruby2_keywords (0.0.5)
|
||||||
@ -278,15 +279,15 @@ GEM
|
|||||||
tzinfo (2.0.6)
|
tzinfo (2.0.6)
|
||||||
concurrent-ruby (~> 1.0)
|
concurrent-ruby (~> 1.0)
|
||||||
uber (0.1.0)
|
uber (0.1.0)
|
||||||
unicode-display_width (2.5.0)
|
unicode-display_width (2.6.0)
|
||||||
word_wrap (1.0.0)
|
word_wrap (1.0.0)
|
||||||
xcodeproj (1.25.0)
|
xcodeproj (1.25.1)
|
||||||
CFPropertyList (>= 2.3.3, < 4.0)
|
CFPropertyList (>= 2.3.3, < 4.0)
|
||||||
atomos (~> 0.1.3)
|
atomos (~> 0.1.3)
|
||||||
claide (>= 1.0.2, < 2.0)
|
claide (>= 1.0.2, < 2.0)
|
||||||
colored2 (~> 3.1)
|
colored2 (~> 3.1)
|
||||||
nanaimo (~> 0.3.0)
|
nanaimo (~> 0.3.0)
|
||||||
rexml (>= 3.3.2, < 4.0)
|
rexml (>= 3.3.6, < 4.0)
|
||||||
xcpretty (0.3.0)
|
xcpretty (0.3.0)
|
||||||
rouge (~> 2.0.7)
|
rouge (~> 2.0.7)
|
||||||
xcpretty-travis-formatter (1.0.1)
|
xcpretty-travis-formatter (1.0.1)
|
||||||
|
@ -1,75 +1,75 @@
|
|||||||
|
# Define app identifiers once for reuse across lanes
|
||||||
def app_identifiers
|
def app_identifiers
|
||||||
["io.bluewallet.bluewallet", "io.bluewallet.bluewallet.watch", "io.bluewallet.bluewallet.watch.extension", "io.bluewallet.bluewallet.Stickers", "io.bluewallet.bluewallet.MarketWidget"]
|
[
|
||||||
|
"io.bluewallet.bluewallet",
|
||||||
|
"io.bluewallet.bluewallet.watch",
|
||||||
|
"io.bluewallet.bluewallet.watch.extension",
|
||||||
|
"io.bluewallet.bluewallet.Stickers",
|
||||||
|
"io.bluewallet.bluewallet.MarketWidget"
|
||||||
|
]
|
||||||
end
|
end
|
||||||
|
|
||||||
default_platform(:android)
|
default_platform(:android)
|
||||||
project_root = File.expand_path("..", __dir__)
|
project_root = File.expand_path("..", __dir__)
|
||||||
|
|
||||||
|
# ===========================
|
||||||
|
# Android Lanes
|
||||||
|
# ===========================
|
||||||
|
|
||||||
platform :android do
|
platform :android do
|
||||||
|
|
||||||
desc "Prepare the keystore file"
|
desc "Prepare the keystore file"
|
||||||
lane :prepare_keystore do
|
lane :prepare_keystore do
|
||||||
Dir.chdir(project_root) do
|
keystore_file_hex = ENV['KEYSTORE_FILE_HEX']
|
||||||
keystore_file_hex = ENV['KEYSTORE_FILE_HEX']
|
UI.user_error!("KEYSTORE_FILE_HEX environment variable is missing") if keystore_file_hex.nil?
|
||||||
UI.user_error!("KEYSTORE_FILE_HEX environment variable is missing") if keystore_file_hex.nil?
|
|
||||||
|
|
||||||
Dir.chdir("android") do
|
Dir.chdir("android") do
|
||||||
UI.message("Creating keystore hex file...")
|
UI.message("Creating keystore from HEX...")
|
||||||
|
File.write("bluewallet-release-key.keystore.hex", keystore_file_hex)
|
||||||
|
|
||||||
File.write("bluewallet-release-key.keystore.hex", keystore_file_hex)
|
sh("xxd -plain -revert bluewallet-release-key.keystore.hex > bluewallet-release-key.keystore") do |status|
|
||||||
|
UI.user_error!("Error reverting hex to keystore") unless status.success?
|
||||||
sh("xxd -plain -revert bluewallet-release-key.keystore.hex > bluewallet-release-key.keystore") do |status|
|
|
||||||
UI.user_error!("Error reverting hex to keystore") unless status.success?
|
|
||||||
end
|
|
||||||
UI.message("Keystore created successfully.")
|
|
||||||
|
|
||||||
File.delete("bluewallet-release-key.keystore.hex")
|
|
||||||
end
|
end
|
||||||
|
UI.message("Keystore created successfully.")
|
||||||
|
|
||||||
|
File.delete("bluewallet-release-key.keystore.hex")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
desc "Update version, build number, and sign APK"
|
||||||
lane :update_version_build_and_sign_apk do
|
lane :update_version_build_and_sign_apk do
|
||||||
Dir.chdir(project_root) do
|
Dir.chdir(project_root) do
|
||||||
build_number = ENV['BUILD_NUMBER']
|
build_number = ENV['BUILD_NUMBER']
|
||||||
UI.user_error!("BUILD_NUMBER environment variable is missing") if build_number.nil?
|
UI.user_error!("BUILD_NUMBER environment variable is missing") if build_number.nil?
|
||||||
|
|
||||||
# Get the version name from build.gradle
|
# Extract versionName from build.gradle
|
||||||
version_name = sh("grep versionName android/app/build.gradle | awk '{print $2}' | tr -d '\"'").strip
|
version_name = sh("grep versionName android/app/build.gradle | awk '{print $2}' | tr -d '\"'").strip
|
||||||
|
|
||||||
# Manually update the versionCode in build.gradle
|
# Update versionCode in build.gradle
|
||||||
UI.message("Updating versionCode in build.gradle to #{build_number}...")
|
UI.message("Updating versionCode in build.gradle to #{build_number}...")
|
||||||
build_gradle_path = "android/app/build.gradle"
|
build_gradle_path = "android/app/build.gradle"
|
||||||
build_gradle_contents = File.read(build_gradle_path)
|
build_gradle_contents = File.read(build_gradle_path)
|
||||||
new_build_gradle_contents = build_gradle_contents.gsub(/versionCode\s+\d+/, "versionCode #{build_number}")
|
new_build_gradle_contents = build_gradle_contents.gsub(/versionCode\s+\d+/, "versionCode #{build_number}")
|
||||||
File.write(build_gradle_path, new_build_gradle_contents)
|
File.write(build_gradle_path, new_build_gradle_contents)
|
||||||
|
|
||||||
# Get the branch name and default to 'master' if empty
|
# Determine branch name
|
||||||
branch_name = ENV['GITHUB_HEAD_REF'] || `git rev-parse --abbrev-ref HEAD`.strip.gsub(/[\/\\:?*"<>|]/, '_')
|
branch_name = ENV['GITHUB_HEAD_REF'] || `git rev-parse --abbrev-ref HEAD`.strip.gsub(/[\/\\:?*"<>|]/, '_')
|
||||||
if branch_name.nil? || branch_name.empty?
|
branch_name = 'master' if branch_name.nil? || branch_name.empty?
|
||||||
branch_name = 'master'
|
|
||||||
end
|
# Define APK name based on branch
|
||||||
|
signed_apk_name = branch_name != 'master' ? "BlueWallet-#{version_name}-#{build_number}-#{branch_name}.apk" : "BlueWallet-#{version_name}-#{build_number}.apk"
|
||||||
# Append branch name only if it's not 'master'
|
|
||||||
if branch_name != 'master'
|
# Build APK
|
||||||
signed_apk_name = "BlueWallet-#{version_name}-#{build_number}-#{branch_name}.apk"
|
|
||||||
else
|
|
||||||
signed_apk_name = "BlueWallet-#{version_name}-#{build_number}.apk"
|
|
||||||
end
|
|
||||||
|
|
||||||
# Continue with the build process
|
|
||||||
Dir.chdir("android") do
|
Dir.chdir("android") do
|
||||||
UI.message("Building APK...")
|
UI.message("Building APK...")
|
||||||
gradle(
|
gradle(task: "assembleRelease", project_dir: "android")
|
||||||
task: "assembleRelease",
|
|
||||||
project_dir: "android"
|
|
||||||
)
|
|
||||||
UI.message("APK build completed.")
|
UI.message("APK build completed.")
|
||||||
|
|
||||||
# Define the output paths
|
# Define paths
|
||||||
unsigned_apk_path = "app/build/outputs/apk/release/app-release-unsigned.apk"
|
unsigned_apk_path = "app/build/outputs/apk/release/app-release-unsigned.apk"
|
||||||
signed_apk_path = "app/build/outputs/apk/release/#{signed_apk_name}"
|
signed_apk_path = "app/build/outputs/apk/release/#{signed_apk_name}"
|
||||||
|
|
||||||
# Rename the unsigned APK to include the version and build number
|
# Rename APK
|
||||||
if File.exist?(unsigned_apk_path)
|
if File.exist?(unsigned_apk_path)
|
||||||
UI.message("Renaming APK to #{signed_apk_name}...")
|
UI.message("Renaming APK to #{signed_apk_name}...")
|
||||||
FileUtils.mv(unsigned_apk_path, signed_apk_path)
|
FileUtils.mv(unsigned_apk_path, signed_apk_path)
|
||||||
@ -78,8 +78,8 @@ platform :android do
|
|||||||
UI.error("Unsigned APK not found at path: #{unsigned_apk_path}")
|
UI.error("Unsigned APK not found at path: #{unsigned_apk_path}")
|
||||||
next
|
next
|
||||||
end
|
end
|
||||||
|
|
||||||
# Sign the APK using apksigner
|
# Sign APK
|
||||||
UI.message("Signing APK with apksigner...")
|
UI.message("Signing APK with apksigner...")
|
||||||
apksigner_path = "#{ENV['ANDROID_HOME']}/build-tools/34.0.0/apksigner"
|
apksigner_path = "#{ENV['ANDROID_HOME']}/build-tools/34.0.0/apksigner"
|
||||||
sh("#{apksigner_path} sign --ks ./bluewallet-release-key.keystore --ks-pass=pass:#{ENV['KEYSTORE_PASSWORD']} #{signed_apk_path}")
|
sh("#{apksigner_path} sign --ks ./bluewallet-release-key.keystore --ks-pass=pass:#{ENV['KEYSTORE_PASSWORD']} #{signed_apk_path}")
|
||||||
@ -91,33 +91,32 @@ platform :android do
|
|||||||
desc "Upload APK to BrowserStack and post result as PR comment"
|
desc "Upload APK to BrowserStack and post result as PR comment"
|
||||||
lane :upload_to_browserstack_and_comment do
|
lane :upload_to_browserstack_and_comment do
|
||||||
Dir.chdir(project_root) do
|
Dir.chdir(project_root) do
|
||||||
# Fetch the APK path from environment variables
|
# Determine APK path
|
||||||
apk_path = ENV['APK_PATH']
|
apk_path = ENV['APK_PATH']
|
||||||
|
|
||||||
# Attempt to find the APK if not provided
|
|
||||||
if apk_path.nil? || apk_path.empty?
|
if apk_path.nil? || apk_path.empty?
|
||||||
UI.message("No APK path provided, attempting to find the artifact...")
|
UI.message("No APK path provided, searching for APK...")
|
||||||
apk_path = `find ./ -name "*.apk"`.strip
|
apk_path = `find ./ -name "*.apk"`.strip
|
||||||
UI.user_error!("No APK file found") if apk_path.nil? || apk_path.empty?
|
UI.user_error!("No APK file found") if apk_path.nil? || apk_path.empty?
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Upload to BrowserStack
|
||||||
UI.message("Uploading APK to BrowserStack: #{apk_path}...")
|
UI.message("Uploading APK to BrowserStack: #{apk_path}...")
|
||||||
upload_to_browserstack_app_live(
|
upload_to_browserstack_app_live(
|
||||||
file_path: apk_path,
|
file_path: apk_path,
|
||||||
browserstack_username: ENV['BROWSERSTACK_USERNAME'],
|
browserstack_username: ENV['BROWSERSTACK_USERNAME'],
|
||||||
browserstack_access_key: ENV['BROWSERSTACK_ACCESS_KEY']
|
browserstack_access_key: ENV['BROWSERSTACK_ACCESS_KEY']
|
||||||
)
|
)
|
||||||
|
|
||||||
# Extract the BrowserStack URL from the output
|
# Extract BrowserStack URL
|
||||||
app_url = ENV['BROWSERSTACK_LIVE_APP_ID']
|
app_url = ENV['BROWSERSTACK_LIVE_APP_ID']
|
||||||
UI.user_error!("BrowserStack upload failed, no app URL returned") if app_url.nil? || app_url.empty?
|
UI.user_error!("BrowserStack upload failed, no app URL returned") if app_url.nil? || app_url.empty?
|
||||||
|
|
||||||
# Prepare necessary values for the PR comment
|
# Prepare PR comment
|
||||||
apk_filename = File.basename(apk_path)
|
apk_filename = File.basename(apk_path)
|
||||||
apk_download_url = ENV['APK_OUTPUT_PATH'] # Assuming this path is accessible to the PR
|
apk_download_url = ENV['APK_OUTPUT_PATH'] # Ensure this path is accessible
|
||||||
browserstack_hashed_id = app_url.gsub('bs://', '')
|
browserstack_hashed_id = app_url.gsub('bs://', '')
|
||||||
pr_number = ENV['GITHUB_PR_NUMBER']
|
pr_number = ENV['GITHUB_PR_NUMBER']
|
||||||
|
|
||||||
comment = <<~COMMENT
|
comment = <<~COMMENT
|
||||||
### APK Successfully Uploaded to BrowserStack
|
### APK Successfully Uploaded to BrowserStack
|
||||||
|
|
||||||
@ -127,16 +126,17 @@ platform :android do
|
|||||||
- [Google Pixel 7 (Android 13.0)](https://app-live.browserstack.com/dashboard#os=android&os_version=13.0&device=Google+Pixel+7&app_hashed_id=#{browserstack_hashed_id}&scale_to_fit=true&speed=1&start=true)
|
- [Google Pixel 7 (Android 13.0)](https://app-live.browserstack.com/dashboard#os=android&os_version=13.0&device=Google+Pixel+7&app_hashed_id=#{browserstack_hashed_id}&scale_to_fit=true&speed=1&start=true)
|
||||||
- [Google Pixel 8 (Android 14.0)](https://app-live.browserstack.com/dashboard#os=android&os_version=14.0&device=Google+Pixel+8&app_hashed_id=#{browserstack_hashed_id}&scale_to_fit=true&speed=1&start=true)
|
- [Google Pixel 8 (Android 14.0)](https://app-live.browserstack.com/dashboard#os=android&os_version=14.0&device=Google+Pixel+8&app_hashed_id=#{browserstack_hashed_id}&scale_to_fit=true&speed=1&start=true)
|
||||||
- [Google Pixel 3a (Android 9.0)](https://app-live.browserstack.com/dashboard#os=android&os_version=9.0&device=Google+Pixel+3a&app_hashed_id=#{browserstack_hashed_id}&scale_to_fit=true&speed=1&start=true)
|
- [Google Pixel 3a (Android 9.0)](https://app-live.browserstack.com/dashboard#os=android&os_version=9.0&device=Google+Pixel+3a&app_hashed_id=#{browserstack_hashed_id}&scale_to_fit=true&speed=1&start=true)
|
||||||
|
|
||||||
- [Samsung Galaxy Z Fold 5 (Android 13.0)](https://app-live.browserstack.com/dashboard#os=android&os_version=13.0&device=Samsung+Galaxy+Z+Fold+5&app_hashed_id=#{browserstack_hashed_id}&scale_to_fit=true&speed=1&start=true)
|
- [Samsung Galaxy Z Fold 5 (Android 13.0)](https://app-live.browserstack.com/dashboard#os=android&os_version=13.0&device=Samsung+Galaxy+Z+Fold+5&app_hashed_id=#{browserstack_hashed_id}&scale_to_fit=true&speed=1&start=true)
|
||||||
- [Samsung Galaxy Z Fold 6 (Android 14.0)](https://app-live.browserstack.com/dashboard#os=android&os_version=14.0&device=Samsung+Galaxy+Z+Fold+6&app_hashed_id=#{browserstack_hashed_id}&scale_to_fit=true&speed=1&start=true)
|
- [Samsung Galaxy Z Fold 6 (Android 14.0)](https://app-live.browserstack.com/dashboard#os=android&os_version=14.0&device=Samsung+Galaxy+Z+Fold+6&app_hashed_id=#{browserstack_hashed_id}&scale_to_fit=true&speed=1&start=true)
|
||||||
- [Samsung Galaxy Tab S9 (Android 13.0)](https://app-live.browserstack.com/dashboard#os=android&os_version=13.0&device=Samsung+Galaxy+Tab+S9&app_hashed_id=#{browserstack_hashed_id}&scale_to_fit=true&speed=1&start=true)
|
- [Samsung Galaxy Tab S9 (Android 13.0)](https://app-live.browserstack.com/dashboard#os=android&os_version=13.0&device=Samsung+Galaxy+Tab+S9&app_hashed_id=#{browserstack_hashed_id}&scale_to_fit=true&speed=1&start=true)
|
||||||
- [Samsung Galaxy Note 9 (Android 8.1)](https://app-live.browserstack.com/dashboard#os=android&os_version=8.1&device=Samsung+Galaxy+Note+9&app_hashed_id=#{browserstack_hashed_id}&scale_to_fit=true&speed=1&start=true)
|
- [Samsung Galaxy Note 9 (Android 8.1)](https://app-live.browserstack.com/dashboard#os=android&os_version=8.1&device=Samsung+Galaxy+Note+9&app_hashed_id=#{browserstack_hashed_id}&scale_to_fit=true&speed=1&start=true)
|
||||||
|
|
||||||
**Filename**: [#{apk_filename}](#{apk_download_url})
|
**Filename**: [#{apk_filename}](#{apk_download_url})
|
||||||
**BrowserStack App URL**: #{app_url}
|
**BrowserStack App URL**: #{app_url}
|
||||||
COMMENT
|
COMMENT
|
||||||
|
|
||||||
|
# Post PR comment if PR number is available
|
||||||
if pr_number
|
if pr_number
|
||||||
begin
|
begin
|
||||||
sh("GH_TOKEN=#{ENV['GH_TOKEN']} gh pr comment #{pr_number} --body '#{comment}'")
|
sh("GH_TOKEN=#{ENV['GH_TOKEN']} gh pr comment #{pr_number} --body '#{comment}'")
|
||||||
@ -149,36 +149,34 @@ platform :android do
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# ===========================
|
||||||
|
# iOS Lanes
|
||||||
|
# ===========================
|
||||||
|
|
||||||
platform :ios do
|
platform :ios do
|
||||||
|
|
||||||
before_all do |lane, options|
|
|
||||||
UI.message("Setting up for all lanes...")
|
|
||||||
UI.message("Discarding all untracked changes before running any lane...")
|
|
||||||
sh("git clean -fd")
|
|
||||||
sh("git checkout -- .")
|
|
||||||
end
|
|
||||||
|
|
||||||
desc "Register new devices from a file"
|
desc "Register new devices from a file"
|
||||||
lane :register_devices_from_txt do
|
lane :register_devices_from_txt do
|
||||||
UI.message("Registering new devices from file...")
|
UI.message("Registering new devices from file...")
|
||||||
|
|
||||||
csv_path = "../../devices.txt" # Update this with the actual path to your file
|
csv_path = "../../devices.txt" # Update this with the actual path to your file
|
||||||
|
|
||||||
# Registering devices using the devices_file parameter
|
# Register devices using the devices_file parameter
|
||||||
register_devices(
|
register_devices(
|
||||||
devices_file: csv_path
|
devices_file: csv_path
|
||||||
)
|
)
|
||||||
|
|
||||||
UI.message("Devices registered successfully.")
|
UI.message("Devices registered successfully.")
|
||||||
|
|
||||||
|
# Update provisioning profiles for all app identifiers
|
||||||
app_identifiers.each do |app_identifier|
|
app_identifiers.each do |app_identifier|
|
||||||
match(
|
match(
|
||||||
type: "development",
|
type: "development",
|
||||||
app_identifier: app_identifier,
|
app_identifier: app_identifier,
|
||||||
readonly: false, # This will regenerate the provisioning profile if needed
|
readonly: false, # Regenerate provisioning profile if needed
|
||||||
force_for_new_devices: true,
|
force_for_new_devices: true,
|
||||||
clone_branch_directly: true
|
clone_branch_directly: true
|
||||||
)
|
)
|
||||||
@ -190,7 +188,7 @@ platform :ios do
|
|||||||
desc "Create a temporary keychain"
|
desc "Create a temporary keychain"
|
||||||
lane :create_temp_keychain do
|
lane :create_temp_keychain do
|
||||||
UI.message("Creating a temporary keychain...")
|
UI.message("Creating a temporary keychain...")
|
||||||
|
|
||||||
create_keychain(
|
create_keychain(
|
||||||
name: "temp_keychain",
|
name: "temp_keychain",
|
||||||
password: ENV["KEYCHAIN_PASSWORD"],
|
password: ENV["KEYCHAIN_PASSWORD"],
|
||||||
@ -199,32 +197,26 @@ platform :ios do
|
|||||||
timeout: 3600,
|
timeout: 3600,
|
||||||
lock_when_sleeps: true
|
lock_when_sleeps: true
|
||||||
)
|
)
|
||||||
|
|
||||||
UI.message("Temporary keychain created successfully.")
|
UI.message("Temporary keychain created successfully.")
|
||||||
end
|
end
|
||||||
|
|
||||||
desc "Synchronize certificates and provisioning profiles"
|
desc "Synchronize certificates and provisioning profiles"
|
||||||
lane :setup_provisioning_profiles do |options|
|
lane :setup_provisioning_profiles do
|
||||||
UI.message("Setting up provisioning profiles...")
|
UI.message("Setting up provisioning profiles...")
|
||||||
target_to_app_identifier = {
|
|
||||||
'BlueWallet' => 'io.bluewallet.bluewallet',
|
|
||||||
'BlueWalletWatch' => 'io.bluewallet.bluewallet.watch',
|
|
||||||
'BlueWalletWatchExtension' => 'io.bluewallet.bluewallet.watch.extension',
|
|
||||||
'Stickers' => 'io.bluewallet.bluewallet.Stickers',
|
|
||||||
'MarketWidget' => 'io.bluewallet.bluewallet.MarketWidget'
|
|
||||||
}
|
|
||||||
|
|
||||||
platform = options[:platform] || "ios" # Default to iOS if not specified
|
platform = "ios"
|
||||||
|
|
||||||
# Remove local master branch if it exists (Exit status: 128 - 'fatal: a branch named 'master' already exists')
|
# Remove local master branch if it exists to avoid conflicts
|
||||||
sh("git branch -D master || true")
|
sh("git branch -D master || true")
|
||||||
|
|
||||||
target_to_app_identifier.each do |target, app_identifier|
|
# Iterate over app identifiers to fetch provisioning profiles
|
||||||
|
app_identifiers.each do |app_identifier|
|
||||||
match(
|
match(
|
||||||
git_basic_authorization: ENV["GIT_ACCESS_TOKEN"],
|
git_basic_authorization: ENV["GIT_ACCESS_TOKEN"],
|
||||||
git_url: ENV["GIT_URL"],
|
git_url: ENV["GIT_URL"],
|
||||||
type: "appstore",
|
type: "appstore",
|
||||||
clone_branch_directly: true, # Skip if the branch already exists (Exit 128 error)
|
clone_branch_directly: true, # Skip if the branch already exists
|
||||||
platform: platform,
|
platform: platform,
|
||||||
app_identifier: app_identifier,
|
app_identifier: app_identifier,
|
||||||
team_id: ENV["ITC_TEAM_ID"],
|
team_id: ENV["ITC_TEAM_ID"],
|
||||||
@ -255,7 +247,6 @@ platform :ios do
|
|||||||
app_identifier: app_identifiers,
|
app_identifier: app_identifiers,
|
||||||
readonly: true,
|
readonly: true,
|
||||||
clone_branch_directly: true
|
clone_branch_directly: true
|
||||||
|
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -306,94 +297,116 @@ platform :ios do
|
|||||||
cocoapods(podfile: "ios/Podfile")
|
cocoapods(podfile: "ios/Podfile")
|
||||||
end
|
end
|
||||||
|
|
||||||
desc "Build the application"
|
desc "Upload IPA to TestFlight"
|
||||||
lane :build_app_lane do
|
lane :upload_to_testflight_lane do
|
||||||
UI.message("Building the application...")
|
ipa_path = ENV['IPA_OUTPUT_PATH']
|
||||||
build_app(
|
changelog = ENV["LATEST_COMMIT_MESSAGE"]
|
||||||
scheme: "BlueWallet",
|
|
||||||
workspace: "ios/BlueWallet.xcworkspace",
|
|
||||||
export_method: "app-store",
|
|
||||||
include_bitcode: false,
|
|
||||||
configuration: "Release",
|
|
||||||
skip_profile_detection: true,
|
|
||||||
include_symbols: true,
|
|
||||||
export_team_id: ENV["ITC_TEAM_ID"],
|
|
||||||
export_options: {
|
|
||||||
signingStyle: "manual",
|
|
||||||
provisioningProfiles: {
|
|
||||||
'io.bluewallet.bluewallet' => 'match AppStore io.bluewallet.bluewallet',
|
|
||||||
'io.bluewallet.bluewallet.watch' => 'match AppStore io.bluewallet.bluewallet.watch',
|
|
||||||
'io.bluewallet.bluewallet.watch.extension' => 'match AppStore io.bluewallet.bluewallet.watch.extension',
|
|
||||||
'io.bluewallet.bluewallet.Stickers' => 'match AppStore io.bluewallet.bluewallet.Stickers',
|
|
||||||
'io.bluewallet.bluewallet.MarketWidget' => 'match AppStore io.bluewallet.bluewallet.MarketWidget'
|
|
||||||
}
|
|
||||||
},
|
|
||||||
xcargs: "GCC_PREPROCESSOR_DEFINITIONS='$(inherited) VERBOSE_LOGGING=1'",
|
|
||||||
output_directory: "./build", # Directory where the IPA file will be stored
|
|
||||||
|
|
||||||
output_name: "BlueWallet_#{ENV['PROJECT_VERSION']}_#{ENV['NEW_BUILD_NUMBER']}.ipa",
|
# Check if IPA exists before proceeding
|
||||||
buildlog_path: "./build_logs"
|
if ipa_path.nil? || ipa_path.empty? || !File.exist?(ipa_path)
|
||||||
)
|
UI.user_error!("IPA file not found at path: #{ipa_path}")
|
||||||
end
|
end
|
||||||
|
|
||||||
desc "Upload to TestFlight without Processing Wait"
|
UI.message("Uploading IPA to TestFlight from path: #{ipa_path}")
|
||||||
lane :upload_to_testflight_lane do
|
|
||||||
attempts = 0
|
upload_to_testflight(
|
||||||
max_attempts = 3
|
api_key_path: "./appstore_api_key.json",
|
||||||
|
ipa: ipa_path,
|
||||||
|
skip_waiting_for_build_processing: true, # Do not wait for processing
|
||||||
|
changelog: changelog
|
||||||
|
)
|
||||||
|
|
||||||
|
UI.success("Successfully uploaded IPA to TestFlight!")
|
||||||
|
end
|
||||||
|
|
||||||
|
desc "Build the iOS app"
|
||||||
|
lane :build_app_lane do
|
||||||
|
Dir.chdir(project_root) do
|
||||||
|
UI.message("Building the application from: #{Dir.pwd}")
|
||||||
|
|
||||||
|
workspace_path = File.join(project_root, "ios", "BlueWallet.xcworkspace")
|
||||||
|
export_options_path = File.join(project_root, "ios", "export_options.plist")
|
||||||
|
|
||||||
begin
|
begin
|
||||||
UI.message("Uploading to TestFlight without processing wait...")
|
build_ios_app(
|
||||||
changelog = ENV["LATEST_COMMIT_MESSAGE"]
|
scheme: "BlueWallet",
|
||||||
ipa_path = "./BlueWallet_#{ENV['PROJECT_VERSION']}_#{ENV['NEW_BUILD_NUMBER']}.ipa"
|
workspace: workspace_path,
|
||||||
|
export_method: "app-store",
|
||||||
upload_to_testflight(
|
include_bitcode: false,
|
||||||
api_key_path: "./appstore_api_key.json",
|
configuration: "Release",
|
||||||
ipa: ipa_path,
|
skip_profile_detection: false,
|
||||||
skip_waiting_for_build_processing: true, # Do not wait for processing
|
include_symbols: true,
|
||||||
changelog: changelog
|
export_team_id: ENV["ITC_TEAM_ID"],
|
||||||
|
export_options: export_options_path,
|
||||||
|
output_directory: File.join(project_root, "ios", "build"),
|
||||||
|
output_name: "BlueWallet_#{ENV['PROJECT_VERSION']}_#{ENV['NEW_BUILD_NUMBER']}.ipa",
|
||||||
|
buildlog_path: File.join(project_root, "ios", "build_logs"),
|
||||||
|
silent: false,
|
||||||
|
clean: true
|
||||||
)
|
)
|
||||||
rescue => exception
|
rescue => e
|
||||||
attempts += 1
|
UI.user_error!("build_ios_app failed: #{e.message}")
|
||||||
if attempts <= max_attempts
|
|
||||||
wait_time = 180 # 3 minutes in seconds
|
|
||||||
UI.message("Attempt ##{attempts} failed with error: #{exception.message}. Waiting #{wait_time} seconds before trying again...")
|
|
||||||
sleep(wait_time)
|
|
||||||
retry
|
|
||||||
else
|
|
||||||
UI.error("Failed after #{max_attempts} attempts. Error: #{exception.message}")
|
|
||||||
raise exception
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
desc "Deploy to TestFlight"
|
|
||||||
lane :deploy do |options|
|
|
||||||
UI.message("Starting build process...")
|
|
||||||
|
|
||||||
# Update the WWDR certificate
|
|
||||||
update_wwdr_certificate
|
|
||||||
|
|
||||||
setup_app_store_connect_api_key
|
|
||||||
setup_provisioning_profiles
|
|
||||||
clear_derived_data_lane
|
|
||||||
increment_build_number_lane
|
|
||||||
|
|
||||||
unless File.directory?("Pods")
|
|
||||||
install_pods
|
|
||||||
end
|
end
|
||||||
|
|
||||||
build_app_lane
|
# Use File.join to construct paths without extra slashes
|
||||||
upload_to_testflight_lane
|
ipa_path = lane_context[SharedValues::IPA_OUTPUT_PATH]
|
||||||
|
|
||||||
# Clean up and delete the temporary keychain
|
if ipa_path && File.exist?(ipa_path)
|
||||||
delete_keychain(name: "temp_keychain")
|
UI.message("IPA successfully found at: #{ipa_path}")
|
||||||
|
ENV['IPA_OUTPUT_PATH'] = ipa_path
|
||||||
|
sh("echo 'IPA_OUTPUT_PATH=#{ipa_path}' >> $GITHUB_ENV") # Export for GitHub Actions
|
||||||
|
else
|
||||||
|
UI.user_error!("IPA not found after build_ios_app.")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
# Mark deployment as completed for the current commit
|
# ===========================
|
||||||
last_commit = last_git_commit
|
# Global Lanes
|
||||||
already_built_flag = ".already_built_#{last_commit[:sha]}"
|
# ===========================
|
||||||
File.write(already_built_flag, Time.now.to_s)
|
|
||||||
|
|
||||||
|
|
||||||
|
desc "Deploy to TestFlight"
|
||||||
|
lane :deploy do |options|
|
||||||
|
UI.message("Starting deployment process...")
|
||||||
|
|
||||||
|
# Update WWDR Certificate
|
||||||
|
update_wwdr_certificate
|
||||||
|
|
||||||
|
# Setup App Store Connect API Key
|
||||||
|
setup_app_store_connect_api_key
|
||||||
|
|
||||||
|
# Setup Provisioning Profiles
|
||||||
|
setup_provisioning_profiles
|
||||||
|
|
||||||
|
# Clear Derived Data
|
||||||
|
clear_derived_data_lane
|
||||||
|
|
||||||
|
# Increment Build Number
|
||||||
|
increment_build_number_lane
|
||||||
|
|
||||||
|
# Install CocoaPods if not already installed
|
||||||
|
unless File.directory?("Pods")
|
||||||
|
install_pods
|
||||||
end
|
end
|
||||||
|
|
||||||
desc "Update 'What's New' section in App Store Connect for the 'Prepare for Submission' version"
|
# Build the iOS App
|
||||||
|
build_app_lane
|
||||||
|
|
||||||
|
# Upload IPA to TestFlight
|
||||||
|
upload_to_testflight_lane
|
||||||
|
|
||||||
|
# Clean up and delete the temporary keychain
|
||||||
|
delete_keychain(name: "temp_keychain")
|
||||||
|
|
||||||
|
# Mark deployment as completed for the current commit
|
||||||
|
last_commit = last_git_commit
|
||||||
|
already_built_flag = ".already_built_#{last_commit[:sha]}"
|
||||||
|
File.write(already_built_flag, Time.now.to_s)
|
||||||
|
end
|
||||||
|
|
||||||
|
desc "Update 'What's New' section in App Store Connect for the 'Prepare for Submission' version"
|
||||||
lane :update_release_notes do |options|
|
lane :update_release_notes do |options|
|
||||||
require 'spaceship'
|
require 'spaceship'
|
||||||
|
|
||||||
@ -402,16 +415,13 @@ lane :update_release_notes do |options|
|
|||||||
|
|
||||||
app = Spaceship::ConnectAPI::App.find(app_identifiers.first)
|
app = Spaceship::ConnectAPI::App.find(app_identifiers.first)
|
||||||
|
|
||||||
unless app
|
UI.user_error!("Could not find the app with identifier: #{app_identifiers.first}") unless app
|
||||||
UI.user_error!("Could not find the app with identifier: #{app_identifiers.first}")
|
|
||||||
end
|
|
||||||
|
|
||||||
# Retry logic for fetching or creating the edit version
|
# Retry logic for fetching or creating the edit version
|
||||||
retries = 5
|
retries = 5
|
||||||
begin
|
begin
|
||||||
prepare_version = app.get_edit_app_store_version(platform: Spaceship::ConnectAPI::Platform::IOS)
|
prepare_version = app.get_edit_app_store_version(platform: Spaceship::ConnectAPI::Platform::IOS)
|
||||||
|
|
||||||
# If no "Prepare for Submission" version is found, create a new one
|
|
||||||
if prepare_version.nil?
|
if prepare_version.nil?
|
||||||
UI.message("No version in 'Prepare for Submission' found. Creating a new version...")
|
UI.message("No version in 'Prepare for Submission' found. Creating a new version...")
|
||||||
latest_version = app.get_latest_version(platform: Spaceship::ConnectAPI::Platform::IOS)
|
latest_version = app.get_latest_version(platform: Spaceship::ConnectAPI::Platform::IOS)
|
||||||
@ -436,12 +446,11 @@ lane :update_release_notes do |options|
|
|||||||
# Extract existing metadata
|
# Extract existing metadata
|
||||||
localized_metadata = prepare_version.get_app_store_version_localizations
|
localized_metadata = prepare_version.get_app_store_version_localizations
|
||||||
|
|
||||||
# Get all the enabled locales for the app version
|
# Get enabled locales
|
||||||
enabled_locales = localized_metadata.map(&:locale)
|
enabled_locales = localized_metadata.map(&:locale)
|
||||||
|
|
||||||
# Define valid language codes and filter them based on enabled locales
|
# Define release notes
|
||||||
release_notes_text = options[:release_notes]
|
release_notes_text = options[:release_notes]
|
||||||
|
|
||||||
if release_notes_text.nil? || release_notes_text.strip.empty?
|
if release_notes_text.nil? || release_notes_text.strip.empty?
|
||||||
release_notes_path = "../../release-notes.txt"
|
release_notes_path = "../../release-notes.txt"
|
||||||
unless File.exist?(release_notes_path)
|
unless File.exist?(release_notes_path)
|
||||||
@ -451,6 +460,7 @@ lane :update_release_notes do |options|
|
|||||||
release_notes_text = File.read(release_notes_path)
|
release_notes_text = File.read(release_notes_path)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Define localized release notes
|
||||||
localized_release_notes = {
|
localized_release_notes = {
|
||||||
'en-US' => release_notes_text, # English (U.S.) - Primary
|
'en-US' => release_notes_text, # English (U.S.) - Primary
|
||||||
'ar-SA' => release_notes_text, # Arabic
|
'ar-SA' => release_notes_text, # Arabic
|
||||||
@ -479,7 +489,7 @@ lane :update_release_notes do |options|
|
|||||||
'th' => release_notes_text, # Thai
|
'th' => release_notes_text, # Thai
|
||||||
}.select { |locale, _| enabled_locales.include?(locale) } # Only include enabled locales
|
}.select { |locale, _| enabled_locales.include?(locale) } # Only include enabled locales
|
||||||
|
|
||||||
# Review what's going to be updated
|
# Review release notes updates
|
||||||
UI.message("Review the following release notes updates:")
|
UI.message("Review the following release notes updates:")
|
||||||
localized_release_notes.each do |locale, notes|
|
localized_release_notes.each do |locale, notes|
|
||||||
UI.message("Locale: #{locale} - Notes: #{notes}")
|
UI.message("Locale: #{locale} - Notes: #{notes}")
|
||||||
@ -487,21 +497,17 @@ lane :update_release_notes do |options|
|
|||||||
|
|
||||||
unless options[:force_yes]
|
unless options[:force_yes]
|
||||||
confirm = UI.confirm("Do you want to proceed with these release notes updates?")
|
confirm = UI.confirm("Do you want to proceed with these release notes updates?")
|
||||||
unless confirm
|
UI.user_error!("User aborted the lane.") unless confirm
|
||||||
UI.user_error!("User aborted the lane.")
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
# Update release notes in App Store Connect and skip all other metadata
|
# Update release notes in App Store Connect
|
||||||
localized_release_notes.each do |locale, notes|
|
localized_release_notes.each do |locale, notes|
|
||||||
app_store_version_localization = localized_metadata.find { |loc| loc.locale == locale }
|
app_store_version_localization = localized_metadata.find { |loc| loc.locale == locale }
|
||||||
|
|
||||||
if app_store_version_localization
|
if app_store_version_localization
|
||||||
app_store_version_localization.update(attributes: { "whats_new" => notes })
|
app_store_version_localization.update(attributes: { "whats_new" => notes })
|
||||||
else
|
else
|
||||||
UI.error("No localization found for locale #{locale}")
|
UI.error("No localization found for locale #{locale}")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
33
ios/export_options.plist
Normal file
33
ios/export_options.plist
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "https://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||||
|
<plist version="1.0">
|
||||||
|
<dict>
|
||||||
|
<key>method</key>
|
||||||
|
<string>app-store</string>
|
||||||
|
<key>signingStyle</key>
|
||||||
|
<string>manual</string>
|
||||||
|
<key>teamID</key>
|
||||||
|
<string>A7W54YZ4WU</string>
|
||||||
|
<key>uploadSymbols</key>
|
||||||
|
<true/>
|
||||||
|
<key>compileBitcode</key>
|
||||||
|
<false/>
|
||||||
|
<key>thinning</key>
|
||||||
|
<string>none</string>
|
||||||
|
<key>destination</key>
|
||||||
|
<string>export</string>
|
||||||
|
<key>provisioningProfiles</key>
|
||||||
|
<dict>
|
||||||
|
<key>io.bluewallet.bluewallet</key>
|
||||||
|
<string>match AppStore io.bluewallet.bluewallet</string>
|
||||||
|
<key>io.bluewallet.bluewallet.watch</key>
|
||||||
|
<string>match AppStore io.bluewallet.bluewallet.watch</string>
|
||||||
|
<key>io.bluewallet.bluewallet.watch.extension</key>
|
||||||
|
<string>match AppStore io.bluewallet.bluewallet.watch.extension</string>
|
||||||
|
<key>io.bluewallet.bluewallet.Stickers</key>
|
||||||
|
<string>match AppStore io.bluewallet.bluewallet.Stickers</string>
|
||||||
|
<key>io.bluewallet.bluewallet.MarketWidget</key>
|
||||||
|
<string>match AppStore io.bluewallet.bluewallet.MarketWidget</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
</plist>
|
Loading…
Reference in New Issue
Block a user