Skip to content

Commit 5420096

Browse files
authored
Merge pull request #69 from ahrefs/feature/#43
pick up filtering rules from the repo itself
2 parents cc8764d + 7f2ea34 commit 5420096

File tree

16 files changed

+370
-53
lines changed

16 files changed

+370
-53
lines changed

README.md

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,7 @@ and use resulting `_build/default/src/notabot.exe` binary.
2020

2121
## Running
2222

23-
Configuration is read at startup from `notabot.json` and `secrets.json` files
24-
according to `lib/notabot.atd` schema.
23+
At startup time, secrets are read from the local `secrets.json` file. The main configuration is read remotely from a `notabot.json` file in the default branch, and its schema is defined in `lib/notabot.atd`.
2524

2625
### Documentation
2726

documentation/config_docs.md

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -36,15 +36,16 @@ Config file is where the variables affecting the behaviour of notabot are define
3636
**example**
3737
```json
3838
"status_rules": {
39-
"name": [
39+
"title": [
4040
"default",
4141
"buildkite/pipeline2"
4242
],
4343
"status": {
4444
"pending": false,
45-
"success": true,
45+
"success": "once",
4646
"failure": true,
47-
"error": true
47+
"error": true,
48+
"cancelled": "^\\(Build #[0-9]+ canceled by .+\\|Failed (exit status 255)\\)$"
4849
}
4950
},
5051
```
@@ -56,7 +57,16 @@ Config file is where the variables affecting the behaviour of notabot are define
5657

5758
### Status State
5859

59-
A json object with fields of bools for each status type. Set them to true to suppress status of that type.
60+
A json object with fields of bools for each status type.
61+
62+
| value | description | optional | default |
63+
|-|-|-|-|
64+
| `pending` | `true` to notify; `false` to ignore | No | - |
65+
| `success` | `true` to notify; `false` to notify all; `"once"` to notify the first and ignore subsequent consecutive successes| No | - |
66+
| `failure` | `true` to notify; `false` to ignore | No | - |
67+
| `error` | `true` to notify; `false` to ignore | No | - |
68+
| `cancelled` | provide regex to ignore `failure` notifications with a description that matches it | Yes | - |
69+
6070

6171
## Label Config
6272

lib/action.ml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -118,22 +118,22 @@ let partition_push cfg n =
118118
| [] -> None
119119
| l -> Some (chan, { n with commits = l }))
120120

121-
let filter_label rules label =
121+
let filter_label rules (label : Github_j.label) =
122122
rules
123123
|> List.filter_map ~f:(fun rule ->
124124
match touching_label rule label.name with
125125
| false -> None
126126
| true -> Some rule.chan)
127127

128-
let partition_label cfg labels =
128+
let partition_label cfg (labels : Github_j.label list) =
129129
let default = Option.to_list cfg.label_rules.default in
130130
match labels with
131131
| [] -> default
132132
| labels ->
133133
let rules = cfg.label_rules.rules in
134134
let channels =
135135
labels
136-
|> List.map ~f:(fun label ->
136+
|> List.map ~f:(fun (label : Github_j.label) ->
137137
match filter_label rules label with
138138
| [] -> default
139139
| l -> l)
@@ -224,7 +224,7 @@ let partition_status (ctx : Context.t) (n : status_notification) =
224224
match List.exists n.branches ~f:(fun { name } -> String.equal name main_branch_name) with
225225
| false -> default ()
226226
| true ->
227-
( match%lwt Github.generate_query_commmit cfg ~url:n.commit.url ~sha:n.commit.sha with
227+
( match%lwt Github.generate_query_commit cfg ~url:n.commit.url ~sha:n.commit.sha with
228228
| None -> default ()
229229
| Some commit ->
230230
(*

lib/config.ml

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,11 @@ let make (json_config : Notabot_t.config) (secrets : Notabot_t.secrets) =
9696
status_rules;
9797
}
9898

99-
let load path secrets =
100-
let config = Notabot_j.config_of_string @@ Stdio.In_channel.read_all path in
101-
let secrets = Notabot_j.secrets_of_string @@ Stdio.In_channel.read_all secrets in
99+
let load_config_file ~config_path = Notabot_j.config_of_string @@ Stdio.In_channel.read_all config_path
100+
101+
let load_secrets_file ~secrets_path = Notabot_j.secrets_of_string @@ Stdio.In_channel.read_all secrets_path
102+
103+
let load ~config_path ~secrets_path =
104+
let config = load_config_file ~config_path in
105+
let secrets = load_secrets_file ~secrets_path in
102106
make config secrets

lib/context.ml

Lines changed: 112 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,76 @@
1+
open Devkit
2+
3+
let log = Log.from "context"
4+
5+
exception Context_error of string
6+
7+
type cfg_make_args =
8+
| LocalMake of string
9+
| RemoteMake of string * Github.t
10+
11+
type cfg_origin =
12+
| Local
13+
| Remote
14+
115
type data = {
2-
cfg : string;
3-
secrets : string;
4-
state : string;
16+
mutable cfg_path : string;
17+
mutable cfg_filename : string;
18+
cfg_source : cfg_origin;
19+
cfg_action_after_refresh : Config.t -> unit;
20+
secrets_path : string;
21+
state_path : string;
522
disable_write : bool;
623
}
724

825
type t = {
926
mutable state : Notabot_t.state;
1027
mutable cfg : Config.t;
28+
secrets : Notabot_t.secrets;
1129
data : data;
1230
}
1331

14-
let refresh_config ctx = ctx.cfg <- Config.load ctx.data.cfg ctx.data.secrets
32+
type context_thunk = {
33+
secrets : Notabot_j.secrets;
34+
thunk : ?req:Github.t -> unit -> t Lwt.t;
35+
mutable ctx : t option;
36+
}
37+
38+
let get_secrets secrets_path = Config.load_secrets_file ~secrets_path
39+
40+
let load_config_json_local config_path = Lwt.return @@ Config.load_config_file ~config_path
41+
42+
let resolve_cfg_getter = function
43+
| Local -> load_config_json_local
44+
| Remote -> Github.load_config_json
45+
46+
let refresh_config ctx =
47+
( match ctx.data.cfg_source with
48+
| Local -> log#info "attempting to retrieve config locally"
49+
| Remote ->
50+
match ctx.secrets.gh_token with
51+
| None -> log#info "attempting to retrieve config remotely without gh_token"
52+
| Some _ -> log#info "attempting to retrieve config remotely with gh_token"
53+
);
54+
let getter = resolve_cfg_getter ctx.data.cfg_source in
55+
let%lwt cfg_json = getter ctx.data.cfg_path in
56+
ctx.cfg <- Config.make cfg_json ctx.secrets;
57+
ctx.data.cfg_action_after_refresh ctx.cfg;
58+
Lwt.return_unit
1559

1660
let refresh_and_get_config ctx =
17-
refresh_config ctx;
18-
ctx.cfg
61+
let%lwt () = refresh_config ctx in
62+
Lwt.return ctx.cfg
63+
64+
let change_remote_url filename ctx req =
65+
match ctx.data.cfg_source with
66+
| Local -> raise @@ Context_error "can't load remote config from a local context"
67+
| Remote ->
68+
ctx.data.cfg_filename <- filename;
69+
let url = Github.get_remote_config_json_url filename ?token:ctx.secrets.gh_token req in
70+
ctx.data.cfg_path <- url;
71+
refresh_config ctx
1972

20-
let refresh_state ctx = ctx.state <- State.load ctx.data.state
73+
let refresh_state ctx = ctx.state <- State.load ctx.data.state_path
2174

2275
let refresh_and_get_state ctx =
2376
refresh_state ctx;
@@ -26,15 +79,62 @@ let refresh_and_get_state ctx =
2679
let update_state ctx event =
2780
ctx.state <- State.update_state ctx.state event;
2881
match ctx.data.disable_write with
29-
| false -> State.save ctx.data.state ctx.state
82+
| false -> State.save ctx.data.state_path ctx.state
3083
| true -> ()
3184

3285
let update_and_get_state ctx event =
3386
update_state ctx event;
3487
ctx.state
3588

36-
let make ~state_path ~cfg_path ~secrets_path ?(disable_write = false) () =
37-
let cfg = Config.load cfg_path secrets_path in
89+
let make_with_secrets ~state_path ~cfg_args ~secrets_path ~(secrets : Notabot_t.secrets) ?(disable_write = false)
90+
?(cfg_action_after_refresh = fun _ -> ()) ()
91+
=
92+
let data_cfg_path, cfg_source, cfg_json, cfg_filename =
93+
match cfg_args with
94+
| LocalMake p -> p, Local, load_config_json_local p, p
95+
| RemoteMake (filename, r) ->
96+
let token = secrets.gh_token in
97+
let url = Github.get_remote_config_json_url filename ?token r in
98+
let cfg_json = Github.load_config_json @@ Github.get_remote_config_json_url filename ?token r in
99+
url, Remote, cfg_json, filename
100+
in
101+
let%lwt cfg_json = cfg_json in
102+
let data =
103+
{
104+
cfg_path = data_cfg_path;
105+
cfg_source;
106+
cfg_action_after_refresh;
107+
secrets_path;
108+
state_path;
109+
disable_write;
110+
cfg_filename;
111+
}
112+
in
113+
let cfg = Config.make cfg_json secrets in
38114
let state = State.load state_path in
39-
let data = { cfg = cfg_path; secrets = secrets_path; state = state_path; disable_write } in
40-
{ cfg; state; data }
115+
Lwt.return { cfg; state; secrets; data }
116+
117+
let make ~state_path ~cfg_args ~secrets_path ?disable_write ?cfg_action_after_refresh () =
118+
let secrets = get_secrets secrets_path in
119+
make_with_secrets ~state_path ~cfg_args ~secrets_path ~secrets ?disable_write ?cfg_action_after_refresh ()
120+
121+
let make_thunk ~state_path ~cfg_path_or_remote_filename ~secrets_path ?disable_write ?cfg_action_after_refresh () =
122+
let secrets = get_secrets secrets_path in
123+
let make_args ?req () =
124+
match req with
125+
| None -> LocalMake cfg_path_or_remote_filename
126+
| Some r -> RemoteMake (cfg_path_or_remote_filename, r)
127+
in
128+
let thunk ?req () =
129+
make_with_secrets ~state_path ~cfg_args:(make_args ?req ()) ~secrets_path ~secrets ?disable_write
130+
?cfg_action_after_refresh ()
131+
in
132+
{ secrets; thunk; ctx = None }
133+
134+
let resolve_ctx_in_thunk ctx_thunk req =
135+
match ctx_thunk.ctx with
136+
| Some ctx -> Lwt.return ctx
137+
| None ->
138+
let%lwt ctx = ctx_thunk.thunk ~req () in
139+
let%lwt () = Lwt.return @@ (ctx_thunk.ctx <- Some ctx) in
140+
Lwt.return ctx

lib/context.mli

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
exception Context_error of string
2+
3+
type cfg_make_args =
4+
| LocalMake of string
5+
| RemoteMake of string * Github.t
6+
7+
type cfg_origin =
8+
| Local
9+
| Remote
10+
11+
type data = {
12+
mutable cfg_path : string;
13+
mutable cfg_filename : string;
14+
cfg_source : cfg_origin;
15+
cfg_action_after_refresh : Config.t -> unit;
16+
secrets_path : string;
17+
state_path : string;
18+
disable_write : bool;
19+
}
20+
21+
type t = {
22+
mutable state : Notabot_t.state;
23+
mutable cfg : Config.t;
24+
secrets : Notabot_t.secrets;
25+
data : data;
26+
}
27+
28+
type context_thunk = {
29+
secrets : Notabot_j.secrets;
30+
thunk : ?req:Github.t -> unit -> t Lwt.t;
31+
mutable ctx : t option;
32+
}
33+
34+
val refresh_config : t -> unit Lwt.t
35+
36+
val refresh_and_get_config : t -> Config.t Lwt.t
37+
38+
val change_remote_url : string -> t -> Github.t -> unit Lwt.t
39+
40+
val refresh_state : t -> unit
41+
42+
val refresh_and_get_state : t -> Notabot_t.state
43+
44+
val update_state : t -> Github.t -> unit
45+
46+
val update_and_get_state : t -> Github.t -> Notabot_t.state
47+
48+
val make_with_secrets
49+
: state_path:string ->
50+
cfg_args:cfg_make_args ->
51+
secrets_path:string ->
52+
secrets:Notabot_t.secrets ->
53+
?disable_write:bool ->
54+
?cfg_action_after_refresh:(Config.t -> unit) ->
55+
unit ->
56+
t Lwt.t
57+
58+
val make
59+
: state_path:string ->
60+
cfg_args:cfg_make_args ->
61+
secrets_path:string ->
62+
?disable_write:bool ->
63+
?cfg_action_after_refresh:(Config.t -> unit) ->
64+
unit ->
65+
t Lwt.t
66+
67+
val make_thunk
68+
: state_path:string ->
69+
cfg_path_or_remote_filename:string ->
70+
secrets_path:string ->
71+
?disable_write:bool ->
72+
?cfg_action_after_refresh:(Config.t -> unit) ->
73+
unit ->
74+
context_thunk
75+
76+
val resolve_ctx_in_thunk : context_thunk -> Github.t -> t Lwt.t

lib/dune

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
(library
22
(name lib)
33
(libraries atdgen atdgen-runtime base base.caml biniou cstruct curl curl.lwt
4-
devkit devkit.core hex lwt lwt.unix nocrypto omd re stdio uri yojson)
4+
devkit devkit.core extlib hex lwt lwt.unix nocrypto omd re stdio uri
5+
yojson)
56
(preprocess
67
(pps lwt_ppx)))
78

lib/github.atd

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -231,3 +231,11 @@ type commit_comment_notification = {
231231
comment: comment;
232232
sender: user;
233233
}
234+
235+
type content_api_response = {
236+
name : string;
237+
path : string;
238+
size : int;
239+
encoding : string;
240+
content : string;
241+
}

0 commit comments

Comments
 (0)