run method
Executes the run command to process distribution tasks.
This method performs the following operations:
- Parses the configuration file specified by
--configoption - Filters tasks and jobs based on the
--operationkey - Executes build and publish operations for each selected job
- Prints a summary and returns a matching exit code
A job that fails aborts the remaining jobs of its task, because a publish step must never run on the artifact of a build that did not succeed.
Implementation
@override
Future<int> run() async {
// Claim stdout for the report before anything is printed, so even a
// configuration error lands on stderr and leaves stdout parseable.
if (argResults!['json'] as bool) {
ColorizeLogger.reserveStdout = true;
ColorizeLogger.retargetColors();
}
final ConfigParser configParser;
try {
configParser = await _buildConfigParser();
} on ConfigException catch (e) {
logger.logError(e.message);
return 1;
}
if (argResults!['list'] as bool) {
_printCatalog(configParser);
return 0;
}
JobArguments.dryRun = isDryRun;
_printBanner(configParser);
final results = <JobResult>[];
final stopwatch = Stopwatch()..start();
for (final task in configParser.tasks) {
final jobs = _resolveJobs(task);
if (jobs.isEmpty) {
logger.logWarning("${task.name} has no job to run, skipping");
continue;
}
logger.logGroup(task.name);
if (task.description != null) logger.logDetail(task.description!);
var taskFailed = false;
await ColorizeLogger.group(() async {
for (final job in jobs) {
logger.logEmpty();
final result = await _runJob(task, job);
results.add(result);
if (result.isFatal) {
taskFailed = true;
final remaining = jobs.length - jobs.indexOf(job) - 1;
if (remaining > 0) {
logger.logWarning(
"skipped $remaining remaining job(s) after ${job.label} failed",
);
}
break;
}
}
});
logger.logEmpty();
if (taskFailed && failFast) {
logger.logWarning("stopping early (--fail-fast)");
break;
}
}
stopwatch.stop();
final summary = _renderSummary(results, stopwatch.elapsed);
_printSummary(results, stopwatch.elapsed);
// A run that executed nothing is not a success. Reporting 0 here let a
// pipeline "pass" while shipping nothing, which is the worst possible way
// to find out a job was excluded by its task's `workflows`.
final failed = results.isEmpty || results.any((result) => result.isFatal);
await _writeJsonReport(results, stopwatch.elapsed, succeeded: !failed);
if (!(argResults!['no-notify'] as bool) && !isDryRun) {
await Notifier(logger, configParser.variables).dispatch(
configParser.notifications,
succeeded: !failed,
summary: summary,
);
}
return failed ? 1 : 0;
}