Skip to content

Commit

Permalink
Merge pull request #201 from Microsoft/users/tihuang/defaultworkingfo…
Browse files Browse the repository at this point in the history
…lder

set working folder to system.defaultworkingdirectory for node handler.
  • Loading branch information
TingluoHuang committed May 25, 2016
2 parents f7ce567 + 14fb9a1 commit 043f11f
Show file tree
Hide file tree
Showing 7 changed files with 80 additions and 157 deletions.
115 changes: 59 additions & 56 deletions src/Agent.Worker/Build/GitCommandManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,15 @@
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
using System.IO;

namespace Microsoft.VisualStudio.Services.Agent.Worker.Build
{
[ServiceLocator(Default = typeof(GitCommandManager))]
public interface IGitCommandManager : IAgentService
{
string GitPath { get; set; }

Version Version { get; set; }

string GitHttpUserAgent { get; set; }
// setup git execution info, git location, version, useragent, execpath
Task LoadGitExecutionInfo(IExecutionContext context);

// git init <LocalDir>
Task<int> GitInit(IExecutionContext context, string repositoryPath);
Expand Down Expand Up @@ -56,7 +54,7 @@ public interface IGitCommandManager : IAgentService

// git config --unset-all <key>
Task<int> GitConfigUnset(IExecutionContext context, string repositoryPath, string configKey);

// git config gc.auto 0
Task<int> GitDisableAutoGC(IExecutionContext context, string repositoryPath);

Expand All @@ -66,20 +64,36 @@ public interface IGitCommandManager : IAgentService

public class GitCommandManager : AgentService, IGitCommandManager
{
private readonly Dictionary<string, Dictionary<Version, string>> _gitCommands = new Dictionary<string, Dictionary<Version, string>>(StringComparer.OrdinalIgnoreCase)
private string _gitHttpUserAgentEnv = null;
private string _gitPath = null;
private Version _version = null;
private string _gitExecPathEnv = null;

public async Task LoadGitExecutionInfo(IExecutionContext context)
{
#if OS_WINDOWS
_gitPath = Path.Combine(IOUtil.GetExternalsPath(), "git", "cmd", $"git{IOUtil.ExeExtension}");
#else
_gitPath = Path.Combine(IOUtil.GetExternalsPath(), "git", "bin", $"git{IOUtil.ExeExtension}");
#endif
if (string.IsNullOrEmpty(_gitPath) || !File.Exists(_gitPath))
{
"checkout", new Dictionary<Version, string> ()
{
{ new Version(1,8), "--force {0}" },
{ new Version(2,7), "--progress --force {0}" }
}
throw new Exception(StringUtil.Loc("GitNotFound"));
}
};

public string GitPath { get; set; }
public Version Version { get; set; }
public string GitHttpUserAgent { get; set; }
context.Debug($"Find git from agent's external directory: {_gitPath}.");

_version = await GitVersion(context);
context.Debug($"Detect git version: {_version.ToString()}.");

_gitHttpUserAgentEnv = $"git/{_version.ToString()} (vsts-agent-git/{Constants.Agent.Version})";
context.Debug($"Set git useragent to: {_gitHttpUserAgentEnv}.");

#if !OS_WINDOWS
_gitExecPathEnv = Path.Combine(IOUtil.GetExternalsPath(), "git", "libexec", "git-core");
context.Debug($"Set git execpath to: {_gitExecPathEnv}");
#endif
}

// git init <LocalDir>
public async Task<int> GitInit(IExecutionContext context, string repositoryPath)
Expand All @@ -105,8 +119,7 @@ public async Task<int> GitFetch(IExecutionContext context, string repositoryPath
public async Task<int> GitCheckout(IExecutionContext context, string repositoryPath, string committishOrBranchSpec, CancellationToken cancellationToken)
{
context.Debug($"Checkout {committishOrBranchSpec}.");
string checkoutOption = GetCommandOption("checkout");
return await ExecuteGitCommandAsync(context, repositoryPath, "checkout", StringUtil.Format(checkoutOption, committishOrBranchSpec), cancellationToken);
return await ExecuteGitCommandAsync(context, repositoryPath, "checkout", StringUtil.Format("--progress --force {0}", committishOrBranchSpec), cancellationToken);
}

// git clean -fdx
Expand Down Expand Up @@ -225,6 +238,7 @@ public async Task<Version> GitVersion(IExecutionContext context)
Version version = null;
List<string> outputStrings = new List<string>();
int exitCode = await ExecuteGitCommandAsync(context, IOUtil.GetWorkPath(HostContext), "version", null, outputStrings);
context.Debug($"git version ouput: {string.Join(Environment.NewLine, outputStrings)}");
if (exitCode == 0)
{
// remove any empty line.
Expand All @@ -248,32 +262,6 @@ public async Task<Version> GitVersion(IExecutionContext context)
return version;
}

private string GetCommandOption(string command)
{
if (string.IsNullOrEmpty(command))
{
throw new ArgumentNullException("command");
}

if (!_gitCommands.ContainsKey(command))
{
throw new NotSupportedException($"Unsupported git command: {command}");
}

Dictionary<Version, string> options = _gitCommands[command];
foreach (var versionOption in options.OrderByDescending(o => o.Key))
{
if (Version >= versionOption.Key)
{
return versionOption.Value;
}
}

var earliestVersion = options.OrderByDescending(o => o.Key).Last();
Trace.Info($"Fallback to version {earliestVersion.Key.ToString()} command option for git {command}.");
return earliestVersion.Value;
}

private async Task<int> ExecuteGitCommandAsync(IExecutionContext context, string repoRoot, string command, string options, CancellationToken cancellationToken = default(CancellationToken))
{
string arg = StringUtil.Format($"{command} {options}").Trim();
Expand All @@ -290,13 +278,18 @@ private string GetCommandOption(string command)
context.Output(message.Data);
};

Dictionary<string, string> _userAgentEnv = new Dictionary<string, string>();
if (!string.IsNullOrEmpty(GitHttpUserAgent))
Dictionary<string, string> _gitEnv = new Dictionary<string, string>();
if (!string.IsNullOrEmpty(_gitHttpUserAgentEnv))
{
_userAgentEnv["GIT_HTTP_USER_AGENT"] = GitHttpUserAgent;
_gitEnv["GIT_HTTP_USER_AGENT"] = _gitHttpUserAgentEnv;
}

return await processInvoker.ExecuteAsync(repoRoot, GitPath, arg, _userAgentEnv, cancellationToken);
if (!string.IsNullOrEmpty(_gitExecPathEnv))
{
_gitEnv["GIT_EXEC_PATH"] = _gitExecPathEnv;
}

return await processInvoker.ExecuteAsync(repoRoot, _gitPath, arg, _gitEnv, cancellationToken);
}

private async Task<int> ExecuteGitCommandAsync(IExecutionContext context, string repoRoot, string command, string options, IList<string> output)
Expand Down Expand Up @@ -327,13 +320,18 @@ private async Task<int> ExecuteGitCommandAsync(IExecutionContext context, string
}
};

Dictionary<string, string> _userAgentEnv = new Dictionary<string, string>();
if (!string.IsNullOrEmpty(GitHttpUserAgent))
Dictionary<string, string> _gitEnv = new Dictionary<string, string>();
if (!string.IsNullOrEmpty(_gitHttpUserAgentEnv))
{
_gitEnv["GIT_HTTP_USER_AGENT"] = _gitHttpUserAgentEnv;
}

if (!string.IsNullOrEmpty(_gitExecPathEnv))
{
_userAgentEnv["GIT_HTTP_USER_AGENT"] = GitHttpUserAgent;
_gitEnv["GIT_EXEC_PATH"] = _gitExecPathEnv;
}

return await processInvoker.ExecuteAsync(repoRoot, GitPath, arg, _userAgentEnv, default(CancellationToken));
return await processInvoker.ExecuteAsync(repoRoot, _gitPath, arg, _gitEnv, default(CancellationToken));
}

private async Task<int> ExecuteGitCommandAsync(IExecutionContext context, string repoRoot, string command, string options, string additionalCommandLine, CancellationToken cancellationToken)
Expand All @@ -352,13 +350,18 @@ private async Task<int> ExecuteGitCommandAsync(IExecutionContext context, string
context.Output(message.Data);
};

Dictionary<string, string> _userAgentEnv = new Dictionary<string, string>();
if (!string.IsNullOrEmpty(GitHttpUserAgent))
Dictionary<string, string> _gitEnv = new Dictionary<string, string>();
if (!string.IsNullOrEmpty(_gitHttpUserAgentEnv))
{
_gitEnv["GIT_HTTP_USER_AGENT"] = _gitHttpUserAgentEnv;
}

if (!string.IsNullOrEmpty(_gitExecPathEnv))
{
_userAgentEnv["GIT_HTTP_USER_AGENT"] = GitHttpUserAgent;
_gitEnv["GIT_EXEC_PATH"] = _gitExecPathEnv;
}

return await processInvoker.ExecuteAsync(repoRoot, GitPath, arg, _userAgentEnv, cancellationToken);
return await processInvoker.ExecuteAsync(repoRoot, _gitPath, arg, _gitEnv, cancellationToken);
}
}
}
57 changes: 2 additions & 55 deletions src/Agent.Worker/Build/GitSourceProvider.cs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ public virtual async Task GetSourceAsync(IExecutionContext executionContext, Ser
ArgUtil.NotNull(endpoint, nameof(endpoint));

executionContext.Output($"Syncing repository: {endpoint.Name} (Git)");
_gitCommandManager = HostContext.GetService<IGitCommandManager>();
await _gitCommandManager.LoadGitExecutionInfo(executionContext);

string targetPath = executionContext.Variables.Get(Constants.Variables.Build.SourcesDirectory);
string sourceBranch = executionContext.Variables.Get(Constants.Variables.Build.SourceBranch);
Expand Down Expand Up @@ -58,29 +60,6 @@ public virtual async Task GetSourceAsync(IExecutionContext executionContext, Ser
Trace.Info($"checkoutSubmodules={checkoutSubmodules}");
Trace.Info($"exposeCred={exposeCred}");

// ensure find full path to git exist, the version of the installed git is what we supported.
string gitPath = null;
if (!TryGetGitLocation(executionContext, out gitPath))
{
throw new Exception(StringUtil.Loc("GitNotInstalled"));
}
Trace.Info($"Git path={gitPath}");

_gitCommandManager = HostContext.GetService<IGitCommandManager>();
_gitCommandManager.GitPath = gitPath;

Version gitVersion = await _gitCommandManager.GitVersion(executionContext);
if (gitVersion < _minSupportGitVersion)
{
throw new Exception(StringUtil.Loc("InstalledGitNotSupport", _minSupportGitVersion));
}
Trace.Info($"Git version={gitVersion}");
_gitCommandManager.Version = gitVersion;

string customizeUserAgent = $"git/{gitVersion.ToString()} (vsts-agent-git/{Constants.Agent.Version})";
Trace.Info($"Git useragent={customizeUserAgent}");
_gitCommandManager.GitHttpUserAgent = customizeUserAgent;

// retrieve credential from endpoint.
Uri repositoryUrl = endpoint.Url;
if (!repositoryUrl.IsAbsoluteUri)
Expand Down Expand Up @@ -309,38 +288,6 @@ public virtual async Task PostJobCleanupAsync(IExecutionContext executionContext
await RemoveCachedCredential(executionContext, targetPath, repositoryUrl, "origin");
}

private bool TryGetGitLocation(IExecutionContext executionContext, out string gitPath)
{
//find git in %Path%
var whichTool = HostContext.GetService<IWhichUtil>();
gitPath = whichTool.Which("git");

#if OS_WINDOWS
//find in %ProgramFiles(x86)%\git\cmd if platform is Windows
if (string.IsNullOrEmpty(gitPath))
{
string programFileX86 = Environment.GetEnvironmentVariable("ProgramFiles(x86)");
if (!string.IsNullOrEmpty(programFileX86))
{
gitPath = Path.Combine(programFileX86, "Git\\cmd\\git.exe");
if (!File.Exists(gitPath))
{
gitPath = null;
}
}
}
#endif
if (string.IsNullOrEmpty(gitPath))
{
return false;
}
else
{
executionContext.Debug($"Find git installation path: {gitPath}.");
return true;
}
}

protected async Task<bool> IsRepositoryOriginUrlMatch(IExecutionContext context, string repositoryPath, Uri expectedRepositoryOriginUrl)
{
context.Debug($"Checking if the repo on {repositoryPath} matches the expected repository origin URL. expected Url: {expectedRepositoryOriginUrl.AbsoluteUri}");
Expand Down
49 changes: 5 additions & 44 deletions src/Agent.Worker/Build/TfsGitSourceProvider.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,25 +12,17 @@ namespace Microsoft.VisualStudio.Services.Agent.Worker.Build
{
public sealed class TfsGitSourceProvider : GitSourceProvider, ISourceProvider
{
public override string RepositoryType => WellKnownRepositoryTypes.TfsGit;
private readonly Dictionary<string, string> _authHeaderCache = new Dictionary<string, string>();
private bool _supportAddAuthHeader = false;

public override string RepositoryType => WellKnownRepositoryTypes.TfsGit;

public override async Task GetSourceAsync(IExecutionContext executionContext, ServiceEndpoint endpoint, CancellationToken cancellationToken)
{
Trace.Entering();
ArgUtil.NotNull(endpoint, nameof(endpoint));

string gitPath = null;
_supportAddAuthHeader = IsLocalGitSupportAddAuthHeader(out gitPath);
if (!_supportAddAuthHeader)
{
// use default git source provider handle credential which will embed credential into remote url
await base.GetSourceAsync(executionContext, endpoint, cancellationToken);
return;
}

executionContext.Output($"Syncing repository: {endpoint.Name} (TfsGit)");
_gitCommandManager = HostContext.GetService<IGitCommandManager>();
await _gitCommandManager.LoadGitExecutionInfo(executionContext);

string targetPath = executionContext.Variables.Get(Constants.Variables.Build.SourcesDirectory);
string sourceBranch = executionContext.Variables.Get(Constants.Variables.Build.SourceBranch);
Expand All @@ -57,18 +49,6 @@ public override async Task GetSourceAsync(IExecutionContext executionContext, Se
Trace.Info($"clean={clean}");
Trace.Info($"checkoutSubmodules={checkoutSubmodules}");
Trace.Info($"exposeCred={exposeCred}");
Trace.Info($"Git path={gitPath}");

_gitCommandManager = HostContext.GetService<IGitCommandManager>();
_gitCommandManager.GitPath = gitPath;

Version gitVersion = await _gitCommandManager.GitVersion(executionContext);
Trace.Info($"Git version={gitVersion}");
_gitCommandManager.Version = gitVersion;

string customizeUserAgent = $"git/{gitVersion.ToString()} (vsts-agent-git/{Constants.Agent.Version})";
Trace.Info($"Git useragent={customizeUserAgent}");
_gitCommandManager.GitHttpUserAgent = customizeUserAgent;

// retrieve credential from endpoint.
Uri repositoryUrl = endpoint.Url;
Expand Down Expand Up @@ -261,15 +241,9 @@ public override async Task GetSourceAsync(IExecutionContext executionContext, Se
public override async Task PostJobCleanupAsync(IExecutionContext executionContext, ServiceEndpoint endpoint)
{
Trace.Entering();
if (!_supportAddAuthHeader)
{
await base.PostJobCleanupAsync(executionContext, endpoint);
return;
}

ArgUtil.NotNull(endpoint, nameof(endpoint));
executionContext.Output($"Cleaning extra http auth header from repository: {endpoint.Name} (TfsGit)");

Uri repositoryUrl = endpoint.Url;
string targetPath = executionContext.Variables.Get(Constants.Variables.Build.SourcesDirectory);

Expand Down Expand Up @@ -298,18 +272,5 @@ public override async Task PostJobCleanupAsync(IExecutionContext executionContex
}
}
}

private bool IsLocalGitSupportAddAuthHeader(out string gitPath)
{
gitPath = string.Empty;

// find portable git in externals
#if OS_WINDOWS
gitPath = Path.Combine(IOUtil.GetExternalsPath(), "git", "cmd", $"git{IOUtil.ExeExtension}");
#else
gitPath = Path.Combine(IOUtil.GetExternalsPath(), "git", "bin", $"git{IOUtil.ExeExtension}");
#endif
return !string.IsNullOrEmpty(gitPath) && File.Exists(gitPath);
}
}
}
9 changes: 8 additions & 1 deletion src/Agent.Worker/Handlers/NodeHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,14 @@ public async Task RunAsync()
string workingDirectory = Data.WorkingDirectory;
if (string.IsNullOrEmpty(workingDirectory))
{
workingDirectory = TaskDirectory;
if (!string.IsNullOrEmpty(ExecutionContext.Variables.System_DefaultWorkingDirectory))
{
workingDirectory = ExecutionContext.Variables.System_DefaultWorkingDirectory;
}
else
{
workingDirectory = ExecutionContext.Variables.Agent_WorkFolder;
}
}

ArgUtil.Directory(workingDirectory, nameof(workingDirectory));
Expand Down
2 changes: 2 additions & 0 deletions src/Agent.Worker/Variables.cs
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ into maskHintGrouping
}

public string Agent_BuildDirectory { get { return Get(Constants.Variables.Agent.BuildDirectory); } }
public string Agent_WorkFolder { get { return Get(Constants.Variables.Agent.WorkFolder); } }
public TaskResult? Agent_JobStatus { get { return GetEnum<TaskResult>(Constants.Variables.Agent.JobStatus); } set { Set(Constants.Variables.Agent.JobStatus, $"{value}"); } }
public int? Build_BuildId { get { return GetInt(BuildWebApi.WellKnownBuildVariables.BuildId); } }
public string Build_BuildUri { get { return Get(BuildWebApi.WellKnownBuildVariables.BuildUri); } }
Expand All @@ -107,6 +108,7 @@ into maskHintGrouping
public string Release_ReleaseUri { get { return Get(Constants.Variables.Release.ReleaseUri); } }
public string System_CollectionId { get { return Get(Constants.Variables.System.CollectionId); } }
public bool? System_Debug { get { return GetBoolean(Constants.Variables.System.Debug); } }
public string System_DefaultWorkingDirectory { get { return Get(Constants.Variables.System.DefaultWorkingDirectory); } }
public string System_DefinitionId { get { return Get(Constants.Variables.System.DefinitionId); } }
public bool? System_EnableAccessToken { get { return GetBoolean(Constants.Variables.System.EnableAccessToken); } }
public string System_HostType { get { return Get(Constants.Variables.System.HostType); } }
Expand Down
Loading

0 comments on commit 043f11f

Please sign in to comment.