diff --git a/docs/input/docs/reference/requirements.md b/docs/input/docs/reference/requirements.md index 3d950f4e6f..68acfb00d5 100644 --- a/docs/input/docs/reference/requirements.md +++ b/docs/input/docs/reference/requirements.md @@ -14,8 +14,9 @@ build server, needs to adhere to the below requirements. ### Unshallow -The repository needs to be an [unshallow][git-unshallow] clone. This means -that the `fetch-depth` in GitHub Actions needs to be set to `0`, for instance. +The repository should be an [unshallow][git-unshallow] clone. This means +that the `fetch-depth` in GitHub Actions should set to `0`, unless +the `allowshallow` flag is used. Check with your [build server][build-servers] to see how it can be configured appropriately. diff --git a/docs/input/docs/usage/cli/arguments.md b/docs/input/docs/usage/cli/arguments.md index 8b1b8ea5ea..b503a1f899 100644 --- a/docs/input/docs/usage/cli/arguments.md +++ b/docs/input/docs/usage/cli/arguments.md @@ -50,6 +50,10 @@ GitVersion [path] Currently supported config overrides: tag-prefix /nocache Bypasses the cache, result will not be written to the cache. /nonormalize Disables normalize step on a build server. + /allowshallow Allows GitVersion to run on a shallow clone. + This is not recommended, but can be used if you are sure + that the shallow clone contains all the information needed + to calculate the version. /verbosity Specifies the amount of information to be displayed. (Quiet, Minimal, Normal, Verbose, Diagnostic) Default is Normal diff --git a/docs/input/docs/usage/msbuild.md b/docs/input/docs/usage/msbuild.md index 9d812f6a80..5b3c258173 100644 --- a/docs/input/docs/usage/msbuild.md +++ b/docs/input/docs/usage/msbuild.md @@ -18,8 +18,8 @@ version information that is compiled into the resulting artifact. Since version 6.0 only MSBuild running on .NET Core (`dotnet msbuild`) is supported. Unfortunately, up until at least Visual Studio 2022 17.11, Visual Studio runs all builds -using the .NET Framework version of MSBuild, and therefore **Visual Studio is not supported**. -For more information see [this discussion](https://github.com/GitTools/GitVersion/discussions/4130). +using the .NET Framework version of MSBuild, and therefore **Visual Studio is not supported**. +For more information see [this discussion](https://github.com/GitTools/GitVersion/discussions/4130). ## TL;DR @@ -261,7 +261,9 @@ There are properties that correspond to certain In particular, setting `GitVersion_NoFetchEnabled` to `true` disables `git fetch` during version calculation, setting `GitVersion_NoNormalizeEnabled` to `true` disables normalize step on a build server, setting `GitVersion_NoCacheEnabled` to `true` -makes GetVersion ignore cache. All the rest command line arguments can be passed via +makes GetVersion ignore cache, setting `GitVersion_AllowShallowEnabled` to `true` +does not mandate a full clone of the repository to determine the version. +All the rest command line arguments can be passed via `GitVersion_CommandLineArguments` variable. ## My Git repository requires authentication. What should I do? diff --git a/src/GitVersion.App.Tests/ArgumentParserTests.cs b/src/GitVersion.App.Tests/ArgumentParserTests.cs index 5e53ac63a0..42e7c36304 100644 --- a/src/GitVersion.App.Tests/ArgumentParserTests.cs +++ b/src/GitVersion.App.Tests/ArgumentParserTests.cs @@ -629,6 +629,13 @@ public void NoNormalizeTrueWhenDefined() arguments.NoNormalize.ShouldBe(true); } + [Test] + public void AllowshallowTrueWhenDefined() + { + var arguments = this.argumentParser.ParseArguments("-allowshallow"); + arguments.AllowShallow.ShouldBe(true); + } + [Test] public void OtherArgumentsCanBeParsedBeforeNofetch() { @@ -653,18 +660,45 @@ public void OtherArgumentsCanBeParsedBeforeNocache() arguments.NoCache.ShouldBe(true); } - [TestCase("-nofetch -nonormalize -nocache")] - [TestCase("-nofetch -nocache -nonormalize")] - [TestCase("-nocache -nofetch -nonormalize")] - [TestCase("-nocache -nonormalize -nofetch")] - [TestCase("-nonormalize -nocache -nofetch")] - [TestCase("-nonormalize -nofetch -nocache")] + [Test] + public void OtherArgumentsCanBeParsedBeforeAllowshallow() + { + var arguments = this.argumentParser.ParseArguments("targetpath -allowshallow"); + arguments.TargetPath.ShouldBe("targetpath"); + arguments.AllowShallow.ShouldBe(true); + } + + [TestCase("-nofetch -nonormalize -nocache -allowshallow")] + [TestCase("-nofetch -nonormalize -allowshallow -nocache")] + [TestCase("-nofetch -nocache -nonormalize -allowshallow")] + [TestCase("-nofetch -nocache -allowshallow -nonormalize")] + [TestCase("-nofetch -allowshallow -nonormalize -nocache")] + [TestCase("-nofetch -allowshallow -nocache -nonormalize")] + [TestCase("-nonormalize -nofetch -nocache -allowshallow")] + [TestCase("-nonormalize -nofetch -allowshallow -nocache")] + [TestCase("-nonormalize -nocache -nofetch -allowshallow")] + [TestCase("-nonormalize -nocache -allowshallow -nofetch")] + [TestCase("-nonormalize -allowshallow -nofetch -nocache")] + [TestCase("-nonormalize -allowshallow -nocache -nofetch")] + [TestCase("-nocache -nofetch -nonormalize -allowshallow")] + [TestCase("-nocache -nofetch -allowshallow -nonormalize")] + [TestCase("-nocache -nonormalize -nofetch -allowshallow")] + [TestCase("-nocache -nonormalize -allowshallow -nofetch")] + [TestCase("-nocache -allowshallow -nofetch -nonormalize")] + [TestCase("-nocache -allowshallow -nonormalize -nofetch")] + [TestCase("-allowshallow -nofetch -nonormalize -nocache")] + [TestCase("-allowshallow -nofetch -nocache -nonormalize")] + [TestCase("-allowshallow -nonormalize -nofetch -nocache")] + [TestCase("-allowshallow -nonormalize -nocache -nofetch")] + [TestCase("-allowshallow -nocache -nofetch -nonormalize")] + [TestCase("-allowshallow -nocache -nonormalize -nofetch")] public void SeveralSwitchesCanBeParsed(string commandLineArgs) { var arguments = this.argumentParser.ParseArguments(commandLineArgs); arguments.NoCache.ShouldBe(true); arguments.NoNormalize.ShouldBe(true); arguments.NoFetch.ShouldBe(true); + arguments.AllowShallow.ShouldBe(true); } [Test] diff --git a/src/GitVersion.App.Tests/HelpWriterTests.cs b/src/GitVersion.App.Tests/HelpWriterTests.cs index bf962ea97f..9005872c44 100644 --- a/src/GitVersion.App.Tests/HelpWriterTests.cs +++ b/src/GitVersion.App.Tests/HelpWriterTests.cs @@ -46,6 +46,7 @@ public void AllArgsAreInHelp() { nameof(Arguments.NoCache), "/nocache" }, { nameof(Arguments.NoFetch), "/nofetch" }, { nameof(Arguments.NoNormalize), "/nonormalize" }, + { nameof(Arguments.AllowShallow), "/allowshallow" }, }; var helpText = string.Empty; diff --git a/src/GitVersion.App/ArgumentParser.cs b/src/GitVersion.App/ArgumentParser.cs index d22b63ee31..1f85a1b3d2 100644 --- a/src/GitVersion.App/ArgumentParser.cs +++ b/src/GitVersion.App/ArgumentParser.cs @@ -281,6 +281,12 @@ private static bool ParseSwitches(Arguments arguments, string? name, IReadOnlyLi return true; } + if (name.IsSwitch("allowshallow")) + { + arguments.AllowShallow = true; + return true; + } + if (name.IsSwitch("verbosity")) { ParseVerbosity(arguments, value); diff --git a/src/GitVersion.App/ArgumentParserExtensions.cs b/src/GitVersion.App/ArgumentParserExtensions.cs index 493052fa06..7a5bbfb006 100644 --- a/src/GitVersion.App/ArgumentParserExtensions.cs +++ b/src/GitVersion.App/ArgumentParserExtensions.cs @@ -69,7 +69,7 @@ public static bool IsSwitch(this string? value, string switchName) public static bool ArgumentRequiresValue(this string argument, int argumentIndex) { - var booleanArguments = new[] { "updateassemblyinfo", "ensureassemblyinfo", "nofetch", "nonormalize", "nocache" }; + var booleanArguments = new[] { "updateassemblyinfo", "ensureassemblyinfo", "nofetch", "nonormalize", "nocache", "allowshallow" }; var argumentMightRequireValue = !booleanArguments.Contains(argument[1..], StringComparer.OrdinalIgnoreCase); diff --git a/src/GitVersion.App/Arguments.cs b/src/GitVersion.App/Arguments.cs index 5d619a5248..ee8b86a85c 100644 --- a/src/GitVersion.App/Arguments.cs +++ b/src/GitVersion.App/Arguments.cs @@ -25,6 +25,7 @@ internal class Arguments public bool NoFetch; public bool NoCache; public bool NoNormalize; + public bool AllowShallow; public string? LogFilePath; public string? ShowVariable; @@ -77,7 +78,8 @@ public GitVersionOptions ToOptions() { NoFetch = NoFetch, NoCache = NoCache, - NoNormalize = NoNormalize + NoNormalize = NoNormalize, + AllowShallow = AllowShallow, }, WixInfo = diff --git a/src/GitVersion.Core.Tests/Core/GitVersionExecutorTests.cs b/src/GitVersion.Core.Tests/Core/GitVersionExecutorTests.cs index 77521b0fcf..0852be5681 100644 --- a/src/GitVersion.Core.Tests/Core/GitVersionExecutorTests.cs +++ b/src/GitVersion.Core.Tests/Core/GitVersionExecutorTests.cs @@ -597,6 +597,79 @@ public void CalculateVersionVariables_ShallowFetch_ThrowException() exception?.Message.ShouldBe("Repository is a shallow clone. Git repositories must contain the full history. See https://gitversion.net/docs/reference/requirements#unshallow for more info."); } + [Test] + public void CalculateVersionVariables_ShallowFetch_WithAllowShallow_ShouldNotThrowException() + { + // Setup + using var fixture = new RemoteRepositoryFixture(); + fixture.LocalRepositoryFixture.MakeShallow(); + + using var worktreeFixture = new LocalRepositoryFixture(new(fixture.LocalRepositoryFixture.RepositoryPath)); + var gitVersionOptions = new GitVersionOptions + { + WorkingDirectory = worktreeFixture.RepositoryPath, + Settings = { AllowShallow = true } + }; + + var environment = new TestEnvironment(); + environment.SetEnvironmentVariable(AzurePipelines.EnvironmentVariableName, "true"); + + this.sp = GetServiceProvider(gitVersionOptions, environment: environment); + + sp.DiscoverRepository(); + + var sut = sp.GetRequiredService(); + + // Execute + var version = sut.CalculateVersionVariables(); + + // Verify + version.ShouldNotBeNull(); + var commits = worktreeFixture.Repository.Head.Commits; + version.Sha.ShouldBe(commits.First().Sha); + } + + [Test] + public void CalculateVersionVariables_WithLimitedCloneDepth_AndAllowShallowTrue_ShouldCalculateVersionCorrectly() + { + // Setup + using var fixture = new RemoteRepositoryFixture(); + fixture.LocalRepositoryFixture.MakeShallow(); + + fixture.LocalRepositoryFixture.Repository.MakeACommit("Initial commit"); + fixture.LocalRepositoryFixture.Repository.MakeATaggedCommit("1.0.0"); + var latestCommit = fixture.LocalRepositoryFixture.Repository.MakeACommit("+semver:major"); + + using var worktreeFixture = new LocalRepositoryFixture(new(fixture.LocalRepositoryFixture.RepositoryPath)); + + var gitVersionOptions = new GitVersionOptions + { + WorkingDirectory = worktreeFixture.RepositoryPath, + Settings = { AllowShallow = true } + }; + + var environment = new TestEnvironment(); + environment.SetEnvironmentVariable(AzurePipelines.EnvironmentVariableName, "true"); + + this.sp = GetServiceProvider(gitVersionOptions, environment: environment); + sp.DiscoverRepository(); + var sut = sp.GetRequiredService(); + + // Execute + var version = sut.CalculateVersionVariables(); + + // Verify + version.ShouldNotBeNull(); + + // Verify that the correct commit is used + version.Sha.ShouldBe(latestCommit.Sha); + version.MajorMinorPatch.ShouldBe("2.0.0"); + + // Verify repository is still recognized as shallow + var repository = this.sp.GetRequiredService(); + repository.IsShallow.ShouldBeTrue("Repository should still be shallow after version calculation"); + } + private string GetWorktreePath(EmptyRepositoryFixture fixture) { var worktreePath = FileSystemHelper.Path.Combine(this.fileSystem.Directory.GetParent(fixture.RepositoryPath)?.FullName, Guid.NewGuid().ToString()); diff --git a/src/GitVersion.Core/Core/GitPreparer.cs b/src/GitVersion.Core/Core/GitPreparer.cs index adcad5de05..77f6b27346 100644 --- a/src/GitVersion.Core/Core/GitPreparer.cs +++ b/src/GitVersion.Core/Core/GitPreparer.cs @@ -190,7 +190,14 @@ private void NormalizeGitDirectory(bool noFetch, string? currentBranchName, bool if (this.repository.IsShallow) { - throw new WarningException("Repository is a shallow clone. Git repositories must contain the full history. See https://gitversion.net/docs/reference/requirements#unshallow for more info."); + if (this.options.Value.Settings.AllowShallow) + { + this.log.Info("Repository is a shallow clone. GitVersion will continue, but it is recommended to use a full clone for accurate versioning."); + } + else + { + throw new WarningException("Repository is a shallow clone. Git repositories must contain the full history. See https://gitversion.net/docs/reference/requirements#unshallow for more info."); + } } } diff --git a/src/GitVersion.Core/Options/Settings.cs b/src/GitVersion.Core/Options/Settings.cs index 58ded50c19..cbb9dabc8c 100644 --- a/src/GitVersion.Core/Options/Settings.cs +++ b/src/GitVersion.Core/Options/Settings.cs @@ -6,4 +6,5 @@ public record Settings public bool NoCache; public bool NoNormalize; public bool OnlyTrackedBranches = false; + public bool AllowShallow = false; } diff --git a/src/GitVersion.Core/PublicAPI.Shipped.txt b/src/GitVersion.Core/PublicAPI.Shipped.txt index 38ca63906a..27793f8f08 100644 --- a/src/GitVersion.Core/PublicAPI.Shipped.txt +++ b/src/GitVersion.Core/PublicAPI.Shipped.txt @@ -595,6 +595,7 @@ GitVersion.Settings.NoCache -> bool GitVersion.Settings.NoFetch -> bool GitVersion.Settings.NoNormalize -> bool GitVersion.Settings.OnlyTrackedBranches -> bool +GitVersion.Settings.AllowShallow -> bool GitVersion.VersionCalculation.BaseVersion GitVersion.VersionCalculation.BaseVersion.BaseVersion() -> void GitVersion.VersionCalculation.BaseVersion.BaseVersion(GitVersion.VersionCalculation.BaseVersionOperand! Operand) -> void diff --git a/src/GitVersion.MsBuild/msbuild/tools/GitVersion.MsBuild.props b/src/GitVersion.MsBuild/msbuild/tools/GitVersion.MsBuild.props index e1f335e940..c497718e77 100644 --- a/src/GitVersion.MsBuild/msbuild/tools/GitVersion.MsBuild.props +++ b/src/GitVersion.MsBuild/msbuild/tools/GitVersion.MsBuild.props @@ -11,20 +11,22 @@ false false false + false $(GitVersion_CommandLineArguments) -output file -outputfile "$(GitVersionOutputFile)" $(GitVersion_ToolArgments) -nofetch $(GitVersion_ToolArgments) -nonormalize $(GitVersion_ToolArgments) -nocache + $(GitVersion_ToolArgments) -allowshallow - true - + false