How to make child-card Discussion notes rollup to parent card in Azure DevOps?
The way we use ADO is like this:
User Story -> Task 1
-> Task 2
-> Task 3
Both User Story cards and Task cards contain Discussion fields, and we have hit a quandary as to "which cards' discussion fields should we use to enter ongoing notes and discussions"? The Parent (user story)? Or the child (task)? It makes more sense for devs to enter discussion notes in the tasks, but our Support people and managers like to just look at the parent User Story card where they hope to see all discussion notes.
For now I am double-entering discussion notes in both tasks and their parent user story cards, which is not only an inefficient pain, but also violates DRY.
Then it occurred to me that the ideal solution would be for user story cards to be able to display (within the Discussion section) all discussion notes from all child cards. So if I enter a note in a Task (child) card and save it, automatically it would appear as a discussion note within its parent user story card. Ideally I could still enter user-story-specific discussion notes on occasion, but all child cards' notes would be automatically pulled in and displayed (maybe readonly? editable only in the child?) in the parent card, in all cases.
Is there an easy way to make this happen?
If the answer to #1 above is no, then is there a difficult way to make it happen? Maybe via customizations or custom API calls? What would be the best way to achieve my desired result?
This is not possible out of the box in Azure DevOps (at least not to my knowledge).
However I can think of a few ways to get this done, but it requires some custom scripting, and have some drawbacks that may of may not affect your use case.
Option 1. Create a custom extension that aggregates the comments on the parent
This option gives you complete freedom of how to visually design the feature. It is also completely DRY
You can develop your own custom extension for Azure DevOps and create a dynamic section on the User Story card that pulls in the comments from all tasks.
Option 2. Setup a Web Hook for the event "Workitem commented on"
This option does is not completely DRY, but it will at least automate the copying of comments across work items.
By configuring a web hook in Azure Devops to post a json object containing information about the new comment to a REST endpoint of your choice. The payload posted looks like below.
{
"subscriptionId": "5be97cbc-ee4b-4c21-91ea-866a61d624c4",
"notificationId": 4,
"id": "fb2617ed-60df-4518-81fa-749faa6c5cd6",
"eventType": "workitem.commented",
"publisherId": "tfs",
"message": {
"markdown": "[Bug #5](http://fabrikam-fiber-inc.visualstudio.com/web/wi.aspx?pcguid=74e918bf-3376-436d-bd20-8e8c1287f465&id=5) (Some great new idea!) commented on by Jamal Hartnett."
},
"detailedMessage": {
"markdown": "[Bug #5](http://fabrikam-fiber-inc.visualstudio.com/web/wi.aspx?pcguid=74e918bf-3376-436d-bd20-8e8c1287f465&id=5) (Some great new idea!) commented on by Jamal Hartnett.\r\nThis is a great new idea"
},
"resource": {
"id": 5,
"rev": 4,
"fields": {
"System.AreaPath": "FabrikamCloud",
"System.TeamProject": "FabrikamCloud",
"System.IterationPath": "FabrikamCloud\\Release 1\\Sprint 1",
"System.WorkItemType": "Bug",
"System.State": "New",
"System.Reason": "New defect reported",
"System.CreatedDate": "2014-07-15T17:42:44.663Z",
"System.CreatedBy": {
"displayName": "Jamal Hartnett",
"url": "https://vssps.dev.azure.com/fabrikam/_apis/Identities/e5a5f7f8-6507-4c34-b397-6c4818e002f4",
"_links": {
"avatar": {
"href": "https://dev.azure.com/mseng/_apis/GraphProfile/MemberAvatars/aad.YTkzODFkODYtNTYxYS03ZDdiLWJjM2QtZDUzMjllMjM5OTAz"
}
},
"id": "e5a5f7f8-6507-4c34-b397-6c4818e002f4",
"uniqueName": "Jamal Hartnett",
"imageUrl": "https://dev.azure.com/fabrikam/_api/_common/identityImage?id=e5a5f7f8-6507-4c34-b397-6c4818e002f4",
"descriptor": "ukn.VXkweExUVXRNakV0TWpFME5qYzNNekE0TlMwNU1ETXpOak15T0RVdE56RTVNelEwTnpBM0xURXpPRGswTlRN"
},
"System.ChangedDate": "2014-07-15T17:42:44.663Z",
"System.ChangedBy": {
"displayName": "Jamal Hartnett",
"url": "https://vssps.dev.azure.com/fabrikam/_apis/Identities/e5a5f7f8-6507-4c34-b397-6c4818e002f4",
"_links": {
"avatar": {
"href": "https://dev.azure.com/mseng/_apis/GraphProfile/MemberAvatars/aad.YTkzODFkODYtNTYxYS03ZDdiLWJjM2QtZDUzMjllMjM5OTAz"
}
},
"id": "e5a5f7f8-6507-4c34-b397-6c4818e002f4",
"uniqueName": "Jamal Hartnett",
"imageUrl": "https://dev.azure.com/fabrikam/_api/_common/identityImage?id=e5a5f7f8-6507-4c34-b397-6c4818e002f4",
"descriptor": "ukn.VXkweExUVXRNakV0TWpFME5qYzNNekE0TlMwNU1ETXpOak15T0RVdE56RTVNelEwTnpBM0xURXpPRGswTlRN"
},
"System.Title": "Some great new idea!",
"System.Parent": 26
"Microsoft.VSTS.Common.Severity": "3 - Medium",
"WEF_EB329F44FE5F4A94ACB1DA153FDF38BA_Kanban.Column": "New",
"System.History": "This is a great new idea"
},
"_links": {
"self": {
"href": "http://fabrikam-fiber-inc.visualstudio.com/DefaultCollection/_apis/wit/workItems/5"
},
"workItemUpdates": {
"href": "http://fabrikam-fiber-inc.visualstudio.com/DefaultCollection/_apis/wit/workItems/5/updates"
},
"workItemRevisions": {
"href": "http://fabrikam-fiber-inc.visualstudio.com/DefaultCollection/_apis/wit/workItems/5/revisions"
},
"workItemType": {
"href": "http://fabrikam-fiber-inc.visualstudio.com/DefaultCollection/_apis/wit/ea830882-2a3c-4095-a53f-972f9a376f6e/workItemTypes/Bug"
},
"fields": {
"href": "http://fabrikam-fiber-inc.visualstudio.com/DefaultCollection/_apis/wit/fields"
}
},
"url": "http://fabrikam-fiber-inc.visualstudio.com/DefaultCollection/_apis/wit/workItems/5"
},
"resourceVersion": "1.0",
"resourceContainers": {
"collection": {
"id": "c12d0eb8-e382-443b-9f9c-c52cba5014c2"
},
"account": {
"id": "f844ec47-a9db-4511-8281-8b63f4eaf94e"
},
"project": {
"id": "be9b3917-87e6-42a4-a549-2bc06a7a878f"
}
},
"createdDate": "2022-07-03T12:30:03.0691717Z"
}
In particular you have the comment message under message, the author of the message under fields.System.ChangedBy, the date of the comment in fields.System.ChangedDate and the parent workitem id in System.Parent
Using this information your REST service that receives the json object can create a comment on the parent work item using the Comments Rest API or post an update to the workitem where you set the System.History field to the value of the comment. This also allows you to set the original comment time and author, given that the user account you use in your automation has the permission Bypass rules on work item updates granted.
Drawbacks
If tasks can be moved from one user story to another, then the task comments on the user stories need to be moved. The same idea as above can be applied to solve this. By configuring a webhook for WorkItem updated you can listen for all updates to tasks.
By fetching the previous revision (Revision is found in resource.rev) from the Revision Rest API and comparing the field System.Parent you can determine whether the task has been moved or not and add the comments to the new parent and remove them from the old.
Similarly if you want to propagate comment updates and reactions, you would need to extend the webhook functionality even further.
Related
I'm trying to migrate chatbot to use newly introduced Assistant API v2.
My chatbot infrastructure includes Middleware services which modifies the context after getting the response from Watson. In some case I used to remove particular properties from the context and it worked fine. However I noticed that after migration to API v2 this approach does not work anymore as the deleted properties are somehow stored on Watson side.
For example I received following context from Watson:
{
"assistantId": "---",
"sessionId": "---",
"messageInput": {
"Text": "Some text",
"Options": {
"Debug": "true",
"ReturnContext": "true",
"Restart": "false"
}
},
"context":
{
"Global": "null",
"Skills": {
"AdditionalProperties": {
"main skill": {
"user_defined": {
"id": "23",
"description": "Dont know"
},
"system": {---}
}
}
}
}
}
Then I remove 'description' from the context and send request to Watson once more. Surprisingly 'description' is still there with the same value ('Dont know').
Possible solution would be not to remove a property but to set it's value to empty string. But even in this case my dialog does not work correctly as Watson somehow stores the point in dialog it was visiting previously (or not, these are my guesses). I assume it might be related to system.state property which stores an encoded state of the dialog (again - or not).
My question is why is dialog behaving this way?
How does it store the context information so I can't remove properties from user_defined context?
And how can I reset dialog state to initial keeping the same conversation_id (session_id)?
P.S. I'm using Watson API v2: 2020-04-01
In Azure Devops REST API, I want to link a task\bug\story (that already exists) when triggering a build. How do I do that?
checkInTicket might be a solution, but it is not documented.
Payload based on Merlin's response worked:
var payload = new object[] {
new {
op = "add",
path = "/relations/-",
value =
new {
rel = "ArtifactLink",
url = $"vstfs:///Build/Build/{buildId}",
attributes = new
{
name = "Build"
}
}
}
};
1. Approach 1
Same with the UI operation, to link the exists work item to build, just need to update one option in build definition:
This is the api:
https://dev.azure.com/{org name}/{project name}/_apis/build/definitions/{definition id}?api-version=5.0-preview.6
In its request body, please focus on below script part:
"options": [
{
"enabled": true,
"inputs": {
"branchFilters": "[\"+refs/heads/*\"]",
"additionalFields": "{}"
},
"definition": {
"id": "5d58cc01-7c75-450c-be18-a388ddb129ec"
}
}
]
The enabled represent whether it will create links to work items which linked to associated changes after the build completed. To achieve what you want, here, please set the enabled value as true. The id value is fixed and represent this option, so here do not worry about this id value.
When you updating the build definition by this method, do not forget increment the revision in request body. revision increment means update the definition as a new revision. or the update action would not actually succeed.
But, what you should concerned is this update should finished before the build triggered. Thus it will create link to the exists WIT automatically after the build finished.
Also, this would only add this build link to work item which associate with the changes.
2. Approach 2
If the above is not what you want, and you just want to link work item to build while the build is triggered. Afraid to say, there's no such direct API could finish that.
You may need to use 2 APIs: one of it is queue build, and another API is add this build link to work item.
The request body sample of add build link to work item:
[
{
"op": "test",
"path": "/rev",
"value": "2"
},
{
"op": "add",
"path": "/relations/-",
"value":
{
"rel": "ArtifactLink",
"url": "vstfs:///Build/Build/{the build id that you just queued}"
}
}
]
This method need you get the generated BuildId after you queue the build, and then pass it to the workitem API. Different with the approach 1, in this method, you can customize the work item id which you want to add the build link to.
I've managed to successfully checkout a file using the https://graph.microsoft.com/beta/drives/{driveId}/items/{itemId}/checkout
Now, I'd like to get the information about the user, who actually perform the checkout operation.
It's possible to check if the item is locked:
https://graph.microsoft.com/beta/drives/{driveId}/items/{itemId}?select=*,publication
However, according to DOCs, publication doesn't provide information about the checked user. Without information who locked the file is the whole checkin/checkout logic is useless.
This kind of information could be retrieved via the metadata for an item in a list as demonstrated below:
https://graph.microsoft.com/beta/sites/{site-id}/lists/{list-id}/items/{item-id}?expand=fields(select=CheckoutUserLookupId)
Once you get checkout user id (CheckoutUserLookupId field) , user details could be determined via the following endpoint:
https://graph.microsoft.com/v1.0/sites/{site-id}/lists('User Information List')/items/{CheckoutUserLookupId}
where CheckoutUserLookupId is the user id from the previous request
https://graph.microsoft.com/beta/sites/{site-id}/lists/{list-id}/items/{item-id} can't work with folders.
Anyway, drive endpoint "Allows access to the list as a drive" (according to MS Graph Docs). It works with folders as expected.
So I have
get the drive-id: /sites/${siteId}/drives
list root folder: /drives/{drive-id}/items/root/children?select=name,publication
if an item is locked, it's possible to list the activity on the item:
/drives/${idObj.driveId}/items/${idObj.fileId}?select=id&expand=activities
return list of actions:
"activities": [
{
"#odata.type": "#oneDrive.activityEntity",
"#odata.id": "https://xxxxxxxxxx/v2.0/oneDrive.activityEntity2a3649d6-2xxxxx",
"#odata.editLink": "oneDrive.activityEntity2a3649d6xxxxxx",
"#sharePoint.localizedRelativeTime": "0|July 30",
"action": {
"checkout": {}
},
"actor": {
"user": {
"email": "XXX#XXX",
"displayName": "vladimir",
"self": {},
"userPrincipalName": "XXX#XXX
}
},
"id": "XXXXXXXXXXXXXX",
"times": {
"recordedTime": "2018-07-31T04:59:03Z"
}
},
although no user ID at least a have the email....
I would like to know if there is an function in the Github API which would return the status of a pull request whether its accepted or rejected. Does such a function exist?
I was stymied by this problem, too. I had a hard time finding relevant info in the docs.
Option A
The tactic I've landed on is to use the issues search endpoint with the review qualifier in the q param.
So, in my case, when I want to see all PRs assigned to me that have not yet been reviewed, I'd hit this endpoint: https://github.com/api/v3/search/issues?q=is:open+is:pr+review-requested:jordan-bonitatis+review:none
Other review qualifiers include approved and changes_requested as explained here: https://docs.github.com/en/github/searching-for-information-on-github/searching-issues-and-pull-requests#search-by-pull-request-review-status-and-reviewer
Option B
If you want to see the review status for a given PR, instead of getting a list filtered by status like in my example above, you can hit the pull requests reviews endpoint: /repos/:owner/:repo/pulls/:number/reviews
This will return a list of reviews for the PR, each of which have a state key.
Note that a given PR may have multiple reviews with conflicting states. Like, if teamMemberA approved it but teamMemberB requested changes. You'll have to traverse the entire list and decide how you want to treat it based on all the states.
Depending on the repo configuration you can get the answer one way or another. The examples below use the GraphQL API.
Case 1: PR reviews are required before merging
You can query reviewDecision on the pullRequest field for a given repository.
reviewDecision is of type PullRequestReviewDecision, an enum with values of APPROVED, CHANGES_REQUESTED, and REVIEW_REQUIRED.
Example query:
{
repository(name: "gatsby", owner: "gatsbyjs") {
pullRequest(number: 30371) {
title
reviewDecision
url
}
}
}
Response:
{
"data": {
"repository": {
"pullRequest": {
"title": "chore(gatsby): don't terminate dev server if graphql wasn't imported from gatsby",
"reviewDecision": "APPROVED",
"url": "https://github.com/gatsbyjs/gatsby/pull/30371"
}
}
}
}
Case 2: PR reviews are not required before merging
If the repository settings don't specify that reviews are required, reviewDecision will be null regardless of approvals.
In this case you could iterate over the reviews and check the states. state is of type PullRequestReviewState, an enum with values of APPROVED, CHANGES_REQUESTED, COMMENTED, DISMISSED, and PENDING.
Example query:
{
repository(name: "create-react-app", owner: "facebook") {
pullRequest(number: 10003) {
title
reviewDecision
url
reviews(first: 100) {
nodes {
state
author {
login
}
}
}
}
}
}
Response:
{
"data": {
"repository": {
"pullRequest": {
"title": "Update postcss packages",
"reviewDecision": null,
"url": "https://github.com/facebook/create-react-app/pull/10003",
"reviews": {
"nodes": [
{
"state": "APPROVED",
"author": {
"login": "jasonwilliams"
}
}
]
}
}
}
}
}
It's possible to filter reviews for approvals: reviews(first: 100, states: APPROVED).
Note that two reviews will be returned if a reviewer gives his approval and subsequently requests changes.
Checking the PR state (of type PullRequestState) could be misleading: an admin user may have bypassed the required review process to merge changes.
You can get a single PR and check its state and merged properties. If it's merged, then it's accepted. If it's closed and not merged it may be rejected.
In fact it may be not rejected but closed by a creator. I'm not sure if it's possible to check if it was closed by another user (rejected) or by it's creator (denied).
I had a similar requirement - to know if a PR has been approved or not before merging it to master. I added a rule on the repo to ensure that every PR must be approved prior to merging. Then on using the API to get details about the branch there was one field which stated if the branch was clean to merge or blocked . I used this as a way to mange things in my app.
mergeable_state
This is now possible using GraphQL.
Specifically if the mergeStateStatus enum is BLOCKED then the pull request hasn't been approved and for any other status it would have been approved.
This enum is present in the PullRequest object. Do note that at the time of posting this is a preview feature and so must have the appropriate header to work. It will also not work using the GraphQL Explorer while it's in preview.
In the official Github API Documentation it shows that there is a GET request you can make that has the field merged_at if it has already been merged. Edit: theres also a merged field as well.
Snippet:
...
"merge_commit_sha": "e5bd3914e2e596debea16f433f57875b5b90bcd6",
"merged": false,
"mergeable": true,
"merged_by": {
"login": "octocat",
"id": 1,
"avatar_url": "https://github.com/images/error/octocat_happy.gif",
"gravatar_id": "",
"url": "https://api.github.com/users/octocat",
"html_url": "https://github.com/octocat",
"followers_url": "https://api.github.com/users/octocat/followers",
"following_url": "https://api.github.com/users/octocat/following{/other_user}",
"gists_url": "https://api.github.com/users/octocat/gists{/gist_id}",
"starred_url": "https://api.github.com/users/octocat/starred{/owner}{/repo}",
"subscriptions_url": "https://api.github.com/users/octocat/subscriptions",
"organizations_url": "https://api.github.com/users/octocat/orgs",
"repos_url": "https://api.github.com/users/octocat/repos",
"events_url": "https://api.github.com/users/octocat/events{/privacy}",
"received_events_url": "https://api.github.com/users/octocat/received_events",
"type": "User",
"site_admin": false
},
I have been working on TFS REST api, to get the work items(bug,task) details.
I have used GET method,
GET https://shankarsam.visualstudio.com/DefaultCollection/New-1/_apis/wit/queries/Shared%20Queries/My%20Bugs?$depth=1&api-version=2.2
It shows the following output
"id": "e7731d7b-10d2-441f-899f-b081e4008b21",
"name": "My Bugs",
"path": "Shared Queries/My Bugs",
"createdBy":
{
"id": "7bb24a89-a490-4ffa-9047-252e4a2b274b",
"displayName": "kalaisankaran B "
},
"createdDate": "2016-07-15T05:30:18.34Z",
"lastModifiedBy":
{
"id": "7bb24a89-a490-4ffa-9047-252e4a2b274b",
"displayName": "kalaisankaran B "
},
"lastModifiedDate": "2016-07-15T05:30:18.34Z",
"isPublic": true,
I couldn't get all bug details.
In case of UI, I have navigated to Shared Queries -> My Bugs -> Bugs has been listed. Please see the attached screen shot.
The best place to start with this is to look at the REST API Documentation. It covers this exact scenario with some useful examples.
I see that you have retrieved the query hierarchy, and with that you can run a query and then get the work items.
From your call above, I will use the "My Bugs" query as the example.
GET https://shankarsam.visualstudio.com/DefaultCollection/New-1/_apis/wit/wiql/7731d7b-10d2-441f-899f-b081e4008b21
Which will return query results:
{
"queryType": "flat",
"workItems": [
{
"id": 300,
"url": "https://fabrikam-fiber-inc.visualstudio.com/DefaultCollection/_apis/wit/workItems/300"
}
]
}
From that, you can use the id property in the result to get the work item:
GET https://shankarsam.visualstudio.com/DefaultCollection/New-1/_apis/wit/workItems/1
Which will return the work item.
I got the solution. If we need to display all the Bugs or Tasks which is associated in the project. Use the following rest api call.
POST https://<Account Name>.visualstudio.com/DefaultCollection/<Project Name>/_apis/wit/wiql?api-version=1.0
Ex :
POST https://shankarsam.visualstudio.com/DefaultCollection/New-1/_apis/wit/wiql?api-version=1.0
Header :
Content-Type application/json
Request Body Ex :
{
"query": "Select [System.Id], [System.Title], [System.State] From WorkItems Where [System.WorkItemType] = 'Bug'"
}
Need to display Task item means , try this [System.WorkItemType] = 'Task'
Display Bug or Task related work items, Repo's try this :
GET https://<Account Name>.visualstudio.com/DefaultCollection/_apis/wit/workitems?id=<Issue ID>&$expand=all&api-version=1.0
Ex:
GET https://shankarsam.visualstudio.com/DefaultCollection/_apis/wit/workitems?id=23&$expand=all&api-version=1.0