Azure DevOps通过给定现有YAML的REST API创建构建定义
我在现有Git repo中有100多个YAML文件,每个文件都定义了自己的构建管道。我正在尝试创建一个PowerShell脚本来创建这些生成定义,这样我就不必花费数小时使用web UI手动添加新的生成定义并指向它们各自的YAML文件 我也遇到过类似的问题和资源,但无法让这个脚本正常工作Azure DevOps通过给定现有YAML的REST API创建构建定义,azure,azure-devops,azure-pipelines,Azure,Azure Devops,Azure Pipelines,我在现有Git repo中有100多个YAML文件,每个文件都定义了自己的构建管道。我正在尝试创建一个PowerShell脚本来创建这些生成定义,这样我就不必花费数小时使用web UI手动添加新的生成定义并指向它们各自的YAML文件 我也遇到过类似的问题和资源,但无法让这个脚本正常工作 我知道它支持克隆,但它是否支持创建链接到Git repo中YAML文件的构建定义 $organization=“我的公司” $project=“MyProject” $projUrl=”https://
$organization=“我的公司”
$project=“MyProject”
$projUrl=”https://dev.azure.com/$($组织)/$($项目)/”
$patToken=“”
$token=[System.Convert]::TOBASE64字符串([System.Text.Encoding]::ASCII.GetBytes(“:$($patToken)”)
$header=@{authorization=“Basic$token”}
$Url=“$($projUrl)\u api/build/definitions?api版本=5.1”
$json=@{
project=“$($project)”;
name=“My.New.Definition.Linked.To.Existing.YAML.File”;
存储库=@{
url=“”;
};
#脚本仍无法定义。进程不能为null。
#过程=0;
path=“\A新文件夹”;
type=“构建”
}
$body=($json |转换为json-深度3)
调用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文件位于Git repo中的/azure pipeline YAML/文件夹中。我怀疑我需要以某种方式将其包含在通过RESTAPI发送的JSON中,但是在哪里/如何?我被这个定义难住了。进程错误
更新
多亏了@danielmann,我最终需要获得一些额外的信息(即repository.Id
和更改repository.Type
)。我在脚本中添加了以下内容,以获取基于现有YAML文件创建的临时定义的示例
$Url=“$($projUrl)\u api/build/definitions/13?api版本=5.1”
调用RestMethod$Url-Headers$header-Method Get-ContentType应用程序/json;
工作脚本最终是:
$organization=“我的公司”
$project=“MyProject”
$projUrl=”https://dev.azure.com/$($组织)/$($项目)/”
$patToken=“”
$token=[System.Convert]::TOBASE64字符串([System.Text.Encoding]::ASCII.GetBytes(“:$($patToken)”)
$header=@{authorization=“Basic$token”}
$Url=“$($projUrl)\u api/build/definitions?api版本=5.1”
$json=@{
project=“$($project)”;
name=“My.New.Definition.Linked.To.Existing.YAML.File”;
存储库=@{
url=“”;
defaultBranch=“refs/heads/feature/my new feature branch”;
id=“”;
type=“TfsGit”;
};
进程=@{
yamlFilename=“azure管道YAML/my pipeline.yml”;
类型=2;
};
path=“\A新文件夹”;
type=“build”;
}
$body=($json |转换为json-深度3)
调用RestMethod-Uri$Url-Headers$header-Body$Body-Method-Post-ContentType application/json;
指定process=0时失败,因为process
不应该是数字数据类型。进程需要指定一个YAML文件和一个“type”参数
"process": {
"yamlFilename": "build.yaml",
"type": 2
}
我真的忘了什么类型的“2”和类型的“1”和类型的“90072972”,但我过去用过
解决这类问题的最简单方法是创建一个YAML构建,并使用RESTAPI提取JSON定义。我就是这样想出来的。公共类常量
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);
}
{
公共类DevOps
{
公共类构建
{
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\u AUTHORIZATION\u SCOPE=“projectCollection”;
公共常量字符串存储库\u TYPE=“TfsGit”;
public const string CREATE_BUILD_DEF_URI=”https://dev.azure.com/{0}/{1}/_api/build/definitions?api版本=5.0”;
}
}
}
公共类存储库
{
公共字符串id{get;set;}
公共字符串名称{get;set;}
公共字符串url{get;set;}
公共DevPSProject项目{get;set;}
公共整数大小{get;set;}
公共字符串remoteUrl{get;set;}
公共字符串sshull{get;set;}
公共bool isFork{get;set;}
公共链接{get;set;}
公共字符串defaultBranch{get;set;}
公共字符串类型{get;set;}
}
private void CreateIntegrationPipelineWithForkRepository(字符串组织名称、字符串sourceProjectName、字符串sourceProjectId、存储库forkRepository)
{
System.Action动作=委托
{
//*********************************使用CICD创建构建******************///
var continuousIntegration=new List(){new BuildTrigger()};
var referenceYamlPath=new
{
yamlFilename=Constants.DevOps.Build.YAML\u文件路径,//=“Data/azure pipelines.yml”,
类型=2
};
var queueWithAgentPool=new
{
name=Constants.DevOps.Build.AGENT\u POOL\u name,
池=新
{
name=Constants.DevOps.Build.AGENT\u POOL\u name,
isHosted=true
}
};
//将存储库类型设置为:“TfsGit”
forksrepository.type=Constants.DevOps.Build.REPOSITORY_type;//=“TfsGit”;
var requestBuild=new
{
触发器=持续集成,
jobAuthorizationScope=Const
$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