mirror of
https://github.com/flutter/flutter.git
synced 2025-06-03 00:51:18 +00:00
382 lines
10 KiB
Dart
382 lines
10 KiB
Dart
// 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 'package:args/args.dart';
|
|
import 'package:dev_tools/roll_dev.dart';
|
|
import 'package:mockito/mockito.dart';
|
|
|
|
import './common.dart';
|
|
|
|
void main() {
|
|
group('run()', () {
|
|
const String usage = 'usage info...';
|
|
const String level = 'z';
|
|
const String commit = 'abcde012345';
|
|
const String origin = 'upstream';
|
|
FakeArgResults fakeArgResults;
|
|
MockGit mockGit;
|
|
|
|
setUp(() {
|
|
mockGit = MockGit();
|
|
});
|
|
|
|
test('returns false if help requested', () {
|
|
fakeArgResults = FakeArgResults(
|
|
level: level,
|
|
commit: commit,
|
|
origin: origin,
|
|
justPrint: false,
|
|
autoApprove: true,
|
|
help: true,
|
|
);
|
|
expect(
|
|
run(
|
|
usage: usage,
|
|
argResults: fakeArgResults,
|
|
git: mockGit,
|
|
),
|
|
false,
|
|
);
|
|
});
|
|
|
|
test('returns false if level not provided', () {
|
|
fakeArgResults = FakeArgResults(
|
|
level: level,
|
|
commit: commit,
|
|
origin: origin,
|
|
justPrint: false,
|
|
autoApprove: true,
|
|
help: true,
|
|
);
|
|
expect(
|
|
run(
|
|
usage: usage,
|
|
argResults: fakeArgResults,
|
|
git: mockGit,
|
|
),
|
|
false,
|
|
);
|
|
});
|
|
|
|
test('returns false if commit not provided', () {
|
|
fakeArgResults = FakeArgResults(
|
|
level: level,
|
|
commit: commit,
|
|
origin: origin,
|
|
justPrint: false,
|
|
autoApprove: true,
|
|
help: true,
|
|
);
|
|
expect(
|
|
run(
|
|
usage: usage,
|
|
argResults: fakeArgResults,
|
|
git: mockGit,
|
|
),
|
|
false,
|
|
);
|
|
});
|
|
|
|
test('throws exception if upstream remote wrong', () {
|
|
when(mockGit.getOutput('remote get-url $origin', any)).thenReturn('wrong-remote');
|
|
fakeArgResults = FakeArgResults(
|
|
level: level,
|
|
commit: commit,
|
|
origin: origin,
|
|
justPrint: false,
|
|
autoApprove: true,
|
|
help: false,
|
|
);
|
|
Exception exception;
|
|
try {
|
|
run(
|
|
usage: usage,
|
|
argResults: fakeArgResults,
|
|
git: mockGit,
|
|
);
|
|
} on Exception catch (e) {
|
|
exception = e;
|
|
}
|
|
const String pattern = r'The current directory is not a Flutter '
|
|
'repository checkout with a correctly configured upstream remote.';
|
|
expect(exception?.toString(), contains(pattern));
|
|
});
|
|
|
|
test('throws exception if git checkout not clean', () {
|
|
when(mockGit.getOutput('remote get-url $origin', any)).thenReturn(kUpstreamRemote);
|
|
when(mockGit.getOutput('status --porcelain', any)).thenReturn(
|
|
' M dev/tools/test/roll_dev_test.dart',
|
|
);
|
|
fakeArgResults = FakeArgResults(
|
|
level: level,
|
|
commit: commit,
|
|
origin: origin,
|
|
justPrint: false,
|
|
autoApprove: true,
|
|
help: false,
|
|
);
|
|
Exception exception;
|
|
try {
|
|
run(
|
|
usage: usage,
|
|
argResults: fakeArgResults,
|
|
git: mockGit,
|
|
);
|
|
} on Exception catch (e) {
|
|
exception = e;
|
|
}
|
|
const String pattern = r'Your git repository is not clean. Try running '
|
|
'"git clean -fd". Warning, this will delete files! Run with -n to find '
|
|
'out which ones.';
|
|
expect(exception?.toString(), contains(pattern));
|
|
});
|
|
|
|
test('does not tag if --just-print is specified', () {
|
|
when(mockGit.getOutput('remote get-url $origin', any)).thenReturn(kUpstreamRemote);
|
|
when(mockGit.getOutput('status --porcelain', any)).thenReturn('');
|
|
when(mockGit.getOutput(
|
|
'describe --match *.*.*-*.*.pre --exact-match --tags refs/remotes/$origin/dev',
|
|
any,
|
|
)).thenReturn('1.2.3-0.0.pre');
|
|
fakeArgResults = FakeArgResults(
|
|
level: level,
|
|
commit: commit,
|
|
origin: origin,
|
|
justPrint: true,
|
|
autoApprove: true,
|
|
help: false,
|
|
);
|
|
expect(run(
|
|
usage: usage,
|
|
argResults: fakeArgResults,
|
|
git: mockGit,
|
|
), false);
|
|
verify(mockGit.run('fetch $origin', any));
|
|
verify(mockGit.run('reset $commit --hard', any));
|
|
verifyNever(mockGit.getOutput('rev-parse HEAD', any));
|
|
});
|
|
|
|
test('successfully tags and publishes release', () {
|
|
when(mockGit.getOutput('remote get-url $origin', any)).thenReturn(kUpstreamRemote);
|
|
when(mockGit.getOutput('status --porcelain', any)).thenReturn('');
|
|
when(mockGit.getOutput(
|
|
'describe --match *.*.*-*.*.pre --exact-match --tags refs/remotes/$origin/dev',
|
|
any,
|
|
)).thenReturn('1.2.3-0.0.pre');
|
|
when(mockGit.getOutput('rev-parse HEAD', any)).thenReturn(commit);
|
|
fakeArgResults = FakeArgResults(
|
|
level: level,
|
|
commit: commit,
|
|
origin: origin,
|
|
justPrint: false,
|
|
autoApprove: true,
|
|
help: false,
|
|
);
|
|
expect(run(
|
|
usage: usage,
|
|
argResults: fakeArgResults,
|
|
git: mockGit,
|
|
), true);
|
|
verify(mockGit.run('fetch $origin', any));
|
|
verify(mockGit.run('reset $commit --hard', any));
|
|
verify(mockGit.run('tag 1.2.0-1.0.pre', any));
|
|
verify(mockGit.run('push $origin HEAD:dev', any));
|
|
});
|
|
|
|
test('successfully publishes release with --force', () {
|
|
when(mockGit.getOutput('remote get-url $origin', any)).thenReturn(kUpstreamRemote);
|
|
when(mockGit.getOutput('status --porcelain', any)).thenReturn('');
|
|
when(mockGit.getOutput(
|
|
'describe --match *.*.*-*.*.pre --exact-match --tags refs/remotes/$origin/dev',
|
|
any,
|
|
)).thenReturn('1.2.3-0.0.pre');
|
|
when(mockGit.getOutput('rev-parse HEAD', any)).thenReturn(commit);
|
|
fakeArgResults = FakeArgResults(
|
|
level: level,
|
|
commit: commit,
|
|
origin: origin,
|
|
justPrint: false,
|
|
autoApprove: true,
|
|
help: false,
|
|
force: true,
|
|
);
|
|
expect(run(
|
|
usage: usage,
|
|
argResults: fakeArgResults,
|
|
git: mockGit,
|
|
), true);
|
|
verify(mockGit.run('fetch $origin', any));
|
|
verify(mockGit.run('reset $commit --hard', any));
|
|
verify(mockGit.run('tag 1.2.0-1.0.pre', any));
|
|
verify(mockGit.run('push --force $origin HEAD:dev', any));
|
|
});
|
|
});
|
|
|
|
group('parseFullTag', () {
|
|
test('returns match on valid version input', () {
|
|
final List<String> validTags = <String>[
|
|
'1.2.3-1.2.pre',
|
|
'10.2.30-12.22.pre',
|
|
'1.18.0-0.0.pre',
|
|
'2.0.0-1.99.pre',
|
|
'12.34.56-78.90.pre',
|
|
'0.0.1-0.0.pre',
|
|
'958.80.144-6.224.pre',
|
|
];
|
|
for (final String validTag in validTags) {
|
|
final Match match = parseFullTag(validTag);
|
|
expect(match, isNotNull, reason: 'Expected $validTag to be parsed');
|
|
}
|
|
});
|
|
|
|
test('returns null on invalid version input', () {
|
|
final List<String> invalidTags = <String>[
|
|
'1.2.3-1.2.pre-3-gabc123',
|
|
'1.2.3-1.2.3.pre',
|
|
'1.2.3.1.2.pre',
|
|
'1.2.3-dev.1.2',
|
|
'1.2.3-1.2-3',
|
|
'v1.2.3',
|
|
'2.0.0',
|
|
'v1.2.3-1.2.pre',
|
|
'1.2.3-1.2.pre_',
|
|
];
|
|
for (final String invalidTag in invalidTags) {
|
|
final Match match = parseFullTag(invalidTag);
|
|
expect(match, null, reason: 'Expected $invalidTag to not be parsed');
|
|
}
|
|
});
|
|
});
|
|
|
|
group('getVersionFromParts', () {
|
|
test('returns correct string from valid parts', () {
|
|
List<int> parts = <int>[1, 2, 3, 4, 5];
|
|
expect(getVersionFromParts(parts), '1.2.3-4.5.pre');
|
|
|
|
parts = <int>[11, 2, 33, 1, 0];
|
|
expect(getVersionFromParts(parts), '11.2.33-1.0.pre');
|
|
});
|
|
});
|
|
|
|
group('incrementLevel()', () {
|
|
const String hash = 'abc123';
|
|
|
|
test('throws exception if hash is not valid release candidate', () {
|
|
String level = 'z';
|
|
|
|
String version = '1.0.0-0.0.pre-1-g$hash';
|
|
expect(
|
|
() => incrementLevel(version, level),
|
|
throwsException,
|
|
reason: 'should throw because $version should be an exact tag',
|
|
);
|
|
|
|
version = '1.2.3';
|
|
expect(
|
|
() => incrementLevel(version, level),
|
|
throwsException,
|
|
reason: 'should throw because $version should be a dev tag, not stable.'
|
|
);
|
|
|
|
version = '1.0.0-0.0.pre-1-g$hash';
|
|
level = 'q';
|
|
expect(
|
|
() => incrementLevel(version, level),
|
|
throwsException,
|
|
reason: 'should throw because $level is unsupported',
|
|
);
|
|
});
|
|
|
|
test('successfully increments x', () {
|
|
const String level = 'x';
|
|
|
|
String version = '1.0.0-0.0.pre';
|
|
expect(incrementLevel(version, level), '2.0.0-0.0.pre');
|
|
|
|
version = '10.20.0-40.50.pre';
|
|
expect(incrementLevel(version, level), '11.0.0-0.0.pre');
|
|
|
|
version = '1.18.0-3.0.pre';
|
|
expect(incrementLevel(version, level), '2.0.0-0.0.pre');
|
|
});
|
|
|
|
test('successfully increments y', () {
|
|
const String level = 'y';
|
|
|
|
String version = '1.0.0-0.0.pre';
|
|
expect(incrementLevel(version, level), '1.1.0-0.0.pre');
|
|
|
|
version = '10.20.0-40.50.pre';
|
|
expect(incrementLevel(version, level), '10.21.0-0.0.pre');
|
|
|
|
version = '1.18.0-3.0.pre';
|
|
expect(incrementLevel(version, level), '1.19.0-0.0.pre');
|
|
});
|
|
|
|
test('successfully increments z', () {
|
|
const String level = 'z';
|
|
|
|
String version = '1.0.0-0.0.pre';
|
|
expect(incrementLevel(version, level), '1.0.0-1.0.pre');
|
|
|
|
version = '10.20.0-40.50.pre';
|
|
expect(incrementLevel(version, level), '10.20.0-41.0.pre');
|
|
|
|
version = '1.18.0-3.0.pre';
|
|
expect(incrementLevel(version, level), '1.18.0-4.0.pre');
|
|
});
|
|
});
|
|
}
|
|
|
|
class FakeArgResults implements ArgResults {
|
|
FakeArgResults({
|
|
String level,
|
|
String commit,
|
|
String origin,
|
|
bool justPrint,
|
|
bool autoApprove,
|
|
bool help,
|
|
bool force = false,
|
|
}) : _parsedArgs = <String, dynamic>{
|
|
'increment': level,
|
|
'commit': commit,
|
|
'origin': origin,
|
|
'just-print': justPrint,
|
|
'yes': autoApprove,
|
|
'help': help,
|
|
'force': force,
|
|
};
|
|
|
|
@override
|
|
String name;
|
|
|
|
@override
|
|
ArgResults command;
|
|
|
|
@override
|
|
final List<String> rest = <String>[];
|
|
|
|
@override
|
|
List<String> arguments;
|
|
|
|
final Map<String, dynamic> _parsedArgs;
|
|
|
|
@override
|
|
Iterable<String> get options {
|
|
return null;
|
|
}
|
|
|
|
@override
|
|
dynamic operator [](String name) {
|
|
return _parsedArgs[name];
|
|
}
|
|
|
|
@override
|
|
bool wasParsed(String name) {
|
|
return null;
|
|
}
|
|
}
|
|
|
|
class MockGit extends Mock implements Git {}
|