feat/prepare-android-pipeline-for-rc #24

Merged
malo merged 11 commits from feat/prepare-android-pipeline-for-rc into main 2023-08-08 15:59:34 +00:00
5 changed files with 79 additions and 62 deletions

View File

@ -22,7 +22,7 @@ To use these actions, you need to add some information to your Android folder so
In your android folder, place a compressed folder containing:
- The application's signing key (in the .jks format). If this is a new application, you can generate this key with the following command:
* The application's signing key (in the .jks format). If this is a new application, you can generate this key with the following command:
```shel
keytool -genkey -v -keystore key_store_name.keystore -alias key_alias_name -keyalg RSA -keysize 2048 -validity 10000
@ -30,29 +30,39 @@ keytool -genkey -v -keystore key_store_name.keystore -alias key_alias_name -keya
During the execution of the above command, you will be prompted to provide a password for your key. Make sure to remember this password, as you will need it later.
- The key.properties file containing sensitive data for using the signing key, such as the path of the key or the password. If this file does not exist yet, create it and fill in the following fields:
* The key.properties file containing sensitive data for using the signing key, such as the path of the key or the password. If this file does not exist yet, create it and fill in the following fields:
- `storeFile`: the relative or absolute path to the key storage file that contains the private key used to sign the Android application.
- `storePassword`: the password used to access the key storage file.
- `keyAlias`: the alias of the key used to sign the application.
- `keyPassword`: the password used to access the key.
+ `storeFile`: the relative or absolute path to the key storage file that contains the private key used to sign the Android application.
+ `storePassword`: the password used to access the key storage file.
+ `keyAlias`: the alias of the key used to sign the application.
+ `keyPassword`: the password used to access the key.
- The credentials in JSON format to allow the fastlane action to connect to the Google Play Store console and upload the new build. To retrieve them, follow these steps:
* The credentials in JSON format to allow the fastlane action to connect to the Google Play Store console and upload the new build. To retrieve them, follow these steps:
- Go to your Google Play Store console.
- In the Settings menu, select `API access`, then click `Create Service Account`
- Navigate to the provided Google Developers Console link in the dialog
- Click `Create Service Account` at the top of the Google Developers Console
- Provide the required details, then click `Create`
- Click `Select a role`, select `Service Accounts`, then click `Service Account User`
- In the Service Accounts dashboard, navigate to the Actions column, tap the menu for the service account that you created, then click `Create Key`
- Select JSON as the key type, then click `Save`
- Back on the Google Play Console, click `Done` to close the dialog
- Click on `Grant Access` for the newly added service account
- Make sure that the role of this service account has the permission to upload builds
- Click `Add User` to close the dialog
+ Go to your Google Play Store console.
+ In the Settings menu, select `API access`, then click `Create Service Account`
+ Navigate to the provided Google Developers Console link in the dialog
+ Click `Create Service Account` at the top of the Google Developers Console
+ Provide the required details, then click `Create`
+ Click `Select a role`, select `Service Accounts`, then click `Service Account User`
+ In the Service Accounts dashboard, navigate to the Actions column, tap the menu for the service account that you created, then click `Create Key`
+ Select JSON as the key type, then click `Save`
+ Back on the Google Play Console, click `Done` to close the dialog
+ Click on `Grant Access` for the newly added service account
+ Make sure that the role of this service account has the permission to upload builds
+ Click `Add User` to close the dialog
Once you have all three elements in your folder, it's time to encrypt them. Indeed, this folder contains elements that are too sensitive to be referenced on git. Compress the folder, place the compressed folder in the android folder of your Flutter project, and execute the following command:
Once you have all three elements in your folder, it's time to encrypt them. Indeed, this folder contains elements that are too sensitive to be referenced on git.
Place them in a folder named `android_keys` and compress it using the following command:
```shell
jar cfvM android_keys.zip android_keys
```
> The plugin will use `jar xvf android/android_keys.zip && mv android/android_keys/* android/` to extract the secret files.
Then, encrypt the compressed folder using GPG.
```shell
gpg --quiet --batch --yes --symmetric --passphrase="<android-key-passphrase>" --output android/android_keys.zip.gpg android/android_keys.zip

View File

@ -14,24 +14,11 @@ module Fastlane
# Decrypt the keys archive and Extract the keys archive
Helper::AndroidCdHelper.decrypt_android_keys('.')
UI.message("👉🏼 Credentials decrypted")
# Clean the project before building
other_action.gradle(task: "clean")
# Set the build number based on the number of commits
build_number = other_action.number_of_commits
# Build the Android App Bundle
other_action.gradle(
task: "bundle",
build_type: "Release",
print_command: true,
project_dir: './',
properties: {
"android.injected.version.code" => build_number
}
other_action.flutter_build(
build: 'appbundle'
)
UI.message("👉🏼 App built")
@ -44,15 +31,12 @@ module Fastlane
skip_upload_metadata: true,
skip_upload_images: true,
skip_upload_screenshots: true,
release_status: "draft",
version_code: build_number
release_status: "draft"
)
# Delete artifacts files
artifacts = ['android_keys.zip', 'key.jks', 'key.properties', 'service_account_key.json']
artifacts.each do |file|
File.delete(file) if File.exist?(file)
end
Helper::AndroidCdHelper.delete_artifacts(artifacts)
UI.success('🍺 Successfully build & deploy appbundle to Google Play Store')
end

View File

@ -26,6 +26,13 @@ module Fastlane
str_variable = variable.strip if variable.class.to_s == "String"
variable && !(str_variable.nil? || str_variable.empty?)
end
# Delete built files
def self.delete_artifacts(artifacts)
artifacts.each do |file|
File.delete(file) if File.exist?(file)
end
end
end
end
end

View File

@ -21,25 +21,19 @@ module Fastlane
# Decrypt the keys archive and Extract the keys archive
Helper::IosCdHelper.decrypt_ios_keys('.')
UI.message("👉🏼 Credentials decrypted.")
UI.message("🍺 Credentials decrypted.")
# Retrieve credentials
creds = Helper::IosCdHelper.parse_ios_credentials('.')
UI.message("👉🏼 Credentials parsed.")
UI.message("🍺 Credentials parsed.")
# Delete decrypted artifacts
artifacts = ['ios_keys.zip', 'ios_credentials.json']
artifacts.each do |file|
File.delete(file) if File.exist?(file)
end
Helper::IosCdHelper.delete_artifacts(artifacts)
# Check credentials
required_fields = ['developer_app_id', 'username', 'developer_app_identifier', 'app_identifier_extensions', 'apple_issuer_id', 'apple_key_id', 'team_id', 'team_name', 'apple_key_content', 'git_url', 'git_basic_authorization', 'provisioning_profiles', 'temp_keychain_user', 'temp_keychain_password']
missing_fields = required_fields - creds.keys
unless missing_fields.empty?
raise ArgumentError, "❌ missing keys in credential json file : #{missing_fields}"
end
Helper::IosCdHelper.check_required_fields(required_fields, creds.keys)
# Delete keychain if existing
if File.exist?(File.expand_path("~/Library/Keychains/#{name}-db"))
@ -55,7 +49,7 @@ module Fastlane
unlock: false,
timeout: 0
)
UI.message("👉🏼 New keychain created")
UI.message("🍺 New keychain created")
# Obtain App Store Connect API key
api_key = other_action.app_store_connect_api_key(
@ -65,7 +59,7 @@ module Fastlane
duration: 500,
in_house: false
)
UI.message("👉🏼 API Key formated")
UI.message("🍺 API Key formated")
last_testflight_build_number =
other_action.latest_testflight_build_number(
@ -82,7 +76,7 @@ module Fastlane
build_number: last_testflight_build_number,
xcodeproj: "Runner.xcodeproj"
)
UI.message("👉🏼 Build number incremented")
UI.message("🍺 Build number incremented")
# Install Cocoapods
other_action.cocoapods(
@ -91,7 +85,7 @@ module Fastlane
integrate: true,
podfile: "./Podfile"
)
UI.message("👉🏼 Pod got")
UI.message("🍺 Pod got")
# Set up code signing using match
# Configures and runs `match` which manages code signing certificates and provisioning profiles for the project.
@ -105,14 +99,13 @@ module Fastlane
git_basic_authorization: Base64.strict_encode64(creds['git_basic_authorization']),
keychain_name: creds['temp_keychain_user'].to_s,
keychain_password: creds['temp_keychain_password'].to_s,
git_url: creds['git_url'].to_s,
username: creds['username'].to_s,
team_id: creds['team_id'].to_s,
team_name: creds['team_name'].to_s,
git_url: creds['git_url'].to_s,
storage_mode: "git"
)
UI.message("👉🏼 App signed")
UI.message("🍺 App signed")
# Build and export app using Gym
# Builds and packages an iOS app or framework for distribution to the App Store, TestFlight, or Enterprise distribution.
@ -124,7 +117,7 @@ module Fastlane
provisioningProfiles: creds['provisioning_profiles']
}
)
UI.message("👉🏼 App built")
UI.message("🍺 App built")
# Upload build to App Store Connect using Pilot
other_action.pilot(
@ -147,9 +140,7 @@ module Fastlane
# Delete build artifacts
artifacts = ['Runner.app.dSYM.zip', 'Runner.ipa']
artifacts.each do |file|
File.delete(file) if File.exist?(file)
end
Helper::IosCdHelper.delete_artifacts(artifacts)
end
def self.description

View File

@ -42,6 +42,31 @@ module Fastlane
puts("json file doesn't exist")
end
end
# Check json fields
def self.check_required_fields(required_fields, json)
missing_fields = required_fields - json
unless missing_fields.empty?
raise ArgumentError, "❌ missing keys in credential json file : #{missing_fields}"
end
end
# Check if set of environment variables are defined
def self.check_environment_variables(variables)
variables.each do |variable|
unless ENV.key?(variable)
raise "❌ The environment variable '#{variable}' is not defined."
end
end
end
# Delete built files
def self.delete_artifacts(artifacts)
artifacts.each do |file|
File.delete(file) if File.exist?(file)
end
end
end
end
end