Skip to content

Commit

Permalink
(GH-183) Add option to use Git CLI (#205)
Browse files Browse the repository at this point in the history
  • Loading branch information
pascalberger authored Aug 3, 2021
1 parent 92f208b commit 39122d1
Show file tree
Hide file tree
Showing 17 changed files with 406 additions and 13 deletions.
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
using Cake.Core.IO;
using Cake.Git;
using Cake.Issues;
using System;
using System.Linq;

namespace Cake.Frosting.Issues.Recipe
{
Expand All @@ -19,8 +17,7 @@ public virtual Uri DetermineRepositoryRemoteUrl(
context.NotNull(nameof(context));
repositoryRootDirectory.NotNull(nameof(repositoryRootDirectory));

var currentBranch = context.GitBranchCurrent(repositoryRootDirectory);
return new Uri(currentBranch.Remotes.Single(x => x.Name == "origin").Url);
return context.State.RepositoryInfo.GetRepositoryRemoteUrl(context, repositoryRootDirectory);
}

/// <inheritdoc />
Expand All @@ -31,7 +28,7 @@ public virtual string DetermineCommitId(
context.NotNull(nameof(context));
repositoryRootDirectory.NotNull(nameof(repositoryRootDirectory));

return context.GitLogTip(repositoryRootDirectory).Sha;
return context.State.RepositoryInfo.GetCommitId(context, repositoryRootDirectory);
}

/// <inheritdoc />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,14 @@ public class IssuesContext : FrostingContext
/// Creates a new instance of the <see cref="IssuesContext"/> class.
/// </summary>
/// <param name="context">The Cake context.</param>
public IssuesContext(ICakeContext context)
/// <param name="repositoryInfoProviderType">Defines how information about the Git repository should be determined.</param>
public IssuesContext(
ICakeContext context,
RepositoryInfoProviderType repositoryInfoProviderType)
: base(context)
{
this.Parameters = new IssuesParameters();
this.State = new IssuesState(this);
this.State = new IssuesState(this, repositoryInfoProviderType);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
namespace Cake.Frosting.Issues.Recipe
{
/// <summary>
/// Supported ways to read repository information.
/// </summary>
public enum RepositoryInfoProviderType
{
/// <summary>
/// Read repository information using Cake.Git addin.
/// Requires system to be compatible with Cake.Git addin.
/// </summary>
CakeGit,

/// <summary>
/// Read repository information using Git CLI.
/// Requires Git CLI to be available in path.
/// </summary>
Cli
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
using Cake.Common.Diagnostics;
using Cake.Common.IO;
using Cake.Core.IO;
using Cake.Git;
using Cake.Issues;
using System;
using System.Collections.Generic;
Expand Down Expand Up @@ -47,6 +46,11 @@ public class IssuesState
/// </summary>
public FilePath SummaryIssuesReport { get; set; }

/// <summary>
/// Gets the provider to read information about the Git repository.
/// </summary>
public IRepositoryInfoProvider RepositoryInfo { get; }

/// <summary>
/// Gets the build server under which the build is running.
/// Returns <c>null</c> if running locally or on an unsupported build server.
Expand All @@ -68,7 +72,10 @@ public class IssuesState
/// Creates a new instance of the <see cref="IssuesState"/> class.
/// </summary>
/// <param name="context">The Cake context.</param>
public IssuesState(IssuesContext context)
/// <param name="repositoryInfoProviderType">Defines how information about the Git repository should be determined.</param>
public IssuesState(
IssuesContext context,
RepositoryInfoProviderType repositoryInfoProviderType)
{
if (context == null)
{
Expand All @@ -78,7 +85,9 @@ public IssuesState(IssuesContext context)
this.BuildRootDirectory = context.MakeAbsolute(context.Directory("./"));
context.Information("Build script root directory: {0}", this.BuildRootDirectory);

this.RepositoryRootDirectory = context.GitFindRootFromPath(this.BuildRootDirectory);
this.RepositoryInfo = DetermineRepositoryInfoProvider(context, repositoryInfoProviderType);

this.RepositoryRootDirectory = this.RepositoryInfo.GetRepositoryRootDirectory(context, this.BuildRootDirectory);
context.Information("Repository root directory: {0}", this.RepositoryRootDirectory);

this.BuildServer = DetermineBuildServer(context);
Expand Down Expand Up @@ -127,6 +136,34 @@ public void AddIssues(IEnumerable<IIssue> issues)
this.issues.AddRange(issues);
}

/// <summary>
/// Determines the repository info provider to use.
/// </summary>
/// <param name="context">The Cake context.</param>
/// <param name="repositoryInfoProviderType">Defines how information about the Git repository should be determined.</param>
/// <returns>The repository info provider which should be used.</returns>
private static IRepositoryInfoProvider DetermineRepositoryInfoProvider(
IssuesContext context,
RepositoryInfoProviderType repositoryInfoProviderType)
{
if (context == null)
{
throw new ArgumentNullException(nameof(context));
}

switch (repositoryInfoProviderType)
{
case RepositoryInfoProviderType.CakeGit:
context.Information("Using Cake.Git for providing repository information");
return new CliRepositoryInfoProvider();
case RepositoryInfoProviderType.Cli:
context.Information("Using Git CLI for providing repository information");
return new CliRepositoryInfoProvider();
default:
throw new NotImplementedException("Unsupported repository info provider");
}
}

/// <summary>
/// Determines the build server on which the build is running.
/// </summary>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
using Cake.Core;
using Cake.Core.IO;
using Cake.Git;
using Cake.Issues;
using System;
using System.Linq;

namespace Cake.Frosting.Issues.Recipe
{
/// <summary>
/// Provider to retrieve repository information using <see href="https://cakebuild.net/extensions/cake-git/">Cake.Git addin</see>.
/// </summary>
public class CakeGitRepositoryInfoProvider : IRepositoryInfoProvider
{
/// <inheritdoc />
public DirectoryPath GetRepositoryRootDirectory(ICakeContext context, DirectoryPath buildRootDirectory)
{
context.NotNull(nameof(context));
buildRootDirectory.NotNull(nameof(buildRootDirectory));

return context.GitFindRootFromPath(buildRootDirectory);
}

/// <inheritdoc />
public Uri GetRepositoryRemoteUrl(ICakeContext context, DirectoryPath repositoryRootDirectory)
{
context.NotNull(nameof(context));
repositoryRootDirectory.NotNull(nameof(repositoryRootDirectory));

var currentBranch = context.GitBranchCurrent(repositoryRootDirectory);
return new Uri(currentBranch.Remotes.Single(x => x.Name == "origin").Url);
}

/// <inheritdoc />
public string GetCommitId(ICakeContext context, DirectoryPath repositoryRootDirectory)
{
context.NotNull(nameof(context));
repositoryRootDirectory.NotNull(nameof(repositoryRootDirectory));

return context.GitLogTip(repositoryRootDirectory).Sha;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
using Cake.Common;
using Cake.Core;
using Cake.Core.IO;
using System;
using System.Collections.Generic;
using System.Linq;

namespace Cake.Frosting.Issues.Recipe
{
/// <summary>
/// Provider to retrieve repository information using Git CLI.
/// </summary>
public class CliRepositoryInfoProvider : IRepositoryInfoProvider
{
/// <inheritdoc />
public DirectoryPath GetRepositoryRootDirectory(ICakeContext context, DirectoryPath buildRootDirectory)
{
var result =
this.GitCommand(context, buildRootDirectory, "rev-parse", "--show-toplevel");
return new DirectoryPath(result.Single());
}

/// <inheritdoc />
public Uri GetRepositoryRemoteUrl(ICakeContext context, DirectoryPath repositoryRootDirectory)
{
var result =
this.GitCommand(context, repositoryRootDirectory, "config", "--get", "remote.origin.url");
return new Uri(result.Single());
}

/// <inheritdoc />
public string GetCommitId(ICakeContext context, DirectoryPath repositoryRootDirectory)
{
return
this.GitCommand(context, repositoryRootDirectory, "rev-parse", "HEAD")
.Single();
}

private IEnumerable<string> GitCommand(
ICakeContext context,
DirectoryPath repositoryRootFolder,
params string[] arguments)
{
if (!arguments.Any())
{
throw new ArgumentOutOfRangeException(nameof(arguments));
}

var gitArguments = string.Join(" ", arguments);

var exitCode = context.StartProcess(
"git",
new ProcessSettings
{
Arguments = gitArguments,
WorkingDirectory = repositoryRootFolder.FullPath,
RedirectStandardOutput = true,
RedirectStandardError = true
},
out var redirectedStandardOutput,
out var redirectedErrorOutput
);

if (exitCode != 0)
{
throw new Exception(
$"Git command failed with arguments {gitArguments}. Exit code: {exitCode}. Error output: {string.Join(Environment.NewLine, redirectedErrorOutput)}"
);
}

return redirectedStandardOutput;

}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
using Cake.Core;
using Cake.Core.IO;
using System;

namespace Cake.Frosting.Issues.Recipe
{
/// <summary>
/// Description of a provider to retrieve repository information.
/// </summary>
public interface IRepositoryInfoProvider
{
/// <summary>
/// Returns the root directory of the current repository.
/// </summary>
/// <param name="context">The Cake context.</param>
/// <param name="buildRootDirectory">Root directory of the build script.</param>
/// <returns>The root directory of the current repository.</returns>
DirectoryPath GetRepositoryRootDirectory(ICakeContext context, DirectoryPath buildRootDirectory);

/// <summary>
/// Returns the URL of the remote repository.
/// </summary>
/// <param name="context">The Cake context.</param>
/// <param name="repositoryRootDirectory">Root directory of the repository.</param>
/// <returns>The URL of the remote repository.</returns>
Uri GetRepositoryRemoteUrl(ICakeContext context, DirectoryPath repositoryRootDirectory);

/// <summary>
/// Returns the SHA hash of the current commit.
/// </summary>
/// <param name="context">The Cake context.</param>
/// <param name="repositoryRootDirectory">Root directory of the repository.</param>
/// <returns>The SHA hash of the current commit</returns>
string GetCommitId(ICakeContext context, DirectoryPath repositoryRootDirectory);
}
}
7 changes: 6 additions & 1 deletion Cake.Issues.Recipe/Content/build.cake
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,19 @@
/// </summary>
var IssuesBuildTasks = new IssuesBuildTaskDefinitions();

/// <summary>
/// Defines how information about the Git repository should be determined.
/// </summary>
var RepositoryInfoProvider = RepositoryInfoProviderType.CakeGit;

///////////////////////////////////////////////////////////////////////////////
// SETUP / TEARDOWN
///////////////////////////////////////////////////////////////////////////////

Setup<IssuesData>(setupContext =>
{
Information("Initializing Cake.Issues.Recipe (Version {0})...", BuildMetaDataCakeIssuesRecipe.Version);
return new IssuesData(setupContext);
return new IssuesData(setupContext, RepositoryInfoProvider);
});

///////////////////////////////////////////////////////////////////////////////
Expand Down
38 changes: 37 additions & 1 deletion Cake.Issues.Recipe/Content/data/IssuesData.cake
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,11 @@ public class IssuesData
/// </summary>
public IIssuesBuildServer BuildServer { get; }

/// <summary>
/// Gets the provider to read information about the Git repository.
/// </summary>
public IRepositoryInfoProvider RepositoryInfo { get; }

/// <summary>
/// Gets the pull request system used for the code.
/// Returns <c>null</c> if not running a pull request build or on an unsupported build server.
Expand All @@ -61,13 +66,16 @@ public class IssuesData
/// Creates a new instance of the <see cref="IssuesData"/> class.
/// </summary>
/// <param name="context">The Cake context.</param>
public IssuesData(ICakeContext context)
/// <param name="repositoryInfoProviderType">Defines how information about the Git repository should be determined.</param>
public IssuesData(ICakeContext context, RepositoryInfoProviderType repositoryInfoProviderType)
{
context.NotNull(nameof(context));

this.BuildRootDirectory = context.MakeAbsolute(context.Directory("./"));
context.Information("Build script root directory: {0}", this.BuildRootDirectory);

this.RepositoryInfo = DetermineRepositoryInfoProvider(context, repositoryInfoProviderType);

this.RepositoryRootDirectory = context.GitFindRootFromPath(this.BuildRootDirectory);
context.Information("Repository root directory: {0}", this.RepositoryRootDirectory);

Expand Down Expand Up @@ -111,6 +119,34 @@ public class IssuesData
this.issues.AddRange(issues);
}

/// <summary>
/// Determines the repository info provider to use.
/// </summary>
/// <param name="context">The Cake context.</param>
/// <param name="repositoryInfoProviderType">Defines how information about the Git repository should be determined.</param>
/// <returns>The repository info provider which should be used.</returns>
private static IRepositoryInfoProvider DetermineRepositoryInfoProvider(
ICakeContext context,
RepositoryInfoProviderType repositoryInfoProviderType)
{
if (context == null)
{
throw new ArgumentNullException(nameof(context));
}

switch (repositoryInfoProviderType)
{
case RepositoryInfoProviderType.CakeGit:
context.Information("Using Cake.Git for providing repository information");
return new CliRepositoryInfoProvider();
case RepositoryInfoProviderType.Cli:
context.Information("Using Git CLI for providing repository information");
return new CliRepositoryInfoProvider();
default:
throw new NotImplementedException("Unsupported repository info provider");
}
}

/// <summary>
/// Determines the build server on which the build is running.
/// </summary>
Expand Down
Loading

0 comments on commit 39122d1

Please sign in to comment.