blob: db9635e73a308da2d988fc7a40c2a36927fe5d5e [file] [log] [blame]
// Copyright 2014 The Flutter Authors. 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' as io;
import 'package:args/args.dart';
import 'package:conductor_core/conductor_core.dart';
import 'package:conductor_core/packages_autoroller.dart';
import 'package:file/file.dart';
import 'package:file/local.dart';
import 'package:meta/meta.dart' show visibleForTesting;
import 'package:platform/platform.dart';
import 'package:process/process.dart';
const String kTokenOption = 'token';
const String kGithubClient = 'github-client';
const String kMirrorRemote = 'mirror-remote';
const String kUpstreamRemote = 'upstream-remote';
Future<void> main(List<String> args) {
return run(args);
}
@visibleForTesting
Future<void> run(
List<String> args, {
FileSystem fs = const LocalFileSystem(),
ProcessManager processManager = const LocalProcessManager(),
}) async {
final ArgParser parser = ArgParser();
parser.addOption(
kTokenOption,
help: 'Path to GitHub access token file.',
mandatory: true,
);
parser.addOption(
kGithubClient,
help: 'Path to GitHub CLI client. If not provided, it is assumed `gh` is '
'present on the PATH.',
);
parser.addOption(
kMirrorRemote,
help: 'The mirror git remote that the feature branch will be pushed to. '
'Required',
mandatory: true,
);
parser.addOption(
kUpstreamRemote,
help: 'The upstream git remote that the feature branch will be merged to.',
hide: true,
defaultsTo: 'https://github.com/flutter/flutter.git',
);
final ArgResults results;
try {
results = parser.parse(args);
} on FormatException {
io.stdout.writeln('''
Usage:
${parser.usage}
''');
rethrow;
}
final String mirrorUrl = results[kMirrorRemote]! as String;
final String upstreamUrl = results[kUpstreamRemote]! as String;
final String tokenPath = results[kTokenOption]! as String;
final File tokenFile = fs.file(tokenPath);
if (!tokenFile.existsSync()) {
throw ArgumentError(
'Provided token path $tokenPath but no file exists at ${tokenFile.absolute.path}',
);
}
final String token = tokenFile.readAsStringSync().trim();
if (token.isEmpty) {
throw ArgumentError(
'Tried to read a GitHub access token from file ${tokenFile.path} but it was empty',
);
}
final FrameworkRepository framework = FrameworkRepository(
_localCheckouts,
mirrorRemote: Remote.mirror(mirrorUrl),
upstreamRemote: Remote.upstream(upstreamUrl),
);
await PackageAutoroller(
framework: framework,
githubClient: results[kGithubClient] as String? ?? 'gh',
orgName: _parseOrgName(mirrorUrl),
token: token,
processManager: processManager,
).roll();
}
String _parseOrgName(String remoteUrl) {
final RegExp pattern = RegExp(r'^https:\/\/github\.com\/(.*)\/');
final RegExpMatch? match = pattern.firstMatch(remoteUrl);
if (match == null) {
throw FormatException(
'Malformed upstream URL "$remoteUrl", should start with "https://github.com/"',
);
}
return match.group(1)!;
}
Checkouts get _localCheckouts {
const FileSystem fileSystem = LocalFileSystem();
const ProcessManager processManager = LocalProcessManager();
const Platform platform = LocalPlatform();
final Stdio stdio = VerboseStdio(
stdout: io.stdout,
stderr: io.stderr,
stdin: io.stdin,
);
return Checkouts(
fileSystem: fileSystem,
parentDirectory: _localFlutterRoot.parent,
platform: platform,
processManager: processManager,
stdio: stdio,
);
}
Directory get _localFlutterRoot {
String filePath;
const FileSystem fileSystem = LocalFileSystem();
const Platform platform = LocalPlatform();
filePath = platform.script.toFilePath();
final String checkoutsDirname = fileSystem.path.normalize(
fileSystem.path.join(
fileSystem.path.dirname(filePath), // flutter/dev/conductor/core/bin
'..', // flutter/dev/conductor/core
'..', // flutter/dev/conductor
'..', // flutter/dev
'..', // flutter
),
);
return fileSystem.directory(checkoutsDirname);
}
@visibleForTesting
void validateTokenFile(String filePath, [FileSystem fs = const LocalFileSystem()]) {
}