Add FlutterVersion.engineCommitDate
, helps signal engine artifact SHA issues (#163652)
Closes #163644. Before this change: ```sh flutter-dev --version Flutter 3.30.0-1.0.pre.215 • channel [user-branch] • https://github.com/matanlurey/flutter Framework • revision cead517e4e (79 seconds ago) • 2025-02-19 13:00:11 -0800 Engine • revision 39b4951f8f Tools • Dart 3.8.0 (build 3.8.0-92.0.dev) • DevTools 2.43.0 ``` After this change: ```sh flutter-dev --version Flutter 3.30.0-1.0.pre.215 • channel [user-branch] • https://github.com/matanlurey/flutter Framework • revision cead517e4e (79 seconds ago) • 2025-02-19 13:00:11 -0800 Engine • revision 39b4951f8f (79 seconds ago) • 2025-02-18 13:42:53 -0800 Tools • Dart 3.8.0 (build 3.8.0-92.0.dev) • DevTools 2.43.0 ``` /cc @jtmcdole as this could be helpful for sleuthing artifact mismatch.
This commit is contained in:
parent
281612e648
commit
7df3f8fc06
@ -168,16 +168,26 @@ abstract class FlutterVersion {
|
|||||||
/// `master`, `dev`, `beta`, `stable`; or old ones, like `alpha`, `hackathon`, ...
|
/// `master`, `dev`, `beta`, `stable`; or old ones, like `alpha`, `hackathon`, ...
|
||||||
String get channel;
|
String get channel;
|
||||||
|
|
||||||
|
/// The SHA describing the commit being used for the SDK and tools provide in `flutter/flutter`.
|
||||||
|
///
|
||||||
|
/// The _exception_ is the _engine artifacts_, which are downloaded separately as [engineRevision].
|
||||||
String get frameworkRevision;
|
String get frameworkRevision;
|
||||||
String get frameworkRevisionShort => _shortGitRevision(frameworkRevision);
|
|
||||||
|
|
||||||
|
/// The shorter Git commit SHA of [frameworkRevion].
|
||||||
|
String get frameworkRevisionShort => _shortGitRevision(frameworkRevision);
|
||||||
String get frameworkVersion;
|
String get frameworkVersion;
|
||||||
|
|
||||||
String get devToolsVersion;
|
String get devToolsVersion;
|
||||||
|
|
||||||
String get dartSdkVersion;
|
String get dartSdkVersion;
|
||||||
|
|
||||||
|
/// The SHA describing the commit being used for the engine artifacts, which are compiled from the `engine/` sub-directory.
|
||||||
|
///
|
||||||
|
/// When using a standard release build, or master channel, [engineRevision] will be identical to [frameworkRevision] since
|
||||||
|
/// the monorepository merge (as of 2025); however when modifying the framework (or engine) locally, or using a flag such
|
||||||
|
/// as `FLUTTER_PREBUILT_ENGINE_VERSION=...`, the engine SHA will be _different_ than the [frameworkRevision].
|
||||||
String get engineRevision;
|
String get engineRevision;
|
||||||
|
|
||||||
|
/// The shorter Git commit SHA of [engineRevision].
|
||||||
String get engineRevisionShort => _shortGitRevision(engineRevision);
|
String get engineRevisionShort => _shortGitRevision(engineRevision);
|
||||||
|
|
||||||
// This is static as it is called from a constructor.
|
// This is static as it is called from a constructor.
|
||||||
@ -187,18 +197,24 @@ abstract class FlutterVersion {
|
|||||||
|
|
||||||
final String flutterRoot;
|
final String flutterRoot;
|
||||||
|
|
||||||
String? _frameworkAge;
|
String _getTimeSinceCommit({String? revision}) {
|
||||||
|
return _runGit(
|
||||||
// TODO(fujino): calculate this relative to frameworkCommitDate for
|
FlutterVersion.gitLog(<String>[
|
||||||
// _FlutterVersionFromFile so we don't need a git call.
|
'-n',
|
||||||
String get frameworkAge {
|
'1',
|
||||||
return _frameworkAge ??= _runGit(
|
'--pretty=format:%ar',
|
||||||
FlutterVersion.gitLog(<String>['-n', '1', '--pretty=format:%ar']).join(' '),
|
if (revision != null) revision,
|
||||||
|
]).join(' '),
|
||||||
globals.processUtils,
|
globals.processUtils,
|
||||||
flutterRoot,
|
flutterRoot,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO(fujino): calculate this relative to frameworkCommitDate for
|
||||||
|
// _FlutterVersionFromFile so we don't need a git call.
|
||||||
|
late final String frameworkAge = _getTimeSinceCommit();
|
||||||
|
late final String engineAge = _getTimeSinceCommit(revision: engineRevision);
|
||||||
|
|
||||||
void ensureVersionFile();
|
void ensureVersionFile();
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@ -209,12 +225,16 @@ abstract class FlutterVersion {
|
|||||||
'Flutter$versionText • channel $channel • ${repositoryUrl ?? 'unknown source'}';
|
'Flutter$versionText • channel $channel • ${repositoryUrl ?? 'unknown source'}';
|
||||||
final String frameworkText =
|
final String frameworkText =
|
||||||
'Framework • revision $frameworkRevisionShort ($frameworkAge) • $frameworkCommitDate';
|
'Framework • revision $frameworkRevisionShort ($frameworkAge) • $frameworkCommitDate';
|
||||||
final String engineText = 'Engine • revision $engineRevisionShort';
|
String engineText = 'Engine • revision $engineRevisionShort ($engineAge)';
|
||||||
|
if (engineCommitDate != null) {
|
||||||
|
engineText = '$engineText • $engineCommitDate';
|
||||||
|
}
|
||||||
|
|
||||||
final String toolsText = 'Tools • Dart $dartSdkVersion • DevTools $devToolsVersion';
|
final String toolsText = 'Tools • Dart $dartSdkVersion • DevTools $devToolsVersion';
|
||||||
|
|
||||||
// Flutter 1.10.2-pre.69 • channel master • https://github.com/flutter/flutter.git
|
// Flutter 1.10.2-pre.69 • channel master • https://github.com/flutter/flutter.git
|
||||||
// Framework • revision 340c158f32 (85 minutes ago) • 2018-10-26 11:27:22 -0400
|
// Framework • revision 340c158f32 (85 minutes ago) • 2018-10-26 11:27:22 -0400
|
||||||
// Engine • revision 9c46333e14
|
// Engine • revision 9c46333e14 (96 minutes ago) • 2018-10-26 11:16:22 -0400
|
||||||
// Tools • Dart 2.1.0 (build 2.1.0-dev.8.0 bf26f760b1)
|
// Tools • Dart 2.1.0 (build 2.1.0-dev.8.0 bf26f760b1)
|
||||||
|
|
||||||
return '$flutterText\n$frameworkText\n$engineText\n$toolsText';
|
return '$flutterText\n$frameworkText\n$engineText\n$toolsText';
|
||||||
@ -227,16 +247,25 @@ abstract class FlutterVersion {
|
|||||||
'frameworkRevision': frameworkRevision,
|
'frameworkRevision': frameworkRevision,
|
||||||
'frameworkCommitDate': frameworkCommitDate,
|
'frameworkCommitDate': frameworkCommitDate,
|
||||||
'engineRevision': engineRevision,
|
'engineRevision': engineRevision,
|
||||||
|
if (engineCommitDate != null) 'engineCommitDate': engineCommitDate!,
|
||||||
'dartSdkVersion': dartSdkVersion,
|
'dartSdkVersion': dartSdkVersion,
|
||||||
'devToolsVersion': devToolsVersion,
|
'devToolsVersion': devToolsVersion,
|
||||||
'flutterVersion': frameworkVersion,
|
'flutterVersion': frameworkVersion,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// A date String describing the last framework commit.
|
/// A date String describing the [frameworkRevision] commit.
|
||||||
///
|
///
|
||||||
/// If a git command fails, this will return a placeholder date.
|
/// If a git command fails, this will return a placeholder date.
|
||||||
String get frameworkCommitDate;
|
String get frameworkCommitDate;
|
||||||
|
|
||||||
|
/// A date String describing the [engineRevision] commit.
|
||||||
|
///
|
||||||
|
/// If a git command fails, this will return a placeholder date.
|
||||||
|
///
|
||||||
|
/// If no date was recorded ([engineCommitDate] is a newly stored field),
|
||||||
|
/// the date is omitted, and left `null`.
|
||||||
|
String? get engineCommitDate;
|
||||||
|
|
||||||
/// Checks if the currently installed version of Flutter is up-to-date, and
|
/// Checks if the currently installed version of Flutter is up-to-date, and
|
||||||
/// warns the user if it isn't.
|
/// warns the user if it isn't.
|
||||||
///
|
///
|
||||||
@ -439,6 +468,7 @@ class _FlutterVersionFromFile extends FlutterVersion {
|
|||||||
required this.frameworkRevision,
|
required this.frameworkRevision,
|
||||||
required this.frameworkCommitDate,
|
required this.frameworkCommitDate,
|
||||||
required this.engineRevision,
|
required this.engineRevision,
|
||||||
|
required this.engineCommitDate,
|
||||||
required this.dartSdkVersion,
|
required this.dartSdkVersion,
|
||||||
required this.devToolsVersion,
|
required this.devToolsVersion,
|
||||||
required this.gitTagVersion,
|
required this.gitTagVersion,
|
||||||
@ -463,6 +493,7 @@ class _FlutterVersionFromFile extends FlutterVersion {
|
|||||||
frameworkRevision: manifest['frameworkRevision']! as String,
|
frameworkRevision: manifest['frameworkRevision']! as String,
|
||||||
frameworkCommitDate: manifest['frameworkCommitDate']! as String,
|
frameworkCommitDate: manifest['frameworkCommitDate']! as String,
|
||||||
engineRevision: manifest['engineRevision']! as String,
|
engineRevision: manifest['engineRevision']! as String,
|
||||||
|
engineCommitDate: manifest['engineCommitDate'] as String?,
|
||||||
dartSdkVersion: manifest['dartSdkVersion']! as String,
|
dartSdkVersion: manifest['dartSdkVersion']! as String,
|
||||||
devToolsVersion: manifest['devToolsVersion']! as String,
|
devToolsVersion: manifest['devToolsVersion']! as String,
|
||||||
gitTagVersion: GitTagVersion.parse(manifest['flutterVersion']! as String),
|
gitTagVersion: GitTagVersion.parse(manifest['flutterVersion']! as String),
|
||||||
@ -503,6 +534,9 @@ class _FlutterVersionFromFile extends FlutterVersion {
|
|||||||
@override
|
@override
|
||||||
final String frameworkCommitDate;
|
final String frameworkCommitDate;
|
||||||
|
|
||||||
|
@override
|
||||||
|
final String? engineCommitDate;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
final String engineRevision;
|
final String engineRevision;
|
||||||
|
|
||||||
@ -537,6 +571,16 @@ class _FlutterVersionGit extends FlutterVersion {
|
|||||||
@override
|
@override
|
||||||
String get frameworkCommitDate => _gitCommitDate(lenient: true, workingDirectory: flutterRoot);
|
String get frameworkCommitDate => _gitCommitDate(lenient: true, workingDirectory: flutterRoot);
|
||||||
|
|
||||||
|
// This uses 'late final' instead of 'String get' because unlike frameworkCommitDate, it is
|
||||||
|
// operating based on a 'gitRef: ...', which we can assume to be immutable in the context of
|
||||||
|
// this invocation (possibly HEAD could change, but gitRef should not).
|
||||||
|
@override
|
||||||
|
late final String engineCommitDate = _gitCommitDate(
|
||||||
|
gitRef: engineRevision,
|
||||||
|
lenient: true,
|
||||||
|
workingDirectory: flutterRoot,
|
||||||
|
);
|
||||||
|
|
||||||
String? _repositoryUrl;
|
String? _repositoryUrl;
|
||||||
@override
|
@override
|
||||||
String? get repositoryUrl {
|
String? get repositoryUrl {
|
||||||
|
@ -168,6 +168,33 @@ void main() {
|
|||||||
],
|
],
|
||||||
stdout: getChannelUpToDateVersion().toString(),
|
stdout: getChannelUpToDateVersion().toString(),
|
||||||
),
|
),
|
||||||
|
const FakeCommand(
|
||||||
|
command: <String>[
|
||||||
|
'git',
|
||||||
|
'-c',
|
||||||
|
'log.showSignature=false',
|
||||||
|
'log',
|
||||||
|
'-n',
|
||||||
|
'1',
|
||||||
|
'--pretty=format:%ar',
|
||||||
|
'abcdefg',
|
||||||
|
],
|
||||||
|
stdout: '2 seconds ago',
|
||||||
|
),
|
||||||
|
FakeCommand(
|
||||||
|
command: const <String>[
|
||||||
|
'git',
|
||||||
|
'-c',
|
||||||
|
'log.showSignature=false',
|
||||||
|
'log',
|
||||||
|
'abcdefg',
|
||||||
|
'-n',
|
||||||
|
'1',
|
||||||
|
'--pretty=format:%ad',
|
||||||
|
'--date=iso',
|
||||||
|
],
|
||||||
|
stdout: getChannelUpToDateVersion().toString(),
|
||||||
|
),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
final FlutterVersion flutterVersion = FlutterVersion(
|
final FlutterVersion flutterVersion = FlutterVersion(
|
||||||
@ -185,7 +212,7 @@ void main() {
|
|||||||
flutterVersion.toString(),
|
flutterVersion.toString(),
|
||||||
'Flutter • channel $channel • $flutterUpstreamUrl\n'
|
'Flutter • channel $channel • $flutterUpstreamUrl\n'
|
||||||
'Framework • revision 1234abcd (1 second ago) • ${getChannelUpToDateVersion()}\n'
|
'Framework • revision 1234abcd (1 second ago) • ${getChannelUpToDateVersion()}\n'
|
||||||
'Engine • revision abcdefg\n'
|
'Engine • revision abcdefg (2 seconds ago) • ${getChannelUpToDateVersion()}\n'
|
||||||
'Tools • Dart 2.12.0 • DevTools 2.8.0',
|
'Tools • Dart 2.12.0 • DevTools 2.8.0',
|
||||||
);
|
);
|
||||||
expect(flutterVersion.frameworkAge, '1 second ago');
|
expect(flutterVersion.frameworkAge, '1 second ago');
|
||||||
@ -689,6 +716,23 @@ void main() {
|
|||||||
.ago(VersionFreshnessValidator.versionAgeConsideredUpToDate('stable') ~/ 2)
|
.ago(VersionFreshnessValidator.versionAgeConsideredUpToDate('stable') ~/ 2)
|
||||||
.toString(),
|
.toString(),
|
||||||
),
|
),
|
||||||
|
FakeCommand(
|
||||||
|
command: const <String>[
|
||||||
|
'git',
|
||||||
|
'-c',
|
||||||
|
'log.showSignature=false',
|
||||||
|
'log',
|
||||||
|
'abcdefg',
|
||||||
|
'-n',
|
||||||
|
'1',
|
||||||
|
'--pretty=format:%ad',
|
||||||
|
'--date=iso',
|
||||||
|
],
|
||||||
|
stdout:
|
||||||
|
_testClock
|
||||||
|
.ago(VersionFreshnessValidator.versionAgeConsideredUpToDate('stable') ~/ 2)
|
||||||
|
.toString(),
|
||||||
|
),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
final MemoryFileSystem fs = MemoryFileSystem.test();
|
final MemoryFileSystem fs = MemoryFileSystem.test();
|
||||||
@ -713,6 +757,7 @@ void main() {
|
|||||||
"frameworkRevision": "1234abcd",
|
"frameworkRevision": "1234abcd",
|
||||||
"frameworkCommitDate": "2014-10-02 00:00:00.000Z",
|
"frameworkCommitDate": "2014-10-02 00:00:00.000Z",
|
||||||
"engineRevision": "abcdefg",
|
"engineRevision": "abcdefg",
|
||||||
|
"engineCommitDate": "2014-10-02 00:00:00.000Z",
|
||||||
"dartSdkVersion": "2.12.0",
|
"dartSdkVersion": "2.12.0",
|
||||||
"devToolsVersion": "2.8.0",
|
"devToolsVersion": "2.8.0",
|
||||||
"flutterVersion": "0.0.0-unknown"
|
"flutterVersion": "0.0.0-unknown"
|
||||||
@ -793,6 +838,67 @@ void main() {
|
|||||||
overrides: <Type, Generator>{ProcessManager: () => processManager, Cache: () => cache},
|
overrides: <Type, Generator>{ProcessManager: () => processManager, Cache: () => cache},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
testUsingContext(
|
||||||
|
'_FlutterVersionFromFile ignores engineCommitDate if historically omitted',
|
||||||
|
() async {
|
||||||
|
final MemoryFileSystem fs = MemoryFileSystem.test();
|
||||||
|
final Directory flutterRoot = fs.directory('/path/to/flutter');
|
||||||
|
final Directory cacheDir = flutterRoot.childDirectory('bin').childDirectory('cache')
|
||||||
|
..createSync(recursive: true);
|
||||||
|
|
||||||
|
const Map<String, Object> versionJson = <String, Object>{
|
||||||
|
'channel': 'stable',
|
||||||
|
'frameworkVersion': '1.2.3',
|
||||||
|
'repositoryUrl': 'https://github.com/flutter/flutter.git',
|
||||||
|
'frameworkRevision': '1234abcd',
|
||||||
|
'frameworkCommitDate': '2023-04-28 12:34:56 -0400',
|
||||||
|
'engineRevision': 'deadbeef',
|
||||||
|
'dartSdkVersion': 'deadbeef2',
|
||||||
|
'devToolsVersion': '0000000',
|
||||||
|
'flutterVersion': 'foo',
|
||||||
|
};
|
||||||
|
cacheDir.childFile('flutter.version.json').writeAsStringSync(jsonEncode(versionJson));
|
||||||
|
|
||||||
|
processManager.addCommands(<FakeCommand>[
|
||||||
|
const FakeCommand(
|
||||||
|
command: <String>[
|
||||||
|
'git',
|
||||||
|
'-c',
|
||||||
|
'log.showSignature=false',
|
||||||
|
'log',
|
||||||
|
'-n',
|
||||||
|
'1',
|
||||||
|
'--pretty=format:%ar',
|
||||||
|
],
|
||||||
|
stdout: '1 second ago',
|
||||||
|
),
|
||||||
|
const FakeCommand(
|
||||||
|
command: <String>[
|
||||||
|
'git',
|
||||||
|
'-c',
|
||||||
|
'log.showSignature=false',
|
||||||
|
'log',
|
||||||
|
'-n',
|
||||||
|
'1',
|
||||||
|
'--pretty=format:%ar',
|
||||||
|
'deadbeef',
|
||||||
|
],
|
||||||
|
stdout: '1 second ago',
|
||||||
|
),
|
||||||
|
]);
|
||||||
|
|
||||||
|
final FlutterVersion flutterVersion = FlutterVersion(
|
||||||
|
clock: _testClock,
|
||||||
|
fs: fs,
|
||||||
|
flutterRoot: flutterRoot.path,
|
||||||
|
);
|
||||||
|
expect(flutterVersion.engineCommitDate, isNull);
|
||||||
|
expect(flutterVersion.toJson(), isNot(contains('engineCommitDate')));
|
||||||
|
expect(flutterVersion.toString(), contains('Engine • revision deadbeef (1 second ago)\n'));
|
||||||
|
},
|
||||||
|
overrides: <Type, Generator>{ProcessManager: () => processManager, Cache: () => cache},
|
||||||
|
);
|
||||||
|
|
||||||
testUsingContext(
|
testUsingContext(
|
||||||
'FlutterVersion() falls back to git if .version.json is malformed',
|
'FlutterVersion() falls back to git if .version.json is malformed',
|
||||||
() async {
|
() async {
|
||||||
@ -846,6 +952,23 @@ void main() {
|
|||||||
.ago(VersionFreshnessValidator.versionAgeConsideredUpToDate('stable') ~/ 2)
|
.ago(VersionFreshnessValidator.versionAgeConsideredUpToDate('stable') ~/ 2)
|
||||||
.toString(),
|
.toString(),
|
||||||
),
|
),
|
||||||
|
FakeCommand(
|
||||||
|
command: const <String>[
|
||||||
|
'git',
|
||||||
|
'-c',
|
||||||
|
'log.showSignature=false',
|
||||||
|
'log',
|
||||||
|
'abcdefg',
|
||||||
|
'-n',
|
||||||
|
'1',
|
||||||
|
'--pretty=format:%ad',
|
||||||
|
'--date=iso',
|
||||||
|
],
|
||||||
|
stdout:
|
||||||
|
_testClock
|
||||||
|
.ago(VersionFreshnessValidator.versionAgeConsideredUpToDate('stable') ~/ 2)
|
||||||
|
.toString(),
|
||||||
|
),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
// version file exists in a malformed state
|
// version file exists in a malformed state
|
||||||
|
@ -366,6 +366,8 @@ class FakeFlutterVersion implements FlutterVersion {
|
|||||||
this.devToolsVersion = '2.8.0',
|
this.devToolsVersion = '2.8.0',
|
||||||
this.engineRevision = 'abcdefghijklmnopqrstuvwxyz',
|
this.engineRevision = 'abcdefghijklmnopqrstuvwxyz',
|
||||||
this.engineRevisionShort = 'abcde',
|
this.engineRevisionShort = 'abcde',
|
||||||
|
this.engineAge = '0 hours ago',
|
||||||
|
this.engineCommitDate = '12/01/01',
|
||||||
this.repositoryUrl = 'https://github.com/flutter/flutter.git',
|
this.repositoryUrl = 'https://github.com/flutter/flutter.git',
|
||||||
this.frameworkVersion = '0.0.0',
|
this.frameworkVersion = '0.0.0',
|
||||||
this.frameworkRevision = '11111111111111111111',
|
this.frameworkRevision = '11111111111111111111',
|
||||||
@ -417,6 +419,12 @@ class FakeFlutterVersion implements FlutterVersion {
|
|||||||
@override
|
@override
|
||||||
final String engineRevisionShort;
|
final String engineRevisionShort;
|
||||||
|
|
||||||
|
@override
|
||||||
|
final String? engineCommitDate;
|
||||||
|
|
||||||
|
@override
|
||||||
|
final String engineAge;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
final String? repositoryUrl;
|
final String? repositoryUrl;
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user