In some automations, you may require to attach a file to a work item in DevOps.
For example, you may want to send an email to a Distribution List, and with the email content and attachments, create a work item based on the subject or simply update the work item with more information.
The connector actions to update the Work Item are very much straight through and will not be approached in this post.
But upload and attaching a file to this work item is not documented to its full extent. Actually, the documentation is somewhat elusive on the actual needs of the Action, but after this, it will make sense.
In my example, I read an attachment from an email and then uploaded it to DevOps.
Adding the attachment to the work item consists of two steps:
- Uploading the File
- Linking it to the Work Item.
Both these steps will use the "Send an HTTP request to Azure DevOps" action.
As per the documentation, you can create file attachments using "Send an HTTP request to Azure DevOps" action. To do this:
- Convert file content to a Base64 string and put it in "Body" parameter.
- Set "Body is Base64" parameter to Yes.
But the action itself does not show the exact needs in the parameters. For example, the "Relative URI" give an example of {project}/{team}/_apis/wit/templates?api-version=5.0-preview.1.
Send an HTTP request to Azure DevOps - Azure DevOps - Connectors | Microsoft Learn
But if you try with just this part of the URL, it will fail with Unauthorized or NotFound.
The URI must be:
I used the API version 7.1-preview3, but you can try this with other versions.
The output bytes from the attachment need to be read as binary, so you need to use the expression to convert the body. With this, you can just set the content-type to what the Get attachment output sends you, as it already inferred it.
The flag Body is Base64 needs to be passed as "Yes".
Remember that you must send the Content of the output, not the full body. We just need the Content bytes.
This POST will upload the file to DevOps.
Keep in mind that you can set the content-type to a fixed value, BUT it may not adjust to every situation. You can restrict your integration to a certain type of files, but if you want to integrate everything, you can choose to grab the Content-type directly from the operation that gets the contents of the file you want to upload.
It will return two properties that we will use, mainly the URL. We need it to PATCH and append it to the Work Item.
As I already knew the output, I used the output directly in the JSON body, and selected the URL property.
I could have parsed the JSON first, but as I already knew it, I skipped this step.
This is the full input to this action (it's still "Send HTTP Request to DevOps")
{
"inputs": {
"host": {
"connection": {
"referenceName": "visualstudioteamservices"
}
},
"method": "post",
"body": {
"Method": "PATCH",
"Uri": "https://dev.azure.com/{team}/{project}/_apis/wit/workItems/{Work Item ID}?api-version=6.0",
"Headers": {
"Content-Type": "application/json-patch+json"
},
"Body": "[
{
"op": "add",
"path": "/relations/-",
"value": {
"rel": "AttachedFile",
"url": "@{body('Upload_File')?['url']}",
"attributes": {
"comment": "Spec for the work"
}
}
}
]",
"IsBase64": false
},
"path": "/httprequest",
"queries": {
"account": "pedroalmeidaXXXX"
}
}
}
You can and should change the comment, but not the other fields. You can see in the body the use of the previous action response and getting the URL property.
Also, the JSON must be properly formatted, so do keep in mind that you may see errors from DevOps if it's not properly formatted.