dart-sdk/tools/manage_deps.dart
Devon Carew c84d0376cd [deps] update the rev script to handle 'main' branches
Also rev package:csslib and package:html.


csslib (7054945..f33d632):
  f33d632  2023-01-28  Devon Carew  switch to using package:dart_flutter_team_lints (#161)
  c0097a0  2023-01-28  Devon Carew  Update README.md (#158)
  0d985fb  2023-01-28  dependabot[bot]  Bump dart-lang/setup-dart from 1.3 to 1.4 (#164)
  56d1152  2023-01-28  dependabot[bot]  Bump actions/checkout from 3.2.0 to 3.3.0 (#163)
  46d2c57  2023-01-28  Devon Carew  Update test-package.yml (#165)
  a7d17bc  2023-01-26  Kevin Moore  all the cleanup (#155)

html (3dd00b0..f118e00):
  f118e00  2023-01-30  Devon Carew  lint with dart_flutter_team_lints (#201)
  52d9185  2023-01-30  Devon Carew  updates from #158 (#202)
  71d3e71  2023-01-30  Ron Booth  fixed issue #157 (querySelector fails), and added test for it (#158)
  9ab8b28  2023-01-30  dependabot[bot]  Bump actions/checkout from 3.2.0 to 3.3.0 (#200)
  fe3fbf6  2023-01-30  dependabot[bot]  Bump dart-lang/setup-dart from 1.3 to 1.4 (#199)
  776daf5  2023-01-30  Devon Carew  Update test-package.yml (#198)
  a5be27f  2023-01-27  Devon Carew  finish work for avoid_dynamic_calls (#196)

Change-Id: If03552028f30b8dfd6a227674aa161e43a05e11f
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/280129
Reviewed-by: William Hesse <whesse@google.com>
Reviewed-by: Sigurd Meldgaard <sigurdm@google.com>
Commit-Queue: Devon Carew <devoncarew@google.com>
2023-02-06 18:04:11 +00:00

283 lines
8.1 KiB
Dart
Executable file

#!tools/sdks/dart-sdk/bin/dart
// Copyright (c) 2021, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
/// Helps rolling dependency to the newest version available
/// (or a target version).
///
/// Usage: ./tools/manage_deps.dart bump <dependency> [--branch <branch>] [--target <ref>]
///
/// This will:
/// 0. Check that git is clean
/// 1. Create branch `<branch> ?? bump_<dependency>`
/// 2. Update `DEPS` for `<dependency>`
/// 3. Create a commit with `git log` of imported commits in the message.
/// 4. Prompt to create a CL
// @dart = 2.13
library bump;
import 'dart:io';
import 'package:args/command_runner.dart';
import 'package:path/path.dart' as p;
class BumpCommand extends Command<int> {
@override
String get description => '''
Bump a dependency in DEPS and create a CL
This will:
0. Check that git is clean
1. Create branch `<branch> ?? bump_<dependency>`
2. Update `DEPS` for `<dependency>`
3. Create a commit with `git log` of imported commits in the message.
4. Prompt to create a CL
''';
@override
String get invocation =>
'./tools/manage_deps.dart bump <path/to/dependency> <options>';
BumpCommand() {
argParser.addOption(
'branch',
help: 'The name of the branch where the update is created.',
valueHelp: 'branch-name',
);
argParser.addOption(
'target',
help: 'The git ref to update to.',
valueHelp: 'ref',
);
}
@override
String get name => 'bump';
@override
Future<int> run() async {
final argResults = this.argResults!;
if (argResults.rest.length != 1) {
usageException('No dependency directory given');
}
final status = runProcessForLines(['git', 'status', '--porcelain'],
explanation: 'Checking if your git checkout is clean');
if (status.isNotEmpty) {
print('Note your git checkout is dirty!');
}
final pkgDir = argResults.rest.first;
if (!Directory(pkgDir).existsSync()) {
usageException('No directory $pkgDir');
}
final toUpdate = p.split(pkgDir).last;
final branchName = argResults['branch'] ?? 'bump_$toUpdate';
final exists = runProcessForExitCode(
['git', 'rev-parse', '--verify', branchName],
explanation: 'Checking if branch-name exists');
if (exists == 0) {
print('Branch $branchName already exist - delete it?');
if (!prompt()) {
print('Ok - exiting');
exit(-1);
}
runProcessAssumingSuccess(
['git', 'branch', '-D', branchName],
explanation: 'Deleting existing branch',
);
}
runProcessAssumingSuccess(
['git', 'checkout', '-b', branchName],
explanation: 'Creating branch',
);
final currentRev = runProcessForLines(
['gclient', 'getdep', '-r', p.join('sdk', pkgDir)],
explanation: 'Finding current revision',
).first;
final originUrl = runProcessForLines(
['git', 'config', '--get', 'remote.origin.url'],
workingDirectory: pkgDir,
explanation: 'Finding origin url',
).first;
runProcessAssumingSuccess(
['git', 'fetch', 'origin'],
workingDirectory: pkgDir,
explanation: 'Retrieving updates to $toUpdate',
);
final gitRevParseResult = runProcessForLines([
'git',
'rev-parse',
if (argResults.wasParsed('target'))
argResults['target']
else
'origin/${defaultBranchTarget(pkgDir)}',
], workingDirectory: pkgDir, explanation: 'Finding sha-id');
final target = gitRevParseResult.first;
if (currentRev == target) {
print('Already at $target - nothing to do');
return -1;
}
runProcessAssumingSuccess(
['gclient', 'setdep', '-r', '${p.join('sdk', pkgDir)}@$target'],
explanation: 'Updating $toUpdate',
);
runProcessAssumingSuccess(
['gclient', 'sync', '-D'],
explanation: 'Syncing your deps',
);
runProcessAssumingSuccess(
[
Platform.resolvedExecutable,
'tools/generate_package_config.dart',
],
explanation: 'Updating package config',
);
final gitLogResult = runProcessForLines([
'git',
'log',
'--format=%C(auto) $originUrl/+/%h %s ',
'$currentRev..$target',
], workingDirectory: pkgDir, explanation: 'Listing new commits');
// To avoid github notifying issues in the sdk when it sees #issueid
// we remove all '#' characters.
final cleanedGitLogResult =
gitLogResult.map((x) => x.replaceAll('#', '')).join('\n');
final commitMessage = '''
Bump $toUpdate to $target
Changes:
```
> git log --format="%C(auto) %h %s" ${currentRev.substring(0, 7)}..${target.substring(0, 7)}
$cleanedGitLogResult
```
Diff: $originUrl/+/$currentRev..$target/
''';
runProcessAssumingSuccess(['git', 'commit', '-am', commitMessage],
explanation: 'Committing');
print('Consider updating CHANGELOG.md');
print('Do you want to create a CL?');
if (prompt()) {
await runProcessInteractively(
['git', 'cl', 'upload', '-m', commitMessage],
explanation: 'Creating CL',
);
}
return 0;
}
}
Future<void> main(List<String> args) async {
final runner = CommandRunner<int>(
'manage_deps.dart', 'helps managing the DEPS file',
usageLineLength: 80)
..addCommand(BumpCommand());
try {
exit(await runner.run(args) ?? -1);
} on UsageException catch (e) {
print(e.message);
print(e.usage);
}
}
bool prompt() {
stdout.write('(y/N):');
final answer = stdin.readLineSync() ?? '';
return answer.trim().toLowerCase() == 'y';
}
void printRunningLine(
List<String> cmd, String? explanation, String? workingDirectory) {
stdout.write(
"${explanation ?? 'Running'}: `${cmd.join(' ')}` ${workingDirectory == null ? '' : 'in $workingDirectory'}");
}
void printSuccessTrailer(ProcessResult result, String? onFailure) {
if (result.exitCode == 0) {
stdout.writeln('');
} else {
stdout.writeln(' X');
stderr.write(result.stdout);
stderr.write(result.stderr);
if (onFailure != null) {
print(onFailure);
}
throw Exception();
}
}
void runProcessAssumingSuccess(List<String> cmd,
{String? explanation,
String? workingDirectory,
Map<String, String> environment = const {},
String? onFailure}) {
printRunningLine(cmd, explanation, workingDirectory);
final result = Process.runSync(
cmd[0],
cmd.skip(1).toList(),
workingDirectory: workingDirectory,
environment: environment,
);
printSuccessTrailer(result, onFailure);
}
List<String> runProcessForLines(List<String> cmd,
{String? explanation, String? workingDirectory, String? onFailure}) {
printRunningLine(cmd, explanation, workingDirectory);
final result = Process.runSync(
cmd[0],
cmd.skip(1).toList(),
workingDirectory: workingDirectory,
environment: {'DEPOT_TOOLS_UPDATE': '0'},
);
printSuccessTrailer(result, onFailure);
final output = (result.stdout as String);
return output == '' ? <String>[] : output.split('\n');
}
Future<void> runProcessInteractively(List<String> cmd,
{String? explanation, String? workingDirectory}) async {
printRunningLine(cmd, explanation, workingDirectory);
stdout.writeln('');
final process = await Process.start(cmd[0], cmd.skip(1).toList(),
workingDirectory: workingDirectory, mode: ProcessStartMode.inheritStdio);
final exitCode = await process.exitCode;
if (exitCode != 0) {
throw Exception();
}
}
int runProcessForExitCode(List<String> cmd,
{String? explanation, String? workingDirectory}) {
printRunningLine(cmd, explanation, workingDirectory);
final result = Process.runSync(
cmd[0],
cmd.skip(1).toList(),
workingDirectory: workingDirectory,
);
stdout.writeln(' => ${result.exitCode}');
return result.exitCode;
}
String defaultBranchTarget(String dir) {
var branchNames = Directory(p.join(dir, '.git', 'refs', 'heads'))
.listSync()
.whereType<File>()
.map((f) => p.basename(f.path))
.toSet();
for (var name in ['main', 'master']) {
if (branchNames.contains(name)) {
return name;
}
}
return 'HEAD';
}