Skip to content
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
10 changes: 9 additions & 1 deletion docfx/docs/shallow-cloning-agents.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,17 @@ See also [GitHub Copilot Coding Agent docs](https://docs.github.com/en/copilot/h

## Dependabot

**As of Nerdbank.GitVersioning v3.9, the git engine is automatically disabled when running under Dependabot**, eliminating the need for manual configuration in most cases.

Specifically, when the `DEPENDABOT` environment variable is set to `true` (case-insensitive) and the `NBGV_GitEngine` environment variable is **not** set, Nerdbank.GitVersioning automatically behaves as if `NBGV_GitEngine=Disabled`. This ensures that Dependabot runs succeed without any additional setup.

If you need to override this behavior for any reason, you can explicitly set the `NBGV_GitEngine` environment variable to your desired value, which will take precedence over the automatic Dependabot detection.

### Background

Dependabot does not yet allow configuring custom environment variables for its runtime environment.
Consider up-voting [this issue](https://github.com/dependabot/dependabot-core/issues/4660).
Be sure to vote up the top-level issue description as that tends to be the tally that maintainers pay attention to.
But you may also upvote [this particular comment](https://github.com/dependabot/dependabot-core/issues/4660#issuecomment-3170935213) that describes our use case.

There is [a known workaround](https://github.com/dependabot/dependabot-core/issues/4660#issuecomment-3399907801) for the time being.
There is [a known workaround](https://github.com/dependabot/dependabot-core/issues/4660#issuecomment-3399907801), but with the automatic detection feature, this workaround should no longer be necessary for most users.
3 changes: 2 additions & 1 deletion src/NerdBank.GitVersioning/Commands/CloudCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,8 @@ public void SetBuildVariables(string projectDirectory, IEnumerable<string> metad
activeCloudBuild = CloudBuild.SupportedCloudBuilds[matchingIndex];
}

using var context = GitContext.Create(projectDirectory, engine: alwaysUseLibGit2 ? GitContext.Engine.ReadWrite : GitContext.Engine.ReadOnly);
GitContext.Engine engine = GitContext.GetEffectiveGitEngine(alwaysUseLibGit2 ? GitContext.Engine.ReadWrite : GitContext.Engine.ReadOnly);
using var context = GitContext.Create(projectDirectory, engine: engine);
var oracle = new VersionOracle(context, cloudBuild: activeCloudBuild);
if (metadata is not null)
{
Expand Down
58 changes: 58 additions & 0 deletions src/NerdBank.GitVersioning/GitContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,54 @@ public string RepoRelativeProjectDirectory
/// </summary>
protected string? DotGitPath { get; }

/// <summary>
/// Gets the effective git engine to use, taking into account automatic disabling for Dependabot.
/// This overload checks the NBGV_GitEngine environment variable and parses it automatically.
/// </summary>
/// <param name="defaultEngine">The engine to use if no environment variables dictate otherwise.</param>
/// <returns>The engine to use.</returns>
/// <remarks>
/// If the NBGV_GitEngine environment variable is set, it takes precedence.
/// Valid values are "LibGit2", "Managed", and "Disabled" (case-sensitive).
/// Unrecognized values are treated as if the variable was not set, maintaining backward compatibility.
/// Otherwise, if the DEPENDABOT environment variable is set to "true" (case-insensitive), returns <see cref="Engine.Disabled"/>.
/// Otherwise, returns <paramref name="defaultEngine"/>.
/// </remarks>
public static Engine GetEffectiveGitEngine(Engine defaultEngine = Engine.ReadOnly)
{
// If NBGV_GitEngine is set, respect that setting regardless of Dependabot
string? nbgvGitEngine = Environment.GetEnvironmentVariable("NBGV_GitEngine");
if (!string.IsNullOrEmpty(nbgvGitEngine))
{
// Parse the NBGV_GitEngine value
if (string.Equals(nbgvGitEngine, "LibGit2", StringComparison.Ordinal))
{
return Engine.ReadWrite;
}
else if (string.Equals(nbgvGitEngine, "Disabled", StringComparison.Ordinal))
{
return Engine.Disabled;
}
else if (string.Equals(nbgvGitEngine, "Managed", StringComparison.Ordinal))
{
return Engine.ReadOnly;
}

// If unrecognized value, fall through to default logic.
// This maintains backward compatibility where invalid environment variable values
// are silently ignored rather than causing build failures.
}

// If we're in a Dependabot environment and NBGV_GitEngine is not set, automatically disable the git engine
if (IsDependabotEnvironment())
{
return Engine.Disabled;
}

// Otherwise, use the default engine
return defaultEngine;
}

/// <summary>
/// Creates a context for reading/writing version information at a given path and committish.
/// </summary>
Expand Down Expand Up @@ -340,4 +388,14 @@ private static (string GitDirectory, string WorkingTreeDirectory)? FindGitDir(st

return null;
}

/// <summary>
/// Determines whether the current environment is running under Dependabot.
/// </summary>
/// <returns><see langword="true"/> if DEPENDABOT environment variable is set to "true" (case-insensitive); otherwise, <see langword="false"/>.</returns>
private static bool IsDependabotEnvironment()
{
string? dependabotEnvVar = Environment.GetEnvironmentVariable("DEPENDABOT");
return string.Equals(dependabotEnvVar, "true", StringComparison.OrdinalIgnoreCase);
}
}
8 changes: 7 additions & 1 deletion src/Nerdbank.GitVersioning.Tasks/GetBuildVersion.cs
Original file line number Diff line number Diff line change
Expand Up @@ -226,9 +226,10 @@ protected override bool ExecuteInner()
Requires.Argument(!containsDotDotSlash, nameof(this.ProjectPathRelativeToGitRepoRoot), "Path must not use ..\\");
}

GitContext.Engine engine = GitContext.Engine.ReadOnly;
GitContext.Engine engine;
if (!string.IsNullOrWhiteSpace(this.GitEngine))
{
// MSBuild property GitEngine takes precedence over environment variables
engine = this.GitEngine switch
{
"Managed" => GitContext.Engine.ReadOnly,
Expand All @@ -237,6 +238,11 @@ protected override bool ExecuteInner()
_ => throw new ArgumentException("GitEngine property must be set to either \"Disabled\", \"Managed\" or \"LibGit2\" or left empty."),
};
}
else
{
// Use environment variable logic (NBGV_GitEngine and DEPENDABOT)
engine = GitContext.GetEffectiveGitEngine();
}

ICloudBuild cloudBuild = CloudBuild.Active;
this.Log.LogMessage(MessageImportance.Low, "Cloud build provider: {0}", cloudBuild?.GetType().Name ?? "None");
Expand Down
13 changes: 12 additions & 1 deletion src/nbgv/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -392,6 +392,17 @@ private static void PrintException(Exception ex)
}
}

/// <summary>
/// Gets the effective git engine to use based on environment variables and command settings.
/// </summary>
/// <param name="preferReadWrite">Whether to prefer ReadWrite (LibGit2) engine when not explicitly specified.</param>
/// <returns>The engine to use.</returns>
private static GitContext.Engine GetEffectiveGitEngine(bool preferReadWrite = false)
{
// Use the shared logic from GitContext which handles both NBGV_GitEngine and DEPENDABOT env vars
return GitContext.GetEffectiveGitEngine(preferReadWrite ? GitContext.Engine.ReadWrite : GitContext.Engine.ReadOnly);
}

private static int MainInner(string[] args)
{
try
Expand Down Expand Up @@ -588,7 +599,7 @@ private static Task<int> OnGetVersionCommand(string project, string[] metadata,

string searchPath = GetSpecifiedOrCurrentDirectoryPath(project);

using var context = GitContext.Create(searchPath, engine: AlwaysUseLibGit2 ? GitContext.Engine.ReadWrite : GitContext.Engine.ReadOnly);
using var context = GitContext.Create(searchPath, engine: GetEffectiveGitEngine(preferReadWrite: AlwaysUseLibGit2));
if (!context.IsRepository)
{
Console.Error.WriteLine("No git repo found at or above: \"{0}\"", searchPath);
Expand Down
98 changes: 98 additions & 0 deletions test/Nerdbank.GitVersioning.Tests/GitContextTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -189,4 +189,102 @@ public void HeadCanonicalName_PackedHead()
this.Context = this.CreateGitContext(Path.Combine(expandedRepo.RepoPath));
Assert.Equal("refs/heads/main", this.Context.HeadCanonicalName);
}

[Fact]
public void GetEffectiveGitEngine_DefaultBehavior()
{
// Arrange: Clear both environment variables
var originalDependabot = Environment.GetEnvironmentVariable("DEPENDABOT");
var originalNbgvGitEngine = Environment.GetEnvironmentVariable("NBGV_GitEngine");
try
{
Environment.SetEnvironmentVariable("DEPENDABOT", null);
Environment.SetEnvironmentVariable("NBGV_GitEngine", null);

// Act & Assert: With no environment variables, should return default ReadOnly
Assert.Equal(GitContext.Engine.ReadOnly, GitContext.GetEffectiveGitEngine());
Assert.Equal(GitContext.Engine.ReadWrite, GitContext.GetEffectiveGitEngine(GitContext.Engine.ReadWrite));
}
finally
{
Environment.SetEnvironmentVariable("DEPENDABOT", originalDependabot);
Environment.SetEnvironmentVariable("NBGV_GitEngine", originalNbgvGitEngine);
}
}

[Theory]
[InlineData("true")]
[InlineData("TRUE")]
[InlineData("True")]
public void GetEffectiveGitEngine_DependabotEnvironment_DisablesEngine(string dependabotValue)
{
// Arrange: Set DEPENDABOT=true and clear NBGV_GitEngine
var originalDependabot = Environment.GetEnvironmentVariable("DEPENDABOT");
var originalNbgvGitEngine = Environment.GetEnvironmentVariable("NBGV_GitEngine");
try
{
Environment.SetEnvironmentVariable("DEPENDABOT", dependabotValue);
Environment.SetEnvironmentVariable("NBGV_GitEngine", null);

// Act & Assert: Should return Disabled regardless of requested engine
Assert.Equal(GitContext.Engine.Disabled, GitContext.GetEffectiveGitEngine());
Assert.Equal(GitContext.Engine.Disabled, GitContext.GetEffectiveGitEngine(GitContext.Engine.ReadOnly));
Assert.Equal(GitContext.Engine.Disabled, GitContext.GetEffectiveGitEngine(GitContext.Engine.ReadWrite));
}
finally
{
Environment.SetEnvironmentVariable("DEPENDABOT", originalDependabot);
Environment.SetEnvironmentVariable("NBGV_GitEngine", originalNbgvGitEngine);
}
}

[Theory]
[InlineData("false")]
[InlineData("False")]
[InlineData("0")]
[InlineData("")]
public void GetEffectiveGitEngine_DependabotNotTrue_UsesDefault(string dependabotValue)
{
// Arrange: Set DEPENDABOT to non-true value and clear NBGV_GitEngine
var originalDependabot = Environment.GetEnvironmentVariable("DEPENDABOT");
var originalNbgvGitEngine = Environment.GetEnvironmentVariable("NBGV_GitEngine");
try
{
Environment.SetEnvironmentVariable("DEPENDABOT", dependabotValue);
Environment.SetEnvironmentVariable("NBGV_GitEngine", null);

// Act & Assert: Should use default behavior
Assert.Equal(GitContext.Engine.ReadOnly, GitContext.GetEffectiveGitEngine());
Assert.Equal(GitContext.Engine.ReadWrite, GitContext.GetEffectiveGitEngine(GitContext.Engine.ReadWrite));
}
finally
{
Environment.SetEnvironmentVariable("DEPENDABOT", originalDependabot);
Environment.SetEnvironmentVariable("NBGV_GitEngine", originalNbgvGitEngine);
}
}

[Theory]
[InlineData("LibGit2", GitContext.Engine.ReadWrite)]
[InlineData("Managed", GitContext.Engine.ReadOnly)]
[InlineData("Disabled", GitContext.Engine.Disabled)]
public void GetEffectiveGitEngine_NbgvGitEngineOverridesDependabot(string nbgvValue, GitContext.Engine expectedEngine)
{
// Arrange: Set both DEPENDABOT and NBGV_GitEngine
var originalDependabot = Environment.GetEnvironmentVariable("DEPENDABOT");
var originalNbgvGitEngine = Environment.GetEnvironmentVariable("NBGV_GitEngine");
try
{
Environment.SetEnvironmentVariable("DEPENDABOT", "true");
Environment.SetEnvironmentVariable("NBGV_GitEngine", nbgvValue);

// Act & Assert: NBGV_GitEngine should take precedence and be parsed correctly
Assert.Equal(expectedEngine, GitContext.GetEffectiveGitEngine());
}
finally
{
Environment.SetEnvironmentVariable("DEPENDABOT", originalDependabot);
Environment.SetEnvironmentVariable("NBGV_GitEngine", originalNbgvGitEngine);
}
}
}
Loading