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 11, 2020
2 parents 5e312ee + 0693a29 commit 43269b3
Show file tree
Hide file tree
Showing 14 changed files with 299 additions and 316 deletions.
2 changes: 2 additions & 0 deletions GitDensity/Density/GitDensity.cs
Original file line number Diff line number Diff line change
Expand Up @@ -531,7 +531,9 @@ public GitDensityAnalysisResult Analyze()
// We can go for parallelism here, but obtaining metrics is very expensive.
ExecutionPolicy = ExecutionPolicy.Parallel
};
metricsRepoAnalyzer.SelectAnalyzerImplementation();

logger.LogInformation($"Analyzing metrics for all commits.");
metricsRepoAnalyzer.Analyze();
foreach (var result in metricsRepoAnalyzer.Results)
{
Expand Down
195 changes: 14 additions & 181 deletions GitDensity/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,17 @@ static void Main(string[] args)

try
{
Program.Configuration = Configuration.ReadDefault();
if (!StringExtensions.IsNullOrEmptyOrWhiteSpace(options.ConfigFile))
{
logger.LogWarning($"Using a separate config-file located at {options.ConfigFile}");
Program.Configuration = Configuration.ReadFromFile(
Path.GetFullPath(options.ConfigFile));
}
else
{
Program.Configuration = Configuration.ReadDefault();
}

logger.LogDebug("Read the following configuration:\n{0}",
JsonConvert.SerializeObject(Program.Configuration, Formatting.Indented));
}
Expand Down Expand Up @@ -157,20 +167,6 @@ static void Main(string[] args)
Environment.Exit((int)ExitCodes.RepoInvalid);
}
}

if (options.CmdRecomputeGitHours)
{
try
{
Program.RecomputeGitHours(options);
Environment.Exit((int)ExitCodes.OK);
}
catch (Exception ex)
{
logger.LogError(ex, ex.Message);
Environment.Exit((int)ExitCodes.CmdError);
}
}
#endregion


Expand Down Expand Up @@ -291,169 +287,6 @@ static void Main(string[] args)

Environment.Exit((int)ExitCodes.OK);
}


/// <summary>
/// This methods purpose was/is to recompute all configured git-hours for already analyzed
/// repositories. Currently, this method recomputes all repositories' git-hours. This method
/// should not be used anymore, unless there are manual changes to the database and new/other
/// types of configured git-hours (hours-types) and one needs to (re-)compute the hours for
/// the already analyzed repositories.
/// </summary>
/// <param name="options"></param>
[Obsolete]
protected internal static void RecomputeGitHours(CommandLineOptions options)
{
var parallelOptions = new ParallelOptions();
if (options.ExecutionPolicy == ExecutionPolicy.Linear)
{
parallelOptions.MaxDegreeOfParallelism = 1;
}

var toRepoName = new Func<RepositoryEntity, String>(re => $"{re.Project.Name}_{re.Project.Owner}");
var checkoutPath = $"R:\\{nameof(GitDensity)}_repos";
var hoursTypesEntities = Configuration.HoursTypes.ToDictionary(
htc => htc, htc =>
{
return HoursTypeEntity.ForSettings(htc.MaxDiff, htc.FirstCommitAdd);
});

List<UInt32> repoEntityIds;
using (var session = DataFactory.Instance.OpenSession())
{
repoEntityIds = session.QueryOver<RepositoryEntity>()
.Where(re => re.Project != null).List().Select(re => re.ID).ToList();
}

Parallel.ForEach(repoEntityIds, parallelOptions, repoEntityId =>
{
using (var session = DataFactory.Instance.OpenSession())
{
var start = DateTime.Now;
var repoEntity = session.QueryOver<RepositoryEntity>()
.Where(re => re.ID == repoEntityId).List()[0];
var useRepoName = toRepoName(repoEntity);
var checkoutDir = Path.Combine(checkoutPath, useRepoName);
try
{
#region conditional clone
if (Directory.Exists(checkoutDir))
{
logger.LogWarning($"Directory exists, skipping: {checkoutDir}");
}
else
{
logger.LogInformation("Cloning repository from {0}", repoEntity.Project.CloneUrl);
LibGit2Sharp.Repository.Clone(repoEntity.Project.CloneUrl, checkoutDir);
}
var repo = checkoutDir.OpenRepository(pullIfAlreadyExists: true,
useRepoName: useRepoName, tempDirectory: checkoutPath);
#endregion
#region compute git-hours
var gitCommitSpan = new GitCommitSpan(repo,
sinceDateTimeOrCommitSha: repoEntity.SinceCommitSha1,
untilDatetimeOrCommitSha: repoEntity.UntilCommitSha1);
var pairs = gitCommitSpan.CommitPairs().ToList();
var commits = repoEntity.Commits.ToDictionary(c => c.HashSHA1, c => c);
var developersRaw = gitCommitSpan.FilteredCommits
.GroupByDeveloperAsSignatures(repoEntity);
var developers = developersRaw.ToDictionary(
kv => kv.Key, kv =>
{
return repoEntity.Developers.Where(dev => dev.Equals(kv.Value)).Single();
});
foreach (var pair in pairs)
{
var gitHoursAnalysesPerDeveloperAndHoursType =
new ConcurrentDictionary<HoursTypeConfiguration, Dictionary<DeveloperEntity, IList<GitHoursAuthorSpan>>>();
// Run all Analysis for each Hours-Type:
Parallel.ForEach(Program.Configuration.HoursTypes, parallelOptions, hoursType =>
{
var addSuccess = gitHoursAnalysesPerDeveloperAndHoursType.TryAdd(hoursType,
new GitHours.Hours.GitHours(
gitCommitSpan, hoursType.MaxDiff, hoursType.FirstCommitAdd)
.Analyze(repoEntity, HoursSpansDetailLevel.Detailed)
.AuthorStats.ToDictionary(
@as => @as.Developer as DeveloperEntity, @as => @as.HourSpans));
if (!addSuccess)
{
throw new InvalidOperationException(
$"Cannot add Hours-Type {hoursType.ToString()}.");
}
});
// Check if Hours-type is already computed:
var numComputed = session.QueryOver<HoursEntity>()
.Where(he => he.Developer == developers[pair.Child.Author] && he.CommitUntil == commits[pair.Child.Sha]).RowCount();
if (numComputed == gitHoursAnalysesPerDeveloperAndHoursType.Keys.Count)
{
return; // nothing to do
}
foreach (var hoursType in gitHoursAnalysesPerDeveloperAndHoursType.Keys)
{
// We need this for every HoursEntity that we use; it is already saved
var hoursTypeEntity = hoursTypesEntities[hoursType];
var gitHoursAnalysesPerDeveloper =
gitHoursAnalysesPerDeveloperAndHoursType[hoursType];
var developerSpans = gitHoursAnalysesPerDeveloper[developers[pair.Child.Author]]
// OK because we analyzed with HoursSpansDetailLevel.Detailed
.Cast<GitHoursAuthorSpanDetailed>().ToList();
var hoursSpan = developerSpans.Where(hs => hs.Until == pair.Child).Single();
var hoursEntity = new HoursEntity
{
InitialCommit = commits[hoursSpan.InitialCommit.Sha],
CommitSince = hoursSpan.Since == null ? null : commits[hoursSpan.Since.Sha],
CommitUntil = commits[hoursSpan.Until.Sha],
Developer = developers[pair.Child.Author],
Hours = hoursSpan.Hours,
HoursTotal = developerSpans.Take(1 + developerSpans.IndexOf(hoursSpan))
.Select(hs => hs.Hours).Sum(),
HoursType = hoursTypeEntity,
IsInitial = hoursSpan.IsInitialSpan,
IsSessionInitial = hoursSpan.IsSessionInitialSpan
};
developers[pair.Child.Author].AddHour(hoursEntity);
}
using (var trans = session.BeginTransaction())
{
var hoursTemp = developers[pair.Child.Author].Hours.ToList();
foreach (var hour in hoursTemp)
{
session.Save(hour);
}
trans.Commit();
}
}
#endregion
}
catch (Exception)
{
File.AppendAllText(@"c:\users\admin\desktop\failed.txt", $"Repo failed: {repoEntity.ID} (Project: {repoEntity.Project.InternalId})\n");
logger.LogError($"Repo failed: {repoEntity.ID} (Project: {repoEntity.Project.InternalId})");
}
logger.LogInformation("Finished repo in {0}: {1}",
(DateTime.Now - start).ToString(), checkoutDir);
}
});
}
}


Expand All @@ -466,6 +299,9 @@ internal class CommandLineOptions
[Option('r', "repo-path", Required = true, HelpText = "Absolute path or HTTP(S) URL to a git-repository. If a URL is provided, the repository will be cloned to a temporary folder first, using its defined default branch. Also allows passing in an Internal-ID of a project from the database.")]
public String RepoPath { get; set; }

[Option('c', "config-file", Required = false, HelpText = "Optional. Absolute path to a valid configuration.json. If not given, uses the configuration.json that is to be found in the same folder as " + nameof(GitDensity) + ".exe.")]
public String ConfigFile { get; set; }

/// <summary>
/// To obtains the actual <see cref="ICollection{ProgrammingLanguage}"/>s, use the
/// property <see cref="ProgrammingLanguages"/>.
Expand Down Expand Up @@ -515,9 +351,6 @@ internal class CommandLineOptions
#region Command-Options
[Option("cmd-delete-repo-id", Required = false, HelpText = "Command. Removes analysis results for an entire RepositoryEntity and all of its associated entities, then terminates the program.")]
public UInt32 DeleteRepoId { get; set; }

[Option("cmd-recompute-githours", Required = false, DefaultValue = false, HelpText = "Command. Run the method " + nameof(Program.RecomputeGitHours) + "(). If called, the application will only run this and ignore/do nothing else. This method was intended to recompute git-hours of already analyzed repos and should not be used anymore.")]
public Boolean CmdRecomputeGitHours { get; set; }
#endregion

[Option('h', "help", Required = false, DefaultValue = false, HelpText = "Print this help-text and exit.")]
Expand Down
21 changes: 21 additions & 0 deletions GitMetrics/GitMetrics.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -39,12 +39,21 @@
<Prefer32Bit>false</Prefer32Bit>
</PropertyGroup>
<ItemGroup>
<Reference Include="Antlr3.Runtime, Version=3.5.0.2, Culture=neutral, PublicKeyToken=eb42632606e9261f, processorArchitecture=MSIL">
<HintPath>..\packages\Antlr3.Runtime.3.5.1\lib\net40-client\Antlr3.Runtime.dll</HintPath>
</Reference>
<Reference Include="CommandLine, Version=1.9.71.2, Culture=neutral, PublicKeyToken=de6f01bd326f8c32, processorArchitecture=MSIL">
<HintPath>..\packages\CommandLineParser.1.9.71\lib\net45\CommandLine.dll</HintPath>
</Reference>
<Reference Include="Iesi.Collections, Version=4.0.0.4000, Culture=neutral, PublicKeyToken=aa95f207798dfdb4, processorArchitecture=MSIL">
<HintPath>..\packages\Iesi.Collections.4.0.4\lib\net461\Iesi.Collections.dll</HintPath>
</Reference>
<Reference Include="LibGit2Sharp, Version=0.26.0.0, Culture=neutral, PublicKeyToken=7cbde695407f0333, processorArchitecture=MSIL">
<HintPath>..\packages\LibGit2Sharp.0.26.0\lib\net46\LibGit2Sharp.dll</HintPath>
</Reference>
<Reference Include="LINQtoCSV, Version=1.5.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\LINQtoCSV.1.5.0.0\lib\net35\LINQtoCSV.dll</HintPath>
</Reference>
<Reference Include="Microsoft.Bcl.AsyncInterfaces, Version=1.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
<HintPath>..\packages\Microsoft.Bcl.AsyncInterfaces.1.1.0\lib\net461\Microsoft.Bcl.AsyncInterfaces.dll</HintPath>
</Reference>
Expand Down Expand Up @@ -78,6 +87,15 @@
<Reference Include="Newtonsoft.Json, Version=12.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
<HintPath>..\packages\Newtonsoft.Json.12.0.3\lib\net45\Newtonsoft.Json.dll</HintPath>
</Reference>
<Reference Include="NHibernate, Version=5.2.0.0, Culture=neutral, PublicKeyToken=aa95f207798dfdb4, processorArchitecture=MSIL">
<HintPath>..\packages\NHibernate.5.2.7\lib\net461\NHibernate.dll</HintPath>
</Reference>
<Reference Include="Remotion.Linq, Version=2.2.0.0, Culture=neutral, PublicKeyToken=fee00910d6e5f53b, processorArchitecture=MSIL">
<HintPath>..\packages\Remotion.Linq.2.2.0\lib\net45\Remotion.Linq.dll</HintPath>
</Reference>
<Reference Include="Remotion.Linq.EagerFetching, Version=2.2.0.0, Culture=neutral, PublicKeyToken=fee00910d6e5f53b, processorArchitecture=MSIL">
<HintPath>..\packages\Remotion.Linq.EagerFetching.2.2.0\lib\net45\Remotion.Linq.EagerFetching.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Buffers, Version=4.0.3.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
<HintPath>..\packages\System.Buffers.4.5.0\lib\netstandard2.0\System.Buffers.dll</HintPath>
Expand All @@ -86,6 +104,7 @@
<HintPath>..\packages\System.ComponentModel.Annotations.4.7.0\lib\net461\System.ComponentModel.Annotations.dll</HintPath>
</Reference>
<Reference Include="System.ComponentModel.DataAnnotations" />
<Reference Include="System.Configuration" />
<Reference Include="System.Core" />
<Reference Include="System.Memory, Version=4.0.1.1, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
<HintPath>..\packages\System.Memory.4.5.3\lib\netstandard2.0\System.Memory.dll</HintPath>
Expand All @@ -97,9 +116,11 @@
<Reference Include="System.Runtime.CompilerServices.Unsafe, Version=4.0.6.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\packages\System.Runtime.CompilerServices.Unsafe.4.7.0\lib\netstandard2.0\System.Runtime.CompilerServices.Unsafe.dll</HintPath>
</Reference>
<Reference Include="System.ServiceModel" />
<Reference Include="System.Threading.Tasks.Extensions, Version=4.2.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
<HintPath>..\packages\System.Threading.Tasks.Extensions.4.5.2\lib\netstandard2.0\System.Threading.Tasks.Extensions.dll</HintPath>
</Reference>
<Reference Include="System.Transactions" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
Expand Down
Loading

0 comments on commit 43269b3

Please sign in to comment.