git-codeowners [--version|--help|--manual]
- git-codeowners [show] [--format FORMAT] [--[no-]project] [PATH...]
+ git-codeowners [show] [--format FORMAT] [--owner OWNER]...
+ [--pattern PATTERN]... [--[no-]patterns]
+ [--project PROJECT]... [--[no-]projects] [PATH...]
git-codeowners owners [--format FORMAT] [--pattern PATTERN]
=head2 show
- git-codeowners [show] [--format FORMAT] [--[no-]project] [PATH...]
+ git-codeowners [show] [--format FORMAT] [--owner OWNER]...
+ [--pattern PATTERN]... [--[no-]patterns]
+ [--project PROJECT]... [--[no-]projects] [PATH...]
Show owners of one or more files in a repo.
+If C<--owner>, C<--project>, C<--pattern> are set, only show files with matching
+criteria. These can be repeated.
+
+Use C<--patterns> to also show the matching pattern associated with each file.
+
+By default the output might show associated projects if the C<CODEOWNERS> file
+defines them. You can control this by explicitly using C<--projects> or
+C<--no-projects> to always show or always hide defined projects, respectively.
+
=head2 owners
git-codeowners owners [--format FORMAT] [--pattern PATTERN]
+List all owners defined in the F<CODEOWNERS> file.
+
=head2 patterns
git-codeowners patterns [--format FORMAT] [--owner OWNER]
+List all patterns defined in the F<CODEOWNERS> file.
+
=head2 create
git-codeowners create [REPO_DIRPATH|CODEOWNERS_FILEPATH]
my ($proc, $cdup) = run_git(qw{rev-parse --show-cdup});
$proc->wait and exit 1;
+ my $show_projects = $opts->{projects} // scalar @{$codeowners->projects};
+
my $formatter = App::Codeowners::Formatter->new(
format => $opts->{format} || ' * %-50F %O',
handle => *STDOUT,
- columns => [qw(File Owner), $opts->{project} ? 'Project' : ()],
+ columns => [
+ 'File',
+ $opts->{patterns} ? 'Pattern' : (),
+ 'Owner',
+ $show_projects ? 'Project' : (),
+ ],
);
+ my %filter_owners = map { $_ => 1 } @{$opts->{owner}};
+ my %filter_projects = map { $_ => 1 } @{$opts->{project}};
+ my %filter_patterns = map { $_ => 1 } @{$opts->{pattern}};
+
$proc = git_ls_files('.', $opts->args);
while (my $filepath = $proc->next) {
my $match = $codeowners->match(path($filepath)->relative($cdup));
+ if (%filter_owners) {
+ for my $owner (@{$match->{owners}}) {
+ goto ADD_RESULT if $filter_owners{$owner};
+ }
+ next;
+ }
+ if (%filter_patterns) {
+ goto ADD_RESULT if $filter_patterns{$match->{pattern} || ''};
+ next;
+ }
+ if (%filter_projects) {
+ goto ADD_RESULT if $filter_projects{$match->{project} || ''};
+ next;
+ }
+ ADD_RESULT:
$formatter->add_result([
$filepath,
+ $opts->{patterns} ? $match->{pattern} : (),
$match->{owners},
- $opts->{project} ? $match->{project} : (),
+ $show_projects ? $match->{project} : (),
]);
}
$proc->wait and exit 1;
$formatter->add_result(map { [$_] } @$results);
}
+sub _command_projects {
+ my $self = shift;
+ my $opts = shift;
+
+ my $toplevel = git_toplevel('.') or die "Not a git repo\n";
+
+ my $codeowners_path = find_codeowners_in_directory($toplevel)
+ or die "No CODEOWNERS file in $toplevel\n";
+ my $codeowners = File::Codeowners->parse_from_filepath($codeowners_path);
+
+ my $results = $codeowners->projects;
+
+ my $formatter = App::Codeowners::Formatter->new(
+ format => $opts->{format} || '%P',
+ handle => *STDOUT,
+ columns => [qw(Project)],
+ );
+ $formatter->add_result(map { [$_] } @$results);
+}
+
sub _command_create { goto &_command_update }
sub _command_update {
my $self = shift;
'patterns' => {
'owner=s' => '',
},
+ 'projects' => {},
'show' => {
- 'project!' => 1,
+ 'owner=s@' => [],
+ 'pattern=s@' => [],
+ 'project=s@' => [],
+ 'patterns!' => 0,
+ 'projects!' => undef,
},
'update' => {},
};
return $patterns;
}
+=method projects
+
+ $projects = $codeowners->projects;
+
+Get an arrayref of all projects defined.
+
+=cut
+
+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;
+}
+
=method update_owners
$codeowners->update_owners($pattern => \@new_owners);
delete $self->{match_lines};
delete $self->{owners};
delete $self->{patterns};
+ delete $self->{projects};
}
1;
subtest 'format json' => sub {
plan skip_all => 'No JSON::MaybeXS' if !eval { require JSON::MaybeXS };
- ($stdout, $stderr, $exit) = run { App::Codeowners->main(qw{-f json show --no-project}) };
+ ($stdout, $stderr, $exit) = run { App::Codeowners->main(qw{-f json show --no-projects}) };
is($exit, 0, 'exited without error');
my $expect = '[{"File":"CODEOWNERS","Owner":null},{"File":"a/b/c/bar.txt","Owner":["@snickers"]},{"File":"foo.txt","Owner":["@twix"]}]';
is($stdout, $expect, 'correct output with json format');