From 83e5b6026e1684c873df4b681ca85ddf307fb1ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nuno=20Sim=C3=B5es?= Date: Tue, 3 Feb 2026 09:26:34 +0100 Subject: [PATCH] workflow, fastlane: upload release artifacts new bucket (#9410) * workflow, fastlane: upload release artifacts new bucket Update release workflows and fastlane to support uploading release artifacts to both buckets (current and new) at the same time. It'll happen during a specific period for validaation / testing phase. * workflows: adjust permissions to use oidc * fastfile: only upload to new bucket in release * workflow, fastlane: add new upload_s3 lane for fastlane --- .github/workflows/build-android-beta.yml | 21 ++++++ .github/workflows/build-android-release.yml | 19 ++++++ .github/workflows/build-ios-beta.yml | 36 +++++++++++ .github/workflows/build-ios-release.yml | 36 +++++++++++ fastlane/Fastfile | 72 ++++++++++++++++++--- 5 files changed, 175 insertions(+), 9 deletions(-) diff --git a/.github/workflows/build-android-beta.yml b/.github/workflows/build-android-beta.yml index 7702b6925..12a10a7e6 100644 --- a/.github/workflows/build-android-beta.yml +++ b/.github/workflows/build-android-beta.yml @@ -24,6 +24,9 @@ jobs: runs-on: ubuntu-22.04 needs: - test + permissions: + id-token: write + contents: read steps: - name: ci/checkout-repo uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 @@ -58,3 +61,21 @@ jobs: with: name: android-build-beta-${{ github.run_id }} path: "*.apk" + + # New AWS bucket deployment steps + - name: Configure AWS credentials new bucket + id: configure-aws-credentials-new-bucket + uses: aws-actions/configure-aws-credentials@61815dcd50bd041e203e49132bacad1fd04d2708 # v5.1.1 + with: + aws-region: us-east-1 + role-to-assume: ${{ secrets.MM_MOBILE_RELEASE_AWS_ROLE_TO_ASSUME }} + + - name: ci/upload-android-beta-new-bucket + env: + AWS_NEW_BUCKET_NAME: "${{ secrets.MM_MOBILE_RELEASE_AWS_NEW_BUCKET_NAME }}" + MATTERMOST_WEBHOOK_URL: "${{ secrets.MM_MOBILE_BETA_MATTERMOST_WEBHOOK_URL }}" + run: | + echo "::group::Upload to new S3 bucket" + bundle exec fastlane android upload_artifacts_to_s3 --env android.beta + echo "::endgroup::" + working-directory: ./fastlane diff --git a/.github/workflows/build-android-release.yml b/.github/workflows/build-android-release.yml index 3bfd062f6..b3f68b569 100644 --- a/.github/workflows/build-android-release.yml +++ b/.github/workflows/build-android-release.yml @@ -24,6 +24,9 @@ jobs: runs-on: ubuntu-22.04 needs: - test + permissions: + id-token: write + contents: read steps: - name: ci/checkout-repo uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 @@ -58,3 +61,19 @@ jobs: with: name: android-build-release-${{ github.run_id }} path: "*.apk" + + - name: Configure AWS credentials new bucket + uses: aws-actions/configure-aws-credentials@61815dcd50bd041e203e49132bacad1fd04d2708 # v5.1.1 + with: + aws-region: us-east-1 + role-to-assume: ${{ secrets.MM_MOBILE_RELEASE_AWS_ROLE_TO_ASSUME }} + + - name: ci/upload-android-release-new-bucket + env: + AWS_NEW_BUCKET_NAME: "${{ secrets.MM_MOBILE_RELEASE_AWS_NEW_BUCKET_NAME }}" + MATTERMOST_WEBHOOK_URL: "${{ secrets.MM_MOBILE_RELEASE_MATTERMOST_WEBHOOK_URL }}" + run: | + echo "::group::Upload to new S3 bucket" + bundle exec fastlane android upload_artifacts_to_s3 --env android.release + echo "::endgroup::" + working-directory: ./fastlane diff --git a/.github/workflows/build-ios-beta.yml b/.github/workflows/build-ios-beta.yml index c3153d52e..44653baab 100644 --- a/.github/workflows/build-ios-beta.yml +++ b/.github/workflows/build-ios-beta.yml @@ -53,11 +53,30 @@ jobs: name: ios-build-simulator-${{ github.run_id }} path: Mattermost-simulator-x86_64.app.zip + # Logic for new bucket upload + - name: Configure AWS credentials new bucket + uses: aws-actions/configure-aws-credentials@61815dcd50bd041e203e49132bacad1fd04d2708 # v5.1.1 + with: + aws-region: us-east-1 + role-to-assume: ${{ secrets.MM_MOBILE_RELEASE_AWS_ROLE_TO_ASSUME }} + + - name: ci/upload-ios-simulator-new-bucket + env: + TAG: "${{ github.ref_name }}" + AWS_NEW_BUCKET_NAME: "${{ secrets.MM_MOBILE_RELEASE_AWS_NEW_BUCKET_NAME }}" + MATTERMOST_WEBHOOK_URL: "${{ secrets.MM_MOBILE_BETA_MATTERMOST_WEBHOOK_URL }}" + GITHUB_TOKEN: "${{ secrets.MM_MOBILE_GITHUB_TOKEN }}" + run: bundle exec fastlane ios upload_artifacts_to_s3 --env ios.simulator output_file:"Mattermost-simulator-x86_64.app.zip" + working-directory: ./fastlane + build-and-deploy-ios-beta: runs-on: macos-15-large if: ${{ !contains(github.ref_name, 'beta-sim') }} needs: - test + permissions: + id-token: write + contents: read steps: - name: ci/checkout-repo uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 @@ -100,3 +119,20 @@ jobs: with: name: ios-build-beta-${{ github.run_id }} path: "*.ipa" + + # Logic for new bucket upload + - name: Configure AWS credentials new bucket + uses: aws-actions/configure-aws-credentials@61815dcd50bd041e203e49132bacad1fd04d2708 # v5.1.1 + with: + aws-region: us-east-1 + role-to-assume: ${{ secrets.MM_MOBILE_RELEASE_AWS_ROLE_TO_ASSUME }} + + - name: ci/upload-ios-beta-new-bucket + env: + AWS_NEW_BUCKET_NAME: "${{ secrets.MM_MOBILE_RELEASE_AWS_NEW_BUCKET_NAME }}" + MATTERMOST_WEBHOOK_URL: "${{ secrets.MM_MOBILE_BETA_MATTERMOST_WEBHOOK_URL }}" + run: | + echo "::group::Upload to new S3 bucket" + bundle exec fastlane ios upload_artifacts_to_s3 --env ios.beta + echo "::endgroup::" + working-directory: ./fastlane diff --git a/.github/workflows/build-ios-release.yml b/.github/workflows/build-ios-release.yml index a8e6e8a44..de33ab631 100644 --- a/.github/workflows/build-ios-release.yml +++ b/.github/workflows/build-ios-release.yml @@ -27,6 +27,9 @@ jobs: if: ${{ !contains(github.ref_name, 'release-sim') }} needs: - test + permissions: + id-token: write + contents: read steps: - name: ci/checkout-repo uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 @@ -46,6 +49,7 @@ jobs: env: AWS_ACCESS_KEY_ID: "${{ secrets.MM_MOBILE_RELEASE_AWS_ACCESS_KEY_ID }}" AWS_SECRET_ACCESS_KEY: "${{ secrets.MM_MOBILE_RELEASE_AWS_SECRET_ACCESS_KEY }}" + AWS_NEW_BUCKET_NAME: "${{ secrets.MM_MOBILE_RELEASE_AWS_NEW_BUCKET_NAME }}" MATTERMOST_WEBHOOK_URL: "${{ secrets.MM_MOBILE_RELEASE_MATTERMOST_WEBHOOK_URL }}" FASTLANE_TEAM_ID: "${{ secrets.MM_MOBILE_FASTLANE_TEAM_ID }}" IOS_API_ISSUER_ID: "${{ secrets.MM_MOBILE_IOS_API_ISSUER_ID }}" @@ -70,6 +74,23 @@ jobs: name: ios-build-release-${{ github.run_id }} path: "*.ipa" + # Upload artifacts to new bucket + - name: Configure AWS credentials new bucket + uses: aws-actions/configure-aws-credentials@61815dcd50bd041e203e49132bacad1fd04d2708 # v5.1.1 + with: + aws-region: us-east-1 + role-to-assume: ${{ secrets.MM_MOBILE_RELEASE_AWS_ROLE_TO_ASSUME }} + + - name: ci/upload-ios-release-to-new-bucket + env: + AWS_NEW_BUCKET_NAME: "${{ secrets.MM_MOBILE_RELEASE_AWS_NEW_BUCKET_NAME }}" + MATTERMOST_WEBHOOK_URL: "${{ secrets.MM_MOBILE_RELEASE_MATTERMOST_WEBHOOK_URL }}" + run: | + echo "::group::Build" + bundle exec fastlane ios upload_artifacts_to_s3 --env ios.release + echo "::endgroup::" + working-directory: ./fastlane + build-ios-simulator: runs-on: macos-15-large if: ${{ !contains(github.ref_name , 'release-ios') }} @@ -100,3 +121,18 @@ jobs: with: name: ios-build-simulator-${{ github.run_id }} path: Mattermost-simulator-x86_64.app.zip + + # Logic for new bucket upload + - name: Configure AWS credentials new bucket + uses: aws-actions/configure-aws-credentials@61815dcd50bd041e203e49132bacad1fd04d2708 # v5.1.1 + with: + aws-region: us-east-1 + role-to-assume: ${{ secrets.MM_MOBILE_RELEASE_AWS_ROLE_TO_ASSUME }} + + - name: ci/upload-ios-simulator-new-bucket + env: + TAG: "${{ github.ref_name }}" + AWS_NEW_BUCKET_NAME: "${{ secrets.MM_MOBILE_BETA_AWS_NEW_BUCKET_NAME }}" + MATTERMOST_WEBHOOK_URL: "${{ secrets.MM_MOBILE_BETA_MATTERMOST_WEBHOOK_URL }}" + run: bundle exec fastlane ios simulator --env ios.simulator output_file:"Mattermost-simulator-x86_64.app.zip" + working-directory: ./fastlane diff --git a/fastlane/Fastfile b/fastlane/Fastfile index 3f4dd4145..6b1db413a 100644 --- a/fastlane/Fastfile +++ b/fastlane/Fastfile @@ -224,12 +224,19 @@ lane :link_sentry do |options| end end +# Uploads built files to S3 +# It's currently uploading to two different buckets depending on the +# enable_s3_new_bucket option. +# Default, uploads to the legacy bucket using static credentials (AWS_BUCKET_NAME). +# To upload to the new bucket AWS_NEW_BUCKET_NAME (using IAM/OIDC), pass :enable_s3_new_bucket => true in options. +# Example: upload_file_to_s3({:os_type => "ios", :enable_s3_new_bucket => true}) desc 'Upload file to s3' lane :upload_file_to_s3 do |options| os_type = options[:os_type].downcase extensions = os_type == "android" ? ["*.apk", "*.aab"] : ["*.ipa"] build_folder_path = Dir[File.expand_path('..')].first files = [] + enable_s3_new_bucket = options[:enable_s3_new_bucket] == true unless options[:file].nil? || options[:file].empty? files.push("#{build_folder_path}/#{options[:file]}") @@ -259,6 +266,8 @@ lane :upload_file_to_s3 do |options| s3_region = ENV['AWS_REGION'] s3_bucket_name = ENV['AWS_BUCKET_NAME'] + s3_new_bucket_name = ENV['AWS_NEW_BUCKET_NAME'] + bucket_name = enable_s3_new_bucket ? s3_new_bucket_name : s3_bucket_name if is_build_pr # Get the current git commit SHA (short version) @@ -267,8 +276,18 @@ lane :upload_file_to_s3 do |options| else s3_folder = "#{ENV['AWS_FOLDER_NAME']}/#{version_number}/#{build_number}" end - - s3_client = Aws::S3::Client.new(region: s3_region) + if enable_s3_new_bucket + # Client for new bucket assumes role via GitHub Actions OIDC + s3_client = Aws::S3::Client.new(region: s3_region) + UI.message("Set S3 Client to upload to new S3 bucket") + else + s3_client = Aws::S3::Client.new( + region: s3_region, + access_key_id: ENV['AWS_ACCESS_KEY_ID'], + secret_access_key: ENV['AWS_SECRET_ACCESS_KEY'] + ) + UI.message("Set S3 Client to upload to existing S3 bucket: #{s3_bucket_name}") + end transfer_manager = Aws::S3::TransferManager.new(client: s3_client) mutex = Mutex.new threads = [] @@ -288,7 +307,8 @@ lane :upload_file_to_s3 do |options| filename = File.basename(file) puts "[#{Thread.current["file_number"]}/#{total_files}] #{filename} uploading..." s3_key = "#{s3_folder}/#{filename}" - transfer_manager.upload_file(file, bucket: s3_bucket_name, key: s3_key) + transfer_manager.upload_file(file, bucket: bucket_name, key: s3_key) + # Keep s3_bucket_name to support both buckets. links.push("https://#{s3_bucket_name}/#{s3_key}") end } @@ -304,7 +324,7 @@ lane :upload_file_to_s3 do |options| plist_body = ERB.new(plist_template).result(binding) s3_client.put_object( - bucket: s3_bucket_name, + bucket: bucket_name, key: "#{s3_folder}/#{plist_file}", body: plist_body, content_type: 'application/xml' @@ -313,13 +333,15 @@ lane :upload_file_to_s3 do |options| install_url = "itms-services://?action=download-manifest&url=https://#{s3_bucket_name}/#{s3_folder}/#{plist_file}" end - qa_build_message({ - :os_type => os_type, - :install_url => install_url - }) + if enable_s3_new_bucket == false + qa_build_message({ + :os_type => os_type, + :install_url => install_url + }) + end end - if options[:file]&.start_with?('Mattermost-simulator-') && options[:file]&.end_with?('.app.zip') + if options[:file]&.start_with?('Mattermost-simulator-') && options[:file]&.end_with?('.app.zip') && enable_s3_new_bucket == false pretext = '#### New iOS build for VM/Simulator' msg = "Download link: #{links.first}" send_message_to_mattermost({ @@ -445,6 +467,28 @@ platform :ios do }) end + desc 'Upload artifacts to S3' + lane :upload_artifacts_to_s3 do |options| + output_file = options[:output_file] + UI.message("Uploading to new S3 bucket..." + (output_file ? " file: #{output_file}" : "")) + begin + if output_file && !output_file.empty? + upload_file_to_s3({ + :os_type => "ios", + :file => output_file, + :enable_s3_new_bucket => true + }) + else + upload_file_to_s3({ + :os_type => "ios", + :enable_s3_new_bucket => true + }) + end + rescue SyntaxError, StandardError + UI.error("Failed to upload to new S3 bucket") + end + end + lane :update_settings do # Configure Main app settings app_name = ENV['APP_NAME'] || 'Mattermost Beta' @@ -793,6 +837,16 @@ platform :android do sh "mv #{lane_context[SharedValues::GRADLE_APK_OUTPUT_PATH]} #{Pathname.new(File.expand_path(File.dirname(__FILE__))).parent.to_s}/Mattermost-unsigned.apk" end + desc 'Upload artifacts to S3' + lane :upload_artifacts_to_s3 do + UI.message("Uploading to new S3 bucket...") + begin + upload_file_to_s3({:os_type => "android", :enable_s3_new_bucket => true}) + rescue SyntaxError, StandardError + UI.error("Failed to upload to new S3 bucket") + end + end + lane :update_identifiers do # Set the name for the app app_name = ENV['APP_NAME'] || 'Mattermost Beta'