Unverified Commit 326ed7d7 authored by Alex's avatar Alex Committed by GitHub

[conductor] add global constants and startContext checkoutpath getter (#93877)

parent 57d1d7be
......@@ -23,6 +23,8 @@ const String kReleaseDocumentationUrl = 'https://github.com/flutter/flutter/wiki
const String kLuciPackagingConsoleLink = 'https://ci.chromium.org/p/flutter/g/packaging/console';
const String kWebsiteReleasesUrl = 'https://docs.flutter.dev/development/tools/sdk/releases';
final RegExp releaseCandidateBranchRegex = RegExp(
r'flutter-(\d+)\.(\d+)-candidate\.(\d+)',
);
......
......@@ -53,8 +53,7 @@ class StartCommand extends Command<void> {
argParser.addOption(
kFrameworkUpstreamOption,
defaultsTo: FrameworkRepository.defaultUpstream,
help:
'Configurable Framework repo upstream remote. Primarily for testing.',
help: 'Configurable Framework repo upstream remote. Primarily for testing.',
hide: true,
);
argParser.addOption(
......@@ -233,12 +232,34 @@ class StartContext extends Context {
required Checkouts checkouts,
required File stateFile,
this.force = false,
}) :
git = Git(processManager),
super(
checkouts: checkouts,
stateFile: stateFile,
);
}) : git = Git(processManager),
engine = EngineRepository(
checkouts,
initialRef: candidateBranch,
upstreamRemote: Remote(
name: RemoteName.upstream,
url: engineUpstream,
),
mirrorRemote: Remote(
name: RemoteName.mirror,
url: engineMirror,
),
), framework = FrameworkRepository(
checkouts,
initialRef: candidateBranch,
upstreamRemote: Remote(
name: RemoteName.upstream,
url: frameworkUpstream,
),
mirrorRemote: Remote(
name: RemoteName.mirror,
url: frameworkMirror,
),
),
super(
checkouts: checkouts,
stateFile: stateFile,
);
final String candidateBranch;
final String? dartRevision;
......@@ -257,10 +278,12 @@ class StartContext extends Context {
/// If validations should be overridden.
final bool force;
final EngineRepository engine;
final FrameworkRepository framework;
Future<void> run() async {
if (stateFile.existsSync()) {
throw ConductorException(
'Error! A persistent state file already found at ${stateFile.path}.\n\n'
throw ConductorException('Error! A persistent state file already found at ${stateFile.path}.\n\n'
'Run `conductor clean` to cancel a previous release.');
}
if (!releaseCandidateBranchRegex.hasMatch(candidateBranch)) {
......@@ -278,19 +301,6 @@ class StartContext extends Context {
state.lastUpdatedDate = unixDate;
state.incrementLevel = incrementLetter;
final EngineRepository engine = EngineRepository(
checkouts,
initialRef: candidateBranch,
upstreamRemote: Remote(
name: RemoteName.upstream,
url: engineUpstream,
),
mirrorRemote: Remote(
name: RemoteName.mirror,
url: engineMirror,
),
);
// Create a new branch so that we don't accidentally push to upstream
// candidateBranch.
final String workingBranchName = 'cherrypicks-$candidateBranch';
......@@ -335,18 +345,7 @@ class StartContext extends Context {
upstream: pb.Remote(name: 'upstream', url: engine.upstreamRemote.url),
mirror: pb.Remote(name: 'mirror', url: engine.mirrorRemote!.url),
);
final FrameworkRepository framework = FrameworkRepository(
checkouts,
initialRef: candidateBranch,
upstreamRemote: Remote(
name: RemoteName.upstream,
url: frameworkUpstream,
),
mirrorRemote: Remote(
name: RemoteName.mirror,
url: frameworkMirror,
),
);
await framework.newBranch(workingBranchName);
final List<pb.Cherrypick> frameworkCherrypicks = (await _sortCherrypicks(
repository: framework,
......@@ -374,8 +373,9 @@ class StartContext extends Context {
// Get framework version
final Version lastVersion = Version.fromString(await framework.getFullTag(
framework.upstreamRemote.name, candidateBranch,
exact: false,
framework.upstreamRemote.name,
candidateBranch,
exact: false,
));
// [force] means we know this would fail but need to publish anyway
if (!force) {
......@@ -421,10 +421,10 @@ class StartContext extends Context {
}
// This is the first stable release, so hardcode the z as 0
return Version(
x: lastVersion.x,
y: lastVersion.y,
z: 0,
type: VersionType.stable,
x: lastVersion.x,
y: lastVersion.y,
z: 0,
type: VersionType.stable,
);
}
return Version.increment(lastVersion, incrementLetter);
......
......@@ -133,7 +133,8 @@ void main() {
const String nextVersion = '1.2.0-1.1.pre';
const String incrementLevel = 'n';
final Directory engine = fileSystem.directory(checkoutsParentDirectory)
final Directory engine = fileSystem
.directory(checkoutsParentDirectory)
.childDirectory('flutter_conductor_checkouts')
.childDirectory('engine');
......@@ -141,21 +142,20 @@ void main() {
final List<FakeCommand> engineCommands = <FakeCommand>[
FakeCommand(
command: <String>[
'git',
'clone',
'--origin',
'upstream',
'--',
EngineRepository.defaultUpstream,
engine.path,
],
onRun: () {
// Create the DEPS file which the tool will update
engine.createSync(recursive: true);
depsFile.writeAsStringSync(generateMockDeps(previousDartRevision));
}
),
command: <String>[
'git',
'clone',
'--origin',
'upstream',
'--',
EngineRepository.defaultUpstream,
engine.path,
],
onRun: () {
// Create the DEPS file which the tool will update
engine.createSync(recursive: true);
depsFile.writeAsStringSync(generateMockDeps(previousDartRevision));
}),
const FakeCommand(
command: <String>['git', 'remote', 'add', 'mirror', engineMirror],
),
......@@ -309,7 +309,7 @@ void main() {
stdio.stdin.add('y'); // accept prompt from ensureBranchPointTagged()
const String revision2 = 'def789';
const String revision3 = '123abc';
const String branchPointRevision='deadbeef';
const String branchPointRevision = 'deadbeef';
const String previousDartRevision = '171876a4e6cf56ee6da1f97d203926bd7afda7ef';
const String nextDartRevision = 'f6c91128be6b77aef8351e1e3a9d07c85bc2e46e';
const String previousVersion = '1.2.0-1.0.pre';
......@@ -319,7 +319,8 @@ void main() {
const String nextVersion = '1.2.0-3.1.pre';
const String incrementLevel = 'm';
final Directory engine = fileSystem.directory(checkoutsParentDirectory)
final Directory engine = fileSystem
.directory(checkoutsParentDirectory)
.childDirectory('flutter_conductor_checkouts')
.childDirectory('engine');
......@@ -327,21 +328,20 @@ void main() {
final List<FakeCommand> engineCommands = <FakeCommand>[
FakeCommand(
command: <String>[
'git',
'clone',
'--origin',
'upstream',
'--',
EngineRepository.defaultUpstream,
engine.path,
],
onRun: () {
// Create the DEPS file which the tool will update
engine.createSync(recursive: true);
depsFile.writeAsStringSync(generateMockDeps(previousDartRevision));
}
),
command: <String>[
'git',
'clone',
'--origin',
'upstream',
'--',
EngineRepository.defaultUpstream,
engine.path,
],
onRun: () {
// Create the DEPS file which the tool will update
engine.createSync(recursive: true);
depsFile.writeAsStringSync(generateMockDeps(previousDartRevision));
}),
const FakeCommand(
command: <String>['git', 'remote', 'add', 'mirror', engineMirror],
),
......@@ -512,7 +512,8 @@ void main() {
const String nextVersion = '1.2.0';
const String incrementLevel = 'z';
final Directory engine = fileSystem.directory(checkoutsParentDirectory)
final Directory engine = fileSystem
.directory(checkoutsParentDirectory)
.childDirectory('flutter_conductor_checkouts')
.childDirectory('engine');
......@@ -520,21 +521,20 @@ void main() {
final List<FakeCommand> engineCommands = <FakeCommand>[
FakeCommand(
command: <String>[
'git',
'clone',
'--origin',
'upstream',
'--',
EngineRepository.defaultUpstream,
engine.path,
],
onRun: () {
// Create the DEPS file which the tool will update
engine.createSync(recursive: true);
depsFile.writeAsStringSync(generateMockDeps(previousDartRevision));
}
),
command: <String>[
'git',
'clone',
'--origin',
'upstream',
'--',
EngineRepository.defaultUpstream,
engine.path,
],
onRun: () {
// Create the DEPS file which the tool will update
engine.createSync(recursive: true);
depsFile.writeAsStringSync(generateMockDeps(previousDartRevision));
}),
const FakeCommand(
command: <String>['git', 'remote', 'add', 'mirror', engineMirror],
),
......@@ -680,6 +680,202 @@ void main() {
expect(state.conductorVersion, conductorVersion);
expect(state.incrementLevel, incrementLevel);
});
test('StartContext gets engine and framework checkout directories after run', () async {
stdio.stdin.add('y');
const String revision2 = 'def789';
const String revision3 = '123abc';
const String branchPointRevision = 'deadbeef';
const String previousDartRevision = '171876a4e6cf56ee6da1f97d203926bd7afda7ef';
const String nextDartRevision = 'f6c91128be6b77aef8351e1e3a9d07c85bc2e46e';
const String previousVersion = '1.2.0-1.0.pre';
// This is a git tag applied to the branch point, not an actual release
const String branchPointTag = '1.2.0-3.0.pre';
// This is what this release will be
const String incrementLevel = 'm';
final Directory engine = fileSystem
.directory(checkoutsParentDirectory)
.childDirectory('flutter_conductor_checkouts')
.childDirectory('engine');
final Directory framework = fileSystem
.directory(checkoutsParentDirectory)
.childDirectory('flutter_conductor_checkouts')
.childDirectory('framework');
final File depsFile = engine.childFile('DEPS');
final List<FakeCommand> engineCommands = <FakeCommand>[
FakeCommand(
command: <String>[
'git',
'clone',
'--origin',
'upstream',
'--',
EngineRepository.defaultUpstream,
engine.path,
],
onRun: () {
// Create the DEPS file which the tool will update
engine.createSync(recursive: true);
depsFile.writeAsStringSync(generateMockDeps(previousDartRevision));
}),
const FakeCommand(
command: <String>['git', 'remote', 'add', 'mirror', engineMirror],
),
const FakeCommand(
command: <String>['git', 'fetch', 'mirror'],
),
const FakeCommand(
command: <String>['git', 'checkout', candidateBranch],
),
const FakeCommand(
command: <String>['git', 'rev-parse', 'HEAD'],
stdout: revision2,
),
const FakeCommand(
command: <String>[
'git',
'checkout',
'-b',
'cherrypicks-$candidateBranch',
],
),
const FakeCommand(
command: <String>['git', 'status', '--porcelain'],
stdout: 'MM path/to/DEPS',
),
const FakeCommand(
command: <String>['git', 'add', '--all'],
),
const FakeCommand(
command: <String>['git', 'commit', "--message='Update Dart SDK to $nextDartRevision'"],
),
const FakeCommand(
command: <String>['git', 'rev-parse', 'HEAD'],
stdout: revision2,
),
const FakeCommand(
command: <String>['git', 'rev-parse', 'HEAD'],
stdout: revision2,
),
];
final List<FakeCommand> frameworkCommands = <FakeCommand>[
FakeCommand(
command: <String>[
'git',
'clone',
'--origin',
'upstream',
'--',
FrameworkRepository.defaultUpstream,
framework.path,
],
),
const FakeCommand(
command: <String>['git', 'remote', 'add', 'mirror', frameworkMirror],
),
const FakeCommand(
command: <String>['git', 'fetch', 'mirror'],
),
const FakeCommand(
command: <String>['git', 'checkout', candidateBranch],
),
const FakeCommand(
command: <String>['git', 'rev-parse', 'HEAD'],
stdout: revision3,
),
const FakeCommand(
command: <String>[
'git',
'checkout',
'-b',
'cherrypicks-$candidateBranch',
],
),
const FakeCommand(
command: <String>[
'git',
'describe',
'--match',
'*.*.*',
'--tags',
'refs/remotes/upstream/$candidateBranch',
],
stdout: '$previousVersion-42-gabc123',
),
const FakeCommand(
command: <String>['git', 'merge-base', candidateBranch, 'master'],
stdout: branchPointRevision,
),
const FakeCommand(
command: <String>['git', 'tag', branchPointTag, branchPointRevision],
),
const FakeCommand(
command: <String>['git', 'push', FrameworkRepository.defaultUpstream, branchPointTag],
),
const FakeCommand(
command: <String>['git', 'rev-parse', 'HEAD'],
stdout: revision3,
),
];
final String operatingSystem = const LocalPlatform().operatingSystem;
final Map<String, String> environment = <String, String>{
'HOME': '/path/to/user/home',
};
final Directory homeDir = fileSystem.directory(
environment['HOME'],
);
// Tool assumes this exists
homeDir.createSync(recursive: true);
platform = FakePlatform(
environment: environment,
operatingSystem: operatingSystem,
);
final String stateFilePath = fileSystem.path.join(
platform.environment['HOME']!,
kStateFileName,
);
final File stateFile = fileSystem.file(stateFilePath);
processManager = FakeProcessManager.list(<FakeCommand>[
...engineCommands,
...frameworkCommands,
]);
checkouts = Checkouts(
fileSystem: fileSystem,
parentDirectory: fileSystem.directory(checkoutsParentDirectory),
platform: platform,
processManager: processManager,
stdio: stdio,
);
final StartContext startContext = StartContext(
candidateBranch: candidateBranch,
checkouts: checkouts,
dartRevision: nextDartRevision,
engineCherrypickRevisions: <String>[],
engineMirror: engineMirror,
engineUpstream: EngineRepository.defaultUpstream,
frameworkCherrypickRevisions: <String>[],
frameworkMirror: frameworkMirror,
frameworkUpstream: FrameworkRepository.defaultUpstream,
releaseChannel: releaseChannel,
incrementLetter: incrementLevel,
processManager: processManager,
conductorVersion: conductorVersion,
stateFile: stateFile);
await startContext.run();
expect((await startContext.engine.checkoutDirectory).path, equals(engine.path));
expect((await startContext.framework.checkoutDirectory).path, equals(framework.path));
});
}, onPlatform: <String, dynamic>{
'windows': const Skip('Flutter Conductor only supported on macos/linux'),
});
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment