diff --git a/.buildkite/code-freeze.yml b/.buildkite/code-freeze.yml index 1cf78e3c066d..933636906759 100644 --- a/.buildkite/code-freeze.yml +++ b/.buildkite/code-freeze.yml @@ -13,6 +13,8 @@ steps: echo '--- :snowflake: Start Code Freeze' bundle exec fastlane code_freeze version:"${RELEASE_VERSION}" skip_confirm:true + # Runs on `mac-metal` so it can use the bot git identity from `use-bot-for-git` (only available + # on these agents) for its git write operations (commit/push/PR). agents: queue: "mac-metal" retry: diff --git a/.buildkite/commands/download-translations.sh b/.buildkite/commands/download-translations.sh new file mode 100755 index 000000000000..7f873e516251 --- /dev/null +++ b/.buildkite/commands/download-translations.sh @@ -0,0 +1,10 @@ +#!/bin/bash -eu + +echo "--- :robot_face: Use bot for git operations" +source use-bot-for-git + +echo "--- :ruby: Setup Ruby Tools" +install_gems + +echo "--- :globe_with_meridians: Download translations and open/update the PR" +bundle exec fastlane update_translations diff --git a/.buildkite/complete-code-freeze.yml b/.buildkite/complete-code-freeze.yml index 310766f39659..20e16f10e7f0 100644 --- a/.buildkite/complete-code-freeze.yml +++ b/.buildkite/complete-code-freeze.yml @@ -15,6 +15,8 @@ steps: echo '--- :snowflake: Complete Code Freeze' bundle exec fastlane complete_code_freeze skip_confirm:true + # Runs on `mac-metal` so it can use the bot git identity from `use-bot-for-git` (only available + # on these agents) for its git write operations (commit/push/PR). agents: queue: "mac-metal" retry: diff --git a/.buildkite/finalize-hotfix-release.yml b/.buildkite/finalize-hotfix-release.yml index 4af22b5700cc..861efa287ac0 100644 --- a/.buildkite/finalize-hotfix-release.yml +++ b/.buildkite/finalize-hotfix-release.yml @@ -15,6 +15,8 @@ steps: echo '--- :shipit: Finalize hotfix' bundle exec fastlane finalize_hotfix_release skip_confirm:true + # Runs on `mac-metal` so it can use the bot git identity from `use-bot-for-git` (only available + # on these agents) for its git write operations (commit/push/PR). agents: queue: mac-metal retry: diff --git a/.buildkite/finalize-release.yml b/.buildkite/finalize-release.yml index b541f8def406..b7868fb9fa1b 100644 --- a/.buildkite/finalize-release.yml +++ b/.buildkite/finalize-release.yml @@ -15,6 +15,8 @@ steps: echo '--- :shipit: Finalize Release' bundle exec fastlane finalize_release skip_confirm:true + # Runs on `mac-metal` so it can use the bot git identity from `use-bot-for-git` (only available + # on these agents) for its git write operations (commit/push/PR). agents: queue: "mac-metal" retry: diff --git a/.buildkite/new-beta-release.yml b/.buildkite/new-beta-release.yml index c684880bb623..ab56f79c6851 100644 --- a/.buildkite/new-beta-release.yml +++ b/.buildkite/new-beta-release.yml @@ -13,6 +13,8 @@ steps: echo '--- :shipit: New Beta Release' bundle exec fastlane new_beta_release skip_confirm:true + # Runs on `mac-metal` so it can use the bot git identity from `use-bot-for-git` (only available + # on these agents) for its git write operations (commit/push/PR). agents: queue: "mac-metal" retry: diff --git a/.buildkite/new-hotfix-release.yml b/.buildkite/new-hotfix-release.yml index 6fea293dc6be..94eb18a41661 100644 --- a/.buildkite/new-hotfix-release.yml +++ b/.buildkite/new-hotfix-release.yml @@ -13,6 +13,8 @@ steps: echo '--- :shipit: Start new hotfix' bundle exec fastlane new_hotfix_release version_name:"$RELEASE_VERSION" build_code:"$BUILD_CODE" skip_confirm:true + # Runs on `mac-metal` so it can use the bot git identity from `use-bot-for-git` (only available + # on these agents) for its git write operations (commit/push/PR). agents: queue: mac-metal retry: diff --git a/.buildkite/publish-release.yml b/.buildkite/publish-release.yml index a75faddbd52e..80fdb10d3c3d 100644 --- a/.buildkite/publish-release.yml +++ b/.buildkite/publish-release.yml @@ -15,6 +15,8 @@ steps: echo '--- :package: Publish Release' bundle exec fastlane publish_release skip_confirm:true + # Runs on `mac-metal` so it can use the bot git identity from `use-bot-for-git` (only available + # on these agents) for its git write operations (commit/push/PR). agents: queue: mac-metal retry: diff --git a/.buildkite/schedules/download-translations.yml b/.buildkite/schedules/download-translations.yml new file mode 100644 index 000000000000..76cbbce96557 --- /dev/null +++ b/.buildkite/schedules/download-translations.yml @@ -0,0 +1,25 @@ +# yaml-language-server: $schema=https://raw.githubusercontent.com/buildkite/pipeline-schema/main/schema.json +--- + +# Runs on a daily schedule (configured in the Buildkite UI, ~06:00 UTC) to sync the latest +# translations from GlotPress into a single rolling `translations/daily-update` PR. +# +# Runs on `mac-metal` (like the release code-freeze/finalize lanes) because this job commits, +# pushes and opens a PR, which needs the bot git identity from `use-bot-for-git` — that command +# is only available on those agents. + +agents: + queue: "mac-metal" + +steps: + - label: ":globe_with_meridians: Download Translations" + command: .buildkite/commands/download-translations.sh + plugins: [$CI_TOOLKIT] + +# Failure notifications are disabled for now. If re-enabled, they go to #wpmobile. +# notify: +# - slack: +# channels: +# - "#wpmobile" +# message: "Failed to sync translations from GlotPress." +# if: build.state == "failed" diff --git a/.buildkite/update-release-notes.yml b/.buildkite/update-release-notes.yml index 3b774014a6b8..b79219be244a 100644 --- a/.buildkite/update-release-notes.yml +++ b/.buildkite/update-release-notes.yml @@ -16,6 +16,8 @@ steps: echo '--- :memo: Update Release Notes' bundle exec fastlane update_appstore_strings version:${RELEASE_VERSION} + # Runs on `mac-metal` so it can use the bot git identity from `use-bot-for-git` (only available + # on these agents) for its git write operations (commit/push/PR). agents: queue: "mac-metal" retry: diff --git a/Gemfile b/Gemfile index 40dfbdd2cfbd..b1bb7f7b6d55 100644 --- a/Gemfile +++ b/Gemfile @@ -9,9 +9,11 @@ gem 'fastlane', '~> 2' gem 'fastlane-plugin-firebase_app_distribution', '~> 1.0' gem 'fastlane-plugin-sentry' -gem 'fastlane-plugin-wpmreleasetoolkit', '~> 14.7' +# TEMPORARY: point at the release-toolkit branch to validate the new `find_or_create_pull_request` +# action used by the `update_translations` lane. Revert to `~> 14.7` once it ships in a tagged release. +# gem 'fastlane-plugin-wpmreleasetoolkit', '~> 14.7' +gem 'fastlane-plugin-wpmreleasetoolkit', git: 'https://github.com/wordpress-mobile/release-toolkit', branch: 'add/find-or-create-pull-request' # gem 'fastlane-plugin-wpmreleasetoolkit', path: '../../release-toolkit' -# gem 'fastlane-plugin-wpmreleasetoolkit', git: 'https://github.com/wordpress-mobile/release-toolkit', branch: '' ### Gems needed only for generating Promo Screenshots group :screenshots, optional: true do diff --git a/Gemfile.lock b/Gemfile.lock index ab185a260b27..a94080d4fa52 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,3 +1,27 @@ +GIT + remote: https://github.com/wordpress-mobile/release-toolkit + revision: 77cdeac5098b460ac6faba189f7e6a4f3d642c25 + branch: add/find-or-create-pull-request + specs: + fastlane-plugin-wpmreleasetoolkit (14.7.0) + buildkit (~> 1.5) + chroma (= 0.2.0) + diffy (~> 3.3) + dotenv (~> 2.8) + fastlane (~> 2.235) + gettext (~> 3.5) + git (~> 1.3) + google-cloud-storage (~> 1.31) + java-properties (~> 0.3.0) + nokogiri (~> 1.19, >= 1.19.3) + octokit (~> 6.1) + parallel (~> 1.14) + plist (~> 3.1) + progress_bar (~> 1.3) + rake (>= 12.3, < 14.0) + rake-compiler (~> 1.0) + xcodeproj (~> 1.22) + GEM remote: https://rubygems.org/ specs: @@ -167,24 +191,6 @@ GEM google-apis-firebaseappdistribution_v1alpha (>= 0.12.0) fastlane-plugin-sentry (1.29.0) os (~> 1.1, >= 1.1.4) - fastlane-plugin-wpmreleasetoolkit (14.7.0) - buildkit (~> 1.5) - chroma (= 0.2.0) - diffy (~> 3.3) - dotenv (~> 2.8) - fastlane (~> 2.235) - gettext (~> 3.5) - git (~> 1.3) - google-cloud-storage (~> 1.31) - java-properties (~> 0.3.0) - nokogiri (~> 1.19, >= 1.19.3) - octokit (~> 6.1) - parallel (~> 1.14) - plist (~> 3.1) - progress_bar (~> 1.3) - rake (>= 12.3, < 14.0) - rake-compiler (~> 1.0) - xcodeproj (~> 1.22) fastlane-sirp (1.1.0) fiddle (1.1.8) forwardable (1.4.0) @@ -378,7 +384,7 @@ DEPENDENCIES fastlane (~> 2) fastlane-plugin-firebase_app_distribution (~> 1.0) fastlane-plugin-sentry - fastlane-plugin-wpmreleasetoolkit (~> 14.7) + fastlane-plugin-wpmreleasetoolkit! rmagick (~> 7.0) BUNDLED WITH diff --git a/fastlane/lanes/localization.rb b/fastlane/lanes/localization.rb index 528c817646cc..6cf97a9689a1 100644 --- a/fastlane/lanes/localization.rb +++ b/fastlane/lanes/localization.rb @@ -375,6 +375,65 @@ ) end + TRANSLATIONS_SYNC_BRANCH = 'translations/daily-update' + + ##################################################################################### + # update_translations + # ----------------------------------------------------------------------------------- + # Downloads the latest WordPress & Jetpack translations from GlotPress and opens (or + # refreshes) a single rolling Pull Request, so `trunk` stays continuously localized. + # Intended to run on a daily schedule. + # + # Each run resets `translations/daily-update` to `trunk` and re-downloads, so the PR + # always shows the complete current translation delta against `trunk` (no accumulation). + # If GlotPress has nothing new, no commit is made and the lane exits without a PR. + # ----------------------------------------------------------------------------------- + # Usage: + # bundle exec fastlane update_translations + ##################################################################################### + lane :update_translations do + Fastlane::Helper::GitHelper.checkout_and_pull(DEFAULT_BRANCH) + + # Reset the rolling branch to the tip of `trunk` so each run produces a clean delta against it. + Fastlane::Helper::GitHelper.delete_local_branch_if_exists!(TRANSLATIONS_SYNC_BRANCH) + Fastlane::Helper::GitHelper.create_branch(TRANSLATIONS_SYNC_BRANCH, from: DEFAULT_BRANCH) + + download_translations + + # `download_translations` commits when GlotPress has updates; if nothing changed, HEAD still + # points at `trunk` and there is nothing to open a PR for. + if Fastlane::Helper::GitHelper.point_to_same_commit?(DEFAULT_BRANCH, 'HEAD') + UI.important('No new translations from GlotPress today; nothing to sync.') + next + end + + # Prune translations whose key is no longer in the source strings (GlotPress can still serve them), + # which would otherwise fail Lint's `ExtraTranslation` check. Done as a separate commit on top of the + # download so the PR shows exactly what was pruned vs. what was downloaded. + main_res = File.join('WordPress', 'src', 'main', 'res') + jetpack_res = File.join('WordPress', 'src', 'jetpack', 'res') + android_prune_orphaned_translations(res_dir: main_res) + android_prune_orphaned_translations( + res_dir: jetpack_res, + additional_source_strings_paths: [File.join(main_res, 'values', 'strings.xml')] + ) + Fastlane::Helper::GitHelper.commit(message: 'Prune orphaned translations', files: :all) + + push_to_git_remote(remote_branch: TRANSLATIONS_SYNC_BRANCH, tags: false, force: true, set_upstream: true) + + # `find_or_create_pull_request` resolves the GitHub token the standard way (GITHUB_TOKEN) and only + # opens a PR when none is already open; the force-push above already refreshed any existing one. + pr_url = find_or_create_pull_request( + repository: GITHUB_REPO, + title: 'Update translations', + body: 'Automated daily translation sync from GlotPress. Opened by the `download-translations` scheduled pipeline.', + head: TRANSLATIONS_SYNC_BRANCH, + base: DEFAULT_BRANCH, + labels: ['Localization'] + ) + UI.success("Translations PR: #{pr_url}") + end + # Updates the `.po` file at the given `po_path` using the content of the `sources` files, # interpolating `release_version` where appropriate. # Internally, this calls the `gp_update_metadata_source` release toolkit action and adds Git management to it.