Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

(GH-183) Add option to use Git CLI #205

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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