fix(shorebird_cli): ensure all release artifacts are built using the same flutter revision (#1911)

This commit is contained in:
Felix Angelov
2024-04-16 14:03:04 -05:00
committed by GitHub
parent 2972919a5e
commit 3dc991cc91
5 changed files with 158 additions and 0 deletions
@@ -245,6 +245,17 @@ Use `shorebird flutter versions list` to list available versions.
release: existingRelease,
platform: releasePlatform,
);
// All artifacts associated with a given release must be built
// with the same Flutter revision.
if (existingRelease.flutterRevision != flutterRevisionForRelease) {
ReleaseCommand.printConflictingFlutterRevisionError(
existingFlutterRevision: existingRelease.flutterRevision,
currentFlutterRevision: flutterRevisionForRelease,
releaseVersion: releaseVersion,
);
return ExitCode.software.code;
}
}
final archNames = architectures.map((a) => a.name);
@@ -22,6 +22,27 @@ class ReleaseCommand extends ShorebirdCommand {
@override
String get name => 'release';
static void printConflictingFlutterRevisionError({
required String existingFlutterRevision,
required String currentFlutterRevision,
required String releaseVersion,
}) {
logger.err(
'''
${styleBold.wrap(lightRed.wrap('A release with version $releaseVersion already exists but was built using a different Flutter revision.'))}
Existing release built with: ${lightCyan.wrap(existingFlutterRevision)}
Current release built with: ${lightCyan.wrap(currentFlutterRevision)}
${styleBold.wrap(lightRed.wrap('All platforms for a given release must be built using the same Flutter revision.'))}
To resolve this issue, you can:
* Re-run the release command with "${lightCyan.wrap('--flutter-version=$existingFlutterRevision')}".
* Delete the existing release and re-run the release command with the desired Flutter version.
* Bump the release version and re-run the release command with the desired Flutter version.''',
);
}
static void printPatchInstructions({
required String name,
required String releaseVersion,
@@ -255,6 +255,17 @@ Use `shorebird flutter versions list` to list available versions.
release: existingRelease,
platform: releasePlatform,
);
// All artifacts associated with a given release must be built
// with the same Flutter revision.
if (existingRelease.flutterRevision != flutterRevisionForRelease) {
ReleaseCommand.printConflictingFlutterRevisionError(
existingFlutterRevision: existingRelease.flutterRevision,
currentFlutterRevision: flutterRevisionForRelease,
releaseVersion: releaseVersion,
);
return ExitCode.software.code;
}
}
final summary = [
@@ -836,6 +836,58 @@ Note: ${lightCyan.wrap('shorebird patch android --flavor=$flavor --target=$targe
);
});
test(
'does not upload artifacts if an existing release is present '
'with a different flutter revision', () async {
when(
() => codePushClientWrapper.maybeGetRelease(
appId: any(named: 'appId'),
releaseVersion: any(named: 'releaseVersion'),
),
).thenAnswer(
(_) async => Release(
id: release.id,
appId: release.appId,
version: release.version,
flutterRevision: 'different-revision',
displayName: release.displayName,
createdAt: release.createdAt.add(const Duration(minutes: 1)),
updatedAt: release.createdAt.add(const Duration(minutes: 1)),
platformStatuses: release.platformStatuses,
),
);
final exitCode = await runWithOverrides(command.run);
expect(exitCode, ExitCode.software.code);
verify(
() => logger.err(
any(
that: contains(
'''All platforms for a given release must be built using the same Flutter revision.''',
),
),
),
).called(1);
verifyNever(
() => codePushClientWrapper.createRelease(
appId: any(named: 'appId'),
version: any(named: 'version'),
flutterRevision: any(named: 'flutterRevision'),
platform: any(named: 'platform'),
),
);
verifyNever(
() => codePushClientWrapper.createAndroidReleaseArtifacts(
appId: any(named: 'appId'),
releaseId: any(named: 'releaseId'),
projectRoot: any(named: 'projectRoot'),
aabPath: any(named: 'aabPath'),
platform: any(named: 'platform'),
architectures: any(named: 'architectures'),
flavor: any(named: 'flavor'),
),
);
});
test('does not prompt if unable to accept user input', () async {
when(() => shorebirdEnv.canAcceptUserInput).thenReturn(false);
@@ -1083,6 +1083,69 @@ Note: ${lightCyan.wrap('shorebird patch ios --flavor=$flavor --target=$target')}
).called(1);
});
test(
'does not upload artifacts if an existing release is present '
'with a different flutter revision', () async {
when(
() => codePushClientWrapper.maybeGetRelease(
appId: any(named: 'appId'),
releaseVersion: any(named: 'releaseVersion'),
),
).thenAnswer(
(_) async => Release(
id: release.id,
appId: release.appId,
version: release.version,
flutterRevision: 'different-revision',
displayName: release.displayName,
createdAt: release.createdAt.add(const Duration(minutes: 1)),
updatedAt: release.createdAt.add(const Duration(minutes: 1)),
platformStatuses: release.platformStatuses,
),
);
setUpProjectRoot();
final exitCode = await runWithOverrides(command.run);
expect(exitCode, ExitCode.software.code);
verify(
() => logger.err(
any(
that: contains(
'''All platforms for a given release must be built using the same Flutter revision.''',
),
),
),
).called(1);
verifyNever(
() => codePushClientWrapper.createRelease(
appId: any(named: 'appId'),
version: any(named: 'version'),
flutterRevision: any(named: 'flutterRevision'),
platform: any(named: 'platform'),
),
);
verifyNever(
() => codePushClientWrapper.createIosReleaseArtifacts(
appId: any(named: 'appId'),
releaseId: any(named: 'releaseId'),
xcarchivePath:
any(named: 'xcarchivePath', that: endsWith('.xcarchive')),
runnerPath: any(named: 'runnerPath', that: endsWith('Runner.app')),
isCodesigned: any(named: 'isCodesigned'),
),
);
verifyNever(
() => codePushClientWrapper.updateReleaseStatus(
appId: any(named: 'appId'),
releaseId: any(named: 'releaseId'),
platform: any(named: 'platform'),
status: any(named: 'status'),
metadata: any(named: 'metadata'),
),
);
});
test('does not provide export options when codesign is false', () async {
when(() => argResults['codesign']).thenReturn(false);
setUpProjectRoot();