1 package App
::Codeowners
;
2 # ABSTRACT: A tool for managing CODEOWNERS files
4 use v5
.10
.1; # defined-or
9 use App
::Codeowners
::Formatter
;
10 use App
::Codeowners
::Options
;
11 use App
::Codeowners
::Util
qw(find_codeowners_in_directory run_git git_ls_files git_toplevel);
12 use Color
::ANSI
::Util
0.03 qw(ansifg);
13 use Encode
qw(encode);
17 our $VERSION = '9999.999'; # VERSION
21 App
::Codeowners-
>main(@ARGV);
23 Run the script
and exit; does not return.
29 my $self = bless {}, $class;
31 my $opts = App
::Codeowners
::Options-
>new(@_);
33 my $color = $opts->{color
};
34 local $ENV{NO_COLOR
} = 1 if defined $color && !$color;
36 my $command = $opts->command;
37 my $handler = $self->can("_command_$command")
38 or die "Unknown command: $command\n";
39 $self->$handler($opts);
48 my $toplevel = git_toplevel
('.') or die "Not a git repo\n";
50 my $codeowners_path = find_codeowners_in_directory
($toplevel)
51 or die "No CODEOWNERS file in $toplevel\n";
52 my $codeowners = File
::Codeowners-
>parse_from_filepath($codeowners_path);
54 my ($proc, $cdup) = run_git
(qw{rev-parse --show-cdup});
55 $proc->wait and exit 1;
57 my $formatter = App
::Codeowners
::Formatter-
>new(
58 format
=> $opts->{format
} || ' * %-50F %O',
60 columns
=> [qw(File Owner), $opts->{project
} ? 'Project' : ()],
63 $proc = git_ls_files
('.', $opts->args);
64 while (my $filepath = $proc->next) {
65 my $match = $codeowners->match(path
($filepath)->relative($cdup));
66 $formatter->add_result([
69 $opts->{project
} ? $match->{project
} : (),
72 $proc->wait and exit 1;
79 my $toplevel = git_toplevel
('.') or die "Not a git repo\n";
81 my $codeowners_path = find_codeowners_in_directory
($toplevel)
82 or die "No CODEOWNERS file in $toplevel\n";
83 my $codeowners = File
::Codeowners-
>parse_from_filepath($codeowners_path);
85 my $results = $codeowners->owners($opts->{pattern
});
87 my $formatter = App
::Codeowners
::Formatter-
>new(
88 format
=> $opts->{format
} || '%O',
90 columns
=> [qw(Owner)],
92 $formatter->add_result(map { [$_] } @$results);
95 sub _command_patterns
{
99 my $toplevel = git_toplevel
('.') or die "Not a git repo\n";
101 my $codeowners_path = find_codeowners_in_directory
($toplevel)
102 or die "No CODEOWNERS file in $toplevel\n";
103 my $codeowners = File
::Codeowners-
>parse_from_filepath($codeowners_path);
105 my $results = $codeowners->patterns($opts->{owner
});
107 my $formatter = App
::Codeowners
::Formatter-
>new(
108 format
=> $opts->{format
} || '%T',
110 columns
=> [qw(Pattern)],
112 $formatter->add_result(map { [$_] } @$results);
115 sub _command_create
{ goto &_command_update
}
116 sub _command_update
{
120 my ($filepath) = $opts->args;
122 my $path = path
($filepath || '.');
125 die "Does not exist: $path\n" if !$path->parent->exists;
129 $path = find_codeowners_in_directory
($path) || $repopath->child('CODEOWNERS');
132 my $is_new = !$path->is_file;
136 $codeowners = File
::Codeowners-
>new;
137 my $template = <<'END';
138 This file shows mappings between subdirs/files and the individuals and
139 teams who own them. You can read this file yourself or use tools to query it,
140 so you can quickly determine who to speak with or send pull requests to. ❤️
142 Simply write a gitignore pattern followed by one or more names/emails/groups.
145 *.js @harry @javascript-cabal
147 for my $line (split(/\n/, $template)) {
148 $codeowners->append(comment
=> $line);
152 $codeowners = File
::Codeowners-
>parse_from_filepath($path);
156 # if there is a repo we can try to update the list of unowned files
157 my $git_files = git_ls_files
($repopath);
159 $codeowners->clear_unowned;
160 $codeowners->add_unowned(grep { !$codeowners->match($_) } @$git_files);
164 $codeowners->write_to_filepath($path);
165 print STDERR
"Wrote $path\n";