How to make child-card Discussion notes rollup to parent card?

Viewed 99

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.

  1. Is there an easy way to make this happen?
  2. 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?
1 Answers

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

  1. 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.
  2. Similarly if you want to propagate comment updates and reactions, you would need to extend the webhook functionality even further.
Related