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:
|
||||
new_build_number: ${{ steps.generate_build_number.outputs.build_number }}
|
||||
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 }}
|
||||
env:
|
||||
APPLE_ID: ${{ secrets.APPLE_ID }}
|
||||
steps:
|
||||
- name: Checkout project
|
||||
- name: Checkout Project
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0 # Fetches all history
|
||||
|
||||
|
||||
- name: Specify node version
|
||||
|
||||
- name: Specify Node.js Version
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 20
|
||||
|
||||
|
||||
- uses: maxim-lobanov/setup-xcode@v1
|
||||
with:
|
||||
xcode-version: 16.0
|
||||
|
||||
- name: Set up Ruby
|
||||
|
||||
- name: Set Up Ruby
|
||||
uses: ruby/setup-ruby@v1
|
||||
with:
|
||||
ruby-version: 3.1.6
|
||||
bundler-cache: true
|
||||
|
||||
- name: Install dependencies with Bundler
|
||||
|
||||
- name: Install Dependencies with Bundler
|
||||
run: |
|
||||
bundle config path vendor/bundle
|
||||
bundle install --jobs 4 --retry 3 --quiet
|
||||
|
||||
- name: Install node_modules
|
||||
- name: Install Node Modules
|
||||
run: npm install --omit=dev --yes
|
||||
|
||||
- name: Install CocoaPods Dependencies
|
||||
run: |
|
||||
bundle exec fastlane ios install_pods
|
||||
|
||||
- name: Cache CocoaPods Pods
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: ios/Pods
|
||||
key: ${{ runner.os }}-pods-${{ hashFiles('**/Podfile.lock') }}
|
||||
- name: Display release-notes.txt
|
||||
run: cat release-notes.txt
|
||||
restore-keys: |
|
||||
${{ runner.os }}-pods-
|
||||
|
||||
- name: Get Latest Commit Message
|
||||
id: get_latest_commit_message
|
||||
run: |
|
||||
LATEST_COMMIT_MESSAGE=$(git log -1 --pretty=format:"%s")
|
||||
echo "LATEST_COMMIT_MESSAGE=${LATEST_COMMIT_MESSAGE}" >> $GITHUB_ENV
|
||||
echo "::set-output name=commit_message::$LATEST_COMMIT_MESSAGE"
|
||||
- name: Set up Git Authentication
|
||||
echo "commit_message=$LATEST_COMMIT_MESSAGE" >> $GITHUB_OUTPUT
|
||||
|
||||
- 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:
|
||||
ACCESS_TOKEN: ${{ secrets.GIT_ACCESS_TOKEN }}
|
||||
run: |
|
||||
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)"
|
||||
|
||||
- name: Create Temporary Keychain
|
||||
run: bundle exec fastlane ios create_temp_keychain
|
||||
env:
|
||||
KEYCHAIN_PASSWORD: ${{ secrets.KEYCHAIN_PASSWORD }}
|
||||
|
||||
- name: Setup Provisioning Profiles
|
||||
env:
|
||||
MATCH_PASSWORD: ${{ secrets.MATCH_PASSWORD }}
|
||||
@ -86,14 +109,16 @@ jobs:
|
||||
KEYCHAIN_PASSWORD: ${{ secrets.KEYCHAIN_PASSWORD }}
|
||||
run: |
|
||||
bundle exec fastlane ios setup_provisioning_profiles
|
||||
|
||||
- name: Cache Provisioning Profiles
|
||||
id: cache_provisioning_profiles
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: ~/Library/MobileDevice/Provisioning Profiles
|
||||
path: ~/Library/MobileDevice/Provisioning\ Profiles
|
||||
key: ${{ runner.os }}-provisioning-profiles-${{ github.sha }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-provisioning-profiles-
|
||||
|
||||
- name: Check Cache Status for Provisioning Profiles
|
||||
run: |
|
||||
if [ -n "${{ steps.cache_provisioning_profiles.outputs.cache-hit }}" ]; then
|
||||
@ -101,41 +126,36 @@ jobs:
|
||||
else
|
||||
echo "No cache found for provisioning profiles. A new cache will be created."
|
||||
fi
|
||||
|
||||
- name: Verify Provisioning Profiles Exist
|
||||
run: |
|
||||
if [ -d "~/Library/MobileDevice/Provisioning Profiles" ]; then
|
||||
echo "Provisioning profiles are available in the cache."
|
||||
ls -la ~/Library/MobileDevice/Provisioning Profiles
|
||||
ls -la ~/Library/MobileDevice/Provisioning\ Profiles
|
||||
else
|
||||
echo "Provisioning profiles directory does not exist."
|
||||
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
|
||||
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
|
||||
if: success()
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
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:
|
||||
needs: build
|
||||
runs-on: macos-latest
|
||||
@ -146,13 +166,15 @@ jobs:
|
||||
PROJECT_VERSION: ${{ needs.build.outputs.project_version }}
|
||||
LATEST_COMMIT_MESSAGE: ${{ needs.build.outputs.latest_commit_message }}
|
||||
steps:
|
||||
- name: Checkout project
|
||||
- name: Checkout Project
|
||||
uses: actions/checkout@v4
|
||||
- name: Set up Ruby
|
||||
|
||||
- name: Set Up Ruby
|
||||
uses: ruby/setup-ruby@v1
|
||||
with:
|
||||
ruby-version: 3.1.6
|
||||
bundler-cache: true
|
||||
|
||||
- name: Cache Ruby Gems
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
@ -160,19 +182,43 @@ jobs:
|
||||
key: ${{ runner.os }}-gems-${{ hashFiles('**/Gemfile.lock') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-gems-
|
||||
- name: Install dependencies with Bundler
|
||||
|
||||
- name: Install Dependencies with Bundler
|
||||
run: |
|
||||
bundle config path vendor/bundle
|
||||
bundle install --jobs 4 --retry 3 --quiet
|
||||
|
||||
- name: Download IPA from Artifact
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
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
|
||||
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
|
||||
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
|
||||
MATCH_PASSWORD: ${{ secrets.MATCH_PASSWORD }}
|
||||
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_ISSUER_ID: ${{ secrets.APP_STORE_CONNECT_API_KEY_ISSUER_ID }}
|
||||
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
|
||||
if: success() && github.event_name == 'pull_request'
|
||||
uses: actions/github-script@v6
|
||||
@ -199,4 +246,4 @@ jobs:
|
||||
...repo,
|
||||
issue_number: prNumber,
|
||||
body: message,
|
||||
});
|
||||
});
|
39
Gemfile.lock
39
Gemfile.lock
@ -24,20 +24,20 @@ GEM
|
||||
artifactory (3.0.17)
|
||||
atomos (0.1.3)
|
||||
aws-eventstream (1.3.0)
|
||||
aws-partitions (1.973.0)
|
||||
aws-sdk-core (3.204.0)
|
||||
aws-partitions (1.989.0)
|
||||
aws-sdk-core (3.209.1)
|
||||
aws-eventstream (~> 1, >= 1.3.0)
|
||||
aws-partitions (~> 1, >= 1.651.0)
|
||||
aws-sigv4 (~> 1.9)
|
||||
jmespath (~> 1, >= 1.6.1)
|
||||
aws-sdk-kms (1.90.0)
|
||||
aws-sdk-core (~> 3, >= 3.203.0)
|
||||
aws-sdk-kms (1.94.0)
|
||||
aws-sdk-core (~> 3, >= 3.207.0)
|
||||
aws-sigv4 (~> 1.5)
|
||||
aws-sdk-s3 (1.161.0)
|
||||
aws-sdk-core (~> 3, >= 3.203.0)
|
||||
aws-sdk-s3 (1.167.0)
|
||||
aws-sdk-core (~> 3, >= 3.207.0)
|
||||
aws-sdk-kms (~> 1)
|
||||
aws-sigv4 (~> 1.5)
|
||||
aws-sigv4 (1.9.1)
|
||||
aws-sigv4 (1.10.0)
|
||||
aws-eventstream (~> 1, >= 1.0.2)
|
||||
babosa (1.0.4)
|
||||
base64 (0.2.0)
|
||||
@ -96,8 +96,8 @@ GEM
|
||||
escape (0.0.4)
|
||||
ethon (0.16.0)
|
||||
ffi (>= 1.15.0)
|
||||
excon (0.111.0)
|
||||
faraday (1.10.3)
|
||||
excon (0.112.0)
|
||||
faraday (1.10.4)
|
||||
faraday-em_http (~> 1.0)
|
||||
faraday-em_synchrony (~> 1.0)
|
||||
faraday-excon (~> 1.1)
|
||||
@ -123,10 +123,10 @@ GEM
|
||||
faraday-patron (1.0.0)
|
||||
faraday-rack (1.0.0)
|
||||
faraday-retry (1.0.3)
|
||||
faraday_middleware (1.2.0)
|
||||
faraday_middleware (1.2.1)
|
||||
faraday (~> 1.0)
|
||||
fastimage (2.3.1)
|
||||
fastlane (2.222.0)
|
||||
fastlane (2.224.0)
|
||||
CFPropertyList (>= 2.3, < 4.0.0)
|
||||
addressable (>= 2.8, < 3.0.0)
|
||||
artifactory (~> 3.0)
|
||||
@ -214,16 +214,17 @@ GEM
|
||||
http-cookie (1.0.7)
|
||||
domain_name (~> 0.5)
|
||||
httpclient (2.8.3)
|
||||
i18n (1.14.5)
|
||||
i18n (1.14.6)
|
||||
concurrent-ruby (~> 1.0)
|
||||
jmespath (1.6.2)
|
||||
json (2.7.2)
|
||||
jwt (2.8.2)
|
||||
jwt (2.9.3)
|
||||
base64
|
||||
logger (1.6.1)
|
||||
mime-types (3.5.2)
|
||||
mime-types (3.6.0)
|
||||
logger
|
||||
mime-types-data (~> 3.2015)
|
||||
mime-types-data (3.2024.0903)
|
||||
mime-types-data (3.2024.1001)
|
||||
mini_magick (4.13.2)
|
||||
mini_mime (1.1.5)
|
||||
minitest (5.25.1)
|
||||
@ -250,7 +251,7 @@ GEM
|
||||
mime-types (>= 1.16, < 4.0)
|
||||
netrc (~> 0.8)
|
||||
retriable (3.1.2)
|
||||
rexml (3.3.7)
|
||||
rexml (3.3.8)
|
||||
rouge (2.0.7)
|
||||
ruby-macho (2.5.1)
|
||||
ruby2_keywords (0.0.5)
|
||||
@ -278,15 +279,15 @@ GEM
|
||||
tzinfo (2.0.6)
|
||||
concurrent-ruby (~> 1.0)
|
||||
uber (0.1.0)
|
||||
unicode-display_width (2.5.0)
|
||||
unicode-display_width (2.6.0)
|
||||
word_wrap (1.0.0)
|
||||
xcodeproj (1.25.0)
|
||||
xcodeproj (1.25.1)
|
||||
CFPropertyList (>= 2.3.3, < 4.0)
|
||||
atomos (~> 0.1.3)
|
||||
claide (>= 1.0.2, < 2.0)
|
||||
colored2 (~> 3.1)
|
||||
nanaimo (~> 0.3.0)
|
||||
rexml (>= 3.3.2, < 4.0)
|
||||
rexml (>= 3.3.6, < 4.0)
|
||||
xcpretty (0.3.0)
|
||||
rouge (~> 2.0.7)
|
||||
xcpretty-travis-formatter (1.0.1)
|
||||
|
@ -1,75 +1,75 @@
|
||||
# Define app identifiers once for reuse across lanes
|
||||
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
|
||||
|
||||
default_platform(:android)
|
||||
project_root = File.expand_path("..", __dir__)
|
||||
|
||||
# ===========================
|
||||
# Android Lanes
|
||||
# ===========================
|
||||
|
||||
platform :android do
|
||||
|
||||
desc "Prepare the keystore file"
|
||||
lane :prepare_keystore do
|
||||
Dir.chdir(project_root) do
|
||||
keystore_file_hex = ENV['KEYSTORE_FILE_HEX']
|
||||
UI.user_error!("KEYSTORE_FILE_HEX environment variable is missing") if keystore_file_hex.nil?
|
||||
keystore_file_hex = ENV['KEYSTORE_FILE_HEX']
|
||||
UI.user_error!("KEYSTORE_FILE_HEX environment variable is missing") if keystore_file_hex.nil?
|
||||
|
||||
Dir.chdir("android") do
|
||||
UI.message("Creating keystore hex file...")
|
||||
Dir.chdir("android") do
|
||||
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?
|
||||
end
|
||||
UI.message("Keystore created successfully.")
|
||||
|
||||
File.delete("bluewallet-release-key.keystore.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?
|
||||
end
|
||||
UI.message("Keystore created successfully.")
|
||||
|
||||
File.delete("bluewallet-release-key.keystore.hex")
|
||||
end
|
||||
end
|
||||
|
||||
desc "Update version, build number, and sign APK"
|
||||
lane :update_version_build_and_sign_apk do
|
||||
Dir.chdir(project_root) do
|
||||
build_number = ENV['BUILD_NUMBER']
|
||||
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
|
||||
|
||||
# Manually update the versionCode in build.gradle
|
||||
|
||||
# Update versionCode in build.gradle
|
||||
UI.message("Updating versionCode in build.gradle to #{build_number}...")
|
||||
build_gradle_path = "android/app/build.gradle"
|
||||
build_gradle_contents = File.read(build_gradle_path)
|
||||
new_build_gradle_contents = build_gradle_contents.gsub(/versionCode\s+\d+/, "versionCode #{build_number}")
|
||||
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(/[\/\\:?*"<>|]/, '_')
|
||||
if branch_name.nil? || branch_name.empty?
|
||||
branch_name = 'master'
|
||||
end
|
||||
|
||||
# Append branch name only if it's not 'master'
|
||||
if branch_name != 'master'
|
||||
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
|
||||
branch_name = 'master' if branch_name.nil? || branch_name.empty?
|
||||
|
||||
# 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"
|
||||
|
||||
# Build APK
|
||||
Dir.chdir("android") do
|
||||
UI.message("Building APK...")
|
||||
gradle(
|
||||
task: "assembleRelease",
|
||||
project_dir: "android"
|
||||
)
|
||||
gradle(task: "assembleRelease", project_dir: "android")
|
||||
UI.message("APK build completed.")
|
||||
|
||||
# Define the output paths
|
||||
|
||||
# Define paths
|
||||
unsigned_apk_path = "app/build/outputs/apk/release/app-release-unsigned.apk"
|
||||
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)
|
||||
UI.message("Renaming APK to #{signed_apk_name}...")
|
||||
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}")
|
||||
next
|
||||
end
|
||||
|
||||
# Sign the APK using apksigner
|
||||
|
||||
# Sign APK
|
||||
UI.message("Signing APK with 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}")
|
||||
@ -91,33 +91,32 @@ platform :android do
|
||||
desc "Upload APK to BrowserStack and post result as PR comment"
|
||||
lane :upload_to_browserstack_and_comment do
|
||||
Dir.chdir(project_root) do
|
||||
# Fetch the APK path from environment variables
|
||||
# Determine APK path
|
||||
apk_path = ENV['APK_PATH']
|
||||
|
||||
# Attempt to find the APK if not provided
|
||||
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
|
||||
UI.user_error!("No APK file found") if apk_path.nil? || apk_path.empty?
|
||||
end
|
||||
|
||||
|
||||
# Upload to BrowserStack
|
||||
UI.message("Uploading APK to BrowserStack: #{apk_path}...")
|
||||
upload_to_browserstack_app_live(
|
||||
file_path: apk_path,
|
||||
browserstack_username: ENV['BROWSERSTACK_USERNAME'],
|
||||
browserstack_access_key: ENV['BROWSERSTACK_ACCESS_KEY']
|
||||
)
|
||||
|
||||
# Extract the BrowserStack URL from the output
|
||||
|
||||
# Extract BrowserStack URL
|
||||
app_url = ENV['BROWSERSTACK_LIVE_APP_ID']
|
||||
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_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://', '')
|
||||
pr_number = ENV['GITHUB_PR_NUMBER']
|
||||
|
||||
|
||||
comment = <<~COMMENT
|
||||
### 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 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)
|
||||
|
||||
|
||||
- [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 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)
|
||||
|
||||
|
||||
**Filename**: [#{apk_filename}](#{apk_download_url})
|
||||
**BrowserStack App URL**: #{app_url}
|
||||
COMMENT
|
||||
|
||||
|
||||
# Post PR comment if PR number is available
|
||||
if pr_number
|
||||
begin
|
||||
sh("GH_TOKEN=#{ENV['GH_TOKEN']} gh pr comment #{pr_number} --body '#{comment}'")
|
||||
@ -149,36 +149,34 @@ platform :android do
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
# ===========================
|
||||
# iOS Lanes
|
||||
# ===========================
|
||||
|
||||
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"
|
||||
lane :register_devices_from_txt do
|
||||
UI.message("Registering new devices from 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(
|
||||
devices_file: csv_path
|
||||
)
|
||||
|
||||
UI.message("Devices registered successfully.")
|
||||
|
||||
# Update provisioning profiles for all app identifiers
|
||||
app_identifiers.each do |app_identifier|
|
||||
match(
|
||||
type: "development",
|
||||
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,
|
||||
clone_branch_directly: true
|
||||
)
|
||||
@ -190,7 +188,7 @@ platform :ios do
|
||||
desc "Create a temporary keychain"
|
||||
lane :create_temp_keychain do
|
||||
UI.message("Creating a temporary keychain...")
|
||||
|
||||
|
||||
create_keychain(
|
||||
name: "temp_keychain",
|
||||
password: ENV["KEYCHAIN_PASSWORD"],
|
||||
@ -199,32 +197,26 @@ platform :ios do
|
||||
timeout: 3600,
|
||||
lock_when_sleeps: true
|
||||
)
|
||||
|
||||
|
||||
UI.message("Temporary keychain created successfully.")
|
||||
end
|
||||
|
||||
desc "Synchronize certificates and provisioning profiles"
|
||||
lane :setup_provisioning_profiles do |options|
|
||||
lane :setup_provisioning_profiles do
|
||||
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
|
||||
|
||||
# Remove local master branch if it exists (Exit status: 128 - 'fatal: a branch named 'master' already exists')
|
||||
platform = "ios"
|
||||
|
||||
# Remove local master branch if it exists to avoid conflicts
|
||||
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(
|
||||
git_basic_authorization: ENV["GIT_ACCESS_TOKEN"],
|
||||
git_url: ENV["GIT_URL"],
|
||||
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,
|
||||
app_identifier: app_identifier,
|
||||
team_id: ENV["ITC_TEAM_ID"],
|
||||
@ -255,7 +247,6 @@ platform :ios do
|
||||
app_identifier: app_identifiers,
|
||||
readonly: true,
|
||||
clone_branch_directly: true
|
||||
|
||||
)
|
||||
end
|
||||
|
||||
@ -306,94 +297,116 @@ platform :ios do
|
||||
cocoapods(podfile: "ios/Podfile")
|
||||
end
|
||||
|
||||
desc "Build the application"
|
||||
lane :build_app_lane do
|
||||
UI.message("Building the application...")
|
||||
build_app(
|
||||
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
|
||||
desc "Upload IPA to TestFlight"
|
||||
lane :upload_to_testflight_lane do
|
||||
ipa_path = ENV['IPA_OUTPUT_PATH']
|
||||
changelog = ENV["LATEST_COMMIT_MESSAGE"]
|
||||
|
||||
output_name: "BlueWallet_#{ENV['PROJECT_VERSION']}_#{ENV['NEW_BUILD_NUMBER']}.ipa",
|
||||
buildlog_path: "./build_logs"
|
||||
)
|
||||
# Check if IPA exists before proceeding
|
||||
if ipa_path.nil? || ipa_path.empty? || !File.exist?(ipa_path)
|
||||
UI.user_error!("IPA file not found at path: #{ipa_path}")
|
||||
end
|
||||
|
||||
desc "Upload to TestFlight without Processing Wait"
|
||||
lane :upload_to_testflight_lane do
|
||||
attempts = 0
|
||||
max_attempts = 3
|
||||
UI.message("Uploading IPA to TestFlight from path: #{ipa_path}")
|
||||
|
||||
upload_to_testflight(
|
||||
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
|
||||
UI.message("Uploading to TestFlight without processing wait...")
|
||||
changelog = ENV["LATEST_COMMIT_MESSAGE"]
|
||||
ipa_path = "./BlueWallet_#{ENV['PROJECT_VERSION']}_#{ENV['NEW_BUILD_NUMBER']}.ipa"
|
||||
|
||||
upload_to_testflight(
|
||||
api_key_path: "./appstore_api_key.json",
|
||||
ipa: ipa_path,
|
||||
skip_waiting_for_build_processing: true, # Do not wait for processing
|
||||
changelog: changelog
|
||||
build_ios_app(
|
||||
scheme: "BlueWallet",
|
||||
workspace: workspace_path,
|
||||
export_method: "app-store",
|
||||
include_bitcode: false,
|
||||
configuration: "Release",
|
||||
skip_profile_detection: false,
|
||||
include_symbols: true,
|
||||
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
|
||||
attempts += 1
|
||||
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
|
||||
rescue => e
|
||||
UI.user_error!("build_ios_app failed: #{e.message}")
|
||||
end
|
||||
|
||||
build_app_lane
|
||||
upload_to_testflight_lane
|
||||
# Use File.join to construct paths without extra slashes
|
||||
ipa_path = lane_context[SharedValues::IPA_OUTPUT_PATH]
|
||||
|
||||
# Clean up and delete the temporary keychain
|
||||
delete_keychain(name: "temp_keychain")
|
||||
if ipa_path && File.exist?(ipa_path)
|
||||
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
|
||||
already_built_flag = ".already_built_#{last_commit[:sha]}"
|
||||
File.write(already_built_flag, Time.now.to_s)
|
||||
# ===========================
|
||||
# Global Lanes
|
||||
# ===========================
|
||||
|
||||
|
||||
|
||||
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
|
||||
|
||||
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|
|
||||
require 'spaceship'
|
||||
|
||||
@ -402,16 +415,13 @@ lane :update_release_notes do |options|
|
||||
|
||||
app = Spaceship::ConnectAPI::App.find(app_identifiers.first)
|
||||
|
||||
unless app
|
||||
UI.user_error!("Could not find the app with identifier: #{app_identifiers.first}")
|
||||
end
|
||||
UI.user_error!("Could not find the app with identifier: #{app_identifiers.first}") unless app
|
||||
|
||||
# Retry logic for fetching or creating the edit version
|
||||
retries = 5
|
||||
begin
|
||||
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?
|
||||
UI.message("No version in 'Prepare for Submission' found. Creating a new version...")
|
||||
latest_version = app.get_latest_version(platform: Spaceship::ConnectAPI::Platform::IOS)
|
||||
@ -436,12 +446,11 @@ lane :update_release_notes do |options|
|
||||
# Extract existing metadata
|
||||
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)
|
||||
|
||||
# Define valid language codes and filter them based on enabled locales
|
||||
# Define release notes
|
||||
release_notes_text = options[:release_notes]
|
||||
|
||||
if release_notes_text.nil? || release_notes_text.strip.empty?
|
||||
release_notes_path = "../../release-notes.txt"
|
||||
unless File.exist?(release_notes_path)
|
||||
@ -451,6 +460,7 @@ lane :update_release_notes do |options|
|
||||
release_notes_text = File.read(release_notes_path)
|
||||
end
|
||||
|
||||
# Define localized release notes
|
||||
localized_release_notes = {
|
||||
'en-US' => release_notes_text, # English (U.S.) - Primary
|
||||
'ar-SA' => release_notes_text, # Arabic
|
||||
@ -479,7 +489,7 @@ lane :update_release_notes do |options|
|
||||
'th' => release_notes_text, # Thai
|
||||
}.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:")
|
||||
localized_release_notes.each do |locale, notes|
|
||||
UI.message("Locale: #{locale} - Notes: #{notes}")
|
||||
@ -487,21 +497,17 @@ lane :update_release_notes do |options|
|
||||
|
||||
unless options[:force_yes]
|
||||
confirm = UI.confirm("Do you want to proceed with these release notes updates?")
|
||||
unless confirm
|
||||
UI.user_error!("User aborted the lane.")
|
||||
end
|
||||
UI.user_error!("User aborted the lane.") unless confirm
|
||||
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|
|
||||
app_store_version_localization = localized_metadata.find { |loc| loc.locale == locale }
|
||||
|
||||
if app_store_version_localization
|
||||
app_store_version_localization.update(attributes: { "whats_new" => notes })
|
||||
else
|
||||
UI.error("No localization found for locale #{locale}")
|
||||
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