1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
|
# CODEOWNERS
## Overview
Project Tick uses a code ownership system based on the `ci/OWNERS` file. This file
follows the same syntax as GitHub's native `CODEOWNERS` file but is stored in a
custom location and validated by a patched version of the
[codeowners-validator](https://github.com/mszostok/codeowners-validator) tool.
The OWNERS file serves two purposes:
1. **Automated review routing** — PR authors know who to request reviews from
2. **Structural validation** — CI checks that referenced paths and users exist
---
## File Location and Format
### Location
```
ci/OWNERS
```
Unlike GitHub's native CODEOWNERS (which must be in `.github/CODEOWNERS`,
`CODEOWNERS`, or `docs/CODEOWNERS`), Project Tick stores ownership data in
`ci/OWNERS` to keep CI infrastructure colocated.
### Syntax
The file uses CODEOWNERS syntax:
```
# Comments start with #
# Pattern followed by one or more @owner references
/path/pattern/ @owner1 @owner2
```
### Header
```
# This file describes who owns what in the Project Tick CI infrastructure.
# Users/teams will get review requests for PRs that change their files.
#
# This file uses the same syntax as the natively supported CODEOWNERS file,
# see https://help.github.com/articles/about-codeowners/ for documentation.
#
# Validated by ci/codeowners-validator.
```
---
## Ownership Map
The OWNERS file maps every major directory and subdirectory in the monorepo to
code owners. Below is the complete ownership mapping:
### GitHub Infrastructure
```
/.github/actions/change-analysis/ @YongDo-Hyun
/.github/actions/meshmc/package/ @YongDo-Hyun
/.github/actions/meshmc/setup-dependencies/ @YongDo-Hyun
/.github/actions/mnv/test_artefacts/ @YongDo-Hyun
/.github/codeql/ @YongDo-Hyun
/.github/ISSUE_TEMPLATE/ @YongDo-Hyun
/.github/workflows/ @YongDo-Hyun
```
### Archived Projects
```
/archived/projt-launcher/ @YongDo-Hyun
/archived/projt-minicraft-modpack/ @YongDo-Hyun
/archived/projt-modpack/ @YongDo-Hyun
/archived/ptlibzippy/ @YongDo-Hyun
```
### Core Projects
```
/cgit/* @YongDo-Hyun
/cgit/contrib/* @YongDo-Hyun
/cgit/contrib/hooks/ @YongDo-Hyun
/cgit/filters/ @YongDo-Hyun
/cgit/tests/ @YongDo-Hyun
/cmark/* @YongDo-Hyun
/cmark/api_test/ @YongDo-Hyun
/cmark/bench/ @YongDo-Hyun
/cmark/cmake/ @YongDo-Hyun
/cmark/data/ @YongDo-Hyun
/cmark/fuzz/ @YongDo-Hyun
/cmark/man/ @YongDo-Hyun
/cmark/src/ @YongDo-Hyun
/cmark/test/ @YongDo-Hyun
/cmark/tools/ @YongDo-Hyun
/cmark/wrappers/ @YongDo-Hyun
```
### Corebinutils (every utility individually owned)
```
/corebinutils/* @YongDo-Hyun
/corebinutils/cat/ @YongDo-Hyun
/corebinutils/chflags/ @YongDo-Hyun
/corebinutils/chmod/ @YongDo-Hyun
/corebinutils/contrib/* @YongDo-Hyun
/corebinutils/contrib/libc-vis/ @YongDo-Hyun
/corebinutils/contrib/libedit/ @YongDo-Hyun
/corebinutils/contrib/printf/ @YongDo-Hyun
/corebinutils/cp/ @YongDo-Hyun
...
/corebinutils/uuidgen/ @YongDo-Hyun
```
### Other Projects
```
/forgewrapper/* @YongDo-Hyun
/forgewrapper/gradle/ @YongDo-Hyun
/forgewrapper/jigsaw/ @YongDo-Hyun
/forgewrapper/src/ @YongDo-Hyun
/genqrcode/* @YongDo-Hyun
/genqrcode/cmake/ @YongDo-Hyun
/genqrcode/tests/ @YongDo-Hyun
/genqrcode/use/ @YongDo-Hyun
/hooks/ @YongDo-Hyun
/images4docker/ @YongDo-Hyun
/json4cpp/* @YongDo-Hyun
/json4cpp/.reuse/ @YongDo-Hyun
/json4cpp/cmake/ @YongDo-Hyun
/json4cpp/docs/ @YongDo-Hyun
/json4cpp/include/* @YongDo-Hyun
...
/libnbtplusplus/* @YongDo-Hyun
/libnbtplusplus/include/* @YongDo-Hyun
...
/LICENSES/ @YongDo-Hyun
/meshmc/* @YongDo-Hyun
/meshmc/branding/ @YongDo-Hyun
/meshmc/buildconfig/ @YongDo-Hyun
/meshmc/cmake/* @YongDo-Hyun
/meshmc/launcher/* @YongDo-Hyun
...
```
---
## Pattern Syntax
### Glob Rules
| Pattern | Matches |
|---------------|------------------------------------------------------|
| `/path/` | All files directly under `path/` |
| `/path/*` | All files directly under `path/` (explicit) |
| `/path/**` | All files recursively under `path/` |
| `*.js` | All `.js` files everywhere |
| `/path/*.md` | All `.md` files directly under `path/` |
### Ownership Resolution
When multiple patterns match a file, the **last matching rule** wins (just like
Git's `.gitignore` and GitHub's native CODEOWNERS):
```
/meshmc/* @teamA # Matches all direct files
/meshmc/launcher/* @teamB # More specific — wins for launcher files
```
A PR modifying `meshmc/launcher/main.cpp` would require review from `@teamB`.
### Explicit Directory Listing
The OWNERS file explicitly lists individual subdirectories rather than using `**`
recursive globs. This is intentional:
1. **Precision** — Each directory has explicit ownership
2. **Validation** — The codeowners-validator checks that each listed path exists
3. **Documentation** — The file serves as a directory map of the monorepo
---
## Validation
### codeowners-validator
The CI runs a patched version of `codeowners-validator` against the OWNERS file.
The tool is built from source with Project Tick–specific patches.
#### What It Validates
| Check | Description |
|-------------------------|------------------------------------------------|
| **Path existence** | All paths in OWNERS exist in the repository |
| **User/team existence** | All `@` references are valid GitHub users/teams|
| **Syntax** | Pattern syntax is valid CODEOWNERS format |
| **No orphaned patterns** | Patterns match at least one file |
#### Custom Patches
Two patches are applied to the upstream validator:
**1. Custom OWNERS file path** (`owners-file-name.patch`)
```go
func openCodeownersFile(dir string) (io.Reader, error) {
if file, ok := os.LookupEnv("OWNERS_FILE"); ok {
return fs.Open(file)
}
// ... default CODEOWNERS paths
}
```
Set `OWNERS_FILE=ci/OWNERS` to validate the custom location.
**2. Removed write-access requirement** (`permissions.patch`)
GitHub's native CODEOWNERS requires that listed users have write access to the
repository. Project Tick's OWNERS file is used for review routing, not branch
protection, so this check is removed:
```go
// Before: required push permission
if t.Permissions["push"] { return nil }
return newValidateError("Team cannot review PRs...")
// After: any team membership is sufficient
return nil
```
Also removes the `github.ScopeReadOrg` requirement from required OAuth scopes,
allowing the validator to work with tokens generated for GitHub Apps.
### Running Validation Locally
```bash
cd ci/
nix-shell # enters the CI dev shell with codeowners-validator available
# Set the custom OWNERS file path:
export OWNERS_FILE=ci/OWNERS
# Run validation:
codeowners-validator
```
Or build and run directly:
```bash
nix-build ci/ -A codeownersValidator
OWNERS_FILE=ci/OWNERS ./result/bin/codeowners-validator
```
---
## MAINTAINERS File Relationship
In addition to `ci/OWNERS`, individual projects may have a `MAINTAINERS` file
(e.g., `archived/projt-launcher/MAINTAINERS`):
```
# MAINTAINERS
#
# Fields:
# - Name: Display name
# - GitHub: GitHub handle (with @)
# - Email: Primary contact email
# - Paths: Comma-separated glob patterns (repo-relative)
[Mehmet Samet Duman]
GitHub: @YongDo-Hyun
Email: yongdohyun@mail.projecttick.org
Paths: **
```
The `MAINTAINERS` file provides additional metadata (email, display name) that
`OWNERS` doesn't support. The two files serve complementary purposes:
| File | Purpose | Format |
|--------------|--------------------------------------|-------------------|
| `ci/OWNERS` | Automated review routing via CI | CODEOWNERS syntax |
| `MAINTAINERS`| Human-readable contact information | INI-style blocks |
---
## Review Requirements
### How Reviews Are Triggered
When a PR modifies files matching an OWNERS pattern:
1. The workflow identifies which owners are responsible for the changed paths
2. Review requests are sent to the matching owners
3. At least one approving review from a code owner is typically required before merge
### Bot-Managed Reviews
The CI bot (`github-actions[bot]`) manages automated reviews via `ci/github-script/reviews.js`:
- Reviews are tagged with a `reviewKey` comment for identification
- When issues are resolved, bot reviews are automatically dismissed or minimized
- The `CHANGES_REQUESTED` state blocks merge until the review is dismissed
---
## Adding Ownership Entries
### For a New Project Directory
1. Add ownership patterns to `ci/OWNERS`:
```
/newproject/* @owner-handle
/newproject/src/ @owner-handle
/newproject/tests/ @owner-handle
```
2. List every subdirectory explicitly (not just the top-level with `**`)
3. Run the validator locally:
```bash
cd ci/
nix-shell
OWNERS_FILE=ci/OWNERS codeowners-validator
```
4. Commit with a CI scope:
```
ci(repo): add ownership for newproject
```
### For a New Team or User
Simply reference the new `@handle` in the ownership patterns:
```
/some/path/ @existing-owner @new-owner
```
The validator will check that `@new-owner` exists in the GitHub organization.
---
## Limitations
### No Recursive Globs in Current File
The current OWNERS file uses explicit directory listings rather than `/**` recursive
globs. This means:
- New subdirectories must be manually added to OWNERS
- Deeply nested directories need their own entries
- The file can grow large for projects with many subdirectories
### Single Organization Scope
All `@` references must be members of the repository's GitHub organization,
or GitHub users with access to the repository.
### No Per-File Patterns
The file doesn't currently use file-level patterns (e.g., `*.nix @nix-team`).
Ownership is assigned at the directory level.
|