From 2fe281b6b85d01d6290d3c91c54232e9152cc377 Mon Sep 17 00:00:00 2001 From: Charles McGarvey Date: Fri, 2 Apr 2021 17:16:35 -0600 Subject: [PATCH] Version 0.50 --- Changes | 3 + LICENSE | 6 +- MANIFEST | 6 +- META.json | 46 +- META.yml | 39 +- Makefile.PL | 17 +- README | 4 +- bin/git-codeowners | 6 +- lib/App/Codeowners.pm | 6 +- lib/App/Codeowners/Formatter.pm | 6 +- lib/App/Codeowners/Formatter/CSV.pm | 6 +- lib/App/Codeowners/Formatter/JSON.pm | 6 +- lib/App/Codeowners/Formatter/String.pm | 6 +- lib/App/Codeowners/Formatter/TSV.pm | 6 +- lib/App/Codeowners/Formatter/Table.pm | 6 +- lib/App/Codeowners/Formatter/YAML.pm | 6 +- lib/App/Codeowners/Options.pm | 63 ++- lib/App/Codeowners/Util.pm | 208 +++----- lib/File/Codeowners.pm | 645 ------------------------- lib/Test/File/Codeowners.pm | 141 ------ t/00-compile.t | 6 +- t/00-report-prereqs.dd | 10 +- t/file-codeowners.t | 167 ------- t/samples/basic.CODEOWNERS | 2 - t/samples/kitchensink.CODEOWNERS | 18 - xt/author/eol.t | 6 +- xt/author/no-tabs.t | 6 +- xt/author/pod-coverage.t | 7 + 28 files changed, 194 insertions(+), 1260 deletions(-) delete mode 100644 lib/File/Codeowners.pm delete mode 100644 lib/Test/File/Codeowners.pm delete mode 100644 t/file-codeowners.t delete mode 100644 t/samples/basic.CODEOWNERS delete mode 100644 t/samples/kitchensink.CODEOWNERS create mode 100644 xt/author/pod-coverage.t diff --git a/Changes b/Changes index 5b4e5ce..4a2a85c 100644 --- a/Changes +++ b/Changes @@ -1,5 +1,8 @@ Revision history for App-Codeowners. +0.50 2021-04-02 17:14:52-06:00 America/Denver + * Split off File::Codeowners to its own distribution. + 0.49 2020-03-22 01:30:54-06:00 MST7MDT * Fix an encoding issue with the YAML formatter. * Add rename_owner methods. diff --git a/LICENSE b/LICENSE index 2eb2acb..9bd2169 100644 --- a/LICENSE +++ b/LICENSE @@ -1,4 +1,4 @@ -This software is copyright (c) 2019 by Charles McGarvey. +This software is copyright (c) 2021 by Charles McGarvey. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. @@ -12,7 +12,7 @@ b) the "Artistic License" --- The GNU General Public License, Version 1, February 1989 --- -This software is Copyright (c) 2019 by Charles McGarvey. +This software is Copyright (c) 2021 by Charles McGarvey. This is free software, licensed under: @@ -272,7 +272,7 @@ That's all there is to it! --- The Artistic License 1.0 --- -This software is Copyright (c) 2019 by Charles McGarvey. +This software is Copyright (c) 2021 by Charles McGarvey. This is free software, licensed under: diff --git a/MANIFEST b/MANIFEST index 0db697f..bdeb5cc 100644 --- a/MANIFEST +++ b/MANIFEST @@ -18,20 +18,16 @@ lib/App/Codeowners/Formatter/Table.pm lib/App/Codeowners/Formatter/YAML.pm lib/App/Codeowners/Options.pm lib/App/Codeowners/Util.pm -lib/File/Codeowners.pm -lib/Test/File/Codeowners.pm t/00-compile.t t/00-report-prereqs.dd t/00-report-prereqs.t t/app-codeowners-util.t t/app-codeowners.t -t/file-codeowners.t -t/samples/basic.CODEOWNERS -t/samples/kitchensink.CODEOWNERS xt/author/critic.t xt/author/eol.t xt/author/minimum-version.t xt/author/no-tabs.t +xt/author/pod-coverage.t xt/author/pod-no404s.t xt/author/pod-syntax.t xt/author/portability.t diff --git a/META.json b/META.json index 10d7765..fb933c2 100644 --- a/META.json +++ b/META.json @@ -49,6 +49,7 @@ "Dist::Zilla::Plugin::Run::Release" : "0", "Dist::Zilla::PluginBundle::Author::CCM" : "0", "Dist::Zilla::PluginBundle::Filter" : "0", + "Pod::Coverage::TrustPod" : "0", "Software::License::Perl_5" : "0", "Test::CPAN::Changes" : "0.19", "Test::CPAN::Meta" : "0", @@ -59,6 +60,7 @@ "Test::NoTabs" : "0", "Test::Perl::Critic" : "0", "Test::Pod" : "1.41", + "Test::Pod::Coverage" : "1.08", "Test::Pod::No404s" : "0", "Test::Portability::Files" : "0" } @@ -70,17 +72,14 @@ "Unicode::GCString" : "0" }, "requires" : { - "Carp" : "0", "Color::ANSI::Util" : "0.03", "Encode" : "0", "Exporter" : "0", + "File::Codeowners" : "0", + "File::Codeowners::Util" : "0", "Getopt::Long" : "2.39", - "IPC::Open2" : "0", "Module::Load" : "0", "Path::Tiny" : "0.089", - "Scalar::Util" : "0", - "Test::Builder" : "0", - "Text::Gitignore" : "0", "parent" : "0", "perl" : "v5.10.1", "strict" : "0", @@ -106,6 +105,7 @@ "FindBin" : "0", "IO::Handle" : "0", "IPC::Open3" : "0", + "Path::Tiny" : "0.089", "Test::Exit" : "0", "Test::More" : "0" } @@ -114,55 +114,43 @@ "provides" : { "App::Codeowners" : { "file" : "lib/App/Codeowners.pm", - "version" : "0.49" + "version" : "0.50" }, "App::Codeowners::Formatter" : { "file" : "lib/App/Codeowners/Formatter.pm", - "version" : "0.49" + "version" : "0.50" }, "App::Codeowners::Formatter::CSV" : { "file" : "lib/App/Codeowners/Formatter/CSV.pm", - "version" : "0.49" + "version" : "0.50" }, "App::Codeowners::Formatter::JSON" : { "file" : "lib/App/Codeowners/Formatter/JSON.pm", - "version" : "0.49" + "version" : "0.50" }, "App::Codeowners::Formatter::String" : { "file" : "lib/App/Codeowners/Formatter/String.pm", - "version" : "0.49" + "version" : "0.50" }, "App::Codeowners::Formatter::TSV" : { "file" : "lib/App/Codeowners/Formatter/TSV.pm", - "version" : "0.49" + "version" : "0.50" }, "App::Codeowners::Formatter::Table" : { "file" : "lib/App/Codeowners/Formatter/Table.pm", - "version" : "0.49" + "version" : "0.50" }, "App::Codeowners::Formatter::YAML" : { "file" : "lib/App/Codeowners/Formatter/YAML.pm", - "version" : "0.49" + "version" : "0.50" }, "App::Codeowners::Options" : { "file" : "lib/App/Codeowners/Options.pm", - "version" : "0.49" + "version" : "0.50" }, "App::Codeowners::Util" : { "file" : "lib/App/Codeowners/Util.pm", - "version" : "0.49" - }, - "App::Codeowners::Util::Process" : { - "file" : "lib/App/Codeowners/Util.pm", - "version" : "0.49" - }, - "File::Codeowners" : { - "file" : "lib/File/Codeowners.pm", - "version" : "0.49" - }, - "Test::File::Codeowners" : { - "file" : "lib/Test/File/Codeowners.pm", - "version" : "0.49" + "version" : "0.50" } }, "release_status" : "stable", @@ -177,10 +165,10 @@ "web" : "https://github.com/chazmcgarvey/git-codeowners" } }, - "version" : "0.49", + "version" : "0.50", "x_authority" : "cpan:CCM", "x_generated_by_perl" : "v5.28.0", - "x_serialization_backend" : "Cpanel::JSON::XS version 4.15", + "x_serialization_backend" : "Cpanel::JSON::XS version 4.25", "x_spdx_expression" : "Artistic-1.0-Perl OR GPL-1.0-or-later" } diff --git a/META.yml b/META.yml index 30c0c55..ab362ad 100644 --- a/META.yml +++ b/META.yml @@ -10,6 +10,7 @@ build_requires: FindBin: '0' IO::Handle: '0' IPC::Open3: '0' + Path::Tiny: '0.089' Test::Exit: '0' Test::More: '0' configure_requires: @@ -31,59 +32,47 @@ no_index: provides: App::Codeowners: file: lib/App/Codeowners.pm - version: '0.49' + version: '0.50' App::Codeowners::Formatter: file: lib/App/Codeowners/Formatter.pm - version: '0.49' + version: '0.50' App::Codeowners::Formatter::CSV: file: lib/App/Codeowners/Formatter/CSV.pm - version: '0.49' + version: '0.50' App::Codeowners::Formatter::JSON: file: lib/App/Codeowners/Formatter/JSON.pm - version: '0.49' + version: '0.50' App::Codeowners::Formatter::String: file: lib/App/Codeowners/Formatter/String.pm - version: '0.49' + version: '0.50' App::Codeowners::Formatter::TSV: file: lib/App/Codeowners/Formatter/TSV.pm - version: '0.49' + version: '0.50' App::Codeowners::Formatter::Table: file: lib/App/Codeowners/Formatter/Table.pm - version: '0.49' + version: '0.50' App::Codeowners::Formatter::YAML: file: lib/App/Codeowners/Formatter/YAML.pm - version: '0.49' + version: '0.50' App::Codeowners::Options: file: lib/App/Codeowners/Options.pm - version: '0.49' + version: '0.50' App::Codeowners::Util: file: lib/App/Codeowners/Util.pm - version: '0.49' - App::Codeowners::Util::Process: - file: lib/App/Codeowners/Util.pm - version: '0.49' - File::Codeowners: - file: lib/File/Codeowners.pm - version: '0.49' - Test::File::Codeowners: - file: lib/Test/File/Codeowners.pm - version: '0.49' + version: '0.50' recommends: Pod::Usage: '0' Term::Detect::Software: '0' Unicode::GCString: '0' requires: - Carp: '0' Color::ANSI::Util: '0.03' Encode: '0' Exporter: '0' + File::Codeowners: '0' + File::Codeowners::Util: '0' Getopt::Long: '2.39' - IPC::Open2: '0' Module::Load: '0' Path::Tiny: '0.089' - Scalar::Util: '0' - Test::Builder: '0' - Text::Gitignore: '0' parent: '0' perl: v5.10.1 strict: '0' @@ -93,7 +82,7 @@ resources: bugtracker: https://github.com/chazmcgarvey/git-codeowners/issues homepage: https://github.com/chazmcgarvey/git-codeowners repository: https://github.com/chazmcgarvey/git-codeowners.git -version: '0.49' +version: '0.50' x_authority: cpan:CCM x_generated_by_perl: v5.28.0 x_serialization_backend: 'YAML::Tiny version 1.73' diff --git a/Makefile.PL b/Makefile.PL index ca1bb2b..a81c2ea 100644 --- a/Makefile.PL +++ b/Makefile.PL @@ -20,17 +20,14 @@ my %WriteMakefileArgs = ( "MIN_PERL_VERSION" => "5.010001", "NAME" => "App::Codeowners", "PREREQ_PM" => { - "Carp" => 0, "Color::ANSI::Util" => "0.03", "Encode" => 0, "Exporter" => 0, + "File::Codeowners" => 0, + "File::Codeowners::Util" => 0, "Getopt::Long" => "2.39", - "IPC::Open2" => 0, "Module::Load" => 0, "Path::Tiny" => "0.089", - "Scalar::Util" => 0, - "Test::Builder" => 0, - "Text::Gitignore" => 0, "parent" => 0, "strict" => 0, "utf8" => 0, @@ -44,10 +41,11 @@ my %WriteMakefileArgs = ( "FindBin" => 0, "IO::Handle" => 0, "IPC::Open3" => 0, + "Path::Tiny" => "0.089", "Test::Exit" => 0, "Test::More" => 0 }, - "VERSION" => "0.49", + "VERSION" => "0.50", "test" => { "TESTS" => "t/*.t" } @@ -56,25 +54,22 @@ my %WriteMakefileArgs = ( my %FallbackPrereqs = ( "Capture::Tiny" => 0, - "Carp" => 0, "Color::ANSI::Util" => "0.03", "Encode" => 0, "Exporter" => 0, "ExtUtils::MakeMaker" => 0, + "File::Codeowners" => 0, + "File::Codeowners::Util" => 0, "File::Spec" => 0, "File::pushd" => 0, "FindBin" => 0, "Getopt::Long" => "2.39", "IO::Handle" => 0, - "IPC::Open2" => 0, "IPC::Open3" => 0, "Module::Load" => 0, "Path::Tiny" => "0.089", - "Scalar::Util" => 0, - "Test::Builder" => 0, "Test::Exit" => 0, "Test::More" => 0, - "Text::Gitignore" => 0, "parent" => 0, "strict" => 0, "utf8" => 0, diff --git a/README b/README index 4d522a7..c622ecd 100644 --- a/README +++ b/README @@ -4,7 +4,7 @@ NAME VERSION - version 0.49 + version 0.50 SYNOPSIS @@ -225,7 +225,7 @@ AUTHOR COPYRIGHT AND LICENSE - This software is copyright (c) 2019 by Charles McGarvey. + This software is copyright (c) 2021 by Charles McGarvey. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. diff --git a/bin/git-codeowners b/bin/git-codeowners index 9fffa25..5c2b3ea 100755 --- a/bin/git-codeowners +++ b/bin/git-codeowners @@ -10,7 +10,7 @@ use strict; use App::Codeowners; -our $VERSION = '0.49'; # VERSION +our $VERSION = '0.50'; # VERSION App::Codeowners->main(@ARGV); @@ -26,7 +26,7 @@ git-codeowners - A tool for managing CODEOWNERS files =head1 VERSION -version 0.49 +version 0.50 =head1 SYNOPSIS @@ -302,7 +302,7 @@ Charles McGarvey =head1 COPYRIGHT AND LICENSE -This software is copyright (c) 2019 by Charles McGarvey. +This software is copyright (c) 2021 by Charles McGarvey. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. diff --git a/lib/App/Codeowners.pm b/lib/App/Codeowners.pm index f33dfb8..85afe53 100644 --- a/lib/App/Codeowners.pm +++ b/lib/App/Codeowners.pm @@ -13,7 +13,7 @@ use Color::ANSI::Util 0.03 qw(ansifg); use File::Codeowners; use Path::Tiny; -our $VERSION = '0.49'; # VERSION +our $VERSION = '0.50'; # VERSION sub main { @@ -219,7 +219,7 @@ App::Codeowners - A tool for managing CODEOWNERS files =head1 VERSION -version 0.49 +version 0.50 =head1 DESCRIPTION @@ -250,7 +250,7 @@ Charles McGarvey =head1 COPYRIGHT AND LICENSE -This software is copyright (c) 2019 by Charles McGarvey. +This software is copyright (c) 2021 by Charles McGarvey. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. diff --git a/lib/App/Codeowners/Formatter.pm b/lib/App/Codeowners/Formatter.pm index 5c908d4..b0991ef 100644 --- a/lib/App/Codeowners/Formatter.pm +++ b/lib/App/Codeowners/Formatter.pm @@ -5,7 +5,7 @@ package App::Codeowners::Formatter; use warnings; use strict; -our $VERSION = '0.49'; # VERSION +our $VERSION = '0.50'; # VERSION use Module::Load; @@ -120,7 +120,7 @@ App::Codeowners::Formatter - Base class for formatting codeowners output =head1 VERSION -version 0.49 +version 0.50 =head1 SYNOPSIS @@ -252,7 +252,7 @@ Charles McGarvey =head1 COPYRIGHT AND LICENSE -This software is copyright (c) 2019 by Charles McGarvey. +This software is copyright (c) 2021 by Charles McGarvey. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. diff --git a/lib/App/Codeowners/Formatter/CSV.pm b/lib/App/Codeowners/Formatter/CSV.pm index b4aff63..2a4a920 100644 --- a/lib/App/Codeowners/Formatter/CSV.pm +++ b/lib/App/Codeowners/Formatter/CSV.pm @@ -5,7 +5,7 @@ package App::Codeowners::Formatter::CSV; use warnings; use strict; -our $VERSION = '0.49'; # VERSION +our $VERSION = '0.50'; # VERSION use parent 'App::Codeowners::Formatter'; @@ -62,7 +62,7 @@ App::Codeowners::Formatter::CSV - Format codeowners output as comma-separated va =head1 VERSION -version 0.49 +version 0.50 =head1 DESCRIPTION @@ -101,7 +101,7 @@ Charles McGarvey =head1 COPYRIGHT AND LICENSE -This software is copyright (c) 2019 by Charles McGarvey. +This software is copyright (c) 2021 by Charles McGarvey. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. diff --git a/lib/App/Codeowners/Formatter/JSON.pm b/lib/App/Codeowners/Formatter/JSON.pm index e4d8332..ea8ad96 100644 --- a/lib/App/Codeowners/Formatter/JSON.pm +++ b/lib/App/Codeowners/Formatter/JSON.pm @@ -5,7 +5,7 @@ package App::Codeowners::Formatter::JSON; use warnings; use strict; -our $VERSION = '0.49'; # VERSION +our $VERSION = '0.50'; # VERSION use parent 'App::Codeowners::Formatter'; @@ -42,7 +42,7 @@ App::Codeowners::Formatter::JSON - Format codeowners output as JSON =head1 VERSION -version 0.49 +version 0.50 =head1 DESCRIPTION @@ -69,7 +69,7 @@ Charles McGarvey =head1 COPYRIGHT AND LICENSE -This software is copyright (c) 2019 by Charles McGarvey. +This software is copyright (c) 2021 by Charles McGarvey. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. diff --git a/lib/App/Codeowners/Formatter/String.pm b/lib/App/Codeowners/Formatter/String.pm index 14b07a4..6fb775e 100644 --- a/lib/App/Codeowners/Formatter/String.pm +++ b/lib/App/Codeowners/Formatter/String.pm @@ -5,7 +5,7 @@ package App::Codeowners::Formatter::String; use warnings; use strict; -our $VERSION = '0.49'; # VERSION +our $VERSION = '0.50'; # VERSION use parent 'App::Codeowners::Formatter'; @@ -135,7 +135,7 @@ App::Codeowners::Formatter::String - Format codeowners output using printf-like =head1 VERSION -version 0.49 +version 0.50 =head1 DESCRIPTION @@ -158,7 +158,7 @@ Charles McGarvey =head1 COPYRIGHT AND LICENSE -This software is copyright (c) 2019 by Charles McGarvey. +This software is copyright (c) 2021 by Charles McGarvey. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. diff --git a/lib/App/Codeowners/Formatter/TSV.pm b/lib/App/Codeowners/Formatter/TSV.pm index 2ba0f53..8700bcc 100644 --- a/lib/App/Codeowners/Formatter/TSV.pm +++ b/lib/App/Codeowners/Formatter/TSV.pm @@ -5,7 +5,7 @@ package App::Codeowners::Formatter::TSV; use warnings; use strict; -our $VERSION = '0.49'; # VERSION +our $VERSION = '0.50'; # VERSION use parent 'App::Codeowners::Formatter::CSV'; @@ -25,7 +25,7 @@ App::Codeowners::Formatter::TSV - Format codeowners output as tab-separated valu =head1 VERSION -version 0.49 +version 0.50 =head1 DESCRIPTION @@ -46,7 +46,7 @@ Charles McGarvey =head1 COPYRIGHT AND LICENSE -This software is copyright (c) 2019 by Charles McGarvey. +This software is copyright (c) 2021 by Charles McGarvey. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. diff --git a/lib/App/Codeowners/Formatter/Table.pm b/lib/App/Codeowners/Formatter/Table.pm index 2309e6a..66ee92b 100644 --- a/lib/App/Codeowners/Formatter/Table.pm +++ b/lib/App/Codeowners/Formatter/Table.pm @@ -5,7 +5,7 @@ package App::Codeowners::Formatter::Table; use warnings; use strict; -our $VERSION = '0.49'; # VERSION +our $VERSION = '0.50'; # VERSION use parent 'App::Codeowners::Formatter'; @@ -39,7 +39,7 @@ App::Codeowners::Formatter::Table - Format codeowners output as a table =head1 VERSION -version 0.49 +version 0.50 =head1 DESCRIPTION @@ -60,7 +60,7 @@ Charles McGarvey =head1 COPYRIGHT AND LICENSE -This software is copyright (c) 2019 by Charles McGarvey. +This software is copyright (c) 2021 by Charles McGarvey. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. diff --git a/lib/App/Codeowners/Formatter/YAML.pm b/lib/App/Codeowners/Formatter/YAML.pm index 079eae5..590ad79 100644 --- a/lib/App/Codeowners/Formatter/YAML.pm +++ b/lib/App/Codeowners/Formatter/YAML.pm @@ -5,7 +5,7 @@ package App::Codeowners::Formatter::YAML; use warnings; use strict; -our $VERSION = '0.49'; # VERSION +our $VERSION = '0.50'; # VERSION use parent 'App::Codeowners::Formatter'; @@ -36,7 +36,7 @@ App::Codeowners::Formatter::YAML - Format codeowners output as YAML =head1 VERSION -version 0.49 +version 0.50 =head1 DESCRIPTION @@ -57,7 +57,7 @@ Charles McGarvey =head1 COPYRIGHT AND LICENSE -This software is copyright (c) 2019 by Charles McGarvey. +This software is copyright (c) 2021 by Charles McGarvey. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. diff --git a/lib/App/Codeowners/Options.pm b/lib/App/Codeowners/Options.pm index db7261e..54d1fc0 100644 --- a/lib/App/Codeowners/Options.pm +++ b/lib/App/Codeowners/Options.pm @@ -9,9 +9,9 @@ use Encode qw(decode); use Getopt::Long 2.39 (); use Path::Tiny; -our $VERSION = '0.49'; # VERSION +our $VERSION = '0.50'; # VERSION -sub pod2usage { +sub _pod2usage { eval { require Pod::Usage }; if ($@) { my $ref = $VERSION eq '9999.999' ? 'master' : "v$VERSION"; @@ -32,7 +32,7 @@ END } } -sub early_options { +sub _early_options { return { 'color|colour!' => (-t STDOUT ? 1 : 0), ## no critic (InputOutput::ProhibitInteractiveTest) 'format|f=s' => undef, @@ -43,7 +43,7 @@ sub early_options { }; } -sub command_options { +sub _command_options { return { 'create' => {}, 'owners' => { @@ -64,21 +64,22 @@ sub command_options { }; } -sub commands { +sub _commands { my $self = shift; - my @commands = sort keys %{$self->command_options}; + my @commands = sort keys %{$self->_command_options}; return @commands; } -sub options { +sub _options { my $self = shift; my @command_options; if (my $command = $self->{command}) { - @command_options = keys %{$self->command_options->{$command} || {}}; + @command_options = keys %{$self->_command_options->{$command} || {}}; } - return (keys %{$self->early_options}, @command_options); + return (keys %{$self->_early_options}, @command_options); } + sub new { my $class = shift; my @args = @_; @@ -92,9 +93,9 @@ sub new { my $opts = $self->get_options( args => \@args, - spec => $self->early_options, + spec => $self->_early_options, config => 'pass_through', - ) or pod2usage(2); + ) or _pod2usage(2); if ($ENV{CODEOWNERS_COMPLETIONS}) { $self->{command} = $args[0] || ''; @@ -114,10 +115,10 @@ sub new { exit 0; } if ($opts->{help}) { - pod2usage(-exitval => 0, -verbose => 99, -sections => [qw(NAME SYNOPSIS OPTIONS COMMANDS)]); + _pod2usage(-exitval => 0, -verbose => 99, -sections => [qw(NAME SYNOPSIS OPTIONS COMMANDS)]); } if ($opts->{manual}) { - pod2usage(-exitval => 0, -verbose => 2); + _pod2usage(-exitval => 0, -verbose => 2); } if (defined $opts->{shell_completion}) { $self->shell_completion($opts->{shell_completion}); @@ -126,31 +127,33 @@ sub new { # figure out the command (or default to "show") my $command = shift @args; - my $command_options = $self->command_options->{$command || ''}; + my $command_options = $self->_command_options->{$command || ''}; if (!$command_options) { unshift @args, $command if defined $command; $command = 'show'; - $command_options = $self->command_options->{$command}; + $command_options = $self->_command_options->{$command}; } my $more_opts = $self->get_options( args => \@args, spec => $command_options, - ) or pod2usage(2); + ) or _pod2usage(2); %$self = (%$opts, %$more_opts, command => $command, args => \@args); return $self; } + sub command { my $self = shift; my $command = $self->{command}; - my @commands = sort keys %{$self->command_options}; + my @commands = sort keys %{$self->_command_options}; return if not grep { $_ eq $command } @commands; $command =~ s/[^a-z]/_/g; return $command; } + sub args { my $self = shift; return @{$self->{args} || []}; @@ -246,7 +249,7 @@ sub completions { } else { if (!$self->command) { - $reply = [$self->commands, @{$self->_completion_options([keys %{$self->early_options}])}]; + $reply = [$self->_commands, @{$self->_completion_options([keys %{$self->_early_options}])}]; } else { print 'file'; @@ -261,7 +264,7 @@ sub completions { sub _completion_options { my $self = shift; - my $opts = shift || [$self->options]; + my $opts = shift || [$self->_options]; my @options; @@ -303,10 +306,28 @@ App::Codeowners::Options - Getopt and shell completion for App::Codeowners =head1 VERSION -version 0.49 +version 0.50 =head1 METHODS +=head2 new + + $options = App::Codeowners::Options->new(@ARGV); + +Construct a new object. + +=head2 command + + $str = $options->command; + +Get the command specified by args provided when the object was created. + +=head2 args + + $args = $options->args; + +Get the args provided when the object was created. + =head2 get_options $options = $options->get_options( @@ -372,7 +393,7 @@ Charles McGarvey =head1 COPYRIGHT AND LICENSE -This software is copyright (c) 2019 by Charles McGarvey. +This software is copyright (c) 2021 by Charles McGarvey. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. diff --git a/lib/App/Codeowners/Util.pm b/lib/App/Codeowners/Util.pm index 57e154d..fd8b793 100644 --- a/lib/App/Codeowners/Util.pm +++ b/lib/App/Codeowners/Util.pm @@ -5,8 +5,8 @@ package App::Codeowners::Util; use warnings; use strict; -use Encode qw(decode); use Exporter qw(import); +use File::Codeowners::Util; use Path::Tiny; our @EXPORT_OK = qw( @@ -23,83 +23,26 @@ our @EXPORT_OK = qw( zip ); -our $VERSION = '0.49'; # VERSION +our $VERSION = '0.50'; # VERSION -sub find_nearest_codeowners { - my $path = path(shift || '.')->absolute; +sub find_nearest_codeowners { goto &File::Codeowners::Util::find_nearest_codeowners } - while (!$path->is_rootdir) { - my $filepath = find_codeowners_in_directory($path); - return $filepath if $filepath; - $path = $path->parent; - } -} - - -sub find_codeowners_in_directory { - my $path = path(shift) or die; - my @tries = ( - [qw(CODEOWNERS)], - [qw(docs CODEOWNERS)], - [qw(.bitbucket CODEOWNERS)], - [qw(.github CODEOWNERS)], - [qw(.gitlab CODEOWNERS)], - ); +sub find_codeowners_in_directory { goto &File::Codeowners::Util::find_codeowners_in_directory } - for my $parts (@tries) { - my $try = $path->child(@$parts); - return $try if $try->is_file; - } -} -sub run_command { - my $filter; - $filter = pop if ref($_[-1]) eq 'CODE'; +sub run_command { goto &File::Codeowners::Util::run_command } - print STDERR "# @_\n" if $ENV{GIT_CODEOWNERS_DEBUG}; - my ($child_in, $child_out); - require IPC::Open2; - my $pid = IPC::Open2::open2($child_out, $child_in, @_); - close($child_in); +sub run_git { goto &File::Codeowners::Util::run_git } - binmode($child_out, ':encoding(UTF-8)'); - my $proc = App::Codeowners::Util::Process->new( - pid => $pid, - fh => $child_out, - filter => $filter, - ); +sub git_ls_files { goto &File::Codeowners::Util::git_ls_files } - return wantarray ? ($proc, @{$proc->all}) : $proc; -} -sub run_git { - return run_command('git', @_); -} +sub git_toplevel { goto &File::Codeowners::Util::git_toplevel } -sub git_ls_files { - my $dir = shift || '.'; - return run_git('-C', $dir, 'ls-files', @_, \&_unescape_git_filepath); -} - -# Depending on git's "core.quotepath" config, non-ASCII chars may be -# escaped (identified by surrounding dquotes), so try to unescape. -sub _unescape_git_filepath { - return $_ if $_ !~ /^"(.+)"$/; - return decode('UTF-8', unbackslash($1)); -} - -sub git_toplevel { - my $dir = shift || '.'; - - my ($proc, $path) = run_git('-C', $dir, qw{rev-parse --show-toplevel}); - - return if $proc->wait != 0 || !$path; - return path($path); -} sub colorstrip { my $str = shift || ''; @@ -107,21 +50,12 @@ sub colorstrip { return $str; } + sub stringify { my $item = shift; return ref($item) eq 'ARRAY' ? join(',', @$item) : $item; } -# The zip code is from List::SomeUtils (thanks DROLSKY), copied just so as not -# to bring in the extra dependency. -sub zip (\@\@) { ## no critic (Subroutines::ProhibitSubroutinePrototypes) - my $max = -1; - $max < $#$_ && ( $max = $#$_ ) foreach @_; - map { - my $ix = $_; - map $_->[$ix], @_; - } 0 .. $max; -} # The stringf code is from String::Format (thanks SREZIC), with changes: # - Use Unicode::GCString for better Unicode character padding, @@ -198,6 +132,7 @@ sub stringf { return $format; } + # The unbacklash code is from String::Escape (thanks EVO), with changes: # - Handle \a, \b, \f and \v (thanks Berk Akinci) my %unbackslash; @@ -215,55 +150,16 @@ sub unbackslash { return $str; } -{ - package App::Codeowners::Util::Process; - - sub new { - my $class = shift; - return bless {@_}, $class; - } - - sub next { - my $self = shift; - my $line = readline($self->{fh}); - if (defined $line) { - chomp $line; - if (my $filter = $self->{filter}) { - local $_ = $line; - $line = $filter->($line); - } - } - $line; - } - - sub all { - my $self = shift; - chomp(my @lines = readline($self->{fh})); - if (my $filter = $self->{filter}) { - $_ = $filter->($_) for @lines; - } - \@lines; - } - - sub wait { - my $self = shift; - my $pid = $self->{pid} or return; - if (my $fh = $self->{fh}) { - close($fh); - delete $self->{fh}; - } - waitpid($pid, 0); - my $status = $?; - print STDERR "# -> status $status\n" if $ENV{GIT_CODEOWNERS_DEBUG}; - delete $self->{pid}; - return $status; - } - sub DESTROY { - my ($self, $global_destruction) = @_; - return if $global_destruction; - $self->wait; - } +# The zip code is from List::SomeUtils (thanks DROLSKY), copied just so as not +# to bring in the extra dependency. +sub zip (\@\@) { ## no critic (Subroutines::ProhibitSubroutinePrototypes) + my $max = -1; + $max < $#$_ && ( $max = $#$_ ) foreach @_; + map { + my $ix = $_; + map $_->[$ix], @_; + } 0 .. $max; } 1; @@ -280,7 +176,7 @@ App::Codeowners::Util - Grab bag of utility subs for Codeowners modules =head1 VERSION -version 0.49 +version 0.50 =head1 DESCRIPTION @@ -290,44 +186,66 @@ B except in L and related modules. =head2 find_nearest_codeowners - $filepath = find_nearest_codeowners($dirpath); - -Find the F file in the current working directory, or search in the -parent directory recursively until a F file is found. +Deprecated. -Returns C if no F is found. +Use L instead. =head2 find_codeowners_in_directory - $filepath = find_codeowners_in_directory($dirpath); +Deprecated. + +Use L instead. + +=head2 run_command + +Deprecated. + +Use L instead. + +=head2 run_git + +Deprecated. + +Use L instead. + +=head2 git_ls_files + +Deprecated. + +Use L instead. + +=head2 git_toplevel + +Deprecated. -Find the F file in a given directory. No recursive searching is done. +Use L instead. -Returns the first of (or undef if none found): +=head2 colorstrip -=over 4 + $str = colorstrip($str); -=item * +Strip ANSI color control commands. -F +=head2 stringify -=item * + $str = stringify($scalar); + $str = stringify(\@array); -F +Get a useful string representation of a scallar or arrayref. -=item * +=head2 stringf -F<.bitbucket/CODEOWNERS> +TODO -=item * +=head2 unbackslash -F<.github/CODEOWNERS> +Deprecated. -=item * +Use L instead. -F<.gitlab/CODEOWNERS> +=head2 zip -=back +Same as L. =head1 BUGS @@ -344,7 +262,7 @@ Charles McGarvey =head1 COPYRIGHT AND LICENSE -This software is copyright (c) 2019 by Charles McGarvey. +This software is copyright (c) 2021 by Charles McGarvey. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. diff --git a/lib/File/Codeowners.pm b/lib/File/Codeowners.pm deleted file mode 100644 index 183208b..0000000 --- a/lib/File/Codeowners.pm +++ /dev/null @@ -1,645 +0,0 @@ -package File::Codeowners; -# ABSTRACT: Read and write CODEOWNERS files - -use v5.10.1; # defined-or -use warnings; -use strict; - -use Encode qw(encode); -use Path::Tiny 0.089; -use Scalar::Util qw(openhandle); -use Text::Gitignore qw(build_gitignore_matcher); - -our $VERSION = '0.49'; # VERSION - -sub _croak { require Carp; Carp::croak(@_); } -sub _usage { _croak("Usage: @_\n") } - - -sub new { - my $class = shift; - my $self = bless {}, $class; -} - - -sub parse { - my $self = shift; - my $input = shift or _usage(q{$codeowners->parse($input)}); - - return $self->parse_from_array($input, @_) if @_; - return $self->parse_from_array($input) if ref($input) eq 'ARRAY'; - return $self->parse_from_string($input) if ref($input) eq 'SCALAR'; - return $self->parse_from_fh($input) if openhandle($input); - return $self->parse_from_filepath($input); -} - - -sub parse_from_filepath { - my $self = shift; - my $path = shift or _usage(q{$codeowners->parse_from_filepath($filepath)}); - - $self = bless({}, $self) if !ref($self); - - return $self->parse_from_fh(path($path)->openr_utf8); -} - - -sub parse_from_fh { - my $self = shift; - my $fh = shift or _usage(q{$codeowners->parse_from_fh($fh)}); - - $self = bless({}, $self) if !ref($self); - - my @lines; - - my $parse_unowned; - my %unowned; - my $current_project; - - while (my $line = <$fh>) { - my $lineno = $. - 1; - chomp $line; - if ($line eq '### UNOWNED (File::Codeowners)') { - $parse_unowned++; - last; - } - elsif ($line =~ /^\h*#(.*)/) { - my $comment = $1; - my $project; - if ($comment =~ /^\h*Project:\h*(.+?)\h*$/i) { - $project = $current_project = $1 || undef; - } - $lines[$lineno] = { - comment => $comment, - $project ? (project => $project) : (), - }; - } - elsif ($line =~ /^\h*$/) { - # blank line - } - elsif ($line =~ /^\h*(.+?)(? $pattern, - owners => \@owners, - $current_project ? (project => $current_project) : (), - }; - } - else { - die "Parse error on line $.: $line\n"; - } - } - - if ($parse_unowned) { - while (my $line = <$fh>) { - chomp $line; - if ($line =~ /# (.+)/) { - my $filepath = $1; - $unowned{$filepath}++; - } - } - } - - $self->{lines} = \@lines; - $self->{unowned} = \%unowned; - - return $self; -} - - -sub parse_from_array { - my $self = shift; - my $arr = shift or _usage(q{$codeowners->parse_from_array(\@lines)}); - - $self = bless({}, $self) if !ref($self); - - $arr = [$arr, @_] if @_; - my $str = join("\n", @$arr); - return $self->parse_from_string(\$str); -} - - -sub parse_from_string { - my $self = shift; - my $str = shift or _usage(q{$codeowners->parse_from_string(\$string)}); - - $self = bless({}, $self) if !ref($self); - - my $ref = ref($str) eq 'SCALAR' ? $str : \$str; - open(my $fh, '<:encoding(UTF-8)', $ref) or die "open failed: $!"; - - return $self->parse_from_fh($fh); -} - - -sub write_to_filepath { - my $self = shift; - my $path = shift or _usage(q{$codeowners->write_to_filepath($filepath)}); - - path($path)->spew_utf8([map { "$_\n" } @{$self->write_to_array}]); -} - - -sub write_to_fh { - my $self = shift; - my $fh = shift or _usage(q{$codeowners->write_to_fh($fh)}); - my $charset = shift; - - for my $line (@{$self->write_to_array($charset)}) { - print $fh "$line\n"; - } -} - - -sub write_to_string { - my $self = shift; - my $charset = shift; - - my $str = join("\n", @{$self->write_to_array($charset)}) . "\n"; - return \$str; -} - - -sub write_to_array { - my $self = shift; - my $charset = shift; - - my @format; - - for my $line (@{$self->_lines}) { - if (my $comment = $line->{comment}) { - push @format, "#$comment"; - } - elsif (my $pattern = $line->{pattern}) { - my $owners = join(' ', @{$line->{owners}}); - push @format, "$pattern $owners"; - } - else { - push @format, ''; - } - } - - my @unowned = sort keys %{$self->_unowned}; - if (@unowned) { - push @format, '' if $format[-1]; - push @format, '### UNOWNED (File::Codeowners)'; - for my $unowned (@unowned) { - push @format, "# $unowned"; - } - } - - if (defined $charset) { - $_ = encode($charset, $_) for @format; - } - return \@format; -} - - -sub match { - my $self = shift; - my $filepath = shift or _usage(q{$codeowners->match($filepath)}); - - my $lines = $self->{match_lines} ||= [reverse grep { ($_ || {})->{pattern} } @{$self->_lines}]; - - for my $line (@$lines) { - my $matcher = $line->{matcher} ||= build_gitignore_matcher([$line->{pattern}]); - return { # deep copy - pattern => $line->{pattern}, - owners => [@{$line->{owners} || []}], - $line->{project} ? (project => $line->{project}) : (), - } if $matcher->($filepath); - } - - return undef; ## no critic (Subroutines::ProhibitExplicitReturn) -} - - -sub owners { - my $self = shift; - my $pattern = shift; - - return $self->{owners} if !$pattern && $self->{owners}; - - my %owners; - for my $line (@{$self->_lines}) { - next if $pattern && $line->{pattern} && $pattern ne $line->{pattern}; - $owners{$_}++ for (@{$line->{owners} || []}); - } - - my $owners = [sort keys %owners]; - $self->{owners} = $owners if !$pattern; - - return $owners; -} - - -sub patterns { - my $self = shift; - my $owner = shift; - - return $self->{patterns} if !$owner && $self->{patterns}; - - my %patterns; - for my $line (@{$self->_lines}) { - next if $owner && !grep { $_ eq $owner } @{$line->{owners} || []}; - my $pattern = $line->{pattern}; - $patterns{$pattern}++ if $pattern; - } - - my $patterns = [sort keys %patterns]; - $self->{patterns} = $patterns if !$owner; - - return $patterns; -} - - -sub projects { - my $self = shift; - - return $self->{projects} if $self->{projects}; - - my %projects; - for my $line (@{$self->_lines}) { - my $project = $line->{project}; - $projects{$project}++ if $project; - } - - my $projects = [sort keys %projects]; - $self->{projects} = $projects; - - return $projects; -} - - -sub update_owners { - my $self = shift; - my $pattern = shift; - my $owners = shift; - $pattern && $owners or _usage(q{$codeowners->update_owners($pattern => \@owners)}); - - $owners = [$owners] if ref($owners) ne 'ARRAY'; - - $self->_clear; - - my $count = 0; - - for my $line (@{$self->_lines}) { - next if !$line->{pattern}; - next if $pattern ne $line->{pattern}; - $line->{owners} = [@$owners]; - ++$count; - } - - return $count; -} - - -sub update_owners_by_project { - my $self = shift; - my $project = shift; - my $owners = shift; - $project && $owners or _usage(q{$codeowners->update_owners_by_project($project => \@owners)}); - - $owners = [$owners] if ref($owners) ne 'ARRAY'; - - $self->_clear; - - my $count = 0; - - for my $line (@{$self->_lines}) { - next if !$line->{project} || !$line->{owners}; - next if $project ne $line->{project}; - $line->{owners} = [@$owners]; - ++$count; - } - - return $count; -} - - -sub rename_owner { - my $self = shift; - my $old_owner = shift; - my $new_owner = shift; - $old_owner && $new_owner or _usage(q{$codeowners->rename_owner($owner => $new_owner)}); - - $self->_clear; - - my $count = 0; - - for my $line (@{$self->_lines}) { - next if !exists $line->{owners}; - for (my $i = 0; $i < @{$line->{owners}}; ++$i) { - next if $line->{owners}[$i] ne $old_owner; - $line->{owners}[$i] = $new_owner; - ++$count; - } - } - - return $count; -} - - -sub rename_project { - my $self = shift; - my $old_project = shift; - my $new_project = shift; - $old_project && $new_project or _usage(q{$codeowners->rename_project($project => $new_project)}); - - $self->_clear; - - my $count = 0; - - for my $line (@{$self->_lines}) { - next if !exists $line->{project} || $old_project ne $line->{project}; - $line->{project} = $new_project; - $line->{comment} = " Project: $new_project" if exists $line->{comment}; - ++$count; - } - - return $count; -} - - -sub append { - my $self = shift; - $self->_clear; - push @{$self->_lines}, (@_ ? {@_} : undef); -} - - -sub prepend { - my $self = shift; - $self->_clear; - unshift @{$self->_lines}, (@_ ? {@_} : undef); -} - - -sub unowned { - my $self = shift; - [sort keys %{$self->{unowned} || {}}]; -} - - -sub add_unowned { - my $self = shift; - $self->_unowned->{$_}++ for @_; -} - - -sub remove_unowned { - my $self = shift; - delete $self->_unowned->{$_} for @_; -} - -sub is_unowned { - my $self = shift; - my $filepath = shift; - $self->_unowned->{$filepath}; -} - - -sub clear_unowned { - my $self = shift; - $self->{unowned} = {}; -} - -sub _lines { shift->{lines} ||= [] } -sub _unowned { shift->{unowned} ||= {} } - -sub _clear { - my $self = shift; - delete $self->{match_lines}; - delete $self->{owners}; - delete $self->{patterns}; - delete $self->{projects}; -} - -1; - -__END__ - -=pod - -=encoding UTF-8 - -=head1 NAME - -File::Codeowners - Read and write CODEOWNERS files - -=head1 VERSION - -version 0.49 - -=head1 METHODS - -=head2 new - - $codeowners = File::Codeowners->new; - -Construct a new L. - -=head2 parse - - $codeowners = File::Codeowners->parse('path/to/CODEOWNERS'); - $codeowners = File::Codeowners->parse($filehandle); - $codeowners = File::Codeowners->parse(\@lines); - $codeowners = File::Codeowners->parse(\$string); - -Parse a F file. - -This is a shortcut for the C methods. - -=head2 parse_from_filepath - - $codeowners = File::Codeowners->parse_from_filepath('path/to/CODEOWNERS'); - -Parse a F file from the filesystem. - -=head2 parse_from_fh - - $codeowners = File::Codeowners->parse_from_fh($filehandle); - -Parse a F file from an open filehandle. - -=head2 parse_from_array - - $codeowners = File::Codeowners->parse_from_array(\@lines); - -Parse a F file stored as lines in an array. - -=head2 parse_from_string - - $codeowners = File::Codeowners->parse_from_string(\$string); - $codeowners = File::Codeowners->parse_from_string($string); - -Parse a F file stored as a string. String should be UTF-8 encoded. - -=head2 write_to_filepath - - $codeowners->write_to_filepath($filepath); - -Write the contents of the file to the filesystem atomically. - -=head2 write_to_fh - - $codeowners->write_to_fh($fh); - -Format the file contents and write to a filehandle. - -=head2 write_to_string - - $scalarref = $codeowners->write_to_string; - -Format the file contents and return a reference to a formatted string. - -=head2 write_to_array - - $lines = $codeowners->write_to_array; - -Format the file contents as an arrayref of lines. - -=head2 match - - $owners = $codeowners->match($filepath); - -Match the given filepath against the available patterns and return just the -owners for the matching pattern. Patterns are checked in the reverse order -they were defined in the file. - -Returns C if no patterns match. - -=head2 owners - - $owners = $codeowners->owners; # get all defined owners - $owners = $codeowners->owners($pattern); - -Get an arrayref of owners defined in the file. If a pattern argument is given, -only owners for the given pattern are returned (or empty arrayref if the -pattern does not exist). If no argument is given, simply returns all owners -defined in the file. - -=head2 patterns - - $patterns = $codeowners->patterns; - $patterns = $codeowners->patterns($owner); - -Get an arrayref of all patterns defined. - -=head2 projects - - $projects = $codeowners->projects; - -Get an arrayref of all projects defined. - -=head2 update_owners - - $codeowners->update_owners($pattern => \@new_owners); - -Set a new set of owners for a given pattern. If for some reason the file has -multiple such patterns, they will all be updated. - -Nothing happens if the file does not already have at least one such pattern. - -=head2 update_owners_by_project - - $codeowners->update_owners_by_project($project => \@new_owners); - -Set a new set of owners for all patterns under the given project. - -Nothing happens if the file does not have a project with the given name. - -=head2 rename_owner - - $codeowners->rename_owner($old_name => $new_name); - -Rename an owner. - -Nothing happens if the file does not have an owner with the old name. - -=head2 rename_project - - $codeowners->rename_project($old_name => $new_name); - -Rename a project. - -Nothing happens if the file does not have a project with the old name. - -=head2 append - - $codeowners->append(comment => $str); - $codeowners->append(pattern => $pattern, owners => \@owners); - $codeowners->append(); # blank line - -Append a new line. - -=head2 prepend - - $codeowners->prepend(comment => $str); - $codeowners->prepend(pattern => $pattern, owners => \@owners); - $codeowners->prepend(); # blank line - -Prepend a new line. - -=head2 unowned - - $filepaths = $codeowners->unowned; - -Get the list of filepaths in the "unowned" section. - -This parser supports an "extension" to the F file format which -lists unowned files at the end of the file. This list can be useful to have in -order to figure out what files we know are unowned versus what files we don't -know are unowned. - -=head2 add_unowned - - $codeowners->add_unowned($filepath, ...); - -Add one or more filepaths to the "unowned" list. - -This method does not check to make sure the filepath(s) actually do not match -any patterns in the file, so you might want to call L first. - -See L for an explanation. - -=head2 remove_unowned - - $codeowners->remove_unowned($filepath, ...); - -Remove one or more filepaths from the "unowned" list. - -Silently ignores filepaths that are already not listed. - -See L for an explanation. - -=head2 clear_unowned - - $codeowners->clear_unowned; - -Remove all filepaths from the "unowned" list. - -See L for an explanation. - -=head1 BUGS - -Please report any bugs or feature requests on the bugtracker website -L - -When submitting a bug or request, please include a test-file or a -patch to an existing test-file that illustrates the bug or desired -feature. - -=head1 AUTHOR - -Charles McGarvey - -=head1 COPYRIGHT AND LICENSE - -This software is copyright (c) 2019 by Charles McGarvey. - -This is free software; you can redistribute it and/or modify it under -the same terms as the Perl 5 programming language system itself. - -=cut diff --git a/lib/Test/File/Codeowners.pm b/lib/Test/File/Codeowners.pm deleted file mode 100644 index 0679e6b..0000000 --- a/lib/Test/File/Codeowners.pm +++ /dev/null @@ -1,141 +0,0 @@ -package Test::File::Codeowners; -# ABSTRACT: Write tests for CODEOWNERS files - - -use warnings; -use strict; - -use App::Codeowners::Util qw(find_nearest_codeowners git_ls_files git_toplevel); -use Encode qw(encode); -use File::Codeowners; -use Test::Builder; - -our $VERSION = '0.49'; # VERSION - -my $Test = Test::Builder->new; - -sub import { - my $self = shift; - my $caller = caller; - no strict 'refs'; ## no critic (TestingAndDebugging::ProhibitNoStrict) - *{$caller.'::codeowners_syntax_ok'} = \&codeowners_syntax_ok; - *{$caller.'::codeowners_git_files_ok'} = \&codeowners_git_files_ok; - - $Test->exported_to($caller); - $Test->plan(@_); -} - - -sub codeowners_syntax_ok { - my $filepath = shift || find_nearest_codeowners(); - - eval { File::Codeowners->parse($filepath) }; - my $err = $@; - - $Test->ok(!$err, "Check syntax: $filepath"); - $Test->diag($err) if $err; -} - - -sub codeowners_git_files_ok { - my $filepath = shift || find_nearest_codeowners(); - - $Test->subtest('codeowners_git_files_ok' => sub { - my $codeowners = eval { File::Codeowners->parse($filepath) }; - if (my $err = $@) { - $Test->plan(tests => 1); - $Test->ok(0, "Parse $filepath"); - $Test->diag($err); - return; - } - - my ($proc, @files) = git_ls_files(git_toplevel()); - - $Test->plan($proc->wait == 0 ? (tests => scalar @files) : (skip_all => 'git ls-files failed')); - - for my $filepath (@files) { - my $msg = encode('UTF-8', "Check file: $filepath"); - - my $match = $codeowners->match($filepath); - my $is_unowned = $codeowners->is_unowned($filepath); - - if (!$match && !$is_unowned) { - $Test->ok(0, $msg); - $Test->diag("File is unowned\n"); - } - elsif ($match && $is_unowned) { - $Test->ok(0, $msg); - $Test->diag("File is owned but listed as unowned\n"); - } - else { - $Test->ok(1, $msg); - } - } - }); -} - -1; - -__END__ - -=pod - -=encoding UTF-8 - -=head1 NAME - -Test::File::Codeowners - Write tests for CODEOWNERS files - -=head1 VERSION - -version 0.49 - -=head1 SYNOPSIS - - use Test::More; - - eval 'use Test::File::Codeowners'; - plan skip_all => 'Test::File::Codeowners required for testing CODEOWNERS' if $@; - - codeowners_syntax_ok(); - done_testing; - -=head1 DESCRIPTION - -This package has assertion subroutines for testing F files. - -=head1 FUNCTIONS - -=head2 codeowners_syntax_ok - - codeowners_syntax_ok(); # search up the tree for a CODEOWNERS file - codeowners_syntax_ok($filepath); - -Check the syntax of a F file. - -=head2 codeowners_git_files_ok - - codeowners_git_files_ok(); # search up the tree for a CODEOWNERS file - codeowners_git_files_ok($filepath); - -=head1 BUGS - -Please report any bugs or feature requests on the bugtracker website -L - -When submitting a bug or request, please include a test-file or a -patch to an existing test-file that illustrates the bug or desired -feature. - -=head1 AUTHOR - -Charles McGarvey - -=head1 COPYRIGHT AND LICENSE - -This software is copyright (c) 2019 by Charles McGarvey. - -This is free software; you can redistribute it and/or modify it under -the same terms as the Perl 5 programming language system itself. - -=cut diff --git a/t/00-compile.t b/t/00-compile.t index 37c2ffc..3832fa4 100644 --- a/t/00-compile.t +++ b/t/00-compile.t @@ -6,7 +6,7 @@ use warnings; use Test::More; -plan tests => 13 + ($ENV{AUTHOR_TESTING} ? 1 : 0); +plan tests => 11 + ($ENV{AUTHOR_TESTING} ? 1 : 0); my @module_files = ( 'App/Codeowners.pm', @@ -18,9 +18,7 @@ my @module_files = ( 'App/Codeowners/Formatter/Table.pm', 'App/Codeowners/Formatter/YAML.pm', 'App/Codeowners/Options.pm', - 'App/Codeowners/Util.pm', - 'File/Codeowners.pm', - 'Test/File/Codeowners.pm' + 'App/Codeowners/Util.pm' ); my @scripts = ( diff --git a/t/00-report-prereqs.dd b/t/00-report-prereqs.dd index ee27381..a66a8e0 100644 --- a/t/00-report-prereqs.dd +++ b/t/00-report-prereqs.dd @@ -25,6 +25,7 @@ do { my $x = { 'Dist::Zilla::Plugin::Run::Release' => '0', 'Dist::Zilla::PluginBundle::Author::CCM' => '0', 'Dist::Zilla::PluginBundle::Filter' => '0', + 'Pod::Coverage::TrustPod' => '0', 'Software::License::Perl_5' => '0', 'Test::CPAN::Changes' => '0.19', 'Test::CPAN::Meta' => '0', @@ -35,6 +36,7 @@ do { my $x = { 'Test::NoTabs' => '0', 'Test::Perl::Critic' => '0', 'Test::Pod' => '1.41', + 'Test::Pod::Coverage' => '1.08', 'Test::Pod::No404s' => '0', 'Test::Portability::Files' => '0' } @@ -46,17 +48,14 @@ do { my $x = { 'Unicode::GCString' => '0' }, 'requires' => { - 'Carp' => '0', 'Color::ANSI::Util' => '0.03', 'Encode' => '0', 'Exporter' => '0', + 'File::Codeowners' => '0', + 'File::Codeowners::Util' => '0', 'Getopt::Long' => '2.39', - 'IPC::Open2' => '0', 'Module::Load' => '0', 'Path::Tiny' => '0.089', - 'Scalar::Util' => '0', - 'Test::Builder' => '0', - 'Text::Gitignore' => '0', 'parent' => '0', 'perl' => 'v5.10.1', 'strict' => '0', @@ -82,6 +81,7 @@ do { my $x = { 'FindBin' => '0', 'IO::Handle' => '0', 'IPC::Open3' => '0', + 'Path::Tiny' => '0.089', 'Test::Exit' => '0', 'Test::More' => '0' } diff --git a/t/file-codeowners.t b/t/file-codeowners.t deleted file mode 100644 index 7bfb53c..0000000 --- a/t/file-codeowners.t +++ /dev/null @@ -1,167 +0,0 @@ -#!/usr/bin/env perl - -use warnings; -use strict; - -use FindBin '$Bin'; - -use File::Codeowners; -use Test::More; - -subtest 'parse CODEOWNERS files', sub { - my @basic_arr = ('#wat', '* @whatever'); - my $basic_str = "#wat\n* \@whatever\n"; - my $expected = [ - {comment => 'wat'}, - {pattern => '*', owners => ['@whatever']}, - ]; - my $r; - - my $file = File::Codeowners->parse_from_filepath("$Bin/samples/basic.CODEOWNERS"); - is_deeply($r = $file->_lines, $expected, 'parse from filepath') or diag explain $r; - - $file = File::Codeowners->parse_from_array(\@basic_arr); - is_deeply($r = $file->_lines, $expected, 'parse from array') or diag explain $r; - - $file = File::Codeowners->parse_from_string(\$basic_str); - is_deeply($r = $file->_lines, $expected, 'parse from string') or diag explain $r; - - open(my $fh, '<', \$basic_str) or die "open failed: $!"; - $file = File::Codeowners->parse_from_fh($fh); - is_deeply($r = $file->_lines, $expected, 'parse from filehandle') or diag explain $r; - close($fh); -}; - -subtest 'query information from CODEOWNERS', sub { - my $file = File::Codeowners->parse("$Bin/samples/kitchensink.CODEOWNERS"); - my $r; - - is_deeply($r = $file->owners, [ - '@"Lucius Fox"', - '@bane', - '@batman', - '@joker', - '@robin', - '@the-penguin', - 'alfred@waynecorp.example.com', - ], 'list all owners') or diag explain $r; - - is_deeply($r = $file->owners('tricks/Grinning/'), [qw( - @joker - @the-penguin - )], 'list owners matching pattern') or diag explain $r; - - is_deeply($r = $file->patterns, [qw( - * - /a/b/c/deep - /vehicles/**/batmobile.cad - mansion.txt - tricks/Explosions.doc - tricks/Grinning/ - )], 'list all patterns') or diag explain $r; - - is_deeply($r = $file->patterns('@joker'), [qw( - tricks/Explosions.doc - tricks/Grinning/ - )], 'list patterns matching owner') or diag explain $r; - - is_deeply($r = $file->unowned, [qw( - lightcycle.cad - )], 'list unowned') or diag explain $r; - - is_deeply($r = $file->match('whatever'), { - owners => [qw(@batman @robin)], - pattern => '*', - }, 'match solitary wildcard') or diag explain $r; - is_deeply($r = $file->match('subdir/mansion.txt'), { - owners => ['alfred@waynecorp.example.com'], - pattern => 'mansion.txt', - }, 'match filename') or diag explain $r; - is_deeply($r = $file->match('vehicles/batmobile.cad'), { - owners => ['@"Lucius Fox"'], - pattern => '/vehicles/**/batmobile.cad', - project => 'Transportation', - }, 'match double asterisk') or diag explain $r; - is_deeply($r = $file->match('vehicles/extra/batmobile.cad'), { - owners => ['@"Lucius Fox"'], - pattern => '/vehicles/**/batmobile.cad', - project => 'Transportation', - }, 'match double asterisk again') or diag explain $r; -}; - -subtest 'parse errors', sub { - eval { File::Codeowners->parse(\q{meh}) }; - like($@, qr/^Parse error on line 1/, 'parse error'); -}; - -subtest 'handling projects', sub { - my $file = File::Codeowners->parse("$Bin/samples/kitchensink.CODEOWNERS"); - my $r; - - is_deeply($r = $file->projects, [ - 'Transportation', - ], 'projects listed') or diag explain $r; - - $file->rename_project('Transportation', 'Getting Around'); - is_deeply($r = $file->projects, [ - 'Getting Around', - ], 'project renamed') or diag explain $r; - - is_deeply($r = [@{$file->_lines}[-3 .. -1]], [ - {comment => ' Project: Getting Around', project => 'Getting Around'}, - {}, - {pattern => '/vehicles/**/batmobile.cad', 'owners' => ['@"Lucius Fox"'], project => 'Getting Around'}, - ], 'renaming project properly modifies lines') or diag explain $r; - - $file->update_owners_by_project('Getting Around', '@twoface'); - ok( scalar grep { $_ eq '@twoface' } @{$file->owners}, 'updating owner adds new owner'); - ok(!scalar grep { $_ eq '@"Lucius Fox"' } @{$file->owners}, 'updating owner removes old owner'); -}; - -subtest 'editing and writing files', sub { - my $file = File::Codeowners->parse("$Bin/samples/basic.CODEOWNERS"); - my $r; - - $file->update_owners('*' => [qw(@foo @bar @baz)]); - is_deeply($r = $file->_lines, [ - {comment => 'wat'}, - {pattern => '*', owners => [qw(@foo @bar @baz)]}, - ], 'update owners for a pattern') or diag explain $r; - is_deeply($r = $file->owners, [qw(@bar @baz @foo)], 'got updated owners') or diag explain $r; - - $file->update_owners('no/such/pattern' => [qw(@wuf)]); - is_deeply($r = $file->_lines, [ - {comment => 'wat'}, - {pattern => '*', owners => [qw(@foo @bar @baz)]}, - ], 'no change when updating nonexistent pattern') or diag explain $r; - - $file->prepend(comment => 'start'); - $file->append(pattern => 'end', owners => ['@qux']); - is_deeply($r = $file->_lines, [ - {comment => 'start'}, - {comment => 'wat'}, - {pattern => '*', owners => [qw(@foo @bar @baz)]}, - {pattern => 'end', owners => [qw(@qux)]}, - ], 'prepand and append') or diag explain $r; - - $file->add_unowned('lonely', 'afraid'); - is_deeply($r = $file->unowned, [qw(afraid lonely)], 'set unowned files') or diag explain $r; - - $file->remove_unowned('afraid'); - is_deeply($r = $file->unowned, [qw(lonely)], 'remove unowned files') or diag explain $r; - - is_deeply($r = $file->write_to_array, [ - '#start', - '#wat', - '* @foo @bar @baz', - 'end @qux', - '', - '### UNOWNED (File::Codeowners)', - '# lonely', - ], 'format file') or diag explain $r; - - $file->clear_unowned; - is_deeply($r = $file->unowned, [], 'clear unowned files') or diag explain $r; -}; - -done_testing; diff --git a/t/samples/basic.CODEOWNERS b/t/samples/basic.CODEOWNERS deleted file mode 100644 index cbbe999..0000000 --- a/t/samples/basic.CODEOWNERS +++ /dev/null @@ -1,2 +0,0 @@ -#wat -* @whatever diff --git a/t/samples/kitchensink.CODEOWNERS b/t/samples/kitchensink.CODEOWNERS deleted file mode 100644 index 06c1688..0000000 --- a/t/samples/kitchensink.CODEOWNERS +++ /dev/null @@ -1,18 +0,0 @@ -# This is a comment. -* @batman @robin - -mansion.txt alfred@waynecorp.example.com - -tricks/Explosions.doc @joker -tricks/Grinning/ @joker @the-penguin - - # not the hero gotham deserves! -/a/b/c/deep @bane @the-penguin - -# project: Transportation - -/vehicles/**/batmobile.cad @"Lucius Fox" - - -### UNOWNED (File::Codeowners) -# lightcycle.cad diff --git a/xt/author/eol.t b/xt/author/eol.t index 0f00e36..1ac98ad 100644 --- a/xt/author/eol.t +++ b/xt/author/eol.t @@ -18,20 +18,16 @@ my @files = ( 'lib/App/Codeowners/Formatter/YAML.pm', 'lib/App/Codeowners/Options.pm', 'lib/App/Codeowners/Util.pm', - 'lib/File/Codeowners.pm', - 'lib/Test/File/Codeowners.pm', 't/00-compile.t', 't/00-report-prereqs.dd', 't/00-report-prereqs.t', 't/app-codeowners-util.t', 't/app-codeowners.t', - 't/file-codeowners.t', - 't/samples/basic.CODEOWNERS', - 't/samples/kitchensink.CODEOWNERS', 'xt/author/critic.t', 'xt/author/eol.t', 'xt/author/minimum-version.t', 'xt/author/no-tabs.t', + 'xt/author/pod-coverage.t', 'xt/author/pod-no404s.t', 'xt/author/pod-syntax.t', 'xt/author/portability.t', diff --git a/xt/author/no-tabs.t b/xt/author/no-tabs.t index 0872e0d..b72d4fb 100644 --- a/xt/author/no-tabs.t +++ b/xt/author/no-tabs.t @@ -18,20 +18,16 @@ my @files = ( 'lib/App/Codeowners/Formatter/YAML.pm', 'lib/App/Codeowners/Options.pm', 'lib/App/Codeowners/Util.pm', - 'lib/File/Codeowners.pm', - 'lib/Test/File/Codeowners.pm', 't/00-compile.t', 't/00-report-prereqs.dd', 't/00-report-prereqs.t', 't/app-codeowners-util.t', 't/app-codeowners.t', - 't/file-codeowners.t', - 't/samples/basic.CODEOWNERS', - 't/samples/kitchensink.CODEOWNERS', 'xt/author/critic.t', 'xt/author/eol.t', 'xt/author/minimum-version.t', 'xt/author/no-tabs.t', + 'xt/author/pod-coverage.t', 'xt/author/pod-no404s.t', 'xt/author/pod-syntax.t', 'xt/author/portability.t', diff --git a/xt/author/pod-coverage.t b/xt/author/pod-coverage.t new file mode 100644 index 0000000..66b3b64 --- /dev/null +++ b/xt/author/pod-coverage.t @@ -0,0 +1,7 @@ +#!perl +# This file was automatically generated by Dist::Zilla::Plugin::PodCoverageTests. + +use Test::Pod::Coverage 1.08; +use Pod::Coverage::TrustPod; + +all_pod_coverage_ok({ coverage_class => 'Pod::Coverage::TrustPod' }); -- 2.44.0