refactor(shorebird_cli): consolidate command precondition checks in ShorebirdValidationMixin (#575)

This commit is contained in:
Bryan Oltman
2023-06-01 12:25:25 -04:00
committed by GitHub
parent 5b28adf8e2
commit 3c07866cdc
24 changed files with 229 additions and 234 deletions
@@ -1,15 +0,0 @@
import 'package:mason_logger/mason_logger.dart';
import 'package:shorebird_cli/src/command.dart';
mixin AuthLoggerMixin on ShorebirdCommand {
void printNeedsAuthInstructions() {
logger
..err('You must be logged in to run this command.')
..info(
'''If you already have an account, run ${lightCyan.wrap('shorebird login')} to sign in.''',
)
..info(
'''If you don't have a Shorebird account, run ${lightCyan.wrap('shorebird account create')} to create one.''',
);
}
}
@@ -1,16 +1,16 @@
import 'dart:async';
import 'package:mason_logger/mason_logger.dart';
import 'package:shorebird_cli/src/auth_logger_mixin.dart';
import 'package:shorebird_cli/src/command.dart';
import 'package:shorebird_cli/src/shorebird_config_mixin.dart';
import 'package:shorebird_cli/src/shorebird_validation_mixin.dart';
import 'package:shorebird_code_push_client/shorebird_code_push_client.dart';
/// {@template subscribe_account_command}
/// `shorebird account subscribe`
/// {@endtemplate}
class SubscribeAccountCommand extends ShorebirdCommand
with AuthLoggerMixin, ShorebirdConfigMixin {
with ShorebirdConfigMixin, ShorebirdValidationMixin {
/// {@macro subscribe_account_command}
SubscribeAccountCommand({
required super.logger,
@@ -35,9 +35,12 @@ Visit ${styleUnderlined.wrap(lightCyan.wrap('https://shorebird.dev'))} for more
@override
Future<int> run() async {
if (!auth.isAuthenticated) {
printNeedsAuthInstructions();
return ExitCode.software.code;
try {
await validatePreconditions(
checkUserIsAuthenticated: true,
);
} on PreconditionFailedException catch (e) {
return e.exitCode.code;
}
final client = buildCodePushClient(
@@ -1,10 +1,10 @@
import 'dart:async';
import 'package:mason_logger/mason_logger.dart';
import 'package:shorebird_cli/src/auth_logger_mixin.dart';
import 'package:shorebird_cli/src/command.dart';
import 'package:shorebird_cli/src/shorebird_config_mixin.dart';
import 'package:shorebird_cli/src/shorebird_create_app_mixin.dart';
import 'package:shorebird_cli/src/shorebird_validation_mixin.dart';
import 'package:shorebird_code_push_client/shorebird_code_push_client.dart';
/// {@template create_app_command}
@@ -13,7 +13,10 @@ import 'package:shorebird_code_push_client/shorebird_code_push_client.dart';
/// Create a new app on Shorebird.
/// {@endtemplate}
class CreateAppCommand extends ShorebirdCommand
with AuthLoggerMixin, ShorebirdConfigMixin, ShorebirdCreateAppMixin {
with
ShorebirdConfigMixin,
ShorebirdValidationMixin,
ShorebirdCreateAppMixin {
/// {@macro create_app_command}
CreateAppCommand({
required super.logger,
@@ -36,9 +39,12 @@ Defaults to the name in "pubspec.yaml".''',
@override
Future<int>? run() async {
if (!auth.isAuthenticated) {
printNeedsAuthInstructions();
return ExitCode.noUser.code;
try {
await validatePreconditions(
checkUserIsAuthenticated: true,
);
} on PreconditionFailedException catch (e) {
return e.exitCode.code;
}
final appName = results['app-name'] as String?;
@@ -1,9 +1,9 @@
import 'dart:async';
import 'package:mason_logger/mason_logger.dart';
import 'package:shorebird_cli/src/auth_logger_mixin.dart';
import 'package:shorebird_cli/src/command.dart';
import 'package:shorebird_cli/src/shorebird_config_mixin.dart';
import 'package:shorebird_cli/src/shorebird_validation_mixin.dart';
/// {@template delete_app_command}
///
@@ -11,7 +11,7 @@ import 'package:shorebird_cli/src/shorebird_config_mixin.dart';
/// Delete an existing app on Shorebird.
/// {@endtemplate}
class DeleteAppCommand extends ShorebirdCommand
with AuthLoggerMixin, ShorebirdConfigMixin {
with ShorebirdConfigMixin, ShorebirdValidationMixin {
/// {@macro delete_app_command}
DeleteAppCommand({
required super.logger,
@@ -34,9 +34,12 @@ Defaults to the app_id in "shorebird.yaml".''',
@override
Future<int>? run() async {
if (!auth.isAuthenticated) {
printNeedsAuthInstructions();
return ExitCode.noUser.code;
try {
await validatePreconditions(
checkUserIsAuthenticated: true,
);
} on PreconditionFailedException catch (e) {
return e.exitCode.code;
}
final appIdArg = results['app-id'] as String?;
@@ -2,9 +2,9 @@ import 'dart:async';
import 'package:barbecue/barbecue.dart';
import 'package:mason_logger/mason_logger.dart';
import 'package:shorebird_cli/src/auth_logger_mixin.dart';
import 'package:shorebird_cli/src/command.dart';
import 'package:shorebird_cli/src/shorebird_config_mixin.dart';
import 'package:shorebird_cli/src/shorebird_validation_mixin.dart';
import 'package:shorebird_code_push_client/shorebird_code_push_client.dart';
/// {@template list_apps_command}
@@ -13,7 +13,7 @@ import 'package:shorebird_code_push_client/shorebird_code_push_client.dart';
/// List all apps using Shorebird.
/// {@endtemplate}
class ListAppsCommand extends ShorebirdCommand
with AuthLoggerMixin, ShorebirdConfigMixin {
with ShorebirdConfigMixin, ShorebirdValidationMixin {
/// {@macro list_apps_command}
ListAppsCommand({
required super.logger,
@@ -32,9 +32,12 @@ class ListAppsCommand extends ShorebirdCommand
@override
Future<int>? run() async {
if (!auth.isAuthenticated) {
printNeedsAuthInstructions();
return ExitCode.noUser.code;
try {
await validatePreconditions(
checkUserIsAuthenticated: true,
);
} on PreconditionFailedException catch (e) {
return e.exitCode.code;
}
final client = buildCodePushClient(
@@ -3,7 +3,6 @@ import 'dart:io';
import 'package:mason_logger/mason_logger.dart';
import 'package:path/path.dart' as p;
import 'package:shorebird_cli/src/auth_logger_mixin.dart';
import 'package:shorebird_cli/src/command.dart';
import 'package:shorebird_cli/src/shorebird_build_mixin.dart';
import 'package:shorebird_cli/src/shorebird_config_mixin.dart';
@@ -15,14 +14,11 @@ import 'package:shorebird_cli/src/shorebird_validation_mixin.dart';
/// Build an Android aar file from your app.
/// {@endtemplate}
class BuildAarCommand extends ShorebirdCommand
with
AuthLoggerMixin,
ShorebirdValidationMixin,
ShorebirdConfigMixin,
ShorebirdBuildMixin {
with ShorebirdConfigMixin, ShorebirdValidationMixin, ShorebirdBuildMixin {
BuildAarCommand({
required super.logger,
super.auth,
super.validators,
}) {
// We would have a "target" option here, similar to what [BuildApkCommand]
// and [BuildAabCommand] have, but target cannot currently be configured in
@@ -49,17 +45,16 @@ class BuildAarCommand extends ShorebirdCommand
@override
Future<int> run() async {
if (!auth.isAuthenticated) {
printNeedsAuthInstructions();
return ExitCode.noUser.code;
}
final pubspec = getPubspecYaml();
if (pubspec == null) {
logger.err('No pubspec.yaml file found.');
return ExitCode.config.code;
try {
await validatePreconditions(
checkUserIsAuthenticated: true,
checkShorebirdInitialized: true,
);
} on PreconditionFailedException catch (e) {
return e.exitCode.code;
}
final pubspec = getPubspecYaml()!;
final module = pubspec.flutter?['module'] as Map?;
final androidPackageName = module?['androidPackage'] as String?;
if (androidPackageName == null) {
@@ -2,7 +2,6 @@ import 'dart:io';
import 'package:mason_logger/mason_logger.dart';
import 'package:path/path.dart' as p;
import 'package:shorebird_cli/src/auth_logger_mixin.dart';
import 'package:shorebird_cli/src/command.dart';
import 'package:shorebird_cli/src/shorebird_build_mixin.dart';
import 'package:shorebird_cli/src/shorebird_config_mixin.dart';
@@ -14,11 +13,7 @@ import 'package:shorebird_cli/src/shorebird_validation_mixin.dart';
/// Build an Android APK file from your app.
/// {@endtemplate}
class BuildApkCommand extends ShorebirdCommand
with
AuthLoggerMixin,
ShorebirdValidationMixin,
ShorebirdConfigMixin,
ShorebirdBuildMixin {
with ShorebirdConfigMixin, ShorebirdValidationMixin, ShorebirdBuildMixin {
/// {@macro build_apk_command}
BuildApkCommand({
required super.logger,
@@ -45,15 +40,13 @@ class BuildApkCommand extends ShorebirdCommand
@override
Future<int> run() async {
if (!auth.isAuthenticated) {
printNeedsAuthInstructions();
return ExitCode.noUser.code;
}
final validationIssues = await runValidators();
if (validationIssuesContainsError(validationIssues)) {
logValidationFailure(issues: validationIssues);
return ExitCode.config.code;
try {
await validatePreconditions(
checkUserIsAuthenticated: true,
checkValidators: true,
);
} on PreconditionFailedException catch (e) {
return e.exitCode.code;
}
final flavor = results['flavor'] as String?;
@@ -2,7 +2,6 @@ import 'dart:io';
import 'package:mason_logger/mason_logger.dart';
import 'package:path/path.dart' as p;
import 'package:shorebird_cli/src/auth_logger_mixin.dart';
import 'package:shorebird_cli/src/command.dart';
import 'package:shorebird_cli/src/shorebird_build_mixin.dart';
import 'package:shorebird_cli/src/shorebird_config_mixin.dart';
@@ -14,11 +13,7 @@ import 'package:shorebird_cli/src/shorebird_validation_mixin.dart';
/// Build an Android App Bundle file from your app.
/// {@endtemplate}
class BuildAppBundleCommand extends ShorebirdCommand
with
AuthLoggerMixin,
ShorebirdValidationMixin,
ShorebirdConfigMixin,
ShorebirdBuildMixin {
with ShorebirdConfigMixin, ShorebirdValidationMixin, ShorebirdBuildMixin {
/// {@macro build_app_bundle_command}
BuildAppBundleCommand({
required super.logger,
@@ -45,15 +40,13 @@ class BuildAppBundleCommand extends ShorebirdCommand
@override
Future<int> run() async {
if (!auth.isAuthenticated) {
printNeedsAuthInstructions();
return ExitCode.noUser.code;
}
final validationIssues = await runValidators();
if (validationIssuesContainsError(validationIssues)) {
logValidationFailure(issues: validationIssues);
return ExitCode.config.code;
try {
await validatePreconditions(
checkUserIsAuthenticated: true,
checkValidators: true,
);
} on PreconditionFailedException catch (e) {
return e.exitCode.code;
}
final flavor = results['flavor'] as String?;
@@ -2,7 +2,6 @@ import 'dart:io';
import 'package:mason_logger/mason_logger.dart';
import 'package:path/path.dart' as p;
import 'package:shorebird_cli/src/auth_logger_mixin.dart';
import 'package:shorebird_cli/src/command.dart';
import 'package:shorebird_cli/src/shorebird_build_mixin.dart';
import 'package:shorebird_cli/src/shorebird_config_mixin.dart';
@@ -14,11 +13,7 @@ import 'package:shorebird_cli/src/shorebird_validation_mixin.dart';
/// App Store submission.
/// {@endtemplate}
class BuildIpaCommand extends ShorebirdCommand
with
AuthLoggerMixin,
ShorebirdValidationMixin,
ShorebirdConfigMixin,
ShorebirdBuildMixin {
with ShorebirdConfigMixin, ShorebirdValidationMixin, ShorebirdBuildMixin {
/// {@macro build_ipa_command}
BuildIpaCommand({required super.logger, super.auth, super.validators}) {
argParser
@@ -47,15 +42,13 @@ class BuildIpaCommand extends ShorebirdCommand
@override
Future<int> run() async {
if (!auth.isAuthenticated) {
printNeedsAuthInstructions();
return ExitCode.noUser.code;
}
final validationIssues = await runValidators();
if (validationIssuesContainsError(validationIssues)) {
logValidationFailure(issues: validationIssues);
return ExitCode.config.code;
try {
await validatePreconditions(
checkUserIsAuthenticated: true,
checkValidators: true,
);
} on PreconditionFailedException catch (e) {
return e.exitCode.code;
}
final flavor = results['flavor'] as String?;
@@ -1,16 +1,16 @@
import 'dart:async';
import 'package:mason_logger/mason_logger.dart';
import 'package:shorebird_cli/src/auth_logger_mixin.dart';
import 'package:shorebird_cli/src/command.dart';
import 'package:shorebird_cli/src/shorebird_config_mixin.dart';
import 'package:shorebird_cli/src/shorebird_validation_mixin.dart';
/// {@template add_collaborators_command}
/// `shorebird collaborators add`
/// Add a new collaborator to a Shorebird app.
/// {@endtemplate}
class AddCollaboratorsCommand extends ShorebirdCommand
with AuthLoggerMixin, ShorebirdConfigMixin {
with ShorebirdConfigMixin, ShorebirdValidationMixin {
/// {@macro add_collaborators_command}
AddCollaboratorsCommand({
required super.logger,
@@ -39,9 +39,12 @@ class AddCollaboratorsCommand extends ShorebirdCommand
@override
Future<int>? run() async {
if (!auth.isAuthenticated) {
printNeedsAuthInstructions();
return ExitCode.noUser.code;
try {
await validatePreconditions(
checkUserIsAuthenticated: true,
);
} on PreconditionFailedException catch (e) {
return e.exitCode.code;
}
final client = buildCodePushClient(
@@ -2,9 +2,9 @@ import 'dart:async';
import 'package:collection/collection.dart';
import 'package:mason_logger/mason_logger.dart';
import 'package:shorebird_cli/src/auth_logger_mixin.dart';
import 'package:shorebird_cli/src/command.dart';
import 'package:shorebird_cli/src/shorebird_config_mixin.dart';
import 'package:shorebird_cli/src/shorebird_validation_mixin.dart';
import 'package:shorebird_code_push_client/shorebird_code_push_client.dart';
/// {@template delete_collaborators_command}
@@ -12,7 +12,7 @@ import 'package:shorebird_code_push_client/shorebird_code_push_client.dart';
/// Delete an existing collaborator from a Shorebird app.
/// {@endtemplate}
class DeleteCollaboratorsCommand extends ShorebirdCommand
with AuthLoggerMixin, ShorebirdConfigMixin {
with ShorebirdConfigMixin, ShorebirdValidationMixin {
/// {@macro delete_collaborators_command}
DeleteCollaboratorsCommand({
required super.logger,
@@ -42,9 +42,12 @@ class DeleteCollaboratorsCommand extends ShorebirdCommand
@override
Future<int>? run() async {
if (!auth.isAuthenticated) {
printNeedsAuthInstructions();
return ExitCode.noUser.code;
try {
await validatePreconditions(
checkUserIsAuthenticated: true,
);
} on PreconditionFailedException catch (e) {
return e.exitCode.code;
}
final client = buildCodePushClient(
@@ -2,9 +2,9 @@ import 'dart:async';
import 'package:barbecue/barbecue.dart';
import 'package:mason_logger/mason_logger.dart';
import 'package:shorebird_cli/src/auth_logger_mixin.dart';
import 'package:shorebird_cli/src/command.dart';
import 'package:shorebird_cli/src/shorebird_config_mixin.dart';
import 'package:shorebird_cli/src/shorebird_validation_mixin.dart';
import 'package:shorebird_code_push_client/shorebird_code_push_client.dart';
/// {@template list_collaborators_command}
@@ -12,7 +12,7 @@ import 'package:shorebird_code_push_client/shorebird_code_push_client.dart';
/// List all collaborators for a Shorebird app.
/// {@endtemplate}
class ListCollaboratorsCommand extends ShorebirdCommand
with AuthLoggerMixin, ShorebirdConfigMixin {
with ShorebirdConfigMixin, ShorebirdValidationMixin {
/// {@macro list_collaborators_command}
ListCollaboratorsCommand({
required super.logger,
@@ -38,9 +38,12 @@ class ListCollaboratorsCommand extends ShorebirdCommand
@override
Future<int>? run() async {
if (!auth.isAuthenticated) {
printNeedsAuthInstructions();
return ExitCode.noUser.code;
try {
await validatePreconditions(
checkUserIsAuthenticated: true,
);
} on PreconditionFailedException catch (e) {
return e.exitCode.code;
}
final client = buildCodePushClient(
@@ -1,12 +1,12 @@
import 'dart:io';
import 'package:mason_logger/mason_logger.dart';
import 'package:shorebird_cli/src/auth_logger_mixin.dart';
import 'package:shorebird_cli/src/command.dart';
import 'package:shorebird_cli/src/shorebird_config_mixin.dart';
import 'package:shorebird_cli/src/shorebird_create_app_mixin.dart';
import 'package:shorebird_cli/src/shorebird_flavor_mixin.dart';
import 'package:shorebird_cli/src/shorebird_java_mixin.dart';
import 'package:shorebird_cli/src/shorebird_validation_mixin.dart';
/// {@template init_command}
///
@@ -15,8 +15,8 @@ import 'package:shorebird_cli/src/shorebird_java_mixin.dart';
/// {@endtemplate}
class InitCommand extends ShorebirdCommand
with
AuthLoggerMixin,
ShorebirdConfigMixin,
ShorebirdValidationMixin,
ShorebirdCreateAppMixin,
ShorebirdJavaMixin,
ShorebirdFlavorMixin {
@@ -38,9 +38,12 @@ class InitCommand extends ShorebirdCommand
@override
Future<int> run() async {
if (!auth.isAuthenticated) {
printNeedsAuthInstructions();
return ExitCode.noUser.code;
try {
await validatePreconditions(
checkUserIsAuthenticated: true,
);
} on PreconditionFailedException catch (e) {
return e.exitCode.code;
}
try {
@@ -6,7 +6,6 @@ import 'package:http/http.dart' as http;
import 'package:mason_logger/mason_logger.dart';
import 'package:path/path.dart' as p;
import 'package:shorebird_cli/src/aab/aab.dart';
import 'package:shorebird_cli/src/auth_logger_mixin.dart';
import 'package:shorebird_cli/src/command.dart';
import 'package:shorebird_cli/src/config/shorebird_yaml.dart';
import 'package:shorebird_cli/src/formatters/formatters.dart';
@@ -44,9 +43,8 @@ class PatchArtifactBundle {
/// {@endtemplate}
class PatchAndroidCommand extends ShorebirdCommand
with
AuthLoggerMixin,
ShorebirdValidationMixin,
ShorebirdConfigMixin,
ShorebirdValidationMixin,
ShorebirdBuildMixin,
ShorebirdCreateAppMixin,
ShorebirdJavaMixin,
@@ -114,16 +112,14 @@ class PatchAndroidCommand extends ShorebirdCommand
@override
Future<int> run() async {
if (!isShorebirdInitialized) {
logger.err(
'Shorebird is not initialized. Did you run "shorebird init"?',
try {
await validatePreconditions(
checkUserIsAuthenticated: true,
checkShorebirdInitialized: true,
checkValidators: true,
);
return ExitCode.config.code;
}
if (!auth.isAuthenticated) {
printNeedsAuthInstructions();
return ExitCode.noUser.code;
} on PreconditionFailedException catch (e) {
return e.exitCode.code;
}
final force = results['force'] == true;
@@ -134,12 +130,6 @@ class PatchAndroidCommand extends ShorebirdCommand
return ExitCode.usage.code;
}
final validationIssues = await runValidators();
if (validationIssuesContainsError(validationIssues)) {
logValidationFailure(issues: validationIssues);
return ExitCode.config.code;
}
await cache.updateAll();
final flavor = results['flavor'] as String?;
@@ -6,7 +6,6 @@ import 'package:collection/collection.dart';
import 'package:crypto/crypto.dart';
import 'package:mason_logger/mason_logger.dart';
import 'package:path/path.dart' as p;
import 'package:shorebird_cli/src/auth_logger_mixin.dart';
import 'package:shorebird_cli/src/command.dart';
import 'package:shorebird_cli/src/config/config.dart';
import 'package:shorebird_cli/src/shorebird_build_mixin.dart';
@@ -23,9 +22,8 @@ import 'package:shorebird_code_push_client/shorebird_code_push_client.dart';
/// {@endtemplate}
class ReleaseAndroidArchiveCommand extends ShorebirdCommand
with
AuthLoggerMixin,
ShorebirdValidationMixin,
ShorebirdConfigMixin,
ShorebirdValidationMixin,
ShorebirdBuildMixin,
ShorebirdCreateAppMixin,
ShorebirdJavaMixin,
@@ -75,25 +73,17 @@ make smaller updates to your app.
@override
Future<int> run() async {
if (!isShorebirdInitialized) {
logger.err(
'Shorebird is not initialized. Did you run "shorebird init"?',
try {
await validatePreconditions(
checkUserIsAuthenticated: true,
checkShorebirdInitialized: true,
checkValidators: true,
);
return ExitCode.config.code;
} on PreconditionFailedException catch (e) {
return e.exitCode.code;
}
if (!auth.isAuthenticated) {
printNeedsAuthInstructions();
return ExitCode.noUser.code;
}
final validationIssues = await runValidators();
if (validationIssuesContainsError(validationIssues)) {
logValidationFailure(issues: validationIssues);
return ExitCode.config.code;
}
// We know the pubspec exists due to the call to isShorebirdInitialized
// We know the pubspec exists due to the checkShorebirdInitialized check
// above.
final pubspec = getPubspecYaml()!;
final module = pubspec.flutter?['module'] as Map?;
@@ -4,7 +4,6 @@ import 'package:collection/collection.dart';
import 'package:crypto/crypto.dart';
import 'package:mason_logger/mason_logger.dart';
import 'package:path/path.dart' as p;
import 'package:shorebird_cli/src/auth_logger_mixin.dart';
import 'package:shorebird_cli/src/command.dart';
import 'package:shorebird_cli/src/config/shorebird_yaml.dart';
import 'package:shorebird_cli/src/shorebird_build_mixin.dart';
@@ -21,9 +20,8 @@ import 'package:shorebird_code_push_client/shorebird_code_push_client.dart';
/// {@endtemplate}
class ReleaseAndroidCommand extends ShorebirdCommand
with
AuthLoggerMixin,
ShorebirdValidationMixin,
ShorebirdConfigMixin,
ShorebirdValidationMixin,
ShorebirdBuildMixin,
ShorebirdCreateAppMixin,
ShorebirdJavaMixin,
@@ -69,22 +67,14 @@ make smaller updates to your app.
@override
Future<int> run() async {
if (!isShorebirdInitialized) {
logger.err(
'Shorebird is not initialized. Did you run "shorebird init"?',
try {
await validatePreconditions(
checkUserIsAuthenticated: true,
checkShorebirdInitialized: true,
checkValidators: true,
);
return ExitCode.config.code;
}
if (!auth.isAuthenticated) {
printNeedsAuthInstructions();
return ExitCode.noUser.code;
}
final validationIssues = await runValidators();
if (validationIssuesContainsError(validationIssues)) {
logValidationFailure(issues: validationIssues);
return ExitCode.config.code;
} on PreconditionFailedException catch (e) {
return e.exitCode.code;
}
final flavor = results['flavor'] as String?;
@@ -2,7 +2,6 @@ import 'dart:io';
import 'package:collection/collection.dart';
import 'package:mason_logger/mason_logger.dart';
import 'package:shorebird_cli/src/auth_logger_mixin.dart';
import 'package:shorebird_cli/src/command.dart';
import 'package:shorebird_cli/src/config/config.dart';
import 'package:shorebird_cli/src/shorebird_build_mixin.dart';
@@ -15,11 +14,7 @@ import 'package:shorebird_code_push_client/shorebird_code_push_client.dart';
/// Create new app releases for iOS.
/// {@endtemplate}
class ReleaseIosCommand extends ShorebirdCommand
with
AuthLoggerMixin,
ShorebirdValidationMixin,
ShorebirdConfigMixin,
ShorebirdBuildMixin {
with ShorebirdConfigMixin, ShorebirdValidationMixin, ShorebirdBuildMixin {
/// {@macro release_ios_command}
ReleaseIosCommand({
required super.logger,
@@ -58,22 +53,14 @@ make smaller updates to your app.
@override
Future<int> run() async {
if (!isShorebirdInitialized) {
logger.err(
'Shorebird is not initialized. Did you run "shorebird init"?',
try {
await validatePreconditions(
checkUserIsAuthenticated: true,
checkShorebirdInitialized: true,
checkValidators: true,
);
return ExitCode.config.code;
}
if (!auth.isAuthenticated) {
printNeedsAuthInstructions();
return ExitCode.noUser.code;
}
final validationIssues = await runValidators();
if (validationIssuesContainsError(validationIssues)) {
logValidationFailure(issues: validationIssues);
return ExitCode.config.code;
} on PreconditionFailedException catch (e) {
return e.exitCode.code;
}
final flavor = results['flavor'] as String?;
@@ -2,10 +2,10 @@ import 'dart:async';
import 'package:collection/collection.dart';
import 'package:mason_logger/mason_logger.dart';
import 'package:shorebird_cli/src/auth_logger_mixin.dart';
import 'package:shorebird_cli/src/command.dart';
import 'package:shorebird_cli/src/config/shorebird_yaml.dart';
import 'package:shorebird_cli/src/shorebird_config_mixin.dart';
import 'package:shorebird_cli/src/shorebird_validation_mixin.dart';
import 'package:shorebird_code_push_client/shorebird_code_push_client.dart';
/// {@template delete_releases_command}
@@ -14,7 +14,7 @@ import 'package:shorebird_code_push_client/shorebird_code_push_client.dart';
/// Delete the specified release.
/// {@endtemplate}
class DeleteReleasesCommand extends ShorebirdCommand
with AuthLoggerMixin, ShorebirdConfigMixin {
with ShorebirdConfigMixin, ShorebirdValidationMixin {
/// {@macro delete_releases_command}
DeleteReleasesCommand({
required super.logger,
@@ -40,16 +40,13 @@ class DeleteReleasesCommand extends ShorebirdCommand
@override
Future<int> run() async {
if (!auth.isAuthenticated) {
printNeedsAuthInstructions();
return ExitCode.noUser.code;
}
if (!hasShorebirdYaml) {
logger.err(
'''Shorebird is not initialized. Did you run ${lightCyan.wrap('shorebird init')}?''',
try {
await validatePreconditions(
checkUserIsAuthenticated: true,
checkShorebirdInitialized: true,
);
return ExitCode.config.code;
} on PreconditionFailedException catch (e) {
return e.exitCode.code;
}
final flavor = results['flavor'] as String?;
@@ -1,9 +1,9 @@
import 'package:barbecue/barbecue.dart';
import 'package:mason_logger/mason_logger.dart';
import 'package:shorebird_cli/src/auth_logger_mixin.dart';
import 'package:shorebird_cli/src/command.dart';
import 'package:shorebird_cli/src/config/shorebird_yaml.dart';
import 'package:shorebird_cli/src/shorebird_config_mixin.dart';
import 'package:shorebird_cli/src/shorebird_validation_mixin.dart';
import 'package:shorebird_code_push_client/shorebird_code_push_client.dart';
/// {@template list_releases_command}
@@ -12,7 +12,7 @@ import 'package:shorebird_code_push_client/shorebird_code_push_client.dart';
/// List all releases for this app.
/// {@endtemplate}
class ListReleasesCommand extends ShorebirdCommand
with AuthLoggerMixin, ShorebirdConfigMixin {
with ShorebirdConfigMixin, ShorebirdValidationMixin {
/// {@macro list_releases_command}
ListReleasesCommand({
required super.logger,
@@ -33,16 +33,13 @@ class ListReleasesCommand extends ShorebirdCommand
@override
Future<int> run() async {
if (!auth.isAuthenticated) {
printNeedsAuthInstructions();
return ExitCode.noUser.code;
}
if (!hasShorebirdYaml) {
logger.err(
'''Shorebird is not initialized. Did you run ${lightCyan.wrap('shorebird init')}?''',
try {
await validatePreconditions(
checkUserIsAuthenticated: true,
checkShorebirdInitialized: true,
);
return ExitCode.config.code;
} on PreconditionFailedException catch (e) {
return e.exitCode.code;
}
final flavor = results['flavor'] as String?;
@@ -1,7 +1,5 @@
import 'dart:convert';
import 'package:mason_logger/mason_logger.dart';
import 'package:shorebird_cli/src/auth_logger_mixin.dart';
import 'package:shorebird_cli/src/command.dart';
import 'package:shorebird_cli/src/shorebird_config_mixin.dart';
import 'package:shorebird_cli/src/shorebird_validation_mixin.dart';
@@ -11,7 +9,7 @@ import 'package:shorebird_cli/src/shorebird_validation_mixin.dart';
/// Run the Flutter application.
/// {@endtemplate}
class RunCommand extends ShorebirdCommand
with AuthLoggerMixin, ShorebirdValidationMixin, ShorebirdConfigMixin {
with ShorebirdConfigMixin, ShorebirdValidationMixin {
/// {@macro run_command}
RunCommand({
required super.logger,
@@ -44,15 +42,13 @@ class RunCommand extends ShorebirdCommand
@override
Future<int> run() async {
if (!auth.isAuthenticated) {
printNeedsAuthInstructions();
return ExitCode.noUser.code;
}
final validationIssues = await runValidators();
if (validationIssuesContainsError(validationIssues)) {
logValidationFailure(issues: validationIssues);
return ExitCode.config.code;
try {
await validatePreconditions(
checkUserIsAuthenticated: true,
checkValidators: true,
);
} on PreconditionFailedException catch (e) {
return e.exitCode.code;
}
logger.info('Running app...');
@@ -2,13 +2,13 @@ import 'dart:async';
import 'package:intl/intl.dart';
import 'package:mason_logger/mason_logger.dart';
import 'package:shorebird_cli/src/auth_logger_mixin.dart';
import 'package:shorebird_cli/src/command.dart';
import 'package:shorebird_cli/src/shorebird_config_mixin.dart';
import 'package:shorebird_cli/src/shorebird_validation_mixin.dart';
import 'package:shorebird_code_push_client/shorebird_code_push_client.dart';
class CancelSubscriptionCommand extends ShorebirdCommand
with AuthLoggerMixin, ShorebirdConfigMixin {
with ShorebirdConfigMixin, ShorebirdValidationMixin {
CancelSubscriptionCommand({
required super.logger,
super.auth,
@@ -23,9 +23,12 @@ class CancelSubscriptionCommand extends ShorebirdCommand
@override
Future<int> run() async {
if (!auth.isAuthenticated) {
printNeedsAuthInstructions();
return ExitCode.noUser.code;
try {
await validatePreconditions(
checkUserIsAuthenticated: true,
);
} on PreconditionFailedException catch (e) {
return e.exitCode.code;
}
final client = buildCodePushClient(
@@ -1,9 +1,63 @@
import 'package:collection/collection.dart';
import 'package:mason_logger/mason_logger.dart';
import 'package:shorebird_cli/src/command.dart';
import 'package:shorebird_cli/src/shorebird_config_mixin.dart';
import 'package:shorebird_cli/src/validators/validators.dart';
mixin ShorebirdValidationMixin on ShorebirdCommand {
abstract interface class PreconditionFailedException implements Exception {
ExitCode get exitCode;
}
class ShorebirdNotInitializedException implements PreconditionFailedException {
@override
ExitCode get exitCode => ExitCode.config;
}
class UserNotAuthorizedException implements PreconditionFailedException {
@override
ExitCode get exitCode => ExitCode.noUser;
}
class ValidationFailedException implements PreconditionFailedException {
@override
ExitCode get exitCode => ExitCode.config;
}
mixin ShorebirdValidationMixin on ShorebirdConfigMixin {
/// Checks common preconditions for running a command and throws an
/// appropriate [PreconditionFailedException] if any of them fail.
Future<void> validatePreconditions({
bool checkShorebirdInitialized = false,
bool checkUserIsAuthenticated = false,
bool checkValidators = false,
}) async {
if (checkUserIsAuthenticated && !auth.isAuthenticated) {
logger
..err('You must be logged in to run this command.')
..info(
'''If you already have an account, run ${lightCyan.wrap('shorebird login')} to sign in.''',
)
..info(
'''If you don't have a Shorebird account, run ${lightCyan.wrap('shorebird account create')} to create one.''',
);
throw UserNotAuthorizedException();
}
if (checkShorebirdInitialized && !isShorebirdInitialized) {
logger.err(
'Shorebird is not initialized. Did you run "shorebird init"?',
);
throw ShorebirdNotInitializedException();
}
if (checkValidators) {
final validationIssues = await runValidators();
if (validationIssuesContainsError(validationIssues)) {
logValidationFailure(issues: validationIssues);
throw ValidationFailedException();
}
}
}
/// Runs [Validator.validate] on all [validators] and writes results to
/// stdout.
Future<List<ValidationIssue>> runValidators() async {
@@ -71,12 +71,12 @@ void main() {
);
});
test('exits with code 70 when user is not logged in', () async {
test('exits with code 67 when user is not logged in', () async {
when(() => auth.isAuthenticated).thenReturn(false);
final result = await subscribeAccountCommand.run();
expect(result, ExitCode.software.code);
expect(result, ExitCode.noUser.code);
verify(
() => logger.err(any(that: contains('You must be logged in to run'))),
@@ -23,6 +23,7 @@ class _MockShorebirdProcess extends Mock implements ShorebirdProcess {}
void main() {
group(BuildAarCommand, () {
const appId = 'test-app-id';
const buildNumber = '1.0';
const noModulePubspecYamlContent = '''
name: example
@@ -64,6 +65,9 @@ flutter:
).writeAsStringSync(
includeModule ? pubspecYamlContent : noModulePubspecYamlContent,
);
File(
p.join(tempDir.path, 'shorebird.yaml'),
).writeAsStringSync('app_id: $appId');
return tempDir;
}
@@ -78,6 +82,7 @@ flutter:
command = BuildAarCommand(
auth: auth,
logger: logger,
validators: [],
)
..testArgResults = argResults
..testProcess = shorebirdProcess