Unverified Commit 37ac9015 authored by Christopher Fujino's avatar Christopher Fujino Committed by GitHub

[flutter_tools] check first for stable tag, then dev tag (#55342)

parent f582246a
...@@ -752,80 +752,83 @@ class GitTagVersion { ...@@ -752,80 +752,83 @@ class GitTagVersion {
_runGit('git fetch $_flutterGit --tags', processUtils, workingDirectory); _runGit('git fetch $_flutterGit --tags', processUtils, workingDirectory);
} }
} }
// `--match` glob must match old version tag `v1.2.3` and new `1.2.3-dev.4.5` final List<String> tags = _runGit(
return parse(_runGit('git describe --match *.*.* --first-parent --long --tags', processUtils, workingDirectory)); 'git tag --contains HEAD', processUtils, workingDirectory).split('\n');
}
// Check first for a stable tag
// TODO(fujino): Deprecate this https://github.com/flutter/flutter/issues/53850 final RegExp stableTagPattern = RegExp(r'^\d+\.\d+\.\d+$');
/// Check for the release tag format of the form x.y.z-dev.m.n for (final String tag in tags) {
static GitTagVersion parseLegacyVersion(String version) { final String trimmedTag = tag.trim();
final RegExp versionPattern = RegExp( if (stableTagPattern.hasMatch(trimmedTag)) {
r'^([0-9]+)\.([0-9]+)\.([0-9]+)(-dev\.[0-9]+\.[0-9]+)?-([0-9]+)-g([a-f0-9]+)$'); return parse(trimmedTag);
final List<String> parts = versionPattern.matchAsPrefix(version)?.groups(<int>[1, 2, 3, 4, 5, 6]); }
if (parts == null) {
return const GitTagVersion.unknown();
} }
final List<int> parsedParts = parts.take(5).map<int>( // Next check for a dev tag
(String source) => source == null ? null : int.tryParse(source)).toList(); final RegExp devTagPattern = RegExp(r'^\d+\.\d+\.\d+-\d+\.\d+\.pre$');
List<int> devParts = <int>[null, null]; for (final String tag in tags) {
if (parts[3] != null) { final String trimmedTag = tag.trim();
devParts = RegExp(r'^-dev\.(\d+)\.(\d+)') if (devTagPattern.hasMatch(trimmedTag)) {
.matchAsPrefix(parts[3]) return parse(trimmedTag);
?.groups(<int>[1, 2]) }
?.map<int>(
(String source) => source == null ? null : int.tryParse(source)
)?.toList() ?? <int>[null, null];
} }
return GitTagVersion(
x: parsedParts[0], // If we're not currently on a tag, use git describe to find the most
y: parsedParts[1], // recent tag and number of commits past.
z: parsedParts[2], return parse(
devVersion: devParts[0], _runGit(
devPatch: devParts[1], 'git describe --match *.*.*-*.*.pre --first-parent --long --tags',
commits: parsedParts[4], processUtils,
hash: parts[5], workingDirectory,
gitTag: '${parts[0]}.${parts[1]}.${parts[2]}${parts[3] ?? ''}', // x.y.z-dev.m.n )
); );
} }
/// Check for the release tag format of the form x.y.z-m.n.pre /// Parse a version string.
///
/// The version string can either be an exact release tag (e.g. '1.2.3' for
/// stable or 1.2.3-4.5.pre for a dev) or the output of `git describe` (e.g.
/// for commit abc123 that is 6 commits after tag 1.2.3-4.5.pre, git would
/// return '1.2.3-4.5.pre-6-gabc123').
static GitTagVersion parseVersion(String version) { static GitTagVersion parseVersion(String version) {
final RegExp versionPattern = RegExp( final RegExp versionPattern = RegExp(
r'^(\d+)\.(\d+)\.(\d+)(-\d+\.\d+\.pre)?-(\d+)-g([a-f0-9]+)$'); r'^(\d+)\.(\d+)\.(\d+)(-\d+\.\d+\.pre)?(?:-(\d+)-g([a-f0-9]+))?$');
final List<String> parts = versionPattern.matchAsPrefix(version)?.groups(<int>[1, 2, 3, 4, 5, 6]); final Match match = versionPattern.firstMatch(version.trim());
if (parts == null) { if (match == null) {
return const GitTagVersion.unknown(); return const GitTagVersion.unknown();
} }
final List<int> parsedParts = parts.take(5).map<int>(
(String source) => source == null ? null : int.tryParse(source)).toList(); final List<String> matchGroups = match.groups(<int>[1, 2, 3, 4, 5, 6]);
List<int> devParts = <int>[null, null]; final int x = matchGroups[0] == null ? null : int.tryParse(matchGroups[0]);
if (parts[3] != null) { final int y = matchGroups[1] == null ? null : int.tryParse(matchGroups[1]);
devParts = RegExp(r'^-(\d+)\.(\d+)\.pre') final int z = matchGroups[2] == null ? null : int.tryParse(matchGroups[2]);
.matchAsPrefix(parts[3]) final String devString = matchGroups[3];
?.groups(<int>[1, 2]) int devVersion, devPatch;
?.map<int>( if (devString != null) {
(String source) => source == null ? null : int.tryParse(source) final Match devMatch = RegExp(r'^-(\d+)\.(\d+)\.pre$')
)?.toList() ?? <int>[null, null]; .firstMatch(devString);
final List<String> devGroups = devMatch.groups(<int>[1, 2]);
devVersion = devGroups[0] == null ? null : int.tryParse(devGroups[0]);
devPatch = devGroups[1] == null ? null : int.tryParse(devGroups[1]);
} }
// count of commits past last tagged version
final int commits = matchGroups[4] == null ? 0 : int.tryParse(matchGroups[4]);
final String hash = matchGroups[5] ?? '';
return GitTagVersion( return GitTagVersion(
x: parsedParts[0], x: x,
y: parsedParts[1], y: y,
z: parsedParts[2], z: z,
devVersion: devParts[0], devVersion: devVersion,
devPatch: devParts[1], devPatch: devPatch,
commits: parsedParts[4], commits: commits,
hash: parts[5], hash: hash,
gitTag: '${parts[0]}.${parts[1]}.${parts[2]}${parts[3] ?? ''}', // x.y.z-m.n.pre gitTag: '$x.$y.$z${devString ?? ''}', // e.g. 1.2.3-4.5.pre
); );
} }
static GitTagVersion parse(String version) { static GitTagVersion parse(String version) {
GitTagVersion gitTagVersion; GitTagVersion gitTagVersion;
gitTagVersion = parseLegacyVersion(version);
if (gitTagVersion != const GitTagVersion.unknown()) {
return gitTagVersion;
}
gitTagVersion = parseVersion(version); gitTagVersion = parseVersion(version);
if (gitTagVersion != const GitTagVersion.unknown()) { if (gitTagVersion != const GitTagVersion.unknown()) {
return gitTagVersion; return gitTagVersion;
......
...@@ -259,7 +259,7 @@ class MockProcessManager extends Mock implements ProcessManager { ...@@ -259,7 +259,7 @@ class MockProcessManager extends Mock implements ProcessManager {
return ProcessResult(0, 0, '000000000000000000000', ''); return ProcessResult(0, 0, '000000000000000000000', '');
} }
if (commandStr == if (commandStr ==
'git describe --match *.*.* --first-parent --long --tags') { 'git describe --match *.*.*-*.*.pre --first-parent --long --tags') {
if (version.isNotEmpty) { if (version.isNotEmpty) {
return ProcessResult(0, 0, '$version-0-g00000000', ''); return ProcessResult(0, 0, '$version-0-g00000000', '');
} }
......
...@@ -238,7 +238,13 @@ void main() { ...@@ -238,7 +238,13 @@ void main() {
fakeProcessManager = FakeProcessManager.list(<FakeCommand>[ fakeProcessManager = FakeProcessManager.list(<FakeCommand>[
const FakeCommand( const FakeCommand(
command: <String>[ command: <String>[
'git', 'describe', '--match', '*.*.*', '--first-parent', '--long', '--tags', 'git', 'tag', '--contains', 'HEAD',
],
stdout: '',
),
const FakeCommand(
command: <String>[
'git', 'describe', '--match', '*.*.*-*.*.pre', '--first-parent', '--long', '--tags',
], ],
stdout: 'v1.12.16-19-gb45b676af', stdout: 'v1.12.16-19-gb45b676af',
), ),
......
...@@ -185,7 +185,9 @@ void main() { ...@@ -185,7 +185,9 @@ void main() {
workingDirectory: Cache.flutterRoot)).thenReturn(result); workingDirectory: Cache.flutterRoot)).thenReturn(result);
when(processManager.runSync('git fetch https://github.com/flutter/flutter.git --tags'.split(' '), when(processManager.runSync('git fetch https://github.com/flutter/flutter.git --tags'.split(' '),
workingDirectory: Cache.flutterRoot)).thenReturn(result); workingDirectory: Cache.flutterRoot)).thenReturn(result);
when(processManager.runSync('git describe --match *.*.* --first-parent --long --tags'.split(' '), when(processManager.runSync('git tag --contains HEAD'.split(' '),
workingDirectory: Cache.flutterRoot)).thenReturn(result);
when(processManager.runSync('git describe --match *.*.*-*.*.pre --first-parent --long --tags'.split(' '),
workingDirectory: Cache.flutterRoot)).thenReturn(result); workingDirectory: Cache.flutterRoot)).thenReturn(result);
when(processManager.runSync(FlutterVersion.gitLog('-n 1 --pretty=format:%ad --date=iso'.split(' ')), when(processManager.runSync(FlutterVersion.gitLog('-n 1 --pretty=format:%ad --date=iso'.split(' ')),
workingDirectory: Cache.flutterRoot)).thenReturn(result); workingDirectory: Cache.flutterRoot)).thenReturn(result);
......
...@@ -394,16 +394,25 @@ void main() { ...@@ -394,16 +394,25 @@ void main() {
const String hash = 'abcdef'; const String hash = 'abcdef';
GitTagVersion gitTagVersion; GitTagVersion gitTagVersion;
// legacy tag format (x.y.z-dev.m.n), master channel // Master channel
gitTagVersion = GitTagVersion.parse('1.2.3-dev.4.5-4-g$hash'); gitTagVersion = GitTagVersion.parse('1.2.3-4.5.pre-13-g$hash');
expect(gitTagVersion.frameworkVersionFor(hash), '1.2.3-5.0.pre.4'); expect(gitTagVersion.frameworkVersionFor(hash), '1.2.3-5.0.pre.13');
expect(gitTagVersion.gitTag, '1.2.3-dev.4.5'); expect(gitTagVersion.gitTag, '1.2.3-4.5.pre');
expect(gitTagVersion.devVersion, 4); expect(gitTagVersion.devVersion, 4);
expect(gitTagVersion.devPatch, 5); expect(gitTagVersion.devPatch, 5);
// new tag release format, master channel // Stable channel
gitTagVersion = GitTagVersion.parse('1.2.3-4.5.pre-13-g$hash'); gitTagVersion = GitTagVersion.parse('1.2.3');
expect(gitTagVersion.frameworkVersionFor(hash), '1.2.3-5.0.pre.13'); expect(gitTagVersion.frameworkVersionFor(hash), '1.2.3');
expect(gitTagVersion.x, 1);
expect(gitTagVersion.y, 2);
expect(gitTagVersion.z, 3);
expect(gitTagVersion.devVersion, null);
expect(gitTagVersion.devPatch, null);
// Dev channel
gitTagVersion = GitTagVersion.parse('1.2.3-4.5.pre');
expect(gitTagVersion.frameworkVersionFor(hash), '1.2.3-4.5.pre');
expect(gitTagVersion.gitTag, '1.2.3-4.5.pre'); expect(gitTagVersion.gitTag, '1.2.3-4.5.pre');
expect(gitTagVersion.devVersion, 4); expect(gitTagVersion.devVersion, 4);
expect(gitTagVersion.devPatch, 5); expect(gitTagVersion.devPatch, 5);
...@@ -448,6 +457,29 @@ void main() { ...@@ -448,6 +457,29 @@ void main() {
); );
}); });
testUsingContext('determine favors stable tags over dev tags', () {
final MockProcessUtils mockProcessUtils = MockProcessUtils();
when(mockProcessUtils.runSync(
<String>['git', 'tag', '--contains', 'HEAD'],
workingDirectory: anyNamed('workingDirectory'),
environment: anyNamed('environment'),
)).thenReturn(RunResult(
ProcessResult(1, 0, '1.2.3-0.0.pre\n1.2.3\n1.2.3-0.1.pre', ''),
<String>['git', 'tag', '--contains', 'HEAD'],
));
final GitTagVersion version = GitTagVersion.determine(mockProcessUtils, workingDirectory: '.');
expect(version.gitTag, '1.2.3');
expect(version.devPatch, null);
expect(version.devVersion, null);
// We shouldn't have to fallback to git describe, because we are exactly
// on a release tag.
verifyNever(mockProcessUtils.runSync(
<String>['git', 'describe', '--match', '*.*.*-*.*.pre', '--first-parent', '--long', '--tags'],
workingDirectory: anyNamed('workingDirectory'),
environment: anyNamed('environment'),
));
});
testUsingContext('determine does not call fetch --tags', () { testUsingContext('determine does not call fetch --tags', () {
final MockProcessUtils processUtils = MockProcessUtils(); final MockProcessUtils processUtils = MockProcessUtils();
when(processUtils.runSync( when(processUtils.runSync(
...@@ -456,10 +488,18 @@ void main() { ...@@ -456,10 +488,18 @@ void main() {
environment: anyNamed('environment'), environment: anyNamed('environment'),
)).thenReturn(RunResult(ProcessResult(105, 0, '', ''), <String>['git', 'fetch'])); )).thenReturn(RunResult(ProcessResult(105, 0, '', ''), <String>['git', 'fetch']));
when(processUtils.runSync( when(processUtils.runSync(
<String>['git', 'describe', '--match', '*.*.*', '--first-parent', '--long', '--tags'], <String>['git', 'describe', '--match', '*.*.*-*.*.pre', '--first-parent', '--long', '--tags'],
workingDirectory: anyNamed('workingDirectory'), workingDirectory: anyNamed('workingDirectory'),
environment: anyNamed('environment'), environment: anyNamed('environment'),
)).thenReturn(RunResult(ProcessResult(106, 0, 'v0.1.2-3-1234abcd', ''), <String>['git', 'describe'])); )).thenReturn(RunResult(ProcessResult(106, 0, 'v0.1.2-3-1234abcd', ''), <String>['git', 'describe']));
when(processUtils.runSync(
<String>['git', 'tag', '--contains', 'HEAD'],
workingDirectory: anyNamed('workingDirectory'),
environment: anyNamed('environment'),
)).thenReturn(
RunResult(ProcessResult(110, 0, '', ''),
<String>['git', 'tag', '--contains', 'HEAD'],
));
GitTagVersion.determine(processUtils, workingDirectory: '.'); GitTagVersion.determine(processUtils, workingDirectory: '.');
...@@ -474,7 +514,7 @@ void main() { ...@@ -474,7 +514,7 @@ void main() {
environment: anyNamed('environment'), environment: anyNamed('environment'),
)); ));
verify(processUtils.runSync( verify(processUtils.runSync(
<String>['git', 'describe', '--match', '*.*.*', '--first-parent', '--long', '--tags'], <String>['git', 'describe', '--match', '*.*.*-*.*.pre', '--first-parent', '--long', '--tags'],
workingDirectory: anyNamed('workingDirectory'), workingDirectory: anyNamed('workingDirectory'),
environment: anyNamed('environment'), environment: anyNamed('environment'),
)).called(1); )).called(1);
...@@ -493,10 +533,18 @@ void main() { ...@@ -493,10 +533,18 @@ void main() {
environment: anyNamed('environment'), environment: anyNamed('environment'),
)).thenReturn(RunResult(ProcessResult(106, 0, '', ''), <String>['git', 'fetch'])); )).thenReturn(RunResult(ProcessResult(106, 0, '', ''), <String>['git', 'fetch']));
when(processUtils.runSync( when(processUtils.runSync(
<String>['git', 'describe', '--match', '*.*.*', '--first-parent', '--long', '--tags'], <String>['git', 'describe', '--match', '*.*.*-*.*.pre', '--first-parent', '--long', '--tags'],
workingDirectory: anyNamed('workingDirectory'), workingDirectory: anyNamed('workingDirectory'),
environment: anyNamed('environment'), environment: anyNamed('environment'),
)).thenReturn(RunResult(ProcessResult(107, 0, 'v0.1.2-3-1234abcd', ''), <String>['git', 'describe'])); )).thenReturn(RunResult(ProcessResult(107, 0, 'v0.1.2-3-1234abcd', ''), <String>['git', 'describe']));
when(processUtils.runSync(
<String>['git', 'tag', '--contains', 'HEAD'],
workingDirectory: anyNamed('workingDirectory'),
environment: anyNamed('environment'),
)).thenReturn(
RunResult(ProcessResult(108, 0, '', ''),
<String>['git', 'tag', '--contains', 'HEAD'],
));
GitTagVersion.determine(processUtils, workingDirectory: '.', fetchTags: true); GitTagVersion.determine(processUtils, workingDirectory: '.', fetchTags: true);
...@@ -511,7 +559,7 @@ void main() { ...@@ -511,7 +559,7 @@ void main() {
environment: anyNamed('environment'), environment: anyNamed('environment'),
)); ));
verify(processUtils.runSync( verify(processUtils.runSync(
<String>['git', 'describe', '--match', '*.*.*', '--first-parent', '--long', '--tags'], <String>['git', 'describe', '--match', '*.*.*-*.*.pre', '--first-parent', '--long', '--tags'],
workingDirectory: anyNamed('workingDirectory'), workingDirectory: anyNamed('workingDirectory'),
environment: anyNamed('environment'), environment: anyNamed('environment'),
)).called(1); )).called(1);
...@@ -530,10 +578,18 @@ void main() { ...@@ -530,10 +578,18 @@ void main() {
environment: anyNamed('environment'), environment: anyNamed('environment'),
)).thenReturn(RunResult(ProcessResult(109, 0, '', ''), <String>['git', 'fetch'])); )).thenReturn(RunResult(ProcessResult(109, 0, '', ''), <String>['git', 'fetch']));
when(processUtils.runSync( when(processUtils.runSync(
<String>['git', 'describe', '--match', '*.*.*', '--first-parent', '--long', '--tags'], <String>['git', 'tag', '--contains', 'HEAD'],
workingDirectory: anyNamed('workingDirectory'),
environment: anyNamed('environment'),
)).thenReturn(
RunResult(ProcessResult(110, 0, '', ''),
<String>['git', 'tag', '--contains', 'HEAD'],
));
when(processUtils.runSync(
<String>['git', 'describe', '--match', '*.*.*-*.*.pre', '--first-parent', '--long', '--tags'],
workingDirectory: anyNamed('workingDirectory'), workingDirectory: anyNamed('workingDirectory'),
environment: anyNamed('environment'), environment: anyNamed('environment'),
)).thenReturn(RunResult(ProcessResult(110, 0, 'v0.1.2-3-1234abcd', ''), <String>['git', 'describe'])); )).thenReturn(RunResult(ProcessResult(111, 0, 'v0.1.2-3-1234abcd', ''), <String>['git', 'describe']));
GitTagVersion.determine(processUtils, workingDirectory: '.', fetchTags: true); GitTagVersion.determine(processUtils, workingDirectory: '.', fetchTags: true);
...@@ -548,7 +604,7 @@ void main() { ...@@ -548,7 +604,7 @@ void main() {
environment: anyNamed('environment'), environment: anyNamed('environment'),
)).called(1); )).called(1);
verify(processUtils.runSync( verify(processUtils.runSync(
<String>['git', 'describe', '--match', '*.*.*', '--first-parent', '--long', '--tags'], <String>['git', 'describe', '--match', '*.*.*-*.*.pre', '--first-parent', '--long', '--tags'],
workingDirectory: anyNamed('workingDirectory'), workingDirectory: anyNamed('workingDirectory'),
environment: anyNamed('environment'), environment: anyNamed('environment'),
)).called(1); )).called(1);
...@@ -669,10 +725,15 @@ void fakeData( ...@@ -669,10 +725,15 @@ void fakeData(
environment: anyNamed('environment'), environment: anyNamed('environment'),
)).thenReturn(ProcessResult(105, 0, '', '')); )).thenReturn(ProcessResult(105, 0, '', ''));
when(pm.runSync( when(pm.runSync(
<String>['git', 'describe', '--match', '*.*.*', '--first-parent', '--long', '--tags'], <String>['git', 'tag', '--contains', 'HEAD'],
workingDirectory: anyNamed('workingDirectory'),
environment: anyNamed('environment'),
)).thenReturn(ProcessResult(106, 0, '', ''));
when(pm.runSync(
<String>['git', 'describe', '--match', '*.*.*-*.*.pre', '--first-parent', '--long', '--tags'],
workingDirectory: anyNamed('workingDirectory'), workingDirectory: anyNamed('workingDirectory'),
environment: anyNamed('environment'), environment: anyNamed('environment'),
)).thenReturn(ProcessResult(106, 0, 'v0.1.2-3-1234abcd', '')); )).thenReturn(ProcessResult(107, 0, 'v0.1.2-3-1234abcd', ''));
} }
class MockProcessManager extends Mock implements ProcessManager {} class MockProcessManager extends Mock implements ProcessManager {}
......
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