From: Junio C Hamano Date: Fri, 29 Apr 2011 04:14:15 +0000 (-0700) Subject: Meta/worklog: summarize weekly progress X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=9015711ed28b797f53189d10ffbe2247c504302e;p=thirdparty%2Fgit.git Meta/worklog: summarize weekly progress --- diff --git a/worklog b/worklog index a102e7a8f8..7b91cefd80 100755 --- a/worklog +++ b/worklog @@ -5,67 +5,118 @@ use warnings; use Getopt::Long; use Time::Local; +################################################################ + sub seconds_in_a_week () { return 7 * 24 * 3600; } -my $verbose = 0; -my $week; -my $cycles; -my $bow = 0; +# Convert seconds from epoch to datestring and dow +sub seconds_to_date { + my $time = shift; + my @time = localtime($time); + return (sprintf("%04d-%02d-%02d", + $time[5]+1900, $time[4]+1, $time[3]), + $time[6]); +} -sub bow { - my ($week) = @_; - my (@time, $time); +sub date_to_seconds { + my $datestring = shift; + my ($year, $mon, $mday) = ($datestring =~ /^(\d{4})-(\d{2})-(\d{2})$/); + unless (defined $year && defined $mon && defined $mday && + 1 <= $mon && $mon <= 12 && + 1 <= $mday && $mday <= 31) { + die "Bad datestring specification: $datestring"; + } + return timelocal(0, 0, 0, $mday, $mon - 1, $year - 1900); +} + +sub next_date { + my $datestring = shift; + my $time = date_to_seconds($datestring); + return seconds_to_date($time + 3600 * 36); +} + +sub prev_date { + my $datestring = shift; + my $time = date_to_seconds($datestring); + return seconds_to_date($time - 3600 * 12); +} + +sub beginning_of_reporting_week { + my ($datestring, $bow) = @_; + my ($date, $dow) = seconds_to_date(date_to_seconds($datestring)); + do { + ($date, $dow) = prev_date($date); + } while ($dow != $bow); + return $date; +} +sub bow { + my ($week, $bow) = @_; + my $time; if (!defined $week) { $time = time; } elsif ($week =~ /^\d+$/) { $time = time - seconds_in_a_week * $week; } else { - my ($year, $mon, $mday) = ($week =~ /^(\d{4})-(\d{2})-(\d{2})$/); - unless (defined $year && defined $mon && defined $mday && - 1 <= $mon && $mon <= 12 && - 1 <= $mday && $mday <= 31) { - die "Bad week specification: $week"; - } - $time = timelocal(0, 0, 0, $mday, $mon - 1, $year - 1900); + $time = date_to_seconds($week); } + my ($datestring, $dow) = seconds_to_date($time); + return beginning_of_reporting_week($datestring, $bow); +} - @time = localtime($time); - if ($time[6] <= $bow) { - $time -= seconds_in_a_week; - @time = localtime($time); - } - $time -= $time[0] + 60 * ($time[1] + 60 * ($time[2] + 24 * ($time[6] - $bow))); - return $time; +sub date_within { + my ($date, $bottom, $top) = @_; + return ($bottom le $date && $date le $top); } +################################################################ + +my $verbose = 0; +my $quiet = 0; +my $reporting_date; +my $weeks; +my $bow = 0; +my $bottom_date; + if (!GetOptions( "verbose!" => \$verbose, - "week=s" => \$week, - "cycles=i" => \$cycles, + "quiet!" => \$quiet, + "date=s" => \$reporting_date, + "weeks=i" => \$weeks, "bow=i" => \$bow, )) { - print STDERR "$0 [-v]\n"; + print STDERR "$0 [-v|-q] [-d date] [-w weeks] [-b bow]\n"; + exit 1; +} + +if ($verbose && $quiet) { + print STDERR "Which? Verbose, or Quiet?\n"; exit 1; } -if (defined $cycles && !defined $week) { - $week = bow($week); - $week -= ($cycles - 1) * seconds_in_a_week; -} else { - $week = bow($week); +if (!defined $reporting_date) { + ($reporting_date, my $dow) = seconds_to_date(time); + while ($dow != $bow) { + ($reporting_date, $dow) = next_date($reporting_date); + } +} + +$bottom_date = beginning_of_reporting_week($reporting_date, $bow); + +if (!defined $weeks || $weeks < 0) { + $weeks = 0; } -if (!defined $cycles) { - my $ends = time(); - my $clock = $week; - for ($cycles = 0; $clock < $ends; $cycles++) { - $clock += seconds_in_a_week; + +for (my $i = 0; $i < $weeks; $i++) { + for (my $j = 0; $j < 7; $j++) { + ($bottom_date, undef) = prev_date($bottom_date); } } +($bottom_date, undef) = next_date($bottom_date); -my $cull_old = "--since=" . $week; +my $cull_old = "--since=" . date_to_seconds($bottom_date); sub plural { my ($number, $singular, $plural) = @_; @@ -111,20 +162,41 @@ sub fmt_join { return join("", @result); } +################################################################ +# Collection + +# Map sha1 to patch information [$sha1, $author, $subject] +# or merge information [$sha1, undef, $branch]. my %patch; + +# $dates{"YYYY-MM-DD"} exists iff something happened my %dates; + +# List of $sha1 of patches applied, grouped by date my %patch_by_date; + +# List of $sha1 of merges, grouped by date my %merge_by_branch_date; + +# List of tags, grouped by date +my %tag_by_date; + +# List of integration branches. my @integrate = (['master', ', to include in the next release'], ['next', ' for public testing'], ['maint', ', to include in the maintenance release'], ); -open I, "-|", ("git", "log", "--pretty=%ci %H %an <%ae>\001%s", +# Collect individial patch application +open I, "-|", ("git", "log", + "--pretty=%ci %H %an <%ae>\001%s", $cull_old, "--glob=refs/heads", "--no-merges") or die; + while () { my ($date, $sha1, $rest) = /^([-0-9]+) [:0-9]+ [-+][0-9]{4} ([0-9a-f]+) (.*)$/; + next unless date_within($date, $bottom_date, $reporting_date); + $patch_by_date{$date} ||= []; push @{$patch_by_date{$date}}, $sha1; my ($name, $subject) = split(/\001/, $rest, 2); @@ -141,6 +213,7 @@ for my $branch (map { $_->[0] } @integrate) { $branch) or die; while () { my ($date, $sha1, $rest) = /^([-0-9]+) [:0-9]+ [-+][0-9]{4} ([0-9a-f]+) (.*)$/; + next unless date_within($date, $bottom_date, $reporting_date); my $msg = $rest; $msg =~ s/^Merge branch //; $msg =~ s/ into \Q$branch\E$//; @@ -157,34 +230,60 @@ for my $branch (map { $_->[0] } @integrate) { close (I) or die; } +open I, "-|", ("git", "for-each-ref", + "--format=%(refname:short) %(taggerdate:iso)", + "refs/tags") or die; +while () { + my ($tagname, $tagdate) = /^(\S+) ([-0-9]+) [:0-9]+ [-+][0-9]{4}$/; + + if (!defined $tagdate || + !date_within($tagdate, $bottom_date, $reporting_date)) { + next; + } + $dates{$tagdate}++; + $tag_by_date{$tagdate} ||= []; + push @{$tag_by_date{$tagdate}}, $tagname; +} + +################################################################ +# Summarize + my $sep = ""; -my %total_names = (); -my %total_merges = (); -my $total_patch = 0; my @dates = sort keys %dates; -for my $date (@dates) { - print "$sep$date\n"; +sub day_summary { + my ($date, $total_names, $total_merges, $total_patches, $total_tags) = @_; + return if (!exists $dates{$date}); + + print "$sep$date\n" if (!$quiet); + if (exists $tag_by_date{$date}) { + for my $tagname (@{$tag_by_date{$date}}) { + $$total_tags++; + print " Tagged $tagname.\n" if (!$quiet); + } + } + if (exists $patch_by_date{$date}) { my $count = scalar @{$patch_by_date{$date}}; my %names = (); for my $patch (map { $patch{$_} } (@{$patch_by_date{$date}})) { my $name = $patch->[1]; $names{$name}++; - $total_names{$name}++; + $total_names->{$name}++; } my $people = scalar @{[keys %names]}; - $total_patch += $count; + $$total_patches += $count; $count = plural($count, "patch", "patches"); $people = plural($people, "person", "people"); - print "Queued $count from $people.\n"; + print " Queued $count from $people.\n" if (!$quiet); if ($verbose) { for my $patch (map { $patch{$_} } @{$patch_by_date{$date}}) { - print " $patch->[2]\n"; + print " $patch->[2]\n"; } } } + for my $branch_data (@integrate) { my ($branch, $purpose) = @{$branch_data}; next unless (exists $merge_by_branch_date{$branch}{$date}); @@ -192,28 +291,85 @@ for my $date (@dates) { my $count = scalar @$merges; next unless $count; - $total_merges{$branch} ||= 0; - $total_merges{$branch} += $count; + $total_merges->{$branch} ||= 0; + $total_merges->{$branch} += $count; $count = plural($count, "topic", "topics"); - print "Merged $count to '$branch' branch$purpose.\n"; + print " Merged $count to '$branch' branch$purpose.\n" if (!$quiet); if ($verbose) { - print fmt_join(" ", 72, " ", (map { $patch{$_}->[2] } @$merges)); + my @pieces = map { $patch{$_}->[2] . "," } @$merges; + $pieces[-1] =~ s/,$/./; + print fmt_join(" ", 72, " ", @pieces); } } - $sep = "\n"; + $sep = "\n" if (!$quiet); } -if (1 < @dates) { - print "${sep}Between $dates[0]..$dates[-1]\n"; +sub range_summary { + my ($range, $bottom, $date, $total_n, $total_m, $total_p, $total_t) = @_; + (my $last_date, undef) = prev_date($date); - my $people = plural(scalar @{[keys %total_names]}, "person", "people"); - my $count = plural($total_patch, "patch", "patches"); - print "Queued $count from $people.\n"; + print "$sep$range $bottom..$last_date\n"; + if ($total_t) { + my $count = plural($total_t, "release", "releases"); + print " Tagged $count.\n"; + } + if ($total_p) { + my $people = plural(scalar @{[keys %{$total_n}]}, "person", "people"); + my$count = plural($total_p, "patch", "patches"); + print " Queued $count from $people.\n"; + } for my $branch_data (@integrate) { my ($branch, $purpose) = @{$branch_data}; - next unless $total_merges{$branch}; - my $count = plural($total_merges{$branch}, "merge", "merges"); - print "Made $count to '$branch' branch$purpose.\n"; + next unless $total_m->{$branch}; + my $count = plural($total_m->{$branch}, "merge", "merges"); + print " Made $count to '$branch' branch$purpose.\n"; + } + $sep = "\n"; +} + +sub weekly_summary { + my ($bottom, $total_names, $total_merges, + $total_patches, $total_tags) = @_; + my $date = $bottom; + my $shown = 0; + + my ($total_p, $total_t, %total_n, %total_m) = (0, 0); + for (my $i = 0; $i < 7; $i++) { + day_summary($date, \%total_n, \%total_m, + \$total_p, \$total_t); + ($date, undef) = next_date($date); + } + for my $name (keys %total_n) { + $total_names->{$name}++; + $shown++; } + for my $merge (keys %total_m) { + $total_merges->{$merge}++; + $shown++; + } + $$total_patches += $total_p; + $$total_tags += $total_t; + if ($shown) { + range_summary("Week of", $bottom, $date, + \%total_n, \%total_m, $total_p, $total_t); + } + return $date; +} + +my %total_names; +my %total_merges; +my $total_patches = 0; +my $total_tags = 0; + +my $date; +for ($date = $bottom_date; $date le $reporting_date; ) { + $date = weekly_summary($date, \%total_names, \%total_merges, + \$total_patches, \$total_tags); +} + +if ($weeks) { + range_summary("Between", $bottom_date, $date, + \%total_names, \%total_merges, + $total_patches, $total_tags); }