added new commit/branch/origin information to git repository reports
[scpubgit/System-Introspector-Report.git] / lib / System / Introspector / Report / Builder / Repositories / Git / Locations.pm
CommitLineData
60136b2b 1package System::Introspector::Report::Builder::Repositories::Git::Locations;
2use Moo;
3
4extends 'System::Introspector::Report::Builder';
5
6has collect_matching => (is => 'ro', default => sub { [] });
7has _locations_by_origin => (is => 'lazy', default => sub { {} });
8
9sub required_data {
10 return qw(
11 repositories/git
12 host
13 );
14}
15
16sub _match_origin {
17 my ($self, $origin) = @_;
18 my @match_rx = @{ $self->collect_matching };
19 for my $rx (@match_rx) {
20 if ($origin =~ qr{^$rx$}i) {
21 return $1;
22 }
23 }
24 return undef;
25}
26
000ae97b 27my $_trim = sub {
28 my ($string) = @_;
29 $string =~ s{^\s*}{}g;
30 $string =~ s{\s*$}{}g;
31 return $string;
32};
33
34my $_format_commit = sub {
35 my ($current) = @_;
36 my @lines = @{ $current->{commit} || [] };
37 return undef
38 unless @lines;
39 (my $commit = shift @lines) =~ s{^commit\s+}{}i;
40 my %header;
41 HEADER: while (my $line = shift @lines) {
42 if ($line =~ m{^([^:]+):\s*(.+)$}) {
43 $header{$1} = $2;
44 }
45 elsif ($line =~ m{^\s*$}) {
46 last HEADER;
47 }
48 else {
49 return 'Unable to parse message headers';
50 }
51 }
52 my $title = '';
53 while (my $line = shift @lines) {
54 if ($line =~ m{\S}) {
55 $title = $line;
56 }
57 }
58 return join("\n",
59 $commit->$_trim,
60 sprintf('by %s', $header{Author} || ''),
61 sprintf('at %s', $header{CommitDate} || ''),
62 $title->$_trim,
63 );
64};
65
66my $_commit_count = sub {
67 my ($data) = @_;
68 my $branch = $data->{current}{branch};
69 return undef
70 unless defined $branch;
71 if (my $cnt = $data->{tracked}{branches}{$branch}{local_commit_count}) {
72 return $cnt
73 if defined($cnt) and not(ref $cnt);
74 }
75 if (my $cnt = $data->{current}{origin}{local_commit_count}) {
76 return $cnt
77 if defined($cnt) and not(ref $cnt);
78 }
79 return undef;
80};
81
60136b2b 82sub collect_from {
83 my ($self, $remote, $data) = @_;
84 my $git = $data->{'repositories/git'}{git} || {};
85 for my $location (keys %$git) {
86 my $origin = $git->{$location}{config}{contents}{'remote.origin.url'}
87 or next;
88 my $matched = $self->_match_origin($origin)
89 or next;
000ae97b 90 my $current = $git->{$location}{current} || {};
60136b2b 91 push @{$self->_locations_by_origin->{$matched}}, {
000ae97b 92 remote => $remote,
93 hostname => $data->{host}{hostname},
94 location => $location,
95 origin => $origin,
96 local_count => $git->{$location}->$_commit_count,
97 branch => $current->{branch},
98 last_commit => $current->$_format_commit,
60136b2b 99 };
100 }
101 return 1;
102}
103
104sub render_reports {
105 my ($self) = @_;
106 my @columns = (
000ae97b 107 { key => 'remote', label => 'Remote Host' },
108 { key => 'hostname', label => 'Hostname' },
109 { key => 'location', label => 'Location' },
110 { key => 'branch', label => 'Branch' },
111 { key => 'local_count', label => 'Changes' },
112 { key => 'last_commit', label => 'Last Commit' },
60136b2b 113 );
114 my $collected = $self->_locations_by_origin;
115 return map {
116 my $identifier = $_;
117 my $rows = $collected->{$identifier};
118 {
119 columns => [@columns],
120 title => "$identifier Checkouts",
121 id => ['repositories-git-locations', $identifier],
122 rowid => [qw( remote location )],
123 meta => { repository => $identifier },
124 rows => [
125 sort {
126 ($a->{remote} cmp $b->{remote})
127 ||
128 ($a->{location} cmp $b->{location})
129 } @$rows,
130 ],
131 };
132 } keys %$collected;
133}
134
1351;