Skip to content

Commit 94fcbbb

Browse files
Add per pipeline failed builds channel config (#164)
* add per pipeline failed builds channel cfg * add atd adapter for old allowed_pipelines config
1 parent caf3992 commit 94fcbbb

15 files changed

+1178
-12
lines changed

lib/action.ml

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -175,14 +175,23 @@ module Action (Github_api : Api.Github) (Slack_api : Api.Slack) = struct
175175
in
176176
let notify_failed_builds_channel =
177177
(* we only notify the failed builds channels for failed builds on the main branch *)
178-
Util.Build.is_failed_build n && Option.is_some cfg.status_rules.failed_builds_channel && is_main_branch
178+
Util.Build.is_failed_build n && Option.is_some cfg.status_rules.allowed_pipelines && is_main_branch
179179
in
180-
match notify_failed_builds_channel with
181-
| false -> Lwt.return (direct_message @ chans)
182-
| true ->
180+
match notify_failed_builds_channel, cfg.status_rules.allowed_pipelines with
181+
| false, _ | true, None -> Lwt.return (direct_message @ chans)
182+
| true, Some allowed_pipelines ->
183183
(* if we have a failed build and a failed builds channel, we send one notification there too,
184184
but we don't notify the same channel twice *)
185-
let chans = Option.get cfg.status_rules.failed_builds_channel :: chans |> List.sort_uniq String.compare in
185+
let chans =
186+
List.find_map
187+
(fun ({ name; failed_builds_channel } : Config_t.pipeline) ->
188+
match String.equal name n.context, failed_builds_channel with
189+
| true, Some failed_builds_channel -> Some (failed_builds_channel :: chans)
190+
| _ -> None)
191+
allowed_pipelines
192+
|> Option.default chans
193+
|> List.sort_uniq String.compare
194+
in
186195
Lwt.return (direct_message @ chans)
187196
in
188197
let%lwt recipients =

lib/atd_adapters.ml

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,3 +68,17 @@ module Slack_response_adapter : Atdgen_runtime.Json_adapter.S = struct
6868
| `List [ `String "Error"; `String msg ] -> `Assoc (mk_fields false [ "error", `String msg ])
6969
| _ -> x
7070
end
71+
72+
(* This adapter is meant to avoid breaking changes in the config because the type for
73+
[allowed_pipelines] was changed from a string list to a pipeline record list. *)
74+
module Strings_to_pipelines_adapter : Atdgen_runtime.Json_adapter.S = struct
75+
let normalize (x : Yojson.Safe.t) =
76+
match x with
77+
| `String s -> `Assoc [ "name", `String s; "failed_builds_channel", `Null ]
78+
| _ -> x
79+
80+
let restore (x : Yojson.Safe.t) =
81+
match x with
82+
| `Assoc [ ("name", `String s); ("failed_builds_channel", _) ] -> `String s
83+
| _ -> x
84+
end

lib/config.atd

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,14 @@ type prefix_rule <ocaml from="Rule"> = abstract
33
type label_rule <ocaml from="Rule"> = abstract
44
type project_owners_rule <ocaml from="Rule"> = abstract
55

6+
type pipeline = {
7+
name: string;
8+
?failed_builds_channel: string nullable;
9+
} <json adapter.ocaml="Atd_adapters.Strings_to_pipelines_adapter">
10+
611
(* This type of rule is used for CI build notifications. *)
712
type status_rules = {
8-
?allowed_pipelines : string list nullable; (* keep only status events with a title matching this list *)
9-
?failed_builds_channel: string nullable; (* channel to post failed builds notifications to *)
13+
?allowed_pipelines : pipeline list nullable; (* keep only status events with a title matching this list *)
1014
rules: status_rule list;
1115
}
1216

@@ -34,7 +38,7 @@ type project_owners = {
3438
type config = {
3539
prefix_rules : prefix_rules;
3640
label_rules : label_rules;
37-
~status_rules <ocaml default="{allowed_pipelines = Some []; rules = []; failed_builds_channel = None}"> : status_rules;
41+
~status_rules <ocaml default="{allowed_pipelines = None; rules = []}"> : status_rules;
3842
~project_owners <ocaml default="{rules = []}"> : project_owners;
3943
~ignored_users <ocaml default="[]">: string list; (* list of ignored users *)
4044
?main_branch_name : string nullable; (* the name of the main branch; used to filter out notifications about merges of main branch into other branches *)

lib/context.ml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,9 @@ let is_pipeline_allowed ctx repo_url ~pipeline =
7979
| None -> true
8080
| Some config ->
8181
match config.status_rules.allowed_pipelines with
82-
| Some allowed_pipelines when not @@ List.exists (String.equal pipeline) allowed_pipelines -> false
82+
| Some allowed_pipelines
83+
when not @@ List.exists (fun (p : Config_t.pipeline) -> String.equal p.name pipeline) allowed_pipelines ->
84+
false
8385
| _ -> true
8486

8587
let refresh_secrets ctx =

lib/slack.ml

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -322,7 +322,13 @@ let generate_status_notification ~(ctx : Context.t) ?slack_user_id (cfg : Config
322322
in
323323
let failed_builds_info =
324324
let is_failed_builds_channel =
325-
Option.map_default (String.equal channel) false cfg.status_rules.failed_builds_channel
325+
match cfg.status_rules.allowed_pipelines with
326+
| None -> false
327+
| Some pipelines ->
328+
List.exists
329+
(fun ({ name; failed_builds_channel } : Config_t.pipeline) ->
330+
String.equal name context && Option.map_default (String.equal channel) false failed_builds_channel)
331+
pipelines
326332
in
327333
match Util.Build.is_failed_build notification && is_failed_builds_channel with
328334
| false -> []
Lines changed: 252 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,252 @@
1+
{
2+
"id": 17813296,
3+
"sha": "7e0a933e9c71b4ca107680ca958ca1888d5e479b",
4+
"name": "ahrefs/monorepo",
5+
"target_url": "https://buildkite.com/ahrefs/monorepo/builds/181732",
6+
"avatar_url": "https://github.com/avatars/oa/6?",
7+
"context": "buildkite/qa",
8+
"description": "Build #181732 failed (7 minutes, 29 seconds)",
9+
"state": "failure",
10+
"commit": {
11+
"sha": "7e0a933e9c71b4ca107680ca958ca1888d5e479b",
12+
"node_id": "MDY6Q29tbWl0ODU6N2UwYTkzM2U5YzcxYjRjYTEwNzY4MGNhOTU4Y2ExODg4ZDVlNDc5Yg==",
13+
"commit": {
14+
"author": {
15+
"name": "author",
16+
"email": "author@ahrefs.com",
17+
"date": "2024-05-31T03:54:00Z"
18+
},
19+
"committer": {
20+
"name": "author",
21+
"email": "author@ahrefs.com",
22+
"date": "2024-05-31T03:54:00Z"
23+
},
24+
"message": "c1 message",
25+
"tree": {
26+
"sha": "51d7c2d0fc8f182f8ffad40ef79471789e6f5578",
27+
"url": "https://github.com/api/v3/repos/ahrefs/monorepo/git/trees/51d7c2d0fc8f182f8ffad40ef79471789e6f5578"
28+
},
29+
"url": "https://github.com/api/v3/repos/ahrefs/monorepo/git/commits/7e0a933e9c71b4ca107680ca958ca1888d5e479b",
30+
"comment_count": 0,
31+
"verification": {
32+
"verified": false,
33+
"reason": "unsigned",
34+
"signature": null,
35+
"payload": null
36+
}
37+
},
38+
"url": "https://github.com/api/v3/repos/ahrefs/monorepo/commits/7e0a933e9c71b4ca107680ca958ca1888d5e479b",
39+
"html_url": "https://github.com/ahrefs/monorepo/commit/7e0a933e9c71b4ca107680ca958ca1888d5e479b",
40+
"comments_url": "https://github.com/api/v3/repos/ahrefs/monorepo/commits/7e0a933e9c71b4ca107680ca958ca1888d5e479b/comments",
41+
"author": {
42+
"login": "author",
43+
"id": 92,
44+
"node_id": "MDQ6VXNlcjky",
45+
"avatar_url": "https://github.com/avatars/u/92?",
46+
"gravatar_id": "",
47+
"url": "https://github.com/api/v3/users/author",
48+
"html_url": "https://github.com/author",
49+
"followers_url": "https://github.com/api/v3/users/author/followers",
50+
"following_url": "https://github.com/api/v3/users/author/following{/other_user}",
51+
"gists_url": "https://github.com/api/v3/users/author/gists{/gist_id}",
52+
"starred_url": "https://github.com/api/v3/users/author/starred{/owner}{/repo}",
53+
"subscriptions_url": "https://github.com/api/v3/users/author/subscriptions",
54+
"organizations_url": "https://github.com/api/v3/users/author/orgs",
55+
"repos_url": "https://github.com/api/v3/users/author/repos",
56+
"events_url": "https://github.com/api/v3/users/author/events{/privacy}",
57+
"received_events_url": "https://github.com/api/v3/users/author/received_events",
58+
"type": "User",
59+
"site_admin": false
60+
},
61+
"committer": {
62+
"login": "author",
63+
"id": 92,
64+
"node_id": "MDQ6VXNlcjky",
65+
"avatar_url": "https://github.com/avatars/u/92?",
66+
"gravatar_id": "",
67+
"url": "https://github.com/api/v3/users/author",
68+
"html_url": "https://github.com/author",
69+
"followers_url": "https://github.com/api/v3/users/author/followers",
70+
"following_url": "https://github.com/api/v3/users/author/following{/other_user}",
71+
"gists_url": "https://github.com/api/v3/users/author/gists{/gist_id}",
72+
"starred_url": "https://github.com/api/v3/users/author/starred{/owner}{/repo}",
73+
"subscriptions_url": "https://github.com/api/v3/users/author/subscriptions",
74+
"organizations_url": "https://github.com/api/v3/users/author/orgs",
75+
"repos_url": "https://github.com/api/v3/users/author/repos",
76+
"events_url": "https://github.com/api/v3/users/author/events{/privacy}",
77+
"received_events_url": "https://github.com/api/v3/users/author/received_events",
78+
"type": "User",
79+
"site_admin": false
80+
},
81+
"parents": [
82+
{
83+
"sha": "b2f115b1be68ab14975f0e581283a954bf67734a",
84+
"url": "https://github.com/api/v3/repos/ahrefs/monorepo/commits/b2f115b1be68ab14975f0e581283a954bf67734a",
85+
"html_url": "https://github.com/ahrefs/monorepo/commit/b2f115b1be68ab14975f0e581283a954bf67734a"
86+
},
87+
{
88+
"sha": "53f8468ca5eafb0e0885b9d62806c52c872ea2af",
89+
"url": "https://github.com/api/v3/repos/ahrefs/monorepo/commits/53f8468ca5eafb0e0885b9d62806c52c872ea2af",
90+
"html_url": "https://github.com/ahrefs/monorepo/commit/53f8468ca5eafb0e0885b9d62806c52c872ea2af"
91+
}
92+
]
93+
},
94+
"branches": [
95+
{
96+
"name": "author/patches/js-storage",
97+
"commit": {
98+
"sha": "7e0a933e9c71b4ca107680ca958ca1888d5e479b",
99+
"url": "https://github.com/api/v3/repos/ahrefs/monorepo/commits/7e0a933e9c71b4ca107680ca958ca1888d5e479b"
100+
},
101+
"protected": false
102+
}
103+
],
104+
"created_at": "2024-06-02T04:57:47+00:00",
105+
"updated_at": "2024-06-02T04:57:47+00:00",
106+
"repository": {
107+
"id": 85,
108+
"node_id": "MDEwOlJlcG9zaXRvcnk4NQ==",
109+
"name": "monorepo",
110+
"full_name": "ahrefs/monorepo",
111+
"private": true,
112+
"owner": {
113+
"login": "ahrefs",
114+
"id": 7,
115+
"node_id": "MDEyOk9yZ2FuaXphdGlvbjc=",
116+
"avatar_url": "https://github.com/avatars/u/7?",
117+
"gravatar_id": "",
118+
"url": "https://github.com/api/v3/users/ahrefs",
119+
"html_url": "https://github.com/ahrefs",
120+
"followers_url": "https://github.com/api/v3/users/ahrefs/followers",
121+
"following_url": "https://github.com/api/v3/users/ahrefs/following{/other_user}",
122+
"gists_url": "https://github.com/api/v3/users/ahrefs/gists{/gist_id}",
123+
"starred_url": "https://github.com/api/v3/users/ahrefs/starred{/owner}{/repo}",
124+
"subscriptions_url": "https://github.com/api/v3/users/ahrefs/subscriptions",
125+
"organizations_url": "https://github.com/api/v3/users/ahrefs/orgs",
126+
"repos_url": "https://github.com/api/v3/users/ahrefs/repos",
127+
"events_url": "https://github.com/api/v3/users/ahrefs/events{/privacy}",
128+
"received_events_url": "https://github.com/api/v3/users/ahrefs/received_events",
129+
"type": "Organization",
130+
"site_admin": false
131+
},
132+
"html_url": "https://github.com/ahrefs/monorepo",
133+
"description": "main repository",
134+
"fork": false,
135+
"url": "https://github.com/api/v3/repos/ahrefs/monorepo",
136+
"forks_url": "https://github.com/api/v3/repos/ahrefs/monorepo/forks",
137+
"keys_url": "https://github.com/api/v3/repos/ahrefs/monorepo/keys{/key_id}",
138+
"collaborators_url": "https://github.com/api/v3/repos/ahrefs/monorepo/collaborators{/collaborator}",
139+
"teams_url": "https://github.com/api/v3/repos/ahrefs/monorepo/teams",
140+
"hooks_url": "https://github.com/api/v3/repos/ahrefs/monorepo/hooks",
141+
"issue_events_url": "https://github.com/api/v3/repos/ahrefs/monorepo/issues/events{/number}",
142+
"events_url": "https://github.com/api/v3/repos/ahrefs/monorepo/events",
143+
"assignees_url": "https://github.com/api/v3/repos/ahrefs/monorepo/assignees{/user}",
144+
"branches_url": "https://github.com/api/v3/repos/ahrefs/monorepo/branches{/branch}",
145+
"tags_url": "https://github.com/api/v3/repos/ahrefs/monorepo/tags",
146+
"blobs_url": "https://github.com/api/v3/repos/ahrefs/monorepo/git/blobs{/sha}",
147+
"git_tags_url": "https://github.com/api/v3/repos/ahrefs/monorepo/git/tags{/sha}",
148+
"git_refs_url": "https://github.com/api/v3/repos/ahrefs/monorepo/git/refs{/sha}",
149+
"trees_url": "https://github.com/api/v3/repos/ahrefs/monorepo/git/trees{/sha}",
150+
"statuses_url": "https://github.com/api/v3/repos/ahrefs/monorepo/statuses/{sha}",
151+
"languages_url": "https://github.com/api/v3/repos/ahrefs/monorepo/languages",
152+
"stargazers_url": "https://github.com/api/v3/repos/ahrefs/monorepo/stargazers",
153+
"contributors_url": "https://github.com/api/v3/repos/ahrefs/monorepo/contributors",
154+
"subscribers_url": "https://github.com/api/v3/repos/ahrefs/monorepo/subscribers",
155+
"subscription_url": "https://github.com/api/v3/repos/ahrefs/monorepo/subscription",
156+
"commits_url": "https://github.com/api/v3/repos/ahrefs/monorepo/commits{/sha}",
157+
"git_commits_url": "https://github.com/api/v3/repos/ahrefs/monorepo/git/commits{/sha}",
158+
"comments_url": "https://github.com/api/v3/repos/ahrefs/monorepo/comments{/number}",
159+
"issue_comment_url": "https://github.com/api/v3/repos/ahrefs/monorepo/issues/comments{/number}",
160+
"contents_url": "https://github.com/api/v3/repos/ahrefs/monorepo/contents/{+path}",
161+
"compare_url": "https://github.com/api/v3/repos/ahrefs/monorepo/compare/{base}...{head}",
162+
"merges_url": "https://github.com/api/v3/repos/ahrefs/monorepo/merges",
163+
"archive_url": "https://github.com/api/v3/repos/ahrefs/monorepo/{archive_format}{/ref}",
164+
"downloads_url": "https://github.com/api/v3/repos/ahrefs/monorepo/downloads",
165+
"issues_url": "https://github.com/api/v3/repos/ahrefs/monorepo/issues{/number}",
166+
"pulls_url": "https://github.com/api/v3/repos/ahrefs/monorepo/pulls{/number}",
167+
"milestones_url": "https://github.com/api/v3/repos/ahrefs/monorepo/milestones{/number}",
168+
"notifications_url": "https://github.com/api/v3/repos/ahrefs/monorepo/notifications{?since,all,participating}",
169+
"labels_url": "https://github.com/api/v3/repos/ahrefs/monorepo/labels{/name}",
170+
"releases_url": "https://github.com/api/v3/repos/ahrefs/monorepo/releases{/id}",
171+
"deployments_url": "https://github.com/api/v3/repos/ahrefs/monorepo/deployments",
172+
"created_at": "2017-03-06T23:40:04Z",
173+
"updated_at": "2024-05-14T07:59:19Z",
174+
"pushed_at": "2024-06-02T04:49:58Z",
175+
"git_url": "git://github.com/ahrefs/monorepo.git",
176+
"ssh_url": "git@github.com:ahrefs/monorepo.git",
177+
"clone_url": "https://github.com/ahrefs/monorepo.git",
178+
"svn_url": "https://github.com/ahrefs/monorepo",
179+
"homepage": "https://ahrefs.com",
180+
"size": 2927252,
181+
"stargazers_count": 6,
182+
"watchers_count": 6,
183+
"language": "HTML",
184+
"has_issues": true,
185+
"has_projects": true,
186+
"has_downloads": true,
187+
"has_wiki": true,
188+
"has_pages": false,
189+
"has_discussions": false,
190+
"forks_count": 0,
191+
"mirror_url": null,
192+
"archived": false,
193+
"disabled": false,
194+
"open_issues_count": 422,
195+
"license": null,
196+
"allow_forking": false,
197+
"is_template": false,
198+
"web_commit_signoff_required": false,
199+
"topics": [],
200+
"visibility": "private",
201+
"forks": 0,
202+
"open_issues": 422,
203+
"watchers": 6,
204+
"default_branch": "develop"
205+
},
206+
"organization": {
207+
"login": "ahrefs",
208+
"id": 7,
209+
"node_id": "MDEyOk9yZ2FuaXphdGlvbjc=",
210+
"url": "https://github.com/api/v3/orgs/ahrefs",
211+
"repos_url": "https://github.com/api/v3/orgs/ahrefs/repos",
212+
"events_url": "https://github.com/api/v3/orgs/ahrefs/events",
213+
"hooks_url": "https://github.com/api/v3/orgs/ahrefs/hooks",
214+
"issues_url": "https://github.com/api/v3/orgs/ahrefs/issues",
215+
"members_url": "https://github.com/api/v3/orgs/ahrefs/members{/member}",
216+
"public_members_url": "https://github.com/api/v3/orgs/ahrefs/public_members{/member}",
217+
"avatar_url": "https://github.com/avatars/u/7?",
218+
"description": null
219+
},
220+
"enterprise": {
221+
"id": 1,
222+
"slug": "ahrefs-pte-ltd",
223+
"name": "Ahrefs Pte Ltd",
224+
"node_id": "MDEwOkVudGVycHJpc2Ux",
225+
"avatar_url": "https://github.com/avatars/b/1?",
226+
"description": null,
227+
"website_url": null,
228+
"html_url": "https://github.com/enterprises/ahrefs-pte-ltd",
229+
"created_at": "2019-01-09T18:50:55Z",
230+
"updated_at": "2024-03-18T14:38:02Z"
231+
},
232+
"sender": {
233+
"login": "ip",
234+
"id": 3,
235+
"node_id": "MDQ6VXNlcjM=",
236+
"avatar_url": "https://github.com/avatars/u/3?",
237+
"gravatar_id": "",
238+
"url": "https://github.com/api/v3/users/ip",
239+
"html_url": "https://github.com/ip",
240+
"followers_url": "https://github.com/api/v3/users/ip/followers",
241+
"following_url": "https://github.com/api/v3/users/ip/following{/other_user}",
242+
"gists_url": "https://github.com/api/v3/users/ip/gists{/gist_id}",
243+
"starred_url": "https://github.com/api/v3/users/ip/starred{/owner}{/repo}",
244+
"subscriptions_url": "https://github.com/api/v3/users/ip/subscriptions",
245+
"organizations_url": "https://github.com/api/v3/users/ip/orgs",
246+
"repos_url": "https://github.com/api/v3/users/ip/repos",
247+
"events_url": "https://github.com/api/v3/users/ip/events{/privacy}",
248+
"received_events_url": "https://github.com/api/v3/users/ip/received_events",
249+
"type": "User",
250+
"site_admin": true
251+
}
252+
}

0 commit comments

Comments
 (0)