我正在构建“如何对构建进行排队并仅使用azure devops nuget运行特定阶段?”中提出的问题,但我需要进一步扩展它,以指定一些资源。
在我的管道 YAML 中,我定义了一个“管道”资源,最终用于下载构建工件。
我可以使用引用问题中提到的相同
PipelinesHttpClient
来检索手动执行的管道运行(注意:重要的是使用“Microsoft.Azure.Pipelines.WebApi”命名空间中的客户端,而不是使用较旧的“Microsoft.TeamFoundation.Pipelines.WebApi”命名空间)。
通过该实例,我看到它有一个
Resources
属性,该属性进一步具有 Repositories
属性,其中包含一个名为“self”的项目,其中包含“Microsoft.Azure.Pipelines.WebApi.RepositoryResource”的实例。
当尝试在代码中复制此实例时,问题就出现了。 我最终陷入尝试实例化我需要分配给
RunResourcesParameters
实例的 RunPipelineParameters
属性的 Resources
实例。
如果我只是实例化一个“vanilla”
RunPipelineParameters
实例,我最终会得到它的Resources
属性为空:
我看到它的类型是
RunResourcesParameters
,所以尝试实例化它。但是,由于其保护级别,它不会让我这样做:
var runResourcesParameters = new RunResourcesParameters();
它还有另一个 ctor,但同样如此:
var runResourcesParameters2 = new RunResourcesParameters((ISecuredObject)(new object()));
如果我尝试在
RunPipelineParameters
实例上进行对象初始化,当然会出现同样的问题:
var runParameters = new RunPipelineParameters{Resources = };
var runParameters = new RunPipelineParameters{Resources = new RunResourcesParameters()};
我做错了什么?
我查看了“.NET 客户端示例”,但它不包含
PipelinesHttpClient
的任何内容。
我注意到该存储库早在 2021 年就已设置为只读模式。
“Microsoft.TeamFoundationServer.Client”NuGet 包的 NuGet 页面显示,这些天有一个全新的 19.x 系列包处于预览状态,因此示例可能会与此结合恢复?
为了解决这个问题,我们可以使用以下代码:
string json = @"{ 'Builds': {}, 'Containers': {}, 'Repositories': {}, 'Pipelines': {}, 'Packages': {} }";
RunResourcesParameters test = JsonConvert.DeserializeObject<RunResourcesParameters>(json);
test.Pipelines.Add(name, PipelineResource);
parameters.Resources = test;
完整代码示例:
using System;
using System.IO;
using System.Runtime.Serialization;
using Microsoft.Azure.Pipelines.WebApi;
using Microsoft.TeamFoundation.Build.WebApi;
using Microsoft.TeamFoundation.Core.WebApi;
using Microsoft.TeamFoundation.SourceControl.WebApi;
using Microsoft.VisualStudio.Services.Common;
using Microsoft.VisualStudio.Services.WebApi;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
namespace ConsoleApp5
{
class Program
{
static async Task Main(string[] args)
{
var vssConnection = new VssConnection(new Uri("https://dev.azure.com/orgname"), new VssBasicCredential(string.Empty, "PAT"));
var name = "pipelineresourcename";
var pipelineClient = new PipelinesHttpClient(vssConnection.Uri, vssConnection.Credentials);
var PipelineResource = new PipelineResourceParameters();
PipelineResource.Version = "Pipelineresourceversion";
var parameters = new RunPipelineParameters();
string json = @"{ 'Builds': {}, 'Containers': {}, 'Repositories': {}, 'Pipelines': {}, 'Packages': {} }";
RunResourcesParameters test = JsonConvert.DeserializeObject<RunResourcesParameters>(json);
test.Pipelines.Add(name, PipelineResource);
parameters.Resources = test;
var run = await pipelineClient.RunPipelineAsync(parameters, "projectid", pipelineid);
}
}
}
当您运行c#示例时,将传递管道资源信息。
作为我感谢@kevin-lu-msft 帮助解决我的问题的评论的后续内容,我还将发布一些附加信息。
通过他的 JSON 反序列化技巧,我能够运行我的管道。 但是,它一直失败,因为我需要引用特定的构建,以下载一些构建工件。 我只为发布构建生成这些构建工件,我也为标签构建了这些构建工件。而不是一个分支。
通过仅指定我想要引用的管道的名称,它不断地向我提供对默认分支的引用,该分支不包含预期的构建工件,因此失败(正如它应该的那样)。
然后我偶然发现其他人描述了他们对“PipelineResourceParameters”类型的使用。 那里提到管道资源中使用的名称应该与实际资源声明(在构建管道中)中使用的名称匹配(我的解释)。
然后我继续查看现有手动运行的元数据:
var existingRun = await pipelinesClient.GetRunAsync(AdoProjectName, buildDefinitionId, buildId);
其“Url”属性指向一个 JSON 文档,其中包含“管道”部分:
"pipelines": {
"$(PipelineResourceIdentifier)": {
"pipeline": {
"url": "some_url",
"id": some_id,
"revision": some_revision,
"name": "some_name",
"folder": "\\some_folder"
},
"version": "some_tag"
}
}
在我的管道中,我实际上使用“$(PipelineResourceIdentifier)”:
variables:
- name: PipelineResourceIdentifier
value: "Build"
resources:
# Reference a build pipeline, to ease download of build artifacts
# For details, see: https://learn.microsoft.com/en-us/azure/devops/pipelines/process/resources?view=azure-devops&tabs=schema#define-a-pipelines-resource
pipelines:
- pipeline: $(PipelineResourceIdentifier) # Doc: "Identifier for the resource used in pipeline resource variables"
source: "some_pipeline" # Doc: "Name of the pipeline that produces an artifact"
trigger: none # Doc: "A new run of the current pipeline is NOT triggered whenever the resource pipeline successfully completes a run"
[...]
# For details, see: https://learn.microsoft.com/en-us/azure/devops/pipelines/process/resources?view=azure-devops&tabs=example#download-for-pipelines
- download: $(PipelineResourceIdentifier)
artifact: $(GitVersionArtifactIdentifier) # Doc: "Artifact to download, optional; defaults to all the artifacts from the resource"
displayName: "GitVersion - Step 1/2 (download build artifact from main build)"
如您所见,将管道资源标识符指定为管道变量的原因是为了稍后重用它以用于构建工件下载目的。
事实证明“PipelineResourceParameters”类型非常字面意思。如上所述,如果您只是指定管道的实际名称,它不起作用。如果您指定该管道变量的值(即本例中的“构建”),它也不起作用。
事实上,它的字面意思必须是这样的:
runResourcesParameters.Pipelines.Add("$(PipelineResourceIdentifier)", pipelineResourceParameters);
这似乎有点脆弱,如果您碰巧在某个时候更改了管道变量的名称...... 不管怎样,它就像一个魅力!
迟到了,但我会补充一点,这不是一个错误,而是一个功能...... Microsoft.TeamFoundationServer.Client 变量类构造函数 - 开发人员社区 (visualstudio.com)
所以 @Kevin 的序列化/反序列化技巧是有效的。对于变量 - 我创建了 PublicVariable 类来模仿 Variable 类,它确实有效。