Been writing a Python code to automate a few setups of the organization creation process in my company, but I can’t create new states in some of the work item types. And, in a odd manner, this seems to happen only in work item types that were already in the system. Here’s the full code:
import base64
from os import environ as env
from dotenv import load_dotenv
import requests
import time
import json
import pandas as pd
import contador
load_dotenv()
AZURE_DEVOPS_PAT = env['AZURE_DEVOPS_PAT']
patEncoded = base64.b64encode((":" + AZURE_DEVOPS_PAT).encode()).decode()
organization = 'dummy-name'
headers = {
'Content-Type': 'application/json',
'Authorization': f'Basic {patEncoded}'
}
def getProcessID(testName, organization, headers):
global contador
getUrl = f'https://dev.azure.com/{organization}/_apis/process/processes?api-version=7.1-preview.1'
while True:
try:
req = requests.get(getUrl, headers=headers)
break
except requests.exceptions.ConnectTimeout as e:
contador.contador += 1
print(f"Erro de timeout número {contador.contador}. Tentando novamente...")
time.sleep(10)
json_object = json.loads(req.text)
reqTextSize = len(json_object['value'])
for i in range(reqTextSize):
name = json_object['value'][i]['name']
if name == testName:
processId = json_object['value'][i]['id']
return processId
def criarEstados(tipo, processId, organization, headers):
tabelaRefNames = getWorkItemTypes(processId, organization, headers)
filePath = "printDebug.txt"
if tipo == 'Agile':
tabelaEstados = pd.read_excel('kanban.xlsx')
elif tipo == 'Scrum':
tabelaEstados = pd.read_excel('scrum.xlsx')
tabelaEstados = tabelaEstados.merge(tabelaRefNames, left_on="workItemType", right_on="originName", how='left')
tabelaEstadosDict = tabelaEstados.to_dict()
tabelaEstadosDictSize = len(tabelaEstadosDict["workItemType"])
linhas = []
with open(filePath, 'w') as printDebug:
for i in range(tabelaEstadosDictSize):
workItemType = tabelaEstadosDict["workItemType"][i]
witRefName = tabelaEstadosDict["referenceName"][i]
name = tabelaEstadosDict["originName"][i]
color = tabelaEstadosDict["color"][i]
stateCategory = tabelaEstadosDict["stateCategory"][i]
referenceName = f"{witRefName} foi passado\n"
status = criarEstado(processId, organization, headers, witRefName, name, color, stateCategory)
resultState = f'Estado {name} no Work Item Type {workItemType} deu este retorno:\n'
linhas.extend([resultState, referenceName, f'{status}\n'])
printDebug.writelines(linhas)
linhas.clear()
print("Debug finalizado.")
def main():
testName = "Processo-Kanban"
processId = getProcessID(testName, organization, headers)
criarEstados('Agile', processId, organization, headers)
main()
For Microsoft.VSTS.WorkItemTypes.Bug as witRefName:
{
"$id": "1",
"innerException": null,
"message": "VS402805: Cannot find work item type with reference name 'Microsoft.VSTS.WorkItemTypes.Bug' in process named '07c52453-a09e-4f35-a0f1-40bdb972afb9'.",
"typeName": "Microsoft.TeamFoundation.WorkItemTracking.Server.Metadata.ProcessWorkItemTypeDoesNotExistException, Microsoft.TeamFoundation.WorkItemTracking.Server",
"typeKey": "ProcessWorkItemTypeDoesNotExistException",
"errorCode": 0,
"eventId": 3200
}
For Microsoft.VSTS.WorkItemTypes.UserStory as witRefName:
{
"$id": "1",
"innerException": null,
"message": "VS402805: Cannot find work item type with reference name 'Microsoft.VSTS.WorkItemTypes.UserStory' in process named '07c52453-a09e-4f35-a0f1-40bdb972afb9'.",
"typeName": "Microsoft.TeamFoundation.WorkItemTracking.Server.Metadata.ProcessWorkItemTypeDoesNotExistException, Microsoft.TeamFoundation.WorkItemTracking.Server",
"typeKey": "ProcessWorkItemTypeDoesNotExistException",
"errorCode": 0,
"eventId": 3200
}
For Microsoft.VSTS.WorkItemTypes.Task as witRefName:
{
"$id": "1",
"innerException": null,
"message": "VS402805: Cannot find work item type with reference name 'Microsoft.VSTS.WorkItemTypes.Task' in process named '07c52453-a09e-4f35-a0f1-40bdb972afb9'.",
"typeName": "Microsoft.TeamFoundation.WorkItemTracking.Server.Metadata.ProcessWorkItemTypeDoesNotExistException, Microsoft.TeamFoundation.WorkItemTracking.Server",
"typeKey": "ProcessWorkItemTypeDoesNotExistException",
"errorCode": 0,
"eventId": 3200
}
For Microsoft.VSTS.WorkItemTypes.Epic as witRefName:
{
"$id": "1",
"innerException": null,
"message": "VS402805: Cannot find work item type with reference name 'Microsoft.VSTS.WorkItemTypes.Epic' in process named '07c52453-a09e-4f35-a0f1-40bdb972afb9'.",
"typeName": "Microsoft.TeamFoundation.WorkItemTracking.Server.Metadata.ProcessWorkItemTypeDoesNotExistException, Microsoft.TeamFoundation.WorkItemTracking.Server",
"typeKey": "ProcessWorkItemTypeDoesNotExistException",
"errorCode": 0,
"eventId": 3200
}
I've succeeded with this script to create the work item state, but only for custom work item types. And also I'm able to create new work item type states through the web UI (organization settings in Azure Devops).
Also, once I added the states to the Bug work item type through the web UI, the code captured the witRefName as “Processo-Kanban.Bug”, and no longer as “Microsoft.VSTS.WorkItemTypes.Bug”.
The same happened to the Epic work item type. And, for both, my code seemed to start working as intended.
So is it possible that the witRefName should be something along the lines of f"{processName}.{workItemName)?
Anyway, could anyone please help me?
I've tried different ways to obtain the witRefName, and they all failed. Code's above.
It seemed that you were trying to add new state for the work item type in the default process. Kindly note that to customize the work tracking system, you need to customize an inherited
process.
Here is my work flow for your refence to create new state for the Bug
in one of my inherited processes AgileInherited
.
Get(list) the processId
of the target inherited process via API;
GET https://dev.azure.com/{organization}/_apis/work/processes?api-version=7.2-preview.2
Agile
is one of the 4 default processes, while AgileInherited
is the customized inherited process.
…
{
"typeId": "adcc42ab-9882-485e-a3ed-7678f01f66bc",
"name": "Agile",
"referenceName": null,
"description": "This template is flexible and will work great for most teams using Agile planning methods, including those practicing Scrum.",
"parentProcessTypeId": "00000000-0000-0000-0000-000000000000",
"isEnabled": true,
"isDefault": false,
"customizationType": "system"
},
{
"typeId": "f37a3e41-85fc-4cbd-8a14-5b97df442661",
"name": "AgileInherited",
"referenceName": "Inherited.f37a3e4185fc4cbd8a145b97df442661",
"description": "Inherited process from Agile",
"parentProcessTypeId": "adcc42ab-9882-485e-a3ed-7678f01f66bc",
"isEnabled": true,
"isDefault": true,
"customizationType": "inherited"
},
…
Get(list) the referenceName
of target work item type via API;
GET https://dev.azure.com/{organization}/_apis/work/processes/{processId}/workitemtypes?api-version=7.2-preview.2
Per the Bug
work item type in my InheritedAgile
process, its witRefName
as well as referenceName
is AgileInherited.Bug
;
…
{
"referenceName": "AgileInherited.Bug",
"name": "Bug",
"description": "Describes a divergence between required and actual behavior, and tracks the work done to correct the defect and verify the correction.",
"url": "https://dev.azure.com/{organization}/_apis/work/processes/f37a3e41-85fc-4cbd-8a14-5b97df442661/workItemTypes/AgileInherited.Bug",
"customization": "inherited",
"color": "CC293D",
"icon": "icon_insect",
"isDisabled": false,
"inherits": "Microsoft.VSTS.WorkItemTypes.Bug"
},
…
Create new state Ready to test
for the Bug
in my AgileInherited
process via API;
POST https://dev.azure.com/{organization}/_apis/work/processes/{processId}/workItemTypes/{witRefName}/states?api-version=7.2-preview.1
My Sample
POST https://dev.azure.com/{organization}/_apis/work/processdefinitions/f37a3e41-85fc-4cbd-8a14-5b97df442661/workItemTypes/AgileInherited.Bug/states?api-version=7.2-preview.1
{
"name": "Ready to test",
"stateCategory": "InProgress",
"color": "207752",
"order": null
}
Hope the information could help resolve your concerns.