diff --git a/GitVersionCore.Tests/Fixtures/RepositoryFixtureBase.cs b/GitVersionCore.Tests/Fixtures/RepositoryFixtureBase.cs index 31a26b7b73..4237a11258 100644 --- a/GitVersionCore.Tests/Fixtures/RepositoryFixtureBase.cs +++ b/GitVersionCore.Tests/Fixtures/RepositoryFixtureBase.cs @@ -21,9 +21,9 @@ protected RepositoryFixtureBase(Func repoBuilder, Config co public bool IsForTrackedBranchOnly { private get; set; } - public void AssertFullSemver(string fullSemver, IRepository repository = null) + public void AssertFullSemver(string fullSemver, IRepository repository = null, string commitId = null) { - var gitVersionContext = new GitVersionContext(repository ?? Repository, configuration, IsForTrackedBranchOnly); + var gitVersionContext = new GitVersionContext(repository ?? Repository, configuration, IsForTrackedBranchOnly, commitId); var executeGitVersion = ExecuteGitVersion(gitVersionContext); var variables = VariableProvider.GetVariablesFor(executeGitVersion, gitVersionContext.Configuration.AssemblyVersioningScheme, diff --git a/GitVersionCore.Tests/IntegrationTests/DevelopScenarios.cs b/GitVersionCore.Tests/IntegrationTests/DevelopScenarios.cs index 9dc8e7f3f9..ccb4b888c0 100644 --- a/GitVersionCore.Tests/IntegrationTests/DevelopScenarios.cs +++ b/GitVersionCore.Tests/IntegrationTests/DevelopScenarios.cs @@ -5,6 +5,42 @@ [TestFixture] public class DevelopScenarios { + [Test] + public void WhenDevelopHasMultipleCommits_SpecifyExistingCommitId() + { + using (var fixture = new EmptyRepositoryFixture(new Config())) + { + fixture.Repository.MakeATaggedCommit("1.0.0"); + fixture.Repository.CreateBranch("develop").Checkout(); + + fixture.Repository.MakeACommit(); + fixture.Repository.MakeACommit(); + var thirdCommit = fixture.Repository.MakeACommit(); + fixture.Repository.MakeACommit(); + fixture.Repository.MakeACommit(); + + fixture.AssertFullSemver("1.1.0-unstable.3", commitId: thirdCommit.Sha); + } + } + + [Test] + public void WhenDevelopHasMultipleCommits_SpecifyNonExistingCommitId() + { + using (var fixture = new EmptyRepositoryFixture(new Config())) + { + fixture.Repository.MakeATaggedCommit("1.0.0"); + fixture.Repository.CreateBranch("develop").Checkout(); + + fixture.Repository.MakeACommit(); + fixture.Repository.MakeACommit(); + fixture.Repository.MakeACommit(); + fixture.Repository.MakeACommit(); + fixture.Repository.MakeACommit(); + + fixture.AssertFullSemver("1.1.0-unstable.5", commitId: "nonexistingcommitid"); + } + } + [Test] public void WhenDevelopBranchedFromTaggedCommitOnMasterVersionDoesNotChange() { diff --git a/GitVersionCore/GitVersionContext.cs b/GitVersionCore/GitVersionContext.cs index 3ad1f2d8a0..a4b875469f 100644 --- a/GitVersionCore/GitVersionContext.cs +++ b/GitVersionCore/GitVersionContext.cs @@ -11,12 +11,12 @@ public class GitVersionContext { readonly Config configuration; - public GitVersionContext(IRepository repository, Config configuration, bool isForTrackingBranchOnly = true) - : this(repository, repository.Head, configuration, isForTrackingBranchOnly) + public GitVersionContext(IRepository repository, Config configuration, bool isForTrackingBranchOnly = true, string commitId = null) + : this(repository, repository.Head, configuration, isForTrackingBranchOnly, commitId) { } - public GitVersionContext(IRepository repository, Branch currentBranch, Config configuration, bool onlyEvaluateTrackedBranches = true) + public GitVersionContext(IRepository repository, Branch currentBranch, Config configuration, bool onlyEvaluateTrackedBranches = true, string commitId = null) { Repository = repository; this.configuration = configuration; @@ -25,7 +25,24 @@ public GitVersionContext(IRepository repository, Branch currentBranch, Config co if (currentBranch == null) throw new InvalidOperationException("Need a branch to operate on"); - CurrentCommit = currentBranch.Tip; + if (!string.IsNullOrWhiteSpace(commitId)) + { + Logger.WriteInfo(string.Format("Searching for specific commit '{0}'", commitId)); + + var commit = repository.Commits.FirstOrDefault(c => string.Equals(c.Sha, commitId, StringComparison.OrdinalIgnoreCase)); + if (commit != null) + { + CurrentCommit = commit; + } + } + + if (CurrentCommit == null) + { + Logger.WriteWarning("No specific commit specified or found, falling back to latest commit on specified branch"); + + CurrentCommit = currentBranch.Tip; + } + if (currentBranch.IsDetachedHead()) { CurrentBranch = CurrentCommit.GetBranchesContainingCommit(repository, OnlyEvaluateTrackedBranches).OnlyOrDefault() ?? currentBranch; diff --git a/GitVersionExe.Tests/HelpWriterTests.cs b/GitVersionExe.Tests/HelpWriterTests.cs index d7142bc598..63fb99bad8 100644 --- a/GitVersionExe.Tests/HelpWriterTests.cs +++ b/GitVersionExe.Tests/HelpWriterTests.cs @@ -24,7 +24,7 @@ public void AllArgsAreInHelp() typeof(Arguments).GetFields() .Select(p => p.Name) .Where(p => IsNotInHelp(lookup, p, helpText)) - .Except(new[] { "Authentication" }) + .Except(new[] { "Authentication", "CommitId" }) .ShouldBeEmpty(); } diff --git a/GitVersionExe/ArgumentParser.cs b/GitVersionExe/ArgumentParser.cs index 3eb8047761..8e2717eb9d 100644 --- a/GitVersionExe/ArgumentParser.cs +++ b/GitVersionExe/ArgumentParser.cs @@ -108,6 +108,12 @@ public static Arguments ParseArguments(List commandLineArguments) continue; } + if (IsSwitch("c", name)) + { + arguments.CommitId = value; + continue; + } + if (IsSwitch("exec", name)) { arguments.Exec = value; @@ -198,6 +204,7 @@ public static Arguments ParseArguments(List commandLineArguments) throw new WarningException(string.Format("Could not parse command line parameter '{0}'.", name)); } + return arguments; } diff --git a/GitVersionExe/Arguments.cs b/GitVersionExe/Arguments.cs index e48363666e..4706c0158e 100644 --- a/GitVersionExe/Arguments.cs +++ b/GitVersionExe/Arguments.cs @@ -14,6 +14,7 @@ public Arguments() public string TargetUrl; public string TargetBranch; + public string CommitId; public bool Init; diff --git a/GitVersionExe/HelpWriter.cs b/GitVersionExe/HelpWriter.cs index 9965b18060..51d4bb6362 100644 --- a/GitVersionExe/HelpWriter.cs +++ b/GitVersionExe/HelpWriter.cs @@ -37,6 +37,7 @@ Specify name of AssemblyInfo file. Can also /updateAssemblyInfo GlobalAssemblyIn /b Name of the branch to use on the remote repository, must be used in combination with /url. /u Username in case authentication is required. /p Password in case authentication is required. + /c The commit id to check. If not specified, the latest available commit on the specified branch will be used. # Execute build args /exec Executes target executable making GitVersion variables available as environmental variables diff --git a/GitVersionExe/Program.cs b/GitVersionExe/Program.cs index 3ea379f9d3..93fc002112 100644 --- a/GitVersionExe/Program.cs +++ b/GitVersionExe/Program.cs @@ -96,7 +96,7 @@ static int Run() using (var repo = RepositoryLoader.GetRepo(gitDirectory)) { - var gitVersionContext = new GitVersionContext(repo, configuration); + var gitVersionContext = new GitVersionContext(repo, configuration, commitId: arguments.CommitId); var semanticVersion = versionFinder.FindVersion(gitVersionContext); var config = gitVersionContext.Configuration; variables = VariableProvider.GetVariablesFor(semanticVersion, config.AssemblyVersioningScheme, config.VersioningMode, config.ContinuousDeploymentFallbackTag, gitVersionContext.IsCurrentCommitTagged);