Skip to content

Commit

Permalink
Merge pull request #204 from corgibytes/compute-history
Browse files Browse the repository at this point in the history
Compute history
  • Loading branch information
Edwin Kortman authored Aug 30, 2022
2 parents 087d325 + 3030120 commit 4f4e4cc
Show file tree
Hide file tree
Showing 15 changed files with 216 additions and 51 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,6 @@

<ItemGroup>
<PackageReference Include="FluentAssertions" Version="6.7.0" />
<PackageReference Include="JetBrains.dotCover.CommandLineTools" Version="2022.2.2">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.3.0" />
<PackageReference Include="Moq" Version="4.18.2" />
<PackageReference Include="MSTest.TestFramework" Version="2.2.10" />
Expand Down
30 changes: 18 additions & 12 deletions Corgibytes.Freshli.Cli.Test/Functionality/Git/ComputeHistoryTest.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
using System;
using System.Collections.Generic;
using Corgibytes.Freshli.Cli.Functionality.Analysis;
using Corgibytes.Freshli.Cli.Functionality.Git;
using Corgibytes.Freshli.Cli.Test.Common;
using Moq;
using Xunit;
using Xunit.Abstractions;
using Xunit.DependencyInjection;
Expand All @@ -11,14 +13,12 @@ namespace Corgibytes.Freshli.Cli.Test.Functionality.Git;
[UnitTest]
public class ComputeHistoryTest : FreshliTest
{
private readonly string _cacheDir;
private readonly ComputeHistory _computeHistory;

public ComputeHistoryTest(ITestOutputHelper output) : base(output)
{
var listCommits = new MockListCommits();
_computeHistory = new ComputeHistory(listCommits);
_cacheDir = "/this/is/a/path";

listCommits.HasCommitsAvailable(new List<GitCommit>
{
Expand All @@ -37,22 +37,28 @@ public ComputeHistoryTest(ITestOutputHelper output) : base(output)
});
}

[Theory]
[MethodData(nameof(ExpectedStopsForCommitHistory))]
public void Verify_it_can_find_sha_identifiers_and_dates_for_the_all_commits(List<HistoryIntervalStop> expectedStops)
{
var analysisLocation = new Mock<IAnalysisLocation>();

Assert.Equivalent(expectedStops,
_computeHistory.ComputeCommitHistory(analysisLocation.Object, "git")
);
}

[Theory]
[MethodData(nameof(ExpectedStopsForDayInterval))]
[MethodData(nameof(ExpectedStopsForWeekInterval))]
[MethodData(nameof(ExpectedStopsForMonthInterval))]
[MethodData(nameof(ExpectedStopsForYearInterval))]
public void Verify_it_can_find_sha_identifiers_and_dates_for_interval(List<HistoryIntervalStop> expectedStops,
string interval) => Assert.Equivalent(expectedStops,
_computeHistory.ComputeWithHistoryInterval("repository.identifier", "git", interval, _cacheDir));

[Theory]
[MethodData(nameof(ExpectedStopsForCommitHistory))]
public void Verify_it_can_find_sha_identifiers_and_dates_for_the_all_commits(
List<HistoryIntervalStop> expectedStops) =>
public void Verify_it_can_find_sha_identifiers_and_dates_for_interval(List<HistoryIntervalStop> expectedStops, string interval)
{
var analysisLocation = new Mock<IAnalysisLocation>();
Assert.Equivalent(expectedStops,
_computeHistory.ComputeCommitHistory("repository.identifier", "git", _cacheDir)
);
_computeHistory.ComputeWithHistoryInterval(analysisLocation.Object, "git", interval));
}

private static TheoryData<List<HistoryIntervalStop>, string> ExpectedStopsForDayInterval() =>
new()
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System.Collections.Generic;
using Corgibytes.Freshli.Cli.Functionality.Analysis;
using Corgibytes.Freshli.Cli.Functionality.Git;

namespace Corgibytes.Freshli.Cli.Test.Functionality.Git;
Expand All @@ -9,9 +10,7 @@ public class MockListCommits : IListCommits

public MockListCommits() => _availableCommits = new List<GitCommit>();

public IEnumerable<GitCommit> ForRepository(string repositoryId, string cacheDir, string gitPath) =>
_availableCommits;
public IEnumerable<GitCommit> ForRepository(IAnalysisLocation analysisLocation, string gitPath) => _availableCommits;

public void HasCommitsAvailable(IEnumerable<GitCommit> availableGitCommits) =>
_availableCommits = availableGitCommits;
public void HasCommitsAvailable(IEnumerable<GitCommit> availableGitCommits) => _availableCommits = availableGitCommits;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
using System;
using System.Collections.Generic;
using Corgibytes.Freshli.Cli.DataModel;
using Corgibytes.Freshli.Cli.Functionality;
using Corgibytes.Freshli.Cli.Functionality.Analysis;
using Corgibytes.Freshli.Cli.Functionality.Engine;
using Corgibytes.Freshli.Cli.Functionality.Git;
using Corgibytes.Freshli.Cli.Functionality.History;
using Moq;
using Xunit;

namespace Corgibytes.Freshli.Cli.Test.Functionality.History;

public class ComputeHistoryActivityTest
{
private readonly Mock<ICacheDb> _cacheDb = new();
private readonly Mock<IComputeHistory> _computeHistory = new();
private readonly Mock<IApplicationEventEngine> _eventEngine = new();

[Fact]
public void FiresHistoryIntervalStopFoundEvents()
{
// Arrange
// Have an analysis available
var cachedAnalysis = new CachedAnalysis("https://lorem-ipsum.com", "main", "month");
_cacheDb.Setup(mock => mock.RetrieveAnalysis(It.IsAny<Guid>())).Returns(cachedAnalysis);


// Have interval stops available
var historyIntervalStops = new List<HistoryIntervalStop>
{
new(
"75c7fcc7336ee718050c4a5c8dfb5598622787b2",
new DateTimeOffset(2021, 2, 20, 12, 31, 34, TimeSpan.Zero)
),
new(
"583d813db3e28b9b44a29db352e2f0e1b4c6e420",
new DateTimeOffset(2021, 5, 19, 15, 24, 24, TimeSpan.Zero)
)
};
_computeHistory.Setup(mock => mock.ComputeWithHistoryInterval(
It.IsAny<IAnalysisLocation>(), It.IsAny<string>(), It.IsAny<string>())
)
.Returns(historyIntervalStops);

var analysisLocation = new Mock<IAnalysisLocation>();

// Act
new ComputeHistoryActivity(
"git",
_cacheDb.Object,
_computeHistory.Object,
new Guid("cbc83480-ae47-46de-91df-60747ca8fb09"),
analysisLocation.Object
).Handle(_eventEngine.Object);

// Assert
_eventEngine.Verify(
mock => mock.Fire(
It.Is<HistoryIntervalStopFoundEvent>(
value =>
value.GitCommitIdentifier == "75c7fcc7336ee718050c4a5c8dfb5598622787b2" && value.AnalysisLocation == analysisLocation.Object
)
)
);
_eventEngine.Verify(
mock => mock.Fire(
It.Is<HistoryIntervalStopFoundEvent>(
value =>
value.GitCommitIdentifier == "583d813db3e28b9b44a29db352e2f0e1b4c6e420" && value.AnalysisLocation == analysisLocation.Object
)
)
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,29 +5,30 @@
using System.Globalization;
using Corgibytes.Freshli.Cli.CommandOptions;
using Corgibytes.Freshli.Cli.Commands.Git;
using Corgibytes.Freshli.Cli.Functionality.Analysis;
using Corgibytes.Freshli.Cli.Functionality.Git;
using Corgibytes.Freshli.Lib;

namespace Corgibytes.Freshli.Cli.CommandRunners.Git;

public class ComputeHistoryCommandRunner : CommandRunner<ComputeHistoryCommand, ComputeHistoryCommandOptions>
{
private readonly ComputeHistory _computeHistory;
private readonly IComputeHistory _computeHistory;

public ComputeHistoryCommandRunner(IServiceProvider serviceProvider, Runner runner, ComputeHistory computeHistory) :
public ComputeHistoryCommandRunner(IServiceProvider serviceProvider, Runner runner,
IComputeHistory computeHistory) :
base(serviceProvider, runner) => _computeHistory = computeHistory;

public override int Run(ComputeHistoryCommandOptions options, InvocationContext context)
{
if (options.CommitHistory)
{
WriteStopsToLines(
_computeHistory.ComputeCommitHistory(options.RepositoryId, options.GitPath, options.CacheDir),
_computeHistory.ComputeCommitHistory(new AnalysisLocation(options.RepositoryId, options.CacheDir), options.GitPath),
context);
return 0;
}


var historyIntervalDuration = options.HistoryInterval switch
{
"d" => "day",
Expand All @@ -39,8 +40,7 @@ public override int Run(ComputeHistoryCommandOptions options, InvocationContext

WriteStopsToLines(
_computeHistory
.ComputeWithHistoryInterval(options.RepositoryId, options.GitPath, historyIntervalDuration,
options.CacheDir),
.ComputeWithHistoryInterval(new AnalysisLocation(options.RepositoryId, options.CacheDir), options.GitPath, historyIntervalDuration),
context
);

Expand Down
15 changes: 15 additions & 0 deletions Corgibytes.Freshli.Cli/Functionality/Analysis/AnalysisLocation.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
namespace Corgibytes.Freshli.Cli.Functionality.Analysis;

public class AnalysisLocation : IAnalysisLocation
{
private readonly string _repositoryId;
private readonly string _cacheDirectory;

public AnalysisLocation(string repositoryId, string cacheDirectory)
{
_repositoryId = repositoryId;
_cacheDirectory = cacheDirectory;
}

public string Path => _cacheDirectory + "/repositories/" + _repositoryId;
}
5 changes: 4 additions & 1 deletion Corgibytes.Freshli.Cli/Functionality/CacheDb.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,10 @@ public class CacheDb : ICacheDb, IDisposable
{
private bool _disposed;

public CacheDb(string cacheDir) => Db = new CacheContext(cacheDir);
public CacheDb(string cacheDir)
{
Db = new CacheContext(cacheDir);
}

private CacheContext Db { get; }

Expand Down
25 changes: 12 additions & 13 deletions Corgibytes.Freshli.Cli/Functionality/Git/ComputeHistory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,31 +2,23 @@
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using Corgibytes.Freshli.Cli.Functionality.Analysis;

namespace Corgibytes.Freshli.Cli.Functionality.Git;

public class ComputeHistory
public class ComputeHistory : IComputeHistory
{
private readonly IListCommits _listCommits;

public ComputeHistory(IListCommits listCommits) => _listCommits = listCommits;

public IEnumerable<HistoryIntervalStop> ComputeCommitHistory(string repositoryId, string gitPath,
string cacheDir)
{
var commitHistory = _listCommits.ForRepository(repositoryId, cacheDir, gitPath);
return commitHistory
.Select(gitCommit => new HistoryIntervalStop(gitCommit.ShaIdentifier, gitCommit.CommittedAt)).ToList();
}

public IEnumerable<HistoryIntervalStop> ComputeWithHistoryInterval(
string repositoryId,
IAnalysisLocation analysisLocation,
string gitPath,
string historyInterval,
string cacheDir
string historyInterval
)
{
var commitHistory = _listCommits.ForRepository(repositoryId, cacheDir, gitPath);
var commitHistory = _listCommits.ForRepository(analysisLocation, gitPath);

var groupedHistories = historyInterval switch
{
Expand Down Expand Up @@ -60,4 +52,11 @@ into mostRecentCommitForThisGroupedPeriod
mostRecentCommitForThisGroupedPeriod.CommittedAt))
.ToList();
}

public IEnumerable<HistoryIntervalStop> ComputeCommitHistory(IAnalysisLocation analysisLocation, string gitPath)
{
var commitHistory = _listCommits.ForRepository(analysisLocation, gitPath);
return commitHistory
.Select(gitCommit => new HistoryIntervalStop(gitCommit.ShaIdentifier, gitCommit.CommittedAt)).ToList();
}
}
15 changes: 15 additions & 0 deletions Corgibytes.Freshli.Cli/Functionality/Git/IComputeHistory.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
using System.Collections.Generic;
using Corgibytes.Freshli.Cli.Functionality.Analysis;

namespace Corgibytes.Freshli.Cli.Functionality.Git;

public interface IComputeHistory
{
public IEnumerable<HistoryIntervalStop> ComputeWithHistoryInterval(
IAnalysisLocation analysisLocation,
string gitPath,
string historyInterval
);

public IEnumerable<HistoryIntervalStop> ComputeCommitHistory(IAnalysisLocation analysisLocation, string gitPath);
}
3 changes: 2 additions & 1 deletion Corgibytes.Freshli.Cli/Functionality/Git/IListCommits.cs
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
using System.Collections.Generic;
using Corgibytes.Freshli.Cli.Functionality.Analysis;

namespace Corgibytes.Freshli.Cli.Functionality.Git;

public interface IListCommits
{
public IEnumerable<GitCommit> ForRepository(string repositoryId, string cacheDir, string gitPath);
public IEnumerable<GitCommit> ForRepository(IAnalysisLocation analysisLocation, string gitPath);
}
12 changes: 3 additions & 9 deletions Corgibytes.Freshli.Cli/Functionality/Git/ListCommits.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,21 +3,15 @@
using System.Text;
using CliWrap;
using Corgibytes.Freshli.Cli.Exceptions;
using Corgibytes.Freshli.Cli.Functionality.Analysis;
using Corgibytes.Freshli.Cli.Resources;

namespace Corgibytes.Freshli.Cli.Functionality.Git;

public class ListCommits : IListCommits
{
private readonly ICachedGitSourceRepository _cachedGitSourceRepository;

public ListCommits(ICachedGitSourceRepository cachedGitSourceRepository) =>
_cachedGitSourceRepository = cachedGitSourceRepository;

public IEnumerable<GitCommit> ForRepository(string repositoryId, string cacheDirectory, string gitPath)
public IEnumerable<GitCommit> ForRepository(IAnalysisLocation analysisLocation, string gitPath)
{
var gitSource = _cachedGitSourceRepository.FindOneByHash(repositoryId, cacheDirectory);

var stdErrBuffer = new StringBuilder();
var stdOutBuffer = new StringBuilder();
var command = CliWrap.Cli.Wrap(gitPath).WithArguments(
Expand All @@ -29,7 +23,7 @@ public IEnumerable<GitCommit> ForRepository(string repositoryId, string cacheDir
.Add("--pretty=format:%H %aI")
)
.WithValidation(CommandResultValidation.None)
.WithWorkingDirectory(gitSource.LocalPath)
.WithWorkingDirectory(analysisLocation.Path)
.WithStandardOutputPipe(PipeTarget.ToStringBuilder(stdOutBuffer))
.WithStandardErrorPipe(PipeTarget.ToStringBuilder(stdErrBuffer));

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
using System;
using Corgibytes.Freshli.Cli.Functionality.Analysis;
using Corgibytes.Freshli.Cli.Functionality.Engine;
using Corgibytes.Freshli.Cli.Functionality.Git;
using Newtonsoft.Json;

namespace Corgibytes.Freshli.Cli.Functionality.History;

public class ComputeHistoryActivity : IApplicationActivity
{
[JsonProperty] private readonly Guid _analysisId;
[JsonProperty] private readonly ICacheDb _cacheDb;
[JsonProperty] private readonly IComputeHistory _computeHistoryService;
private readonly string _gitExecutablePath;
[JsonProperty] private readonly IAnalysisLocation _analysisLocation;

public ComputeHistoryActivity(string gitExecutablePath, ICacheDb cacheDb, IComputeHistory computeHistoryService,
Guid analysisId, IAnalysisLocation analysisLocation)
{
_gitExecutablePath = gitExecutablePath;
_cacheDb = cacheDb;
_computeHistoryService = computeHistoryService;
_analysisId = analysisId;
_analysisLocation = analysisLocation;
}

public void Handle(IApplicationEventEngine eventClient)
{
var analysis = _cacheDb.RetrieveAnalysis(_analysisId);
if (analysis == null)
{
return;
}

var historyIntervalStops =
_computeHistoryService.ComputeWithHistoryInterval(_analysisLocation, _gitExecutablePath, analysis.HistoryInterval);

foreach (var historyIntervalStop in historyIntervalStops)
{
eventClient.Fire(new HistoryIntervalStopFoundEvent
{
GitCommitIdentifier = historyIntervalStop.GitCommitIdentifier,
AnalysisLocation = _analysisLocation
});
}
}
}
Loading

0 comments on commit 4f4e4cc

Please sign in to comment.