Skip to content

Commit 624a8be

Browse files
authored
[ci] Update branch management for batch release (#11575)
based on go/batch-release-branch option 2 Needs to add flutter github bot to be able to bypass branch protection first ## Pre-Review Checklist **Note**: The Flutter team is currently trialing the use of [Gemini Code Assist for GitHub](https://developers.google.com/gemini-code-assist/docs/review-github-code). Comments from the `gemini-code-assist` bot should not be taken as authoritative feedback from the Flutter team. If you find its comments useful you can update your code accordingly, but if you are unsure or disagree with the feedback, please feel free to wait for a Flutter team member's review for guidance on which automated comments should be addressed. [^1]: Regular contributors who have demonstrated familiarity with the repository guidelines only need to comment if the PR is not auto-exempted by repo tooling.
1 parent ff0189e commit 624a8be

10 files changed

Lines changed: 144 additions & 179 deletions

.github/workflows/batch_release_pr.yml

Lines changed: 19 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -4,64 +4,69 @@ on:
44
repository_dispatch:
55
types: [batch-release-pr]
66

7+
env:
8+
HEAD_BRANCH_NAME: ${{ github.event.client_payload.package }}-${{ github.run_id }}-${{ github.run_attempt }}
9+
710
jobs:
811
create_batch_release_branch:
912
runs-on: ubuntu-latest
1013
permissions:
1114
contents: write # Grants write permission to create a branch.
12-
env:
13-
BRANCH_NAME: ${{ github.event.client_payload.package }}-${{ github.run_id }}-${{ github.run_attempt }}
1415
outputs:
15-
branch_created: ${{ steps.check-branch-exists.outputs.exists }}
16+
head_branch_created: ${{ steps.check-branch-exists.outputs.exists }}
17+
release_branch: ${{ steps.create-branch.outputs.release_branch }} # e.g. release-go_router-17.2.2, returned by branches-for-batch-release tool.
18+
env:
19+
GITHUB_TOKEN: ${{ secrets.FLUTTERGITHUBBOT_TOKEN }}
1620
steps:
1721
- name: checkout repository
1822
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd
23+
with:
24+
token: ${{ secrets.FLUTTERGITHUBBOT_TOKEN }}
1925
- name: "Install Flutter"
2026
uses: ./.github/workflows/internals/install_flutter
2127
- name: Set up tools
2228
run: dart pub get
2329
working-directory: ${{ github.workspace }}/script/tool
24-
# This step is to create a branch for batch release
25-
# A branch may not be created if there is nothing to release.
30+
# This step is to create branches for a batch release
31+
# Branches may not be created if there is nothing to release.
2632
# In that case, the workflow will exit and complete successfully.
2733
- name: create batch release branch
34+
id: create-branch
2835
run: |
2936
git config --global user.name "flutteractionsbot"
3037
git config --global user.email "fluttergithubbot@gmail.com"
31-
dart ./script/tool/lib/src/main.dart branch-for-batch-release --packages=${GITHUB_EVENT_CLIENT_PAYLOAD_PACKAGE} --branch=${BRANCH_NAME} --remote=origin
38+
dart ./script/tool/lib/src/main.dart branches-for-batch-release --packages=${GITHUB_EVENT_CLIENT_PAYLOAD_PACKAGE} --branch=${HEAD_BRANCH_NAME} --remote=origin
3239
env:
3340
GITHUB_EVENT_CLIENT_PAYLOAD_PACKAGE: ${{ github.event.client_payload.package }}
3441
- name: Check if branch was created
3542
id: check-branch-exists
3643
run: |
37-
if git show-ref --verify --quiet refs/heads/${BRANCH_NAME}; then
44+
if git show-ref --verify --quiet refs/heads/${HEAD_BRANCH_NAME}; then
3845
echo "exists=true" >> $GITHUB_OUTPUT
3946
else
4047
echo "exists=false" >> $GITHUB_OUTPUT
4148
fi
4249
4350
create_release_pr:
4451
needs: create_batch_release_branch
45-
if: needs.create_batch_release_branch.outputs.branch_created == 'true'
52+
if: needs.create_batch_release_branch.outputs.head_branch_created == 'true'
4653
runs-on: ubuntu-latest
4754
permissions:
4855
# The create-pull-request action needs both content and pull-requests permissions.
4956
pull-requests: write
5057
contents: write
5158
env:
52-
BRANCH_NAME: ${{ github.event.client_payload.package }}-${{ github.run_id }}-${{ github.run_attempt }}
59+
GITHUB_TOKEN: ${{ secrets.FLUTTERGITHUBBOT_TOKEN }}
5360
steps:
5461
- name: checkout repository
5562
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd
5663
with:
57-
ref: ${{ env.BRANCH_NAME }}
64+
ref: ${{ env.HEAD_BRANCH_NAME }}
5865
- name: Create batch release PR
59-
env:
60-
GITHUB_TOKEN: ${{ secrets.FLUTTERGITHUBBOT_TOKEN }}
6166
run: |
6267
gh pr create \
63-
--base "release-${{ github.event.client_payload.package }}" \
64-
--head "${{ env.BRANCH_NAME }}" \
68+
--base "${{ needs.create_batch_release_branch.outputs.release_branch }}" \
69+
--head "${{ env.HEAD_BRANCH_NAME }}" \
6570
--title "[${{ github.event.client_payload.package }}] Batch release" \
6671
--body "This PR was created automatically to batch release the \`${{ github.event.client_payload.package }}\`."
6772

.github/workflows/release_from_branches.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ name: Batch Release
22
on:
33
push:
44
branches:
5-
- 'release-go_router'
5+
- 'release-go_router-*'
66
permissions:
77
# Release needs to push a tag back to the repo.
88
contents: write

.github/workflows/sync_release_pr.yml

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ on:
44
push:
55
branches:
66
# As packages opt into batched releases, they need to be added here
7-
- 'release-go_router'
7+
- 'release-go_router-*'
88

99
jobs:
1010
create_sync_pr:
@@ -35,10 +35,14 @@ jobs:
3535
exit 0
3636
fi
3737
38-
# 3. Create the PR directly
38+
# 3. Extract release name without version for label
39+
BRANCH_NAME="${{ github.ref_name }}"
40+
RELEASE_NAME="${BRANCH_NAME%-*}"
41+
42+
# 4. Create the PR directly
3943
gh pr create \
4044
--base "main" \
4145
--head "${{ github.ref_name }}" \
4246
--title "Sync ${{ github.ref_name }} to main" \
4347
--body "This automated PR syncs the changes from the release branch ${{ github.ref_name }} back to the main branch." \
44-
--label "override: post-${{ github.ref_name }}"
48+
--label "override: post-${RELEASE_NAME}"

script/tool/lib/src/branch_for_batch_release_command.dart renamed to script/tool/lib/src/branches_for_batch_release_command.dart

Lines changed: 48 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,10 @@ import 'common/repository_package.dart';
1818
const int _kExitPackageMalformed = 3;
1919
const int _kGitFailedToPush = 4;
2020

21-
/// A command to create a remote branch with release changes for a single package.
22-
class BranchForBatchReleaseCommand extends PackageCommand {
23-
/// Creates a new `branch-for-batch-release` command.
24-
BranchForBatchReleaseCommand(
21+
/// A command to create remote branches with release changes for a single package.
22+
class BranchesForBatchReleaseCommand extends PackageCommand {
23+
/// Creates a new `branches-for-batch-release` command.
24+
BranchesForBatchReleaseCommand(
2525
super.packagesDir, {
2626
super.processRunner,
2727
super.platform,
@@ -42,10 +42,10 @@ class BranchForBatchReleaseCommand extends PackageCommand {
4242
}
4343

4444
@override
45-
final String name = 'branch-for-batch-release';
45+
final String name = 'branches-for-batch-release';
4646

4747
@override
48-
final String description = 'Creates a release PR for a single package.';
48+
final String description = 'Creates release branches for a single package.';
4949

5050
@override
5151
Future<void> run() async {
@@ -97,7 +97,17 @@ class BranchForBatchReleaseCommand extends PackageCommand {
9797
return;
9898
}
9999

100-
await _generateCommitAndBranch(
100+
final releaseBranchName =
101+
'release-${package.directory.basename}-${releaseInfo.newVersion}';
102+
103+
await _createAndPushReleaseBranch(
104+
git: repository,
105+
package: package,
106+
releaseBranchName: releaseBranchName,
107+
remoteName: remoteName,
108+
);
109+
110+
await _createHeadBranchAndCommit(
101111
git: repository,
102112
package: package,
103113
branchName: branchName,
@@ -145,7 +155,37 @@ class BranchForBatchReleaseCommand extends PackageCommand {
145155
/// remove the pending changelog files, stage the changes, and commit them.
146156
///
147157
/// Throws a [ToolExit] if any of the steps fail.
148-
Future<void> _generateCommitAndBranch({
158+
Future<void> _createAndPushReleaseBranch({
159+
required GitDir git,
160+
required RepositoryPackage package,
161+
required String releaseBranchName,
162+
required String remoteName,
163+
}) async {
164+
print(' Creating release branch "$releaseBranchName"...');
165+
final io.ProcessResult releaseBranchResult = await git.runCommand(<String>[
166+
'branch',
167+
releaseBranchName,
168+
]);
169+
if (releaseBranchResult.exitCode != 0) {
170+
printError(
171+
'Failed to create release branch $releaseBranchName: ${releaseBranchResult.stderr}',
172+
);
173+
throw ToolExit(_kGitFailedToPush);
174+
}
175+
176+
await _pushBranch(git, remoteName, releaseBranchName);
177+
178+
final String? githubOutput = platform.environment['GITHUB_OUTPUT'];
179+
if (githubOutput != null && githubOutput.isNotEmpty) {
180+
final File file = package.directory.fileSystem.file(githubOutput);
181+
file.writeAsStringSync(
182+
'release_branch=$releaseBranchName\n',
183+
mode: io.FileMode.append,
184+
);
185+
}
186+
}
187+
188+
Future<void> _createHeadBranchAndCommit({
149189
required GitDir git,
150190
required RepositoryPackage package,
151191
required String branchName,

script/tool/lib/src/main.dart

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import 'package:file/file.dart';
99
import 'package:file/local.dart';
1010

1111
import 'analyze_command.dart';
12-
import 'branch_for_batch_release_command.dart';
12+
import 'branches_for_batch_release_command.dart';
1313
import 'build_examples_command.dart';
1414
import 'common/core.dart';
1515
import 'create_all_packages_app_command.dart';
@@ -92,7 +92,7 @@ void main(List<String> args) {
9292
..addCommand(UpdateMinSdkCommand(packagesDir))
9393
..addCommand(UpdateReleaseInfoCommand(packagesDir))
9494
..addCommand(VersionCheckCommand(packagesDir))
95-
..addCommand(BranchForBatchReleaseCommand(packagesDir));
95+
..addCommand(BranchesForBatchReleaseCommand(packagesDir));
9696

9797
commandRunner.run(args).catchError((Object e) {
9898
final toolExit = e as ToolExit;

script/tool/lib/src/publish_command.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -233,7 +233,7 @@ class PublishCommand extends PackageLoopingCommand {
233233
// the opt-in flag and that the package name matches the branch suffix.
234234
// Example: branch "release-go_router" matches package "go_router".
235235
if (!isBatchReleasePackage ||
236-
batchReleaseBranchName != 'release-$packageName') {
236+
!batchReleaseBranchName.startsWith('release-$packageName-')) {
237237
continue;
238238
}
239239
}

script/tool/lib/src/repo_package_info_check_command.dart

Lines changed: 3 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,6 @@
22
// Use of this source code is governed by a BSD-style license that can be
33
// found in the LICENSE file.
44

5-
import 'dart:io' as io;
6-
75
import 'package:file/file.dart';
86
import 'package:yaml/yaml.dart';
97

@@ -274,13 +272,6 @@ class RepoPackageInfoCheckCommand extends PackageLoopingCommand {
274272
),
275273
);
276274

277-
errors.addAll(
278-
await _validateRemoteReleaseBranch(
279-
packageName,
280-
isBatchRelease: isBatchRelease,
281-
),
282-
);
283-
284275
if (isBatchRelease &&
285276
(package.parsePubspec().version?.isPreRelease ?? false)) {
286277
errors.add(
@@ -292,35 +283,6 @@ class RepoPackageInfoCheckCommand extends PackageLoopingCommand {
292283
return errors;
293284
}
294285

295-
Future<List<String>> _validateRemoteReleaseBranch(
296-
String packageName, {
297-
required bool isBatchRelease,
298-
}) async {
299-
final errors = <String>[];
300-
// Verify release branch exists on remote flutter/packages if it is a batch release package.
301-
final io.ProcessResult result = await (await gitDir).runCommand(<String>[
302-
'ls-remote',
303-
'--exit-code',
304-
'--heads',
305-
'origin',
306-
'release-$packageName',
307-
], throwOnError: false);
308-
final branchExists = result.exitCode == 0;
309-
if (isBatchRelease && !branchExists) {
310-
errors.add(
311-
'Branch release-$packageName does not exist on remote flutter/packages\n'
312-
'See https://github.com/flutter/flutter/blob/master/docs/ecosystem/release/README.md#batch-release',
313-
);
314-
}
315-
// Allow branch to exist on remote flutter/packages for non-batch release packages.
316-
// Otherwise, it will be hard to opt package out of batch release.
317-
//
318-
// Enforcing this will run into a deadlock where the ci in the PR to opts out of batch release
319-
// will require removal of the release branch. but removing the release branch will immediately break
320-
// the latest main.
321-
return errors;
322-
}
323-
324286
List<String> _validateSpecificBatchWorkflow(
325287
String packageName, {
326288
required Directory workflowDir,
@@ -426,7 +388,7 @@ class RepoPackageInfoCheckCommand extends PackageLoopingCommand {
426388
if (push is YamlMap) {
427389
final branches = push['branches'] as YamlList?;
428390
if (branches is YamlList) {
429-
if (branches.contains('release-$packageName')) {
391+
if (branches.contains('release-$packageName-*')) {
430392
hasTrigger = true;
431393
}
432394
}
@@ -435,12 +397,12 @@ class RepoPackageInfoCheckCommand extends PackageLoopingCommand {
435397

436398
if (isBatchRelease && !hasTrigger) {
437399
errors.add(
438-
'Missing trigger for release-$packageName in .github/workflows/$workflowName\n'
400+
'Missing trigger for release-$packageName-* in .github/workflows/$workflowName\n'
439401
'See https://github.com/flutter/flutter/blob/master/docs/ecosystem/release/README.md#batch-release',
440402
);
441403
} else if (!isBatchRelease && hasTrigger) {
442404
errors.add(
443-
'Unexpected trigger for release-$packageName in .github/workflows/$workflowName\n',
405+
'Unexpected trigger for release-$packageName-* in .github/workflows/$workflowName\n',
444406
);
445407
}
446408
return errors;

0 commit comments

Comments
 (0)