Make the pub roller bot re-generate gradle lockfiles (#149355)

Fixes https://github.com/flutter/flutter/issues/142475
This commit is contained in:
Gray Mackall 2024-08-26 09:44:19 -07:00 committed by GitHub
parent 6608936e6d
commit 7362d07cb0
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 58 additions and 28 deletions

View File

@ -5,6 +5,8 @@
import 'dart:convert'; import 'dart:convert';
import 'dart:io' as io; import 'dart:io' as io;
import 'package:file/file.dart';
import 'package:meta/meta.dart';
import 'package:process/process.dart'; import 'package:process/process.dart';
import 'git.dart'; import 'git.dart';
@ -93,6 +95,7 @@ This PR was generated by the automated
log('Packages are already at latest.'); log('Packages are already at latest.');
return; return;
} }
await generateGradleLockfiles(await framework.checkoutDirectory);
await pushBranch(); await pushBranch();
await createPr(repository: await framework.checkoutDirectory); await createPr(repository: await framework.checkoutDirectory);
await authLogout(); await authLogout();
@ -135,6 +138,15 @@ This PR was generated by the automated
return true; return true;
} }
@visibleForTesting
Future<void> generateGradleLockfiles(Directory repoRoot) async {
await framework.runDart(<String>[
'${repoRoot.path}/dev/tools/bin/generate_gradle_lockfiles.dart',
'--no-gradle-generation',
'--no-exclusion',
]);
}
Future<void> pushBranch() async { Future<void> pushBranch() async {
final String projectName = framework.mirrorRemote!.url.split(r'/').last; final String projectName = framework.mirrorRemote!.url.split(r'/').last;
// Encode the token into the remote URL for authentication to work // Encode the token into the remote URL for authentication to work

View File

@ -601,6 +601,13 @@ class FrameworkRepository extends Repository {
]); ]);
} }
Future<io.ProcessResult> runDart(List<String> args) async {
return processManager.run(<String>[
fileSystem.path.join((await checkoutDirectory).path, 'bin', 'dart'),
...args,
]);
}
Future<io.ProcessResult> runFlutter(List<String> args) async { Future<io.ProcessResult> runFlutter(List<String> args) async {
await _ensureToolReady(); await _ensureToolReady();
return processManager.run(<String>[ return processManager.run(<String>[

View File

@ -432,6 +432,12 @@ void main() {
'rev-parse', 'rev-parse',
'HEAD', 'HEAD',
], stdout: '000deadbeef'), ], stdout: '000deadbeef'),
const FakeCommand(command: <String>[
'$checkoutsParentDirectory/flutter_conductor_checkouts/framework/bin/dart',
'$checkoutsParentDirectory/flutter_conductor_checkouts/framework/dev/tools/bin/generate_gradle_lockfiles.dart',
'--no-gradle-generation',
'--no-exclusion',
]),
const FakeCommand(command: <String>[ const FakeCommand(command: <String>[
'git', 'git',
'push', 'push',

View File

@ -2,12 +2,12 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
// For each directory specified in the stdin, this script generates: // For `android` directory in the repo, this script generates:
// 1. The top-level build.gradle (android/build.gradle). // 1. The top-level build.gradle (android/build.gradle).
// 2. The top level settings.gradle (android/settings.gradle). // 2. The top level settings.gradle (android/settings.gradle).
// 3. The gradle wrapper file (android/gradle/wrapper/gradle-wrapper.properties). // 3. The gradle wrapper file (android/gradle/wrapper/gradle-wrapper.properties).
// Then it generate the lockfiles for each Gradle project. // Then it generate the lockfiles for each Gradle project.
// To regenerate these files, run `find . -type d -name 'android' | dart dev/tools/bin/generate_gradle_lockfiles.dart`. // To regenerate these files, run `dart dev/tools/bin/generate_gradle_lockfiles.dart`.
import 'dart:collection'; import 'dart:collection';
import 'dart:io'; import 'dart:io';
@ -15,16 +15,14 @@ import 'dart:io';
import 'package:args/args.dart'; import 'package:args/args.dart';
import 'package:file/file.dart'; import 'package:file/file.dart';
import 'package:file/local.dart'; import 'package:file/local.dart';
import 'package:path/path.dart' as path;
import 'package:yaml/yaml.dart'; import 'package:yaml/yaml.dart';
void main(List<String> arguments) { void main(List<String> arguments) {
const String usageMessage = "Usage: find . -type d -name 'android' | dart dev/tools/bin/generate_gradle_lockfiles.dart\n" const String usageMessage = "If you don't wish to re-generate the "
'If you would rather enter the files manually, just run `dart dev/tools/bin/generate_gradle_lockfiles.dart`,\n' 'settings.gradle, build.gradle, and gradle-wrapper.properties files,\n'
"enter the absolute paths to the app's android directory, then press CTRL-D.\n"
"If you don't wish to re-generate the settings.gradle, build.gradle, and gradle-wrapper.properties files,\n"
'add the flag `--no-gradle-generation`.\n' 'add the flag `--no-gradle-generation`.\n'
'This tool automatically excludes a set of android subdirectories, defined at dev/tools/bin/config/lockfile_exclusion.yaml.\n' 'This tool automatically excludes a set of android subdirectories, '
'defined at dev/tools/bin/config/lockfile_exclusion.yaml.\n'
'To disable this behavior, run with `--no-exclusion`.\n'; 'To disable this behavior, run with `--no-exclusion`.\n';
final ArgParser argParser = ArgParser() final ArgParser argParser = ArgParser()
@ -56,10 +54,25 @@ void main(List<String> arguments) {
final bool useExclusion = (args['exclusion'] as bool?) ?? true; final bool useExclusion = (args['exclusion'] as bool?) ?? true;
const FileSystem fileSystem = LocalFileSystem(); const FileSystem fileSystem = LocalFileSystem();
final List<String> androidDirectories = getFilesFromStdin();
final File exclusionFile = fileSystem final Directory repoRoot = (() {
.currentDirectory.childDirectory('dev').childDirectory('tools').childDirectory('bin') final String repoRootPath = exec(
'git',
const <String>['rev-parse', '--show-toplevel'],
).trim();
final Directory repoRoot = fileSystem.directory(repoRootPath);
if (!repoRoot.existsSync()) {
throw StateError("Expected $repoRoot to exist but it didn't!");
}
return repoRoot;
})();
final Iterable<Directory> androidDirectories = discoverAndroidDirectories(repoRoot);
final File exclusionFile = repoRoot
.childDirectory('dev')
.childDirectory('tools')
.childDirectory('bin')
.childDirectory('config') .childDirectory('config')
.childFile('lockfile_exclusion.yaml'); .childFile('lockfile_exclusion.yaml');
@ -77,10 +90,7 @@ void main(List<String> arguments) {
print('Running without exclusion.'); print('Running without exclusion.');
} }
for (final Directory androidDirectory in androidDirectories) {
for (final String androidDirectoryPath in androidDirectories) {
final Directory androidDirectory = fileSystem.directory(path.normalize(androidDirectoryPath));
if (!androidDirectory.existsSync()) { if (!androidDirectory.existsSync()) {
throw '$androidDirectory does not exist'; throw '$androidDirectory does not exist';
} }
@ -188,19 +198,7 @@ void main(List<String> arguments) {
} }
} }
List<String> getFilesFromStdin() { String exec(
final List<String> files = <String>[];
while (true) {
final String? file = stdin.readLineSync();
if (file == null) {
break;
}
files.add(file);
}
return files;
}
void exec(
String cmd, String cmd,
List<String> args, { List<String> args, {
String? workingDirectory, String? workingDirectory,
@ -210,6 +208,7 @@ void exec(
throw ProcessException( throw ProcessException(
cmd, args, '${result.stdout}${result.stderr}', result.exitCode); cmd, args, '${result.stdout}${result.stderr}', result.exitCode);
} }
return result.stdout as String;
} }
const String rootGradleFileContent = r''' const String rootGradleFileContent = r'''
@ -300,3 +299,9 @@ zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.3-all.zip distributionUrl=https\://services.gradle.org/distributions/gradle-8.3-all.zip
'''; ''';
Iterable<Directory> discoverAndroidDirectories(Directory repoRoot) {
return repoRoot.listSync(recursive: true)
.whereType<Directory>()
.where((FileSystemEntity entity) => entity.basename == 'android');
}