diff --git a/apps/docs/src/content/docs/packages/plugin-fastlane.mdx b/apps/docs/src/content/docs/packages/plugin-fastlane.mdx index 351255e9c5..fbafb5c62a 100644 --- a/apps/docs/src/content/docs/packages/plugin-fastlane.mdx +++ b/apps/docs/src/content/docs/packages/plugin-fastlane.mdx @@ -82,9 +82,9 @@ For more detailed guidance and information, please refer to the [Flagship Code C ### Build Configuration -Depending on the plugin, there might be additional configuration required. Regarding the `plugin-fastlane`, there's an optional additional build configuration feature available to extend your Fastlane setup. Presently, the only extension supported is for AppCenter uploads. Providing the AppCenter configuration will prompt the plugin to update your Fastlane setup accordingly. +Depending on the plugin, there might be additional configuration required. Regarding the `plugin-fastlane`, there's an optional additional build configuration feature available to extend your Fastlane setup. Presently, the only extensions supported are for uploads to AppCenter and/or Firebase App Distribution. Providing configuration for either services will prompt the plugin to update your Fastlane setup accordingly. -For the purpose of illustration, the `build.internal.ts` configuration shall be presented as follows if you want to include AppCenter uploads: +For the purpose of illustration, the `build.internal.ts` configuration shall be presented as follows if you want to include both AppCenter and Firebase App Distribution uploads: ```ts title="build.internal.ts" import { defineBuild } from "@brandingbrand/code-cli-kit"; @@ -108,6 +108,10 @@ export default defineBuild({ destinationType: "group", destinations: ["iat"], }, + firebase: { + appId: '1234', + groups: ['iat'], + }, }, android: { appCenter: { @@ -116,6 +120,10 @@ export default defineBuild({ destinationType: "group", destinations: ["iat"], }, + firebase: { + appId: '4321', + groups: ['iat'], + }, }, }, }, @@ -164,6 +172,26 @@ _required_ Array of distribution destinations. +##### `codePluginFastlane.plugin.ios.firebase` + +#### `FirebaseIOS` + +###### `appId` + +**type:** `"string" + +_required_ + +The Firebase app id. + +###### `groups` + +**type:** `string[]` + +_required_ + +Array of distribution groups. + ##### `codePluginFastlane.plugin.android.appCenter` **type:** [AppCenterAndroid](#appcenterandroid) @@ -204,6 +232,26 @@ _required_ Array of distribution destinations. +##### `codePluginFastlane.plugin.android.firebase` + +#### `FirebaseAndroid` + +###### `appId` + +**type:** `"string" + +_required_ + +The Firebase app id. + +###### `groups` + +**type:** `string[]` + +_required_ + +Array of distribution groups. + :::note -If you don't need AppCenter then do not include the `codePluginFastlane` configuration. +If you don't need AppCenter or Firebase App Distribution then do not include the `codePluginFastlane` configuration. ::: diff --git a/packages/plugin-fastlane/__tests__/index.ts b/packages/plugin-fastlane/__tests__/index.ts index dfda95f509..2389a0e0f4 100644 --- a/packages/plugin-fastlane/__tests__/index.ts +++ b/packages/plugin-fastlane/__tests__/index.ts @@ -52,6 +52,26 @@ describe('plugin-fastlane', () => { }, }; + const configWithFirebase = { + ...config, + codePluginFastlane: { + plugin: { + ios: { + firebase: { + appId: '1234', + groups: ['IAT'], + }, + }, + android: { + firebase: { + appId: '4321', + groups: ['IAT'], + }, + }, + }, + }, + }; + const options = { release: false, }; @@ -97,6 +117,31 @@ describe('plugin-fastlane', () => { plugins_path = File.join(File.dirname(__FILE__), 'fastlane', 'Pluginfile') eval_gemfile(plugins_path) if File.exist?(plugins_path)`); + + expect(fastfileContent).toContain('appcenter_upload'); + expect(fastfileContent).not.toContain('firebase_app_distribution'); + }); + + it('ios with firebase config', async () => { + await plugin.ios?.(configWithFirebase, options as any); + + expect( + await fs.doesPathExist( + path.project.resolve('ios', 'fastlane', 'Fastfile'), + ), + ).toBeTruthy(); + expect( + await fs.doesPathExist( + path.project.resolve('ios', 'fastlane', 'Pluginfile'), + ), + ).toBeTruthy(); + + const fastfileContent = await fs.readFile( + path.project.resolve('ios', 'fastlane', 'Fastfile'), + 'utf-8', + ); + expect(fastfileContent).toContain('firebase_app_distribution'); + expect(fastfileContent).not.toContain('appcenter_upload'); }); it('android', async () => { @@ -111,14 +156,19 @@ eval_gemfile(plugins_path) if File.exist?(plugins_path)`); 'utf-8', ); - expect(fastfileContent).toContain(`lane :appcenter_bundle do - increment_build`); expect(fastfileContent).not.toContain('<%='); expect(fastfileContent).not.toContain('%>'); + + expect(fastfileContent).toContain('appcenter_upload'); + expect(fastfileContent).not.toContain('firebase_app_distribution'); + expect(gemfileContent).toContain(`gem 'fastlane' plugins_path = File.join(File.dirname(__FILE__), 'fastlane', 'Pluginfile') eval_gemfile(plugins_path) if File.exist?(plugins_path)`); + + expect(fastfileContent).toContain('appcenter_upload'); + expect(fastfileContent).not.toContain('firebase_app_distribution'); }); it('android bundle without increment build', async () => { @@ -151,4 +201,16 @@ eval_gemfile(plugins_path) if File.exist?(plugins_path)`); plugins_path = File.join(File.dirname(__FILE__), 'fastlane', 'Pluginfile') eval_gemfile(plugins_path) if File.exist?(plugins_path)`); }); + + it('android with firebase config', async () => { + await plugin.android?.(configWithFirebase, options as any); + + const fastfileContent = await fs.readFile( + path.project.resolve('android', 'fastlane', 'Fastfile'), + 'utf-8', + ); + + expect(fastfileContent).toContain('firebase_app_distribution'); + expect(fastfileContent).not.toContain('appcenter_upload'); + }); }); diff --git a/packages/plugin-fastlane/src/types.ts b/packages/plugin-fastlane/src/types.ts index a70f12bdfd..30ea12e618 100644 --- a/packages/plugin-fastlane/src/types.ts +++ b/packages/plugin-fastlane/src/types.ts @@ -36,6 +36,21 @@ type AppCenterIOS = { destinations: string[]; }; +/** + * Represents the configuration for Firebase App Distribution for iOS. + */ +type FirebaseIOS = { + /** + * The application id in firebase. + */ + appId: string; + + /** + * Array of testing groups + */ + groups: string[]; +}; + /** * Represents the configuration for Fastlane specific to iOS. */ @@ -44,6 +59,7 @@ type FastlaneIOS = { * Configuration for App Center for iOS. */ appCenter?: AppCenterIOS; + firebase?: FirebaseIOS; }; /** @@ -71,6 +87,21 @@ type AppCenterAndroid = { destinations: string[]; }; +/** + * Represents the configuration for Firebase App Distribution for Android. + */ +type FirebaseAndroid = { + /** + * The application id in firebase. + */ + appId: string; + + /** + * Array of testing groups + */ + groups: string[]; +}; + /** * Represents the configuration for Fastlane specific to Android. */ @@ -79,4 +110,5 @@ type FastlaneAndroid = { * Configuration for App Center for Android. */ appCenter?: AppCenterAndroid; + firebase?: FirebaseAndroid; }; diff --git a/packages/plugin-fastlane/template/android/fastlane/Fastfile b/packages/plugin-fastlane/template/android/fastlane/Fastfile index 596599aa23..563403a830 100644 --- a/packages/plugin-fastlane/template/android/fastlane/Fastfile +++ b/packages/plugin-fastlane/template/android/fastlane/Fastfile @@ -31,6 +31,37 @@ lane :increment_build do end <% } -%> +lane :increment_build_appcenter do +<% if(codePluginFastlane.plugin && codePluginFastlane.plugin.android && codePluginFastlane.plugin.android.appCenter) { -%> + increment_build +<% } else { -%> + UI.user_error!("Fastlane: Tried to increment build number with appcenter but no appcenter configuration was provided in the build configuration.") +<% } -%> +end + +lane :increment_build_firebase do +<% if(codePluginFastlane.plugin && codePluginFastlane.plugin.android && codePluginFastlane.plugin.android.firebase) { -%> + begin + version = firebase_app_distribution_get_latest_release( + app: "<%= codePluginFastlane.plugin.android.firebase.appId %>", + service_credentials_json_data: ENV["GOOGLE_SERVICE_CREDENTIALS"] + ) + + if version[:buildVersion] + build_number = version[:buildVersion].to_i + 1 + sh %Q{cd .. && echo "$(awk '{sub(/versionCode [[:digit:]]+$/,"versionCode "#{build_number})}1' app/build.gradle)" > app/build.gradle && cd -} + puts "Fastlane: updated build number to #{build_number}" + end + rescue StandardError => e + puts "Fastlane: did not find any applicable versions for 'firebase_app_distribution_get_latest_release" + puts "Fastlane: #{e.message}" + end +<% } else { -%> + UI.user_error!("Fastlane: Tried to increment build number with firebase but no firebase configuration was provided in the build configuration.") +<% } -%> +end + + <% if(codePluginFastlane.plugin && codePluginFastlane.plugin.android && codePluginFastlane.plugin.android.appCenter) { -%> lane :appcenter_assemble do increment_build @@ -51,12 +82,54 @@ lane :appcenter_bundle do <% } -%> bundle + appcenter_upload( + owner_name: "<%= codePluginFastlane.plugin.android.appCenter.organization %>", + app_name: "<%= codePluginFastlane.plugin.android.appCenter.appName %>", + destination_type: "<%= codePluginFastlane.plugin.android.appCenter.destinationType %>", + destinations: "<%= codePluginFastlane.plugin.android.appCenter.destinations %>" + ) +end +<% } -%> + +lane :distribute_package do + assemble +<% if(codePluginFastlane.plugin && codePluginFastlane.plugin.android && codePluginFastlane.plugin.android.appCenter) { -%> appcenter_upload( owner_name: "<%= codePluginFastlane.plugin.android.appCenter.organization %>", app_name: "<%= codePluginFastlane.plugin.android.appCenter.appName %>", destination_type: "<%= codePluginFastlane.plugin.android.appCenter.destinationType %>", destinations: "<%= codePluginFastlane.plugin.android.appCenter.destinations %>" ) +<% } -%> +<% if(codePluginFastlane.plugin && codePluginFastlane.plugin.android && codePluginFastlane.plugin.android.firebase) { -%> + firebase_app_distribution( + app: "<%= codePluginFastlane.plugin.android.firebase.appId %>", + service_credentials_json_data: ENV["GOOGLE_SERVICE_CREDENTIALS"], + release_notes: ENV["FIREBASE_DISTRIBUTE_RELEASE_NOTES"], + groups: "<%= codePluginFastlane.plugin.android.firebase.groups %>" + ) +<% } -%> end + +lane :distribute_bundle do + bundle + +<% if(codePluginFastlane.plugin && codePluginFastlane.plugin.android && codePluginFastlane.plugin.android.appCenter) { -%> + appcenter_upload( + owner_name: "<%= codePluginFastlane.plugin.android.appCenter.organization %>", + app_name: "<%= codePluginFastlane.plugin.android.appCenter.appName %>", + destination_type: "<%= codePluginFastlane.plugin.android.appCenter.destinationType %>", + destinations: "<%= codePluginFastlane.plugin.android.appCenter.destinations %>" + ) <% } -%> +<% if(codePluginFastlane.plugin && codePluginFastlane.plugin.android && codePluginFastlane.plugin.android.firebase) { -%> + firebase_app_distribution( + app: "<%= codePluginFastlane.plugin.android.firebase.appId %>", + service_credentials_json_data: ENV["GOOGLE_SERVICE_CREDENTIALS"], + release_notes: ENV["FIREBASE_DISTRIBUTE_RELEASE_NOTES"], + android_artifact_type: "AAB", + groups: "<%= codePluginFastlane.plugin.android.firebase.groups %>" + ) +<% } -%> +end diff --git a/packages/plugin-fastlane/template/android/fastlane/Pluginfile b/packages/plugin-fastlane/template/android/fastlane/Pluginfile index 756bff8e13..ed527591a5 100644 --- a/packages/plugin-fastlane/template/android/fastlane/Pluginfile +++ b/packages/plugin-fastlane/template/android/fastlane/Pluginfile @@ -3,3 +3,4 @@ # Ensure this file is checked in to source control! gem 'fastlane-plugin-appcenter' +gem 'fastlane-plugin-firebase_app_distribution' diff --git a/packages/plugin-fastlane/template/ios/fastlane/Fastfile b/packages/plugin-fastlane/template/ios/fastlane/Fastfile index c0399b3bb7..ff7b782a45 100644 --- a/packages/plugin-fastlane/template/ios/fastlane/Fastfile +++ b/packages/plugin-fastlane/template/ios/fastlane/Fastfile @@ -1,6 +1,6 @@ default_platform :ios -# make a provisioned build and upload to appcenter +# make a provisioned build lane :build do keychain_password = SecureRandom.uuid keychain_name = 'ios-build.keychain' @@ -76,6 +76,15 @@ lane :increment_build do end <% } -%> +lane :increment_build_appcenter do +<% if(codePluginFastlane.plugin && codePluginFastlane.plugin.ios && codePluginFastlane.plugin.ios.appCenter) { -%> + increment_build +<% } else { -%> + UI.user_error!("Fastlane: Tried to increment build number with appcenter but no appcenter configuration was provided in the build configuration.") +<% } -%> +end + + <% if(codePluginFastlane.plugin && codePluginFastlane.plugin.ios && codePluginFastlane.plugin.ios.appCenter) { -%> lane :appcenter do increment_build @@ -90,3 +99,49 @@ lane :appcenter do ) end <% } -%> + +lane :increment_build_firebase do +<% if(codePluginFastlane.plugin && codePluginFastlane.plugin.ios && codePluginFastlane.plugin.ios.firebase) { -%> + begin + version = firebase_app_distribution_get_latest_release( + app: "<%= codePluginFastlane.plugin.ios.firebase.appId %>", + service_credentials_json_data: ENV["GOOGLE_SERVICE_CREDENTIALS"], + ) + + if version[:buildVersion] + build_number = increment_build_number( + build_number: version[:buildVersion].to_i + 1 + ) + puts "Fastlane: updated build number to #{build_number}" + end + rescue StandardError => e + puts "Fastlane: did not find any applicable versions for 'firebase_app_distribution_get_latest_release" + puts "Fastlane: #{e.message}" + end +<% } else { -%> + UI.user_error!("Fastlane: Tried to increment build number with firebase but no firebase configuration was provided in the build configuration.") +<% } -%> +end + +lane :distribute do + build + +<% if(codePluginFastlane.plugin && codePluginFastlane.plugin.ios && codePluginFastlane.plugin.ios.appCenter) { -%> + appcenter_upload( + owner_name: "<%= codePluginFastlane.plugin.ios.appCenter.organization %>", + app_name: "<%= codePluginFastlane.plugin.ios.appCenter.appName %>", + destination_type: "<%= codePluginFastlane.plugin.ios.appCenter.destinationType %>", + destinations: "<%= codePluginFastlane.plugin.ios.appCenter.destinations %>" + ) +<% } -%> + +<% if(codePluginFastlane.plugin && codePluginFastlane.plugin.ios && codePluginFastlane.plugin.ios.firebase) { -%> + firebase_app_distribution( + app: "<%= codePluginFastlane.plugin.ios.firebase.appId %>", + service_credentials_json_data: ENV["GOOGLE_SERVICE_CREDENTIALS"], + release_notes: ENV["FIREBASE_DISTRIBUTE_RELEASE_NOTES"], + groups: "<%= codePluginFastlane.plugin.ios.firebase.groups %>" + ) +<% } -%> +end + diff --git a/packages/plugin-fastlane/template/ios/fastlane/Pluginfile b/packages/plugin-fastlane/template/ios/fastlane/Pluginfile index 756bff8e13..ed527591a5 100644 --- a/packages/plugin-fastlane/template/ios/fastlane/Pluginfile +++ b/packages/plugin-fastlane/template/ios/fastlane/Pluginfile @@ -3,3 +3,4 @@ # Ensure this file is checked in to source control! gem 'fastlane-plugin-appcenter' +gem 'fastlane-plugin-firebase_app_distribution'