fix(shorebird_cli): better handling for platforms that don't support flavors (#3308)

This commit is contained in:
Bryan Oltman
2025-09-08 11:35:14 -04:00
committed by GitHub
parent bcc982b8f8
commit 779821c0f3
6 changed files with 799 additions and 659 deletions
File diff suppressed because it is too large Load Diff
@@ -257,7 +257,11 @@ of the iOS app that is using this module. (aar and ios-framework only)''',
await releaser.assertPreconditions();
await assertArgsAreValid(releaser);
await shorebirdValidator.validateFlavors(flavorArg: flavor);
try {
await shorebirdValidator.validateFlavors(flavorArg: flavor);
} on ValidationFailedException {
throw ProcessExit(ExitCode.config.code);
}
await cache.updateAll();
@@ -148,6 +148,21 @@ To fix, update your pubspec.yaml to include the following:
/// Runs [FlavorValidator] and throws a [ValidationFailedException] if any
/// issues are found.
Future<void> validateFlavors({required String? flavorArg}) async {
final platformSupportsFlavors = !platform.isWindows && !platform.isLinux;
if (!platformSupportsFlavors) {
if (flavorArg != null) {
logger
..err('Flavors are not supported on this platform.')
..info(
'''Please re-run this command without the --flavor argument. The app id ${lightCyan.wrap(shorebirdEnv.getShorebirdYaml()!.appId)} will be used.''',
);
throw ValidationFailedException();
}
return;
}
final flavorValidator = FlavorValidator(flavorArg: flavorArg);
final issues = await flavorValidator.validate();
if (validationIssuesContainsError(issues)) {
@@ -399,6 +399,23 @@ void main() {
).called(1);
});
});
group('when flavor validation fails', () {
setUp(() {
when(
() => shorebirdValidator.validateFlavors(
flavorArg: any(named: 'flavorArg'),
),
).thenThrow(ValidationFailedException());
});
test('exits with code 78 (config)', () async {
await expectLater(
runWithOverrides(() => command.createPatch(patcher)),
exitsWithCode(ExitCode.config),
);
});
});
});
group('correctly validates key pair', () {
@@ -443,6 +443,23 @@ void main() {
),
]);
});
group('when flavor validation fails', () {
setUp(() {
when(
() => shorebirdValidator.validateFlavors(
flavorArg: any(named: 'flavorArg'),
),
).thenThrow(ValidationFailedException());
});
test('exits with code 78 (config)', () async {
await expectLater(
() => runWithOverrides(command.run),
exitsWithCode(ExitCode.config),
);
});
});
});
group('when there is an existing release with the same version', () {
@@ -218,34 +218,116 @@ To fix, update your pubspec.yaml to include the following:
});
group('validateFlavors', () {
const shorebirdYaml = ShorebirdYaml(
appId: 'test',
flavors: {'flavorA': 'flavorA'},
);
late ShorebirdYaml shorebirdYaml;
setUp(() {
when(() => shorebirdEnv.getShorebirdYaml()).thenReturn(shorebirdYaml);
when(
() => shorebirdEnv.getShorebirdYaml(),
).thenAnswer((_) => shorebirdYaml);
when(() => platform.isWindows).thenReturn(false);
when(() => platform.isLinux).thenReturn(false);
});
group('when validation fails', () {
test('throws ValidationException', () async {
await expectLater(
runWithOverrides(
() => shorebirdValidator.validateFlavors(flavorArg: null),
),
throwsA(isA<ValidationFailedException>()),
group('when shorebird.yaml has flavors', () {
setUp(() {
shorebirdYaml = const ShorebirdYaml(
appId: 'test',
flavors: {'flavorA': 'flavorA'},
);
});
setUp(() {
when(() => shorebirdEnv.getShorebirdYaml()).thenReturn(shorebirdYaml);
});
group('when platform does not support flavors', () {
setUp(() {
when(() => platform.isWindows).thenReturn(true);
});
group('when a flavor arg is provided', () {
test('validation fails', () async {
await expectLater(
runWithOverrides(
() =>
shorebirdValidator.validateFlavors(flavorArg: 'flavorA'),
),
throwsA(isA<ValidationFailedException>()),
);
verify(
() => logger.err('Flavors are not supported on this platform.'),
).called(1);
verify(
() => logger.info(
'''Please re-run this command without the --flavor argument. The app id ${lightCyan.wrap('test')} will be used.''',
),
).called(1);
});
});
group('when no flavor arg is provided', () {
test('passes validation', () async {
await expectLater(
runWithOverrides(
() => shorebirdValidator.validateFlavors(flavorArg: null),
),
completes,
);
});
});
});
group('when no flavor is specified', () {
test('fails validation', () async {
await expectLater(
runWithOverrides(
() => shorebirdValidator.validateFlavors(flavorArg: null),
),
throwsA(isA<ValidationFailedException>()),
);
});
});
group('when a flavor arg is provided that exists in the project', () {
test('passes validation', () async {
await expectLater(
runWithOverrides(
() => shorebirdValidator.validateFlavors(flavorArg: 'flavorA'),
),
completes,
);
});
});
});
group('when validation succeeds', () {
test('completes normally', () async {
await expectLater(
runWithOverrides(
() => shorebirdValidator.validateFlavors(flavorArg: 'flavorA'),
),
completes,
);
group('when shorebird.yaml does not have flavors', () {
setUp(() {
shorebirdYaml = const ShorebirdYaml(appId: 'test');
});
group('when no flavor arg is provided', () {
test('passes validation', () async {
await expectLater(
runWithOverrides(
() => shorebirdValidator.validateFlavors(flavorArg: null),
),
completes,
);
});
group('when a flavor arg is provided', () {
test('fails validation', () async {
await expectLater(
runWithOverrides(
() =>
shorebirdValidator.validateFlavors(flavorArg: 'flavorA'),
),
throwsA(isA<ValidationFailedException>()),
);
});
});
});
});
});