【问题标题】:Work item creation issue in TFS 2015.2 (with vsts-node-api)TFS 2015.2 中的工作项创建问题(使用 vsts-node-api)
【发布时间】:2017-03-02 00:51:07
【问题描述】:

通过 vso-node-api 包在 TFS 2015.2(本地)中创建错误项时出现以下错误,但是相同的代码在我的 VSTS(在线)订阅中运行良好。

错误:请求失败:错误请求 (400) - TF401349:发生意外错误,请验证您的请求并重试。
状态码:400

我正在使用 vso-node-api 库中的 WorkItemTrackingApi/createWorkItem 函数来创建工作项。以下是我用来创建工作项的示例代码。

WorkItemCreator.ts

import * as vm from 'vso-node-api/WebApi';
import * as wa from 'vso-node-api/WorkItemTrackingApi';
import * as wi from 'vso-node-api/interfaces/WorkItemTrackingInterfaces';
import * as vss from 'vso-node-api/interfaces/Common/VSSInterfaces';
import * as core from 'vso-node-api/interfaces/CoreInterfaces';
import tl = require('vsts-task-lib/task');

export class WorkItemCreator {
    workItemType: string = "Bug";
    fieldsToRetrieve: string[] = ["System.State", "System.Title"];

    collectionUrl: string;
    projName: string;
    accessToken: string;
    vstsWI: wa.IWorkItemTrackingApi;
    projectId: string;

    constructor() {
        console.log("Initializing Workitem Creator...");
        console.log("Retrieving enviornment values...");
        this.collectionUrl = process.env["SYSTEM_TEAMFOUNDATIONCOLLECTIONURI"];
        this.projName = process.env["SYSTEM_TEAMPROJECT"];
        this.projectId = process.env["SYSTEM_TEAMPROJECTID"];

        console.log("SYSTEM_TEAMFOUNDATIONCOLLECTIONURI: " + this.collectionUrl);
        console.log("SYSTEM_TEAMPROJECT: " + this.projName);

        this.accessToken = this.getAccessToken();
        let creds = vm.getBearerHandler(this.accessToken);
        let connection = new vm.WebApi(this.collectionUrl, creds);
        this.vstsWI = connection.getWorkItemTrackingApi();
    }

    /**
     * Create Work Items
     */
    public createWorkItems(workItems: Array<BugItem>) {
        workItems.forEach(workItem => {
            let selectWorkItemsQry = { query: "Select [System.Id] From WorkItems Where [System.WorkItemType] = '" + this.workItemType + "' AND [System.Title] = '" + workItem.title + "'" };
            this.getWorkitem(this.projName, this.projectId, selectWorkItemsQry).then((qr: wi.WorkItemQueryResult) => {
                console.log("WorkItem Count:" + qr.workItems.length);
                if (qr.workItems.length == 0) {
                    console.log("Creating WorkItem '" + workItem.title + "' in project '" + this.projName + "'");
                    let xs: string[] = ["TagX", "TagY", "TagZ"];
                    console.log("Tags: " + xs);
                    this.createWorkitem(this.projName, this.workItemType, workItem.title, workItem.description, workItem.severity, xs);
                }
            })
            .catch((e) => {
                    console.error("Failed to retrieve WorkItem by title '" + workItem.title + "' Error: " + e);
            });
        });        
    }

    //Get acces token
    private getAccessToken(): string {
        tl.debug("Getting credentials for local feeds");
        let auth = tl.getEndpointAuthorization("SYSTEMVSSCONNECTION", false);
        if (auth.scheme === "OAuth") {
            console.log("Token retrieved: " + auth.parameters["AccessToken"]);
            tl.debug("Token retrieved: " + auth.parameters["AccessToken"]);
            return auth.parameters["AccessToken"];
        }
        else {
            tl.warning("Could not retrieve authentication token for Workitem creation.");
        }
    }


    //Create Workitem
    private createWorkitem(projectName: string, witype: string, title: string, description: string, severity: string, tagsCollection: string[]) {
        let wijson: vss.JsonPatchDocument = [
            { "op": "add", "path": "/fields/System.Title", "value": title },
        ];

        this.vstsWI.createWorkItem(null, wijson, projectName, witype, null, null).then((workitem: wi.WorkItem) => {
            console.log("WorkItem '" + workitem.id + "' Created");
        }).catch((e) => {
            console.error("Failed to create work item for '" + title + "' Error: " + e);
        });
    }

    /**
     * Get Workitems
     */
    private getWorkitem(projectName: string, teamProjectId: string, wiqlQuery: wi.Wiql): Promise<wi.WorkItemQueryResult> {
        console.log(wiqlQuery.query);
        let teamContext: core.TeamContext = { project: projectName, projectId: teamProjectId, team: "", teamId: "" };
        return this.vstsWI.queryByWiql(wiqlQuery, teamContext, null, null);
    }
}

/**
 * BugItem
 */
export class BugItem {
    title: string;
    description: string;
    severity: string;

    constructor(title: string, description: string, severity: string) {
        this.title = title;
        this.description = description;
        this.severity = severity;
    }
}

App.ts

/// <reference path="../definitions/node.d.ts" />
/// <reference path="../definitions/minimatch.d.ts" />
const Critical = "1 - Critical";
const Low = "4 - Low";

import * as wIc from './WorkItemCreator';

var x = new wIc.WorkItemCreator();
var fullCollection = new Array<wIc.BugItem>();

var itm1 = new wIc.BugItem("Bug1TitleItem1", "DescriptionCritical", Critical);
fullCollection.push(itm1);
var itm6 = new wIc.BugItem("Bug1TitleItem6","DescriptionLow",Low);
fullCollection.push(itm6);

x.createWorkItems(fullCollection);
console.log("End.");

范围: “范围”:[ "vso.build_execute", “vso.work_write” ],

【问题讨论】:

  • 你是如何通过 TFS 服务器认证的?
  • @Patrick:我已经用身份验证逻辑更新了问题。
  • 您可以从门户网站手动使用代码中的信息创建工作项吗?
  • 是的 Eddie,我能够手动创建工作项。
  • 你能分享整个代码,以便我可以尝试在我身边重现它吗?

标签: tfs azure-devops azure-pipelines azure-pipelines-build-task


【解决方案1】:

正如post 指出的那样,允许的 TFS 仅支持 NTLM 和 Kerberos 进行身份验证。我会假设在 MS 更新 TFS 之前,访问令牌永远不是一个选项。

【讨论】:

  • 您说得对,直到 TFS2017 on-prem 才支持 PAT。但是,根据上面的代码,没有使用 PAT。他们正在使用不记名令牌。例如,每次构建创建的令牌(并由构建任务使用)是 JWT 不记名令牌。
  • ... 参见 getAccessToken 函数。它正在获取每个构建创建的 vss 连接令牌。那是 JWT 不记名令牌,而不是 PAT。
  • @bryanmac 是的,不支持 PAT。那篇文章说唯一支持的身份验证是 NTLM 和 Kerberos。我相信这意味着您只能使用 NTLM 或 Kerberos,对吧?
  • JWT 不记名令牌不是 PAT 令牌。您似乎在暗示,因为不支持 PAT,它留给 NTLM/Kerberos。当我们构建构建服务器时,我们让服务器生成每个构建 JWT 不记名令牌,该令牌作为构建作业消息的一部分向下发送。这就是代理用于返回 TFS/VSTS 服务器的所有通信的内容。
【解决方案2】:

TFS 2015.3 不支持基于令牌的身份验证。另一种方法是使用基本身份验证选项。如果扩展应该与 VSTS 和 TFS 兼容,那么您必须创建一种机制来为每个部署场景使用单独的身份验证机制。 TFS 2017 支持令牌身份验证,因此它可以像 VSTS 一样与 PAT 一起正常工作。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-05-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-04-15
    • 2017-07-20
    • 1970-01-01
    • 2019-03-11
    相关资源
    最近更新 更多