-
Notifications
You must be signed in to change notification settings - Fork 7
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add
package:trebuchet
to repo. (#289)
Moving over from https://github.com/mosuem/merger/. We might want to move the issue transfer tool from `repo_manage` to this tool as well, it would be cleaner. --- - [x] I’ve reviewed the contributor guide and applied the relevant portions to this PR. <details> <summary>Contribution guidelines:</summary><br> - See our [contributor guide](https://github.com/dart-lang/.github/blob/main/CONTRIBUTING.md) for general expectations for PRs. - Larger or significant changes should be discussed in an issue before creating a PR. - Contributions to our repos should follow the [Dart style guide](https://dart.dev/guides/language/effective-dart) and use `dart format`. - Most changes should add an entry to the changelog and may need to [rev the pubspec package version](https://github.com/dart-lang/sdk/blob/main/docs/External-Package-Maintenance.md#making-a-change). - Changes to packages require [corresponding tests](https://github.com/dart-lang/.github/blob/main/CONTRIBUTING.md#Testing). Note that many Dart repos have a weekly cadence for reviewing PRs - please allow for some latency before initial review feedback. </details> --------- Co-authored-by: Devon Carew <devoncarew@google.com>
- Loading branch information
1 parent
dd8d12a
commit 5da8a7a
Showing
5 changed files
with
257 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
## What's this? | ||
|
||
This is a tool to move existing packages into monorepos. | ||
|
||
## Running this tool | ||
|
||
```bash | ||
dart run bin/trebuchet.dart \ | ||
--input-name coverage \ | ||
--branch-name master \ | ||
--input-path ~/projects/coverage/ \ | ||
--target-path ~/projects/tools/ \ | ||
--git-filter-repo ~/tools/git-filter-repo | ||
``` | ||
|
||
This basically executes the instructions at https://github.com/dart-lang/ecosystem/wiki/Merging-existing-repos-into-a-monorepo |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
include: package:dart_flutter_team_lints/analysis_options.yaml | ||
|
||
linter: | ||
rules: | ||
- prefer_final_locals |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,219 @@ | ||
// Copyright (c) 2024, 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:io'; | ||
|
||
import 'package:args/args.dart'; | ||
import 'package:path/path.dart' as p; | ||
|
||
Future<void> main(List<String> arguments) async { | ||
final argParser = ArgParser() | ||
..addOption( | ||
'input-name', | ||
help: 'Name of the package which should be transferred to a mono-repo', | ||
) | ||
..addOption( | ||
'input-path', | ||
help: 'Path to the package which should be transferred to a mono-repo', | ||
) | ||
..addOption( | ||
'target-path', | ||
help: 'Path to the mono-repo', | ||
) | ||
..addOption( | ||
'branch-name', | ||
help: 'The name of the main branch on the input repo', | ||
defaultsTo: 'main', | ||
) | ||
..addOption( | ||
'git-filter-repo', | ||
help: 'Path to the git-filter-repo tool', | ||
) | ||
..addFlag( | ||
'dry-run', | ||
help: 'Do not actually execute any of the steps', | ||
defaultsTo: false, | ||
) | ||
..addFlag( | ||
'help', | ||
abbr: 'h', | ||
help: 'Prints usage info', | ||
negatable: false, | ||
); | ||
|
||
String? input; | ||
String? inputPath; | ||
String? targetPath; | ||
String? branchName; | ||
String? gitFilterRepo; | ||
bool dryRun; | ||
try { | ||
final parsed = argParser.parse(arguments); | ||
if (parsed.flag('help')) { | ||
print(argParser.usage); | ||
exit(0); | ||
} | ||
|
||
input = parsed.option('input-name')!; | ||
inputPath = parsed.option('input-path')!; | ||
targetPath = parsed.option('target-path')!; | ||
branchName = parsed.option('branch-name')!; | ||
gitFilterRepo = parsed.option('git-filter-repo')!; | ||
dryRun = parsed.flag('dry-run'); | ||
} catch (e) { | ||
print(e); | ||
print(''); | ||
print(argParser.usage); | ||
exit(1); | ||
} | ||
|
||
final trebuchet = Trebuchet( | ||
input: input, | ||
inputPath: inputPath, | ||
targetPath: targetPath, | ||
branchName: branchName, | ||
gitFilterRepo: gitFilterRepo, | ||
dryRun: dryRun, | ||
); | ||
|
||
await trebuchet.hurl(); | ||
} | ||
|
||
class Trebuchet { | ||
final String input; | ||
final String inputPath; | ||
final String targetPath; | ||
final String branchName; | ||
final String gitFilterRepo; | ||
final bool dryRun; | ||
|
||
Trebuchet({ | ||
required this.input, | ||
required this.inputPath, | ||
required this.targetPath, | ||
required this.branchName, | ||
required this.gitFilterRepo, | ||
required this.dryRun, | ||
}); | ||
|
||
Future<void> hurl() async { | ||
print('Check existence of python3 on path'); | ||
await runProcess( | ||
'python3', | ||
['--version'], | ||
inTarget: false, | ||
); | ||
|
||
print('Start moving package'); | ||
|
||
print('Rename to `pkgs/`'); | ||
await filterRepo(['--path-rename', ':pkgs/$input/']); | ||
|
||
print('Prefix tags'); | ||
await filterRepo(['--tag-rename', ':$input-']); | ||
|
||
print('Replace issue references in commit messages'); | ||
await inTempDir((tempDirectory) async { | ||
final regexFile = File(p.join(tempDirectory.path, 'expressions.txt')); | ||
await regexFile.create(); | ||
await regexFile.writeAsString('regex:#(\\d)==>dart-lang/$input#\\1'); | ||
await filterRepo(['--replace-message', regexFile.path]); | ||
}); | ||
|
||
print('Create branch at target'); | ||
await runProcess('git', ['checkout', '-b', 'merge-$input-package']); | ||
|
||
print('Add a remote for the local clone of the moving package'); | ||
await runProcess( | ||
'git', | ||
['remote', 'add', '${input}_package', inputPath], | ||
); | ||
await runProcess('git', ['fetch', '${input}_package']); | ||
|
||
print('Merge branch into monorepo'); | ||
await runProcess( | ||
'git', | ||
[ | ||
'merge', | ||
'--allow-unrelated-histories', | ||
'${input}_package/$branchName', | ||
'-m', | ||
'Merge package:$input into shared tool repository' | ||
], | ||
); | ||
|
||
final shouldPush = getInput('Push to remote? (y/N)'); | ||
|
||
if (shouldPush) { | ||
print('Push to remote'); | ||
await runProcess( | ||
'git', | ||
['push', '--set-upstream', 'origin', 'merge-$input-package'], | ||
); | ||
} | ||
|
||
print('DONE!'); | ||
print(''' | ||
Steps left to do: | ||
- Move and fix workflow files | ||
${shouldPush ? '' : '- Run `git push --set-upstream origin merge-$input-package` in the monorepo directory'} | ||
- Disable squash-only in GitHub settings, and merge with a fast forward merge to the main branch, enable squash-only in GitHub settings. | ||
- Push tags to github using `git tag --list '$input*' | xargs git push origin` | ||
- Follow up with a PR adding links to the top-level readme table. | ||
- Add a commit to https://github.com/dart-lang/$input/ with it's readme pointing to the monorepo. | ||
- Update the auto-publishing settings on pub.dev/packages/$input. | ||
- Archive https://github.com/dart-lang/$input/. | ||
'''); | ||
} | ||
|
||
bool getInput(String question) { | ||
print(question); | ||
final line = stdin.readLineSync()?.toLowerCase(); | ||
return line == 'y' || line == 'yes'; | ||
} | ||
|
||
Future<void> runProcess( | ||
String executable, | ||
List<String> arguments, { | ||
bool inTarget = true, | ||
}) async { | ||
final workingDirectory = inTarget ? targetPath : inputPath; | ||
print('----------'); | ||
print('Running `$executable $arguments` in $workingDirectory'); | ||
if (!dryRun) { | ||
final processResult = await Process.run( | ||
executable, | ||
arguments, | ||
workingDirectory: workingDirectory, | ||
); | ||
print('stdout:'); | ||
print(processResult.stdout); | ||
if ((processResult.stderr as String).isNotEmpty) { | ||
print('stderr:'); | ||
print(processResult.stderr); | ||
} | ||
if (processResult.exitCode != 0) { | ||
throw ProcessException(executable, arguments); | ||
} | ||
} else { | ||
print('Not running, as --dry-run is set.'); | ||
} | ||
print('=========='); | ||
} | ||
|
||
Future<void> filterRepo(List<String> args) async { | ||
await runProcess( | ||
'python3', | ||
[p.relative(gitFilterRepo, from: inputPath), ...args], | ||
inTarget: false, | ||
); | ||
} | ||
} | ||
|
||
Future<void> inTempDir(Future<void> Function(Directory temp) f) async { | ||
final tempDirectory = await Directory.systemTemp.createTemp(); | ||
await f(tempDirectory); | ||
await tempDirectory.delete(recursive: true); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
name: trebuchet | ||
description: A tool for hurling packages into monorepos. | ||
|
||
publish_to: none | ||
|
||
environment: | ||
sdk: ^3.3.0 | ||
|
||
dependencies: | ||
args: ^2.5.0 | ||
path: ^1.9.0 | ||
|
||
dev_dependencies: | ||
dart_flutter_team_lints: ^3.2.0 | ||
lints: ^4.0.0 | ||
test: ^1.24.0 |