From f1a3cdc4c6b63fab4a465f51ffb54e13c31e80c5 Mon Sep 17 00:00:00 2001 From: Christopher Chong Date: Sun, 17 Jul 2022 11:28:15 +0000 Subject: [PATCH] integrations: Add Azure DevOps webhook integration. --- .../images/integrations/azuredevops/001.png | Bin 0 -> 49300 bytes .../integrations/bot_avatars/azuredevops.png | Bin 0 -> 3271 bytes .../images/integrations/logos/azuredevops.svg | 12 + zerver/lib/integrations.py | 2 + zerver/webhooks/azuredevops/__init__.py | 0 zerver/webhooks/azuredevops/doc.md | 28 + .../code_pull_request__merge_attempted.json | 114 +++ .../fixtures/code_pull_request__merged.json | 135 +++ .../fixtures/code_pull_request__opened.json | 113 +++ ...l_request__opened_without_description.json | 129 +++ .../fixtures/code_pull_request__updated.json | 136 +++ .../azuredevops/fixtures/code_push.json | 107 +++ .../code_push__commits_more_than_limit.json | 842 ++++++++++++++++++ ...de_push__local_branch_without_commits.json | 90 ++ .../code_push__multiple_committers.json | 122 +++ ...push__multiple_committers_with_others.json | 182 ++++ .../fixtures/code_push__remove_branch.json | 90 ++ zerver/webhooks/azuredevops/tests.py | 94 ++ zerver/webhooks/azuredevops/view.py | 182 ++++ 19 files changed, 2378 insertions(+) create mode 100644 static/images/integrations/azuredevops/001.png create mode 100644 static/images/integrations/bot_avatars/azuredevops.png create mode 100644 static/images/integrations/logos/azuredevops.svg create mode 100644 zerver/webhooks/azuredevops/__init__.py create mode 100644 zerver/webhooks/azuredevops/doc.md create mode 100644 zerver/webhooks/azuredevops/fixtures/code_pull_request__merge_attempted.json create mode 100644 zerver/webhooks/azuredevops/fixtures/code_pull_request__merged.json create mode 100644 zerver/webhooks/azuredevops/fixtures/code_pull_request__opened.json create mode 100644 zerver/webhooks/azuredevops/fixtures/code_pull_request__opened_without_description.json create mode 100644 zerver/webhooks/azuredevops/fixtures/code_pull_request__updated.json create mode 100644 zerver/webhooks/azuredevops/fixtures/code_push.json create mode 100644 zerver/webhooks/azuredevops/fixtures/code_push__commits_more_than_limit.json create mode 100644 zerver/webhooks/azuredevops/fixtures/code_push__local_branch_without_commits.json create mode 100644 zerver/webhooks/azuredevops/fixtures/code_push__multiple_committers.json create mode 100644 zerver/webhooks/azuredevops/fixtures/code_push__multiple_committers_with_others.json create mode 100644 zerver/webhooks/azuredevops/fixtures/code_push__remove_branch.json create mode 100644 zerver/webhooks/azuredevops/tests.py create mode 100644 zerver/webhooks/azuredevops/view.py diff --git a/static/images/integrations/azuredevops/001.png b/static/images/integrations/azuredevops/001.png new file mode 100644 index 0000000000000000000000000000000000000000..f20fb2197d428348df2e2fb7c9678851200af4cb GIT binary patch literal 49300 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 K1oE!#i~j*}OC*N? literal 0 HcmV?d00001 diff --git a/static/images/integrations/bot_avatars/azuredevops.png b/static/images/integrations/bot_avatars/azuredevops.png new file mode 100644 index 0000000000000000000000000000000000000000..019e9ee0ec1de8868cebe4d1fd94ee314018ba0f GIT binary patch literal 3271 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 literal 0 HcmV?d00001 diff --git a/static/images/integrations/logos/azuredevops.svg b/static/images/integrations/logos/azuredevops.svg new file mode 100644 index 0000000000..aba8103277 --- /dev/null +++ b/static/images/integrations/logos/azuredevops.svg @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/zerver/lib/integrations.py b/zerver/lib/integrations.py index b17f049e4f..5c3ebb41ef 100644 --- a/zerver/lib/integrations.py +++ b/zerver/lib/integrations.py @@ -334,6 +334,7 @@ WEBHOOK_INTEGRATIONS: List[WebhookIntegration] = [ WebhookIntegration("ansibletower", ["deployment"], display_name="Ansible Tower"), WebhookIntegration("appfollow", ["customer-support"], display_name="AppFollow"), WebhookIntegration("appveyor", ["continuous-integration"], display_name="AppVeyor"), + WebhookIntegration("azuredevops", ["version-control"], display_name="AzureDevOps"), WebhookIntegration("beanstalk", ["version-control"], stream_name="commits"), WebhookIntegration("basecamp", ["project-management"]), WebhookIntegration("beeminder", ["misc"], display_name="Beeminder"), @@ -690,6 +691,7 @@ DOC_SCREENSHOT_CONFIG: Dict[str, List[BaseScreenshotConfig]] = { "ansibletower": [ScreenshotConfig("job_successful_multiple_hosts.json")], "appfollow": [ScreenshotConfig("review.json")], "appveyor": [ScreenshotConfig("appveyor_build_success.json")], + "azuredevops": [ScreenshotConfig("code_push.json")], "basecamp": [ScreenshotConfig("doc_active.json")], "beanstalk": [ ScreenshotConfig("git_multiple.json", use_basic_auth=True, payload_as_query_param=True) diff --git a/zerver/webhooks/azuredevops/__init__.py b/zerver/webhooks/azuredevops/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/zerver/webhooks/azuredevops/doc.md b/zerver/webhooks/azuredevops/doc.md new file mode 100644 index 0000000000..515f087f12 --- /dev/null +++ b/zerver/webhooks/azuredevops/doc.md @@ -0,0 +1,28 @@ +Get Azure Devops notifications in Zulip! + +1. {!create-stream.md!} + +1. {!create-bot-construct-url.md!} + + {!git-webhook-url-with-branches.md!} + +1. Go to your project on Azure DevOps and click on the **Project + settings** in the bottom left corner. Select **Service + hooks**. Click on **Create subscription**. Select **Web hooks** and + then **Next**. + +1. Select the events you would like to receive notifications for and + then click **Next**. This integration supports the following + events: + * Code pushed + * Pull request created + * Pull request updated + * Pull request merge attempted + +1. Set **URL** to the URL constructed above. Ensure that **Resource + details to send** and **Detailed messages to send** are set to + **All**. Click **Finish**. + +{!congrats.md!} + +![](/static/images/integrations/azuredevops/001.png) diff --git a/zerver/webhooks/azuredevops/fixtures/code_pull_request__merge_attempted.json b/zerver/webhooks/azuredevops/fixtures/code_pull_request__merge_attempted.json new file mode 100644 index 0000000000..b50d4d8119 --- /dev/null +++ b/zerver/webhooks/azuredevops/fixtures/code_pull_request__merge_attempted.json @@ -0,0 +1,114 @@ +{ + "subscriptionId": "4f1eccb6-04ff-45dd-90aa-713078e5c395", + "notificationId": 5, + "id": "e41a8834-0875-4fa1-ace0-ba656e630af9", + "eventType": "git.pullrequest.merged", + "publisherId": "tfs", + "message": { + "text": "Merge attempted for pull request 4 (Add 4th PR) in test-zulip\r\nhttps://dev.azure.com/ttchong/test-zulip/_git/test-zulip/", + "html": "Merge attempted for pull request 4 (Add 4th PR) in test-zulip", + "markdown": "Merge attempted for [pull request 4](https://dev.azure.com/ttchong/test-zulip/_git/test-zulip/pullrequest/4) (Add 4th PR) in [test-zulip](https://dev.azure.com/ttchong/test-zulip/_git/test-zulip/)" + }, + "detailedMessage": { + "text": "Merge attempted for pull request 4 (Add 4th PR) in test-zulip\r\nhttps://dev.azure.com/ttchong/test-zulip/_git/test-zulip/", + "html": "Merge attempted for pull request 4 (Add 4th PR) in test-zulip", + "markdown": "Merge attempted for [pull request 4](https://dev.azure.com/ttchong/test-zulip/_git/test-zulip/pullrequest/4) (Add 4th PR) in [test-zulip](https://dev.azure.com/ttchong/test-zulip/_git/test-zulip/)" + }, + "resource": { + "repository": { + "id": "98f0ce59-a912-43d5-96d2-bc0942a03f7b", + "name": "test-zulip", + "url": "https://dev.azure.com/ttchong/068d2409-14eb-4d8a-88bf-c8a9e7f5b4e2/_apis/git/repositories/98f0ce59-a912-43d5-96d2-bc0942a03f7b", + "project": { + "id": "068d2409-14eb-4d8a-88bf-c8a9e7f5b4e2", + "name": "test-zulip", + "url": "https://dev.azure.com/ttchong/_apis/projects/068d2409-14eb-4d8a-88bf-c8a9e7f5b4e2", + "state": "wellFormed", + "revision": 11, + "visibility": "private", + "lastUpdateTime": "2022-07-17T05:01:05.987Z" + }, + "size": 7840, + "remoteUrl": "https://ttchong@dev.azure.com/ttchong/test-zulip/_git/test-zulip", + "sshUrl": "git@ssh.dev.azure.com:v3/ttchong/test-zulip/test-zulip", + "webUrl": "https://dev.azure.com/ttchong/test-zulip/_git/test-zulip", + "isDisabled": false + }, + "pullRequestId": 4, + "codeReviewId": 4, + "status": "active", + "createdBy": { + "displayName": "Yuro Itaki", + "url": "https://spsprodsea2.vssps.visualstudio.com/Aa56cba4a-dc80-4dd2-91fa-6fe7047fea7c/_apis/Identities/107e08c7-2725-675e-a1b0-281729035ea6", + "_links": { + "avatar": { + "href": "https://dev.azure.com/ttchong/_apis/GraphProfile/MemberAvatars/msa.MTA3ZTA4YzctMjcyNS03NzVlLWExYjAtMjgxNzI5MDM1ZWE2" + } + }, + "id": "107e08c7-2725-675e-a1b0-281729035ea6", + "uniqueName": "yuroitaki@email.com", + "imageUrl": "https://dev.azure.com/ttchong/_api/_common/identityImage?id=107e08c7-2725-675e-a1b0-281729035ea6", + "descriptor": "msa.MTA3ZTA4YzctMjcyNS03NzVlLWExYjAtMjgxNzI5MDM1ZWE2" + }, + "creationDate": "2022-07-30T07:47:15.091534Z", + "title": "Add 4th PR", + "sourceRefName": "refs/heads/preprod", + "targetRefName": "refs/heads/main", + "mergeStatus": "conflicts", + "isDraft": false, + "mergeId": "697a791b-ab1a-48bf-910f-df958081a45c", + "lastMergeSourceCommit": { + "commitId": "885adddfa29eeeb8a0c9448b6744d2cfe02b1ebf", + "url": "https://dev.azure.com/ttchong/068d2409-14eb-4d8a-88bf-c8a9e7f5b4e2/_apis/git/repositories/98f0ce59-a912-43d5-96d2-bc0942a03f7b/commits/885adddfa29eeeb8a0c9448b6744d2cfe02b1ebf" + }, + "lastMergeTargetCommit": { + "commitId": "6c86f973c0cd02726af8a5da074795745927e0d2", + "url": "https://dev.azure.com/ttchong/068d2409-14eb-4d8a-88bf-c8a9e7f5b4e2/_apis/git/repositories/98f0ce59-a912-43d5-96d2-bc0942a03f7b/commits/6c86f973c0cd02726af8a5da074795745927e0d2" + }, + "reviewers": [ + { + "reviewerUrl": "https://dev.azure.com/ttchong/068d2409-14eb-4d8a-88bf-c8a9e7f5b4e2/_apis/git/repositories/98f0ce59-a912-43d5-96d2-bc0942a03f7b/pullRequests/4/reviewers/107e08c7-2725-675e-a1b0-281729035ea6", + "vote": 10, + "hasDeclined": false, + "isFlagged": false, + "displayName": "Yuro Itaki", + "url": "https://spsprodsea2.vssps.visualstudio.com/Aa56cba4a-dc80-4dd2-91fa-6fe7047fea7c/_apis/Identities/107e08c7-2725-675e-a1b0-281729035ea6", + "_links": { + "avatar": { + "href": "https://dev.azure.com/ttchong/_apis/GraphProfile/MemberAvatars/msa.MTA3ZTA4YzctMjcyNS03NzVlLWExYjAtMjgxNzI5MDM1ZWE2" + } + }, + "id": "107e08c7-2725-675e-a1b0-281729035ea6", + "uniqueName": "yuroitaki@email.com", + "imageUrl": "https://dev.azure.com/ttchong/_api/_common/identityImage?id=107e08c7-2725-675e-a1b0-281729035ea6" + } + ], + "url": "https://dev.azure.com/ttchong/068d2409-14eb-4d8a-88bf-c8a9e7f5b4e2/_apis/git/repositories/98f0ce59-a912-43d5-96d2-bc0942a03f7b/pullRequests/4", + "_links": { + "web": { + "href": "https://dev.azure.com/ttchong/test-zulip/_git/test-zulip/pullrequest/4" + }, + "statuses": { + "href": "https://dev.azure.com/ttchong/068d2409-14eb-4d8a-88bf-c8a9e7f5b4e2/_apis/git/repositories/98f0ce59-a912-43d5-96d2-bc0942a03f7b/pullRequests/4/statuses" + } + }, + "supportsIterations": true, + "artifactId": "vstfs:///Git/PullRequestId/068d2409-14eb-4d8a-88bf-c8a9e7f5b4e2%2f98f0ce59-a912-43d5-96d2-bc0942a03f7b%2f4" + }, + "resourceVersion": "1.0", + "resourceContainers": { + "collection": { + "id": "ad9e1dcf-6055-4fc7-a146-5511ab5ab1e8", + "baseUrl": "https://dev.azure.com/ttchong/" + }, + "account": { + "id": "a56cba4a-dc80-4dd2-91fa-6fe7047fea7c", + "baseUrl": "https://dev.azure.com/ttchong/" + }, + "project": { + "id": "068d2409-14eb-4d8a-88bf-c8a9e7f5b4e2", + "baseUrl": "https://dev.azure.com/ttchong/" + } + }, + "createdDate": "2022-07-30T07:48:03.2511337Z" +} diff --git a/zerver/webhooks/azuredevops/fixtures/code_pull_request__merged.json b/zerver/webhooks/azuredevops/fixtures/code_pull_request__merged.json new file mode 100644 index 0000000000..191d1d9ba2 --- /dev/null +++ b/zerver/webhooks/azuredevops/fixtures/code_pull_request__merged.json @@ -0,0 +1,135 @@ +{ + "subscriptionId": "4f1eccb6-04ff-45dd-90aa-713078e5c395", + "notificationId": 8, + "id": "d4cbc5f3-be4a-4fa6-80df-bfad83e313c5", + "eventType": "git.pullrequest.merged", + "publisherId": "tfs", + "message": { + "text": "Merge attempted for pull request 1 (Add PR request) in test-zulip\r\nhttps://dev.azure.com/ttchong/test-zulip/_git/test-zulip/", + "html": "Merge attempted for pull request 1 (Add PR request) in test-zulip", + "markdown": "Merge attempted for [pull request 1](https://dev.azure.com/ttchong/test-zulip/_git/test-zulip/pullrequest/1) (Add PR request) in [test-zulip](https://dev.azure.com/ttchong/test-zulip/_git/test-zulip/)" + }, + "detailedMessage": { + "text": "Merge attempted for pull request 1 (Add PR request) in test-zulip\r\nhttps://dev.azure.com/ttchong/test-zulip/_git/test-zulip/\r\nAdd PR request\r\n", + "html": "Merge attempted for pull request 1 (Add PR request) in test-zulip

Add PR request

", + "markdown": "Merge attempted for [pull request 1](https://dev.azure.com/ttchong/test-zulip/_git/test-zulip/pullrequest/1) (Add PR request) in [test-zulip](https://dev.azure.com/ttchong/test-zulip/_git/test-zulip/)\r\nAdd PR request\r\n" + }, + "resource": { + "repository": { + "id": "98f0ce59-a912-43d5-96d2-bc0942a03f7b", + "name": "test-zulip", + "url": "https://dev.azure.com/ttchong/068d2409-14eb-4d8a-88bf-c8a9e7f5b4e2/_apis/git/repositories/98f0ce59-a912-43d5-96d2-bc0942a03f7b", + "project": { + "id": "068d2409-14eb-4d8a-88bf-c8a9e7f5b4e2", + "name": "test-zulip", + "url": "https://dev.azure.com/ttchong/_apis/projects/068d2409-14eb-4d8a-88bf-c8a9e7f5b4e2", + "state": "wellFormed", + "revision": 11, + "visibility": "private", + "lastUpdateTime": "2022-07-17T05:01:05.987Z" + }, + "size": 7840, + "remoteUrl": "https://ttchong@dev.azure.com/ttchong/test-zulip/_git/test-zulip", + "sshUrl": "git@ssh.dev.azure.com:v3/ttchong/test-zulip/test-zulip", + "webUrl": "https://dev.azure.com/ttchong/test-zulip/_git/test-zulip", + "isDisabled": false + }, + "pullRequestId": 1, + "codeReviewId": 1, + "status": "completed", + "createdBy": { + "displayName": "Yuro Itaki", + "url": "https://spsprodsea2.vssps.visualstudio.com/Aa56cba4a-dc80-4dd2-91fa-6fe7047fea7c/_apis/Identities/107e08c7-2725-675e-a1b0-281729035ea6", + "_links": { + "avatar": { + "href": "https://dev.azure.com/ttchong/_apis/GraphProfile/MemberAvatars/msa.MTA3ZTA4YzctMjcyNS03NzVlLWExYjAtMjgxNzI5MDM1ZWE2" + } + }, + "id": "107e08c7-2725-675e-a1b0-281729035ea6", + "uniqueName": "yuroitaki@email.com", + "imageUrl": "https://dev.azure.com/ttchong/_api/_common/identityImage?id=107e08c7-2725-675e-a1b0-281729035ea6", + "descriptor": "msa.MTA3ZTA4YzctMjcyNS03NzVlLWExYjAtMjgxNzI5MDM1ZWE2" + }, + "creationDate": "2022-07-24T08:02:50.160355Z", + "closedDate": "2022-07-30T07:55:03.5006647Z", + "title": "Add PR request", + "description": "Add PR request", + "sourceRefName": "refs/heads/dev", + "targetRefName": "refs/heads/main", + "mergeStatus": "succeeded", + "isDraft": false, + "mergeId": "3cb082bf-62fd-4ff9-81f2-bea41241eadb", + "lastMergeSourceCommit": { + "commitId": "179f0b4e4a9318d1907402662b0a416550926ebb", + "url": "https://dev.azure.com/ttchong/068d2409-14eb-4d8a-88bf-c8a9e7f5b4e2/_apis/git/repositories/98f0ce59-a912-43d5-96d2-bc0942a03f7b/commits/179f0b4e4a9318d1907402662b0a416550926ebb" + }, + "lastMergeTargetCommit": { + "commitId": "6c86f973c0cd02726af8a5da074795745927e0d2", + "url": "https://dev.azure.com/ttchong/068d2409-14eb-4d8a-88bf-c8a9e7f5b4e2/_apis/git/repositories/98f0ce59-a912-43d5-96d2-bc0942a03f7b/commits/6c86f973c0cd02726af8a5da074795745927e0d2" + }, + "lastMergeCommit": { + "commitId": "b2606c193460441311f4d31f4729589c77f5efe0", + "author": { + "name": "Yuro Itaki", + "email": "yuroitaki@email.com", + "date": "2022-07-30T07:55:02Z" + }, + "committer": { + "name": "Yuro Itaki", + "email": "yuroitaki@email.com", + "date": "2022-07-30T07:55:02Z" + }, + "comment": "Merged PR 1: Add PR request", + "commentTruncated": true, + "url": "https://dev.azure.com/ttchong/068d2409-14eb-4d8a-88bf-c8a9e7f5b4e2/_apis/git/repositories/98f0ce59-a912-43d5-96d2-bc0942a03f7b/commits/b2606c193460441311f4d31f4729589c77f5efe0" + }, + "reviewers": [], + "url": "https://dev.azure.com/ttchong/068d2409-14eb-4d8a-88bf-c8a9e7f5b4e2/_apis/git/repositories/98f0ce59-a912-43d5-96d2-bc0942a03f7b/pullRequests/1", + "_links": { + "web": { + "href": "https://dev.azure.com/ttchong/test-zulip/_git/test-zulip/pullrequest/1" + }, + "statuses": { + "href": "https://dev.azure.com/ttchong/068d2409-14eb-4d8a-88bf-c8a9e7f5b4e2/_apis/git/repositories/98f0ce59-a912-43d5-96d2-bc0942a03f7b/pullRequests/1/statuses" + } + }, + "completionOptions": { + "mergeCommitMessage": "Merged PR 1: Add PR request\n\nAdd PR request", + "mergeStrategy": "noFastForward", + "transitionWorkItems": true, + "autoCompleteIgnoreConfigIds": [] + }, + "supportsIterations": true, + "completionQueueTime": "2022-07-30T07:55:02.6159917Z", + "closedBy": { + "displayName": "Yuro Itaki", + "url": "https://spsprodsea2.vssps.visualstudio.com/Aa56cba4a-dc80-4dd2-91fa-6fe7047fea7c/_apis/Identities/107e08c7-2725-675e-a1b0-281729035ea6", + "_links": { + "avatar": { + "href": "https://dev.azure.com/ttchong/_apis/GraphProfile/MemberAvatars/msa.MTA3ZTA4YzctMjcyNS03NzVlLWExYjAtMjgxNzI5MDM1ZWE2" + } + }, + "id": "107e08c7-2725-675e-a1b0-281729035ea6", + "uniqueName": "yuroitaki@email.com", + "imageUrl": "https://dev.azure.com/ttchong/_api/_common/identityImage?id=107e08c7-2725-675e-a1b0-281729035ea6", + "descriptor": "msa.MTA3ZTA4YzctMjcyNS03NzVlLWExYjAtMjgxNzI5MDM1ZWE2" + }, + "artifactId": "vstfs:///Git/PullRequestId/068d2409-14eb-4d8a-88bf-c8a9e7f5b4e2%2f98f0ce59-a912-43d5-96d2-bc0942a03f7b%2f1" + }, + "resourceVersion": "1.0", + "resourceContainers": { + "collection": { + "id": "ad9e1dcf-6055-4fc7-a146-5511ab5ab1e8", + "baseUrl": "https://dev.azure.com/ttchong/" + }, + "account": { + "id": "a56cba4a-dc80-4dd2-91fa-6fe7047fea7c", + "baseUrl": "https://dev.azure.com/ttchong/" + }, + "project": { + "id": "068d2409-14eb-4d8a-88bf-c8a9e7f5b4e2", + "baseUrl": "https://dev.azure.com/ttchong/" + } + }, + "createdDate": "2022-07-30T07:55:09.816217Z" +} diff --git a/zerver/webhooks/azuredevops/fixtures/code_pull_request__opened.json b/zerver/webhooks/azuredevops/fixtures/code_pull_request__opened.json new file mode 100644 index 0000000000..1a9dbbc4f7 --- /dev/null +++ b/zerver/webhooks/azuredevops/fixtures/code_pull_request__opened.json @@ -0,0 +1,113 @@ +{ + "subscriptionId": "a0e7f493-8c02-498d-b9ee-86a8612bc74e", + "notificationId": 1, + "id": "d1e96858-24cd-4064-9e08-0c55db2ff3fa", + "eventType": "git.pullrequest.created", + "publisherId": "tfs", + "message": { + "text": "Yuro Itaki created pull request 1 (Add PR request) in test-zulip\r\nhttps://dev.azure.com/ttchong/test-zulip/_git/test-zulip/", + "html": "Yuro Itaki created pull request 1 (Add PR request) in test-zulip", + "markdown": "Yuro Itaki created [pull request 1](https://dev.azure.com/ttchong/test-zulip/_git/test-zulip/pullrequest/1) (Add PR request) in [test-zulip](https://dev.azure.com/ttchong/test-zulip/_git/test-zulip/)" + }, + "detailedMessage": { + "text": "Yuro Itaki created pull request 1 (Add PR request) in test-zulip\r\nhttps://dev.azure.com/ttchong/test-zulip/_git/test-zulip/\r\nAdd PR request\r\n", + "html": "Yuro Itaki created pull request 1 (Add PR request) in test-zulip

Add PR request

", + "markdown": "Yuro Itaki created [pull request 1](https://dev.azure.com/ttchong/test-zulip/_git/test-zulip/pullrequest/1) (Add PR request) in [test-zulip](https://dev.azure.com/ttchong/test-zulip/_git/test-zulip/)\r\nAdd PR request\r\n" + }, + "resource": { + "repository": { + "id": "98f0ce59-a912-43d5-96d2-bc0942a03f7b", + "name": "test-zulip", + "url": "https://dev.azure.com/ttchong/068d2409-14eb-4d8a-88bf-c8a9e7f5b4e2/_apis/git/repositories/98f0ce59-a912-43d5-96d2-bc0942a03f7b", + "project": { + "id": "068d2409-14eb-4d8a-88bf-c8a9e7f5b4e2", + "name": "test-zulip", + "url": "https://dev.azure.com/ttchong/_apis/projects/068d2409-14eb-4d8a-88bf-c8a9e7f5b4e2", + "state": "wellFormed", + "revision": 11, + "visibility": "private", + "lastUpdateTime": "2022-07-17T05:01:05.987Z" + }, + "size": 4425, + "remoteUrl": "https://ttchong@dev.azure.com/ttchong/test-zulip/_git/test-zulip", + "sshUrl": "git@ssh.dev.azure.com:v3/ttchong/test-zulip/test-zulip", + "webUrl": "https://dev.azure.com/ttchong/test-zulip/_git/test-zulip", + "isDisabled": false + }, + "pullRequestId": 1, + "codeReviewId": 1, + "status": "active", + "createdBy": { + "displayName": "Yuro Itaki", + "url": "https://spsprodsea2.vssps.visualstudio.com/Aa56cba4a-dc80-4dd2-91fa-6fe7047fea7c/_apis/Identities/107e08c7-2725-675e-a1b0-281729035ea6", + "_links": { + "avatar": { + "href": "https://dev.azure.com/ttchong/_apis/GraphProfile/MemberAvatars/msa.MTA3ZTA4YzctMjcyNS03NzVlLWExYjAtMjgxNzI5MDM1ZWE2" + } + }, + "id": "107e08c7-2725-675e-a1b0-281729035ea6", + "uniqueName": "yuroitaki@email.com", + "imageUrl": "https://dev.azure.com/ttchong/_api/_common/identityImage?id=107e08c7-2725-675e-a1b0-281729035ea6", + "descriptor": "msa.MTA3ZTA4YzctMjcyNS03NzVlLWExYjAtMjgxNzI5MDM1ZWE2" + }, + "creationDate": "2022-07-24T08:02:50.160355Z", + "title": "Add PR request", + "description": "Add PR request", + "sourceRefName": "refs/heads/dev", + "targetRefName": "refs/heads/main", + "mergeStatus": "succeeded", + "isDraft": false, + "mergeId": "3cb082bf-62fd-4ff9-81f2-bea41241eadb", + "lastMergeSourceCommit": { + "commitId": "8b913c8e0d0492952bd215da12df9a422182e9c5", + "url": "https://dev.azure.com/ttchong/068d2409-14eb-4d8a-88bf-c8a9e7f5b4e2/_apis/git/repositories/98f0ce59-a912-43d5-96d2-bc0942a03f7b/commits/8b913c8e0d0492952bd215da12df9a422182e9c5" + }, + "lastMergeTargetCommit": { + "commitId": "0929a3404b39f6e39076a640779b2c1c961e19b5", + "url": "https://dev.azure.com/ttchong/068d2409-14eb-4d8a-88bf-c8a9e7f5b4e2/_apis/git/repositories/98f0ce59-a912-43d5-96d2-bc0942a03f7b/commits/0929a3404b39f6e39076a640779b2c1c961e19b5" + }, + "lastMergeCommit": { + "commitId": "4d1292958374b3311a517429d6160f7fc434de86", + "author": { + "name": "Yuro Itaki", + "email": "yuroitaki@email.com", + "date": "2022-07-24T08:02:50Z" + }, + "committer": { + "name": "Yuro Itaki", + "email": "yuroitaki@email.com", + "date": "2022-07-24T08:02:50Z" + }, + "comment": "Merge pull request 1 from dev into main", + "url": "https://dev.azure.com/ttchong/068d2409-14eb-4d8a-88bf-c8a9e7f5b4e2/_apis/git/repositories/98f0ce59-a912-43d5-96d2-bc0942a03f7b/commits/4d1292958374b3311a517429d6160f7fc434de86" + }, + "reviewers": [], + "url": "https://dev.azure.com/ttchong/068d2409-14eb-4d8a-88bf-c8a9e7f5b4e2/_apis/git/repositories/98f0ce59-a912-43d5-96d2-bc0942a03f7b/pullRequests/1", + "_links": { + "web": { + "href": "https://dev.azure.com/ttchong/test-zulip/_git/test-zulip/pullrequest/1" + }, + "statuses": { + "href": "https://dev.azure.com/ttchong/068d2409-14eb-4d8a-88bf-c8a9e7f5b4e2/_apis/git/repositories/98f0ce59-a912-43d5-96d2-bc0942a03f7b/pullRequests/1/statuses" + } + }, + "supportsIterations": true, + "artifactId": "vstfs:///Git/PullRequestId/068d2409-14eb-4d8a-88bf-c8a9e7f5b4e2%2f98f0ce59-a912-43d5-96d2-bc0942a03f7b%2f1" + }, + "resourceVersion": "1.0", + "resourceContainers": { + "collection": { + "id": "ad9e1dcf-6055-4fc7-a146-5511ab5ab1e8", + "baseUrl": "https://dev.azure.com/ttchong/" + }, + "account": { + "id": "a56cba4a-dc80-4dd2-91fa-6fe7047fea7c", + "baseUrl": "https://dev.azure.com/ttchong/" + }, + "project": { + "id": "068d2409-14eb-4d8a-88bf-c8a9e7f5b4e2", + "baseUrl": "https://dev.azure.com/ttchong/" + } + }, + "createdDate": "2022-07-24T08:02:56.9717413Z" +} diff --git a/zerver/webhooks/azuredevops/fixtures/code_pull_request__opened_without_description.json b/zerver/webhooks/azuredevops/fixtures/code_pull_request__opened_without_description.json new file mode 100644 index 0000000000..255d000fe9 --- /dev/null +++ b/zerver/webhooks/azuredevops/fixtures/code_pull_request__opened_without_description.json @@ -0,0 +1,129 @@ +{ + "subscriptionId": "a0e7f493-8c02-498d-b9ee-86a8612bc74e", + "notificationId": 2, + "id": "3559461b-0001-422f-8c1c-7946284839ab", + "eventType": "git.pullrequest.created", + "publisherId": "tfs", + "message": { + "text": "Yuro Itaki created pull request 2 (Raised 2nd PR!) in test-zulip\r\nhttps://dev.azure.com/ttchong/test-zulip/_git/test-zulip/", + "html": "Yuro Itaki created pull request 2 (Raised 2nd PR!) in test-zulip", + "markdown": "Yuro Itaki created [pull request 2](https://dev.azure.com/ttchong/test-zulip/_git/test-zulip/pullrequest/2) (Raised 2nd PR!) in [test-zulip](https://dev.azure.com/ttchong/test-zulip/_git/test-zulip/)" + }, + "detailedMessage": { + "text": "Yuro Itaki created pull request 2 (Raised 2nd PR!) in test-zulip\r\nhttps://dev.azure.com/ttchong/test-zulip/_git/test-zulip/\r\nRaised 2nd PR!\r\n", + "html": "Yuro Itaki created pull request 2 (Raised 2nd PR!) in test-zulip

Raised 2nd PR!

", + "markdown": "Yuro Itaki created [pull request 2](https://dev.azure.com/ttchong/test-zulip/_git/test-zulip/pullrequest/2) (Raised 2nd PR!) in [test-zulip](https://dev.azure.com/ttchong/test-zulip/_git/test-zulip/)\r\nRaised 2nd PR!\r\n" + }, + "resource": { + "repository": { + "id": "98f0ce59-a912-43d5-96d2-bc0942a03f7b", + "name": "test-zulip", + "url": "https://dev.azure.com/ttchong/068d2409-14eb-4d8a-88bf-c8a9e7f5b4e2/_apis/git/repositories/98f0ce59-a912-43d5-96d2-bc0942a03f7b", + "project": { + "id": "068d2409-14eb-4d8a-88bf-c8a9e7f5b4e2", + "name": "test-zulip", + "url": "https://dev.azure.com/ttchong/_apis/projects/068d2409-14eb-4d8a-88bf-c8a9e7f5b4e2", + "state": "wellFormed", + "revision": 11, + "visibility": "private", + "lastUpdateTime": "2022-07-17T05:01:05.987Z" + }, + "size": 4425, + "remoteUrl": "https://ttchong@dev.azure.com/ttchong/test-zulip/_git/test-zulip", + "sshUrl": "git@ssh.dev.azure.com:v3/ttchong/test-zulip/test-zulip", + "webUrl": "https://dev.azure.com/ttchong/test-zulip/_git/test-zulip", + "isDisabled": false + }, + "pullRequestId": 2, + "codeReviewId": 2, + "status": "active", + "createdBy": { + "displayName": "Yuro Itaki", + "url": "https://spsprodsea2.vssps.visualstudio.com/Aa56cba4a-dc80-4dd2-91fa-6fe7047fea7c/_apis/Identities/107e08c7-2725-675e-a1b0-281729035ea6", + "_links": { + "avatar": { + "href": "https://dev.azure.com/ttchong/_apis/GraphProfile/MemberAvatars/msa.MTA3ZTA4YzctMjcyNS03NzVlLWExYjAtMjgxNzI5MDM1ZWE2" + } + }, + "id": "107e08c7-2725-675e-a1b0-281729035ea6", + "uniqueName": "yuroitaki@email.com", + "imageUrl": "https://dev.azure.com/ttchong/_api/_common/identityImage?id=107e08c7-2725-675e-a1b0-281729035ea6", + "descriptor": "msa.MTA3ZTA4YzctMjcyNS03NzVlLWExYjAtMjgxNzI5MDM1ZWE2" + }, + "creationDate": "2022-07-24T08:45:53.9577409Z", + "title": "Raised 2nd PR!", + "sourceRefName": "refs/heads/stg", + "targetRefName": "refs/heads/main", + "mergeStatus": "succeeded", + "isDraft": false, + "mergeId": "675bced4-738a-4f9e-b255-a30dce8b91df", + "lastMergeSourceCommit": { + "commitId": "fe3b16dd2079fc96f4e31752b0e3e0782389b469", + "url": "https://dev.azure.com/ttchong/068d2409-14eb-4d8a-88bf-c8a9e7f5b4e2/_apis/git/repositories/98f0ce59-a912-43d5-96d2-bc0942a03f7b/commits/fe3b16dd2079fc96f4e31752b0e3e0782389b469" + }, + "lastMergeTargetCommit": { + "commitId": "0929a3404b39f6e39076a640779b2c1c961e19b5", + "url": "https://dev.azure.com/ttchong/068d2409-14eb-4d8a-88bf-c8a9e7f5b4e2/_apis/git/repositories/98f0ce59-a912-43d5-96d2-bc0942a03f7b/commits/0929a3404b39f6e39076a640779b2c1c961e19b5" + }, + "lastMergeCommit": { + "commitId": "037561654dedfcc22e96230eee4550916357ec7a", + "author": { + "name": "Yuro Itaki", + "email": "yuroitaki@email.com", + "date": "2022-07-24T08:45:54Z" + }, + "committer": { + "name": "Yuro Itaki", + "email": "yuroitaki@email.com", + "date": "2022-07-24T08:45:54Z" + }, + "comment": "Merge pull request 2 from stg into main", + "url": "https://dev.azure.com/ttchong/068d2409-14eb-4d8a-88bf-c8a9e7f5b4e2/_apis/git/repositories/98f0ce59-a912-43d5-96d2-bc0942a03f7b/commits/037561654dedfcc22e96230eee4550916357ec7a" + }, + "reviewers": [ + { + "reviewerUrl": "https://dev.azure.com/ttchong/068d2409-14eb-4d8a-88bf-c8a9e7f5b4e2/_apis/git/repositories/98f0ce59-a912-43d5-96d2-bc0942a03f7b/pullRequests/2/reviewers/ed580ebe-b4a9-485d-bfed-c58ba519d7b6", + "vote": 0, + "hasDeclined": false, + "isFlagged": false, + "displayName": "Project Collection Build Service (Pad9e1dcf-6055-4fc7-a146-5511ab5ab1e8)", + "url": "https://spsprodsea2.vssps.visualstudio.com/Aa56cba4a-dc80-4dd2-91fa-6fe7047fea7c/_apis/Identities/ed580ebe-b4a9-485d-bfed-c58ba519d7b6", + "_links": { + "avatar": { + "href": "https://dev.azure.com/ttchong/_apis/GraphProfile/MemberAvatars/svc.YTU2Y2JhNGEtZGM4MC00ZGQyLTkxZmEtNmZlNzA0N2ZlYTdjOkJ1aWxkOmFkOWUxZGNmLTYwNTUtNGZjNy1hMTQ2LTU1MTFhYjVhYjFlOA" + } + }, + "id": "ed580ebe-b4a9-485d-bfed-c58ba519d7b6", + "uniqueName": "Build\\ad9e1dcf-6055-4fc7-a146-5511ab5ab1e8", + "imageUrl": "https://dev.azure.com/ttchong/_api/_common/identityImage?id=ed580ebe-b4a9-485d-bfed-c58ba519d7b6" + } + ], + "url": "https://dev.azure.com/ttchong/068d2409-14eb-4d8a-88bf-c8a9e7f5b4e2/_apis/git/repositories/98f0ce59-a912-43d5-96d2-bc0942a03f7b/pullRequests/2", + "_links": { + "web": { + "href": "https://dev.azure.com/ttchong/test-zulip/_git/test-zulip/pullrequest/2" + }, + "statuses": { + "href": "https://dev.azure.com/ttchong/068d2409-14eb-4d8a-88bf-c8a9e7f5b4e2/_apis/git/repositories/98f0ce59-a912-43d5-96d2-bc0942a03f7b/pullRequests/2/statuses" + } + }, + "supportsIterations": true, + "artifactId": "vstfs:///Git/PullRequestId/068d2409-14eb-4d8a-88bf-c8a9e7f5b4e2%2f98f0ce59-a912-43d5-96d2-bc0942a03f7b%2f2" + }, + "resourceVersion": "1.0", + "resourceContainers": { + "collection": { + "id": "ad9e1dcf-6055-4fc7-a146-5511ab5ab1e8", + "baseUrl": "https://dev.azure.com/ttchong/" + }, + "account": { + "id": "a56cba4a-dc80-4dd2-91fa-6fe7047fea7c", + "baseUrl": "https://dev.azure.com/ttchong/" + }, + "project": { + "id": "068d2409-14eb-4d8a-88bf-c8a9e7f5b4e2", + "baseUrl": "https://dev.azure.com/ttchong/" + } + }, + "createdDate": "2022-07-24T08:46:00.8535001Z" +} diff --git a/zerver/webhooks/azuredevops/fixtures/code_pull_request__updated.json b/zerver/webhooks/azuredevops/fixtures/code_pull_request__updated.json new file mode 100644 index 0000000000..97d0a6ba07 --- /dev/null +++ b/zerver/webhooks/azuredevops/fixtures/code_pull_request__updated.json @@ -0,0 +1,136 @@ +{ + "subscriptionId": "d21a27a6-3b89-45fb-9af9-0fe220348c1d", + "notificationId": 1, + "id": "6544f94b-ce5d-4bc1-b4be-30559b589d15", + "eventType": "git.pullrequest.updated", + "publisherId": "tfs", + "message": { + "text": "Yuro Itaki updated the source branch of pull request 2 (Raised 2nd PR!) in test-zulip\r\nhttps://dev.azure.com/ttchong/test-zulip/_git/test-zulip/", + "html": "Yuro Itaki updated the source branch of pull request 2 (Raised 2nd PR!) in test-zulip", + "markdown": "Yuro Itaki updated the source branch of [pull request 2](https://dev.azure.com/ttchong/test-zulip/_git/test-zulip/pullrequest/2) (Raised 2nd PR!) in [test-zulip](https://dev.azure.com/ttchong/test-zulip/_git/test-zulip/)" + }, + "detailedMessage": { + "text": "Yuro Itaki updated the source branch of pull request 2 (Raised 2nd PR!) in test-zulip\r\nhttps://dev.azure.com/ttchong/test-zulip/_git/test-zulip/\r\nRaised 2nd PR!\r\n", + "html": "Yuro Itaki updated the source branch of pull request 2 (Raised 2nd PR!) in test-zulip

Raised 2nd PR!

", + "markdown": "Yuro Itaki updated the source branch of [pull request 2](https://dev.azure.com/ttchong/test-zulip/_git/test-zulip/pullrequest/2) (Raised 2nd PR!) in [test-zulip](https://dev.azure.com/ttchong/test-zulip/_git/test-zulip/)\r\nRaised 2nd PR!\r\n" + }, + "resource": { + "repository": { + "id": "98f0ce59-a912-43d5-96d2-bc0942a03f7b", + "name": "test-zulip", + "url": "https://dev.azure.com/ttchong/068d2409-14eb-4d8a-88bf-c8a9e7f5b4e2/_apis/git/repositories/98f0ce59-a912-43d5-96d2-bc0942a03f7b", + "project": { + "id": "068d2409-14eb-4d8a-88bf-c8a9e7f5b4e2", + "name": "test-zulip", + "url": "https://dev.azure.com/ttchong/_apis/projects/068d2409-14eb-4d8a-88bf-c8a9e7f5b4e2", + "state": "wellFormed", + "revision": 11, + "visibility": "private", + "lastUpdateTime": "2022-07-17T05:01:05.987Z" + }, + "size": 7840, + "remoteUrl": "https://ttchong@dev.azure.com/ttchong/test-zulip/_git/test-zulip", + "sshUrl": "git@ssh.dev.azure.com:v3/ttchong/test-zulip/test-zulip", + "webUrl": "https://dev.azure.com/ttchong/test-zulip/_git/test-zulip", + "isDisabled": false + }, + "pullRequestId": 2, + "codeReviewId": 2, + "status": "active", + "createdBy": { + "displayName": "Yuro Itaki", + "url": "https://spsprodsea2.vssps.visualstudio.com/Aa56cba4a-dc80-4dd2-91fa-6fe7047fea7c/_apis/Identities/107e08c7-2725-675e-a1b0-281729035ea6", + "_links": { + "avatar": { + "href": "https://dev.azure.com/ttchong/_apis/GraphProfile/MemberAvatars/msa.MTA3ZTA4YzctMjcyNS03NzVlLWExYjAtMjgxNzI5MDM1ZWE2" + } + }, + "id": "107e08c7-2725-675e-a1b0-281729035ea6", + "uniqueName": "yuroitaki@email.com", + "imageUrl": "https://dev.azure.com/ttchong/_api/_common/identityImage?id=107e08c7-2725-675e-a1b0-281729035ea6", + "descriptor": "msa.MTA3ZTA4YzctMjcyNS03NzVlLWExYjAtMjgxNzI5MDM1ZWE2" + }, + "creationDate": "2022-07-24T08:45:53.9577409Z", + "title": "Raised 2nd PR!", + "description": "Raised 2nd PR!", + "sourceRefName": "refs/heads/stg", + "targetRefName": "refs/heads/main", + "mergeStatus": "succeeded", + "isDraft": false, + "mergeId": "675bced4-738a-4f9e-b255-a30dce8b91df", + "lastMergeSourceCommit": { + "commitId": "aefa35fb7c4505b9b8337aff3c4be96eddbbd861", + "url": "https://dev.azure.com/ttchong/068d2409-14eb-4d8a-88bf-c8a9e7f5b4e2/_apis/git/repositories/98f0ce59-a912-43d5-96d2-bc0942a03f7b/commits/aefa35fb7c4505b9b8337aff3c4be96eddbbd861" + }, + "lastMergeTargetCommit": { + "commitId": "b2606c193460441311f4d31f4729589c77f5efe0", + "url": "https://dev.azure.com/ttchong/068d2409-14eb-4d8a-88bf-c8a9e7f5b4e2/_apis/git/repositories/98f0ce59-a912-43d5-96d2-bc0942a03f7b/commits/b2606c193460441311f4d31f4729589c77f5efe0" + }, + "lastMergeCommit": { + "commitId": "f0fb095f4e89065e2edccaedae4535979e212b78", + "author": { + "name": "Yuro Itaki", + "email": "yuroitaki@email.com", + "date": "2022-07-30T08:42:00Z" + }, + "committer": { + "name": "Yuro Itaki", + "email": "yuroitaki@email.com", + "date": "2022-07-30T08:42:00Z" + }, + "comment": "Merge pull request 2 from stg into main", + "url": "https://dev.azure.com/ttchong/068d2409-14eb-4d8a-88bf-c8a9e7f5b4e2/_apis/git/repositories/98f0ce59-a912-43d5-96d2-bc0942a03f7b/commits/f0fb095f4e89065e2edccaedae4535979e212b78" + }, + "reviewers": [ + { + "reviewerUrl": "https://dev.azure.com/ttchong/068d2409-14eb-4d8a-88bf-c8a9e7f5b4e2/_apis/git/repositories/98f0ce59-a912-43d5-96d2-bc0942a03f7b/pullRequests/2/reviewers/ed580ebe-b4a9-485d-bfed-c58ba519d7b6", + "vote": 0, + "hasDeclined": false, + "isFlagged": false, + "displayName": "Project Collection Build Service (Pad9e1dcf-6055-4fc7-a146-5511ab5ab1e8)", + "url": "https://spsprodsea2.vssps.visualstudio.com/Aa56cba4a-dc80-4dd2-91fa-6fe7047fea7c/_apis/Identities/ed580ebe-b4a9-485d-bfed-c58ba519d7b6", + "_links": { + "avatar": { + "href": "https://dev.azure.com/ttchong/_apis/GraphProfile/MemberAvatars/svc.YTU2Y2JhNGEtZGM4MC00ZGQyLTkxZmEtNmZlNzA0N2ZlYTdjOkJ1aWxkOmFkOWUxZGNmLTYwNTUtNGZjNy1hMTQ2LTU1MTFhYjVhYjFlOA" + } + }, + "id": "ed580ebe-b4a9-485d-bfed-c58ba519d7b6", + "uniqueName": "Build\\ad9e1dcf-6055-4fc7-a146-5511ab5ab1e8", + "imageUrl": "https://dev.azure.com/ttchong/_api/_common/identityImage?id=ed580ebe-b4a9-485d-bfed-c58ba519d7b6" + } + ], + "url": "https://dev.azure.com/ttchong/068d2409-14eb-4d8a-88bf-c8a9e7f5b4e2/_apis/git/repositories/98f0ce59-a912-43d5-96d2-bc0942a03f7b/pullRequests/2", + "_links": { + "web": { + "href": "https://dev.azure.com/ttchong/test-zulip/_git/test-zulip/pullrequest/2" + }, + "statuses": { + "href": "https://dev.azure.com/ttchong/068d2409-14eb-4d8a-88bf-c8a9e7f5b4e2/_apis/git/repositories/98f0ce59-a912-43d5-96d2-bc0942a03f7b/pullRequests/2/statuses" + } + }, + "completionOptions": { + "mergeCommitMessage": "Merged PR 2: Raised 2nd PR!\n\nRaised 2nd PR!", + "mergeStrategy": "noFastForward", + "transitionWorkItems": true, + "autoCompleteIgnoreConfigIds": [] + }, + "supportsIterations": true, + "artifactId": "vstfs:///Git/PullRequestId/068d2409-14eb-4d8a-88bf-c8a9e7f5b4e2%2f98f0ce59-a912-43d5-96d2-bc0942a03f7b%2f2" + }, + "resourceVersion": "1.0", + "resourceContainers": { + "collection": { + "id": "ad9e1dcf-6055-4fc7-a146-5511ab5ab1e8", + "baseUrl": "https://dev.azure.com/ttchong/" + }, + "account": { + "id": "a56cba4a-dc80-4dd2-91fa-6fe7047fea7c", + "baseUrl": "https://dev.azure.com/ttchong/" + }, + "project": { + "id": "068d2409-14eb-4d8a-88bf-c8a9e7f5b4e2", + "baseUrl": "https://dev.azure.com/ttchong/" + } + }, + "createdDate": "2022-07-30T08:42:07.2382228Z" +} diff --git a/zerver/webhooks/azuredevops/fixtures/code_push.json b/zerver/webhooks/azuredevops/fixtures/code_push.json new file mode 100644 index 0000000000..5ddc5cb3cd --- /dev/null +++ b/zerver/webhooks/azuredevops/fixtures/code_push.json @@ -0,0 +1,107 @@ +{ + "subscriptionId": "bb3738ff-00ae-472e-b752-d192c676780c", + "notificationId": 2, + "id": "9c335e3e-e047-405c-a420-d679bd54a299", + "eventType": "git.push", + "publisherId": "tfs", + "message": { + "text": "Yuro Itaki pushed updates to test-zulip:main\r\n(https://dev.azure.com/ttchong/test-zulip/_git/test-zulip/#version=GBmain)", + "html": "Yuro Itaki pushed updates to test-zulip:main", + "markdown": "Yuro Itaki pushed updates to [test-zulip](https://dev.azure.com/ttchong/test-zulip/_git/test-zulip/):[main](https://dev.azure.com/ttchong/test-zulip/_git/test-zulip/#version=GBmain)" + }, + "detailedMessage": { + "text": "Yuro Itaki pushed a commit to test-zulip:main\r\n - Modify readme b0ce2f20 (https://dev.azure.com/ttchong/test-zulip/_git/test-zulip/commit/b0ce2f2009c3c87dbefadf61d7eb2c0697a6f369)", + "html": "Yuro Itaki pushed a commit to test-zulip:main\r\n", + "markdown": "Yuro Itaki pushed a commit to [test-zulip](https://dev.azure.com/ttchong/test-zulip/_git/test-zulip/):[main](https://dev.azure.com/ttchong/test-zulip/_git/test-zulip/#version=GBmain)\r\n* Modify readme [b0ce2f20](https://dev.azure.com/ttchong/test-zulip/_git/test-zulip/commit/b0ce2f2009c3c87dbefadf61d7eb2c0697a6f369)" + }, + "resource": { + "commits": [ + { + "commitId": "b0ce2f2009c3c87dbefadf61d7eb2c0697a6f369", + "author": { + "name": "Yuro Itaki", + "email": "yuroitaki@email.com", + "date": "2022-07-17T07:14:01Z" + }, + "committer": { + "name": "Yuro Itaki", + "email": "yuroitaki@email.com", + "date": "2022-07-17T07:14:01Z" + }, + "comment": "Modify readme", + "url": "https://dev.azure.com/ttchong/_apis/git/repositories/98f0ce59-a912-43d5-96d2-bc0942a03f7b/commits/b0ce2f2009c3c87dbefadf61d7eb2c0697a6f369" + } + ], + "refUpdates": [ + { + "name": "refs/heads/main", + "oldObjectId": "51515957669f93c543df09f8f3e7f47c3613c879", + "newObjectId": "b0ce2f2009c3c87dbefadf61d7eb2c0697a6f369" + } + ], + "repository": { + "id": "98f0ce59-a912-43d5-96d2-bc0942a03f7b", + "name": "test-zulip", + "url": "https://dev.azure.com/ttchong/_apis/git/repositories/98f0ce59-a912-43d5-96d2-bc0942a03f7b", + "project": { + "id": "068d2409-14eb-4d8a-88bf-c8a9e7f5b4e2", + "name": "test-zulip", + "url": "https://dev.azure.com/ttchong/_apis/projects/068d2409-14eb-4d8a-88bf-c8a9e7f5b4e2", + "state": "wellFormed", + "visibility": "unchanged", + "lastUpdateTime": "0001-01-01T00:00:00" + }, + "defaultBranch": "refs/heads/main", + "remoteUrl": "https://dev.azure.com/ttchong/test-zulip/_git/test-zulip" + }, + "pushedBy": { + "displayName": "Yuro Itaki", + "url": "https://spsprodsea2.vssps.visualstudio.com/Aa56cba4a-dc80-4dd2-91fa-6fe7047fea7c/_apis/Identities/107e08c7-2725-675e-a1b0-281729035ea6", + "_links": { + "avatar": { + "href": "https://dev.azure.com/ttchong/_apis/GraphProfile/MemberAvatars/msa.MTA3ZTA4YzctMjcyNS03NzVlLWExYjAtMjgxNzI5MDM1ZWE2" + } + }, + "id": "107e08c7-2725-675e-a1b0-281729035ea6", + "uniqueName": "yuroitaki@email.com", + "imageUrl": "https://dev.azure.com/ttchong/_api/_common/identityImage?id=107e08c7-2725-675e-a1b0-281729035ea6", + "descriptor": "msa.MTA3ZTA4YzctMjcyNS03NzVlLWExYjAtMjgxNzI5MDM1ZWE2" + }, + "pushId": 2, + "date": "2022-07-17T07:14:05.9409049Z", + "url": "https://dev.azure.com/ttchong/_apis/git/repositories/98f0ce59-a912-43d5-96d2-bc0942a03f7b/pushes/2", + "_links": { + "self": { + "href": "https://dev.azure.com/ttchong/_apis/git/repositories/98f0ce59-a912-43d5-96d2-bc0942a03f7b/pushes/2" + }, + "repository": { + "href": "https://dev.azure.com/ttchong/068d2409-14eb-4d8a-88bf-c8a9e7f5b4e2/_apis/git/repositories/98f0ce59-a912-43d5-96d2-bc0942a03f7b" + }, + "commits": { + "href": "https://dev.azure.com/ttchong/_apis/git/repositories/98f0ce59-a912-43d5-96d2-bc0942a03f7b/pushes/2/commits" + }, + "pusher": { + "href": "https://spsprodsea2.vssps.visualstudio.com/Aa56cba4a-dc80-4dd2-91fa-6fe7047fea7c/_apis/Identities/107e08c7-2725-675e-a1b0-281729035ea6" + }, + "refs": { + "href": "https://dev.azure.com/ttchong/068d2409-14eb-4d8a-88bf-c8a9e7f5b4e2/_apis/git/repositories/98f0ce59-a912-43d5-96d2-bc0942a03f7b/refs/heads/main" + } + } + }, + "resourceVersion": "1.0", + "resourceContainers": { + "collection": { + "id": "ad9e1dcf-6055-4fc7-a146-5511ab5ab1e8", + "baseUrl": "https://dev.azure.com/ttchong/" + }, + "account": { + "id": "a56cba4a-dc80-4dd2-91fa-6fe7047fea7c", + "baseUrl": "https://dev.azure.com/ttchong/" + }, + "project": { + "id": "068d2409-14eb-4d8a-88bf-c8a9e7f5b4e2", + "baseUrl": "https://dev.azure.com/ttchong/" + } + }, + "createdDate": "2022-07-17T07:14:12.5477052Z" +} diff --git a/zerver/webhooks/azuredevops/fixtures/code_push__commits_more_than_limit.json b/zerver/webhooks/azuredevops/fixtures/code_push__commits_more_than_limit.json new file mode 100644 index 0000000000..3ec900b6dd --- /dev/null +++ b/zerver/webhooks/azuredevops/fixtures/code_push__commits_more_than_limit.json @@ -0,0 +1,842 @@ +{ + "subscriptionId": "bb3738ff-00ae-472e-b752-d192c676780c", + "notificationId": 2, + "id": "9c335e3e-e047-405c-a420-d679bd54a299", + "eventType": "git.push", + "publisherId": "tfs", + "message": { + "text": "Yuro Itaki pushed updates to test-zulip:main\r\n(https://dev.azure.com/ttchong/test-zulip/_git/test-zulip/#version=GBmain)", + "html": "Yuro Itaki pushed updates to test-zulip:main", + "markdown": "Yuro Itaki pushed updates to [test-zulip](https://dev.azure.com/ttchong/test-zulip/_git/test-zulip/):[main](https://dev.azure.com/ttchong/test-zulip/_git/test-zulip/#version=GBmain)" + }, + "detailedMessage": { + "text": "Yuro Itaki pushed 50 commits to test-zulip:main\r\n - Modify readme b0ce2f20 (https://dev.azure.com/ttchong/test-zulip/_git/test-zulip/commit/b0ce2f2009c3c87dbefadf61d7eb2c0697a6f369)", + "html": "Yuro Itaki pushed 50 commits to test-zulip:main\r\n", + "markdown": "Yuro Itaki pushed 50 commits to [test-zulip](https://dev.azure.com/ttchong/test-zulip/_git/test-zulip/):[main](https://dev.azure.com/ttchong/test-zulip/_git/test-zulip/#version=GBmain)\r\n* Modify readme [b0ce2f20](https://dev.azure.com/ttchong/test-zulip/_git/test-zulip/commit/b0ce2f2009c3c87dbefadf61d7eb2c0697a6f369)" + }, + "resource": { + "commits": [ + { + "commitId": "b0ce2f2009c3c87dbefadf61d7eb2c0697a6f369", + "author": { + "name": "Yuro Itaki", + "email": "yuroitaki@email.com", + "date": "2022-07-17T07:14:01Z" + }, + "committer": { + "name": "Yuro Itaki", + "email": "yuroitaki@email.com", + "date": "2022-07-17T07:14:01Z" + }, + "comment": "Modify readme", + "url": "https://dev.azure.com/ttchong/_apis/git/repositories/98f0ce59-a912-43d5-96d2-bc0942a03f7b/commits/b0ce2f2009c3c87dbefadf61d7eb2c0697a6f369" + }, + { + "commitId": "b0ce2f2009c3c87dbefadf61d7eb2c0697a6f369", + "author": { + "name": "Yuro Itaki", + "email": "yuroitaki@email.com", + "date": "2022-07-17T07:14:01Z" + }, + "committer": { + "name": "Yuro Itaki", + "email": "yuroitaki@email.com", + "date": "2022-07-17T07:14:01Z" + }, + "comment": "Modify readme", + "url": "https://dev.azure.com/ttchong/_apis/git/repositories/98f0ce59-a912-43d5-96d2-bc0942a03f7b/commits/b0ce2f2009c3c87dbefadf61d7eb2c0697a6f369" + }, + { + "commitId": "b0ce2f2009c3c87dbefadf61d7eb2c0697a6f369", + "author": { + "name": "Yuro Itaki", + "email": "yuroitaki@email.com", + "date": "2022-07-17T07:14:01Z" + }, + "committer": { + "name": "Yuro Itaki", + "email": "yuroitaki@email.com", + "date": "2022-07-17T07:14:01Z" + }, + "comment": "Modify readme", + "url": "https://dev.azure.com/ttchong/_apis/git/repositories/98f0ce59-a912-43d5-96d2-bc0942a03f7b/commits/b0ce2f2009c3c87dbefadf61d7eb2c0697a6f369" + }, + { + "commitId": "b0ce2f2009c3c87dbefadf61d7eb2c0697a6f369", + "author": { + "name": "Yuro Itaki", + "email": "yuroitaki@email.com", + "date": "2022-07-17T07:14:01Z" + }, + "committer": { + "name": "Yuro Itaki", + "email": "yuroitaki@email.com", + "date": "2022-07-17T07:14:01Z" + }, + "comment": "Modify readme", + "url": "https://dev.azure.com/ttchong/_apis/git/repositories/98f0ce59-a912-43d5-96d2-bc0942a03f7b/commits/b0ce2f2009c3c87dbefadf61d7eb2c0697a6f369" + }, + { + "commitId": "b0ce2f2009c3c87dbefadf61d7eb2c0697a6f369", + "author": { + "name": "Yuro Itaki", + "email": "yuroitaki@email.com", + "date": "2022-07-17T07:14:01Z" + }, + "committer": { + "name": "Yuro Itaki", + "email": "yuroitaki@email.com", + "date": "2022-07-17T07:14:01Z" + }, + "comment": "Modify readme", + "url": "https://dev.azure.com/ttchong/_apis/git/repositories/98f0ce59-a912-43d5-96d2-bc0942a03f7b/commits/b0ce2f2009c3c87dbefadf61d7eb2c0697a6f369" + }, + { + "commitId": "b0ce2f2009c3c87dbefadf61d7eb2c0697a6f369", + "author": { + "name": "Yuro Itaki", + "email": "yuroitaki@email.com", + "date": "2022-07-17T07:14:01Z" + }, + "committer": { + "name": "Yuro Itaki", + "email": "yuroitaki@email.com", + "date": "2022-07-17T07:14:01Z" + }, + "comment": "Modify readme", + "url": "https://dev.azure.com/ttchong/_apis/git/repositories/98f0ce59-a912-43d5-96d2-bc0942a03f7b/commits/b0ce2f2009c3c87dbefadf61d7eb2c0697a6f369" + }, + { + "commitId": "b0ce2f2009c3c87dbefadf61d7eb2c0697a6f369", + "author": { + "name": "Yuro Itaki", + "email": "yuroitaki@email.com", + "date": "2022-07-17T07:14:01Z" + }, + "committer": { + "name": "Yuro Itaki", + "email": "yuroitaki@email.com", + "date": "2022-07-17T07:14:01Z" + }, + "comment": "Modify readme", + "url": "https://dev.azure.com/ttchong/_apis/git/repositories/98f0ce59-a912-43d5-96d2-bc0942a03f7b/commits/b0ce2f2009c3c87dbefadf61d7eb2c0697a6f369" + }, + { + "commitId": "b0ce2f2009c3c87dbefadf61d7eb2c0697a6f369", + "author": { + "name": "Yuro Itaki", + "email": "yuroitaki@email.com", + "date": "2022-07-17T07:14:01Z" + }, + "committer": { + "name": "Yuro Itaki", + "email": "yuroitaki@email.com", + "date": "2022-07-17T07:14:01Z" + }, + "comment": "Modify readme", + "url": "https://dev.azure.com/ttchong/_apis/git/repositories/98f0ce59-a912-43d5-96d2-bc0942a03f7b/commits/b0ce2f2009c3c87dbefadf61d7eb2c0697a6f369" + }, + { + "commitId": "b0ce2f2009c3c87dbefadf61d7eb2c0697a6f369", + "author": { + "name": "Yuro Itaki", + "email": "yuroitaki@email.com", + "date": "2022-07-17T07:14:01Z" + }, + "committer": { + "name": "Yuro Itaki", + "email": "yuroitaki@email.com", + "date": "2022-07-17T07:14:01Z" + }, + "comment": "Modify readme", + "url": "https://dev.azure.com/ttchong/_apis/git/repositories/98f0ce59-a912-43d5-96d2-bc0942a03f7b/commits/b0ce2f2009c3c87dbefadf61d7eb2c0697a6f369" + }, + { + "commitId": "b0ce2f2009c3c87dbefadf61d7eb2c0697a6f369", + "author": { + "name": "Yuro Itaki", + "email": "yuroitaki@email.com", + "date": "2022-07-17T07:14:01Z" + }, + "committer": { + "name": "Yuro Itaki", + "email": "yuroitaki@email.com", + "date": "2022-07-17T07:14:01Z" + }, + "comment": "Modify readme", + "url": "https://dev.azure.com/ttchong/_apis/git/repositories/98f0ce59-a912-43d5-96d2-bc0942a03f7b/commits/b0ce2f2009c3c87dbefadf61d7eb2c0697a6f369" + }, + { + "commitId": "b0ce2f2009c3c87dbefadf61d7eb2c0697a6f369", + "author": { + "name": "Yuro Itaki", + "email": "yuroitaki@email.com", + "date": "2022-07-17T07:14:01Z" + }, + "committer": { + "name": "Yuro Itaki", + "email": "yuroitaki@email.com", + "date": "2022-07-17T07:14:01Z" + }, + "comment": "Modify readme", + "url": "https://dev.azure.com/ttchong/_apis/git/repositories/98f0ce59-a912-43d5-96d2-bc0942a03f7b/commits/b0ce2f2009c3c87dbefadf61d7eb2c0697a6f369" + }, + { + "commitId": "b0ce2f2009c3c87dbefadf61d7eb2c0697a6f369", + "author": { + "name": "Yuro Itaki", + "email": "yuroitaki@email.com", + "date": "2022-07-17T07:14:01Z" + }, + "committer": { + "name": "Yuro Itaki", + "email": "yuroitaki@email.com", + "date": "2022-07-17T07:14:01Z" + }, + "comment": "Modify readme", + "url": "https://dev.azure.com/ttchong/_apis/git/repositories/98f0ce59-a912-43d5-96d2-bc0942a03f7b/commits/b0ce2f2009c3c87dbefadf61d7eb2c0697a6f369" + }, + { + "commitId": "b0ce2f2009c3c87dbefadf61d7eb2c0697a6f369", + "author": { + "name": "Yuro Itaki", + "email": "yuroitaki@email.com", + "date": "2022-07-17T07:14:01Z" + }, + "committer": { + "name": "Yuro Itaki", + "email": "yuroitaki@email.com", + "date": "2022-07-17T07:14:01Z" + }, + "comment": "Modify readme", + "url": "https://dev.azure.com/ttchong/_apis/git/repositories/98f0ce59-a912-43d5-96d2-bc0942a03f7b/commits/b0ce2f2009c3c87dbefadf61d7eb2c0697a6f369" + }, + { + "commitId": "b0ce2f2009c3c87dbefadf61d7eb2c0697a6f369", + "author": { + "name": "Yuro Itaki", + "email": "yuroitaki@email.com", + "date": "2022-07-17T07:14:01Z" + }, + "committer": { + "name": "Yuro Itaki", + "email": "yuroitaki@email.com", + "date": "2022-07-17T07:14:01Z" + }, + "comment": "Modify readme", + "url": "https://dev.azure.com/ttchong/_apis/git/repositories/98f0ce59-a912-43d5-96d2-bc0942a03f7b/commits/b0ce2f2009c3c87dbefadf61d7eb2c0697a6f369" + }, + { + "commitId": "b0ce2f2009c3c87dbefadf61d7eb2c0697a6f369", + "author": { + "name": "Yuro Itaki", + "email": "yuroitaki@email.com", + "date": "2022-07-17T07:14:01Z" + }, + "committer": { + "name": "Yuro Itaki", + "email": "yuroitaki@email.com", + "date": "2022-07-17T07:14:01Z" + }, + "comment": "Modify readme", + "url": "https://dev.azure.com/ttchong/_apis/git/repositories/98f0ce59-a912-43d5-96d2-bc0942a03f7b/commits/b0ce2f2009c3c87dbefadf61d7eb2c0697a6f369" + }, + { + "commitId": "b0ce2f2009c3c87dbefadf61d7eb2c0697a6f369", + "author": { + "name": "Yuro Itaki", + "email": "yuroitaki@email.com", + "date": "2022-07-17T07:14:01Z" + }, + "committer": { + "name": "Yuro Itaki", + "email": "yuroitaki@email.com", + "date": "2022-07-17T07:14:01Z" + }, + "comment": "Modify readme", + "url": "https://dev.azure.com/ttchong/_apis/git/repositories/98f0ce59-a912-43d5-96d2-bc0942a03f7b/commits/b0ce2f2009c3c87dbefadf61d7eb2c0697a6f369" + }, + { + "commitId": "b0ce2f2009c3c87dbefadf61d7eb2c0697a6f369", + "author": { + "name": "Yuro Itaki", + "email": "yuroitaki@email.com", + "date": "2022-07-17T07:14:01Z" + }, + "committer": { + "name": "Yuro Itaki", + "email": "yuroitaki@email.com", + "date": "2022-07-17T07:14:01Z" + }, + "comment": "Modify readme", + "url": "https://dev.azure.com/ttchong/_apis/git/repositories/98f0ce59-a912-43d5-96d2-bc0942a03f7b/commits/b0ce2f2009c3c87dbefadf61d7eb2c0697a6f369" + }, + { + "commitId": "b0ce2f2009c3c87dbefadf61d7eb2c0697a6f369", + "author": { + "name": "Yuro Itaki", + "email": "yuroitaki@email.com", + "date": "2022-07-17T07:14:01Z" + }, + "committer": { + "name": "Yuro Itaki", + "email": "yuroitaki@email.com", + "date": "2022-07-17T07:14:01Z" + }, + "comment": "Modify readme", + "url": "https://dev.azure.com/ttchong/_apis/git/repositories/98f0ce59-a912-43d5-96d2-bc0942a03f7b/commits/b0ce2f2009c3c87dbefadf61d7eb2c0697a6f369" + }, + { + "commitId": "b0ce2f2009c3c87dbefadf61d7eb2c0697a6f369", + "author": { + "name": "Yuro Itaki", + "email": "yuroitaki@email.com", + "date": "2022-07-17T07:14:01Z" + }, + "committer": { + "name": "Yuro Itaki", + "email": "yuroitaki@email.com", + "date": "2022-07-17T07:14:01Z" + }, + "comment": "Modify readme", + "url": "https://dev.azure.com/ttchong/_apis/git/repositories/98f0ce59-a912-43d5-96d2-bc0942a03f7b/commits/b0ce2f2009c3c87dbefadf61d7eb2c0697a6f369" + }, + { + "commitId": "b0ce2f2009c3c87dbefadf61d7eb2c0697a6f369", + "author": { + "name": "Yuro Itaki", + "email": "yuroitaki@email.com", + "date": "2022-07-17T07:14:01Z" + }, + "committer": { + "name": "Yuro Itaki", + "email": "yuroitaki@email.com", + "date": "2022-07-17T07:14:01Z" + }, + "comment": "Modify readme", + "url": "https://dev.azure.com/ttchong/_apis/git/repositories/98f0ce59-a912-43d5-96d2-bc0942a03f7b/commits/b0ce2f2009c3c87dbefadf61d7eb2c0697a6f369" + }, + { + "commitId": "b0ce2f2009c3c87dbefadf61d7eb2c0697a6f369", + "author": { + "name": "Yuro Itaki", + "email": "yuroitaki@email.com", + "date": "2022-07-17T07:14:01Z" + }, + "committer": { + "name": "Yuro Itaki", + "email": "yuroitaki@email.com", + "date": "2022-07-17T07:14:01Z" + }, + "comment": "Modify readme", + "url": "https://dev.azure.com/ttchong/_apis/git/repositories/98f0ce59-a912-43d5-96d2-bc0942a03f7b/commits/b0ce2f2009c3c87dbefadf61d7eb2c0697a6f369" + }, + { + "commitId": "b0ce2f2009c3c87dbefadf61d7eb2c0697a6f369", + "author": { + "name": "Yuro Itaki", + "email": "yuroitaki@email.com", + "date": "2022-07-17T07:14:01Z" + }, + "committer": { + "name": "Yuro Itaki", + "email": "yuroitaki@email.com", + "date": "2022-07-17T07:14:01Z" + }, + "comment": "Modify readme", + "url": "https://dev.azure.com/ttchong/_apis/git/repositories/98f0ce59-a912-43d5-96d2-bc0942a03f7b/commits/b0ce2f2009c3c87dbefadf61d7eb2c0697a6f369" + }, + { + "commitId": "b0ce2f2009c3c87dbefadf61d7eb2c0697a6f369", + "author": { + "name": "Yuro Itaki", + "email": "yuroitaki@email.com", + "date": "2022-07-17T07:14:01Z" + }, + "committer": { + "name": "Yuro Itaki", + "email": "yuroitaki@email.com", + "date": "2022-07-17T07:14:01Z" + }, + "comment": "Modify readme", + "url": "https://dev.azure.com/ttchong/_apis/git/repositories/98f0ce59-a912-43d5-96d2-bc0942a03f7b/commits/b0ce2f2009c3c87dbefadf61d7eb2c0697a6f369" + }, + { + "commitId": "b0ce2f2009c3c87dbefadf61d7eb2c0697a6f369", + "author": { + "name": "Yuro Itaki", + "email": "yuroitaki@email.com", + "date": "2022-07-17T07:14:01Z" + }, + "committer": { + "name": "Yuro Itaki", + "email": "yuroitaki@email.com", + "date": "2022-07-17T07:14:01Z" + }, + "comment": "Modify readme", + "url": "https://dev.azure.com/ttchong/_apis/git/repositories/98f0ce59-a912-43d5-96d2-bc0942a03f7b/commits/b0ce2f2009c3c87dbefadf61d7eb2c0697a6f369" + }, + { + "commitId": "b0ce2f2009c3c87dbefadf61d7eb2c0697a6f369", + "author": { + "name": "Yuro Itaki", + "email": "yuroitaki@email.com", + "date": "2022-07-17T07:14:01Z" + }, + "committer": { + "name": "Yuro Itaki", + "email": "yuroitaki@email.com", + "date": "2022-07-17T07:14:01Z" + }, + "comment": "Modify readme", + "url": "https://dev.azure.com/ttchong/_apis/git/repositories/98f0ce59-a912-43d5-96d2-bc0942a03f7b/commits/b0ce2f2009c3c87dbefadf61d7eb2c0697a6f369" + }, + { + "commitId": "b0ce2f2009c3c87dbefadf61d7eb2c0697a6f369", + "author": { + "name": "Yuro Itaki", + "email": "yuroitaki@email.com", + "date": "2022-07-17T07:14:01Z" + }, + "committer": { + "name": "Yuro Itaki", + "email": "yuroitaki@email.com", + "date": "2022-07-17T07:14:01Z" + }, + "comment": "Modify readme", + "url": "https://dev.azure.com/ttchong/_apis/git/repositories/98f0ce59-a912-43d5-96d2-bc0942a03f7b/commits/b0ce2f2009c3c87dbefadf61d7eb2c0697a6f369" + }, + { + "commitId": "b0ce2f2009c3c87dbefadf61d7eb2c0697a6f369", + "author": { + "name": "Yuro Itaki", + "email": "yuroitaki@email.com", + "date": "2022-07-17T07:14:01Z" + }, + "committer": { + "name": "Yuro Itaki", + "email": "yuroitaki@email.com", + "date": "2022-07-17T07:14:01Z" + }, + "comment": "Modify readme", + "url": "https://dev.azure.com/ttchong/_apis/git/repositories/98f0ce59-a912-43d5-96d2-bc0942a03f7b/commits/b0ce2f2009c3c87dbefadf61d7eb2c0697a6f369" + }, + { + "commitId": "b0ce2f2009c3c87dbefadf61d7eb2c0697a6f369", + "author": { + "name": "Yuro Itaki", + "email": "yuroitaki@email.com", + "date": "2022-07-17T07:14:01Z" + }, + "committer": { + "name": "Yuro Itaki", + "email": "yuroitaki@email.com", + "date": "2022-07-17T07:14:01Z" + }, + "comment": "Modify readme", + "url": "https://dev.azure.com/ttchong/_apis/git/repositories/98f0ce59-a912-43d5-96d2-bc0942a03f7b/commits/b0ce2f2009c3c87dbefadf61d7eb2c0697a6f369" + }, + { + "commitId": "b0ce2f2009c3c87dbefadf61d7eb2c0697a6f369", + "author": { + "name": "Yuro Itaki", + "email": "yuroitaki@email.com", + "date": "2022-07-17T07:14:01Z" + }, + "committer": { + "name": "Yuro Itaki", + "email": "yuroitaki@email.com", + "date": "2022-07-17T07:14:01Z" + }, + "comment": "Modify readme", + "url": "https://dev.azure.com/ttchong/_apis/git/repositories/98f0ce59-a912-43d5-96d2-bc0942a03f7b/commits/b0ce2f2009c3c87dbefadf61d7eb2c0697a6f369" + }, + { + "commitId": "b0ce2f2009c3c87dbefadf61d7eb2c0697a6f369", + "author": { + "name": "Yuro Itaki", + "email": "yuroitaki@email.com", + "date": "2022-07-17T07:14:01Z" + }, + "committer": { + "name": "Yuro Itaki", + "email": "yuroitaki@email.com", + "date": "2022-07-17T07:14:01Z" + }, + "comment": "Modify readme", + "url": "https://dev.azure.com/ttchong/_apis/git/repositories/98f0ce59-a912-43d5-96d2-bc0942a03f7b/commits/b0ce2f2009c3c87dbefadf61d7eb2c0697a6f369" + }, + { + "commitId": "b0ce2f2009c3c87dbefadf61d7eb2c0697a6f369", + "author": { + "name": "Yuro Itaki", + "email": "yuroitaki@email.com", + "date": "2022-07-17T07:14:01Z" + }, + "committer": { + "name": "Yuro Itaki", + "email": "yuroitaki@email.com", + "date": "2022-07-17T07:14:01Z" + }, + "comment": "Modify readme", + "url": "https://dev.azure.com/ttchong/_apis/git/repositories/98f0ce59-a912-43d5-96d2-bc0942a03f7b/commits/b0ce2f2009c3c87dbefadf61d7eb2c0697a6f369" + }, + { + "commitId": "b0ce2f2009c3c87dbefadf61d7eb2c0697a6f369", + "author": { + "name": "Yuro Itaki", + "email": "yuroitaki@email.com", + "date": "2022-07-17T07:14:01Z" + }, + "committer": { + "name": "Yuro Itaki", + "email": "yuroitaki@email.com", + "date": "2022-07-17T07:14:01Z" + }, + "comment": "Modify readme", + "url": "https://dev.azure.com/ttchong/_apis/git/repositories/98f0ce59-a912-43d5-96d2-bc0942a03f7b/commits/b0ce2f2009c3c87dbefadf61d7eb2c0697a6f369" + }, + { + "commitId": "b0ce2f2009c3c87dbefadf61d7eb2c0697a6f369", + "author": { + "name": "Yuro Itaki", + "email": "yuroitaki@email.com", + "date": "2022-07-17T07:14:01Z" + }, + "committer": { + "name": "Yuro Itaki", + "email": "yuroitaki@email.com", + "date": "2022-07-17T07:14:01Z" + }, + "comment": "Modify readme", + "url": "https://dev.azure.com/ttchong/_apis/git/repositories/98f0ce59-a912-43d5-96d2-bc0942a03f7b/commits/b0ce2f2009c3c87dbefadf61d7eb2c0697a6f369" + }, + { + "commitId": "b0ce2f2009c3c87dbefadf61d7eb2c0697a6f369", + "author": { + "name": "Yuro Itaki", + "email": "yuroitaki@email.com", + "date": "2022-07-17T07:14:01Z" + }, + "committer": { + "name": "Yuro Itaki", + "email": "yuroitaki@email.com", + "date": "2022-07-17T07:14:01Z" + }, + "comment": "Modify readme", + "url": "https://dev.azure.com/ttchong/_apis/git/repositories/98f0ce59-a912-43d5-96d2-bc0942a03f7b/commits/b0ce2f2009c3c87dbefadf61d7eb2c0697a6f369" + }, + { + "commitId": "b0ce2f2009c3c87dbefadf61d7eb2c0697a6f369", + "author": { + "name": "Yuro Itaki", + "email": "yuroitaki@email.com", + "date": "2022-07-17T07:14:01Z" + }, + "committer": { + "name": "Yuro Itaki", + "email": "yuroitaki@email.com", + "date": "2022-07-17T07:14:01Z" + }, + "comment": "Modify readme", + "url": "https://dev.azure.com/ttchong/_apis/git/repositories/98f0ce59-a912-43d5-96d2-bc0942a03f7b/commits/b0ce2f2009c3c87dbefadf61d7eb2c0697a6f369" + }, + { + "commitId": "b0ce2f2009c3c87dbefadf61d7eb2c0697a6f369", + "author": { + "name": "Yuro Itaki", + "email": "yuroitaki@email.com", + "date": "2022-07-17T07:14:01Z" + }, + "committer": { + "name": "Yuro Itaki", + "email": "yuroitaki@email.com", + "date": "2022-07-17T07:14:01Z" + }, + "comment": "Modify readme", + "url": "https://dev.azure.com/ttchong/_apis/git/repositories/98f0ce59-a912-43d5-96d2-bc0942a03f7b/commits/b0ce2f2009c3c87dbefadf61d7eb2c0697a6f369" + }, + { + "commitId": "b0ce2f2009c3c87dbefadf61d7eb2c0697a6f369", + "author": { + "name": "Yuro Itaki", + "email": "yuroitaki@email.com", + "date": "2022-07-17T07:14:01Z" + }, + "committer": { + "name": "Yuro Itaki", + "email": "yuroitaki@email.com", + "date": "2022-07-17T07:14:01Z" + }, + "comment": "Modify readme", + "url": "https://dev.azure.com/ttchong/_apis/git/repositories/98f0ce59-a912-43d5-96d2-bc0942a03f7b/commits/b0ce2f2009c3c87dbefadf61d7eb2c0697a6f369" + }, + { + "commitId": "b0ce2f2009c3c87dbefadf61d7eb2c0697a6f369", + "author": { + "name": "Yuro Itaki", + "email": "yuroitaki@email.com", + "date": "2022-07-17T07:14:01Z" + }, + "committer": { + "name": "Yuro Itaki", + "email": "yuroitaki@email.com", + "date": "2022-07-17T07:14:01Z" + }, + "comment": "Modify readme", + "url": "https://dev.azure.com/ttchong/_apis/git/repositories/98f0ce59-a912-43d5-96d2-bc0942a03f7b/commits/b0ce2f2009c3c87dbefadf61d7eb2c0697a6f369" + }, + { + "commitId": "b0ce2f2009c3c87dbefadf61d7eb2c0697a6f369", + "author": { + "name": "Yuro Itaki", + "email": "yuroitaki@email.com", + "date": "2022-07-17T07:14:01Z" + }, + "committer": { + "name": "Yuro Itaki", + "email": "yuroitaki@email.com", + "date": "2022-07-17T07:14:01Z" + }, + "comment": "Modify readme", + "url": "https://dev.azure.com/ttchong/_apis/git/repositories/98f0ce59-a912-43d5-96d2-bc0942a03f7b/commits/b0ce2f2009c3c87dbefadf61d7eb2c0697a6f369" + }, + { + "commitId": "b0ce2f2009c3c87dbefadf61d7eb2c0697a6f369", + "author": { + "name": "Yuro Itaki", + "email": "yuroitaki@email.com", + "date": "2022-07-17T07:14:01Z" + }, + "committer": { + "name": "Yuro Itaki", + "email": "yuroitaki@email.com", + "date": "2022-07-17T07:14:01Z" + }, + "comment": "Modify readme", + "url": "https://dev.azure.com/ttchong/_apis/git/repositories/98f0ce59-a912-43d5-96d2-bc0942a03f7b/commits/b0ce2f2009c3c87dbefadf61d7eb2c0697a6f369" + }, + { + "commitId": "b0ce2f2009c3c87dbefadf61d7eb2c0697a6f369", + "author": { + "name": "Yuro Itaki", + "email": "yuroitaki@email.com", + "date": "2022-07-17T07:14:01Z" + }, + "committer": { + "name": "Yuro Itaki", + "email": "yuroitaki@email.com", + "date": "2022-07-17T07:14:01Z" + }, + "comment": "Modify readme", + "url": "https://dev.azure.com/ttchong/_apis/git/repositories/98f0ce59-a912-43d5-96d2-bc0942a03f7b/commits/b0ce2f2009c3c87dbefadf61d7eb2c0697a6f369" + }, + { + "commitId": "b0ce2f2009c3c87dbefadf61d7eb2c0697a6f369", + "author": { + "name": "Yuro Itaki", + "email": "yuroitaki@email.com", + "date": "2022-07-17T07:14:01Z" + }, + "committer": { + "name": "Yuro Itaki", + "email": "yuroitaki@email.com", + "date": "2022-07-17T07:14:01Z" + }, + "comment": "Modify readme", + "url": "https://dev.azure.com/ttchong/_apis/git/repositories/98f0ce59-a912-43d5-96d2-bc0942a03f7b/commits/b0ce2f2009c3c87dbefadf61d7eb2c0697a6f369" + }, + { + "commitId": "b0ce2f2009c3c87dbefadf61d7eb2c0697a6f369", + "author": { + "name": "Yuro Itaki", + "email": "yuroitaki@email.com", + "date": "2022-07-17T07:14:01Z" + }, + "committer": { + "name": "Yuro Itaki", + "email": "yuroitaki@email.com", + "date": "2022-07-17T07:14:01Z" + }, + "comment": "Modify readme", + "url": "https://dev.azure.com/ttchong/_apis/git/repositories/98f0ce59-a912-43d5-96d2-bc0942a03f7b/commits/b0ce2f2009c3c87dbefadf61d7eb2c0697a6f369" + }, + { + "commitId": "b0ce2f2009c3c87dbefadf61d7eb2c0697a6f369", + "author": { + "name": "Yuro Itaki", + "email": "yuroitaki@email.com", + "date": "2022-07-17T07:14:01Z" + }, + "committer": { + "name": "Yuro Itaki", + "email": "yuroitaki@email.com", + "date": "2022-07-17T07:14:01Z" + }, + "comment": "Modify readme", + "url": "https://dev.azure.com/ttchong/_apis/git/repositories/98f0ce59-a912-43d5-96d2-bc0942a03f7b/commits/b0ce2f2009c3c87dbefadf61d7eb2c0697a6f369" + }, + { + "commitId": "b0ce2f2009c3c87dbefadf61d7eb2c0697a6f369", + "author": { + "name": "Yuro Itaki", + "email": "yuroitaki@email.com", + "date": "2022-07-17T07:14:01Z" + }, + "committer": { + "name": "Yuro Itaki", + "email": "yuroitaki@email.com", + "date": "2022-07-17T07:14:01Z" + }, + "comment": "Modify readme", + "url": "https://dev.azure.com/ttchong/_apis/git/repositories/98f0ce59-a912-43d5-96d2-bc0942a03f7b/commits/b0ce2f2009c3c87dbefadf61d7eb2c0697a6f369" + }, + { + "commitId": "b0ce2f2009c3c87dbefadf61d7eb2c0697a6f369", + "author": { + "name": "Yuro Itaki", + "email": "yuroitaki@email.com", + "date": "2022-07-17T07:14:01Z" + }, + "committer": { + "name": "Yuro Itaki", + "email": "yuroitaki@email.com", + "date": "2022-07-17T07:14:01Z" + }, + "comment": "Modify readme", + "url": "https://dev.azure.com/ttchong/_apis/git/repositories/98f0ce59-a912-43d5-96d2-bc0942a03f7b/commits/b0ce2f2009c3c87dbefadf61d7eb2c0697a6f369" + }, + { + "commitId": "b0ce2f2009c3c87dbefadf61d7eb2c0697a6f369", + "author": { + "name": "Yuro Itaki", + "email": "yuroitaki@email.com", + "date": "2022-07-17T07:14:01Z" + }, + "committer": { + "name": "Yuro Itaki", + "email": "yuroitaki@email.com", + "date": "2022-07-17T07:14:01Z" + }, + "comment": "Modify readme", + "url": "https://dev.azure.com/ttchong/_apis/git/repositories/98f0ce59-a912-43d5-96d2-bc0942a03f7b/commits/b0ce2f2009c3c87dbefadf61d7eb2c0697a6f369" + }, + { + "commitId": "b0ce2f2009c3c87dbefadf61d7eb2c0697a6f369", + "author": { + "name": "Yuro Itaki", + "email": "yuroitaki@email.com", + "date": "2022-07-17T07:14:01Z" + }, + "committer": { + "name": "Yuro Itaki", + "email": "yuroitaki@email.com", + "date": "2022-07-17T07:14:01Z" + }, + "comment": "Modify readme", + "url": "https://dev.azure.com/ttchong/_apis/git/repositories/98f0ce59-a912-43d5-96d2-bc0942a03f7b/commits/b0ce2f2009c3c87dbefadf61d7eb2c0697a6f369" + }, + { + "commitId": "b0ce2f2009c3c87dbefadf61d7eb2c0697a6f369", + "author": { + "name": "Yuro Itaki", + "email": "yuroitaki@email.com", + "date": "2022-07-17T07:14:01Z" + }, + "committer": { + "name": "Yuro Itaki", + "email": "yuroitaki@email.com", + "date": "2022-07-17T07:14:01Z" + }, + "comment": "Modify readme", + "url": "https://dev.azure.com/ttchong/_apis/git/repositories/98f0ce59-a912-43d5-96d2-bc0942a03f7b/commits/b0ce2f2009c3c87dbefadf61d7eb2c0697a6f369" + }, + { + "commitId": "b0ce2f2009c3c87dbefadf61d7eb2c0697a6f369", + "author": { + "name": "Yuro Itaki", + "email": "yuroitaki@email.com", + "date": "2022-07-17T07:14:01Z" + }, + "committer": { + "name": "Yuro Itaki", + "email": "yuroitaki@email.com", + "date": "2022-07-17T07:14:01Z" + }, + "comment": "Modify readme", + "url": "https://dev.azure.com/ttchong/_apis/git/repositories/98f0ce59-a912-43d5-96d2-bc0942a03f7b/commits/b0ce2f2009c3c87dbefadf61d7eb2c0697a6f369" + } + ], + "refUpdates": [ + { + "name": "refs/heads/main", + "oldObjectId": "51515957669f93c543df09f8f3e7f47c3613c879", + "newObjectId": "b0ce2f2009c3c87dbefadf61d7eb2c0697a6f369" + } + ], + "repository": { + "id": "98f0ce59-a912-43d5-96d2-bc0942a03f7b", + "name": "test-zulip", + "url": "https://dev.azure.com/ttchong/_apis/git/repositories/98f0ce59-a912-43d5-96d2-bc0942a03f7b", + "project": { + "id": "068d2409-14eb-4d8a-88bf-c8a9e7f5b4e2", + "name": "test-zulip", + "url": "https://dev.azure.com/ttchong/_apis/projects/068d2409-14eb-4d8a-88bf-c8a9e7f5b4e2", + "state": "wellFormed", + "visibility": "unchanged", + "lastUpdateTime": "0001-01-01T00:00:00" + }, + "defaultBranch": "refs/heads/main", + "remoteUrl": "https://dev.azure.com/ttchong/test-zulip/_git/test-zulip" + }, + "pushedBy": { + "displayName": "Yuro Itaki", + "url": "https://spsprodsea2.vssps.visualstudio.com/Aa56cba4a-dc80-4dd2-91fa-6fe7047fea7c/_apis/Identities/107e08c7-2725-675e-a1b0-281729035ea6", + "_links": { + "avatar": { + "href": "https://dev.azure.com/ttchong/_apis/GraphProfile/MemberAvatars/msa.MTA3ZTA4YzctMjcyNS03NzVlLWExYjAtMjgxNzI5MDM1ZWE2" + } + }, + "id": "107e08c7-2725-675e-a1b0-281729035ea6", + "uniqueName": "yuroitaki@email.com", + "imageUrl": "https://dev.azure.com/ttchong/_api/_common/identityImage?id=107e08c7-2725-675e-a1b0-281729035ea6", + "descriptor": "msa.MTA3ZTA4YzctMjcyNS03NzVlLWExYjAtMjgxNzI5MDM1ZWE2" + }, + "pushId": 2, + "date": "2022-07-17T07:14:05.9409049Z", + "url": "https://dev.azure.com/ttchong/_apis/git/repositories/98f0ce59-a912-43d5-96d2-bc0942a03f7b/pushes/2", + "_links": { + "self": { + "href": "https://dev.azure.com/ttchong/_apis/git/repositories/98f0ce59-a912-43d5-96d2-bc0942a03f7b/pushes/2" + }, + "repository": { + "href": "https://dev.azure.com/ttchong/068d2409-14eb-4d8a-88bf-c8a9e7f5b4e2/_apis/git/repositories/98f0ce59-a912-43d5-96d2-bc0942a03f7b" + }, + "commits": { + "href": "https://dev.azure.com/ttchong/_apis/git/repositories/98f0ce59-a912-43d5-96d2-bc0942a03f7b/pushes/2/commits" + }, + "pusher": { + "href": "https://spsprodsea2.vssps.visualstudio.com/Aa56cba4a-dc80-4dd2-91fa-6fe7047fea7c/_apis/Identities/107e08c7-2725-675e-a1b0-281729035ea6" + }, + "refs": { + "href": "https://dev.azure.com/ttchong/068d2409-14eb-4d8a-88bf-c8a9e7f5b4e2/_apis/git/repositories/98f0ce59-a912-43d5-96d2-bc0942a03f7b/refs/heads/main" + } + } + }, + "resourceVersion": "1.0", + "resourceContainers": { + "collection": { + "id": "ad9e1dcf-6055-4fc7-a146-5511ab5ab1e8", + "baseUrl": "https://dev.azure.com/ttchong/" + }, + "account": { + "id": "a56cba4a-dc80-4dd2-91fa-6fe7047fea7c", + "baseUrl": "https://dev.azure.com/ttchong/" + }, + "project": { + "id": "068d2409-14eb-4d8a-88bf-c8a9e7f5b4e2", + "baseUrl": "https://dev.azure.com/ttchong/" + } + }, + "createdDate": "2022-07-17T07:14:12.5477052Z" +} diff --git a/zerver/webhooks/azuredevops/fixtures/code_push__local_branch_without_commits.json b/zerver/webhooks/azuredevops/fixtures/code_push__local_branch_without_commits.json new file mode 100644 index 0000000000..0565924e76 --- /dev/null +++ b/zerver/webhooks/azuredevops/fixtures/code_push__local_branch_without_commits.json @@ -0,0 +1,90 @@ +{ + "subscriptionId": "eead0877-fb06-46e2-9ec1-5f852a6d0297", + "notificationId": 3, + "id": "7687ae00-23fe-44e8-a66b-bb61d279e2e1", + "eventType": "git.push", + "publisherId": "tfs", + "message": { + "text": "Yuro Itaki pushed updates to test-zulip:dev\r\n(https://dev.azure.com/ttchong/test-zulip/_git/test-zulip/#version=GBdev)", + "html": "Yuro Itaki pushed updates to test-zulip:dev", + "markdown": "Yuro Itaki pushed updates to [test-zulip](https://dev.azure.com/ttchong/test-zulip/_git/test-zulip/):[dev](https://dev.azure.com/ttchong/test-zulip/_git/test-zulip/#version=GBdev)" + }, + "detailedMessage": { + "text": "Yuro Itaki pushed a commit to test-zulip:dev\r\n - Add reply 0929a340 (https://dev.azure.com/ttchong/test-zulip/_git/test-zulip/commit/0929a3404b39f6e39076a640779b2c1c961e19b5)", + "html": "Yuro Itaki pushed a commit to test-zulip:dev\r\n", + "markdown": "Yuro Itaki pushed a commit to [test-zulip](https://dev.azure.com/ttchong/test-zulip/_git/test-zulip/):[dev](https://dev.azure.com/ttchong/test-zulip/_git/test-zulip/#version=GBdev)\r\n* Add reply [0929a340](https://dev.azure.com/ttchong/test-zulip/_git/test-zulip/commit/0929a3404b39f6e39076a640779b2c1c961e19b5)" + }, + "resource": { + "refUpdates": [ + { + "name": "refs/heads/dev", + "oldObjectId": "0000000000000000000000000000000000000000", + "newObjectId": "0929a3404b39f6e39076a640779b2c1c961e19b5" + } + ], + "repository": { + "id": "98f0ce59-a912-43d5-96d2-bc0942a03f7b", + "name": "test-zulip", + "url": "https://dev.azure.com/ttchong/_apis/git/repositories/98f0ce59-a912-43d5-96d2-bc0942a03f7b", + "project": { + "id": "068d2409-14eb-4d8a-88bf-c8a9e7f5b4e2", + "name": "test-zulip", + "url": "https://dev.azure.com/ttchong/_apis/projects/068d2409-14eb-4d8a-88bf-c8a9e7f5b4e2", + "state": "wellFormed", + "visibility": "unchanged", + "lastUpdateTime": "0001-01-01T00:00:00" + }, + "defaultBranch": "refs/heads/main", + "remoteUrl": "https://dev.azure.com/ttchong/test-zulip/_git/test-zulip" + }, + "pushedBy": { + "displayName": "Yuro Itaki", + "url": "https://spsprodsea2.vssps.visualstudio.com/Aa56cba4a-dc80-4dd2-91fa-6fe7047fea7c/_apis/Identities/107e08c7-2725-675e-a1b0-281729035ea6", + "_links": { + "avatar": { + "href": "https://dev.azure.com/ttchong/_apis/GraphProfile/MemberAvatars/msa.MTA3ZTA4YzctMjcyNS03NzVlLWExYjAtMjgxNzI5MDM1ZWE2" + } + }, + "id": "107e08c7-2725-675e-a1b0-281729035ea6", + "uniqueName": "yuroitaki@email.com", + "imageUrl": "https://dev.azure.com/ttchong/_api/_common/identityImage?id=107e08c7-2725-675e-a1b0-281729035ea6", + "descriptor": "msa.MTA3ZTA4YzctMjcyNS03NzVlLWExYjAtMjgxNzI5MDM1ZWE2" + }, + "pushId": 5, + "date": "2022-07-17T10:18:15.3667447Z", + "url": "https://dev.azure.com/ttchong/_apis/git/repositories/98f0ce59-a912-43d5-96d2-bc0942a03f7b/pushes/5", + "_links": { + "self": { + "href": "https://dev.azure.com/ttchong/_apis/git/repositories/98f0ce59-a912-43d5-96d2-bc0942a03f7b/pushes/5" + }, + "repository": { + "href": "https://dev.azure.com/ttchong/068d2409-14eb-4d8a-88bf-c8a9e7f5b4e2/_apis/git/repositories/98f0ce59-a912-43d5-96d2-bc0942a03f7b" + }, + "commits": { + "href": "https://dev.azure.com/ttchong/_apis/git/repositories/98f0ce59-a912-43d5-96d2-bc0942a03f7b/pushes/5/commits" + }, + "pusher": { + "href": "https://spsprodsea2.vssps.visualstudio.com/Aa56cba4a-dc80-4dd2-91fa-6fe7047fea7c/_apis/Identities/107e08c7-2725-675e-a1b0-281729035ea6" + }, + "refs": { + "href": "https://dev.azure.com/ttchong/068d2409-14eb-4d8a-88bf-c8a9e7f5b4e2/_apis/git/repositories/98f0ce59-a912-43d5-96d2-bc0942a03f7b/refs/heads/dev" + } + } + }, + "resourceVersion": "1.0", + "resourceContainers": { + "collection": { + "id": "ad9e1dcf-6055-4fc7-a146-5511ab5ab1e8", + "baseUrl": "https://dev.azure.com/ttchong/" + }, + "account": { + "id": "a56cba4a-dc80-4dd2-91fa-6fe7047fea7c", + "baseUrl": "https://dev.azure.com/ttchong/" + }, + "project": { + "id": "068d2409-14eb-4d8a-88bf-c8a9e7f5b4e2", + "baseUrl": "https://dev.azure.com/ttchong/" + } + }, + "createdDate": "2022-07-17T10:18:22.69149Z" +} diff --git a/zerver/webhooks/azuredevops/fixtures/code_push__multiple_committers.json b/zerver/webhooks/azuredevops/fixtures/code_push__multiple_committers.json new file mode 100644 index 0000000000..189499ca75 --- /dev/null +++ b/zerver/webhooks/azuredevops/fixtures/code_push__multiple_committers.json @@ -0,0 +1,122 @@ +{ + "subscriptionId": "eead0877-fb06-46e2-9ec1-5f852a6d0297", + "notificationId": 2, + "id": "7afcf4e6-f3d0-47f0-ba5f-395f0776496b", + "eventType": "git.push", + "publisherId": "tfs", + "message": { + "text": "Yuro Itaki pushed updates to test-zulip:main\r\n(https://dev.azure.com/ttchong/test-zulip/_git/test-zulip/#version=GBmain)", + "html": "Yuro Itaki pushed updates to test-zulip:main", + "markdown": "Yuro Itaki pushed updates to [test-zulip](https://dev.azure.com/ttchong/test-zulip/_git/test-zulip/):[main](https://dev.azure.com/ttchong/test-zulip/_git/test-zulip/#version=GBmain)" + }, + "detailedMessage": { + "text": "Yuro Itaki pushed 2 commits to test-zulip:main\r\n - Add reply 0929a340 (https://dev.azure.com/ttchong/test-zulip/_git/test-zulip/commit/0929a3404b39f6e39076a640779b2c1c961e19b5)\r\n - Add how are you 819ce8de (https://dev.azure.com/ttchong/test-zulip/_git/test-zulip/commit/819ce8de51bedfc250c202edcaee0ce8dc70bf3b)", + "html": "Yuro Itaki pushed 2 commits to test-zulip:main\r\n", + "markdown": "Yuro Itaki pushed 2 commits to [test-zulip](https://dev.azure.com/ttchong/test-zulip/_git/test-zulip/):[main](https://dev.azure.com/ttchong/test-zulip/_git/test-zulip/#version=GBmain)\r\n* Add reply [0929a340](https://dev.azure.com/ttchong/test-zulip/_git/test-zulip/commit/0929a3404b39f6e39076a640779b2c1c961e19b5)\r\n* Add how are you [819ce8de](https://dev.azure.com/ttchong/test-zulip/_git/test-zulip/commit/819ce8de51bedfc250c202edcaee0ce8dc70bf3b)" + }, + "resource": { + "commits": [ + { + "commitId": "0929a3404b39f6e39076a640779b2c1c961e19b5", + "author": { + "name": "Yuro Itaki", + "email": "yuroitaki@email.com", + "date": "2022-07-17T09:13:02Z" + }, + "committer": { + "name": "Yuro Itaki", + "email": "yuroitaki@email.com", + "date": "2022-07-17T09:13:02Z" + }, + "comment": "Add reply", + "url": "https://dev.azure.com/ttchong/_apis/git/repositories/98f0ce59-a912-43d5-96d2-bc0942a03f7b/commits/0929a3404b39f6e39076a640779b2c1c961e19b5" + }, + { + "commitId": "819ce8de51bedfc250c202edcaee0ce8dc70bf3b", + "author": { + "name": "Itachi Sensei", + "email": "itachisensei@email.com", + "date": "2022-07-17T09:12:35Z" + }, + "committer": { + "name": "Itachi Sensei", + "email": "itachisensei@email.com", + "date": "2022-07-17T09:12:35Z" + }, + "comment": "Add how are you", + "url": "https://dev.azure.com/ttchong/_apis/git/repositories/98f0ce59-a912-43d5-96d2-bc0942a03f7b/commits/819ce8de51bedfc250c202edcaee0ce8dc70bf3b" + } + ], + "refUpdates": [ + { + "name": "refs/heads/main", + "oldObjectId": "cc21b940719cc372b364d932eb39e528b0ec2a91", + "newObjectId": "0929a3404b39f6e39076a640779b2c1c961e19b5" + } + ], + "repository": { + "id": "98f0ce59-a912-43d5-96d2-bc0942a03f7b", + "name": "test-zulip", + "url": "https://dev.azure.com/ttchong/_apis/git/repositories/98f0ce59-a912-43d5-96d2-bc0942a03f7b", + "project": { + "id": "068d2409-14eb-4d8a-88bf-c8a9e7f5b4e2", + "name": "test-zulip", + "url": "https://dev.azure.com/ttchong/_apis/projects/068d2409-14eb-4d8a-88bf-c8a9e7f5b4e2", + "state": "wellFormed", + "visibility": "unchanged", + "lastUpdateTime": "0001-01-01T00:00:00" + }, + "defaultBranch": "refs/heads/main", + "remoteUrl": "https://dev.azure.com/ttchong/test-zulip/_git/test-zulip" + }, + "pushedBy": { + "displayName": "Yuro Itaki", + "url": "https://spsprodsea2.vssps.visualstudio.com/Aa56cba4a-dc80-4dd2-91fa-6fe7047fea7c/_apis/Identities/107e08c7-2725-675e-a1b0-281729035ea6", + "_links": { + "avatar": { + "href": "https://dev.azure.com/ttchong/_apis/GraphProfile/MemberAvatars/msa.MTA3ZTA4YzctMjcyNS03NzVlLWExYjAtMjgxNzI5MDM1ZWE2" + } + }, + "id": "107e08c7-2725-675e-a1b0-281729035ea6", + "uniqueName": "yuroitaki@email.com", + "imageUrl": "https://dev.azure.com/ttchong/_api/_common/identityImage?id=107e08c7-2725-675e-a1b0-281729035ea6", + "descriptor": "msa.MTA3ZTA4YzctMjcyNS03NzVlLWExYjAtMjgxNzI5MDM1ZWE2" + }, + "pushId": 4, + "date": "2022-07-17T09:13:10.0775053Z", + "url": "https://dev.azure.com/ttchong/_apis/git/repositories/98f0ce59-a912-43d5-96d2-bc0942a03f7b/pushes/4", + "_links": { + "self": { + "href": "https://dev.azure.com/ttchong/_apis/git/repositories/98f0ce59-a912-43d5-96d2-bc0942a03f7b/pushes/4" + }, + "repository": { + "href": "https://dev.azure.com/ttchong/068d2409-14eb-4d8a-88bf-c8a9e7f5b4e2/_apis/git/repositories/98f0ce59-a912-43d5-96d2-bc0942a03f7b" + }, + "commits": { + "href": "https://dev.azure.com/ttchong/_apis/git/repositories/98f0ce59-a912-43d5-96d2-bc0942a03f7b/pushes/4/commits" + }, + "pusher": { + "href": "https://spsprodsea2.vssps.visualstudio.com/Aa56cba4a-dc80-4dd2-91fa-6fe7047fea7c/_apis/Identities/107e08c7-2725-675e-a1b0-281729035ea6" + }, + "refs": { + "href": "https://dev.azure.com/ttchong/068d2409-14eb-4d8a-88bf-c8a9e7f5b4e2/_apis/git/repositories/98f0ce59-a912-43d5-96d2-bc0942a03f7b/refs/heads/main" + } + } + }, + "resourceVersion": "1.0", + "resourceContainers": { + "collection": { + "id": "ad9e1dcf-6055-4fc7-a146-5511ab5ab1e8", + "baseUrl": "https://dev.azure.com/ttchong/" + }, + "account": { + "id": "a56cba4a-dc80-4dd2-91fa-6fe7047fea7c", + "baseUrl": "https://dev.azure.com/ttchong/" + }, + "project": { + "id": "068d2409-14eb-4d8a-88bf-c8a9e7f5b4e2", + "baseUrl": "https://dev.azure.com/ttchong/" + } + }, + "createdDate": "2022-07-17T09:13:17.0920723Z" +} diff --git a/zerver/webhooks/azuredevops/fixtures/code_push__multiple_committers_with_others.json b/zerver/webhooks/azuredevops/fixtures/code_push__multiple_committers_with_others.json new file mode 100644 index 0000000000..41db88be87 --- /dev/null +++ b/zerver/webhooks/azuredevops/fixtures/code_push__multiple_committers_with_others.json @@ -0,0 +1,182 @@ +{ + "subscriptionId": "eead0877-fb06-46e2-9ec1-5f852a6d0297", + "notificationId": 2, + "id": "7afcf4e6-f3d0-47f0-ba5f-395f0776496b", + "eventType": "git.push", + "publisherId": "tfs", + "message": { + "text": "Yuro Itaki pushed updates to test-zulip:main\r\n(https://dev.azure.com/ttchong/test-zulip/_git/test-zulip/#version=GBmain)", + "html": "Yuro Itaki pushed updates to test-zulip:main", + "markdown": "Yuro Itaki pushed updates to [test-zulip](https://dev.azure.com/ttchong/test-zulip/_git/test-zulip/):[main](https://dev.azure.com/ttchong/test-zulip/_git/test-zulip/#version=GBmain)" + }, + "detailedMessage": { + "text": "Yuro Itaki pushed 6 commits to test-zulip:main\r\n - Add reply 0929a340 (https://dev.azure.com/ttchong/test-zulip/_git/test-zulip/commit/0929a3404b39f6e39076a640779b2c1c961e19b5)\r\n - Add how are you 819ce8de (https://dev.azure.com/ttchong/test-zulip/_git/test-zulip/commit/819ce8de51bedfc250c202edcaee0ce8dc70bf3b)", + "html": "Yuro Itaki pushed 6 commits to test-zulip:main\r\n", + "markdown": "Yuro Itaki pushed 6 commits to [test-zulip](https://dev.azure.com/ttchong/test-zulip/_git/test-zulip/):[main](https://dev.azure.com/ttchong/test-zulip/_git/test-zulip/#version=GBmain)\r\n* Add reply [0929a340](https://dev.azure.com/ttchong/test-zulip/_git/test-zulip/commit/0929a3404b39f6e39076a640779b2c1c961e19b5)\r\n* Add how are you [819ce8de](https://dev.azure.com/ttchong/test-zulip/_git/test-zulip/commit/819ce8de51bedfc250c202edcaee0ce8dc70bf3b)" + }, + "resource": { + "commits": [ + { + "commitId": "0929a3404b39f6e39076a640779b2c1c961e19b5", + "author": { + "name": "Yuro Itaki", + "email": "yuroitaki@email.com", + "date": "2022-07-17T09:13:02Z" + }, + "committer": { + "name": "Yuro Itaki", + "email": "yuroitaki@email.com", + "date": "2022-07-17T09:13:02Z" + }, + "comment": "Add reply", + "url": "https://dev.azure.com/ttchong/_apis/git/repositories/98f0ce59-a912-43d5-96d2-bc0942a03f7b/commits/0929a3404b39f6e39076a640779b2c1c961e19b5" + }, + { + "commitId": "819ce8de51bedfc250c202edcaee0ce8dc70bf3b", + "author": { + "name": "Itachi Sensei", + "email": "itachisensei@email.com", + "date": "2022-07-17T09:12:35Z" + }, + "committer": { + "name": "Itachi Sensei", + "email": "itachisensei@email.com", + "date": "2022-07-17T09:12:35Z" + }, + "comment": "Add how are you", + "url": "https://dev.azure.com/ttchong/_apis/git/repositories/98f0ce59-a912-43d5-96d2-bc0942a03f7b/commits/819ce8de51bedfc250c202edcaee0ce8dc70bf3b" + }, + { + "commitId": "819ce8de51bedfc250c202edcaee0ce8dc70bf3b", + "author": { + "name": "Itachi Sensei", + "email": "itachisensei@email.com", + "date": "2022-07-17T09:12:35Z" + }, + "committer": { + "name": "Itachi Sensei", + "email": "itachisensei@email.com", + "date": "2022-07-17T09:12:35Z" + }, + "comment": "Add how are you", + "url": "https://dev.azure.com/ttchong/_apis/git/repositories/98f0ce59-a912-43d5-96d2-bc0942a03f7b/commits/819ce8de51bedfc250c202edcaee0ce8dc70bf3b" + }, + { + "commitId": "819ce8de51bedfc250c202edcaee0ce8dc70bf3b", + "author": { + "name": "Lelouch Strange", + "email": "lelouchstrange@email.com", + "date": "2022-07-17T09:12:35Z" + }, + "committer": { + "name": "Lelouch Strange", + "email": "lelouchstrange@email.com", + "date": "2022-07-17T09:12:35Z" + }, + "comment": "Add how are you", + "url": "https://dev.azure.com/ttchong/_apis/git/repositories/98f0ce59-a912-43d5-96d2-bc0942a03f7b/commits/819ce8de51bedfc250c202edcaee0ce8dc70bf3b" + }, + { + "commitId": "819ce8de51bedfc250c202edcaee0ce8dc70bf3b", + "author": { + "name": "Jonas Nielsen", + "email": "jonasnielsen@email.com", + "date": "2022-07-17T09:12:35Z" + }, + "committer": { + "name": "Jonas Nielsen", + "email": "jonasnielsen@email.com", + "date": "2022-07-17T09:12:35Z" + }, + "comment": "Add how are you", + "url": "https://dev.azure.com/ttchong/_apis/git/repositories/98f0ce59-a912-43d5-96d2-bc0942a03f7b/commits/819ce8de51bedfc250c202edcaee0ce8dc70bf3b" + }, + { + "commitId": "0929a3404b39f6e39076a640779b2c1c961e19b5", + "author": { + "name": "Yuro Itaki", + "email": "yuroitaki@email.com", + "date": "2022-07-17T09:13:02Z" + }, + "committer": { + "name": "Yuro Itaki", + "email": "yuroitaki@email.com", + "date": "2022-07-17T09:13:02Z" + }, + "comment": "Add reply", + "url": "https://dev.azure.com/ttchong/_apis/git/repositories/98f0ce59-a912-43d5-96d2-bc0942a03f7b/commits/0929a3404b39f6e39076a640779b2c1c961e19b5" + } + ], + "refUpdates": [ + { + "name": "refs/heads/main", + "oldObjectId": "cc21b940719cc372b364d932eb39e528b0ec2a91", + "newObjectId": "0929a3404b39f6e39076a640779b2c1c961e19b5" + } + ], + "repository": { + "id": "98f0ce59-a912-43d5-96d2-bc0942a03f7b", + "name": "test-zulip", + "url": "https://dev.azure.com/ttchong/_apis/git/repositories/98f0ce59-a912-43d5-96d2-bc0942a03f7b", + "project": { + "id": "068d2409-14eb-4d8a-88bf-c8a9e7f5b4e2", + "name": "test-zulip", + "url": "https://dev.azure.com/ttchong/_apis/projects/068d2409-14eb-4d8a-88bf-c8a9e7f5b4e2", + "state": "wellFormed", + "visibility": "unchanged", + "lastUpdateTime": "0001-01-01T00:00:00" + }, + "defaultBranch": "refs/heads/main", + "remoteUrl": "https://dev.azure.com/ttchong/test-zulip/_git/test-zulip" + }, + "pushedBy": { + "displayName": "Yuro Itaki", + "url": "https://spsprodsea2.vssps.visualstudio.com/Aa56cba4a-dc80-4dd2-91fa-6fe7047fea7c/_apis/Identities/107e08c7-2725-675e-a1b0-281729035ea6", + "_links": { + "avatar": { + "href": "https://dev.azure.com/ttchong/_apis/GraphProfile/MemberAvatars/msa.MTA3ZTA4YzctMjcyNS03NzVlLWExYjAtMjgxNzI5MDM1ZWE2" + } + }, + "id": "107e08c7-2725-675e-a1b0-281729035ea6", + "uniqueName": "yuroitaki@email.com", + "imageUrl": "https://dev.azure.com/ttchong/_api/_common/identityImage?id=107e08c7-2725-675e-a1b0-281729035ea6", + "descriptor": "msa.MTA3ZTA4YzctMjcyNS03NzVlLWExYjAtMjgxNzI5MDM1ZWE2" + }, + "pushId": 4, + "date": "2022-07-17T09:13:10.0775053Z", + "url": "https://dev.azure.com/ttchong/_apis/git/repositories/98f0ce59-a912-43d5-96d2-bc0942a03f7b/pushes/4", + "_links": { + "self": { + "href": "https://dev.azure.com/ttchong/_apis/git/repositories/98f0ce59-a912-43d5-96d2-bc0942a03f7b/pushes/4" + }, + "repository": { + "href": "https://dev.azure.com/ttchong/068d2409-14eb-4d8a-88bf-c8a9e7f5b4e2/_apis/git/repositories/98f0ce59-a912-43d5-96d2-bc0942a03f7b" + }, + "commits": { + "href": "https://dev.azure.com/ttchong/_apis/git/repositories/98f0ce59-a912-43d5-96d2-bc0942a03f7b/pushes/4/commits" + }, + "pusher": { + "href": "https://spsprodsea2.vssps.visualstudio.com/Aa56cba4a-dc80-4dd2-91fa-6fe7047fea7c/_apis/Identities/107e08c7-2725-675e-a1b0-281729035ea6" + }, + "refs": { + "href": "https://dev.azure.com/ttchong/068d2409-14eb-4d8a-88bf-c8a9e7f5b4e2/_apis/git/repositories/98f0ce59-a912-43d5-96d2-bc0942a03f7b/refs/heads/main" + } + } + }, + "resourceVersion": "1.0", + "resourceContainers": { + "collection": { + "id": "ad9e1dcf-6055-4fc7-a146-5511ab5ab1e8", + "baseUrl": "https://dev.azure.com/ttchong/" + }, + "account": { + "id": "a56cba4a-dc80-4dd2-91fa-6fe7047fea7c", + "baseUrl": "https://dev.azure.com/ttchong/" + }, + "project": { + "id": "068d2409-14eb-4d8a-88bf-c8a9e7f5b4e2", + "baseUrl": "https://dev.azure.com/ttchong/" + } + }, + "createdDate": "2022-07-17T09:13:17.0920723Z" +} diff --git a/zerver/webhooks/azuredevops/fixtures/code_push__remove_branch.json b/zerver/webhooks/azuredevops/fixtures/code_push__remove_branch.json new file mode 100644 index 0000000000..6c155fbe50 --- /dev/null +++ b/zerver/webhooks/azuredevops/fixtures/code_push__remove_branch.json @@ -0,0 +1,90 @@ +{ + "subscriptionId": "eead0877-fb06-46e2-9ec1-5f852a6d0297", + "notificationId": 4, + "id": "91264257-1f51-46d3-bba3-5448d40a724a", + "eventType": "git.push", + "publisherId": "tfs", + "message": { + "text": "Yuro Itaki deleted test-zulip:dev\r\n(https://dev.azure.com/ttchong/test-zulip/_git/test-zulip/#version=GBdev)", + "html": "Yuro Itaki deleted test-zulip:dev", + "markdown": "Yuro Itaki deleted [test-zulip](https://dev.azure.com/ttchong/test-zulip/_git/test-zulip/):dev" + }, + "detailedMessage": { + "text": "Yuro Itaki deleted test-zulip:dev", + "html": "Yuro Itaki deleted test-zulip:dev", + "markdown": "Yuro Itaki deleted [test-zulip](https://dev.azure.com/ttchong/test-zulip/_git/test-zulip/):[dev](https://dev.azure.com/ttchong/test-zulip/_git/test-zulip/#version=GBdev)" + }, + "resource": { + "refUpdates": [ + { + "name": "refs/heads/dev", + "oldObjectId": "0929a3404b39f6e39076a640779b2c1c961e19b5", + "newObjectId": "0000000000000000000000000000000000000000" + } + ], + "repository": { + "id": "98f0ce59-a912-43d5-96d2-bc0942a03f7b", + "name": "test-zulip", + "url": "https://dev.azure.com/ttchong/_apis/git/repositories/98f0ce59-a912-43d5-96d2-bc0942a03f7b", + "project": { + "id": "068d2409-14eb-4d8a-88bf-c8a9e7f5b4e2", + "name": "test-zulip", + "url": "https://dev.azure.com/ttchong/_apis/projects/068d2409-14eb-4d8a-88bf-c8a9e7f5b4e2", + "state": "wellFormed", + "visibility": "unchanged", + "lastUpdateTime": "0001-01-01T00:00:00" + }, + "defaultBranch": "refs/heads/main", + "remoteUrl": "https://dev.azure.com/ttchong/test-zulip/_git/test-zulip" + }, + "pushedBy": { + "displayName": "Yuro Itaki", + "url": "https://spsprodsea2.vssps.visualstudio.com/Aa56cba4a-dc80-4dd2-91fa-6fe7047fea7c/_apis/Identities/107e08c7-2725-675e-a1b0-281729035ea6", + "_links": { + "avatar": { + "href": "https://dev.azure.com/ttchong/_apis/GraphProfile/MemberAvatars/msa.MTA3ZTA4YzctMjcyNS03NzVlLWExYjAtMjgxNzI5MDM1ZWE2" + } + }, + "id": "107e08c7-2725-675e-a1b0-281729035ea6", + "uniqueName": "yuroitaki@email.com", + "imageUrl": "https://dev.azure.com/ttchong/_api/_common/identityImage?id=107e08c7-2725-675e-a1b0-281729035ea6", + "descriptor": "msa.MTA3ZTA4YzctMjcyNS03NzVlLWExYjAtMjgxNzI5MDM1ZWE2" + }, + "pushId": 6, + "date": "2022-07-17T11:08:58.0728467Z", + "url": "https://dev.azure.com/ttchong/_apis/git/repositories/98f0ce59-a912-43d5-96d2-bc0942a03f7b/pushes/6", + "_links": { + "self": { + "href": "https://dev.azure.com/ttchong/_apis/git/repositories/98f0ce59-a912-43d5-96d2-bc0942a03f7b/pushes/6" + }, + "repository": { + "href": "https://dev.azure.com/ttchong/068d2409-14eb-4d8a-88bf-c8a9e7f5b4e2/_apis/git/repositories/98f0ce59-a912-43d5-96d2-bc0942a03f7b" + }, + "commits": { + "href": "https://dev.azure.com/ttchong/_apis/git/repositories/98f0ce59-a912-43d5-96d2-bc0942a03f7b/pushes/6/commits" + }, + "pusher": { + "href": "https://spsprodsea2.vssps.visualstudio.com/Aa56cba4a-dc80-4dd2-91fa-6fe7047fea7c/_apis/Identities/107e08c7-2725-675e-a1b0-281729035ea6" + }, + "refs": { + "href": "https://dev.azure.com/ttchong/068d2409-14eb-4d8a-88bf-c8a9e7f5b4e2/_apis/git/repositories/98f0ce59-a912-43d5-96d2-bc0942a03f7b/refs/heads/dev" + } + } + }, + "resourceVersion": "1.0", + "resourceContainers": { + "collection": { + "id": "ad9e1dcf-6055-4fc7-a146-5511ab5ab1e8", + "baseUrl": "https://dev.azure.com/ttchong/" + }, + "account": { + "id": "a56cba4a-dc80-4dd2-91fa-6fe7047fea7c", + "baseUrl": "https://dev.azure.com/ttchong/" + }, + "project": { + "id": "068d2409-14eb-4d8a-88bf-c8a9e7f5b4e2", + "baseUrl": "https://dev.azure.com/ttchong/" + } + }, + "createdDate": "2022-07-17T11:09:05.1538362Z" +} diff --git a/zerver/webhooks/azuredevops/tests.py b/zerver/webhooks/azuredevops/tests.py new file mode 100644 index 0000000000..2f532d47cf --- /dev/null +++ b/zerver/webhooks/azuredevops/tests.py @@ -0,0 +1,94 @@ +from unittest.mock import MagicMock, patch + +from zerver.lib.test_classes import WebhookTestCase +from zerver.lib.webhooks.git import COMMITS_LIMIT + + +class AzuredevopsHookTests(WebhookTestCase): + STREAM_NAME = "azure-devops" + URL_TEMPLATE = "/api/v1/external/azuredevops?&api_key={api_key}&stream={stream}" + WEBHOOK_DIR_NAME = "azuredevops" + + def test_push_event_message(self) -> None: + expected_topic = "test-zulip / main" + expected_message = "Yuro Itaki [pushed](https://dev.azure.com/ttchong/test-zulip/_git/test-zulip/branchCompare?baseVersion=GC51515957669f93c543df09f8f3e7f47c3613c879&targetVersion=GCb0ce2f2009c3c87dbefadf61d7eb2c0697a6f369&_a=files) 1 commit to branch main.\n\n* Modify readme ([b0ce2f2](https://dev.azure.com/ttchong/test-zulip/_git/test-zulip/commit/b0ce2f2009c3c87dbefadf61d7eb2c0697a6f369))" + self.check_webhook("code_push", expected_topic, expected_message) + + def test_push_event_message_filtered_by_branches(self) -> None: + self.url = self.build_webhook_url(branches="main,dev") + expected_topic = "test-zulip / main" + expected_message = "Yuro Itaki [pushed](https://dev.azure.com/ttchong/test-zulip/_git/test-zulip/branchCompare?baseVersion=GC51515957669f93c543df09f8f3e7f47c3613c879&targetVersion=GCb0ce2f2009c3c87dbefadf61d7eb2c0697a6f369&_a=files) 1 commit to branch main.\n\n* Modify readme ([b0ce2f2](https://dev.azure.com/ttchong/test-zulip/_git/test-zulip/commit/b0ce2f2009c3c87dbefadf61d7eb2c0697a6f369))" + self.check_webhook("code_push", expected_topic, expected_message) + + @patch("zerver.lib.webhooks.common.check_send_webhook_message") + def test_push_event_message_filtered_by_branches_ignore( + self, check_send_webhook_message_mock: MagicMock + ) -> None: + self.url = self.build_webhook_url(branches="development") + payload = self.get_body("code_push") + result = self.client_post(self.url, payload, content_type="application/json") + self.assertFalse(check_send_webhook_message_mock.called) + self.assert_json_success(result) + + def test_push_local_branch_without_commits(self) -> None: + expected_topic = "test-zulip / dev" + expected_message = "Yuro Itaki [pushed](https://dev.azure.com/ttchong/test-zulip/_git/test-zulip/branchCompare?baseVersion=GC0000000000000000000000000000000000000000&targetVersion=GC0929a3404b39f6e39076a640779b2c1c961e19b5&_a=files) the branch dev." + self.check_webhook( + "code_push__local_branch_without_commits", expected_topic, expected_message + ) + + def test_push_multiple_committers(self) -> None: + expected_topic = "test-zulip / main" + expected_message = "Yuro Itaki [pushed](https://dev.azure.com/ttchong/test-zulip/_git/test-zulip/branchCompare?baseVersion=GCcc21b940719cc372b364d932eb39e528b0ec2a91&targetVersion=GC0929a3404b39f6e39076a640779b2c1c961e19b5&_a=files) 2 commits to branch main. Commits by Itachi Sensei (1) and Yuro Itaki (1).\n\n* Add reply ([0929a34](https://dev.azure.com/ttchong/test-zulip/_git/test-zulip/commit/0929a3404b39f6e39076a640779b2c1c961e19b5))\n* Add how are you ([819ce8d](https://dev.azure.com/ttchong/test-zulip/_git/test-zulip/commit/819ce8de51bedfc250c202edcaee0ce8dc70bf3b))" + self.check_webhook("code_push__multiple_committers", expected_topic, expected_message) + + def test_push_multiple_committers_with_others(self) -> None: + expected_topic = "test-zulip / main" + commits_info = "* Add how are you ([819ce8d](https://dev.azure.com/ttchong/test-zulip/_git/test-zulip/commit/819ce8de51bedfc250c202edcaee0ce8dc70bf3b))\n" + expected_message = f"Yuro Itaki [pushed](https://dev.azure.com/ttchong/test-zulip/_git/test-zulip/branchCompare?baseVersion=GCcc21b940719cc372b364d932eb39e528b0ec2a91&targetVersion=GC0929a3404b39f6e39076a640779b2c1c961e19b5&_a=files) 6 commits to branch main. Commits by Itachi Sensei (2), Yuro Itaki (2), Jonas Nielsen (1) and others (1).\n\n* Add reply ([0929a34](https://dev.azure.com/ttchong/test-zulip/_git/test-zulip/commit/0929a3404b39f6e39076a640779b2c1c961e19b5))\n{commits_info * 4}* Add reply ([0929a34](https://dev.azure.com/ttchong/test-zulip/_git/test-zulip/commit/0929a3404b39f6e39076a640779b2c1c961e19b5))" + self.check_webhook( + "code_push__multiple_committers_with_others", expected_topic, expected_message + ) + + def test_push_commits_more_than_limit(self) -> None: + expected_topic = "test-zulip / main" + commits_info = "* Modify readme ([b0ce2f2](https://dev.azure.com/ttchong/test-zulip/_git/test-zulip/commit/b0ce2f2009c3c87dbefadf61d7eb2c0697a6f369))\n" + expected_message = f"Yuro Itaki [pushed](https://dev.azure.com/ttchong/test-zulip/_git/test-zulip/branchCompare?baseVersion=GC51515957669f93c543df09f8f3e7f47c3613c879&targetVersion=GCb0ce2f2009c3c87dbefadf61d7eb2c0697a6f369&_a=files) 50 commits to branch main.\n\n{commits_info * COMMITS_LIMIT}[and {50 - COMMITS_LIMIT} more commit(s)]" + self.check_webhook("code_push__commits_more_than_limit", expected_topic, expected_message) + + def test_push_remove_branch(self) -> None: + expected_topic = "test-zulip / dev" + expected_message = "Yuro Itaki [pushed](https://dev.azure.com/ttchong/test-zulip/_git/test-zulip/branchCompare?baseVersion=GC0929a3404b39f6e39076a640779b2c1c961e19b5&targetVersion=GC0000000000000000000000000000000000000000&_a=files) the branch dev." + self.check_webhook("code_push__remove_branch", expected_topic, expected_message) + + def test_pull_request_opened(self) -> None: + expected_topic = "test-zulip / PR #1 Add PR request" + expected_message = "Yuro Itaki created [PR #1 Add PR request](https://dev.azure.com/ttchong/test-zulip/_git/test-zulip/pullrequest/1) from `dev` to `main`:\n\n~~~ quote\nAdd PR request\n~~~" + self.check_webhook("code_pull_request__opened", expected_topic, expected_message) + + def test_pull_request_opened_without_description(self) -> None: + expected_topic = "test-zulip / PR #2 Raised 2nd PR!" + expected_message = "Yuro Itaki created [PR #2 Raised 2nd PR!](https://dev.azure.com/ttchong/test-zulip/_git/test-zulip/pullrequest/2) from `stg` to `main`." + self.check_webhook( + "code_pull_request__opened_without_description", expected_topic, expected_message + ) + + def test_pull_request_merged(self) -> None: + expected_topic = "test-zulip / PR #1 Add PR request" + expected_message = "Yuro Itaki merged [PR #1 Add PR request](https://dev.azure.com/ttchong/test-zulip/_git/test-zulip/pullrequest/1)." + self.check_webhook("code_pull_request__merged", expected_topic, expected_message) + + @patch("zerver.lib.webhooks.common.check_send_webhook_message") + def test_pull_request_merge_attempted_ignore( + self, check_send_webhook_message_mock: MagicMock + ) -> None: + self.url = self.build_webhook_url() + payload = self.get_body("code_pull_request__merge_attempted") + result = self.client_post(self.url, payload, content_type="application/json") + self.assertFalse(check_send_webhook_message_mock.called) + self.assert_json_success(result) + + def test_pull_request_updated(self) -> None: + expected_topic = "test-zulip / PR #2 Raised 2nd PR!" + expected_message = "Yuro Itaki updated [PR #2 Raised 2nd PR!](https://dev.azure.com/ttchong/test-zulip/_git/test-zulip/pullrequest/2)\n\n~~~ quote\nYuro Itaki updated the source branch of [pull request 2](https://dev.azure.com/ttchong/test-zulip/_git/test-zulip/pullrequest/2) (Raised 2nd PR!) in [test-zulip](https://dev.azure.com/ttchong/test-zulip/_git/test-zulip/)\r\nRaised 2nd PR!\r\n\n~~~" + self.check_webhook("code_pull_request__updated", expected_topic, expected_message) diff --git a/zerver/webhooks/azuredevops/view.py b/zerver/webhooks/azuredevops/view.py new file mode 100644 index 0000000000..fd708331ad --- /dev/null +++ b/zerver/webhooks/azuredevops/view.py @@ -0,0 +1,182 @@ +from typing import Callable, Dict, Optional + +from django.http import HttpRequest, HttpResponse + +from zerver.decorator import webhook_view +from zerver.lib.exceptions import UnsupportedWebhookEventType +from zerver.lib.request import REQ, has_request_variables +from zerver.lib.response import json_success +from zerver.lib.validator import WildValue, check_int, check_string, to_wild_value +from zerver.lib.webhooks.common import check_send_webhook_message +from zerver.lib.webhooks.git import ( + TOPIC_WITH_BRANCH_TEMPLATE, + TOPIC_WITH_PR_OR_ISSUE_INFO_TEMPLATE, + get_pull_request_event_message, + get_push_commits_event_message, +) +from zerver.models import UserProfile + + +def get_code_pull_request_updated_body(payload: WildValue) -> str: + return get_pull_request_event_message( + get_code_pull_request_user_name(payload), + "updated", + get_code_pull_request_url(payload), + get_code_pull_request_id(payload), + message=payload["detailedMessage"]["markdown"].tame(check_string), + title=get_code_pull_request_title(payload), + ) + + +def get_code_pull_request_merged_body(payload: WildValue) -> str: + return get_pull_request_event_message( + get_code_pull_request_user_name(payload), + "merged", + get_code_pull_request_url(payload), + get_code_pull_request_id(payload), + title=get_code_pull_request_title(payload), + ) + + +def get_code_pull_request_opened_body(payload: WildValue) -> str: + if payload["resource"].get("description"): + description = payload["resource"]["description"].tame(check_string) + else: + description = None + return get_pull_request_event_message( + get_code_pull_request_user_name(payload), + "created", + get_code_pull_request_url(payload), + get_code_pull_request_id(payload), + payload["resource"]["sourceRefName"].tame(check_string).replace("refs/heads/", ""), + payload["resource"]["targetRefName"].tame(check_string).replace("refs/heads/", ""), + description, + title=get_code_pull_request_title(payload), + ) + + +def get_code_push_commits_body(payload: WildValue) -> str: + compare_url = "{}/branchCompare?baseVersion=GC{}&targetVersion=GC{}&_a=files".format( + get_code_repository_url(payload), + payload["resource"]["refUpdates"][0]["oldObjectId"].tame(check_string), + payload["resource"]["refUpdates"][0]["newObjectId"].tame(check_string), + ) + commits_data = [] + if payload["resource"].get("commits"): + for commit in payload["resource"]["commits"]: + commits_data.append( + { + "name": commit["author"]["name"].tame(check_string), + "sha": commit["commitId"].tame(check_string), + "url": "{}/commit/{}".format( + get_code_repository_url(payload), commit["commitId"].tame(check_string) + ), + "message": commit["comment"].tame(check_string), + } + ) + return get_push_commits_event_message( + get_code_push_user_name(payload), + compare_url, + get_code_push_branch_name(payload), + commits_data, + ) + + +def get_code_push_user_name(payload: WildValue) -> str: + return payload["resource"]["pushedBy"]["displayName"].tame(check_string) + + +def get_code_push_branch_name(payload: WildValue) -> str: + return ( + payload["resource"]["refUpdates"][0]["name"].tame(check_string).replace("refs/heads/", "") + ) + + +def get_code_repository_name(payload: WildValue) -> str: + return payload["resource"]["repository"]["name"].tame(check_string) + + +def get_code_repository_url(payload: WildValue) -> str: + return payload["resource"]["repository"]["remoteUrl"].tame(check_string) + + +def get_code_pull_request_id(payload: WildValue) -> int: + return payload["resource"]["pullRequestId"].tame(check_int) + + +def get_code_pull_request_title(payload: WildValue) -> str: + return payload["resource"]["title"].tame(check_string) + + +def get_code_pull_request_url(payload: WildValue) -> str: + return payload["resource"]["_links"]["web"]["href"].tame(check_string) + + +def get_code_pull_request_user_name(payload: WildValue) -> str: + return payload["resource"]["createdBy"]["displayName"].tame(check_string) + + +def get_topic_based_on_event(payload: WildValue, event: str) -> str: + if event == "git.push": + return TOPIC_WITH_BRANCH_TEMPLATE.format( + repo=get_code_repository_name(payload), branch=get_code_push_branch_name(payload) + ) + elif "pullrequest" in event: + return TOPIC_WITH_PR_OR_ISSUE_INFO_TEMPLATE.format( + repo=get_code_repository_name(payload), + type="PR", + id=get_code_pull_request_id(payload), + title=get_code_pull_request_title(payload), + ) + return get_code_repository_name(payload) # nocoverage + + +def get_event_name(payload: WildValue, branches: Optional[str]) -> Optional[str]: + event_name = payload["eventType"].tame(check_string) + if event_name == "git.push": + if branches is not None: + branch = get_code_push_branch_name(payload) + if branches.find(branch) == -1: + return None + if event_name == "git.pullrequest.merged": + status = payload["resource"]["status"].tame(check_string) + merge_status = payload["resource"]["mergeStatus"].tame(check_string) + # azure devops sends webhook messages when a merge is attempted, i.e. there is a merge conflict + # after a PR is created, or when there is no conflict when PR is updated + # we're only interested in the case when the PR is merged successfully + if status != "completed" or merge_status != "succeeded": + return None + if event_name in EVENT_FUNCTION_MAPPER: + return event_name + raise UnsupportedWebhookEventType(event_name) + + +EVENT_FUNCTION_MAPPER: Dict[str, Callable[[WildValue], str]] = { + "git.push": get_code_push_commits_body, + "git.pullrequest.created": get_code_pull_request_opened_body, + "git.pullrequest.merged": get_code_pull_request_merged_body, + "git.pullrequest.updated": get_code_pull_request_updated_body, +} + +ALL_EVENT_TYPES = list(EVENT_FUNCTION_MAPPER.keys()) + + +@webhook_view("AzureDevOps", all_event_types=ALL_EVENT_TYPES) +@has_request_variables +def api_azuredevops_webhook( + request: HttpRequest, + user_profile: UserProfile, + payload: WildValue = REQ(argument_type="body", converter=to_wild_value), + branches: Optional[str] = REQ(default=None), +) -> HttpResponse: + event = get_event_name(payload, branches) + if event is None: + return json_success(request) + + topic = get_topic_based_on_event(payload, event) + + body_function = EVENT_FUNCTION_MAPPER[event] + body = body_function(payload) + + check_send_webhook_message(request, user_profile, topic, body) + return json_success(request)