private void GetChangesByDateAndTotalLines() { // line statistics // outputs: // N files changed, N insertions (+), N deletions(-) // <stamp> <author> ChangesByDate = new DictionaryWithDefault <DateTime, Change>(); var lines = GitStats.GetPipeOutput(new[] { "git log --shortstat --pretty=format:\"%at %an\"" }).Split("\n") .ToList(); lines.Reverse(); var files = 0; var inserted = 0; var deleted = 0; var totalLines = 0; foreach (var line in lines) { if (line.Length == 0) { files = 0; inserted = 0; deleted = 0; continue; } if (line.IndexOf(" changed,", StringComparison.CurrentCultureIgnoreCase) == -1) { var pos = line.IndexOf(" ", StringComparison.CurrentCultureIgnoreCase); if (pos != -1) { try { var datetime = DateTimeOffset.FromUnixTimeSeconds(Convert.ToInt32(line.Substring(0, pos))).DateTime; var author = line.Substring(pos + 1); ChangesByDate[datetime] = new Change { Files = files, Inserted = inserted, Deleted = deleted, TotalLines = totalLines }; if (!Authors.ContainsKey(author)) { Authors[author] = new Author(); } Authors[author].LinesAdded += inserted; Authors[author].LinesRemoved += deleted; } catch (Exception) { Console.WriteLine($"Warning: unexpected line \"{line}\""); } } else { Console.WriteLine($"Warning: unexpected line \"{line}\""); } } else { files = GetIntFromStartOfRegex(line, "\\d+ file"); inserted = GetIntFromStartOfRegex(line, "\\d+ insertion"); deleted = GetIntFromStartOfRegex(line, "\\d+ delet"); totalLines += inserted; totalLines -= deleted; TotalLinesAdded += inserted; TotalLinesRemoved += deleted; } } TotalLines = totalLines; }
// Collect revision statistics // Outputs "<stamp> <date> <time> <timezone> <author> '<' <mail> '>'" private List <string> GetActivityDataAndAuthors() { var lines = GitStats.GetPipeOutput(new[] { "git rev-list --remotes --pretty=format:\"%at %ai %an <%aE>\" HEAD", "grep -v ^commit" }, PipingLevel.Full, true).Split("\n").ToList(); foreach (var line in lines) { var parts = Regex.Split(line, "([01-9-:+]+ )").Where(x => !string.IsNullOrEmpty(x)).Select(s => s.Trim()) .ToArray(); DateTime stamp; try { stamp = DateTimeOffset.FromUnixTimeSeconds(Convert.ToInt32(parts[0])).DateTime; } catch (FormatException) { stamp = DateTime.MinValue; } var timezone = parts[3]; var tup1 = parts[4].Split("<"); var author = tup1[0]; var mail = tup1[1]; author = author.TrimEnd(); mail = mail.TrimEnd('>'); var domain = "?"; if (mail.IndexOf("@", StringComparison.CurrentCultureIgnoreCase) != -1) { domain = mail.Split("@")[1]; } var date = stamp; // First and last commit stamp if (LastCommitStamp == DateTime.MinValue) { LastCommitStamp = stamp; } FirstCommitStamp = stamp; // activity // hour var hour = date.Hour; ActivityByHourOfDay[hour] = ActivityByHourOfDay[hour] + 1; // most active hour? if (ActivityByHourOfDay[hour] > ActivityByHourOfDayBusiest) { ActivityByHourOfDayBusiest = ActivityByHourOfDay[hour]; } // day of week var day = (int)date.DayOfWeek - 1; ActivityByDayOfWeek[day] = ActivityByDayOfWeek[day] + 1; // domain stats if (!Domains.ContainsKey(domain)) { Domains[domain] = new Domain(); } // commits Domains[domain].Commits = Domains[domain].Commits + 1; // hour of week if (!ActivityByHourOfWeek.ContainsKey(day)) { ActivityByHourOfWeek[day] = new DictionaryWithDefault <int, int>(); } ActivityByHourOfWeek[day][hour] = ActivityByHourOfWeek[day][hour] + 1; // most active hour? if (ActivityByHourOfWeek[day][hour] > ActivityByHourOfWeekBusiest) { ActivityByHourOfWeekBusiest = ActivityByHourOfWeek[day][hour]; } // month of year var month = date.Month; ActivityByMonthOfYear[month] = ActivityByMonthOfYear[month] + 1; // yearly/weekly activity var yyw = $"{date.Year}-{_calendar.GetWeekOfYear(date, _cultureInfo.DateTimeFormat.CalendarWeekRule, _cultureInfo.DateTimeFormat.FirstDayOfWeek)}"; ActivityByYearWeek[yyw] = ActivityByYearWeek[yyw] + 1; if (ActivityByYearWeekPeak < ActivityByYearWeek[yyw]) { ActivityByYearWeekPeak = ActivityByYearWeek[yyw]; } // author stats if (!Authors.ContainsKey(author)) { Authors[author] = new Author(); } // commits if (Authors[author].LastCommitStamp == DateTime.MinValue) { Authors[author].LastCommitStamp = stamp; } Authors[author].FirstCommitStamp = stamp; Authors[author].Commits = Authors[author].Commits + 1; // author of the month/year var yymm = $"{date.Year}-{date.Month:D2}"; if (AuthorOfMonth.ContainsKey(yymm)) { AuthorOfMonth[yymm][author] = AuthorOfMonth[yymm][author] + 1; } else { AuthorOfMonth[yymm] = new DictionaryWithDefault <string, int> { [author] = 1 } }; CommitsByMonth[yymm] = CommitsByMonth[yymm] + 1; var yy = date.Year; if (AuthorOfYear.ContainsKey(yy)) { AuthorOfYear[yy][author] = AuthorOfYear[yy][author] + 1; } else { AuthorOfYear[yy] = new DictionaryWithDefault <string, int> { [author] = 1 } }; CommitsByYear[yy] = CommitsByYear[yy] + 1; // authors: active days var yymmdd = date; if (Authors[author].LastActiveDay == DateTime.MinValue) { Authors[author].LastActiveDay = yymmdd; Authors[author].ActiveDays = 1; } else if (yymmdd != Authors[author].LastActiveDay) { Authors[author].LastActiveDay = yymmdd; Authors[author].ActiveDays += 1; } // project: active days if (yymmdd != LastActiveDay) { LastActiveDay = yymmdd; ActiveDays.Add(yymmdd); } // timezone CommitsByTimezone[timezone] = CommitsByTimezone[timezone] + 1; } return(lines); }