Skip to content

Commit

Permalink
Merge pull request cake-contrib#3 from cake-contrib/feature/cake-cont…
Browse files Browse the repository at this point in the history
…ribgh-1

 (cake-contribGH-1) Check for binary files not tracked by LFS
  • Loading branch information
pascalberger authored Jul 27, 2019
2 parents 907d72f + 3f5e40b commit 72287d6
Show file tree
Hide file tree
Showing 9 changed files with 424 additions and 10 deletions.
31 changes: 31 additions & 0 deletions src/Cake.Issues.GitRepository.Tests/GitRunnerFixture.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
namespace Cake.Issues.GitRepository.Tests
{
using System.Collections.Generic;
using Cake.Testing.Fixtures;

internal class GitRunnerFixture : ToolFixture<GitRunnerSettings>
{
private readonly List<string> standardOutput = new List<string>();

public GitRunnerFixture()
: base("git")
{
}

public IEnumerable<string> StandardOutput => this.standardOutput;

protected override void RunTool()
{
this.standardOutput.Clear();

var tool = new GitRunner(this.FileSystem, this.Environment, this.ProcessRunner, this.Tools);

var output = tool.RunCommand(this.Settings);

if (output != null)
{
this.standardOutput.AddRange(output);
}
}
}
}
39 changes: 39 additions & 0 deletions src/Cake.Issues.GitRepository.Tests/GitRunnerTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
namespace Cake.Issues.GitRepository.Tests
{
using Cake.Issues.Testing;
using Shouldly;
using Xunit;

public sealed class GitRunnerTests
{
public sealed class TheRunCommandMethod
{
[Fact]
public void Should_Throw_If_Settings_Are_Null()
{
// Given
var fixture = new GitRunnerFixture
{
Settings = null,
};

// When
var result = Record.Exception(() => fixture.Run());

// Then
result.IsArgumentNullException("settings");
}

[Fact]
public void Arguments_Should_Be_Added_If_Settings_Are_Passed()
{
var fixture = new GitRunnerFixture();
fixture.Settings.Arguments.Add("Bar");

var result = fixture.Run();

result.Args.ShouldBe("Bar");
}
}
}
}
17 changes: 13 additions & 4 deletions src/Cake.Issues.GitRepository/GitRepositoryIssuesAliases.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
{
using Cake.Core;
using Cake.Core.Annotations;
using Cake.Core.IO;

/// <summary>
/// Contains functionality related to analyze Git repositories.
Expand Down Expand Up @@ -33,11 +32,14 @@ public static string GitRepositoryIssuesProviderTypeName(
/// <param name="settings">Settings for analyzing the Git repository.</param>
/// <returns>Instance of a provider for analyzing a Git repository and reporting issues.</returns>
/// <example>
/// <para>Analyze Git repository:</para>
/// <para>Check for binary files not tracked by Git LFS:</para>
/// <code>
/// <![CDATA[
/// var settings =
/// new GitRepositoryIssues();
/// new GitRepositoryIssuesSettings
/// {
/// CheckBinaryFilesTrackedWithLfs = true
/// };
///
/// var issues =
/// ReadIssues(
Expand All @@ -55,7 +57,14 @@ public static IIssueProvider GitRepositoryIssues(
context.NotNull(nameof(context));
settings.NotNull(nameof(settings));

return new GitRepositoryIssuesProvider(context.Log, settings);
return
new GitRepositoryIssuesProvider(
context.Log,
context.FileSystem,
context.Environment,
context.ProcessRunner,
context.Tools,
settings);
}
}
}
160 changes: 158 additions & 2 deletions src/Cake.Issues.GitRepository/GitRepositoryIssuesProvider.cs
Original file line number Diff line number Diff line change
@@ -1,24 +1,46 @@
namespace Cake.Issues.GitRepository
{
using System;
using System.Collections.Generic;
using System.Linq;
using Cake.Core;
using Cake.Core.Diagnostics;
using Cake.Core.IO;
using Cake.Core.Tooling;

/// <summary>
/// Provider for issues in Git repositories.
/// </summary>
internal class GitRepositoryIssuesProvider : BaseIssueProvider
{
private readonly GitRunner runner;

/// <summary>
/// Initializes a new instance of the <see cref="GitRepositoryIssuesProvider"/> class.
/// </summary>
/// <param name="log">The Cake log context.</param>
/// <param name="fileSystem">The file system.</param>
/// <param name="environment">The Cake environment.</param>
/// <param name="processRunner">The process runner.</param>
/// <param name="toolLocator">The tool locator.</param>
/// <param name="issueProviderSettings">Settings for the issue provider.</param>
public GitRepositoryIssuesProvider(ICakeLog log, GitRepositoryIssuesSettings issueProviderSettings)
public GitRepositoryIssuesProvider(
ICakeLog log,
IFileSystem fileSystem,
ICakeEnvironment environment,
IProcessRunner processRunner,
IToolLocator toolLocator,
GitRepositoryIssuesSettings issueProviderSettings)
: base(log)
{
fileSystem.NotNull(nameof(fileSystem));
environment.NotNull(nameof(environment));
processRunner.NotNull(nameof(processRunner));
toolLocator.NotNull(nameof(toolLocator));
issueProviderSettings.NotNull(nameof(issueProviderSettings));

this.IssueProviderSettings = issueProviderSettings;
this.runner = new GitRunner(fileSystem, environment, processRunner, toolLocator);
}

/// <inheritdoc />
Expand All @@ -32,7 +54,141 @@ public GitRepositoryIssuesProvider(ICakeLog log, GitRepositoryIssuesSettings iss
/// <inheritdoc />
protected override IEnumerable<IIssue> InternalReadIssues(IssueCommentFormat format)
{
return new List<IIssue>();
var result = new List<IIssue>();

if (this.IssueProviderSettings.CheckBinaryFilesTrackedByLfs)
{
result.AddRange(this.CheckForBinaryFilesNotTrackedByLfs());
}

return result;
}

/// <summary>
/// Checks for binary files which are not tracked by LFS.
/// </summary>
/// <returns>List of issues for binary files which are not tracked by LFS.</returns>
private IEnumerable<IIssue> CheckForBinaryFilesNotTrackedByLfs()
{
var allFiles = this.GetAllFilesFromRepository();
if (!allFiles.Any())
{
return new List<IIssue>();
}

var textFiles = this.GetTextFilesFromRepository();
if (!textFiles.Any())
{
return new List<IIssue>();
}

this.Log.Information("Determine binary files...");
var binaryFiles = allFiles.Except(textFiles);
this.Log.Information("Found {0} binary file(s)", binaryFiles.Count());

if (!binaryFiles.Any())
{
return new List<IIssue>();
}

this.Log.Debug(string.Join(Environment.NewLine, binaryFiles));

this.Log.Information("Checking if binary files are tracked by LFS...");
var lfsTrackedFiles = this.GetLfsTrackedFilesFromRepository();

var binaryFilesNotTrackedByLfs = binaryFiles.Except(lfsTrackedFiles);
this.Log.Information("Found {0} binary file(s) not tracked by LFS", binaryFilesNotTrackedByLfs.Count());

var result = new List<IIssue>();
foreach (var file in binaryFilesNotTrackedByLfs)
{
result.Add(
IssueBuilder
.NewIssue(
$"File '{file}' is a binary file but not tracked by LFS.", this)
.InFile(file)
.OfRule("BinaryFileNotTrackedByLfs")
.WithPriority(IssuePriority.Warning)
.Create());
}

return result;
}

/// <summary>
/// Returns a list of the files in the repository.
/// </summary>
/// <returns>List of files in the repository.</returns>
private IEnumerable<string> GetAllFilesFromRepository()
{
var settings = new GitRunnerSettings
{
WorkingDirectory = this.Settings.RepositoryRoot,
};

this.Log.Information("Reading all files from repository '{0}'...", this.Settings.RepositoryRoot);
settings.Arguments.Clear();
settings.Arguments.Add("ls-files");
var allFiles = this.runner.RunCommand(settings);

if (allFiles == null)
{
throw new Exception("Error reading files from repository");
}

this.Log.Information("Found {0} file(s)", allFiles.Count());

return allFiles;
}

/// <summary>
/// Returns a list of text files in the repository.
/// </summary>
/// <returns>List of text files in the repository.</returns>
private IEnumerable<string> GetTextFilesFromRepository()
{
var settings = new GitRunnerSettings
{
WorkingDirectory = this.Settings.RepositoryRoot,
};

this.Log.Information("Reading all text files from repository '{0}'...", this.Settings.RepositoryRoot);
settings.Arguments.Clear();
settings.Arguments.Add("grep -Il .");
var textFiles = this.runner.RunCommand(settings);
if (textFiles == null)
{
throw new Exception("Error reading text files from repository");
}

this.Log.Information("Found {0} text file(s)", textFiles.Count());

return textFiles;
}

/// <summary>
/// Returns a list of files tracked by Git LFS.
/// </summary>
/// <returns>List of files tracked by Git LFS.</returns>
private IEnumerable<string> GetLfsTrackedFilesFromRepository()
{
var settings = new GitRunnerSettings
{
WorkingDirectory = this.Settings.RepositoryRoot,
};

this.Log.Information("Reading all LFS tracked files from repository '{0}'...", this.Settings.RepositoryRoot);
settings.Arguments.Clear();
settings.Arguments.Add("lfs ls-files");
var lfsTrackedFiles = this.runner.RunCommand(settings);
if (lfsTrackedFiles == null)
{
throw new Exception("Error reading LFS tracked files from repository");
}

this.Log.Information("Found {0} LFS tracked file(s)", lfsTrackedFiles.Count());

return lfsTrackedFiles;
}
}
}
8 changes: 4 additions & 4 deletions src/Cake.Issues.GitRepository/GitRepositoryIssuesSettings.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,10 @@
public class GitRepositoryIssuesSettings
{
/// <summary>
/// Initializes a new instance of the <see cref="GitRepositoryIssuesSettings"/> class.
/// Gets or sets a value indicating whether the repository should be checked for
/// binary files not tracked by Git LFS.
/// Requires Git and Git-LFS to be available through Cake tool resolution.
/// </summary>
public GitRepositoryIssuesSettings()
{
}
public bool CheckBinaryFilesTrackedByLfs { get; set; }
}
}
Loading

0 comments on commit 72287d6

Please sign in to comment.