Skip to content

Commit 37ac901

Browse files
[flutter_tools] check first for stable tag, then dev tag (flutter#55342)
1 parent f582246 commit 37ac901

File tree

5 files changed

+148
-76
lines changed

5 files changed

+148
-76
lines changed

packages/flutter_tools/lib/src/version.dart

Lines changed: 60 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -752,80 +752,83 @@ class GitTagVersion {
752752
_runGit('git fetch $_flutterGit --tags', processUtils, workingDirectory);
753753
}
754754
}
755-
// `--match` glob must match old version tag `v1.2.3` and new `1.2.3-dev.4.5`
756-
return parse(_runGit('git describe --match *.*.* --first-parent --long --tags', processUtils, workingDirectory));
757-
}
758-
759-
// TODO(fujino): Deprecate this https://github.com/flutter/flutter/issues/53850
760-
/// Check for the release tag format of the form x.y.z-dev.m.n
761-
static GitTagVersion parseLegacyVersion(String version) {
762-
final RegExp versionPattern = RegExp(
763-
r'^([0-9]+)\.([0-9]+)\.([0-9]+)(-dev\.[0-9]+\.[0-9]+)?-([0-9]+)-g([a-f0-9]+)$');
764-
final List<String> parts = versionPattern.matchAsPrefix(version)?.groups(<int>[1, 2, 3, 4, 5, 6]);
765-
if (parts == null) {
766-
return const GitTagVersion.unknown();
755+
final List<String> tags = _runGit(
756+
'git tag --contains HEAD', processUtils, workingDirectory).split('\n');
757+
758+
// Check first for a stable tag
759+
final RegExp stableTagPattern = RegExp(r'^\d+\.\d+\.\d+$');
760+
for (final String tag in tags) {
761+
final String trimmedTag = tag.trim();
762+
if (stableTagPattern.hasMatch(trimmedTag)) {
763+
return parse(trimmedTag);
764+
}
767765
}
768-
final List<int> parsedParts = parts.take(5).map<int>(
769-
(String source) => source == null ? null : int.tryParse(source)).toList();
770-
List<int> devParts = <int>[null, null];
771-
if (parts[3] != null) {
772-
devParts = RegExp(r'^-dev\.(\d+)\.(\d+)')
773-
.matchAsPrefix(parts[3])
774-
?.groups(<int>[1, 2])
775-
?.map<int>(
776-
(String source) => source == null ? null : int.tryParse(source)
777-
)?.toList() ?? <int>[null, null];
766+
// Next check for a dev tag
767+
final RegExp devTagPattern = RegExp(r'^\d+\.\d+\.\d+-\d+\.\d+\.pre$');
768+
for (final String tag in tags) {
769+
final String trimmedTag = tag.trim();
770+
if (devTagPattern.hasMatch(trimmedTag)) {
771+
return parse(trimmedTag);
772+
}
778773
}
779-
return GitTagVersion(
780-
x: parsedParts[0],
781-
y: parsedParts[1],
782-
z: parsedParts[2],
783-
devVersion: devParts[0],
784-
devPatch: devParts[1],
785-
commits: parsedParts[4],
786-
hash: parts[5],
787-
gitTag: '${parts[0]}.${parts[1]}.${parts[2]}${parts[3] ?? ''}', // x.y.z-dev.m.n
774+
775+
// If we're not currently on a tag, use git describe to find the most
776+
// recent tag and number of commits past.
777+
return parse(
778+
_runGit(
779+
'git describe --match *.*.*-*.*.pre --first-parent --long --tags',
780+
processUtils,
781+
workingDirectory,
782+
)
788783
);
789784
}
790785

791-
/// Check for the release tag format of the form x.y.z-m.n.pre
786+
/// Parse a version string.
787+
///
788+
/// The version string can either be an exact release tag (e.g. '1.2.3' for
789+
/// stable or 1.2.3-4.5.pre for a dev) or the output of `git describe` (e.g.
790+
/// for commit abc123 that is 6 commits after tag 1.2.3-4.5.pre, git would
791+
/// return '1.2.3-4.5.pre-6-gabc123').
792792
static GitTagVersion parseVersion(String version) {
793793
final RegExp versionPattern = RegExp(
794-
r'^(\d+)\.(\d+)\.(\d+)(-\d+\.\d+\.pre)?-(\d+)-g([a-f0-9]+)$');
795-
final List<String> parts = versionPattern.matchAsPrefix(version)?.groups(<int>[1, 2, 3, 4, 5, 6]);
796-
if (parts == null) {
794+
r'^(\d+)\.(\d+)\.(\d+)(-\d+\.\d+\.pre)?(?:-(\d+)-g([a-f0-9]+))?$');
795+
final Match match = versionPattern.firstMatch(version.trim());
796+
if (match == null) {
797797
return const GitTagVersion.unknown();
798798
}
799-
final List<int> parsedParts = parts.take(5).map<int>(
800-
(String source) => source == null ? null : int.tryParse(source)).toList();
801-
List<int> devParts = <int>[null, null];
802-
if (parts[3] != null) {
803-
devParts = RegExp(r'^-(\d+)\.(\d+)\.pre')
804-
.matchAsPrefix(parts[3])
805-
?.groups(<int>[1, 2])
806-
?.map<int>(
807-
(String source) => source == null ? null : int.tryParse(source)
808-
)?.toList() ?? <int>[null, null];
799+
800+
final List<String> matchGroups = match.groups(<int>[1, 2, 3, 4, 5, 6]);
801+
final int x = matchGroups[0] == null ? null : int.tryParse(matchGroups[0]);
802+
final int y = matchGroups[1] == null ? null : int.tryParse(matchGroups[1]);
803+
final int z = matchGroups[2] == null ? null : int.tryParse(matchGroups[2]);
804+
final String devString = matchGroups[3];
805+
int devVersion, devPatch;
806+
if (devString != null) {
807+
final Match devMatch = RegExp(r'^-(\d+)\.(\d+)\.pre$')
808+
.firstMatch(devString);
809+
final List<String> devGroups = devMatch.groups(<int>[1, 2]);
810+
devVersion = devGroups[0] == null ? null : int.tryParse(devGroups[0]);
811+
devPatch = devGroups[1] == null ? null : int.tryParse(devGroups[1]);
809812
}
813+
// count of commits past last tagged version
814+
final int commits = matchGroups[4] == null ? 0 : int.tryParse(matchGroups[4]);
815+
final String hash = matchGroups[5] ?? '';
816+
810817
return GitTagVersion(
811-
x: parsedParts[0],
812-
y: parsedParts[1],
813-
z: parsedParts[2],
814-
devVersion: devParts[0],
815-
devPatch: devParts[1],
816-
commits: parsedParts[4],
817-
hash: parts[5],
818-
gitTag: '${parts[0]}.${parts[1]}.${parts[2]}${parts[3] ?? ''}', // x.y.z-m.n.pre
818+
x: x,
819+
y: y,
820+
z: z,
821+
devVersion: devVersion,
822+
devPatch: devPatch,
823+
commits: commits,
824+
hash: hash,
825+
gitTag: '$x.$y.$z${devString ?? ''}', // e.g. 1.2.3-4.5.pre
819826
);
820827
}
821828

822829
static GitTagVersion parse(String version) {
823830
GitTagVersion gitTagVersion;
824831

825-
gitTagVersion = parseLegacyVersion(version);
826-
if (gitTagVersion != const GitTagVersion.unknown()) {
827-
return gitTagVersion;
828-
}
829832
gitTagVersion = parseVersion(version);
830833
if (gitTagVersion != const GitTagVersion.unknown()) {
831834
return gitTagVersion;

packages/flutter_tools/test/commands.shard/hermetic/version_test.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -259,7 +259,7 @@ class MockProcessManager extends Mock implements ProcessManager {
259259
return ProcessResult(0, 0, '000000000000000000000', '');
260260
}
261261
if (commandStr ==
262-
'git describe --match *.*.* --first-parent --long --tags') {
262+
'git describe --match *.*.*-*.*.pre --first-parent --long --tags') {
263263
if (version.isNotEmpty) {
264264
return ProcessResult(0, 0, '$version-0-g00000000', '');
265265
}

packages/flutter_tools/test/commands.shard/permeable/upgrade_test.dart

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -238,7 +238,13 @@ void main() {
238238
fakeProcessManager = FakeProcessManager.list(<FakeCommand>[
239239
const FakeCommand(
240240
command: <String>[
241-
'git', 'describe', '--match', '*.*.*', '--first-parent', '--long', '--tags',
241+
'git', 'tag', '--contains', 'HEAD',
242+
],
243+
stdout: '',
244+
),
245+
const FakeCommand(
246+
command: <String>[
247+
'git', 'describe', '--match', '*.*.*-*.*.pre', '--first-parent', '--long', '--tags',
242248
],
243249
stdout: 'v1.12.16-19-gb45b676af',
244250
),

packages/flutter_tools/test/general.shard/runner/flutter_command_runner_test.dart

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -185,7 +185,9 @@ void main() {
185185
workingDirectory: Cache.flutterRoot)).thenReturn(result);
186186
when(processManager.runSync('git fetch https://github.com/flutter/flutter.git --tags'.split(' '),
187187
workingDirectory: Cache.flutterRoot)).thenReturn(result);
188-
when(processManager.runSync('git describe --match *.*.* --first-parent --long --tags'.split(' '),
188+
when(processManager.runSync('git tag --contains HEAD'.split(' '),
189+
workingDirectory: Cache.flutterRoot)).thenReturn(result);
190+
when(processManager.runSync('git describe --match *.*.*-*.*.pre --first-parent --long --tags'.split(' '),
189191
workingDirectory: Cache.flutterRoot)).thenReturn(result);
190192
when(processManager.runSync(FlutterVersion.gitLog('-n 1 --pretty=format:%ad --date=iso'.split(' ')),
191193
workingDirectory: Cache.flutterRoot)).thenReturn(result);

packages/flutter_tools/test/general.shard/version_test.dart

Lines changed: 77 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -394,16 +394,25 @@ void main() {
394394
const String hash = 'abcdef';
395395
GitTagVersion gitTagVersion;
396396

397-
// legacy tag format (x.y.z-dev.m.n), master channel
398-
gitTagVersion = GitTagVersion.parse('1.2.3-dev.4.5-4-g$hash');
399-
expect(gitTagVersion.frameworkVersionFor(hash), '1.2.3-5.0.pre.4');
400-
expect(gitTagVersion.gitTag, '1.2.3-dev.4.5');
397+
// Master channel
398+
gitTagVersion = GitTagVersion.parse('1.2.3-4.5.pre-13-g$hash');
399+
expect(gitTagVersion.frameworkVersionFor(hash), '1.2.3-5.0.pre.13');
400+
expect(gitTagVersion.gitTag, '1.2.3-4.5.pre');
401401
expect(gitTagVersion.devVersion, 4);
402402
expect(gitTagVersion.devPatch, 5);
403403

404-
// new tag release format, master channel
405-
gitTagVersion = GitTagVersion.parse('1.2.3-4.5.pre-13-g$hash');
406-
expect(gitTagVersion.frameworkVersionFor(hash), '1.2.3-5.0.pre.13');
404+
// Stable channel
405+
gitTagVersion = GitTagVersion.parse('1.2.3');
406+
expect(gitTagVersion.frameworkVersionFor(hash), '1.2.3');
407+
expect(gitTagVersion.x, 1);
408+
expect(gitTagVersion.y, 2);
409+
expect(gitTagVersion.z, 3);
410+
expect(gitTagVersion.devVersion, null);
411+
expect(gitTagVersion.devPatch, null);
412+
413+
// Dev channel
414+
gitTagVersion = GitTagVersion.parse('1.2.3-4.5.pre');
415+
expect(gitTagVersion.frameworkVersionFor(hash), '1.2.3-4.5.pre');
407416
expect(gitTagVersion.gitTag, '1.2.3-4.5.pre');
408417
expect(gitTagVersion.devVersion, 4);
409418
expect(gitTagVersion.devPatch, 5);
@@ -448,6 +457,29 @@ void main() {
448457
);
449458
});
450459

460+
testUsingContext('determine favors stable tags over dev tags', () {
461+
final MockProcessUtils mockProcessUtils = MockProcessUtils();
462+
when(mockProcessUtils.runSync(
463+
<String>['git', 'tag', '--contains', 'HEAD'],
464+
workingDirectory: anyNamed('workingDirectory'),
465+
environment: anyNamed('environment'),
466+
)).thenReturn(RunResult(
467+
ProcessResult(1, 0, '1.2.3-0.0.pre\n1.2.3\n1.2.3-0.1.pre', ''),
468+
<String>['git', 'tag', '--contains', 'HEAD'],
469+
));
470+
final GitTagVersion version = GitTagVersion.determine(mockProcessUtils, workingDirectory: '.');
471+
expect(version.gitTag, '1.2.3');
472+
expect(version.devPatch, null);
473+
expect(version.devVersion, null);
474+
// We shouldn't have to fallback to git describe, because we are exactly
475+
// on a release tag.
476+
verifyNever(mockProcessUtils.runSync(
477+
<String>['git', 'describe', '--match', '*.*.*-*.*.pre', '--first-parent', '--long', '--tags'],
478+
workingDirectory: anyNamed('workingDirectory'),
479+
environment: anyNamed('environment'),
480+
));
481+
});
482+
451483
testUsingContext('determine does not call fetch --tags', () {
452484
final MockProcessUtils processUtils = MockProcessUtils();
453485
when(processUtils.runSync(
@@ -456,10 +488,18 @@ void main() {
456488
environment: anyNamed('environment'),
457489
)).thenReturn(RunResult(ProcessResult(105, 0, '', ''), <String>['git', 'fetch']));
458490
when(processUtils.runSync(
459-
<String>['git', 'describe', '--match', '*.*.*', '--first-parent', '--long', '--tags'],
491+
<String>['git', 'describe', '--match', '*.*.*-*.*.pre', '--first-parent', '--long', '--tags'],
460492
workingDirectory: anyNamed('workingDirectory'),
461493
environment: anyNamed('environment'),
462494
)).thenReturn(RunResult(ProcessResult(106, 0, 'v0.1.2-3-1234abcd', ''), <String>['git', 'describe']));
495+
when(processUtils.runSync(
496+
<String>['git', 'tag', '--contains', 'HEAD'],
497+
workingDirectory: anyNamed('workingDirectory'),
498+
environment: anyNamed('environment'),
499+
)).thenReturn(
500+
RunResult(ProcessResult(110, 0, '', ''),
501+
<String>['git', 'tag', '--contains', 'HEAD'],
502+
));
463503

464504
GitTagVersion.determine(processUtils, workingDirectory: '.');
465505

@@ -474,7 +514,7 @@ void main() {
474514
environment: anyNamed('environment'),
475515
));
476516
verify(processUtils.runSync(
477-
<String>['git', 'describe', '--match', '*.*.*', '--first-parent', '--long', '--tags'],
517+
<String>['git', 'describe', '--match', '*.*.*-*.*.pre', '--first-parent', '--long', '--tags'],
478518
workingDirectory: anyNamed('workingDirectory'),
479519
environment: anyNamed('environment'),
480520
)).called(1);
@@ -493,10 +533,18 @@ void main() {
493533
environment: anyNamed('environment'),
494534
)).thenReturn(RunResult(ProcessResult(106, 0, '', ''), <String>['git', 'fetch']));
495535
when(processUtils.runSync(
496-
<String>['git', 'describe', '--match', '*.*.*', '--first-parent', '--long', '--tags'],
536+
<String>['git', 'describe', '--match', '*.*.*-*.*.pre', '--first-parent', '--long', '--tags'],
497537
workingDirectory: anyNamed('workingDirectory'),
498538
environment: anyNamed('environment'),
499539
)).thenReturn(RunResult(ProcessResult(107, 0, 'v0.1.2-3-1234abcd', ''), <String>['git', 'describe']));
540+
when(processUtils.runSync(
541+
<String>['git', 'tag', '--contains', 'HEAD'],
542+
workingDirectory: anyNamed('workingDirectory'),
543+
environment: anyNamed('environment'),
544+
)).thenReturn(
545+
RunResult(ProcessResult(108, 0, '', ''),
546+
<String>['git', 'tag', '--contains', 'HEAD'],
547+
));
500548

501549
GitTagVersion.determine(processUtils, workingDirectory: '.', fetchTags: true);
502550

@@ -511,7 +559,7 @@ void main() {
511559
environment: anyNamed('environment'),
512560
));
513561
verify(processUtils.runSync(
514-
<String>['git', 'describe', '--match', '*.*.*', '--first-parent', '--long', '--tags'],
562+
<String>['git', 'describe', '--match', '*.*.*-*.*.pre', '--first-parent', '--long', '--tags'],
515563
workingDirectory: anyNamed('workingDirectory'),
516564
environment: anyNamed('environment'),
517565
)).called(1);
@@ -530,10 +578,18 @@ void main() {
530578
environment: anyNamed('environment'),
531579
)).thenReturn(RunResult(ProcessResult(109, 0, '', ''), <String>['git', 'fetch']));
532580
when(processUtils.runSync(
533-
<String>['git', 'describe', '--match', '*.*.*', '--first-parent', '--long', '--tags'],
581+
<String>['git', 'tag', '--contains', 'HEAD'],
582+
workingDirectory: anyNamed('workingDirectory'),
583+
environment: anyNamed('environment'),
584+
)).thenReturn(
585+
RunResult(ProcessResult(110, 0, '', ''),
586+
<String>['git', 'tag', '--contains', 'HEAD'],
587+
));
588+
when(processUtils.runSync(
589+
<String>['git', 'describe', '--match', '*.*.*-*.*.pre', '--first-parent', '--long', '--tags'],
534590
workingDirectory: anyNamed('workingDirectory'),
535591
environment: anyNamed('environment'),
536-
)).thenReturn(RunResult(ProcessResult(110, 0, 'v0.1.2-3-1234abcd', ''), <String>['git', 'describe']));
592+
)).thenReturn(RunResult(ProcessResult(111, 0, 'v0.1.2-3-1234abcd', ''), <String>['git', 'describe']));
537593

538594
GitTagVersion.determine(processUtils, workingDirectory: '.', fetchTags: true);
539595

@@ -548,7 +604,7 @@ void main() {
548604
environment: anyNamed('environment'),
549605
)).called(1);
550606
verify(processUtils.runSync(
551-
<String>['git', 'describe', '--match', '*.*.*', '--first-parent', '--long', '--tags'],
607+
<String>['git', 'describe', '--match', '*.*.*-*.*.pre', '--first-parent', '--long', '--tags'],
552608
workingDirectory: anyNamed('workingDirectory'),
553609
environment: anyNamed('environment'),
554610
)).called(1);
@@ -669,10 +725,15 @@ void fakeData(
669725
environment: anyNamed('environment'),
670726
)).thenReturn(ProcessResult(105, 0, '', ''));
671727
when(pm.runSync(
672-
<String>['git', 'describe', '--match', '*.*.*', '--first-parent', '--long', '--tags'],
728+
<String>['git', 'tag', '--contains', 'HEAD'],
729+
workingDirectory: anyNamed('workingDirectory'),
730+
environment: anyNamed('environment'),
731+
)).thenReturn(ProcessResult(106, 0, '', ''));
732+
when(pm.runSync(
733+
<String>['git', 'describe', '--match', '*.*.*-*.*.pre', '--first-parent', '--long', '--tags'],
673734
workingDirectory: anyNamed('workingDirectory'),
674735
environment: anyNamed('environment'),
675-
)).thenReturn(ProcessResult(106, 0, 'v0.1.2-3-1234abcd', ''));
736+
)).thenReturn(ProcessResult(107, 0, 'v0.1.2-3-1234abcd', ''));
676737
}
677738

678739
class MockProcessManager extends Mock implements ProcessManager {}

0 commit comments

Comments
 (0)