fix: --flutter-version=hash stopped working (#3478)

This commit is contained in:
Eric Seidel
2026-01-26 14:51:18 -08:00
committed by GitHub
parent cbef35914e
commit b064f1e76f
2 changed files with 59 additions and 50 deletions
@@ -214,29 +214,37 @@ class ShorebirdFlutter {
.firstOrNull;
}
/// Pattern for a valid git hash (4-40 hex characters).
/// Git allows short hashes as long as they're unambiguous.
static final _gitHashPattern = RegExp(r'^[0-9a-fA-F]{4,40}$');
/// Translates [versionOrHash] into a Flutter revision. If this is a semver
/// version, it will simply parse that into a [Version]. If not, it will
/// attempt to look up the Flutter version for the provided revision hash and
/// return the hash if a version is found, or null if not.
/// version, it will look up the git revision for that version. If not, it
/// will check if it's a valid git hash that exists in the local Flutter repo.
///
/// Returns the full hash if valid, or null if it's neither a valid semver
/// version nor a valid git hash that exists locally.
Future<String?> resolveFlutterRevision(String versionOrHash) async {
final parsedVersion = tryParseVersion(versionOrHash);
if (parsedVersion != null) {
return getRevisionForVersion(versionOrHash);
}
// If we were unable to parse the version, assume it's a revision hash.
try {
final version = await getVersionForRevision(
flutterRevision: versionOrHash,
);
if (version != null) {
return versionOrHash;
}
} on Exception {
// If we were unable to parse the version, check if it's a valid git hash.
if (!_gitHashPattern.hasMatch(versionOrHash)) {
return null;
}
return null;
// Verify the hash exists locally by resolving it to its full hash.
try {
final fullHash = await git.revParse(
revision: versionOrHash,
directory: _workingDirectory(),
);
return fullHash;
} on ProcessException {
return null;
}
}
/// Translates [versionOrHash] into a Flutter [Version]. If [versionOrHash]
@@ -313,62 +313,63 @@ Tools • Dart 3.0.6 • DevTools 2.23.1''');
);
});
group('when input is a commit hash that maps to a Flutter version', () {
group('when input is a valid git hash that exists locally', () {
const fullHash = 'eead750584a909f506eb6fc111ece5d8fed4aa39';
setUp(() {
when(
() => git.forEachRef(
() => git.revParse(
revision: any(named: 'revision'),
directory: any(named: 'directory'),
contains: any(named: 'contains'),
format: any(named: 'format'),
pattern: any(named: 'pattern'),
),
).thenAnswer((_) async => 'origin/flutter_release/1.2.3');
).thenAnswer((_) async => fullHash);
});
test('returns the input string', () async {
test('returns full hash for full input', () async {
final revision = await runWithOverrides(
() => shorebirdFlutter.resolveFlutterRevision(fullHash),
);
expect(revision, equals(fullHash));
});
test('returns full hash for short input', () async {
final revision = await runWithOverrides(
() => shorebirdFlutter.resolveFlutterRevision('deadbeef'),
);
expect(revision, equals('deadbeef'));
expect(revision, equals(fullHash));
});
});
group(
'when input is not a commit hash that maps to a Flutter version',
() {
setUp(() {
when(
() => git.forEachRef(
directory: any(named: 'directory'),
contains: any(named: 'contains'),
format: any(named: 'format'),
pattern: any(named: 'pattern'),
),
).thenAnswer((_) async => '');
});
test('returns the input string', () async {
final revision = await runWithOverrides(
() => shorebirdFlutter.resolveFlutterRevision('not-a-version'),
);
expect(revision, isNull);
});
},
);
group('when exception occurs doing revision lookup', () {
group('when input is a valid git hash format but does not exist', () {
setUp(() {
when(
() => git.forEachRef(
() => git.revParse(
revision: any(named: 'revision'),
directory: any(named: 'directory'),
contains: any(named: 'contains'),
format: any(named: 'format'),
pattern: any(named: 'pattern'),
),
).thenThrow(Exception('oops'));
).thenThrow(
const ProcessException('git', ['rev-parse']),
);
});
test('returns null', () async {
const validHash = 'eead750584a909f506eb6fc111ece5d8fed4aa39';
final revision = await runWithOverrides(
() => shorebirdFlutter.resolveFlutterRevision(validHash),
);
expect(revision, isNull);
});
});
group('when input is not a valid git hash format', () {
test('returns null for too-short hash', () async {
final revision = await runWithOverrides(
() => shorebirdFlutter.resolveFlutterRevision('abc'),
);
expect(revision, isNull);
});
test('returns null for non-hex string', () async {
final revision = await runWithOverrides(
() => shorebirdFlutter.resolveFlutterRevision('not-a-version'),
);