App-GHGen

 view release on metacpan or  search on metacpan

t/integration.t  view on Meta::CPAN

			'total_minutes equals sum of per-workflow minutes_per_month');

		# Within free tier: billable_minutes == 0 and monthly_cost == 0.
		if ($usage->{total_minutes} <= $FREE_TIER_MINUTES) {
			is($usage->{billable_minutes}, 0, 'billable_minutes is 0 within free tier');
			is($usage->{monthly_cost},     0, 'monthly_cost is 0 within free tier');
		}

		diag(sprintf 'Total: %.1f min  billable: %.1f  cost: $%.2f',
			$usage->{total_minutes}, $usage->{billable_minutes}, $usage->{monthly_cost})
			if $ENV{TEST_VERBOSE};

		restore_all();
	});
};

# ---------------------------------------------------------------------------
# Subtest 10: Fixer::fix_workflow end-to-end file round-trip
# Write a YAML file with known issues, call fix_workflow(), read it back,
# and verify the mutations persisted to disk.
subtest 'Fixer::fix_workflow: mutations written to disk and re-loadable' => sub {
	in_tempdir(sub {
		path('.github/workflows')->mkpath;
		my $wf_path = '.github/workflows/fixme.yml';

		DumpFile($wf_path, {
			name => 'Fixable',
			on   => [qw(push)],
			jobs => {
				build => {
					'runs-on' => 'ubuntu-18.04',
					steps     => [
						{ uses => 'actions/checkout@main' },
						{ run  => 'cargo build' },
					],
				},
			},
		});

		my @issues = (
			{
				type     => 'cost',
				severity => 'low',
				message  => 'No concurrency group - old runs continue when superseded',
			},
			{
				type     => 'maintenance',
				severity => 'low',
				message  => 'Using older runner versions - consider updating',
			},
		);

		my $n = fix_workflow($wf_path, \@issues);
		cmp_ok($n, '>=', 1, "fix_workflow applied at least one fix (got $n)");

		# Re-read the YAML from disk and assert the fixes persisted.
		my $reloaded = LoadFile($wf_path);
		ok(defined $reloaded->{concurrency},
			'concurrency key present in reloaded workflow (persisted to disk)');
		isnt($reloaded->{jobs}{build}{'runs-on'}, 'ubuntu-18.04',
			'outdated runner updated in reloaded workflow');

		diag("Reloaded runs-on: $reloaded->{jobs}{build}{'runs-on'}") if $ENV{TEST_VERBOSE};
	});
};

# ---------------------------------------------------------------------------
# Subtest 11: fix_workflow skips DumpFile when no fixes applied
# POD: the file is only rewritten when fix count > 0.
# Spy on DumpFile to confirm it is never called when the issues list is empty.
subtest 'Fixer::fix_workflow: DumpFile not called when zero fixes applied' => sub {
	in_tempdir(sub {
		path('.github/workflows')->mkpath;
		my $wf_path = '.github/workflows/clean.yml';
		DumpFile($wf_path, _clean_workflow());

		# Spy (call-through) records calls without preventing them.
		my $get_dump_calls = spy('App::GHGen::Fixer::DumpFile');

		my $n = fix_workflow($wf_path, []);
		is($n, 0, 'fix_workflow returns 0 when no issues passed');
		is(scalar $get_dump_calls->(), 0,
			'DumpFile not called when fix count is zero');

		restore_all();
	});
};

# ---------------------------------------------------------------------------
# Subtest 12: PerlCustomizer detect_perl_requirements + generate_custom_perl_workflow
# Verify the detect -> configure -> generate pipeline and the step-ordering
# invariant documented in CLAUDE.md and PerlCustomizer POD.
subtest 'PerlCustomizer: detect_perl_requirements feeds generate_custom_perl_workflow' => sub {
	in_tempdir(sub {
		path('cpanfile')->spew("requires 'perl', '5.036';\nrequires 'Moose';\n");
		path('Makefile.PL')->spew("use ExtUtils::MakeMaker;\n");

		my $reqs = detect_perl_requirements();
		ok($reqs->{has_cpanfile},     'cpanfile detected');
		ok($reqs->{has_makefile_pl},  'Makefile.PL detected');
		is($reqs->{min_version}, '5.036', 'Correct minimum Perl version extracted');

		my $yaml = generate_custom_perl_workflow({
			enable_linter        => 1,
			enable_linter_unused => 0,
			enable_critic        => 1,
			enable_coverage      => 1,
		});
		ok(defined $yaml && length $yaml > 0, 'generate_custom_perl_workflow returns YAML');

		# Step ordering invariant per CLAUDE.md:
		# checkout -> setup-perl -> cache -> deps -> lint -> tests -> critic -> coverage
		my $checkout_pos = index($yaml, 'checkout');
		my $lint_pos     = index($yaml, 'perl {0}');
		my $prove_pos    = index($yaml, 'prove');
		my $critic_pos   = index($yaml, 'Perl::Critic');
		my $cover_pos    = index($yaml, 'Devel::Cover');

		cmp_ok($checkout_pos, '>=', 0, 'checkout step present in generated YAML');
		cmp_ok($lint_pos,     '>=', 0, 'lint step (perl {0}) present in generated YAML');
		cmp_ok($prove_pos,    '>=', 0, 'test step (prove) present in generated YAML');



( run in 0.614 second using v1.01-cache-2.11-cpan-81fc1098f69 )