flagon-io/g1t

public

Where people and agents ship software together. The open-source git platform for the whole job: issues, agents, checks and deploys to the edge.

g1t/crates/contracts/src/webhooks.rs

186 lines5,428 bytesCodeBlame
1//! The webhooks service: events, delivered to the addresses a repository or
2//! a workspace registers.
3//!
4//! Every event g1t publishes can be delivered: an HTTPS `POST` of JSON,
5//! signed with the webhook's secret in `X-G1t-Signature-256`, and retried
6//! with growing waits when the receiver does not answer with a 2xx. Each
7//! delivery is kept, with what was sent and what came back, and can be sent
8//! again.
9//!
10//! Mirrors `packages/contracts/src/webhooks.ts`.
11
12use serde::{Deserialize, Serialize};
13
14use crate::repos::RepoPath;
15use crate::{User, Viewer};
16
17/// Every event a webhook can be sent, in the order people are shown them.
18pub const EVENT_TYPES: [&str; 21] = [
19 "git.push",
20 "repo.created",
21 "repo.forked",
22 "issue.opened",
23 "issue.updated",
24 "issue.assigned",
25 "issue.closed",
26 "issue.reopened",
27 "comment.created",
28 "pull.opened",
29 "pull.ready",
30 "pull.updated",
31 "pull.merge_requested",
32 "pull.merged",
33 "pull.closed",
34 "agent.asked",
35 "checks.completed",
36 "review.completed",
37 "workflow.completed",
38 "queue.changed",
39 "session.appended",
40];
41
42/// What a webhook belongs to.
43#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
44#[serde(rename_all = "snake_case")]
45pub enum HookScope {
46 /// One repository's events.
47 Repo,
48 /// The events of every repository in a workspace.
49 Workspace,
50}
51
52#[derive(Clone, Debug, Serialize, Deserialize)]
53#[serde(rename_all = "camelCase")]
54pub struct Hook {
55 pub id: String,
56 pub scope: HookScope,
57 pub workspace: String,
58 /// For a repository's webhook: `owner/name`.
59 pub repo: Option<String>,
60 pub url: String,
61 /// The event types it is sent, or `["*"]` for all.
62 pub events: Vec<String>,
63 pub active: bool,
64 /// The last four characters of its secret.
65 pub secret_hint: String,
66 pub created_by: String,
67 /// RFC 3339.
68 pub created_at: String,
69 /// How its latest delivery went: `delivered`, `pending` or `failed`.
70 pub last_status: Option<String>,
71 pub last_delivered_at: Option<String>,
72}
73
74/// One event sent, or being sent, to a webhook.
75#[derive(Clone, Debug, Serialize, Deserialize)]
76#[serde(rename_all = "camelCase")]
77pub struct HookDelivery {
78 pub id: String,
79 pub hook_id: String,
80 /// The event's id, or empty for a ping.
81 pub event_id: String,
82 pub event: String,
83 /// `pending` while it will be tried again, `delivered`, or `failed` once
84 /// it has been tried as often as it will be.
85 pub status: String,
86 pub attempts: u32,
87 /// The receiver's HTTP status, the last time it answered.
88 pub response_status: Option<u16>,
89 /// The start of what it answered.
90 pub response_body: Option<String>,
91 /// Why the last attempt failed, when the receiver could not be reached.
92 pub error: Option<String>,
93 pub duration_ms: Option<u32>,
94 /// The JSON that was sent.
95 pub payload: String,
96 /// RFC 3339.
97 pub created_at: String,
98 pub delivered_at: Option<String>,
99 pub next_attempt_at: Option<String>,
100}
101
102/// Which webhooks a call is about: a repository's, or with `repo` left out,
103/// the workspace's own.
104#[derive(Clone, Debug, Serialize, Deserialize)]
105pub struct HookOwner {
106 pub workspace: String,
107 #[serde(default)]
108 pub repo: Option<RepoPath>,
109}
110
111/// `list`. Returns `Outcome<Vec<Hook>>`. Members of the workspace only.
112#[derive(Debug, Serialize, Deserialize)]
113pub struct ListArgs {
114 pub viewer: Viewer,
115 #[serde(flatten)]
116 pub owner: HookOwner,
117}
118
119/// `create`. Returns `Outcome<CreatedHook>`. Members, for a repository's
120/// webhooks; owners, for the workspace's.
121#[derive(Debug, Serialize, Deserialize)]
122pub struct CreateArgs {
123 pub actor: User,
124 #[serde(flatten)]
125 pub owner: HookOwner,
126 pub url: String,
127 /// Event types, or `["*"]` for all. All when empty.
128 #[serde(default)]
129 pub events: Vec<String>,
130 /// Made by g1t when left out.
131 #[serde(default)]
132 pub secret: Option<String>,
133}
134
135#[derive(Clone, Debug, Serialize, Deserialize)]
136pub struct CreatedHook {
137 pub hook: Hook,
138 /// The secret, when g1t made it: shown this once.
139 pub secret: Option<String>,
140}
141
142/// `update`: only the fields given change. Returns `Outcome<Hook>`.
143#[derive(Debug, Serialize, Deserialize)]
144pub struct UpdateArgs {
145 pub actor: User,
146 #[serde(flatten)]
147 pub owner: HookOwner,
148 pub id: String,
149 #[serde(default)]
150 pub url: Option<String>,
151 #[serde(default)]
152 pub events: Option<Vec<String>>,
153 #[serde(default)]
154 pub active: Option<bool>,
155}
156
157/// `delete` (returns `Outcome<bool>`) and `ping` (sends a `ping` event and
158/// returns `Outcome<HookDelivery>`).
159#[derive(Debug, Serialize, Deserialize)]
160pub struct HookArgs {
161 pub actor: User,
162 #[serde(flatten)]
163 pub owner: HookOwner,
164 pub id: String,
165}
166
167/// `deliveries`: a webhook's latest deliveries, newest first. Returns
168/// `Outcome<Vec<HookDelivery>>`.
169#[derive(Debug, Serialize, Deserialize)]
170pub struct DeliveriesArgs {
171 pub viewer: Viewer,
172 #[serde(flatten)]
173 pub owner: HookOwner,
174 pub id: String,
175}
176
177/// `redeliver`: sends a delivery's payload again, as a new delivery.
178/// Returns `Outcome<HookDelivery>`.
179#[derive(Debug, Serialize, Deserialize)]
180#[serde(rename_all = "camelCase")]
181pub struct RedeliverArgs {
182 pub actor: User,
183 #[serde(flatten)]
184 pub owner: HookOwner,
185 pub delivery_id: String,
186}