private TaskStep GetSelfCheckoutTask(IList<JobStep> steps)
 {
     return steps.Select(x => x as TaskStep)
             .Where(task => task.IsCheckoutTask()
                 && task.Inputs.TryGetValue(PipelineConstants.CheckoutTaskInputs.Repository, out string repositoryAlias)
                 && RepositoryUtil.IsPrimaryRepositoryName(repositoryAlias)).FirstOrDefault();
 }
        private string GetDefaultRepoLocalPathValue(IExecutionContext executionContext, IList<Pipelines.JobStep> steps, TrackingConfig trackingConfig, RepositoryInfo repoInfo)
        {
            string selfRepoPath = null;
            // For saving backward compatibility with the behavior of the Build.RepoLocalPath that was before this PR https://github.com/microsoft/azure-pipelines-agent/pull/3237
            // We need to change how we set the default value of this variable
            // We need to allow the setting of paths from RepositoryTrackingInfo for checkout tasks where path input was provided by the user
            // and this input is not point to the default location for this repository
            // This is the only case where the value of Build.RepoLocalPath variable is not pointing to the root of sources directory /s.
            // The new logic is not affecting single checkout jobs and jobs with multiple checkouts and default paths for Self repository
            if (RepositoryUtil.HasMultipleCheckouts(executionContext.JobSettings))
            {
                // get checkout task for self repo
                var selfCheckoutTask = GetSelfCheckoutTask(steps);

                // Check if the task has path input with custom path, if so we need to set as a value of selfRepoPath the value of SourcesDirectory from RepositoryTrackingInfo
                if (IsCheckoutToCustomPath(trackingConfig, repoInfo, selfCheckoutTask))
                {
                    selfRepoPath = trackingConfig.RepositoryTrackingInfo
                        .Where(repo => RepositoryUtil.IsPrimaryRepositoryName(repo.Identifier))
                        .Select(props => props.SourcesDirectory).FirstOrDefault(); 
                }
            }
            // For single checkout jobs and multicheckout jobs with default paths set selfRepoPath to the default sources directory
            if (selfRepoPath == null)
            {
                selfRepoPath = trackingConfig.SourcesDirectory;
            }

            return selfRepoPath;
        }
Ejemplo n.º 3
0
        public void Execute(IExecutionContext context, Command command)
        {
            var eventProperties = command.Properties;
            var data            = command.Data;

            String alias;

            if (!eventProperties.TryGetValue(PluginInternalUpdateRepositoryEventProperties.Alias, out alias) || String.IsNullOrEmpty(alias))
            {
                throw new Exception(StringUtil.Loc("MissingRepositoryAlias"));
            }

            var repository = context.Repositories.FirstOrDefault(x => string.Equals(x.Alias, alias, StringComparison.OrdinalIgnoreCase));

            if (repository == null)
            {
                throw new Exception(StringUtil.Loc("RepositoryNotExist"));
            }

            if (string.IsNullOrEmpty(data))
            {
                throw new Exception(StringUtil.Loc("MissingRepositoryPath"));
            }

            var currentPath = repository.Properties.Get <string>(RepositoryPropertyNames.Path);

            if (!string.Equals(data.TrimEnd(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar), currentPath.TrimEnd(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar), IOUtil.FilePathStringComparison))
            {
                string repositoryPath = data.TrimEnd(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar);
                repository.Properties.Set <string>(RepositoryPropertyNames.Path, repositoryPath);

                bool isSelfRepo           = RepositoryUtil.IsPrimaryRepositoryName(repository.Alias);
                bool hasMultipleCheckouts = RepositoryUtil.HasMultipleCheckouts(context.JobSettings);

                if (isSelfRepo || !hasMultipleCheckouts)
                {
                    var    directoryManager = context.GetHostContext().GetService <IBuildDirectoryManager>();
                    string _workDirectory   = context.GetHostContext().GetDirectory(WellKnownDirectory.Work);

                    var trackingConfig = directoryManager.UpdateDirectory(context, repository);
                    if (hasMultipleCheckouts)
                    {
                        // In Multi-checkout, we don't want to reset sources dir or default working dir.
                        // So, we will just reset the repo local path
                        string buildDirectory   = context.Variables.Get(Constants.Variables.Pipeline.Workspace);
                        string repoRelativePath = directoryManager.GetRelativeRepositoryPath(buildDirectory, repositoryPath);
                        context.SetVariable(Constants.Variables.Build.RepoLocalPath, Path.Combine(_workDirectory, repoRelativePath), isFilePath: true);
                    }
                    else
                    {
                        // If we only have a single repository, then update all the paths to point to it.
                        context.SetVariable(Constants.Variables.Build.SourcesDirectory, repositoryPath, isFilePath: true);
                        context.SetVariable(Constants.Variables.Build.RepoLocalPath, repositoryPath, isFilePath: true);
                        context.SetVariable(Constants.Variables.System.DefaultWorkingDirectory, repositoryPath, isFilePath: true);
                    }
                }
            }

            repository.Properties.Set("__AZP_READY", bool.TrueString);
        }
Ejemplo n.º 4
0
 public void IsPrimaryRepositoryName_should_work_correctly()
 {
     using (TestHostContext hc = new TestHostContext(this))
     {
         Assert.Equal(false, RepositoryUtil.IsPrimaryRepositoryName(null));
         Assert.Equal(false, RepositoryUtil.IsPrimaryRepositoryName(""));
         Assert.Equal(false, RepositoryUtil.IsPrimaryRepositoryName("none"));
         Assert.Equal(false, RepositoryUtil.IsPrimaryRepositoryName("some random string"));
         Assert.Equal(true, RepositoryUtil.IsPrimaryRepositoryName("self"));
         Assert.Equal(true, RepositoryUtil.IsPrimaryRepositoryName("SELF"));
         Assert.Equal(true, RepositoryUtil.IsPrimaryRepositoryName("Self"));
         Assert.Equal(true, RepositoryUtil.IsPrimaryRepositoryName("sELF"));
     }
 }
        private void UpdateCheckoutTasksAndVariables(IExecutionContext executionContext, IList <JobStep> steps, RepositoryInfo repoInfo, string pipelineWorkspaceDirectory)
        {
            bool?submoduleCheckout = null;
            // RepoClean may be set from the server, so start with the server value
            bool?repoClean = executionContext.Variables.GetBoolean(Constants.Variables.Build.RepoClean);

            foreach (var checkoutTask in steps.Where(x => x.IsCheckoutTask()).Select(x => x as TaskStep))
            {
                if (!checkoutTask.Inputs.TryGetValue(PipelineConstants.CheckoutTaskInputs.Repository, out string repositoryAlias))
                {
                    // If the checkout task isn't associated with a repo, just skip it
                    Trace.Info($"Checkout task {checkoutTask.Name} does not have a repository property.");
                    continue;
                }

                // Update the checkout "Clean" property for all repos, if the variable was set by the server.
                if (repoClean != null)
                {
                    checkoutTask.Inputs[PipelineConstants.CheckoutTaskInputs.Clean] = repoClean.Value.ToString();
                }

                // If this is the primary repository, use it to get the variable values
                if (RepositoryUtil.IsPrimaryRepositoryName(repositoryAlias))
                {
                    submoduleCheckout = checkoutTask.Inputs.ContainsKey(PipelineConstants.CheckoutTaskInputs.Submodules);
                    repoClean         = repoClean ?? checkoutTask.Inputs.ContainsKey(PipelineConstants.CheckoutTaskInputs.Clean);
                }

                // Update the checkout task display name if not already set
                if (string.IsNullOrEmpty(checkoutTask.DisplayName) || string.Equals(checkoutTask.DisplayName, "Checkout", StringComparison.OrdinalIgnoreCase))
                {
                    var repository = RepositoryUtil.GetRepository(executionContext.Repositories, repositoryAlias);
                    if (repository != null)
                    {
                        string repoName = repository.Properties.Get <string>(RepositoryPropertyNames.Name);
                        string version  = RepositoryUtil.TrimStandardBranchPrefix(repository.Properties.Get <string>(RepositoryPropertyNames.Ref));
                        string path     = null;
                        if (checkoutTask.Inputs.ContainsKey(PipelineConstants.CheckoutTaskInputs.Path))
                        {
                            path = checkoutTask.Inputs[PipelineConstants.CheckoutTaskInputs.Path];
                        }
                        else
                        {
                            path = IOUtil.MakeRelative(repository.Properties.Get <string>(RepositoryPropertyNames.Path), pipelineWorkspaceDirectory);
                        }
                        checkoutTask.DisplayName = StringUtil.Loc("CheckoutTaskDisplayNameFormat", repoName, version, path);
                    }
                    else
                    {
                        Trace.Info($"Checkout task {checkoutTask.Name} has a repository property {repositoryAlias} that does not match any repository resource.");
                    }
                }
            }

            // Set variables
            if (submoduleCheckout.HasValue)
            {
                executionContext.SetVariable(Constants.Variables.Build.RepoGitSubmoduleCheckout, submoduleCheckout.Value.ToString());
            }

            if (repoClean.HasValue)
            {
                executionContext.SetVariable(Constants.Variables.Build.RepoClean, repoClean.Value.ToString());
            }
        }
Ejemplo n.º 6
0
        private void UpdateCheckoutTasksAndVariables(IExecutionContext executionContext, IList <JobStep> steps, string pipelineWorkspaceDirectory)
        {
            bool?submoduleCheckout = null;
            // RepoClean may be set from the server, so start with the server value
            bool?repoCleanFromServer = executionContext.Variables.GetBoolean(Constants.Variables.Build.RepoClean);
            // The value for the global clean option will be set in this variable based on Self repository clean input if the global value weren't set by the server
            bool?repoCleanFromSelf = null;

            var checkoutTasks          = steps.Where(x => x.IsCheckoutTask()).Select(x => x as TaskStep).ToList();
            var hasOnlyOneCheckoutTask = checkoutTasks.Count == 1;

            foreach (var checkoutTask in checkoutTasks)
            {
                if (!checkoutTask.Inputs.TryGetValue(PipelineConstants.CheckoutTaskInputs.Repository, out string repositoryAlias))
                {
                    // If the checkout task isn't associated with a repo, just skip it
                    Trace.Info($"Checkout task {checkoutTask.Name} does not have a repository property.");
                    continue;
                }

                // Update the checkout "Clean" property for all repos, if the variable was set by the server.
                if (repoCleanFromServer.HasValue)
                {
                    checkoutTask.Inputs[PipelineConstants.CheckoutTaskInputs.Clean] = repoCleanFromServer.Value.ToString();
                }

                Trace.Info($"Checking repository name {repositoryAlias}");
                // If this is the primary repository, use it to get the variable values
                // A repository is considered the primary one if the name is 'self' or if there is only
                // one checkout task. This is because Designer builds set the name of the repository something
                // other than 'self'
                if (hasOnlyOneCheckoutTask || RepositoryUtil.IsPrimaryRepositoryName(repositoryAlias))
                {
                    submoduleCheckout = checkoutTask.Inputs.ContainsKey(PipelineConstants.CheckoutTaskInputs.Submodules);
                    if (!repoCleanFromServer.HasValue && checkoutTask.Inputs.TryGetValue(PipelineConstants.CheckoutTaskInputs.Clean, out string cleanInputValue))
                    {
                        repoCleanFromSelf = Boolean.TryParse(cleanInputValue, out bool cleanValue) ? cleanValue : true;
                    }
                }

                // Update the checkout task display name if not already set
                if (string.IsNullOrEmpty(checkoutTask.DisplayName) ||
                    string.Equals(checkoutTask.DisplayName, "Checkout", StringComparison.OrdinalIgnoreCase) ||      // this is the default for jobs
                    string.Equals(checkoutTask.DisplayName, checkoutTask.Name, StringComparison.OrdinalIgnoreCase)) // this is the default for deployment jobs
                {
                    var repository = RepositoryUtil.GetRepository(executionContext.Repositories, repositoryAlias);
                    if (repository != null)
                    {
                        string repoName = repository.Properties.Get <string>(RepositoryPropertyNames.Name);
                        string version  = RepositoryUtil.TrimStandardBranchPrefix(repository.Properties.Get <string>(RepositoryPropertyNames.Ref));
                        string path     = null;
                        if (checkoutTask.Inputs.ContainsKey(PipelineConstants.CheckoutTaskInputs.Path))
                        {
                            path = checkoutTask.Inputs[PipelineConstants.CheckoutTaskInputs.Path];
                        }
                        else
                        {
                            path = IOUtil.MakeRelative(repository.Properties.Get <string>(RepositoryPropertyNames.Path), pipelineWorkspaceDirectory);
                        }
                        checkoutTask.DisplayName = StringUtil.Loc("CheckoutTaskDisplayNameFormat", repoName, version, path);
                    }
                    else
                    {
                        Trace.Info($"Checkout task {checkoutTask.Name} has a repository property {repositoryAlias} that does not match any repository resource.");
                    }
                }
            }

            // Set variables
            if (submoduleCheckout.HasValue)
            {
                executionContext.SetVariable(Constants.Variables.Build.RepoGitSubmoduleCheckout, submoduleCheckout.Value.ToString());
            }

            if (repoCleanFromSelf.HasValue)
            {
                executionContext.SetVariable(Constants.Variables.Build.RepoClean, repoCleanFromSelf.Value.ToString());
            }
        }
        public void Execute(IExecutionContext context, Command command)
        {
            ArgUtil.NotNull(context, nameof(context));
            ArgUtil.NotNull(command, nameof(command));

            var eventProperties = command.Properties;
            var data            = command.Data;

            String alias;

            if (!eventProperties.TryGetValue(PluginInternalUpdateRepositoryEventProperties.Alias, out alias) || String.IsNullOrEmpty(alias))
            {
                throw new ArgumentNullException(StringUtil.Loc("MissingRepositoryAlias"));
            }

            var repository = context.Repositories.FirstOrDefault(x => string.Equals(x.Alias, alias, StringComparison.OrdinalIgnoreCase));

            if (repository == null)
            {
                throw new ArgumentNullException(StringUtil.Loc("RepositoryNotExist"));
            }

            if (string.IsNullOrEmpty(data))
            {
                throw new ArgumentNullException(StringUtil.Loc("MissingRepositoryPath"));
            }

            var currentPath = repository.Properties.Get <string>(RepositoryPropertyNames.Path);

            if (!string.Equals(data.TrimEnd(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar), currentPath.TrimEnd(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar), IOUtil.FilePathStringComparison))
            {
                string repositoryPath = data.TrimEnd(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar);
                repository.Properties.Set <string>(RepositoryPropertyNames.Path, repositoryPath);

                bool isSelfRepo           = RepositoryUtil.IsPrimaryRepositoryName(repository.Alias);
                bool hasMultipleCheckouts = RepositoryUtil.HasMultipleCheckouts(context.JobSettings);

                var    directoryManager = context.GetHostContext().GetService <IBuildDirectoryManager>();
                string _workDirectory   = context.GetHostContext().GetDirectory(WellKnownDirectory.Work);
                var    trackingConfig   = directoryManager.UpdateDirectory(context, repository);

                if (isSelfRepo || !hasMultipleCheckouts)
                {
                    if (hasMultipleCheckouts)
                    {
                        // In Multi-checkout, we don't want to reset sources dir or default working dir.
                        // So, we will just reset the repo local path
                        string buildDirectory   = context.Variables.Get(Constants.Variables.Pipeline.Workspace);
                        string repoRelativePath = directoryManager.GetRelativeRepositoryPath(buildDirectory, repositoryPath);

                        string sourcesDirectory = context.Variables.Get(Constants.Variables.Build.SourcesDirectory);
                        string repoLocalPath    = context.Variables.Get(Constants.Variables.Build.RepoLocalPath);
                        string newRepoLocation  = Path.Combine(_workDirectory, repoRelativePath);
                        // For saving backward compatibility with the behavior of the Build.RepoLocalPath that was before this PR https://github.com/microsoft/azure-pipelines-agent/pull/3237
                        // we need to deny updating of the variable in case the new path is the default location for the repository that is equal to sourcesDirectory/repository.Name
                        // since the variable already has the right value in this case and pointing to the default sources location
                        if (repoLocalPath == null ||
                            !string.Equals(newRepoLocation, Path.Combine(sourcesDirectory, repository.Name), IOUtil.FilePathStringComparison))
                        {
                            context?.SetVariable(Constants.Variables.Build.RepoLocalPath, newRepoLocation, isFilePath: true);
                        }
                    }
                    else
                    {
                        // If we only have a single repository, then update all the paths to point to it.
                        context.SetVariable(Constants.Variables.Build.SourcesDirectory, repositoryPath, isFilePath: true);
                        context.SetVariable(Constants.Variables.Build.RepoLocalPath, repositoryPath, isFilePath: true);
                        context.SetVariable(Constants.Variables.System.DefaultWorkingDirectory, repositoryPath, isFilePath: true);
                    }
                }
            }

            repository.Properties.Set("__AZP_READY", bool.TrueString);
        }
Ejemplo n.º 8
0
 protected bool ShouldUpdateRepositoryPath(AgentTaskPluginExecutionContext executionContext, string repositoryAlias)
 {
     // Only update the repo path if this is the only checkout task or this checkout task is for the 'self' repo
     return(!HasMultipleCheckouts(executionContext) || RepositoryUtil.IsPrimaryRepositoryName(repositoryAlias));
 }