From a8fdd6ef87660db98593635a4ecbdb4a88088265 Mon Sep 17 00:00:00 2001 From: Davide Bianchi <10374360+davidebianchi@users.noreply.github.com> Date: Tue, 26 Nov 2024 12:53:22 +0100 Subject: [PATCH] feat: add jira event support --- docs/sources/20_jira.md | 184 +++++++++++++++++++++++++++++++- internal/sources/jira/events.go | 68 ++++++++++-- 2 files changed, 242 insertions(+), 10 deletions(-) diff --git a/docs/sources/20_jira.md b/docs/sources/20_jira.md index 702db9d..210c102 100644 --- a/docs/sources/20_jira.md +++ b/docs/sources/20_jira.md @@ -57,17 +57,44 @@ For the issue events, it is possible to set a filter to receive only the events Example of a filter is `project = "My Project"`. -- issue created: `jira:issue_created`: this event will upsert data on the sink; -- issue updated: `jira:issue_updated`: this event will upsert data on the sink; -- issue deleted: `jira:issue_deleted`: this event will delete data on the sink. +| Event | Event Type | Example Payload | Operation | +|-----------------------|----------------------------|-----------------------------------------------|-----------| +| issue created | `jira:issue_created` | [link](#issue-event-payload) | Write | +| issue updated | `jira:issue_updated` | [link](#issue-event-payload) | Write | +| issue deleted | `jira:issue_deleted` | [link](#issue-event-payload) | Delete | +| issue link created | `issuelink_created` | [link](#issue-link-event-payload) | Write | +| issue link deleted | `issuelink_deleted` | [link](#issue-link-event-payload) | Delete | +| project created | `project_created` | [link](#project-event-payload) | Write | +| project updated | `project_updated` | [link](#project-event-payload) | Write | +| project deleted | `project_deleted` | [link](#project-event-payload) | Delete | +| project soft deleted | `project_soft_deleted` | [link](#project-event-payload) | Delete | +| project restore | `project_restored_deleted` | [link](#project-event-payload) | Write | +| version created | `jira:version_created` | [link](#project-version-event-payload) | Write | +| version updated | `jira:version_updated` | [link](#project-version-event-payload) | Write | +| version deleted | `jira:version_deleted` | [link](#project-version-event-payload) | Deleted | +| version merged | `jira:version_deleted` | [link](#project-version-merged-event-payload) | Deleted | +| version released | `jira:version_released` | [link](#project-version-event-payload) | Write | +| version unreleased | `jira:version_unreleased` | [link](#project-version-event-payload) | Write | + + +The operation will be used by the sink which supports the upsert of the data to decide if +the event should be inserted/updated or deleted. :::info The **event ID** used in the webhook payload is extracted from the `issue.id` field. ::: +#### Known Issues + +- The archived version is not correctly handled by the Webhook, so when archiving a version the WebHook is correctly +triggered but the `archived` field is always `false`. [Here the opened issue](https://jira.atlassian.com/browse/JRASERVER-71000). + #### Issue Event payload -The issue event payload is something like: +The following is an example of an issue event payload. + +
+Issue Event Payload ```json { @@ -154,3 +181,152 @@ The issue event payload is something like: "webhookEvent": "jira:issue_updated" } ``` + +
+ +#### Issue link Event payload + +The following is an example of an issue link event payload. + +
+Issue link Event Payload + +```json +{ + "timestamp": 1525698237764, + "id": 876, + "sourceIssueId": 222, + "destinationIssueId": 333, + "issueLinkType": { + "id": 111, + "name": "Link name", + "outwardName": "executes Test", + "inwardName": "is executed by", + "isSubTaskLinkType": false, + "isSystemLinkType": false, + }, + "systemLink": false, +} +``` + +
+ +#### Project Event payload + +The following is an example of a project event payload. + +
+Project Event Payload + +```json +{ + "timestamp": 1525698237764, + "webhookEvent": "project_created", + "project": { + "self": "https://jira.atlassian.com/rest/api/2/project/12345", + "id": 12345, + "key": "ACTP", + "name": "Agent Connector Test Project", + "avatarUrls": { + "16x16": "https://jira.atlassian.com/secure/useravatar?size=small&avatarId=10605", + "48x48": "https://jira.atlassian.com/secure/useravatar?avatarId=10605" + }, + "projectCategory": { + "self": "https://jira.atlassian.com/rest/api/2/projectCategory/65432", + "id": 65432, + "name": "category name", + "description": "" + }, + "projectLead": { + "self": "https://jira.atlassian.com/rest/api/2/user?accountId=some-id", + "accountId": "some-id", + "avatarUrls": { + "16x16": "https://jira.atlassian.com/secure/useravatar?size=small&avatarId=10605", + "48x48": "https://jira.atlassian.com/secure/useravatar?avatarId=10605" + }, + "displayName": "The Lead Name", + "active": true, + "timeZone": "Europe/Rome", + "accountType": "..." + }, + "assigneeType": "admin.assignee.type.unassigned" + } +} +``` + +
+ +#### Project Version Event payload + +The following is an example of a project version event payload. + +
+Project Version Event Payload + +```json +{ + "timestamp": 1732615465165, + "webhookEvent": "jira:version_created", + "version": { + "self": "https://jira.atlassian.com/rest/api/2/version/65456", + "id": "65456", + "description": "This is the description", + "name": "v1", + "archived": false, + "released": false, + "startDate": "2024-11-26", + "releaseDate": "2024-11-30", + "overdue": false, + "userStartDate": "26/Nov/24", + "userReleaseDate": "30/Nov/24", + "projectId": 12345 + } +} +``` + +
+ +##### Project Version Merged Event Payload + +The `jira:version_deleted` event is used to also notify that a version has been merged into another one. +In this case, a flag `mergedTo` is added to the payload with the information of the version where the version has been merged. + +
+Project Version Merged Event Payload + +```json +{ + "timestamp": 1732615465165, + "webhookEvent": "jira:version_deleted", + "version": { + "self": "https://jira.atlassian.com/rest/api/2/version/65456", + "id": "65456", + "description": "This is the description", + "name": "v1-rc.0", + "archived": false, + "released": false, + "startDate": "2024-11-26", + "releaseDate": "2024-11-30", + "overdue": false, + "userStartDate": "26/Nov/24", + "userReleaseDate": "30/Nov/24", + "projectId": 12345 + }, + "mergedTo": { + "self": "https://jira.atlassian.com/rest/api/2/version/99991", + "id": "99991", + "description": "This is the version description", + "name": "v1", + "archived": false, + "released": false, + "startDate": "2024-11-26", + "releaseDate": "2024-11-30", + "overdue": false, + "userStartDate": "26/Nov/24", + "userReleaseDate": "30/Nov/24", + "projectId": 12345 + } +} +``` + +
diff --git a/internal/sources/jira/events.go b/internal/sources/jira/events.go index 8772d16..5f64243 100644 --- a/internal/sources/jira/events.go +++ b/internal/sources/jira/events.go @@ -21,14 +21,30 @@ import ( ) const ( - issueCreated = "jira:issue_created" - issueUpdated = "jira:issue_updated" - issueDeleted = "jira:issue_deleted" + // issue events + issueCreated = "jira:issue_created" + issueUpdated = "jira:issue_updated" + issueDeleted = "jira:issue_deleted" + // issuelink events issueLinkCreated = "issuelink_created" issueLinkDeleted = "issuelink_deleted" + // project events + projectCreated = "project_created" + projectUpdated = "project_updated" + projectDeleted = "project_deleted" + projectSoftDeleted = "project_soft_deleted" + projectRestoredDeleted = "project_restored_deleted" + // version events + versionReleased = "jira:version_released" + versionUnreleased = "jira:version_unreleased" + versionCreated = "jira:version_created" + versionUpdated = "jira:version_updated" + versionDeleted = "jira:version_deleted" issueEventIDPath = "issue.id" - issuelinkEventIDPath = "issueLink.id" + issueLinkEventIDPath = "issueLink.id" + projectEventIDPath = "project.id" + versionEventIDPath = "version.id" ) var DefaultSupportedEvents = webhook.Events{ @@ -47,11 +63,51 @@ var DefaultSupportedEvents = webhook.Events{ }, issueLinkCreated: { Operation: entities.Write, - FieldID: issuelinkEventIDPath, + FieldID: issueLinkEventIDPath, }, issueLinkDeleted: { Operation: entities.Delete, - FieldID: issuelinkEventIDPath, + FieldID: issueLinkEventIDPath, + }, + projectCreated: { + Operation: entities.Write, + FieldID: projectEventIDPath, + }, + projectUpdated: { + Operation: entities.Write, + FieldID: projectEventIDPath, + }, + projectDeleted: { + Operation: entities.Delete, + FieldID: projectEventIDPath, + }, + projectSoftDeleted: { + Operation: entities.Delete, + FieldID: projectEventIDPath, + }, + projectRestoredDeleted: { + Operation: entities.Write, + FieldID: projectEventIDPath, + }, + versionReleased: { + Operation: entities.Write, + FieldID: versionEventIDPath, + }, + versionUnreleased: { + Operation: entities.Write, + FieldID: versionEventIDPath, + }, + versionCreated: { + Operation: entities.Write, + FieldID: versionEventIDPath, + }, + versionUpdated: { + Operation: entities.Write, + FieldID: versionEventIDPath, + }, + versionDeleted: { + Operation: entities.Delete, + FieldID: versionEventIDPath, }, }, EventTypeFieldPath: webhookEventPath,