execute method
Executes the command with the provided arguments.
Returns an integer exit code (0 for success).
Implementation
@override
Future<int> execute(List<String> arguments) async {
final ArgResults results;
try {
results = _argParser.parse(arguments);
} on FormatException catch (e) {
throw ValidationException(
'Error: ${e.message}\n\nUsage:\n flutter_setup release [--mode normal|shorebird] [--patch|--minor|--major|--version X] [--dry-run]',
);
}
final targetPath = results['path'] as String? ?? '.';
// Handle sub-actions (info, history, verify, summary, notes)
if (results.rest.isNotEmpty) {
final action = results.rest.first;
if (action == 'info') {
return _handleInfo(targetPath);
} else if (action == 'history') {
return _handleHistory(targetPath);
} else if (action == 'status') {
final statusText = await _recoveryManager.getReleaseStatus(targetPath);
_output.info(statusText);
return 0;
} else if (action == 'verify') {
final verifyText = await _recoveryManager.verifyRelease(targetPath);
_output.info(verifyText);
return 0;
} else if (action == 'recover') {
final success = await _recoveryManager.recoverRelease(
targetPath,
dryRun: results['dry-run'] as bool? ?? false,
);
return success ? 0 : 1;
} else if (action == 'summary') {
final summaryCmd = ReleaseSummaryCommand(_output);
return summaryCmd.execute(arguments.sublist(1));
} else if (action == 'notes') {
final notesCmd = ReleaseNotesCommand(_output);
return notesCmd.execute(arguments.sublist(1));
}
}
final modeRaw = results['mode'] as String? ?? 'normal';
final dryRun = results['dry-run'] as bool? ?? false;
final allowDirty = results['allow-dirty'] as bool? ?? false;
final patchFlag = results['patch'] as bool? ?? false;
final minorFlag = results['minor'] as bool? ?? false;
final majorFlag = results['major'] as bool? ?? false;
final explicitVersion = results['version'] as String?;
final explicitBuildStr = results['build-number'] as String?;
int? explicitBuildNumber;
if (explicitBuildStr != null && explicitBuildStr.isNotEmpty) {
explicitBuildNumber = int.tryParse(explicitBuildStr);
if (explicitBuildNumber == null || explicitBuildNumber <= 0) {
throw const ValidationException(
'Build number must be a positive integer.');
}
}
// Determine VersionBumpMode
VersionBumpMode bumpMode = VersionBumpMode.none;
final int bumpFlagsCount = (patchFlag ? 1 : 0) +
(minorFlag ? 1 : 0) +
(majorFlag ? 1 : 0) +
(explicitVersion != null ? 1 : 0);
if (bumpFlagsCount > 1) {
throw const ValidationException(
'Cannot specify multiple version bump options (--patch, --minor, --major, --version) simultaneously.',
);
}
if (patchFlag) {
bumpMode = VersionBumpMode.patch;
} else if (minorFlag) {
bumpMode = VersionBumpMode.minor;
} else if (majorFlag) {
bumpMode = VersionBumpMode.major;
} else if (explicitVersion != null && explicitVersion.isNotEmpty) {
bumpMode = VersionBumpMode.explicit;
} else if (explicitBuildNumber != null) {
bumpMode = VersionBumpMode.buildNumberOnly;
}
// Validate that projectPath points to a valid Flutter project
Validators.validateExistingFlutterProject(Directory(targetPath));
final releaseType = ReleaseType.fromString(modeRaw);
if (releaseType == ReleaseType.shorebirdPatch) {
throw const ValidationException(
'Use "flutter_setup patch" to apply Shorebird OTA patches.',
);
}
final platformRaw = results['platform'] as String? ?? 'android';
final formatRaw = results['format'] as String?;
final deployFlag = results['deploy'] as bool? ?? false;
final laneRaw = results['lane'] as String?;
final ciFlag = results['ci'] as bool? ?? false;
final tagFlag = results['tag'] as bool? ?? false;
final tagPrefix = results['tag-prefix'] as String? ?? 'v';
final envArg =
results['environment'] as String? ?? results['env'] as String?;
final rawDefines =
(results['dart-define'] as List<String>?) ?? const <String>[];
final parsedDefines = EnvironmentResolver.parseDartDefines(rawDefines);
final resolver = const EnvironmentResolver();
final envConfig = resolver.resolve(
cliEnvironment: envArg,
cliFlavor: results['flavor'] as String?,
cliDartDefines: parsedDefines,
envVars: Platform.environment,
);
final context = ReleaseContext(
projectPath: targetPath,
type: releaseType,
dryRun: dryRun,
allowDirty: allowDirty,
versionBumpMode: bumpMode,
targetPlatform: platformRaw,
versionName: explicitVersion,
buildNumber: explicitBuildNumber,
config: ReleaseConfig(
targetPlatform: platformRaw,
format: formatRaw,
deploy: deployFlag,
lane: laneRaw ?? envConfig.lane,
isCi: ciFlag,
createTag: tagFlag,
tagPrefix: tagPrefix,
environmentName: envArg != null ? envConfig.name : null,
flavor: envConfig.flavor,
dartDefines: envConfig.dartDefines,
),
);
final result = await _manager.executeRelease(context);
if (!result.success) {
for (final err in result.errors) {
_output.error('Error: $err');
}
return 1;
}
return 0;
}