当前位置:首页 » 《随便一记》 » 正文

Jira Webhook配置与使用

25 人参与  2024年09月19日 10:01  分类 : 《随便一记》  评论

点击全文阅读


Jira Webhook配置与使用

什么是Jira Webhook(网络钩子)创建Webhook使用Webhook通过Webhook创建时设置的事件来触发通过工作流来触发Webhook 总结一下

什么是Jira Webhook(网络钩子)

Webhook是一种回调接口,一般用在由事件驱动的系统中。那么Jira内置的功能是支持自定义Webhook的,然后在特定的事件或者工作流执行中调用自己定义的Webhook,来实现与第三方系统的通信,并且Webhook中提供了几乎与Issue相关的所有字段信息。

创建Webhook

使用系统管员登录,进入系统设置页面,点击左侧“网络钩子菜单”,进入网络钩子管理页面,点击右上角“创建网络钩子”按钮,添加一个新的Webhook。
在这里插入图片描述
在这里,我们使用一个在线工具来测试打印出webhook推送给第三方系统的数据,UU在线工具https://uutool.cn/mock/。
名称:自己取个名字就好了
状态:可以启用或禁用掉Webhook,因为在实际工作中Webhook可以在很多流程里面去触发,所以这里可以禁用掉就不用去修改每个流程了
URL:这里填写的就是第三方系统的接口地址,我这里填写的是UU在线工具的临时接口地址,这个接口是一个挡板能把所有的请求信息打印出来。
事件:这里我们定义在创建和修改Issue时去触发这个Webhook的执行,注意这里也可以不选任何的事件,而是由工作流中我们去触发这个Webhook,事件的主体有Issue、项目、用户、备注还有敏捷相关的看板等等。注意这里选的事件类型与数据主体信息是相对应的,比如选Issue的事件,Raw里面的json数据就是issue相关的;如果选择的是用户事件,那么Raw里面在json主体就是用户信息
排除主体:有些事件发生时我们只需要少量的字段我们可以通过在URL的变量中携带而不必传输整个Raw数据,这时我们勾选排除主体就可以了。
在这里插入图片描述
在这里插入图片描述

使用Webhook

通过Webhook创建时设置的事件来触发

刚才我们定义的Webhook是在Issue创建和修改的时候触发的,那么我们现在创建一个Issue观察一下Webhook推送的数据。
创建Issue:
在这里插入图片描述
查看推送数据:

请求头

请求头,可以看到是通用HttpClient的库发送的请求{  "Content-Type": "application/json; charset=UTF-8",  "User-Agent": "Atlassian HttpClient 3.0.4 / JIRA-9.13.1 (9130002) / Default",  "Connection": "Keep-Alive",  "Host": "mock.uutool.cn",  "Content-Length": "7137",  "Via": "1.1 localhost (Apache-HttpClient/4.5.14 (cache))",  "Accept": "*/*"}

数据结构
Issue的Webhook数据结构中包括了用户、项目、报告人、Issue字段等的信息,如果在第三方系统需要其它信息都可以通过自定义字段去放置。

数据位置和结构,可以看到Webhook在GET参数中带了用户名,具体信息在请求体中通过JSON结构传输的。GET参数:{  "user_id": "admin",  "user_key": "JIRAUSER10000"}                                POST参数:[]                                Raw:{    "timestamp": 1725868650247,    "webhookEvent": "jira:issue_created",    "issue_event_type_name": "issue_created",    "user": {        "self": "http://192.168.1.100:8080/rest/api/2/user?username=admin",        "name": "admin",        "key": "JIRAUSER10000",        "emailAddress": "admin@abdxww.co",        "avatarUrls": {            "48x48": "http://192.168.1.100:8080/secure/useravatar?avatarId=10351",            "24x24": "http://192.168.1.100:8080/secure/useravatar?size=small&avatarId=10351",            "16x16": "http://192.168.1.100:8080/secure/useravatar?size=xsmall&avatarId=10351",            "32x32": "http://192.168.1.100:8080/secure/useravatar?size=medium&avatarId=10351"        },        "displayName": "admin",        "active": true,        "timeZone": "Asia/Shanghai"    },    "issue": {        "id": "11104",        "self": "http://192.168.1.100:8080/rest/api/2/issue/11104",        "key": "TEST-17",        "fields": {            "issuetype": {                "self": "http://192.168.1.100:8080/rest/api/2/issuetype/10006",                "id": "10006",                "description": "",                "iconUrl": "http://192.168.1.100:8080/secure/viewavatar?size=xsmall&avatarId=10303&avatarType=issuetype",                "name": "故障",                "subtask": false,                "avatarId": 10303            },            "timespent": null,            "project": {                "self": "http://192.168.1.100:8080/rest/api/2/project/10200",                "id": "10200",                "key": "TEST",                "name": "TEST1",                "projectTypeKey": "software",                "avatarUrls": {                    "48x48": "http://192.168.1.100:8080/secure/projectavatar?avatarId=10324",                    "24x24": "http://192.168.1.100:8080/secure/projectavatar?size=small&avatarId=10324",                    "16x16": "http://192.168.1.100:8080/secure/projectavatar?size=xsmall&avatarId=10324",                    "32x32": "http://192.168.1.100:8080/secure/projectavatar?size=medium&avatarId=10324"                }            },            "fixVersions": [],            "customfield_10110": null,            "aggregatetimespent": null,            "resolution": null,            "customfield_10104": null,            "customfield_10108": "0|i005h3:",            "customfield_10109": null,            "resolutiondate": null,            "workratio": -1,            "lastViewed": null,            "watches": {                "self": "http://192.168.1.100:8080/rest/api/2/issue/TEST-17/watchers",                "watchCount": 0,                "isWatching": false            },            "created": "2024-09-09T15:57:30.142+0800",            "priority": {                "self": "http://192.168.1.100:8080/rest/api/2/priority/3",                "iconUrl": "http://192.168.1.100:8080/images/icons/priorities/medium.svg",                "name": "Medium",                "id": "3"            },            "customfield_10100": null,            "customfield_10101": null,            "customfield_10102": null,            "customfield_10300": null,            "labels": [],            "customfield_10103": null,            "timeestimate": null,            "aggregatetimeoriginalestimate": null,            "versions": [],            "issuelinks": [],            "assignee": null,            "updated": "2024-09-09T15:57:30.142+0800",            "status": {                "self": "http://192.168.1.100:8080/rest/api/2/status/10000",                "description": "",                "iconUrl": "http://192.168.1.100:8080/",                "name": "待办",                "id": "10000",                "statusCategory": {                    "self": "http://192.168.1.100:8080/rest/api/2/statuscategory/2",                    "id": 2,                    "key": "new",                    "colorName": "default",                    "name": "待办"                }            },            "components": [],            "timeoriginalestimate": null,            "description": null,            "timetracking": {},            "archiveddate": null,            "customfield_10401": null,            "customfield_10203": null,            "attachment": [],            "aggregatetimeestimate": null,            "summary": "test webhook1",            "creator": {                "self": "http://192.168.1.100:8080/rest/api/2/user?username=admin",                "name": "admin",                "key": "JIRAUSER10000",                "emailAddress": "admin@abdxww.co",                "avatarUrls": {                    "48x48": "http://192.168.1.100:8080/secure/useravatar?avatarId=10351",                    "24x24": "http://192.168.1.100:8080/secure/useravatar?size=small&avatarId=10351",                    "16x16": "http://192.168.1.100:8080/secure/useravatar?size=xsmall&avatarId=10351",                    "32x32": "http://192.168.1.100:8080/secure/useravatar?size=medium&avatarId=10351"                },                "displayName": "admin",                "active": true,                "timeZone": "Asia/Shanghai"            },            "subtasks": [],            "reporter": {                "self": "http://192.168.1.100:8080/rest/api/2/user?username=admin",                "name": "admin",                "key": "JIRAUSER10000",                "emailAddress": "admin@abdxww.co",                "avatarUrls": {                    "48x48": "http://192.168.1.100:8080/secure/useravatar?avatarId=10351",                    "24x24": "http://192.168.1.100:8080/secure/useravatar?size=small&avatarId=10351",                    "16x16": "http://192.168.1.100:8080/secure/useravatar?size=xsmall&avatarId=10351",                    "32x32": "http://192.168.1.100:8080/secure/useravatar?size=medium&avatarId=10351"                },                "displayName": "admin",                "active": true,                "timeZone": "Asia/Shanghai"            },            "customfield_10000": "{summaryBean=com.atlassian.jira.plugin.devstatus.rest.SummaryBean@7ae0bb11[summary={pullrequest=com.atlassian.jira.plugin.devstatus.rest.SummaryItemBean@f3a1dea[byInstanceType={},overall=PullRequestOverallBean{stateCount=0, state='OPEN', details=PullRequestOverallDetails{openCount=0, mergedCount=0, declinedCount=0}}], build=com.atlassian.jira.plugin.devstatus.rest.SummaryItemBean@4a6368d[byInstanceType={},overall=com.atlassian.jira.plugin.devstatus.summary.beans.BuildOverallBean@5b2caebe[failedBuildCount=0,successfulBuildCount=0,unknownBuildCount=0,count=0,lastUpdated=<null>,lastUpdatedTimestamp=<null>]], review=com.atlassian.jira.plugin.devstatus.rest.SummaryItemBean@4a735e4b[byInstanceType={},overall=com.atlassian.jira.plugin.devstatus.summary.beans.ReviewsOverallBean@38f61afc[dueDate=<null>,overDue=false,state=<null>,stateCount=0,count=0,lastUpdated=<null>,lastUpdatedTimestamp=<null>]], deployment-environment=com.atlassian.jira.plugin.devstatus.rest.SummaryItemBean@dd14131[byInstanceType={},overall=com.atlassian.jira.plugin.devstatus.summary.beans.DeploymentOverallBean@33b6576b[showProjects=false,successfulCount=0,topEnvironments=[],count=0,lastUpdated=<null>,lastUpdatedTimestamp=<null>]], repository=com.atlassian.jira.plugin.devstatus.rest.SummaryItemBean@63e7c650[byInstanceType={},overall=com.atlassian.jira.plugin.devstatus.summary.beans.CommitOverallBean@6bce112a[count=0,lastUpdated=<null>,lastUpdatedTimestamp=<null>]], branch=com.atlassian.jira.plugin.devstatus.rest.SummaryItemBean@6c110dab[byInstanceType={},overall=com.atlassian.jira.plugin.devstatus.summary.beans.BranchOverallBean@6d1d024d[count=0,lastUpdated=<null>,lastUpdatedTimestamp=<null>]]},configErrors=[],errors=[]], devSummaryJson={\"cachedValue\":{\"errors\":[],\"configErrors\":[],\"summary\":{\"pullrequest\":{\"overall\":{\"count\":0,\"lastUpdated\":null,\"stateCount\":0,\"state\":\"OPEN\",\"details\":{\"openCount\":0,\"mergedCount\":0,\"declinedCount\":0,\"total\":0},\"open\":true},\"byInstanceType\":{}},\"build\":{\"overall\":{\"count\":0,\"lastUpdated\":null,\"failedBuildCount\":0,\"successfulBuildCount\":0,\"unknownBuildCount\":0},\"byInstanceType\":{}},\"review\":{\"overall\":{\"count\":0,\"lastUpdated\":null,\"stateCount\":0,\"state\":null,\"dueDate\":null,\"overDue\":false,\"completed\":false},\"byInstanceType\":{}},\"deployment-environment\":{\"overall\":{\"count\":0,\"lastUpdated\":null,\"topEnvironments\":[],\"showProjects\":false,\"successfulCount\":0},\"byInstanceType\":{}},\"repository\":{\"overall\":{\"count\":0,\"lastUpdated\":null},\"byInstanceType\":{}},\"branch\":{\"overall\":{\"count\":0,\"lastUpdated\":null},\"byInstanceType\":{}}}},\"isStale\":false}}",            "aggregateprogress": {                "progress": 0,                "total": 0            },            "customfield_10200": null,            "customfield_10201": null,            "customfield_10400": null,            "customfield_10202": null,            "environment": null,            "duedate": null,            "progress": {                "progress": 0,                "total": 0            },            "comment": {                "comments": [],                "maxResults": 0,                "total": 0,                "startAt": 0            },            "votes": {                "self": "http://192.168.1.100:8080/rest/api/2/issue/TEST-17/votes",                "votes": 0,                "hasVoted": false            },            "worklog": {                "startAt": 0,                "maxResults": 20,                "total": 0,                "worklogs": []            },            "archivedby": null        }    }}             

通过工作流来触发Webhook

我们创建的Webhook,不勾选任何事件,然后在流程中去触发。
在这里插入图片描述
修改项目D35问题类型是故障的工作流,在完成的转换中添加后处理功能,去触发刚才定义的Webhook。
点击后处理功能:
在这里插入图片描述
点击添加后处理功能:
在这里插入图片描述
点击引发一个webhook,选择刚才定义的webhook。
在这里插入图片描述
在D35-1这个Issue中点击完成。
在这里插入图片描述
我们可以看到通过流程触发的webhook的数据主体还是Issue,多了流程状态的数据。

GET和POST外的其他方法见Raw数据:GET参数:{  "user_id": "admin",  "user_key": "JIRAUSER10000"}                                POST参数:[]                                Raw:{    "transition": {        "workflowId": 11105,        "workflowName": "Software Simplified Workflow for Project D35",        "transitionId": 31,        "transitionName": "Done",        "from_status": "To Do",        "to_status": "Done"    },    "comment": "",    "user": {        "self": "http://192.168.1.100:8080/rest/api/2/user?username=admin",        "name": "admin",        "key": "JIRAUSER10000",        "emailAddress": "admin@abdxww.co"        "avatarUrls": {            "48x48": "http://192.168.1.100:8080/secure/useravatar?avatarId=10351",            "24x24": "http://192.168.1.100:8080/secure/useravatar?size=small&avatarId=10351",            "16x16": "http://192.168.1.100:8080/secure/useravatar?size=xsmall&avatarId=10351",            "32x32": "http://192.168.1.100:8080/secure/useravatar?size=medium&avatarId=10351"        },        "displayName": "admin",        "active": true,        "timeZone": "Asia/Shanghai"    },    "issue": {        "id": "11105",        "self": "http://192.168.1.100:8080/rest/api/2/issue/11105",        "key": "D35-1",        "fields": {            "issuetype": {                "self": "http://192.168.1.100:8080/rest/api/2/issuetype/10006",                "id": "10006",                "description": "",                "iconUrl": "http://192.168.1.100:8080/secure/viewavatar?size=xsmall&avatarId=10303&avatarType=issuetype",                "name": "故障",                "subtask": false,                "avatarId": 10303            },            "timespent": null,            "project": {                "self": "http://192.168.1.100:8080/rest/api/2/project/10302",                "id": "10302",                "key": "D35",                "name": "D35",                "projectTypeKey": "software",                "avatarUrls": {                    "48x48": "http://192.168.1.100:8080/secure/projectavatar?avatarId=10324",                    "24x24": "http://192.168.1.100:8080/secure/projectavatar?size=small&avatarId=10324",                    "16x16": "http://192.168.1.100:8080/secure/projectavatar?size=xsmall&avatarId=10324",                    "32x32": "http://192.168.1.100:8080/secure/projectavatar?size=medium&avatarId=10324"                }            },            "fixVersions": [],            "customfield_10110": null,            "aggregatetimespent": null,            "resolution": null,            "customfield_10104": null,            "customfield_10108": "0|i005hb:",            "customfield_10109": null,            "resolutiondate": null,            "workratio": -1,            "lastViewed": "2024-09-09T16:45:38.601+0800",            "watches": {                "self": "http://192.168.1.100:8080/rest/api/2/issue/D35-1/watchers",                "watchCount": 1,                "isWatching": true            },            "created": "2024-09-09T16:35:50.000+0800",            "priority": {                "self": "http://192.168.1.100:8080/rest/api/2/priority/3",                "iconUrl": "http://192.168.1.100:8080/images/icons/priorities/medium.svg",                "name": "Medium",                "id": "3"            },            "customfield_10100": null,            "customfield_10101": null,            "customfield_10102": null,            "customfield_10300": null,            "labels": [],            "customfield_10103": null,            "timeestimate": null,            "aggregatetimeoriginalestimate": null,            "versions": [],            "issuelinks": [],            "assignee": null,            "updated": "2024-09-09T16:44:11.000+0800",            "status": {                "self": "http://192.168.1.100:8080/rest/api/2/status/10000",                "description": "",                "iconUrl": "http://192.168.1.100:8080/",                "name": "待办",                "id": "10000",                "statusCategory": {                    "self": "http://192.168.1.100:8080/rest/api/2/statuscategory/2",                    "id": 2,                    "key": "new",                    "colorName": "default",                    "name": "待办"                }            },            "components": [],            "timeoriginalestimate": null,            "description": null,            "timetracking": {},            "archiveddate": null,            "customfield_10401": null,            "customfield_10203": null,            "attachment": [],            "aggregatetimeestimate": null,            "summary": "bug1",            "creator": {                "self": "http://192.168.1.100:8080/rest/api/2/user?username=admin",                "name": "admin",                "key": "JIRAUSER10000",                "emailAddress": "admin@abdxww.co",                "avatarUrls": {                    "48x48": "http://192.168.1.100:8080/secure/useravatar?avatarId=10351",                    "24x24": "http://192.168.1.100:8080/secure/useravatar?size=small&avatarId=10351",                    "16x16": "http://192.168.1.100:8080/secure/useravatar?size=xsmall&avatarId=10351",                    "32x32": "http://192.168.1.100:8080/secure/useravatar?size=medium&avatarId=10351"                },                "displayName": "admin",                "active": true,                "timeZone": "Asia/Shanghai"            },            "subtasks": [],            "reporter": {                "self": "http://192.168.1.100:8080/rest/api/2/user?username=admin",                "name": "admin",                "key": "JIRAUSER10000",                "emailAddress": "admin@abdxww.co",                "avatarUrls": {                    "48x48": "http://192.168.1.100:8080/secure/useravatar?avatarId=10351",                    "24x24": "http://192.168.1.100:8080/secure/useravatar?size=small&avatarId=10351",                    "16x16": "http://192.168.1.100:8080/secure/useravatar?size=xsmall&avatarId=10351",                    "32x32": "http://192.168.1.100:8080/secure/useravatar?size=medium&avatarId=10351"                },                "displayName": "admin",                "active": true,                "timeZone": "Asia/Shanghai"            },            "customfield_10000": "{summaryBean=com.atlassian.jira.plugin.devstatus.rest.SummaryBean@46fa0a08[summary={pullrequest=com.atlassian.jira.plugin.devstatus.rest.SummaryItemBean@4c98c539[byInstanceType={},overall=PullRequestOverallBean{stateCount=0, state='OPEN', details=PullRequestOverallDetails{openCount=0, mergedCount=0, declinedCount=0}}], build=com.atlassian.jira.plugin.devstatus.rest.SummaryItemBean@734de769[byInstanceType={},overall=com.atlassian.jira.plugin.devstatus.summary.beans.BuildOverallBean@79f64534[failedBuildCount=0,successfulBuildCount=0,unknownBuildCount=0,count=0,lastUpdated=<null>,lastUpdatedTimestamp=<null>]], review=com.atlassian.jira.plugin.devstatus.rest.SummaryItemBean@780f02[byInstanceType={},overall=com.atlassian.jira.plugin.devstatus.summary.beans.ReviewsOverallBean@6d38812b[dueDate=<null>,overDue=false,state=<null>,stateCount=0,count=0,lastUpdated=<null>,lastUpdatedTimestamp=<null>]], deployment-environment=com.atlassian.jira.plugin.devstatus.rest.SummaryItemBean@71d2454a[byInstanceType={},overall=com.atlassian.jira.plugin.devstatus.summary.beans.DeploymentOverallBean@3a4671a1[showProjects=false,successfulCount=0,topEnvironments=[],count=0,lastUpdated=<null>,lastUpdatedTimestamp=<null>]], repository=com.atlassian.jira.plugin.devstatus.rest.SummaryItemBean@7a0669f4[byInstanceType={},overall=com.atlassian.jira.plugin.devstatus.summary.beans.CommitOverallBean@531e8e46[count=0,lastUpdated=<null>,lastUpdatedTimestamp=<null>]], branch=com.atlassian.jira.plugin.devstatus.rest.SummaryItemBean@3005697a[byInstanceType={},overall=com.atlassian.jira.plugin.devstatus.summary.beans.BranchOverallBean@39c7cda2[count=0,lastUpdated=<null>,lastUpdatedTimestamp=<null>]]},configErrors=[],errors=[]], devSummaryJson={\"cachedValue\":{\"errors\":[],\"configErrors\":[],\"summary\":{\"pullrequest\":{\"overall\":{\"count\":0,\"lastUpdated\":null,\"stateCount\":0,\"state\":\"OPEN\",\"details\":{\"openCount\":0,\"mergedCount\":0,\"declinedCount\":0,\"total\":0},\"open\":true},\"byInstanceType\":{}},\"build\":{\"overall\":{\"count\":0,\"lastUpdated\":null,\"failedBuildCount\":0,\"successfulBuildCount\":0,\"unknownBuildCount\":0},\"byInstanceType\":{}},\"review\":{\"overall\":{\"count\":0,\"lastUpdated\":null,\"stateCount\":0,\"state\":null,\"dueDate\":null,\"overDue\":false,\"completed\":false},\"byInstanceType\":{}},\"deployment-environment\":{\"overall\":{\"count\":0,\"lastUpdated\":null,\"topEnvironments\":[],\"showProjects\":false,\"successfulCount\":0},\"byInstanceType\":{}},\"repository\":{\"overall\":{\"count\":0,\"lastUpdated\":null},\"byInstanceType\":{}},\"branch\":{\"overall\":{\"count\":0,\"lastUpdated\":null},\"byInstanceType\":{}}}},\"isStale\":false}}",            "aggregateprogress": {                "progress": 0,                "total": 0            },            "customfield_10200": null,            "customfield_10201": null,            "customfield_10400": null,            "customfield_10202": null,            "environment": null,            "duedate": null,            "progress": {                "progress": 0,                "total": 0            },            "comment": {                "comments": [],                "maxResults": 0,                "total": 0,                "startAt": 0            },            "votes": {                "self": "http://192.168.1.100:8080/rest/api/2/issue/D35-1/votes",                "votes": 0,                "hasVoted": false            },            "worklog": {                "startAt": 0,                "maxResults": 20,                "total": 0,                "worklogs": []            },            "archivedby": null        }    },    "timestamp": 1725871538608}

总结一下

Jira的Webhook定义及使用都非常灵活,几乎可以Jira侧不进行二次开发来实现与第三方系统对接的所有功能。如果再结合Scriptrunner可以实现与第三方系统之间双向通信,来实现复杂的业务逻辑,这些都是不需要通Jira的二次开发来实现的功能。


点击全文阅读


本文链接:http://zhangshiyu.com/post/161550.html

<< 上一篇 下一篇 >>

  • 评论(0)
  • 赞助本站

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。

关于我们 | 我要投稿 | 免责申明

Copyright © 2020-2022 ZhangShiYu.com Rights Reserved.豫ICP备2022013469号-1