diff --git a/packages/source-control-azure-devops/src/server/azureDevOpsPullRequestJson.test.ts b/packages/source-control-azure-devops/src/server/azureDevOpsPullRequestJson.test.ts index b9b1e36a9434..9a1911655c26 100644 --- a/packages/source-control-azure-devops/src/server/azureDevOpsPullRequestJson.test.ts +++ b/packages/source-control-azure-devops/src/server/azureDevOpsPullRequestJson.test.ts @@ -248,6 +248,41 @@ describe("decodeThreadsJson", () => { expect(comments.map((comment) => comment.id)).toEqual(["4:1", "4:2", "4:3"]); }); + it("marks a comment whose text was edited, not one only otherwise updated", () => { + const comments = expectSuccess( + decodeThreadsJson( + asJson({ + value: [ + { + id: 5, + comments: [ + { + id: 1, + content: "Edited remark.", + publishedDate: "2026-07-02T00:00:00Z", + lastUpdatedDate: "2026-07-02T03:00:00Z", + lastContentUpdatedDate: "2026-07-02T03:00:00Z", + }, + { + id: 2, + content: "Updated remark.", + publishedDate: "2026-07-02T01:00:00Z", + lastUpdatedDate: "2026-07-02T04:00:00Z", + lastContentUpdatedDate: "2026-07-02T01:00:00Z", + }, + ], + }, + ], + }), + ), + ); + + expect(comments.map((comment) => comment.editedAt)).toEqual([ + "2026-07-02T03:00:00Z", + undefined, + ]); + }); + it("drops deleted threads and threads with nothing to show", () => { const comments = expectSuccess( decodeThreadsJson( diff --git a/packages/source-control-azure-devops/src/server/azureDevOpsPullRequestJson.ts b/packages/source-control-azure-devops/src/server/azureDevOpsPullRequestJson.ts index b3632ef1af98..7d9a22af1d98 100644 --- a/packages/source-control-azure-devops/src/server/azureDevOpsPullRequestJson.ts +++ b/packages/source-control-azure-devops/src/server/azureDevOpsPullRequestJson.ts @@ -85,6 +85,8 @@ const RawThreadSchema = Schema.Struct({ content: Schema.optional(Schema.NullOr(Schema.String)), author: Schema.optional(Schema.NullOr(RawIdentitySchema)), publishedDate: Schema.optional(Schema.NullOr(Schema.String)), + // lastUpdatedDate moves on any change to the comment; this one only on its text. + lastContentUpdatedDate: Schema.optional(Schema.NullOr(Schema.String)), isDeleted: Schema.optional(Schema.NullOr(Schema.Boolean)), commentType: Schema.optional(Schema.NullOr(Schema.String)), }), @@ -301,6 +303,7 @@ export function decodeThreadsJson( const path = toRepositoryPath(thread.threadContext?.filePath); for (const comment of thread.comments ?? []) { const publishedDate = trimmed(comment.publishedDate); + const editedAt = trimmed(comment.lastContentUpdatedDate); if ( comment.isDeleted === true || comment.commentType?.trim().toLowerCase() === "system" || @@ -315,6 +318,9 @@ export function decodeThreadsJson( author: toActor(comment.author), body: comment.content ?? "", createdAt: publishedDate, + ...(editedAt !== null && Date.parse(editedAt) > Date.parse(publishedDate) + ? { editedAt } + : {}), url: null, path, reviewState: null,