execute method
Executes the release workflow represented by this strategy.
Implementation
@override
Future<ReleaseResult> execute(ReleaseContext context) async {
final steps = <String>[
'Initialized ReleaseContext',
'Selected NormalReleaseStrategy',
];
// Determine platform and format
final platformStr = context.targetPlatform ?? 'android';
final platform = BuildPlatform.parse(platformStr);
BuildFormat format;
if (context.config.format != null && context.config.format!.isNotEmpty) {
format = BuildFormat.parse(context.config.format!);
} else {
format = BuildFormat.defaultForPlatform(platform);
}
final buildContext = BuildContext(
projectPath: context.projectPath,
platform: platform,
format: format,
versionName: context.versionName,
buildNumber: context.buildNumber,
dryRun: context.dryRun,
isReleaseMode: true,
);
steps.add('Configured build for platform $platform with format $format');
if (context.dryRun) {
steps.add('Executed build subsystem in dry-run mode.');
final buildResults = await _buildManager.executeBuild(buildContext);
if (context.config.deploy) {
steps.add('Executing store deployment subsystem in dry-run mode...');
final deployContext = DeploymentContext(
projectPath: context.projectPath,
platform: platform,
lane: context.config.lane,
versionName: context.versionName,
buildNumber: context.buildNumber?.toString(),
dryRun: true,
);
final deployResults = await _deploymentManager.deploy(deployContext);
for (final dRes in deployResults) {
steps.addAll(dRes.executedSteps);
}
}
if (context.config.createTag) {
final tagName =
'${context.config.tagPrefix}${context.versionName ?? "1.0.0"}';
final tagRes = await _gitClient.createTag(
context.projectPath,
tagName,
message: 'Release $tagName',
dryRun: true,
);
steps.add(tagRes.message);
}
return ReleaseResult.success(
type: type,
message:
'[DRY-RUN] Normal Flutter Release build preview executed successfully.',
versionName: context.versionName,
buildNumber: context.buildNumber,
targetPlatform: platformStr,
executedSteps: [
...steps,
...buildResults.expand((r) => r.executedSteps),
],
metadata: {
'dryRun': true,
'buildResults': buildResults,
},
);
}
steps.add('Executing Flutter build compilation...');
final buildResults = await _buildManager.executeBuild(buildContext);
final allSuccessful = buildResults.every((r) => r.success);
final errors = <String>[];
final warnings = <String>[];
final artifactPaths = <String, String>{};
for (final res in buildResults) {
if (res.success && res.artifactPath != null) {
artifactPaths[res.platform.name] = res.artifactPath!;
}
errors.addAll(res.errors);
warnings.addAll(res.warnings);
}
if (!allSuccessful) {
return ReleaseResult.failure(
type: type,
message: 'Normal Flutter Release build failed.',
executedSteps: [
...steps,
...buildResults.expand((r) => r.executedSteps),
],
errors:
errors.isNotEmpty ? errors : ['One or more build targets failed.'],
warnings: warnings,
);
}
steps.add('Build compilation finished cleanly for all targets.');
if (context.config.deploy) {
steps.add('Triggering store deployment via Fastlane...');
final deployContext = DeploymentContext(
projectPath: context.projectPath,
platform: platform,
artifactPath: artifactPaths[platform.name],
lane: context.config.lane,
versionName: context.versionName,
buildNumber: context.buildNumber?.toString(),
dryRun: false,
);
final deployResults = await _deploymentManager.deploy(deployContext);
final deploySuccess = deployResults.every((r) => r.success);
for (final dRes in deployResults) {
steps.addAll(dRes.executedSteps);
warnings.addAll(dRes.warnings);
errors.addAll(dRes.errors);
}
if (!deploySuccess) {
return ReleaseResult.failure(
type: type,
message: 'Store deployment failed after successful build.',
executedSteps: steps,
errors: errors,
warnings: warnings,
);
}
}
// Handle Git Tagging
String? createdTagName;
if (context.config.createTag) {
final tagName =
'${context.config.tagPrefix}${context.versionName ?? "1.0.0"}';
final tagRes = await _gitClient.createTag(
context.projectPath,
tagName,
message: 'Release $tagName',
dryRun: false,
);
if (tagRes.success) {
createdTagName = tagName;
steps.add(tagRes.message);
} else {
warnings.add(tagRes.message);
}
}
// Save Release Metadata
final commitSha = await _gitClient.getCurrentCommitSha(context.projectPath);
final branch = await _gitClient.getCurrentBranch(context.projectPath);
final metadata = ReleaseMetadata(
versionName: context.versionName ?? '1.0.0',
buildNumber: context.buildNumber?.toString() ?? '1',
releaseMode: 'normal',
platforms: [platformStr],
tag: createdTagName,
commitSha: commitSha,
branch: branch,
artifacts: artifactPaths,
deploymentStatus: context.config.deploy ? 'Deployed' : 'Built',
);
await _metadataManager.saveMetadata(context.projectPath, metadata);
steps.add('Persisted release manifest to .flutter_setup/releases/');
return ReleaseResult.success(
type: type,
message: 'Normal Flutter Release build completed successfully.',
versionName: context.versionName,
buildNumber: context.buildNumber,
targetPlatform: platformStr,
executedSteps: [
...steps,
...buildResults.expand((r) => r.executedSteps),
],
warnings: warnings,
metadata: {
'artifactPaths': artifactPaths,
'buildResults': buildResults,
'tag': createdTagName,
'commitSha': commitSha,
},
);
}