Ctrl K
ComunidadGuías…

script/coverage-check

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
#!/usr/bin/env perl
# SPDX-FileCopyrightText: 2026 GPForum Contributors
# SPDX-License-Identifier: BSD-3-Clause

package main;

use v5.40;

use Carp qw(croak);
use Const::Fast;
use English qw(-no_match_vars);

use Devel::Cover::DB;

our $VERSION = '0.001';

# The coverage verdict, read from the coverage database rather than scraped
# from a report: a table enforces no threshold, and the CI step named "Run
# coverage gate" has to be able to fail.
#
# This measures lib/ only and compares it with a floor recorded in
# etc/coverage-floor. The floor is a ratchet: it is raised by hand when
# coverage improves and never lowered to make a build pass.

const my $FLOOR_FILE => 'etc/coverage-floor';
const my @CRITERIA   => qw(statement subroutine);
const my $HEADROOM   => 1;

my $database = shift @ARGV || 'cover_db';
croak "no coverage database at $database" if !-d $database;

my $db    = Devel::Cover::DB->new( db => $database )->merge_runs;
my @files = grep { m{\A lib/}msx } $db->cover->items;
if ( !@files ) {
    _say( *STDERR, 'coverage-check status=fail reason=no-lib-files-measured' );
    exit 1;
}

$db->calculate_summary( ( map { $_ => 1 } @CRITERIA ), files => \@files );

my %floor_for = _floor();
my @failed;
my @report;
for my $criterion (@CRITERIA) {
    my $measured = $db->summary( 'Total', $criterion, 'percentage' );
    if ( !defined $measured ) {
        $measured = 0;
    }
    my $minimum = $floor_for{$criterion};
    croak "$FLOOR_FILE has no floor for $criterion" if !defined $minimum;

    push @report, sprintf '%s=%.1f(floor %.1f)', $criterion, $measured,
      $minimum;
    if ( $measured < $minimum ) {
        push @failed, $criterion;
    }
    if ( $measured >= $minimum + $HEADROOM ) {
        printf {*STDERR}
          "coverage-check: %s is %.1f, %.1f above its floor; raise %s\n",
          $criterion, $measured, $measured - $minimum, $FLOOR_FILE;
    }
}

my $files = scalar @files;
if (@failed) {
    _say( *STDERR, "coverage-check status=fail files=$files @report" );
    exit 1;
}

_say( *STDOUT, "coverage-check status=ok files=$files @report" );
exit 0;

sub _say {
    my ( $handle, $line ) = @_;

    print {$handle} "$line\n" or croak "write: $ERRNO";

    return;
}

sub _floor {
    open my $handle, '<', $FLOOR_FILE
      or croak "open $FLOOR_FILE: $ERRNO";
    my %floor;
    while ( my $line = <$handle> ) {
        next if $line =~ /\A \s* (?: [#] | \z )/msx;
        my ( $criterion, $value ) = split q{ }, $line;
        $floor{$criterion} = $value;
    }
    close $handle or croak "close $FLOOR_FILE: $ERRNO";

    return %floor;
}