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

Add the credential environment configuration to the Git checkout command #4965

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
50 changes: 4 additions & 46 deletions src/Agent.Plugins/GitCliManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -195,7 +195,7 @@ public async Task<int> GitInit(AgentTaskPluginExecutionContext context, string r
}

// git fetch --tags --prune --progress --no-recurse-submodules [--depth=15] origin [+refs/pull/*:refs/remote/pull/*]
public async Task<int> GitFetch(AgentTaskPluginExecutionContext context, string repositoryPath, string remoteName, int fetchDepth, string fetchFilter, bool fetchTags, List<string> refSpec, string additionalCommandLine, CancellationToken cancellationToken)
public async Task<int> GitFetch(AgentTaskPluginExecutionContext context, string repositoryPath, string remoteName, int fetchDepth, IEnumerable<string> filters, bool fetchTags, List<string> refSpec, string additionalCommandLine, CancellationToken cancellationToken)
{
context.Debug($"Fetch git repository at: {repositoryPath} remote: {remoteName}.");
if (refSpec != null && refSpec.Count > 0)
Expand Down Expand Up @@ -233,50 +233,8 @@ public async Task<int> GitFetch(AgentTaskPluginExecutionContext context, string
// add --unshallow to convert the shallow repository to a complete repository
string depth = fetchDepth > 0 ? $"--depth={fetchDepth}" : (File.Exists(Path.Combine(repositoryPath, ".git", "shallow")) ? "--unshallow" : string.Empty);

// parse filter and only include valid options
List<string> filters = new List<String>();

if (AgentKnobs.UseFetchFilterInCheckoutTask.GetValue(context).AsBoolean())
{
List<string> splitFilter = fetchFilter.Split('+').Where(filter => !String.IsNullOrWhiteSpace(filter)).ToList();

foreach (string filter in splitFilter)
{
List<string> parsedFilter = filter.Split(':')
.Where(filter => !String.IsNullOrWhiteSpace(filter))
.Select(filter => filter.Trim())
.ToList();

if (parsedFilter.Count == 2)
{
switch (parsedFilter[0].ToLower())
{
case "tree":
// currently only supporting treeless filter
if (int.TryParse(parsedFilter[1], out int treeSize) && treeSize == 0)
{
filters.Add($"{parsedFilter[0]}:{treeSize}");
}
break;

case "blob":
// currently only supporting blobless filter
if (parsedFilter[1].Equals("none", StringComparison.OrdinalIgnoreCase))
{
filters.Add($"{parsedFilter[0]}:{parsedFilter[1]}");
}
break;

default:
// either invalid or unsupported git object
break;
}
}
}
}

//define options for fetch
string options = $"{forceTag} {tags} --prune {pruneTags} {progress} --no-recurse-submodules {remoteName} {depth} {String.Join(" ", filters.Select(filter => "--filter=" + filter))} {string.Join(" ", refSpec)}";
string options = $"{forceTag} {tags} --prune {pruneTags} {progress} --no-recurse-submodules {remoteName} {depth} {string.Join(" ", filters.Select(filter => "--filter=" + filter))} {string.Join(" ", refSpec)}";
int retryCount = 0;
int fetchExitCode = 0;
while (retryCount < 3)
Expand Down Expand Up @@ -363,7 +321,7 @@ public async Task<int> GitLFSFetch(AgentTaskPluginExecutionContext context, stri
}

// git checkout -f --progress <commitId/branch>
public async Task<int> GitCheckout(AgentTaskPluginExecutionContext context, string repositoryPath, string committishOrBranchSpec, CancellationToken cancellationToken)
public async Task<int> GitCheckout(AgentTaskPluginExecutionContext context, string repositoryPath, string committishOrBranchSpec, string additionalCommandLine, CancellationToken cancellationToken)
{
context.Debug($"Checkout {committishOrBranchSpec}.");

Expand All @@ -378,7 +336,7 @@ public async Task<int> GitCheckout(AgentTaskPluginExecutionContext context, stri
options = StringUtil.Format("--force {0}", committishOrBranchSpec);
}

return await ExecuteGitCommandAsync(context, repositoryPath, "checkout", options, cancellationToken);
return await ExecuteGitCommandAsync(context, repositoryPath, "checkout", options, additionalCommandLine, cancellationToken);
}

// git clean -ffdx
Expand Down
70 changes: 65 additions & 5 deletions src/Agent.Plugins/GitSourceProvider.cs
Original file line number Diff line number Diff line change
Expand Up @@ -718,8 +718,10 @@ public async Task GetSourceAsync(
await RemoveGitConfig(executionContext, gitCommandManager, targetPath, $"http.proxy", string.Empty);
}

List<string> additionalFetchArgs = new List<string>();
List<string> additionalLfsFetchArgs = new List<string>();
var additionalFetchFilterOptions = ParseFetchFilterOptions(executionContext, fetchFilter);
var additionalFetchArgs = new List<string>();
var additionalLfsFetchArgs = new List<string>();
var additionalCheckoutArgs = new List<string>();

// Force Git to HTTP/1.1. Otherwise IIS will reject large pushes to Azure Repos due to the large content-length header
// This is caused by these header limits - https://docs.microsoft.com/en-us/iis/configuration/system.webserver/security/requestfiltering/requestlimits/headerlimits/
Expand All @@ -738,6 +740,11 @@ public async Task GetSourceAsync(
string configKey = "http.extraheader";
string args = ComposeGitArgs(executionContext, gitCommandManager, configKey, username, password, useBearerAuthType);
additionalFetchArgs.Add(args);

if (additionalFetchFilterOptions.Any() && AgentKnobs.AddForceCredentialsToGitCheckout.GetValue(executionContext).AsBoolean())
{
additionalCheckoutArgs.Add(args);
}
}
else
{
Expand Down Expand Up @@ -899,7 +906,7 @@ public async Task GetSourceAsync(
}
}

int exitCode_fetch = await gitCommandManager.GitFetch(executionContext, targetPath, "origin", fetchDepth, fetchFilter, fetchTags, additionalFetchSpecs, string.Join(" ", additionalFetchArgs), cancellationToken);
int exitCode_fetch = await gitCommandManager.GitFetch(executionContext, targetPath, "origin", fetchDepth, additionalFetchFilterOptions, fetchTags, additionalFetchSpecs, string.Join(" ", additionalFetchArgs), cancellationToken);
if (exitCode_fetch != 0)
{
throw new InvalidOperationException($"Git fetch failed with exit code: {exitCode_fetch}");
Expand All @@ -911,7 +918,7 @@ public async Task GetSourceAsync(
if (fetchByCommit && !string.IsNullOrEmpty(sourceVersion))
{
List<string> commitFetchSpecs = new List<string>() { $"+{sourceVersion}" };
exitCode_fetch = await gitCommandManager.GitFetch(executionContext, targetPath, "origin", fetchDepth, fetchFilter, fetchTags, commitFetchSpecs, string.Join(" ", additionalFetchArgs), cancellationToken);
exitCode_fetch = await gitCommandManager.GitFetch(executionContext, targetPath, "origin", fetchDepth, additionalFetchFilterOptions, fetchTags, commitFetchSpecs, string.Join(" ", additionalFetchArgs), cancellationToken);
if (exitCode_fetch != 0)
{
throw new InvalidOperationException($"Git fetch failed with exit code: {exitCode_fetch}");
Expand Down Expand Up @@ -963,7 +970,7 @@ public async Task GetSourceAsync(
}

// Finally, checkout the sourcesToBuild (if we didn't find a valid git object this will throw)
int exitCode_checkout = await gitCommandManager.GitCheckout(executionContext, targetPath, sourcesToBuild, cancellationToken);
int exitCode_checkout = await gitCommandManager.GitCheckout(executionContext, targetPath, sourcesToBuild, string.Join(" ", additionalCheckoutArgs), cancellationToken);
if (exitCode_checkout != 0)
{
// local repository is shallow repository, checkout may fail due to lack of commits history.
Expand Down Expand Up @@ -1374,6 +1381,59 @@ private async Task<bool> IsRepositoryOriginUrlMatch(AgentTaskPluginExecutionCont
}
}

private IEnumerable<string> ParseFetchFilterOptions(AgentTaskPluginExecutionContext context, string fetchFilter)
{
if (!AgentKnobs.UseFetchFilterInCheckoutTask.GetValue(context).AsBoolean())
{
return Enumerable.Empty<string>();
}

if (string.IsNullOrEmpty(fetchFilter))
{
return Enumerable.Empty<string>();
}

// parse filter and only include valid options
var filters = new List<string>();
var splitFilter = fetchFilter.Split('+').Where(filter => !string.IsNullOrWhiteSpace(filter)).ToList();

foreach (string filter in splitFilter)
{
var parsedFilter = filter.Split(':')
.Where(filter => !string.IsNullOrWhiteSpace(filter))
.Select(filter => filter.Trim())
.ToList();

if (parsedFilter.Count == 2)
{
switch (parsedFilter[0].ToLower())
{
case "tree":
// currently only supporting treeless filter
if (int.TryParse(parsedFilter[1], out int treeSize) && treeSize == 0)
{
filters.Add($"{parsedFilter[0]}:{treeSize}");
}
break;

case "blob":
// currently only supporting blobless filter
if (parsedFilter[1].Equals("none", StringComparison.OrdinalIgnoreCase))
{
filters.Add($"{parsedFilter[0]}:{parsedFilter[1]}");
}
break;

default:
// either invalid or unsupported git object
break;
}
}
}

return filters;
}

private async Task RunGitStatusIfSystemDebug(AgentTaskPluginExecutionContext executionContext, GitCliManager gitCommandManager, string targetPath)
{
if (executionContext.IsSystemDebugTrue())
Expand Down
7 changes: 7 additions & 0 deletions src/Agent.Sdk/Knob/AgentKnobs.cs
Original file line number Diff line number Diff line change
Expand Up @@ -759,6 +759,13 @@ public class AgentKnobs
new PipelineFeatureSource("UsePSScriptWrapper"),
new BuiltInDefaultKnobSource("false"));

public static readonly Knob AddForceCredentialsToGitCheckout = new Knob(
nameof(AddForceCredentialsToGitCheckout),
"If true, the credentials will be forcibly added to the Git checkout command.",
new RuntimeKnobSource("ADD_FORCE_CREDENTIALS_TO_GIT_CHECKOUT"),
new PipelineFeatureSource(nameof(AddForceCredentialsToGitCheckout)),
new BuiltInDefaultKnobSource("false"));

public static readonly Knob InstallLegacyTfExe = new Knob(
nameof(InstallLegacyTfExe),
"If true, the agent will install the legacy versions of TF, vstsom and vstshost",
Expand Down
Loading