-
Notifications
You must be signed in to change notification settings - Fork 57
[Tooling] Make beta releases self-contained with translations and backmerge #2676
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: trunk
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
This file was deleted.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -166,14 +166,18 @@ end | |
| # Release Management Lanes | ||
| ######################################################################## | ||
|
|
||
| # Create a new release branch from trunk and the first beta. | ||
| # Create a new release branch from trunk, extract translatable strings, and generate draft release notes. | ||
| # | ||
| # - Extracts translatable strings and commits them to the release branch (for GlotPress import) | ||
| # - Creates a `release/<version>` branch from trunk | ||
| # - Delegates to {new_beta_release} to bump to beta1, commit, push, tag, and trigger a build | ||
| # - Extracts translatable strings and commits them to the release branch (for GlotPress import) | ||
| # - Generates draft release notes from merged PRs and commits them to the release branch | ||
| # - Creates a backmerge PR from the release branch to trunk (so wpcom cron can import strings to GlotPress) | ||
| # | ||
| # The first beta is triggered separately via {new_beta_release}. | ||
| # | ||
| # @param version [String] The version to freeze (e.g., '1.7.4') | ||
| # @param skip_confirm [Boolean] Skip interactive confirmation prompts (default: false) | ||
| # @param github_username [String, nil] GitHub username to assign as reviewer on the backmerge PR | ||
| # | ||
| lane :code_freeze do |version:, skip_confirm: false, github_username: nil| | ||
| branch_name = "release/#{version}" | ||
|
|
@@ -184,9 +188,6 @@ lane :code_freeze do |version:, skip_confirm: false, github_username: nil| | |
| - Extract translatable strings and commit to `#{branch_name}` | ||
| - Generate draft release notes from merged PRs | ||
| - Create a backmerge PR from `#{branch_name}` to `#{MAIN_BRANCH}` | ||
| - Trigger the first beta build for all platforms (macOS, Windows), which will then: | ||
| - Upload build artifacts to the Apps CDN | ||
| - Notify #dotcom-studio on Slack | ||
| PROMPT | ||
| next unless skip_confirm || UI.confirm('Continue?') | ||
|
|
||
|
|
@@ -211,30 +212,29 @@ lane :code_freeze do |version:, skip_confirm: false, github_username: nil| | |
|
|
||
| push_to_git_remote(set_upstream: true) | ||
|
|
||
| # Create the first beta (bumps version, commits, pushes, tags, triggers build) | ||
| new_beta_release(version: version, skip_confirm: skip_confirm) | ||
|
|
||
| # Create backmerge PR from the release branch to MAIN_BRANCH so that the pot strings bundle is uploaded to GlotPress once it hits trunk | ||
| # Important: this must come after new_beta_release because the backmerge action switches branches. | ||
| # Create backmerge PR so that the .pot strings file reaches trunk for GlotPress import | ||
| create_backmerge_pr(source_branch: branch_name, github_username: github_username) | ||
|
|
||
| UI.success("Code freeze complete! Created #{branch_name} with first beta") | ||
| UI.success("Code freeze complete! Created #{branch_name}") | ||
| end | ||
|
|
||
| # Create a new beta release on the current release branch. | ||
| # | ||
| # - Downloads latest translations from GlotPress and commits them | ||
| # - Determines the next beta number automatically from package.json | ||
| # - Bumps the version, commits, tags, and triggers a release build | ||
| # - Bumps the version, commits, pushes, and triggers a release build | ||
| # - Creates a backmerge PR from the release branch to trunk | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Note that this means that code-freeze will create one backmerge PR (to commit the version bump + extracted translatable strings etc), then on the step close after that in the scenario, we will separately trigger the first new_beta_release… which will also create yet another backmerge PR (whose diff this time will mostly only contain the beta version bump and not much else), right? I'm OK with that if that's acknowledged, but just wanted to highlight that side effect of the separation, since that now means 2 backmerge PRs close to one another instead of a single one (and means waiting for CI to go green on each of those… but for that we can improve the RMs life via
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah, good point, I discussed this a bit with @sejas. I like the fact that we'll have backmerge PRs for each beta + download translations and I think that's the main point I wanted to address after the discussions. But one point I'm not totally convinced about is the need (or not) of the "automatic" first beta build during code freeze (which could create the first backmerge instead of having it both on code freeze + first beta). The implementation removed it, but on a second thought I think having it saves a couple of clicks and binds the release process together a bit more. 🤷
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Another option would be to remove the backmerge PR at the time of Thinking about it, this is kinda what we do in some other product repos that need a pause between the start of the code freeze and the first beta (e.g. DOAndroid)… except in those repos we've used the convention to have a lane named This also re-enforces my suggestion on the ReleasesV2 PR (205520-ghe-Automattic/wpcom#discussion_r201295) that this step to create the first beta post code-freeze, even if it's now on demand and not done as part of the [EDIT] At the time I wrote this comment I hadn't seen your intermediate reply (as I hadn't refreshed the GitHub page) [/EDIT]
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. One important point about the Code Freeze backmerge is the .pot file update, so that's the main reason I kept the backmerge.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah but if we're guaranteed to have a beta being done as a follow up step after the backmerge (be it because the
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
I think this has always been the case even in other products? And probably part of why we've been calling the betas added via the button as "Intermediate beta" (as a cheat to suggest that there's the first beta made during code freeze, then a first intermediate beta after that, etc) 😅 So even in other products where we use different naming conventions of where we do the first beta as part of the code freeze lane this is also the case (eg first beta done during code freeze is named
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Random example with PockatCasts Android:
So that off-by-one in the title has always been there. Maybe if we renamed the task in Releases V2 from "Intermediate Beta 1" to "Intermediate Bugfix build 1" to make the distinction even clearer between "the first build done during code freeze" vs "subsequent beta builds that are only done if we found a bug and merged a fix and want to do a new beta to include that bugfix". But at that point I think that'd be wayyy too nitpicky 😄 Besides, there is also the seldom but possible case that a failed beta build would need to be retried and end up bumping the version number multiple times (see the case we had this morning with DOAndroid — p1772201201312009-slack-C06CKSPHYA1) which would lead to the version being So in the end I think we don't need to be too much attached with this off-by-one offset between "Intermediate Beta" index and
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Would it be possible to separate the pots generation and the submission of strings to GlotPress from the code freeze milestone?
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We decided p1772217237435699/1771256551.851819-slack-C06DRMD6VPZ to produce the code freeze and then a different milestone to produce a new beta1 a couple of days later. We always can iterate in these decisions after trying the real process a couple of cycles.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. So if I understand the discussion from Slack correctly, that will be:
If so, then that sounds good to me 👍 |
||
| # | ||
| # @param version [String] The base release version (e.g., '1.7.4') | ||
| # @param skip_confirm [Boolean] Skip interactive confirmation prompts (default: false) | ||
| # @param github_username [String, nil] GitHub username to assign as reviewer on the backmerge PR | ||
| # | ||
| lane :new_beta_release do |version:, skip_confirm: false| | ||
| lane :new_beta_release do |version:, skip_confirm: false, github_username: nil| | ||
| current_version = read_package_json_version | ||
| current_beta = current_version[/beta(\d+)$/, 1].to_i | ||
|
|
||
| # Guard against version mismatch (e.g. package.json has 1.7.4-beta3 but version param is 1.8.0) | ||
| # Skip the check when current_beta is 0, meaning this is the first beta (called from code_freeze before any bump). | ||
| # Skip the check when current_beta is 0, meaning this is the first beta (before any bump). | ||
| if current_beta.positive? | ||
| base_version = current_version.sub(/-beta\d+$/, '') | ||
| UI.user_error!("Version mismatch: package.json has #{current_version} but expected #{version}-betaN") unless base_version == version | ||
|
|
@@ -244,23 +244,38 @@ lane :new_beta_release do |version:, skip_confirm: false| | |
|
|
||
| UI.important <<~PROMPT | ||
| Creating new beta release #{new_version}. This will: | ||
| - Download latest translations from GlotPress | ||
| - Bump version to #{new_version} | ||
| - Trigger a release build for all platforms (macOS, Windows), which will then: | ||
| - Upload build artifacts to the Apps CDN | ||
| - Tag v#{new_version} | ||
| - Notify #dotcom-studio on Slack | ||
| - Create a backmerge PR from the release branch to `#{MAIN_BRANCH}` | ||
| PROMPT | ||
| next unless skip_confirm || UI.confirm('Continue?') | ||
|
|
||
| # Download latest translations so they're included in the beta build | ||
| fetch_glotpress_translations | ||
| git_add(path: [TRANSLATIONS_DIR]) | ||
| git_commit( | ||
| path: [TRANSLATIONS_DIR], | ||
| message: '[skip ci] Update translations', | ||
| allow_nothing_to_commit: true | ||
| ) | ||
|
|
||
| bump_version_commit_and_push(version: new_version) | ||
|
|
||
| trigger_release_build(version: new_version) | ||
|
|
||
| UI.success("New beta release created: v#{new_version}") | ||
|
|
||
| # Create backmerge PR so that translations and version bump get merged back to trunk | ||
| create_backmerge_pr(source_branch: "release/#{version}", github_username: github_username) | ||
| end | ||
|
|
||
| # Finalize the release by removing the beta suffix and triggering the final build. | ||
| # | ||
| # - Downloads latest translations from GlotPress (to capture any translations added during the beta period) | ||
| # - Bumps version to the final release number (removes beta suffix) | ||
| # - Triggers a release build in Buildkite | ||
| # - The build creates a draft GitHub release (with notes and download links) after uploading to CDN | ||
|
|
@@ -272,6 +287,7 @@ end | |
| lane :finalize_release do |version:, skip_confirm: false| | ||
| UI.important <<~PROMPT | ||
| Finalizing release #{version}. This will: | ||
| - Download latest translations from GlotPress | ||
| - Bump version to #{version} (remove beta suffix) | ||
| - Trigger a release build for all platforms (macOS, Windows), which will then: | ||
| - Upload build artifacts to the Apps CDN | ||
|
|
@@ -280,6 +296,15 @@ lane :finalize_release do |version:, skip_confirm: false| | |
| PROMPT | ||
| next unless skip_confirm || UI.confirm('Continue?') | ||
|
|
||
| # Download latest translations to capture any added during the beta period | ||
| fetch_glotpress_translations | ||
| git_add(path: [TRANSLATIONS_DIR]) | ||
| git_commit( | ||
| path: [TRANSLATIONS_DIR], | ||
| message: '[skip ci] Update translations', | ||
| allow_nothing_to_commit: true | ||
| ) | ||
|
|
||
| bump_version_commit_and_push(version: version) | ||
|
|
||
| trigger_release_build(version: version) | ||
|
|
@@ -387,70 +412,6 @@ lane :fetch_glotpress_translations do | |
| UI.success("Downloaded translations for #{locales.length} locales") | ||
| end | ||
|
|
||
| # Download the latest translations and create a PR to merge them into the release branch. | ||
| # | ||
| # @param skip_confirm [Boolean] Skip interactive confirmation prompts (default: false) | ||
| # | ||
| lane :download_translations do |skip_confirm: false, github_username: nil| | ||
| current_branch = Fastlane::Helper::GitHelper.current_git_branch | ||
|
|
||
| UI.important <<~PROMPT | ||
| Downloading translations. This will: | ||
| - Download latest translations from GlotPress | ||
| - Create a PR to merge them into `#{current_branch}` | ||
| PROMPT | ||
| next unless skip_confirm || UI.confirm('Continue?') | ||
|
|
||
| fetch_glotpress_translations | ||
|
|
||
| translations_branch = 'update/latest-translations' | ||
| Fastlane::Helper::GitHelper.delete_local_branch_if_exists!(translations_branch) | ||
| Fastlane::Helper::GitHelper.create_branch(translations_branch) | ||
|
|
||
| git_add(path: ['.']) | ||
| result = git_commit( | ||
| path: ['.'], | ||
| message: 'Update translations', | ||
| allow_nothing_to_commit: true | ||
| ) | ||
|
|
||
| if result.nil? | ||
| Fastlane::Helper::GitHelper.checkout_and_pull(current_branch) | ||
| Fastlane::Helper::GitHelper.delete_local_branch_if_exists!(translations_branch) | ||
| UI.important('No translation changes detected.') | ||
|
|
||
| if is_ci? | ||
| buildkite_annotate( | ||
| context: 'download-translations', | ||
| style: 'info', | ||
| message: 'No translation changes detected. No PR was created.' | ||
| ) | ||
| end | ||
| next | ||
| end | ||
|
|
||
| Fastlane::Helper::GitHelper.delete_remote_branch_if_exists!(translations_branch) | ||
| push_to_git_remote(set_upstream: true, tags: false) | ||
|
|
||
| pr_url = create_pull_request( | ||
| repo: GITHUB_REPO, | ||
| title: 'Update translations', | ||
| body: 'Merges the latest translations from GlotPress.', | ||
| labels: 'Releases', | ||
| base: current_branch, | ||
| head: translations_branch, | ||
| reviewers: Array(github_username) | ||
| ) | ||
|
|
||
| if is_ci? && pr_url | ||
| buildkite_annotate( | ||
| context: 'download-translations', | ||
| style: 'info', | ||
| message: "Translations Pull Request: #{pr_url}" | ||
| ) | ||
| end | ||
| end | ||
|
|
||
| ######################################################################## | ||
| # Build and Distribution Helper Methods | ||
| ######################################################################## | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd suggest to always download the latest translations at the time of release finalization scenario phase milestone (or the day before, like we do for Tumblr) to ensure that they get downloaded late in the release cycle and thus give the most time for translators to translate as much as possible.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's a good point -- the previous implementation, at the "Pre-Release" stage, wasn't fully in line with the process either. Running a final fetch during finalize release makes total sense 👍
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Updated on f4ccc01.