Skip to content

Commit

Permalink
Merge branch 'develop'
Browse files Browse the repository at this point in the history
  • Loading branch information
Sebastian Hönel committed Feb 14, 2019
2 parents 193f531 + 79a22ce commit 81b4678
Show file tree
Hide file tree
Showing 18 changed files with 357 additions and 75 deletions.
2 changes: 1 addition & 1 deletion GitDensity/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ public static BaseLogger<T> CreateLogger<T>()
/// <param name="args"></param>
static void Main(string[] args)
{
Thread.CurrentThread.CurrentCulture = new CultureInfo("en-us");
Thread.CurrentThread.CurrentUICulture = new CultureInfo("en-us");
var options = new CommandLineOptions();

Expand Down Expand Up @@ -363,7 +364,6 @@ protected internal static void RecomputeGitHours(CommandLineOptions options)
var developers = developersRaw.ToDictionary(
kv => kv.Key, kv =>
{
var foo = repoEntity.Developers.Count(dev => dev.Equals(kv.Value));
return repoEntity.Developers.Where(dev => dev.Equals(kv.Value)).Single();
});
Expand Down
2 changes: 1 addition & 1 deletion GitHours/Hours/GitHours.cs
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ public GitHoursAnalysisResult Analyze(RepositoryEntity repositoryEntity = null,
{
var stats = new GitHoursAuthorStat(commitGroup.Key)
{
HoursTotal = this.Estimate(commitGroup.Select(commit => commit.Committer.When.DateTime).ToArray()),
HoursTotal = this.Estimate(commitGroup.Select(commit => commit.Committer.When.UtcDateTime).ToArray()),
NumCommits = (UInt32)commitGroup.Count()
};
Expand Down
2 changes: 1 addition & 1 deletion GitHours/Hours/GitHoursAuthorSpan.cs
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ public static IEnumerable<GitHoursAuthorSpan> GetHoursSpans(IEnumerable<Commit>
for (var take = 2; take <= commitsSorted.Count; take++)
{
hoursUntilCommit[take] = Tuple.Create(
commitsSorted[take - 1], estimator(commitsSorted.Take(take).Select(commit => commit.Committer.When.DateTime).ToArray()));
commitsSorted[take - 1], estimator(commitsSorted.Take(take).Select(commit => commit.Committer.When.UtcDateTime).ToArray()));
}

foreach (var kv in hoursUntilCommit)
Expand Down
2 changes: 1 addition & 1 deletion GitHours/Hours/GitHoursAuthorSpanDetailed.cs
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ public static IEnumerable<GitHoursAuthorSpanDetailed> GetHoursSpans(IEnumerable<
commitsSorted[0], null, commitsSorted[0], 0d, true, true);

estimator(
commitsSorted.Select(commit => commit.Committer.When.DateTime).ToArray(),
commitsSorted.Select(commit => commit.Committer.When.UtcDateTime).ToArray(),
out EstimateHelper[] estimates);

for (int i = 0; i < commitsSorted.Count - 1; i++)
Expand Down
5 changes: 5 additions & 0 deletions GitHours/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,10 @@
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
using System;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Threading;
using Util;
using Util.Data.Entities;
using Util.Extensions;
Expand Down Expand Up @@ -64,6 +66,9 @@ public static BaseLogger<T> CreateLogger<T>()
/// <param name="args"></param>
static void Main(string[] args)
{
Thread.CurrentThread.CurrentCulture = new CultureInfo("en-us");
Thread.CurrentThread.CurrentUICulture = new CultureInfo("en-us");

var options = new CommandLineOptions();

if (Parser.Default.ParseArguments(args, options))
Expand Down
2 changes: 1 addition & 1 deletion GitHoursTests/EstimationTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ public void TestEstimatesWithHelper()
{
var analysis = new GitHours.Hours.GitHours(span);

var dates = span.Repository.Commits.Select(c => c.Committer.When.DateTime).ToArray();
var dates = span.Repository.Commits.Select(c => c.Committer.When.UtcDateTime).ToArray();
var original = analysis.Estimate(dates);
var withHelper = analysis.Estimate(dates, out EstimateHelper[] estimates);

Expand Down
1 change: 1 addition & 0 deletions GitMetrics/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ public static BaseLogger<T> CreateLogger<T>()
/// <param name="args"></param>
static void Main(string[] args)
{
Thread.CurrentThread.CurrentCulture = new CultureInfo("en-us");
Thread.CurrentThread.CurrentUICulture = new CultureInfo("en-us");

var options = new CommandLineOptions();
Expand Down
76 changes: 76 additions & 0 deletions GitTools/Analysis/BaseAnalyzer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,16 @@
/// ---------------------------------------------------------------------------------
///
using LibGit2Sharp;
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using Util;
using Util.Data.Entities;
using Util.Extensions;
using static Util.Extensions.RepositoryExtensions;
using Signature = LibGit2Sharp.Signature;

namespace GitTools.Analysis
{
Expand All @@ -29,6 +36,8 @@ public abstract class BaseAnalyzer<T> :
IAnalyzer<T>
where T : IAnalyzedCommit
{
protected abstract ILogger<IAnalyzer<T>> Logger { get; }

/// <summary>
/// A path or URL to the <see cref="Repository"/> that is being
/// analyzed.
Expand All @@ -41,6 +50,12 @@ public abstract class BaseAnalyzer<T> :
/// </summary>
public GitCommitSpan GitCommitSpan { get; protected set; }

private IReadOnlyDictionary<Signature, DeveloperWithAlternativeNamesAndEmails> authorSignatures;

private IReadOnlyDictionary<Signature, DeveloperWithAlternativeNamesAndEmails> committerSignatures;

private IReadOnlyDictionary<DeveloperEntity, String> developerNominals;

/// <summary>
/// Base constructor that initalizes the repo-path and commits-span.
/// </summary>
Expand All @@ -50,8 +65,69 @@ public BaseAnalyzer(String repoPathOrUrl, GitCommitSpan span)
{
this.RepoPathOrUrl = repoPathOrUrl;
this.GitCommitSpan = span;
this.InitializeNominalSignatures();
}

#region Nominal Signatures
/// <summary>
/// Will map each <see cref="Signature"/> uniquely to a <see cref="DeveloperEntity"/>.
/// Then, for each entity, a unique ID (within the current repository) is assigned. The
/// IDs look like Excel columns.
/// </summary>
private void InitializeNominalSignatures()
{
this.Logger.LogInformation("Initializing developer identities for repository..");

this.developerNominals = new Dictionary<DeveloperEntity, String>();

this.authorSignatures = new ReadOnlyDictionary<Signature, DeveloperWithAlternativeNamesAndEmails>(
this.GitCommitSpan.GroupByDeveloperAsSignatures(
repository: null, useAuthorAndNotCommitter: true));
this.committerSignatures = new ReadOnlyDictionary<Signature, DeveloperWithAlternativeNamesAndEmails>(
this.GitCommitSpan.GroupByDeveloperAsSignatures(
repository: null, useAuthorAndNotCommitter: false));

Func<Int32, String> excelColumnFromNumber = num =>
{
var colLetters = new LinkedList<Char>();
while (num > 0)
{
var currentLetterNum = (num - 1) % 26;
var currentLetter = (char)(currentLetterNum + 65);
colLetters.AddLast(currentLetter);
num = (num - (currentLetterNum + 1)) / 26;
}
return new string(colLetters.Reverse().ToArray()).ToUpper();
};

var set = new HashSet<DeveloperEntity>(this.authorSignatures.Select(kv => kv.Value)
.Concat(this.committerSignatures.Select(kv => kv.Value)));

this.developerNominals = new ReadOnlyDictionary<DeveloperEntity, String>(
set.Select((dev, idx) => new {
Dev = dev,
Id = idx + 1
}).ToDictionary(kv => kv.Dev, kv => excelColumnFromNumber(kv.Id))
);

this.Logger.LogInformation($"Found {String.Format("{0:n0}", this.authorSignatures.Count + this.committerSignatures.Count)} signatures and mapped them to {String.Format("{0:n0}", this.developerNominals.Count)} distinct developer identities.");
}

/// <summary>
/// Returns a unique nominal ID for a <see cref="Commit.Author"/> and
/// <see cref="Commit.Committer"/> (<see cref="InitializeNominalSignatures"/>).
/// </summary>
/// <param name="commit"></param>
/// <param name="authorNominal"></param>
/// <param name="committerNominal"></param>
protected void AuthorAndCommitterNominalForCommit(Commit commit, out string authorNominal, out string committerNominal)
{
// TODO: Refactor this to use the SHA256 and remove obsolete code in InitializeNominalSignatures
authorNominal = this.developerNominals[this.authorSignatures[commit.Author]];
committerNominal = this.developerNominals[this.committerSignatures[commit.Committer]];
}
#endregion

#region ISupportsExecutionPolicy
/// <summary>
/// An analyzer may do heavy work and its execution-policy
Expand Down
21 changes: 16 additions & 5 deletions GitTools/Analysis/ExtendedAnalyzer/ExtendedAnalyzer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,11 @@ public class ExtendedAnalyzer : BaseAnalyzer<ExtendedCommitDetails>
private readonly BaseLogger<ExtendedAnalyzer> logger =
Program.CreateLogger<ExtendedAnalyzer>();

/// <summary>
/// Concrete logger of type <see cref="BaseLogger{ExtendedAnalyzer}"/>.
/// </summary>
protected override ILogger<IAnalyzer<ExtendedCommitDetails>> Logger => this.logger;

/// <summary>
/// Can be set to true in the constructor.
/// </summary>
Expand All @@ -65,15 +70,15 @@ public ExtendedAnalyzer(String repoPathOrUrl, GitCommitSpan span, Boolean skipSi
/// <returns></returns>
public override IEnumerable<ExtendedCommitDetails> AnalyzeCommits()
{
this.logger.LogInformation("Starting analysis of commits..");
this.logger.LogWarning("Parallel Analysis is: {0}ABLED!",
this.Logger.LogInformation("Starting analysis of commits..");
this.Logger.LogWarning("Parallel Analysis is: {0}ABLED!",
this.ExecutionPolicy == ExecutionPolicy.Parallel ? "EN" : "DIS");

var done = 0;
var total = this.GitCommitSpan.Count();
var repo = this.GitCommitSpan.Repository;
var bag = new ConcurrentBag<ExtendedCommitDetails>();
var reporter = new SimpleAnalyzer.SimpleProgressReporter<ExtendedAnalyzer>(this.logger);
var reporter = new SimpleAnalyzer.SimpleProgressReporter<ExtendedAnalyzer>(this.Logger);

var pairs = this.GitCommitSpan.CommitPairs(
skipInitialCommit: false,
Expand All @@ -90,12 +95,18 @@ public override IEnumerable<ExtendedCommitDetails> AnalyzeCommits()
pair.ExecutionPolicy = ExecutionPolicy.Linear; // As we're probably running parallel in outer scope already
var parents = pair.Child.Parents.ToList();
String authorLabel, committerLabel;
this.AuthorAndCommitterNominalForCommit(
pair.Child, out authorLabel, out committerLabel);
var ecd = new ExtendedCommitDetails(this.RepoPathOrUrl, repo, pair.Child)
{
MinutesSincePreviousCommit = parents.Count == 0 ? -.1 :
Math.Round(
(pair.Child.Committer.When.UtcDateTime -
(parents.OrderByDescending(p => p.Committer.When.UtcDateTime).First().Committer.When.UtcDateTime)).TotalMinutes, 4)
(parents.OrderByDescending(p => p.Committer.When.UtcDateTime).First().Committer.When.UtcDateTime)).TotalMinutes, 4),
AuthorNominalLabel = authorLabel,
CommitterNominalLabel = committerLabel,
};
// We are interested in how many files were affected by this commit
Expand Down Expand Up @@ -164,7 +175,7 @@ public override IEnumerable<ExtendedCommitDetails> AnalyzeCommits()
reporter.ReportProgress(Interlocked.Increment(ref done), total);
});

this.logger.LogInformation("Finished analysis of commits.");
this.Logger.LogInformation("Finished analysis of commits.");

return bag.OrderBy(ecd => ecd.AuthorTime);
}
Expand Down
27 changes: 14 additions & 13 deletions GitTools/Analysis/ExtendedAnalyzer/ExtendedCommitDetails.cs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,8 @@ public class ExtendedCommitDetails : SimpleCommitDetails
/// <param name="repoPathOrUrl"></param>
/// <param name="repository"></param>
/// <param name="commit"></param>
public ExtendedCommitDetails(String repoPathOrUrl, Repository repository, Commit commit) : base(repoPathOrUrl, repository, commit)
public ExtendedCommitDetails(String repoPathOrUrl, Repository repository, Commit commit)
: base(repoPathOrUrl, repository, commit)
{
}

Expand All @@ -53,41 +54,41 @@ public override string Message
[CsvColumn(FieldIndex = 7)]
public double MinutesSincePreviousCommit { get; protected internal set; } = -.1;

[CsvColumn(FieldIndex = 15)]
[CsvColumn(FieldIndex = 17)]
public UInt32 NumberOfFilesAdded { get; protected internal set; } = 0u;

[CsvColumn(FieldIndex = 16)]
[CsvColumn(FieldIndex = 18)]
public UInt32 NumberOfLinesAddedByAddedFilesNoComments { get; protected internal set; } = 0u;

[CsvColumn(FieldIndex = 17)]
[CsvColumn(FieldIndex = 19)]
public UInt32 NumberOfLinesAddedByAddedFilesGross { get; protected internal set; } = 0u;

[CsvColumn(FieldIndex = 18)]
[CsvColumn(FieldIndex = 20)]
public UInt32 NumberOfFilesDeleted { get; protected internal set; } = 0u;

[CsvColumn(FieldIndex = 19)]
[CsvColumn(FieldIndex = 21)]
public UInt32 NumberOfLinesDeletedByDeletedFilesNoComments { get; protected internal set; } = 0u;

[CsvColumn(FieldIndex = 20)]
[CsvColumn(FieldIndex = 22)]
public UInt32 NumberOfLinesDeletedByDeletedFilesGross { get; protected internal set; } = 0u;


[CsvColumn(FieldIndex = 21)]
[CsvColumn(FieldIndex = 23)]
public UInt32 NumberOfFilesModified { get; protected internal set; } = 0u;

[CsvColumn(FieldIndex = 22)]
[CsvColumn(FieldIndex = 24)]
public UInt32 NumberOfFilesRenamed { get; protected internal set; } = 0u;

[CsvColumn(FieldIndex = 23)]
[CsvColumn(FieldIndex = 25)]
public UInt32 NumberOfLinesAddedByModifiedFiles { get; protected internal set; } = 0u;

[CsvColumn(FieldIndex = 24)]
[CsvColumn(FieldIndex = 26)]
public UInt32 NumberOfLinesDeletedByModifiedFiles { get; protected internal set; } = 0u;

[CsvColumn(FieldIndex = 25)]
[CsvColumn(FieldIndex = 27)]
public UInt32 NumberOfLinesAddedByRenamedFiles { get; protected internal set; } = 0u;

[CsvColumn(FieldIndex = 26)]
[CsvColumn(FieldIndex = 28)]
public UInt32 NumberOfLinesDeletedByRenamedFiles { get; protected internal set; } = 0u;
#endregion
}
Expand Down
27 changes: 20 additions & 7 deletions GitTools/Analysis/SimpleAnalyzer/SimpleAnalyzer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,11 @@ public class SimpleAnalyzer : BaseAnalyzer<SimpleCommitDetails>
private readonly BaseLogger<SimpleAnalyzer> logger =
Program.CreateLogger<SimpleAnalyzer>();

/// <summary>
/// Returns a concrete <see cref="BaseLogger{SimpleAnalyzer}"/> for this analyzer.
/// </summary>
protected override ILogger<IAnalyzer<SimpleCommitDetails>> Logger => this.logger;

/// <summary>
/// This is a forwarding constructor that does not do any other
/// initialization than <see cref="BaseAnalyzer{T}.BaseAnalyzer(string, GitCommitSpan)"/>.
Expand All @@ -52,15 +57,15 @@ public SimpleAnalyzer(String repoPathOrUrl, GitCommitSpan span)
/// <returns><see cref="IEnumerable{SimpleCommitDetails}"/></returns>
public override IEnumerable<SimpleCommitDetails> AnalyzeCommits()
{
this.logger.LogInformation("Starting analysis of commits..");
this.logger.LogWarning("Parallel Analysis is: {0}ABLED!",
this.Logger.LogInformation("Starting analysis of commits..");
this.Logger.LogWarning("Parallel Analysis is: {0}ABLED!",
this.ExecutionPolicy == ExecutionPolicy.Parallel ? "EN" : "DIS");

var done = 0;
var total = this.GitCommitSpan.Count();
var repo = this.GitCommitSpan.Repository;
var bag = new ConcurrentBag<SimpleCommitDetails>();
var reporter = new SimpleProgressReporter<SimpleAnalyzer>(this.logger);
var reporter = new SimpleProgressReporter<SimpleAnalyzer>(this.Logger);

var po = new ParallelOptions();
if (this.ExecutionPolicy == ExecutionPolicy.Linear)
Expand All @@ -70,11 +75,19 @@ public override IEnumerable<SimpleCommitDetails> AnalyzeCommits()

Parallel.ForEach(this.GitCommitSpan, po, commit =>
{
bag.Add(new SimpleCommitDetails(this.RepoPathOrUrl, repo, commit));
String authorLabel, committerLabel;
this.AuthorAndCommitterNominalForCommit(
commit, out authorLabel, out committerLabel);
bag.Add(new SimpleCommitDetails(this.RepoPathOrUrl, repo, commit)
{
AuthorNominalLabel = authorLabel,
CommitterNominalLabel = committerLabel
});
reporter.ReportProgress(Interlocked.Increment(ref done), total);
});

this.logger.LogInformation("Finished analysis of commits.");
this.Logger.LogInformation("Finished analysis of commits.");

return bag.OrderBy(scd => scd.AuthorTime);
}
Expand All @@ -85,13 +98,13 @@ internal class SimpleProgressReporter<T> where T: IAnalyzer<IAnalyzedCommit>
public static readonly ISet<Int32> DefaultSteps
= new HashSet<Int32>(Enumerable.Range(1, 20).Select(i => i * 5));

protected readonly BaseLogger<T> logger;
protected readonly ILogger<IAnalyzer<SimpleCommitDetails>> logger;

protected readonly ISet<Int32> steps;

protected readonly SemaphoreSlim semaphoreSlim;

public SimpleProgressReporter(BaseLogger<T> logger, ISet<Int32> stepsToProgress = null)
public SimpleProgressReporter(ILogger<IAnalyzer<SimpleCommitDetails>> logger, ISet<Int32> stepsToProgress = null)
{
this.logger = logger;
this.steps = stepsToProgress ?? DefaultSteps;
Expand Down
Loading

0 comments on commit 81b4678

Please sign in to comment.