linear-webhook の new type への対応
Linear.app の Webhoook を捌くためのハンドラ
Linear 側のアップデートで Webhook のタイプが増えた。
types: issue labels, comment reactions, cycles and projects.
新たに、ラベル、コメントへのリアクション、サイクル、プロジェクトの追加、更新、削除に対して Webhook を飛ばすようになった。
これに対応したい
まずはラベル。
以前からIssueにラベルを貼り付けたらIssueUpdateイベントとなってwebhookは飛んでいた。
そこら辺は変わってない模様
Team Settings -> Labels -> New label でラベルを作成した
{
"action": "create",
"createdAt": "2021-02-07T09:17:51.393Z",
"data": {
"id": "13aa50db-xxxx-xxxx-xxxx-1cdd26695e65",
"createdAt": "2021-02-07T09:17:51.393Z",
"updatedAt": "2021-02-07T09:17:51.393Z",
"name": "new label",
"color": "#5a450d",
"teamId": "eeaa0cbd-xxxx-xxxx-xxxx-1c701c3485f1",
"creatorId": "80e102b0-xxxx-xxxx-xxxx-044bcfb4cd39"
},
"type": "IssueLabel"
}
IssueLabel
というtype
になるらしい。Label
ではないんだ。
これに対応する
今までのaction: "create"
は必ずurl
メンバを持っていたが、CreateIssueLabel
はそれを持たない。optional property にする
次は UpdateIssueLabel を確認する
ラベル名を変更した
{
"action": "update",
"createdAt": "2021-02-07T09:33:32.156Z",
"data": {
"id": "13aa50db-xxxx-xxxx-xxxx-1cdd26695e65",
"createdAt": "2021-02-07T09:17:51.393Z",
"updatedAt": "2021-02-07T09:33:32.156Z",
"name": "update new label",
"color": "#5a450d",
"teamId": "eeaa0cbd-xxxx-xxxx-xxxx-1c701c3485f1",
"creatorId": "80e102b0-xxxx-xxxx-xxxx-044bcfb4cd39"
},
"updatedFrom": {
"updatedAt": "2021-02-07T09:17:51.393Z",
"archivedAt": null,
"name": "new label",
"description": null
},
"type": "IssueLabel"
}
最後に RemoveIssueLabel を確認する。
{
"action": "remove",
"createdAt": "2021-02-07T09:38:46.255Z",
"data": {
"id": "13aa50db-xxxx-xxxx-xxxx-1cdd26695e65",
"createdAt": "2021-02-07T09:17:51.393Z",
"updatedAt": "2021-02-07T09:33:32.156Z",
"archivedAt": "2021-02-07T09:38:46.255Z",
"name": "update new label",
"color": "#5a450d",
"teamId": "eeaa0cbd-xxxx-xxxx-xxxx-1c701c3485f1",
"creatorId": "80e102b0-xxxx-xxxx-xxxx-044bcfb4cd39"
},
"type": "IssueLabel"
}
data
にarchivedAt
が増えた
RemoveIssueLabel のみarchivedAt
を持っているので、CreateIssueLabel、UpdateIssueLabelが持つdata
からarchivedAt
をOmit
export interface CreateIssueLabel extends Create, IssueLabel {
data: Omit<IssueLabelDate, "archivedAt">;
}
export interface UpdateIssueLabel extends Update, IssueLabel {
data: Omit<IssueLabelDate, "archivedAt">;
}
今回はOmitしてるけど、これRemoveIssueLabelのdataにarchivedAt
を追加した方がいいのだろうか?
export interface RemoveIssueLabel extends Remove, IssueLabel {
data: IssueLabelDate & {
archivedAt: ISOString;
};
}
こっちの方が同じ変更をCreateIssueLabelとUpdateIssueLabelに入れなくて済むから良い?
とりあえず後者を採用しよう
IssueLabel関連のinterfaceはできたのでHandler.tsで捌けるようにする
getWebhookEvent()
に登録。テストを追加した
プルリク
進捗
- IssueLabel
- CommentReaction
- Cycle
- Project
コメントにリアクションする
{
"action": "create",
"createdAt": "2021-02-07T10:10:55.083Z",
"data": {
"id": "c6d50a94-xxxx-xxxx-xxxx-8a552952a50e",
"createdAt": "2021-02-07T10:10:55.083Z",
"updatedAt": "2021-02-07T10:10:55.083Z",
"emoji": "white_check_mark",
"userId": "80e102b0-xxxx-xxxx-xxxx-044bcfb4cd39",
"commentId": "fd58dfb7-xxxx-xxxx-xxxx-759c3c2437d5",
"comment": {
"id": "fd58dfb7-xxxx-xxxx-xxxx-759c3c2437d5",
"body": "new comment",
"userId": "80e102b0-xxxx-xxxx-xxxx-044bcfb4cd39"
},
"user": {
"id": "80e102b0-xxxx-xxxx-xxxx-044bcfb4cd39",
"name": "hoge@example.com"
}
},
"type": "Reaction"
}
CreateReactionが飛んでくる
なぜかついでにUpdateCommentが飛んでくる
{
"action": "update",
"createdAt": "2021-02-07T10:10:55.083Z",
"data": {
"id": "fd58dfb7-xxxx-xxxx-xxxx-759c3c2437d5",
"createdAt": "2021-02-07T10:10:51.760Z",
"updatedAt": "2021-02-07T10:10:55.083Z",
"body": "new comment",
"userId": "80e102b0-xxxx-xxxx-xxxx-044bcfb4cd39",
"issueId": "396f4eb9-xxxx-xxxx-xxxx-33fe2fcca5e0",
"issue": {
"id": "396f4eb9-xxxx-xxxx-xxxx-33fe2fcca5e0",
"title": "hihi"
},
"user": {
"id": "80e102b0-xxxx-xxxx-xxxx-044bcfb4cd39",
"name": "hoge@example.com"
}
},
"updatedFrom": {
"updatedAt": "2021-02-07T10:10:51.760Z",
"archivedAt": null,
"editedAt": null
},
"url": "https://linear.app/xxxx/issue/KOR-13/hihi#comment-fd58dfb7",
"type": "Comment"
}
以前はコメントにリアクションをするとUpdateCommentイベントとしてwebhookが飛んでいた。
{
action: "update",
createdAt: "2021-01-31T13:13:07.588Z",
data: {
....
reactions: [],
},
updatedFrom: {
updatedAt: "2021-01-31T13:13:00.988Z",
archivedAt: null,
body: "aaaaa",
editedAt: null,
},
url: "https://linear.app/xxxx/issue/KOR-15/subissue#comment-00c2b179",
type: "Comment",
}
data.reactions
という配列に下のような構造でリアクションが含まれていた。
interface Reaction {
id: ReactionId;
emoji: string;
userId: UserId;
}
今回の更新でUpdateCommentイベントにリアクションは含まれなくなった模様。なのにUpdateCommentイベントが飛んでくる。冗長では?
とりあえずComment周りを修正してCreateReactionWebhookインタフェースを作成。
次はReactionを取り消してみる
リアクション消そうとしてるのに押しても消えねー
あ、時間差で消えた。
リアクション消してもRemoveReactionもUpdateReactionも飛んでこない。
UpdateCommentは相変わらずくる。
これだとリアクション取り消してもWebhookじゃ検知できない。
これもバグじゃね?
しょうがないからReactionはCreateのみ用意しておく
PR: https://github.com/korosuke613/linear-webhook/pull/20
進捗
- IssueLabel
- Reaction(createのみ)
- Cycle
- Project
Cycle 名を rename
長い
{
"action": "update",
"createdAt": "2021-02-07T11:54:03.602Z",
"data": {
"id": "8becebd5-xxxx-xxxx-xxxx-5a4c46206590",
"createdAt": "2021-01-30T11:21:04.585Z",
"updatedAt": "2021-02-07T11:54:03.602Z",
"number": 1,
"name": "rename cycle",
"startsAt": "2021-01-24T15:00:00.000Z",
"endsAt": "2021-02-07T15:00:00.000Z",
"issueCountHistory": [
0,
0,
0,
0,
0,
1,
1,
1,
1,
1,
1,
1,
1
],
"completedIssueCountHistory": [
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0
],
"scopeHistory": [
0,
0,
0,
0,
0,
1,
1,
1,
1,
1,
1,
1,
1
],
"completedScopeHistory": [
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0
],
"teamId": "eeaa0cbd-xxxx-xxxx-xxxx-1c701c3485f1",
"uncompletedIssuesUponCloseIds": []
},
"updatedFrom": {
"updatedAt": "2021-02-06T15:00:01.678Z",
"archivedAt": null,
"name": null,
"completedAt": null
},
"type": "Cycle"
}
今度は'Change cycle start time...'してみた
{
"action": "update",
"createdAt": "2021-02-07T12:05:20.358Z",
"data": {
"id": "397b115e-xxxx-xxxx-xxxx-5012096c7484",
"createdAt": "2021-01-30T11:21:04.585Z",
"updatedAt": "2021-02-07T12:05:20.358Z",
"number": 3,
"startsAt": "2021-03-21T15:00:00.000Z",
"endsAt": "2021-04-04T15:00:00.000Z",
"issueCountHistory": [],
"completedIssueCountHistory": [],
"scopeHistory": [],
"completedScopeHistory": [],
"teamId": "eeaa0cbd-xxxx-xxxx-xxxx-1c701c3485f1",
"uncompletedIssuesUponCloseIds": []
},
"updatedFrom": {
"updatedAt": "2021-01-30T11:21:04.585Z",
"archivedAt": null,
"name": null,
"startsAt": "2021-02-21T15:00:00.000Z",
"endsAt": "2021-03-07T15:00:00.000Z",
"completedAt": null
},
"type": "Cycle"
}
data.name
が消えた。多分リネームしないとnameは存在しないのだろう。optionalにする
updatedFromもstartsAtとendsAtが増えた
createとremoveは多分次のCycleになった時に飛んでくるから今検証できない。
またチェックする
pr:
進捗
- IssueLabel
- Reaction(createのみ)
- Cycle(updateのみ)
- Project
Project の作成
基本
{
"action": "create",
"createdAt": "2021-02-07T12:18:42.073Z",
"data": {
"id": "14449f5f-xxxx-xxxx-xxxx-155b5c08af2a",
"createdAt": "2021-02-07T12:18:42.073Z",
"updatedAt": "2021-02-07T12:18:42.073Z",
"name": "new Project",
"description": "",
"slugId": "87cf626a561e",
"color": "#bec2c8",
"state": "planned",
"creatorId": "80e102b0-xxxx-xxxx-xxxx-044bcfb4cd39",
"milestoneId": "b89dd730-xxxx-xxxx-xxxx-b195ab3144da",
"sortOrder": 1109.12,
"issueCountHistory": [],
"completedIssueCountHistory": [],
"scopeHistory": [],
"completedScopeHistory": [],
"slackNewIssue": true,
"slackIssueComments": true,
"slackIssueStatuses": true,
"teamIds": [
"eeaa0cbd-xxxx-xxxx-xxxx-1c701c3485f1"
],
"memberIds": []
},
"url": "https://linear.app/xxxx/project/new-project-87cf626a561e",
"type": "Project"
}
全部入り
{
"action": "create",
"createdAt": "2021-02-07T12:21:05.729Z",
"data": {
"id": "5ad6280f-xxxx-xxxx-xxxx-b869cfa62b33",
"createdAt": "2021-02-07T12:21:05.729Z",
"updatedAt": "2021-02-07T12:21:05.729Z",
"name": "fffff",
"description": "aaaa",
"slugId": "37f87fe3d558",
"icon": "Page",
"color": "#0f7488",
"state": "started",
"creatorId": "80e102b0-xxxx-xxxx-xxxx-044bcfb4cd39",
"leadId": "80e102b0-xxxx-xxxx-xxxx-044bcfb4cd39",
"milestoneId": "b89dd730-xxxx-xxxx-xxxx-b195ab3144da",
"targetDate": "2021-02-11",
"startedAt": "2021-02-07T12:21:05.748Z",
"sortOrder": 2031.02,
"issueCountHistory": [],
"completedIssueCountHistory": [],
"scopeHistory": [],
"completedScopeHistory": [],
"slackNewIssue": true,
"slackIssueComments": true,
"slackIssueStatuses": true,
"teamIds": [
"eeaa0cbd-xxxx-xxxx-xxxx-1c701c3485f1"
],
"memberIds": [
"80e102b0-xxxx-xxxx-xxxx-044bcfb4cd39"
]
},
"url": "https://linear.app/xxxx/project/fffff-37f87fe3d558",
"type": "Project"
}
createは対応した。
次はupdate
なんか二つきたんだが
{
"action": "update",
"createdAt": "2021-02-07T12:41:09.314Z",
"data": {
"id": "5ad6280f-eeef-435e-949f-b869cfa62b33",
"createdAt": "2021-02-07T12:21:05.729Z",
"updatedAt": "2021-02-07T12:41:09.314Z",
"name": "rename project",
"description": "aaaa",
"slugId": "37f87fe3d558",
"icon": "Page",
"color": "#0f7488",
"state": "started",
"creatorId": "80e102b0-4a45-44d4-93a8-044bcfb4cd39",
"leadId": "80e102b0-4a45-44d4-93a8-044bcfb4cd39",
"milestoneId": "b89dd730-af60-4880-b408-b195ab3144da",
"targetDate": "2021-02-11",
"startedAt": "2021-02-07T12:21:05.748Z",
"sortOrder": 2031.02,
"issueCountHistory": [],
"completedIssueCountHistory": [],
"scopeHistory": [],
"completedScopeHistory": [],
"slackNewIssue": true,
"slackIssueComments": true,
"slackIssueStatuses": true,
"teamIds": [
"eeaa0cbd-5902-4d57-a7ad-1c701c3485f1"
],
"memberIds": [
"80e102b0-4a45-44d4-93a8-044bcfb4cd39"
]
},
"updatedFrom": {
"archivedAt": null,
"completedAt": null,
"canceledAt": null
},
"url": "https://linear.app/korosuke613/project/rename-project-37f87fe3d558",
"type": "Project"
}
{
"action": "update",
"createdAt": "2021-02-07T12:41:09.314Z",
"data": {
"id": "5ad6280f-eeef-435e-949f-b869cfa62b33",
"createdAt": "2021-02-07T12:21:05.729Z",
"updatedAt": "2021-02-07T12:41:09.314Z",
"name": "rename project",
"description": "aaaa",
"slugId": "37f87fe3d558",
"icon": "Page",
"color": "#0f7488",
"state": "started",
"creatorId": "80e102b0-4a45-44d4-93a8-044bcfb4cd39",
"leadId": "80e102b0-4a45-44d4-93a8-044bcfb4cd39",
"milestoneId": "b89dd730-af60-4880-b408-b195ab3144da",
"targetDate": "2021-02-11",
"startedAt": "2021-02-07T12:21:05.748Z",
"sortOrder": 2031.02,
"issueCountHistory": [],
"completedIssueCountHistory": [],
"scopeHistory": [],
"completedScopeHistory": [],
"slackNewIssue": true,
"slackIssueComments": true,
"slackIssueStatuses": true,
"teamIds": [
"eeaa0cbd-5902-4d57-a7ad-1c701c3485f1"
],
"memberIds": [
"80e102b0-4a45-44d4-93a8-044bcfb4cd39"
]
},
"updatedFrom": {
"name": "fffff",
"updatedAt": "2021-02-07T12:21:05.729Z",
"archivedAt": null,
"completedAt": null,
"canceledAt": null
},
"url": "https://linear.app/korosuke613/project/rename-project-37f87fe3d558",
"type": "Project"
}
UpdateProject は特に変更なかった。
export interface UpdateProjectWebhook extends Update, Project {}
Project画面でIssueを作成したけどUpdateProjectイベントは発生せず、CreateIssueイベントが発生した。想定通り
Projectを削除
archivedAt
が追加された
{
"action": "remove",
"createdAt": "2021-02-07T13:23:03.860Z",
"data": {
"id": "5ad6280f-eeef-435e-949f-b869cfa62b33",
"createdAt": "2021-02-07T12:21:05.729Z",
"updatedAt": "2021-02-07T13:22:11.230Z",
"archivedAt": "2021-02-07T13:23:03.860Z",
"name": "rename project",
"description": "aaaa",
"slugId": "37f87fe3d558",
"icon": "Page",
"color": "#0f7488",
"state": "canceled",
"creatorId": "80e102b0-4a45-44d4-93a8-044bcfb4cd39",
"leadId": "80e102b0-4a45-44d4-93a8-044bcfb4cd39",
"milestoneId": "b89dd730-af60-4880-b408-b195ab3144da",
"targetDate": "2021-02-11",
"startedAt": "2021-02-07T12:21:05.748Z",
"canceledAt": "2021-02-07T13:22:11.227Z",
"sortOrder": 2031.02,
"issueCountHistory": [],
"completedIssueCountHistory": [],
"scopeHistory": [],
"completedScopeHistory": [],
"slackNewIssue": true,
"slackIssueComments": true,
"slackIssueStatuses": true,
"teamIds": [
"eeaa0cbd-5902-4d57-a7ad-1c701c3485f1"
],
"memberIds": [
"80e102b0-4a45-44d4-93a8-044bcfb4cd39"
]
},
"url": "https://linear.app/korosuke613/project/rename-project-37f87fe3d558",
"type": "Project"
}
メモ
これアリかも?
type Create<T extends Webhook> = T & {
url: string;
};
ProjectのPR
リリースしたのでDone