代码之家  ›  专栏  ›  技术社区  ›  bachq22

运行azure devops-api创建的管道时“未指定池”

  •  0
  • bachq22  · 技术社区  · 1 年前

    我在一个现有的Git仓库中有100多个YAML文件,每个文件都定义了自己的构建管道。我正在尝试创建一个PowerShell脚本来创建这些构建定义,这样我就不必花几个小时使用web UI手动添加新的构建定义并指向它们各自的YAML文件。

    我遇到过类似的问题和资源,但没能让这个脚本发挥作用。

    我知道 the REST API documentation 支持克隆,但它是否支持创建一个链接到Git repo中的YAML文件的构建定义?

    $organization = "my-company"
    $project = "MyProject"
    $projUrl = "https://dev.azure.com/$($organization)/$($project)/"
    $patToken = "<PAT>"
    $token = [System.Convert]::ToBase64String([System.Text.Encoding]::ASCII.GetBytes(":$($patToken)"))
    $header = @{authorization = "Basic $token"}
    $Url = "$($projUrl)_apis/build/definitions?api-version=5.1"
    
    $json = @{
        project = "$($project)";
        name = "My.New.Definition.Linked.To.Existing.YAML.File";
        repository = @{
            url = "<the-https-link-to-my-Git-repo>";
        };
        # The script still fails with definition.Process cannot be null.
        # process = 0;
        path = "\A New Folder";
        type = "build"
    }
    
    $body = ($json | ConvertTo-Json -Depth 3)
    Invoke-RestMethod -Uri $Url -Headers $header -Body $body -Method Post -ContentType application/json;
    

    上面的脚本出现以下错误:

    Invoke-RestMethod : {"$id":"1","innerException":null,"message":"Value cannot be null.\r\nParameter name:
    definition.Process","typeName":"System.ArgumentNullException, mscorlib","typeKey":"ArgumentNullException","errorCode":0,"eventId":0}
    At create_pipelines.ps1:22 char:1
    + Invoke-RestMethod -Uri $Url -Headers $header -Body $body -Method Post ...
    + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        + CategoryInfo          : InvalidOperation: (System.Net.HttpWebRequest:HttpWebRequest) [Invoke-RestMethod], WebException
        + FullyQualifiedErrorId : WebCmdletWebResponseException,Microsoft.PowerShell.Commands.InvokeRestMethodCommand
    

    是否可以在不克隆我必须通过web UI手动创建的现有构建定义的情况下创建新的构建定义?

    我有100多个YAML文件位于一个文件夹中 /azure管道YAML/ Git回购内部。我怀疑我需要以某种方式将其包含在我通过REST API发送的JSON中,但在哪里/如何?我陷入了困境 释义过程 错误

    使现代化

    多亏了@danielmann,我最终需要获得一些额外的信息(即。 repository.Id 以及更改 repository.Type )。我在脚本中放入以下内容,以获得我基于现有YAML文件创建的临时定义的示例。

    $Url = "$($projUrl)_apis/build/definitions/13?api-version=5.1"
    Invoke-RestMethod $Url -Headers $header -Method Get -ContentType application/json;
    

    工作脚本最终是:

    $organization = "my-company"
    $project = "MyProject"
    $projUrl = "https://dev.azure.com/$($organization)/$($project)/"
    $patToken = "<PAT>"
    $token = [System.Convert]::ToBase64String([System.Text.Encoding]::ASCII.GetBytes(":$($patToken)"))
    $header = @{authorization = "Basic $token"}
    $Url = "$($projUrl)_apis/build/definitions?api-version=5.1"
    
    $json = @{
        project = "$($project)";
        name = "My.New.Definition.Linked.To.Existing.YAML.File";
        repository = @{
            url = "<the-https-link-to-my-Git-repo>";
            defaultBranch = "refs/heads/feature/my-new-feature-branch";
            id = "<taken-from-the-GET-API-request>";
            type = "TfsGit";
        };
        process = @{
            yamlFilename = "azure-pipeline-YAML/my-pipeline.yml";
            type = 2;
        };
        path = "\A New Folder";
        type = "build";
    }
    
    $body = ($json | ConvertTo-Json -Depth 3)
    Invoke-RestMethod -Uri $Url -Headers $header -Body $body -Method Post -ContentType application/json;
    
    0 回复  |  直到 5 年前
        1
  •  4
  •   Daniel Mann    5 年前

    当您指定 process = 0 因为 process 不应该是数字数据类型。流程需要指定一个YAML文件和一个“type”参数。

      "process": {
        "yamlFilename": "build.yaml",
        "type": 2
      }
    

    老实说,我忘了什么是类型“2”与类型“1”和类型“90072972”,但我以前也用过。

    解决这类问题的最简单方法是创建一个YAML构建,并使用RESTneneneba API下拉定义JSON。我就是这么想的。

        2
  •  0
  •   Rakesh Suryawanshi    4 年前
         public class Constants
        {
         public class DevOps
            {
                public class Build
                {
                    public const string QUEUE_STATUS = "enabled";
                    public const string YAML_FILE_PATH = "Data/azure-pipelines.yml";
                    public const string AGENT_POOL_NAME = "Hosted Ubuntu 1604";
                    public const string JOB_AUTHORIZATION_SCOPE = "projectCollection";
                    public const string REPOSITORY_TYPE = "TfsGit";
                    public const string CREATE_BUILD_DEF_URI = "https://dev.azure.com/{0}/{1}/_apis/build/definitions?api-version=5.0";
                }
        }
    }
    public class Repository
    {
              public string id { get; set; }
            public string name { get; set; }
            public string url { get; set; }
            public DevOpsProject project { get; set; }
            public int size { get; set; }
            public string remoteUrl { get; set; }
            public string sshUrl { get; set; }
            public bool isFork { get; set; }
            public _Links _links { get; set; }
            public string defaultBranch { get; set; }
    
            public string type { get; set; }
    
    
    }
    
       private void CreateIntegrationPipelineWithForkRepository(string orgnizationName, string sourceProjectName, string sourceProjectId, Repository forkRepository)
        {
            System.Action action = delegate
            {
                //********************************* Create Build with CICD ******************///
                var continuousIntegration = new List<BuildTrigger>() { new BuildTrigger() };
                var referenceYamlPath = new
                {
                    yamlFilename = Constants.DevOps.Build.YAML_FILE_PATH,// = "Data/azure-pipelines.yml",
                    type = 2
                };
                var queueWithAgentPool = new
                {
                    name = Constants.DevOps.Build.AGENT_POOL_NAME,
                    pool = new
                    {
                        name = Constants.DevOps.Build.AGENT_POOL_NAME,
                        isHosted = true
                    }
                };
    
                //Set repository type to: 'TfsGit'
                forkRepository.type = Constants.DevOps.Build.REPOSITORY_TYPE;// = "TfsGit";
                var requestBuild = new
                {
                    triggers = continuousIntegration,
                    jobAuthorizationScope = Constants.DevOps.Build.JOB_AUTHORIZATION_SCOPE,
                    jobTimeoutInMinutes = 60,
                    jobCancelTimeoutInMinutes = 5,
                    process = referenceYamlPath,
                    repository = forkRepository, // new repository
                    quality = "definition",
                    queue = queueWithAgentPool,
                    name = string.Format("{0}-{1}", forkRepository.name, "ci"),
                    path = "\\",
                    type = "build",
                    queueStatus = Constants.DevOps.Build.QUEUE_STATUS,//= "enabled",
                    revision = 1,
                    project = new { id = sourceProjectId } // source project id
                };
    
                //********************************* Create Build with CICD ******************///
                var uri = string.Format(Constants.DevOps.Build.CREATE_BUILD_DEF_URI, orgnizationName,sourceProjectName);
    
                this.Post(uri, HttpMethod.Post, requestBuild);
            };
    
            _exceptionHandlingPolicy.Execute(action);
    
        }
        
        private string Post<T>(uri, HttpMethod.Post, T request)
        {
        if (request != null)
                    {
                        data = JsonConvert.SerializeObject(request);
                    }
                    var personalaccesstoken = "azure-devOps-PAT-token";
    
                    var authorization = Convert.ToBase64String(System.Text.ASCIIEncoding.ASCII.GetBytes(string.Format("{0}:{1}", "", personalaccesstoken)));
    
                    var result = _httpClient.Send(uri, method, data, authorization);
        }
    
        3
  •  0
  •   natescherer    4 年前

    通过使用@E-rich的解决方案,我能够构建一系列API调用,这些调用将创建一个启用CI触发的管道,因为这在所示示例中不起作用。

    根据我的测试,在创建构建定义时,有必要将“队列”和“触发器”定义为POST的一部分。

    我完成的剧本如下。

    $DevOpsPat = "PersonalAccessTokenHere"
    $Organization = "OrgNameHere"
    $Project = "ProjNameHere"
    $RepoName = "RepoNameHere"
    $PipelineName = "PipelineNameHere"
    $PipelinePath = "\PathHere"
    $PipelineTriggerBranch = "master"
    $YamlPath = "/azure-pipelines.yml"
    
    $AuthHeader = 'Basic ' + [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes(":$($DevOpsPat)"))
    
    $QueuesSplat = @{
        Uri = "https://dev.azure.com/$Organization/$Project/_apis/distributedtask/queues?api-version=6.1-preview.1"
        Method = "GET"
        ContentType = "application/json"
        Headers = @{
            Authorization = $AuthHeader
        }
    }
    $Queues = Invoke-RestMethod @QueuesSplat
    $APQueueID = ($Queues.value | Where-Object {$_.name -eq "Azure Pipelines"}).id
    
    $ReposSplat = @{
        Uri = "https://dev.azure.com/$Organization/$Project/_apis/git/repositories?api-version=6.1-preview.1"
        Method = "GET"
        ContentType = "application/json"
        Headers = @{
            Authorization = $AuthHeader
        }
    }
    $Repos = Invoke-RestMethod @ReposSplat
    $Repo = $Repos.value | Where-Object {$_.name -eq $RepoName}
    
    $PipelineSplat = @{
        Uri = "https://dev.azure.com/$Organization/$Project/_apis/build/definitions?api-version=5.1"
        Method = "POST"
        ContentType = "application/json" 
        Body = ConvertTo-Json @{
            project = "$Project"
            name = $PipelineName
            repository = @{
                url = $Repo.webUrl
                defaultBranch = $PipelineTriggerBranch
                id = $Repo.id
                type = "TfsGit"
            }
            process = @{
                yamlFilename = $YamlPath
                type = 2
            }
            path = $PipelinePath
            type = "build"
            triggers = @(
                @{
                    settingsSourceType = 2
                    triggerType = "continuousIntegration"
                }
            )
            queue  = @{
                id = $APQueueID
            }
        }
        Headers = @{
            Authorization = $AuthHeader
        }    
    }
    Invoke-RestMethod @PipelineSplat