App-GHGen
view release on metacpan or search on metacpan
}
my @issues = analyze_workflow($workflow, $file->basename);
if (@issues) {
# Filter to auto-fixable issues if in fix mode
my @fixable = $opts{fix} ? grep { can_auto_fix($_) } @issues : @issues;
if ($opts{fix} && @fixable) {
say " " . colored(['yellow'], "â ") . "Applying " . scalar(@fixable) . " fix(es)...";
my $fixes = fix_workflow($file, \@fixable);
$total_fixes += $fixes;
if ($fixes > 0) {
say " " . colored(['green'], "â ") . "Applied $fixes fix(es)";
} else {
say " " . colored(['yellow'], "â ") . "Could not apply some fixes automatically";
}
} else {
# Just report issues
for my $issue (@issues) {
my $icon = can_auto_fix($issue) ? "â " : "â¹";
say " " . colored(['yellow'], "$icon ") . $issue->{message};
if ($issue->{fix} && !$opts{fix} && !$opts{estimate}) {
say colored(['cyan'], " ð¡ Fix:");
for my $line (split /\n/, $issue->{fix}) {
say " " . $line;
}
}
}
}
push @all_issues, map { { file => $file->basename, %$_ } } @issues;
} else {
say " " . colored(['green'], "â No issues found");
}
say '';
}
# Summary
say colored(['bold cyan'], "=" x 50);
say colored(['bold'], "Summary:");
say " Workflows analyzed: $total_workflows";
say " Total issues found: " . scalar(@all_issues);
if ($opts{fix}) {
say " Fixes applied: " . colored(['green'], $total_fixes);
}
# Cost savings estimate
if ($opts{estimate} && @all_issues) {
say '';
my $savings = estimate_savings(\@all_issues, \@workflow_files);
if ($savings->{minutes} > 0) {
say colored(['bold'], "ð° Potential Savings:");
say ' With recommended changes: ' . colored(['green'], ($current_usage->{total_minutes} - $savings->{minutes})) .
" CI minutes/month";
say " Reduction: " . colored(['green'], "-$savings->{minutes} minutes") .
" (" . colored(['green'], "$savings->{percentage}%") . ")";
say " Cost savings: " . colored(['green'], "\$savings->{cost}/month") .
" (for private repos)";
if (@{$savings->{details}}) {
say '';
say " Breakdown:";
for my $detail (@{$savings->{details}}) {
say " ⢠$detail->{description}: ~$detail->{minutes} min/month";
}
}
}
}
if (@all_issues && !$opts{fix}) {
say '';
say colored(['bold yellow'], "Recommendations:");
my %by_type;
push @{$by_type{$_->{type}}}, $_ for @all_issues;
for my $type (sort keys %by_type) {
my $count = scalar @{$by_type{$type}};
my $fixable = grep { can_auto_fix($_) } @{$by_type{$type}};
my $suffix = $fixable > 0 ? " ($fixable auto-fixable)" : '';
say " ⢠" . colored(['yellow'], "$type") . ": $count workflow(s) affected$suffix";
}
say '';
say colored(['cyan'], "ð¡ Tip: ") . "Run " . colored(['bold'], "ghgen analyze --fix") .
" to automatically apply fixes";
if (!$opts{estimate}) {
say colored(['cyan'], "ð¡ Tip: ") . "Run " . colored(['bold'], "ghgen analyze --estimate") .
" to see potential cost savings";
}
}
exit(@all_issues ? 1 : 0);
}
sub list_types() {
say colored(['bold cyan'], "Available workflow templates:");
say '';
my %types = list_workflow_types();
for my $type (sort keys %types) {
say " " . colored(['green'], sprintf("%-10s", $type)) . " - $types{$type}";
}
say '';
say "Usage: ghgen generate --type=<type> [--output=<file>]";
say " or: ghgen generate --interactive";
}
sub interactive_select_type() {
say colored(['bold cyan'], "GitHub Actions Workflow Generator");
say colored(['cyan'], "=" x 50);
say '';
say "Select a project type:";
say '';
( run in 2.486 seconds using v1.01-cache-2.11-cpan-0bb4e1dffa6 )