diff --git a/Gemfile b/Gemfile index b740cfb3689f..48b1977610b5 100644 --- a/Gemfile +++ b/Gemfile @@ -9,12 +9,12 @@ gem 'dotenv' # See failures like https://buildkite.com/automattic/wordpress-ios/builds/24053#019234f2-80a5-40f6-b55e-2f420e6483a8/3840-3915 # and https://github.com/fastlane/fastlane/pull/22256 gem 'fastlane', '~> 2.227' -gem 'fastlane-plugin-appcenter', '~> 2.1' +gem 'fastlane-plugin-firebase_app_distribution', '~> 0.10' gem 'fastlane-plugin-sentry' # This comment avoids typing to switch to a development version for testing. # # gem 'fastlane-plugin-wpmreleasetoolkit', git: 'https://github.com/wordpress-mobile/release-toolkit', ref: '' -gem 'fastlane-plugin-wpmreleasetoolkit', '~> 12.5' +gem 'fastlane-plugin-wpmreleasetoolkit', '~> 13.0' gem 'rake' gem 'rubocop', '~> 1.74' gem 'rubocop-rake', '~> 0.7' diff --git a/Gemfile.lock b/Gemfile.lock index 2c45fb98351b..6609cc59609f 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -5,7 +5,7 @@ GEM base64 nkf rexml - activesupport (8.0.1) + activesupport (8.0.2) base64 benchmark (>= 0.3) bigdecimal @@ -60,7 +60,6 @@ GEM connection_pool (2.5.0) cork (0.3.0) colored2 (~> 3.1) - csv (3.3.2) danger (9.5.1) base64 (~> 0.2) claide (~> 1.0) @@ -167,11 +166,12 @@ GEM xcodeproj (>= 1.13.0, < 2.0.0) xcpretty (~> 0.4.0) xcpretty-travis-formatter (>= 0.0.3, < 2.0.0) - fastlane-plugin-appcenter (2.1.3) - csv + fastlane-plugin-firebase_app_distribution (0.10.0) + google-apis-firebaseappdistribution_v1 (~> 0.3.0) + google-apis-firebaseappdistribution_v1alpha (~> 0.2.0) fastlane-plugin-sentry (1.28.0) os (~> 1.1, >= 1.1.4) - fastlane-plugin-wpmreleasetoolkit (12.5.0) + fastlane-plugin-wpmreleasetoolkit (13.0.0) activesupport (>= 6.1.7.1) buildkit (~> 1.5) chroma (= 0.2.0) @@ -204,6 +204,10 @@ GEM representable (~> 3.0) retriable (>= 2.0, < 4.a) rexml + google-apis-firebaseappdistribution_v1 (0.3.0) + google-apis-core (>= 0.11.0, < 2.a) + google-apis-firebaseappdistribution_v1alpha (0.2.0) + google-apis-core (>= 0.11.0, < 2.a) google-apis-iamcredentials_v1 (0.17.0) google-apis-core (>= 0.11.0, < 2.a) google-apis-playcustomapp_v1 (0.13.0) @@ -365,9 +369,9 @@ DEPENDENCIES danger-dangermattic (~> 1.2) dotenv fastlane (~> 2.227) - fastlane-plugin-appcenter (~> 2.1) + fastlane-plugin-firebase_app_distribution (~> 0.10) fastlane-plugin-sentry - fastlane-plugin-wpmreleasetoolkit (~> 12.5) + fastlane-plugin-wpmreleasetoolkit (~> 13.0) rake rmagick (~> 6.1.1) rubocop (~> 1.74) diff --git a/WordPress/Credentials/Secrets-example.swift b/WordPress/Credentials/Secrets-example.swift index 5b9ac9ecfceb..22eb27604ea2 100644 --- a/WordPress/Credentials/Secrets-example.swift +++ b/WordPress/Credentials/Secrets-example.swift @@ -20,7 +20,6 @@ class ApiCredentials: NSObject { // Other Services static let tenorApiKey = "" static let sentryDSN = "" - static let appCenterAppId = "" static let encryptedLogKey = "" static let debuggingKey = "" static let docsBotId = "" diff --git a/docs/feature-flags.md b/docs/feature-flags.md index d2d0f42035cc..e484991992db 100644 --- a/docs/feature-flags.md +++ b/docs/feature-flags.md @@ -15,7 +15,7 @@ case localDeveloper // debug case a8cBranchTest // alpha /// Beta released internally for Automattic employees -case a8cPrereleaseTesting. // internal - AppCenter / TestFlight +case a8cPrereleaseTesting. // internal - Firebase App Distribution / TestFlight /// Production build released in the app store case appStore // release diff --git a/fastlane/Fastfile b/fastlane/Fastfile index b652009de547..be986d657d93 100644 --- a/fastlane/Fastfile +++ b/fastlane/Fastfile @@ -240,3 +240,9 @@ end def editorial_branch_name(version: release_version_current) "release_notes/#{version}" end + +def pull_request_number + # Buildkite sets this env var to the PR number if on a PR, but to 'false' (and not nil) if not on a PR + pr_num = ENV.fetch('BUILDKITE_PULL_REQUEST', 'false') + pr_num == 'false' ? nil : Integer(pr_num) +end diff --git a/fastlane/env/project.env-example b/fastlane/env/project.env-example index 280df896d851..371b75b57b51 100644 --- a/fastlane/env/project.env-example +++ b/fastlane/env/project.env-example @@ -1,8 +1,6 @@ INT_EXPORT_TEAM_ID= EXT_EXPORT_TEAM_ID= -APPCENTER_PUBLIC_ID= - FASTLANE_ITC_TEAM_ID= SENTRY_ORG_SLUG= diff --git a/fastlane/env/user.env-example b/fastlane/env/user.env-example index f75ebe246bc8..9463ab4a964d 100644 --- a/fastlane/env/user.env-example +++ b/fastlane/env/user.env-example @@ -2,7 +2,6 @@ FASTLANE_USER= DELIVER_USER= GHHELPER_ACCESS= -APPCENTER_API_TOKEN= SENTRY_AUTH_TOKEN= BUILDKITE_TOKEN= diff --git a/fastlane/lanes/build.rb b/fastlane/lanes/build.rb index 93c5cc014f59..2ea527a3db8b 100644 --- a/fastlane/lanes/build.rb +++ b/fastlane/lanes/build.rb @@ -1,10 +1,25 @@ # frozen_string_literal: true +# Sentry SENTRY_ORG_SLUG = 'a8c' SENTRY_PROJECT_SLUG_WORDPRESS = 'wordpress-ios' SENTRY_PROJECT_SLUG_JETPACK = 'jetpack-ios' -APPCENTER_OWNER_NAME = 'automattic' -APPCENTER_OWNER_TYPE = 'organization' + +# Prototype Builds in Firebase App Distribution +PROTOTYPE_BUILD_XCODE_CONFIGURATION = 'Release-Alpha' +FIREBASE_APP_CONFIG_WORDPRESS = { + app_name: 'WordPress', + app_icon: ':wordpress:', # Use Buildkite emoji + app_id: '1:124902176124:ios:ff9714d0b53aac821620f9', + testers_group: 'wordpress-ios---prototype-builds' +}.freeze +FIREBASE_APP_CONFIG_JETPACK = { + app_name: 'Jetpack', + app_icon: ':jetpack:', # Use Buildkite emoji + app_id: '1:124902176124:ios:121c494b82f283ec1620f9', + testers_group: 'jetpack-ios---prototype-builds' +}.freeze + CONCURRENT_SIMULATORS = 2 # Shared options to use when invoking `build_app` (`gym`). @@ -251,7 +266,7 @@ ) end - # Builds the WordPress app for a Prototype Build ("WordPress Alpha" scheme), and uploads it to App Center + # Builds the WordPress app for a Prototype Build ("WordPress Alpha" scheme), and uploads it to Firebase App Distribution # # @called_by CI # @@ -264,14 +279,13 @@ build_and_upload_prototype_build( scheme: 'WordPress', output_app_name: 'WordPress Alpha', - appcenter_app_name: 'WPiOS-One-Offs', - app_icon: ':wordpress:', # Use Buildkite emoji + firebase_app_config: FIREBASE_APP_CONFIG_WORDPRESS, sentry_project_slug: SENTRY_PROJECT_SLUG_WORDPRESS, app_identifier: 'org.wordpress.alpha' ) end - # Builds the Jetpack app for a Prototype Build ("Jetpack" scheme), and uploads it to App Center + # Builds the Jetpack app for a Prototype Build ("Jetpack" scheme), and uploads it to Firebase App Distribution # # @called_by CI # @@ -284,8 +298,7 @@ build_and_upload_prototype_build( scheme: 'Jetpack', output_app_name: 'Jetpack Alpha', - appcenter_app_name: 'jetpack-installable-builds', - app_icon: ':jetpack:', # Use Buildkite emoji + firebase_app_config: FIREBASE_APP_CONFIG_JETPACK, sentry_project_slug: SENTRY_PROJECT_SLUG_JETPACK, app_identifier: 'com.jetpack.alpha' ) @@ -306,49 +319,19 @@ # Helper Functions ################################################# - - # Generates a build number for Prototype Builds, based on the PR number and short commit SHA1 + # Builds a Prototype Build for WordPress or Jetpack, then uploads it to Firebase App Distribution and comment with a link to it on the PR. # - # @note This function uses Buildkite-specific ENV vars - # - def generate_prototype_build_number - if ENV['BUILDKITE'] - commit = ENV.fetch('BUILDKITE_COMMIT', nil)[0, 7] - branch = ENV.fetch('BUILDKITE_BRANCH', nil) - pr_num = ENV.fetch('BUILDKITE_PULL_REQUEST', nil) - - pr_num == 'false' ? "#{branch}-#{commit}" : "pr#{pr_num}-#{commit}" - else - repo = Git.open(PROJECT_ROOT_FOLDER) - commit = repo.current_branch - branch = repo.revparse('HEAD')[0, 7] - - "#{branch}-#{commit}" - end - end - - # Builds a Prototype Build for WordPress or Jetpack, then uploads it to App Center and comment with a link to it on the PR. - # - # rubocop:disable Metrics/AbcSize - # rubocop:disable Metrics/ParameterLists - def build_and_upload_prototype_build(scheme:, output_app_name:, appcenter_app_name:, app_icon:, sentry_project_slug:, app_identifier:) - configuration = 'Release-Alpha' - - # Get the current build version, and update it if needed - version_config_path = File.join(PROJECT_ROOT_FOLDER, 'config', 'Version.public.xcconfig') - versions = Xcodeproj::Config.new(File.new(version_config_path)).to_hash - build_number = generate_prototype_build_number - UI.message("Updating build version to #{build_number}") - versions['VERSION_LONG'] = build_number - new_config = Xcodeproj::Config.new(versions) - new_config.save_as(Pathname.new(version_config_path)) + def build_and_upload_prototype_build(scheme:, output_app_name:, firebase_app_config:, sentry_project_slug:, app_identifier:) + build_number = ENV.fetch('BUILDKITE_BUILD_NUMBER', '0') + pr_or_branch = pull_request_number&.then { |num| "PR ##{num}" } || ENV.fetch('BUILDKITE_BRANCH', nil) # Build build_app( scheme: scheme, workspace: WORKSPACE_PATH, - configuration: configuration, + configuration: PROTOTYPE_BUILD_XCODE_CONFIGURATION, clean: true, + xcargs: { VERSION_LONG: build_number, VERSION_SHORT: pr_or_branch }.compact, output_directory: BUILD_PRODUCTS_PATH, output_name: output_app_name, derived_data_path: DERIVED_DATA_PATH, @@ -357,21 +340,8 @@ def build_and_upload_prototype_build(scheme:, output_app_name:, appcenter_app_na export_options: { **COMMON_EXPORT_OPTIONS, method: 'enterprise' } ) - # Upload to App Center - commit = ENV.fetch('BUILDKITE_COMMIT', 'Unknown') - pr = ENV.fetch('BUILDKITE_PULL_REQUEST', nil) - release_notes = <<~NOTES - - Branch: `#{ENV.fetch('BUILDKITE_BRANCH', 'Unknown')}`\n - - Commit: [#{commit[0...7]}](https://github.com/#{GITHUB_REPO}/commit/#{commit})\n - - Pull Request: [##{pr}](https://github.com/#{GITHUB_REPO}/pull/#{pr})\n - NOTES - - upload_build_to_app_center( - name: appcenter_app_name, - file: lane_context[SharedValues::IPA_OUTPUT_PATH], - dsym: lane_context[SharedValues::DSYM_OUTPUT_PATH], - release_notes: release_notes, - distribute_to_everyone: false + upload_build_to_firebase_app_distribution( + firebase_app_config: firebase_app_config ) # Upload dSYMs to Sentry @@ -388,33 +358,7 @@ def build_and_upload_prototype_build(scheme:, output_app_name:, appcenter_app_na build_version: build_number, app_identifier: app_identifier ) - - # Post PR Comment - comment_body = prototype_build_details_comment( - app_display_name: output_app_name, - app_icon: app_icon, - app_center_org_name: APPCENTER_OWNER_NAME, - metadata: { Configuration: configuration }, - fold: true - ) - - comment_on_pr( - project: GITHUB_REPO, - pr_number: Integer(ENV.fetch('BUILDKITE_PULL_REQUEST', nil)), - reuse_identifier: "prototype-build-link-#{appcenter_app_name}", - body: comment_body - ) - - # Attach version information as Buildkite metadata and annotation - appcenter_id = lane_context.dig(SharedValues::APPCENTER_BUILD_INFORMATION, 'id') - metadata = versions.merge(build_type: 'Prototype', 'appcenter:id': appcenter_id) - buildkite_metadata(set: metadata) - appcenter_install_url = "https://install.appcenter.ms/orgs/#{APPCENTER_OWNER_NAME}/apps/#{appcenter_app_name}/releases/#{appcenter_id}" - list = metadata.map { |k, v| " - **#{k}**: #{v}" }.join("\n") - buildkite_annotate(context: "appcenter-info-#{output_app_name}", style: 'info', message: "#{output_app_name} [App Center Build](#{appcenter_install_url}) Info:\n\n#{list}") end - # rubocop:enable Metrics/AbcSize - # rubocop:enable Metrics/ParameterLists def inject_buildkite_analytics_environment(xctestrun_path:) require 'plist' @@ -467,23 +411,39 @@ def send_slack_message(message:, channel: '#build-and-ship') ) end - def upload_build_to_app_center( - name:, - file:, - dsym:, - release_notes:, - distribute_to_everyone: - ) - appcenter_upload( - api_token: get_required_env('APPCENTER_API_TOKEN'), - owner_name: APPCENTER_OWNER_NAME, - owner_type: APPCENTER_OWNER_TYPE, - app_name: name, - file: file, - dsym: dsym, + # Uploads a build to Firebase App Distribution and post the corresponding PR comment + # + # @param [Hash] firebase_app_config A hash with the app name as the key and the Firebase app ID and testers group as the value + # Typically one of FIREBASE_APP_CONFIG_WORDPRESS or FIREBASE_APP_CONFIG_JETPACK + # + def upload_build_to_firebase_app_distribution(firebase_app_config:) + release_notes = <<~NOTES + Pull Request: ##{pull_request_number || 'N/A'} + Branch: `#{ENV.fetch('BUILDKITE_BRANCH', 'N/A')}` + Commit: #{ENV.fetch('BUILDKITE_COMMIT', 'N/A')[0...7]} + NOTES + + firebase_app_distribution( + app: firebase_app_config[:app_id], + service_credentials_json_data: get_required_env('FIREBASE_APP_DISTRIBUTION_ACCOUNT_KEY'), release_notes: release_notes, - destinations: distribute_to_everyone ? '*' : 'Collaborators', - notify_testers: false + groups: firebase_app_config[:testers_group] + ) + + return if pull_request_number.nil? + + # PR Comment + comment_body = prototype_build_details_comment( + app_display_name: firebase_app_config[:app_name], + app_icon: firebase_app_config[:app_icon], + metadata: { Configuration: PROTOTYPE_BUILD_XCODE_CONFIGURATION }, + fold: true + ) + comment_on_pr( + project: GITHUB_REPO, + pr_number: pull_request_number, + reuse_identifier: "prototype-build-link-#{firebase_app_config[:app_id]}", + body: comment_body ) end