| // Copyright (c) 2022, 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. |
| |
| import 'dart:async'; |
| import 'dart:convert'; |
| import 'dart:io'; |
| |
| import 'package:git/git.dart'; |
| |
| import 'repo_tweak.dart'; |
| import 'tweaks/auto_publish_tweak.dart'; |
| import 'tweaks/dependabot_tweak.dart'; |
| import 'tweaks/github_action_tweak.dart'; |
| import 'tweaks/mono_repo_tweak.dart'; |
| import 'tweaks/no_reponse_tweak.dart'; |
| import 'utils.dart'; |
| |
| final allTweaks = Set<RepoTweak>.unmodifiable([ |
| AutoPublishTweak(), |
| DependabotTweak(), |
| GitHubActionTweak(), |
| MonoRepoTweak(), |
| NoResponseTweak(), |
| ]); |
| |
| Future<void> runFix({ |
| required String slug, |
| required bool deleteTemp, |
| required String? reviewer, |
| List<RepoTweak>? tweaks, |
| List<String> labels = const [], |
| bool dryRun = false, |
| }) async { |
| await withSystemTemp( |
| deleteTemp: deleteTemp, |
| (tempDir, runKey) async { |
| await cloneGitHubRepoToPath(slug, tempDir.path); |
| |
| final result = await fixAll( |
| slug, |
| tempDir, |
| tweaks: tweaks, |
| ); |
| |
| final fixes = result.entries |
| .where((element) => element.value.fixes.isNotEmpty) |
| .map((e) => e.key.id) |
| .toList() |
| ..sort(); |
| |
| if (fixes.isEmpty) { |
| printHeader('No changes! All done!'); |
| return; |
| } |
| |
| printHeader('Fixes:'); |
| for (var entry in result.entries) { |
| print(entry.key.id); |
| print(const JsonEncoder.withIndent(' ').convert(entry.value.fixes)); |
| } |
| |
| final gitDir = await GitDir.fromExisting(tempDir.path); |
| |
| await gitDir.exec( |
| 'Creating a working branch', |
| ['checkout', '-b', runKey], |
| ); |
| |
| await gitDir.exec( |
| 'Add all files to index', |
| ['add', '-v', '.'], |
| ); |
| |
| await gitDir.exec( |
| 'Commit changes', |
| [ |
| 'commit', |
| '-am', |
| ''' |
| $packageName fixes |
| |
| ${fixes.join(', ')} |
| ''' |
| ], |
| ); |
| |
| await gitDir.exec( |
| 'Changes:', |
| ['--no-pager', 'show'], |
| ); |
| |
| await runProc( |
| 'Creating pull request', |
| 'gh', |
| [ |
| 'pr', |
| 'create', |
| '--fill', |
| '--title', |
| 'blast repo changes: ${fixes.join(', ')}', |
| '--body', |
| 'This PR contains changes created by the blast repo tool.\n\n' |
| '${fixes.map((fix) => '- `$fix`').join('\n')}', |
| '--repo', |
| slug, |
| if (reviewer != null) ...['--reviewer', reviewer], |
| for (final label in labels) ...['--label', label], |
| ], |
| workingDirectory: tempDir.path, |
| skipExecution: dryRun, |
| ); |
| }, |
| ); |
| } |
| |
| Future<Map<RepoTweak, FixResult>> fixAll( |
| String repoSlug, |
| Directory checkout, { |
| List<RepoTweak>? tweaks, |
| }) async { |
| tweaks ??= allTweaks |
| .where((tweak) => tweak.shouldRunByDefault(checkout, repoSlug)) |
| .toList(); |
| |
| return { |
| for (var tweak in tweaks) |
| tweak: await _safeRun(repoSlug, checkout, tweak.id, tweak.fix), |
| }; |
| } |
| |
| Future<T> _safeRun<T>( |
| String repoSlug, |
| Directory checkout, |
| String id, |
| FutureOr<T> Function(Directory, String repoSlug) action, |
| ) async { |
| printHeader('Running "$id"'); |
| try { |
| return await action(checkout, repoSlug); |
| } catch (_) { |
| printError(' Error running $id'); |
| rethrow; |
| } |
| } |