/// <summary> /// Resolve a rev to a shortened commit sha1 /// </summary> /// /// <param name="minimumLength"> /// Minimum length of the shortened sha1, or <c>0</c> for Git to choose automatically /// </param> /// public GitShortSha1 GetShortCommitId(GitRev rev, int minimumLength = 0) { Guard.NotNull(rev, nameof(rev)); if (minimumLength < 0) { throw new ArgumentOutOfRangeException(nameof(minimumLength)); } if (0 < minimumLength && minimumLength < 4) { throw new ArgumentOutOfRangeException(nameof(minimumLength)); } var length = minimumLength == 0 ? "auto" : minimumLength.ToString(); var r = ProcessExtensions.ExecuteCaptured(false, false, null, "git", "-C", Path, "rev-parse", $"--short={length}", rev); if (r.ExitCode != 0) { throw new GitException("Resolve rev to short commit sha1 failed", r); } return(new GitShortSha1(r.StandardOutput.Trim())); }
public void Captures_Output_Correctly() { var result = ProcessExtensions.ExecuteCaptured(true, true, null, TestExe); result.StandardOutput.ShouldBe( Lines( "aaa", "bbb", "", "ccc")); result.ErrorOutput.ShouldBe( Lines( "ddd", "eee", "", "fff")); result.CombinedOutput.Trim().Split(new[] { Environment.NewLine }, StringSplitOptions.None) .ShouldBe( new[] { "aaa", "bbb", "", "ccc", "ddd", "eee", "", "fff", }, ignoreOrder: true); result.ExitCode.ShouldBe(0); }
/// <summary> /// Clone a Git repository /// </summary> /// public static GitRepository Clone(string parentPath, GitUrl url) { Guard.Required(parentPath, nameof(parentPath)); if (!Directory.Exists(parentPath)) { throw new ArgumentException("Parent path doesn't exist", nameof(parentPath)); } Guard.NotNull(url, nameof(url)); var directoryName = IOPath.GetFileName(url.AbsolutePath); if (directoryName.EndsWith(".git", StringComparison.OrdinalIgnoreCase)) { directoryName = directoryName.Substring(0, directoryName.Length - 4); } var path = IOPath.Combine(parentPath, directoryName); var r = ProcessExtensions.ExecuteCaptured(false, false, null, "git", "-C", parentPath, "clone", url); if (r.ExitCode != 0) { throw new GitException("Cloning repository failed", r); } return(new GitRepository(path)); }
public void Passes_Arguments_Correctly() { var result = ProcessExtensions.ExecuteCaptured(true, true, null, TestExe, "a b c", "d", "\"e f\""); result.StandardOutput.ShouldContain("arg0: a b c"); result.StandardOutput.ShouldContain("arg1: d"); result.StandardOutput.ShouldContain("arg2: e f"); }
/// <summary> /// Stage uncommitted changes /// </summary> /// public void StageChanges() { var r = ProcessExtensions.ExecuteCaptured(false, false, null, "git", "-C", Path, "add", "-A"); if (r.ExitCode != 0) { throw new GitException("Stage uncommitted changes failed", r); } }
/// <summary> /// Invoke the nugit.exe under test, for use by tests /// </summary> /// static void Nugit(GitRepository repo, string command, params string[] args) { var allArgs = new [] { command }.Concat(args).ToArray(); var r = ProcessExtensions.ExecuteCaptured(true, true, repo.Path, nugitPath, allArgs); if (r.ExitCode != 0) { throw new Exception("nugit failed"); } }
/// <summary> /// Delete a tag /// </summary> /// public void DeleteTag(GitRefNameComponent name) { Guard.NotNull(name, nameof(name)); var r = ProcessExtensions.ExecuteCaptured(false, false, null, "git", "-C", Path, "tag", "-d", name); if (r.ExitCode != 0) { throw new GitException("Delete tag failed", r); } }
/// <summary> /// Are there any uncommitted changes? /// </summary> /// /// <remarks> /// "Uncommitted changes" includes staged or unstaged changes of any kind. /// </remarks> /// /// <exception cref="GitException"> /// The check for uncommitted changes failed /// </exception> /// public bool HasUncommittedChanges() { var r = ProcessExtensions.ExecuteCaptured(false, false, null, "git", "-C", Path, "status", "--porcelain"); if (r.ExitCode != 0) { throw new GitException("Uncommitted changes check failed", r); } return(r.CombinedOutput.Trim() != ""); }
public void Uses_Specified_WorkingDirectory() { var here = Path.GetFullPath(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location)); var testWorkingDirectory = Path.Combine(here, "testworkingdirectory"); Directory.CreateDirectory(testWorkingDirectory); var result = ProcessExtensions.ExecuteCaptured(true, true, testWorkingDirectory, TestExe, "workingdirectory"); result.StandardOutput.Trim().ShouldBe(testWorkingDirectory); }
/// <summary> /// Commit staged changes /// </summary> /// public void Commit(string message) { Guard.Required(message, nameof(message)); var r = ProcessExtensions.ExecuteCaptured(false, false, null, "git", "-C", Path, "commit", "-m", message); if (r.ExitCode != 0) { throw new GitException("Commit failed", r); } }
/// <summary> /// Create a branch /// </summary> /// public void CreateBranch(GitRefNameComponent name, GitRev target) { Guard.NotNull(name, nameof(name)); Guard.NotNull(target, nameof(target)); var r = ProcessExtensions.ExecuteCaptured(false, false, null, "git", "-C", Path, "branch", name, target); if (r.ExitCode != 0) { throw new GitException("Create branch failed", r); } }
/// <summary> /// Get a symbolic ref's target /// </summary> /// /// <returns> /// The name of the symbolic ref's target /// - OR - /// <c>null</c> if the ref is not symbolic /// - OR - /// <c>null</c> if the ref doesn't exist /// </returns> /// public GitFullRefName FindSymbolicRefTarget(GitFullRefName name) { Guard.NotNull(name, nameof(name)); var r = ProcessExtensions.ExecuteCaptured(false, false, null, "git", "-C", Path, "symbolic-ref", name); if (r.ExitCode != 0) { return(null); } return(new GitFullRefName(r.StandardOutput.Trim())); }
/// <summary> /// Get list of remote branches and the commit ids they point to /// </summary> /// public IEnumerable <GitRef> GetRemoteBranches() { var r = ProcessExtensions.ExecuteCaptured(false, false, null, "git", "-C", Path, "ls-remote", "--heads"); switch (r.ExitCode) { case 0: return(ParseRefLines(StringExtensions.SplitLines(r.StandardOutput))); default: throw new GitException("Get remote branches failed", r); } }
/// <summary> /// Resolve a rev to a commit sha1 /// </summary> /// public GitSha1 GetCommitId(GitRev rev) { Guard.NotNull(rev, nameof(rev)); var r = ProcessExtensions.ExecuteCaptured(false, false, null, "git", "-C", Path, "rev-parse", "-q", "--verify", $"{rev}^{{commit}}"); if (r.ExitCode != 0) { throw new GitException("Resolve rev to commit sha1 failed", r); } return(new GitSha1(r.StandardOutput.Trim())); }
/// <summary> /// Get list of tags and the commit ids they point to /// </summary> /// public IEnumerable <GitRef> GetTags() { var r = ProcessExtensions.ExecuteCaptured(false, false, null, "git", "-C", Path, "show-ref", "--tags", "-d"); switch (r.ExitCode) { case 0: case 1: return(ParseRefLines(StringExtensions.SplitLines(r.StandardOutput))); default: throw new GitException("Get tags failed", r); } }
/// <summary> /// Check out a particular commit /// </summary> /// /// <exception cref="InvalidOperationException"> /// The repository has uncommitted changes /// </exception> /// /// <exception cref="GitException"> /// The checkout operation failed /// </exception> /// public void Checkout(GitRev rev) { Guard.NotNull(rev, nameof(rev)); if (HasUncommittedChanges()) { throw new InvalidOperationException("Repository contains uncommitted changes"); } var r = ProcessExtensions.ExecuteCaptured(false, false, null, "git", "-C", Path, "checkout", rev); if (r.ExitCode != 0) { throw new GitException("Checkout failed", r); } }
/// <summary> /// Get the name of the currently-checked-out branch /// </summary> /// /// <returns> /// The name of the currently-checked out branch /// - OR - /// <c>null</c> if no branch is checked out /// </returns> /// public GitRefNameComponent GetBranch() { var r = ProcessExtensions.ExecuteCaptured(false, false, null, "git", "-C", Path, "rev-parse", "--abbrev-ref", "HEAD"); if (r.ExitCode != 0) { throw new GitException("Get current branch failed", r); } var branchName = r.StandardOutput.Trim(); if (branchName == "HEAD") { return(null); } return(new GitRefNameComponent(branchName)); }
/// <summary> /// Determine whether a file or directory within the repository is .gitignore'd /// </summary> /// public bool IsIgnored(string path) { Guard.NotNull(path, nameof(path)); Guard.NotWhiteSpaceOnly(path, nameof(path)); var r = ProcessExtensions.ExecuteCaptured(false, false, null, "git", "-C", Path, "check-ignore", "-q", path); switch (r.ExitCode) { case 0: return(true); case 1: return(false); default: throw new GitException("check-ignore failed", r); } }
/// <summary> /// Is one commit the ancestor of another? /// </summary> /// public bool IsAncestor(GitRev ancestor, GitRev descendent) { Guard.NotNull(ancestor, nameof(ancestor)); Guard.NotNull(descendent, nameof(descendent)); var r = ProcessExtensions.ExecuteCaptured(false, false, null, "git", "-C", Path, "merge-base", "--is-ancestor", ancestor, descendent); switch (r.ExitCode) { case 0: return(true); case 1: return(false); default: throw new GitException("merge-base --is-ancestor failed", r); } }
/// <summary> /// Push branches or tags to a remote /// </summary> /// /// <param name="refs"> /// Names of branches and/or tags to push /// </param> /// /// <param name="remote"> /// Name of remote (default "origin") /// </param> /// /// <param name="dryRun"> /// Don't actually do anything, just show what would be done /// </param> /// /// <param name="echoOutput"> /// Echo Git command output as it runs /// </param> /// /// <returns> /// Git command output /// </returns> /// public string Push( IEnumerable <GitFullRefName> refs, string remote = "origin", bool dryRun = false, bool echoOutput = false) { Guard.NotNull(refs, nameof(refs)); Guard.NotNull(remote, nameof(remote)); Guard.NotWhiteSpaceOnly(remote, nameof(remote)); if (!refs.Any()) { return(""); } var args = new List <string>() { "-C", Path, "push", "--atomic" }; if (dryRun) { args.Add("--dry-run"); } args.Add(remote); args.AddRange(refs.Select(r => r.ToString())); var result = ProcessExtensions.ExecuteCaptured(false, echoOutput, null, "git", args.ToArray()); if (result.ExitCode != 0) { throw new GitException("Push failed", result); } return(result.CombinedOutput); }
/// <summary> /// Initialise a new Git repository /// </summary> /// /// <remarks> /// If the specified <paramref name="path"/> doesn't exist, it is created /// </remarks> /// /// <param name="path"> /// Path to new repository /// </param> /// /// <returns> /// The newly-initialised repository /// </returns> /// /// <exception cref="InvalidOperationException"> /// The specified <paramref name="path"/> is already a Git repository /// </exception> /// public static GitRepository Init(string path) { Guard.Required(path, nameof(path)); path = IOPath.GetFullPath(path); if (!Directory.Exists(path)) { Directory.CreateDirectory(path); } if (IsRepository(path)) { throw new InvalidOperationException("Path is already a Git repository"); } var r = ProcessExtensions.ExecuteCaptured(false, false, null, "git", "-C", path, "init"); if (r.ExitCode != 0) { throw new GitException("Initialising repository failed", r); } return(new GitRepository(path)); }
public void Non_Existent_WorkingDirectory_Fails() { Should.Throw <ArgumentException>(() => ProcessExtensions.ExecuteCaptured(true, true, "C:\\does\\not\\exist", TestExe, "workingdirectory")); }
public void Captures_CommandLine() { var result = ProcessExtensions.ExecuteCaptured(true, true, null, TestExe); result.CommandLine.ShouldNotBeNullOrWhiteSpace(); }
public void Uses_Current_WorkingDirectory_By_Default() { var result = ProcessExtensions.ExecuteCaptured(true, true, null, TestExe, "workingdirectory"); result.StandardOutput.Trim().ShouldBe(Path.GetFullPath(Environment.CurrentDirectory)); }
public void Relative_WorkingDirectory_Fails() { Should.Throw <ArgumentException>(() => ProcessExtensions.ExecuteCaptured(true, true, "relative\\path", TestExe, "workingdirectory")); }