tenseleyflow/shithub / 0bf7e12

Browse files

S24: check_runs migration 0025 + queries + sqlc regen

Authored by mfwolffe <wolffemf@dukes.jmu.edu>
SHA
0bf7e12de050dd2cfb393aa25234aab57f8f5237
Parents
062a225
Tree
c7cc65b

17 changed files

StatusFile+-
M internal/auth/policy/sqlc/models.go 136 15
A internal/checks/queries/checks.sql 95 0
A internal/checks/sqlc/checks.sql.go 463 0
A internal/checks/sqlc/db.go 25 0
C internal/checks/sqlc/models.go 0 0
A internal/checks/sqlc/querier.go 42 0
M internal/issues/sqlc/models.go 136 15
M internal/meta/sqlc/models.go 136 15
A internal/migrationsfs/migrations/0025_check_runs.sql 94 0
M internal/pulls/sqlc/models.go 136 15
M internal/repos/queries/branch_protection.sql 12 2
M internal/repos/sqlc/branch_protection.sql.go 26 2
M internal/repos/sqlc/models.go 136 15
M internal/repos/sqlc/querier.go 3 0
M internal/users/sqlc/models.go 136 15
M internal/worker/sqlc/models.go 136 15
M sqlc.yaml 16 0
internal/auth/policy/sqlc/models.gomodified
@@ -12,6 +12,98 @@ import (
1212
 	"github.com/jackc/pgx/v5/pgtype"
1313
 )
1414
 
15
+type CheckConclusion string
16
+
17
+const (
18
+	CheckConclusionSuccess        CheckConclusion = "success"
19
+	CheckConclusionFailure        CheckConclusion = "failure"
20
+	CheckConclusionNeutral        CheckConclusion = "neutral"
21
+	CheckConclusionCancelled      CheckConclusion = "cancelled"
22
+	CheckConclusionSkipped        CheckConclusion = "skipped"
23
+	CheckConclusionTimedOut       CheckConclusion = "timed_out"
24
+	CheckConclusionActionRequired CheckConclusion = "action_required"
25
+	CheckConclusionStale          CheckConclusion = "stale"
26
+)
27
+
28
+func (e *CheckConclusion) Scan(src interface{}) error {
29
+	switch s := src.(type) {
30
+	case []byte:
31
+		*e = CheckConclusion(s)
32
+	case string:
33
+		*e = CheckConclusion(s)
34
+	default:
35
+		return fmt.Errorf("unsupported scan type for CheckConclusion: %T", src)
36
+	}
37
+	return nil
38
+}
39
+
40
+type NullCheckConclusion struct {
41
+	CheckConclusion CheckConclusion
42
+	Valid           bool // Valid is true if CheckConclusion is not NULL
43
+}
44
+
45
+// Scan implements the Scanner interface.
46
+func (ns *NullCheckConclusion) Scan(value interface{}) error {
47
+	if value == nil {
48
+		ns.CheckConclusion, ns.Valid = "", false
49
+		return nil
50
+	}
51
+	ns.Valid = true
52
+	return ns.CheckConclusion.Scan(value)
53
+}
54
+
55
+// Value implements the driver Valuer interface.
56
+func (ns NullCheckConclusion) Value() (driver.Value, error) {
57
+	if !ns.Valid {
58
+		return nil, nil
59
+	}
60
+	return string(ns.CheckConclusion), nil
61
+}
62
+
63
+type CheckStatus string
64
+
65
+const (
66
+	CheckStatusQueued     CheckStatus = "queued"
67
+	CheckStatusInProgress CheckStatus = "in_progress"
68
+	CheckStatusCompleted  CheckStatus = "completed"
69
+	CheckStatusPending    CheckStatus = "pending"
70
+)
71
+
72
+func (e *CheckStatus) Scan(src interface{}) error {
73
+	switch s := src.(type) {
74
+	case []byte:
75
+		*e = CheckStatus(s)
76
+	case string:
77
+		*e = CheckStatus(s)
78
+	default:
79
+		return fmt.Errorf("unsupported scan type for CheckStatus: %T", src)
80
+	}
81
+	return nil
82
+}
83
+
84
+type NullCheckStatus struct {
85
+	CheckStatus CheckStatus
86
+	Valid       bool // Valid is true if CheckStatus is not NULL
87
+}
88
+
89
+// Scan implements the Scanner interface.
90
+func (ns *NullCheckStatus) Scan(value interface{}) error {
91
+	if value == nil {
92
+		ns.CheckStatus, ns.Valid = "", false
93
+		return nil
94
+	}
95
+	ns.Valid = true
96
+	return ns.CheckStatus.Scan(value)
97
+}
98
+
99
+// Value implements the driver Valuer interface.
100
+func (ns NullCheckStatus) Value() (driver.Value, error) {
101
+	if !ns.Valid {
102
+		return nil, nil
103
+	}
104
+	return string(ns.CheckStatus), nil
105
+}
106
+
15107
 type CollabRole string
16108
 
17109
 const (
@@ -651,6 +743,35 @@ type BranchProtectionRule struct {
651743
 	RequiredReviewCount            int32
652744
 	DismissStaleReviewsOnPush      bool
653745
 	RequireCodeOwnerReview         bool
746
+	DismissStaleStatusChecksOnPush bool
747
+}
748
+
749
+type CheckRun struct {
750
+	ID          int64
751
+	SuiteID     int64
752
+	RepoID      int64
753
+	HeadSha     string
754
+	Name        string
755
+	Status      CheckStatus
756
+	Conclusion  NullCheckConclusion
757
+	StartedAt   pgtype.Timestamptz
758
+	CompletedAt pgtype.Timestamptz
759
+	DetailsUrl  string
760
+	Output      []byte
761
+	ExternalID  pgtype.Text
762
+	CreatedAt   pgtype.Timestamptz
763
+	UpdatedAt   pgtype.Timestamptz
764
+}
765
+
766
+type CheckSuite struct {
767
+	ID         int64
768
+	RepoID     int64
769
+	HeadSha    string
770
+	AppSlug    string
771
+	Status     CheckStatus
772
+	Conclusion NullCheckConclusion
773
+	CreatedAt  pgtype.Timestamptz
774
+	UpdatedAt  pgtype.Timestamptz
654775
 }
655776
 
656777
 type EmailVerification struct {
internal/checks/queries/checks.sqladded
@@ -0,0 +1,95 @@
1
+-- SPDX-License-Identifier: AGPL-3.0-or-later
2
+
3
+-- ─── check_suites ────────────────────────────────────────────────────
4
+
5
+-- name: GetOrCreateCheckSuite :one
6
+-- Idempotent suite-by-(repo, head_sha, app_slug) lookup. Used by every
7
+-- check-run create so consumers don't need to manage suite ids. ON
8
+-- CONFLICT … DO UPDATE returns the existing row when the unique
9
+-- (repo_id, head_sha, app_slug) already exists; otherwise returns the
10
+-- freshly inserted one.
11
+INSERT INTO check_suites (repo_id, head_sha, app_slug)
12
+VALUES ($1, $2, $3)
13
+ON CONFLICT (repo_id, head_sha, app_slug) DO UPDATE
14
+    SET app_slug = EXCLUDED.app_slug
15
+RETURNING *;
16
+
17
+-- name: GetCheckSuite :one
18
+SELECT * FROM check_suites WHERE id = $1;
19
+
20
+-- name: ListCheckSuitesForCommit :many
21
+SELECT * FROM check_suites
22
+WHERE repo_id = $1 AND head_sha = $2
23
+ORDER BY app_slug;
24
+
25
+-- name: UpdateCheckSuiteRollup :exec
26
+-- Persists the rollup result computed in Go (suite_rollup.go).
27
+UPDATE check_suites
28
+SET status = $2,
29
+    conclusion = sqlc.narg(conclusion)::check_conclusion
30
+WHERE id = $1;
31
+
32
+-- name: ListCheckSuiteIDsForHead :many
33
+-- Used by the stale-on-push hook to flip queued/in_progress suites on
34
+-- the previous head to conclusion='stale'.
35
+SELECT id FROM check_suites
36
+WHERE repo_id = $1 AND head_sha = $2 AND status <> 'completed';
37
+
38
+-- name: MarkCheckSuiteStale :exec
39
+UPDATE check_suites
40
+SET status = 'completed', conclusion = 'stale'
41
+WHERE id = $1;
42
+
43
+
44
+-- ─── check_runs ──────────────────────────────────────────────────────
45
+
46
+-- name: GetCheckRunByExternalID :one
47
+-- External-system create dedupe: lookup by (repo, head_sha, name,
48
+-- external_id). NULL external_id never matches via this query.
49
+SELECT * FROM check_runs
50
+WHERE repo_id = $1 AND head_sha = $2 AND name = $3 AND external_id = $4;
51
+
52
+-- name: CreateCheckRun :one
53
+INSERT INTO check_runs (
54
+    suite_id, repo_id, head_sha, name,
55
+    status, conclusion,
56
+    started_at, completed_at,
57
+    details_url, output, external_id
58
+) VALUES (
59
+    $1, $2, $3, $4,
60
+    $5, sqlc.narg(conclusion)::check_conclusion,
61
+    sqlc.narg(started_at)::timestamptz, sqlc.narg(completed_at)::timestamptz,
62
+    $6, $7, sqlc.narg(external_id)::text
63
+)
64
+RETURNING *;
65
+
66
+-- name: GetCheckRun :one
67
+SELECT * FROM check_runs WHERE id = $1;
68
+
69
+-- name: UpdateCheckRun :exec
70
+UPDATE check_runs
71
+SET status = $2,
72
+    conclusion = sqlc.narg(conclusion)::check_conclusion,
73
+    started_at = sqlc.narg(started_at)::timestamptz,
74
+    completed_at = sqlc.narg(completed_at)::timestamptz,
75
+    details_url = $3,
76
+    output = $4
77
+WHERE id = $1;
78
+
79
+-- name: ListCheckRunsForCommit :many
80
+SELECT * FROM check_runs
81
+WHERE repo_id = $1 AND head_sha = $2
82
+ORDER BY name;
83
+
84
+-- name: ListCheckRunsBySuite :many
85
+SELECT * FROM check_runs
86
+WHERE suite_id = $1
87
+ORDER BY name;
88
+
89
+-- name: GetLatestCheckRunByName :one
90
+-- Required-check evaluator: most recent run with the given name on the
91
+-- specified head_sha.
92
+SELECT * FROM check_runs
93
+WHERE repo_id = $1 AND head_sha = $2 AND name = $3
94
+ORDER BY created_at DESC
95
+LIMIT 1;
internal/checks/sqlc/checks.sql.goadded
@@ -0,0 +1,463 @@
1
+// Code generated by sqlc. DO NOT EDIT.
2
+// versions:
3
+//   sqlc v1.31.1
4
+// source: checks.sql
5
+
6
+package checksdb
7
+
8
+import (
9
+	"context"
10
+
11
+	"github.com/jackc/pgx/v5/pgtype"
12
+)
13
+
14
+const createCheckRun = `-- name: CreateCheckRun :one
15
+INSERT INTO check_runs (
16
+    suite_id, repo_id, head_sha, name,
17
+    status, conclusion,
18
+    started_at, completed_at,
19
+    details_url, output, external_id
20
+) VALUES (
21
+    $1, $2, $3, $4,
22
+    $5, $8::check_conclusion,
23
+    $9::timestamptz, $10::timestamptz,
24
+    $6, $7, $11::text
25
+)
26
+RETURNING id, suite_id, repo_id, head_sha, name, status, conclusion, started_at, completed_at, details_url, output, external_id, created_at, updated_at
27
+`
28
+
29
+type CreateCheckRunParams struct {
30
+	SuiteID     int64
31
+	RepoID      int64
32
+	HeadSha     string
33
+	Name        string
34
+	Status      CheckStatus
35
+	DetailsUrl  string
36
+	Output      []byte
37
+	Conclusion  NullCheckConclusion
38
+	StartedAt   pgtype.Timestamptz
39
+	CompletedAt pgtype.Timestamptz
40
+	ExternalID  pgtype.Text
41
+}
42
+
43
+func (q *Queries) CreateCheckRun(ctx context.Context, db DBTX, arg CreateCheckRunParams) (CheckRun, error) {
44
+	row := db.QueryRow(ctx, createCheckRun,
45
+		arg.SuiteID,
46
+		arg.RepoID,
47
+		arg.HeadSha,
48
+		arg.Name,
49
+		arg.Status,
50
+		arg.DetailsUrl,
51
+		arg.Output,
52
+		arg.Conclusion,
53
+		arg.StartedAt,
54
+		arg.CompletedAt,
55
+		arg.ExternalID,
56
+	)
57
+	var i CheckRun
58
+	err := row.Scan(
59
+		&i.ID,
60
+		&i.SuiteID,
61
+		&i.RepoID,
62
+		&i.HeadSha,
63
+		&i.Name,
64
+		&i.Status,
65
+		&i.Conclusion,
66
+		&i.StartedAt,
67
+		&i.CompletedAt,
68
+		&i.DetailsUrl,
69
+		&i.Output,
70
+		&i.ExternalID,
71
+		&i.CreatedAt,
72
+		&i.UpdatedAt,
73
+	)
74
+	return i, err
75
+}
76
+
77
+const getCheckRun = `-- name: GetCheckRun :one
78
+SELECT id, suite_id, repo_id, head_sha, name, status, conclusion, started_at, completed_at, details_url, output, external_id, created_at, updated_at FROM check_runs WHERE id = $1
79
+`
80
+
81
+func (q *Queries) GetCheckRun(ctx context.Context, db DBTX, id int64) (CheckRun, error) {
82
+	row := db.QueryRow(ctx, getCheckRun, id)
83
+	var i CheckRun
84
+	err := row.Scan(
85
+		&i.ID,
86
+		&i.SuiteID,
87
+		&i.RepoID,
88
+		&i.HeadSha,
89
+		&i.Name,
90
+		&i.Status,
91
+		&i.Conclusion,
92
+		&i.StartedAt,
93
+		&i.CompletedAt,
94
+		&i.DetailsUrl,
95
+		&i.Output,
96
+		&i.ExternalID,
97
+		&i.CreatedAt,
98
+		&i.UpdatedAt,
99
+	)
100
+	return i, err
101
+}
102
+
103
+const getCheckRunByExternalID = `-- name: GetCheckRunByExternalID :one
104
+
105
+SELECT id, suite_id, repo_id, head_sha, name, status, conclusion, started_at, completed_at, details_url, output, external_id, created_at, updated_at FROM check_runs
106
+WHERE repo_id = $1 AND head_sha = $2 AND name = $3 AND external_id = $4
107
+`
108
+
109
+type GetCheckRunByExternalIDParams struct {
110
+	RepoID     int64
111
+	HeadSha    string
112
+	Name       string
113
+	ExternalID pgtype.Text
114
+}
115
+
116
+// ─── check_runs ──────────────────────────────────────────────────────
117
+// External-system create dedupe: lookup by (repo, head_sha, name,
118
+// external_id). NULL external_id never matches via this query.
119
+func (q *Queries) GetCheckRunByExternalID(ctx context.Context, db DBTX, arg GetCheckRunByExternalIDParams) (CheckRun, error) {
120
+	row := db.QueryRow(ctx, getCheckRunByExternalID,
121
+		arg.RepoID,
122
+		arg.HeadSha,
123
+		arg.Name,
124
+		arg.ExternalID,
125
+	)
126
+	var i CheckRun
127
+	err := row.Scan(
128
+		&i.ID,
129
+		&i.SuiteID,
130
+		&i.RepoID,
131
+		&i.HeadSha,
132
+		&i.Name,
133
+		&i.Status,
134
+		&i.Conclusion,
135
+		&i.StartedAt,
136
+		&i.CompletedAt,
137
+		&i.DetailsUrl,
138
+		&i.Output,
139
+		&i.ExternalID,
140
+		&i.CreatedAt,
141
+		&i.UpdatedAt,
142
+	)
143
+	return i, err
144
+}
145
+
146
+const getCheckSuite = `-- name: GetCheckSuite :one
147
+SELECT id, repo_id, head_sha, app_slug, status, conclusion, created_at, updated_at FROM check_suites WHERE id = $1
148
+`
149
+
150
+func (q *Queries) GetCheckSuite(ctx context.Context, db DBTX, id int64) (CheckSuite, error) {
151
+	row := db.QueryRow(ctx, getCheckSuite, id)
152
+	var i CheckSuite
153
+	err := row.Scan(
154
+		&i.ID,
155
+		&i.RepoID,
156
+		&i.HeadSha,
157
+		&i.AppSlug,
158
+		&i.Status,
159
+		&i.Conclusion,
160
+		&i.CreatedAt,
161
+		&i.UpdatedAt,
162
+	)
163
+	return i, err
164
+}
165
+
166
+const getLatestCheckRunByName = `-- name: GetLatestCheckRunByName :one
167
+SELECT id, suite_id, repo_id, head_sha, name, status, conclusion, started_at, completed_at, details_url, output, external_id, created_at, updated_at FROM check_runs
168
+WHERE repo_id = $1 AND head_sha = $2 AND name = $3
169
+ORDER BY created_at DESC
170
+LIMIT 1
171
+`
172
+
173
+type GetLatestCheckRunByNameParams struct {
174
+	RepoID  int64
175
+	HeadSha string
176
+	Name    string
177
+}
178
+
179
+// Required-check evaluator: most recent run with the given name on the
180
+// specified head_sha.
181
+func (q *Queries) GetLatestCheckRunByName(ctx context.Context, db DBTX, arg GetLatestCheckRunByNameParams) (CheckRun, error) {
182
+	row := db.QueryRow(ctx, getLatestCheckRunByName, arg.RepoID, arg.HeadSha, arg.Name)
183
+	var i CheckRun
184
+	err := row.Scan(
185
+		&i.ID,
186
+		&i.SuiteID,
187
+		&i.RepoID,
188
+		&i.HeadSha,
189
+		&i.Name,
190
+		&i.Status,
191
+		&i.Conclusion,
192
+		&i.StartedAt,
193
+		&i.CompletedAt,
194
+		&i.DetailsUrl,
195
+		&i.Output,
196
+		&i.ExternalID,
197
+		&i.CreatedAt,
198
+		&i.UpdatedAt,
199
+	)
200
+	return i, err
201
+}
202
+
203
+const getOrCreateCheckSuite = `-- name: GetOrCreateCheckSuite :one
204
+
205
+
206
+INSERT INTO check_suites (repo_id, head_sha, app_slug)
207
+VALUES ($1, $2, $3)
208
+ON CONFLICT (repo_id, head_sha, app_slug) DO UPDATE
209
+    SET app_slug = EXCLUDED.app_slug
210
+RETURNING id, repo_id, head_sha, app_slug, status, conclusion, created_at, updated_at
211
+`
212
+
213
+type GetOrCreateCheckSuiteParams struct {
214
+	RepoID  int64
215
+	HeadSha string
216
+	AppSlug string
217
+}
218
+
219
+// SPDX-License-Identifier: AGPL-3.0-or-later
220
+// ─── check_suites ────────────────────────────────────────────────────
221
+// Idempotent suite-by-(repo, head_sha, app_slug) lookup. Used by every
222
+// check-run create so consumers don't need to manage suite ids. ON
223
+// CONFLICT … DO UPDATE returns the existing row when the unique
224
+// (repo_id, head_sha, app_slug) already exists; otherwise returns the
225
+// freshly inserted one.
226
+func (q *Queries) GetOrCreateCheckSuite(ctx context.Context, db DBTX, arg GetOrCreateCheckSuiteParams) (CheckSuite, error) {
227
+	row := db.QueryRow(ctx, getOrCreateCheckSuite, arg.RepoID, arg.HeadSha, arg.AppSlug)
228
+	var i CheckSuite
229
+	err := row.Scan(
230
+		&i.ID,
231
+		&i.RepoID,
232
+		&i.HeadSha,
233
+		&i.AppSlug,
234
+		&i.Status,
235
+		&i.Conclusion,
236
+		&i.CreatedAt,
237
+		&i.UpdatedAt,
238
+	)
239
+	return i, err
240
+}
241
+
242
+const listCheckRunsBySuite = `-- name: ListCheckRunsBySuite :many
243
+SELECT id, suite_id, repo_id, head_sha, name, status, conclusion, started_at, completed_at, details_url, output, external_id, created_at, updated_at FROM check_runs
244
+WHERE suite_id = $1
245
+ORDER BY name
246
+`
247
+
248
+func (q *Queries) ListCheckRunsBySuite(ctx context.Context, db DBTX, suiteID int64) ([]CheckRun, error) {
249
+	rows, err := db.Query(ctx, listCheckRunsBySuite, suiteID)
250
+	if err != nil {
251
+		return nil, err
252
+	}
253
+	defer rows.Close()
254
+	items := []CheckRun{}
255
+	for rows.Next() {
256
+		var i CheckRun
257
+		if err := rows.Scan(
258
+			&i.ID,
259
+			&i.SuiteID,
260
+			&i.RepoID,
261
+			&i.HeadSha,
262
+			&i.Name,
263
+			&i.Status,
264
+			&i.Conclusion,
265
+			&i.StartedAt,
266
+			&i.CompletedAt,
267
+			&i.DetailsUrl,
268
+			&i.Output,
269
+			&i.ExternalID,
270
+			&i.CreatedAt,
271
+			&i.UpdatedAt,
272
+		); err != nil {
273
+			return nil, err
274
+		}
275
+		items = append(items, i)
276
+	}
277
+	if err := rows.Err(); err != nil {
278
+		return nil, err
279
+	}
280
+	return items, nil
281
+}
282
+
283
+const listCheckRunsForCommit = `-- name: ListCheckRunsForCommit :many
284
+SELECT id, suite_id, repo_id, head_sha, name, status, conclusion, started_at, completed_at, details_url, output, external_id, created_at, updated_at FROM check_runs
285
+WHERE repo_id = $1 AND head_sha = $2
286
+ORDER BY name
287
+`
288
+
289
+type ListCheckRunsForCommitParams struct {
290
+	RepoID  int64
291
+	HeadSha string
292
+}
293
+
294
+func (q *Queries) ListCheckRunsForCommit(ctx context.Context, db DBTX, arg ListCheckRunsForCommitParams) ([]CheckRun, error) {
295
+	rows, err := db.Query(ctx, listCheckRunsForCommit, arg.RepoID, arg.HeadSha)
296
+	if err != nil {
297
+		return nil, err
298
+	}
299
+	defer rows.Close()
300
+	items := []CheckRun{}
301
+	for rows.Next() {
302
+		var i CheckRun
303
+		if err := rows.Scan(
304
+			&i.ID,
305
+			&i.SuiteID,
306
+			&i.RepoID,
307
+			&i.HeadSha,
308
+			&i.Name,
309
+			&i.Status,
310
+			&i.Conclusion,
311
+			&i.StartedAt,
312
+			&i.CompletedAt,
313
+			&i.DetailsUrl,
314
+			&i.Output,
315
+			&i.ExternalID,
316
+			&i.CreatedAt,
317
+			&i.UpdatedAt,
318
+		); err != nil {
319
+			return nil, err
320
+		}
321
+		items = append(items, i)
322
+	}
323
+	if err := rows.Err(); err != nil {
324
+		return nil, err
325
+	}
326
+	return items, nil
327
+}
328
+
329
+const listCheckSuiteIDsForHead = `-- name: ListCheckSuiteIDsForHead :many
330
+SELECT id FROM check_suites
331
+WHERE repo_id = $1 AND head_sha = $2 AND status <> 'completed'
332
+`
333
+
334
+type ListCheckSuiteIDsForHeadParams struct {
335
+	RepoID  int64
336
+	HeadSha string
337
+}
338
+
339
+// Used by the stale-on-push hook to flip queued/in_progress suites on
340
+// the previous head to conclusion='stale'.
341
+func (q *Queries) ListCheckSuiteIDsForHead(ctx context.Context, db DBTX, arg ListCheckSuiteIDsForHeadParams) ([]int64, error) {
342
+	rows, err := db.Query(ctx, listCheckSuiteIDsForHead, arg.RepoID, arg.HeadSha)
343
+	if err != nil {
344
+		return nil, err
345
+	}
346
+	defer rows.Close()
347
+	items := []int64{}
348
+	for rows.Next() {
349
+		var id int64
350
+		if err := rows.Scan(&id); err != nil {
351
+			return nil, err
352
+		}
353
+		items = append(items, id)
354
+	}
355
+	if err := rows.Err(); err != nil {
356
+		return nil, err
357
+	}
358
+	return items, nil
359
+}
360
+
361
+const listCheckSuitesForCommit = `-- name: ListCheckSuitesForCommit :many
362
+SELECT id, repo_id, head_sha, app_slug, status, conclusion, created_at, updated_at FROM check_suites
363
+WHERE repo_id = $1 AND head_sha = $2
364
+ORDER BY app_slug
365
+`
366
+
367
+type ListCheckSuitesForCommitParams struct {
368
+	RepoID  int64
369
+	HeadSha string
370
+}
371
+
372
+func (q *Queries) ListCheckSuitesForCommit(ctx context.Context, db DBTX, arg ListCheckSuitesForCommitParams) ([]CheckSuite, error) {
373
+	rows, err := db.Query(ctx, listCheckSuitesForCommit, arg.RepoID, arg.HeadSha)
374
+	if err != nil {
375
+		return nil, err
376
+	}
377
+	defer rows.Close()
378
+	items := []CheckSuite{}
379
+	for rows.Next() {
380
+		var i CheckSuite
381
+		if err := rows.Scan(
382
+			&i.ID,
383
+			&i.RepoID,
384
+			&i.HeadSha,
385
+			&i.AppSlug,
386
+			&i.Status,
387
+			&i.Conclusion,
388
+			&i.CreatedAt,
389
+			&i.UpdatedAt,
390
+		); err != nil {
391
+			return nil, err
392
+		}
393
+		items = append(items, i)
394
+	}
395
+	if err := rows.Err(); err != nil {
396
+		return nil, err
397
+	}
398
+	return items, nil
399
+}
400
+
401
+const markCheckSuiteStale = `-- name: MarkCheckSuiteStale :exec
402
+UPDATE check_suites
403
+SET status = 'completed', conclusion = 'stale'
404
+WHERE id = $1
405
+`
406
+
407
+func (q *Queries) MarkCheckSuiteStale(ctx context.Context, db DBTX, id int64) error {
408
+	_, err := db.Exec(ctx, markCheckSuiteStale, id)
409
+	return err
410
+}
411
+
412
+const updateCheckRun = `-- name: UpdateCheckRun :exec
413
+UPDATE check_runs
414
+SET status = $2,
415
+    conclusion = $5::check_conclusion,
416
+    started_at = $6::timestamptz,
417
+    completed_at = $7::timestamptz,
418
+    details_url = $3,
419
+    output = $4
420
+WHERE id = $1
421
+`
422
+
423
+type UpdateCheckRunParams struct {
424
+	ID          int64
425
+	Status      CheckStatus
426
+	DetailsUrl  string
427
+	Output      []byte
428
+	Conclusion  NullCheckConclusion
429
+	StartedAt   pgtype.Timestamptz
430
+	CompletedAt pgtype.Timestamptz
431
+}
432
+
433
+func (q *Queries) UpdateCheckRun(ctx context.Context, db DBTX, arg UpdateCheckRunParams) error {
434
+	_, err := db.Exec(ctx, updateCheckRun,
435
+		arg.ID,
436
+		arg.Status,
437
+		arg.DetailsUrl,
438
+		arg.Output,
439
+		arg.Conclusion,
440
+		arg.StartedAt,
441
+		arg.CompletedAt,
442
+	)
443
+	return err
444
+}
445
+
446
+const updateCheckSuiteRollup = `-- name: UpdateCheckSuiteRollup :exec
447
+UPDATE check_suites
448
+SET status = $2,
449
+    conclusion = $3::check_conclusion
450
+WHERE id = $1
451
+`
452
+
453
+type UpdateCheckSuiteRollupParams struct {
454
+	ID         int64
455
+	Status     CheckStatus
456
+	Conclusion NullCheckConclusion
457
+}
458
+
459
+// Persists the rollup result computed in Go (suite_rollup.go).
460
+func (q *Queries) UpdateCheckSuiteRollup(ctx context.Context, db DBTX, arg UpdateCheckSuiteRollupParams) error {
461
+	_, err := db.Exec(ctx, updateCheckSuiteRollup, arg.ID, arg.Status, arg.Conclusion)
462
+	return err
463
+}
internal/checks/sqlc/db.goadded
@@ -0,0 +1,25 @@
1
+// Code generated by sqlc. DO NOT EDIT.
2
+// versions:
3
+//   sqlc v1.31.1
4
+
5
+package checksdb
6
+
7
+import (
8
+	"context"
9
+
10
+	"github.com/jackc/pgx/v5"
11
+	"github.com/jackc/pgx/v5/pgconn"
12
+)
13
+
14
+type DBTX interface {
15
+	Exec(context.Context, string, ...interface{}) (pgconn.CommandTag, error)
16
+	Query(context.Context, string, ...interface{}) (pgx.Rows, error)
17
+	QueryRow(context.Context, string, ...interface{}) pgx.Row
18
+}
19
+
20
+func New() *Queries {
21
+	return &Queries{}
22
+}
23
+
24
+type Queries struct {
25
+}
internal/auth/policy/sqlc/models.go → internal/checks/sqlc/models.gocopied (86% similarity)
@@ -2,7 +2,7 @@
22
 // versions:
33
 //   sqlc v1.31.1
44
 
5
-package policydb
5
+package checksdb
66
 
77
 import (
88
 	"database/sql/driver"
@@ -12,6 +12,98 @@ import (
1212
 	"github.com/jackc/pgx/v5/pgtype"
1313
 )
1414
 
15
+type CheckConclusion string
16
+
17
+const (
18
+	CheckConclusionSuccess        CheckConclusion = "success"
19
+	CheckConclusionFailure        CheckConclusion = "failure"
20
+	CheckConclusionNeutral        CheckConclusion = "neutral"
21
+	CheckConclusionCancelled      CheckConclusion = "cancelled"
22
+	CheckConclusionSkipped        CheckConclusion = "skipped"
23
+	CheckConclusionTimedOut       CheckConclusion = "timed_out"
24
+	CheckConclusionActionRequired CheckConclusion = "action_required"
25
+	CheckConclusionStale          CheckConclusion = "stale"
26
+)
27
+
28
+func (e *CheckConclusion) Scan(src interface{}) error {
29
+	switch s := src.(type) {
30
+	case []byte:
31
+		*e = CheckConclusion(s)
32
+	case string:
33
+		*e = CheckConclusion(s)
34
+	default:
35
+		return fmt.Errorf("unsupported scan type for CheckConclusion: %T", src)
36
+	}
37
+	return nil
38
+}
39
+
40
+type NullCheckConclusion struct {
41
+	CheckConclusion CheckConclusion
42
+	Valid           bool // Valid is true if CheckConclusion is not NULL
43
+}
44
+
45
+// Scan implements the Scanner interface.
46
+func (ns *NullCheckConclusion) Scan(value interface{}) error {
47
+	if value == nil {
48
+		ns.CheckConclusion, ns.Valid = "", false
49
+		return nil
50
+	}
51
+	ns.Valid = true
52
+	return ns.CheckConclusion.Scan(value)
53
+}
54
+
55
+// Value implements the driver Valuer interface.
56
+func (ns NullCheckConclusion) Value() (driver.Value, error) {
57
+	if !ns.Valid {
58
+		return nil, nil
59
+	}
60
+	return string(ns.CheckConclusion), nil
61
+}
62
+
63
+type CheckStatus string
64
+
65
+const (
66
+	CheckStatusQueued     CheckStatus = "queued"
67
+	CheckStatusInProgress CheckStatus = "in_progress"
68
+	CheckStatusCompleted  CheckStatus = "completed"
69
+	CheckStatusPending    CheckStatus = "pending"
70
+)
71
+
72
+func (e *CheckStatus) Scan(src interface{}) error {
73
+	switch s := src.(type) {
74
+	case []byte:
75
+		*e = CheckStatus(s)
76
+	case string:
77
+		*e = CheckStatus(s)
78
+	default:
79
+		return fmt.Errorf("unsupported scan type for CheckStatus: %T", src)
80
+	}
81
+	return nil
82
+}
83
+
84
+type NullCheckStatus struct {
85
+	CheckStatus CheckStatus
86
+	Valid       bool // Valid is true if CheckStatus is not NULL
87
+}
88
+
89
+// Scan implements the Scanner interface.
90
+func (ns *NullCheckStatus) Scan(value interface{}) error {
91
+	if value == nil {
92
+		ns.CheckStatus, ns.Valid = "", false
93
+		return nil
94
+	}
95
+	ns.Valid = true
96
+	return ns.CheckStatus.Scan(value)
97
+}
98
+
99
+// Value implements the driver Valuer interface.
100
+func (ns NullCheckStatus) Value() (driver.Value, error) {
101
+	if !ns.Valid {
102
+		return nil, nil
103
+	}
104
+	return string(ns.CheckStatus), nil
105
+}
106
+
15107
 type CollabRole string
16108
 
17109
 const (
@@ -651,6 +743,35 @@ type BranchProtectionRule struct {
651743
 	RequiredReviewCount            int32
652744
 	DismissStaleReviewsOnPush      bool
653745
 	RequireCodeOwnerReview         bool
746
+	DismissStaleStatusChecksOnPush bool
747
+}
748
+
749
+type CheckRun struct {
750
+	ID          int64
751
+	SuiteID     int64
752
+	RepoID      int64
753
+	HeadSha     string
754
+	Name        string
755
+	Status      CheckStatus
756
+	Conclusion  NullCheckConclusion
757
+	StartedAt   pgtype.Timestamptz
758
+	CompletedAt pgtype.Timestamptz
759
+	DetailsUrl  string
760
+	Output      []byte
761
+	ExternalID  pgtype.Text
762
+	CreatedAt   pgtype.Timestamptz
763
+	UpdatedAt   pgtype.Timestamptz
764
+}
765
+
766
+type CheckSuite struct {
767
+	ID         int64
768
+	RepoID     int64
769
+	HeadSha    string
770
+	AppSlug    string
771
+	Status     CheckStatus
772
+	Conclusion NullCheckConclusion
773
+	CreatedAt  pgtype.Timestamptz
774
+	UpdatedAt  pgtype.Timestamptz
654775
 }
655776
 
656777
 type EmailVerification struct {
internal/checks/sqlc/querier.goadded
@@ -0,0 +1,42 @@
1
+// Code generated by sqlc. DO NOT EDIT.
2
+// versions:
3
+//   sqlc v1.31.1
4
+
5
+package checksdb
6
+
7
+import (
8
+	"context"
9
+)
10
+
11
+type Querier interface {
12
+	CreateCheckRun(ctx context.Context, db DBTX, arg CreateCheckRunParams) (CheckRun, error)
13
+	GetCheckRun(ctx context.Context, db DBTX, id int64) (CheckRun, error)
14
+	// ─── check_runs ──────────────────────────────────────────────────────
15
+	// External-system create dedupe: lookup by (repo, head_sha, name,
16
+	// external_id). NULL external_id never matches via this query.
17
+	GetCheckRunByExternalID(ctx context.Context, db DBTX, arg GetCheckRunByExternalIDParams) (CheckRun, error)
18
+	GetCheckSuite(ctx context.Context, db DBTX, id int64) (CheckSuite, error)
19
+	// Required-check evaluator: most recent run with the given name on the
20
+	// specified head_sha.
21
+	GetLatestCheckRunByName(ctx context.Context, db DBTX, arg GetLatestCheckRunByNameParams) (CheckRun, error)
22
+	// SPDX-License-Identifier: AGPL-3.0-or-later
23
+	// ─── check_suites ────────────────────────────────────────────────────
24
+	// Idempotent suite-by-(repo, head_sha, app_slug) lookup. Used by every
25
+	// check-run create so consumers don't need to manage suite ids. ON
26
+	// CONFLICT … DO UPDATE returns the existing row when the unique
27
+	// (repo_id, head_sha, app_slug) already exists; otherwise returns the
28
+	// freshly inserted one.
29
+	GetOrCreateCheckSuite(ctx context.Context, db DBTX, arg GetOrCreateCheckSuiteParams) (CheckSuite, error)
30
+	ListCheckRunsBySuite(ctx context.Context, db DBTX, suiteID int64) ([]CheckRun, error)
31
+	ListCheckRunsForCommit(ctx context.Context, db DBTX, arg ListCheckRunsForCommitParams) ([]CheckRun, error)
32
+	// Used by the stale-on-push hook to flip queued/in_progress suites on
33
+	// the previous head to conclusion='stale'.
34
+	ListCheckSuiteIDsForHead(ctx context.Context, db DBTX, arg ListCheckSuiteIDsForHeadParams) ([]int64, error)
35
+	ListCheckSuitesForCommit(ctx context.Context, db DBTX, arg ListCheckSuitesForCommitParams) ([]CheckSuite, error)
36
+	MarkCheckSuiteStale(ctx context.Context, db DBTX, id int64) error
37
+	UpdateCheckRun(ctx context.Context, db DBTX, arg UpdateCheckRunParams) error
38
+	// Persists the rollup result computed in Go (suite_rollup.go).
39
+	UpdateCheckSuiteRollup(ctx context.Context, db DBTX, arg UpdateCheckSuiteRollupParams) error
40
+}
41
+
42
+var _ Querier = (*Queries)(nil)
internal/issues/sqlc/models.gomodified
@@ -12,6 +12,98 @@ import (
1212
 	"github.com/jackc/pgx/v5/pgtype"
1313
 )
1414
 
15
+type CheckConclusion string
16
+
17
+const (
18
+	CheckConclusionSuccess        CheckConclusion = "success"
19
+	CheckConclusionFailure        CheckConclusion = "failure"
20
+	CheckConclusionNeutral        CheckConclusion = "neutral"
21
+	CheckConclusionCancelled      CheckConclusion = "cancelled"
22
+	CheckConclusionSkipped        CheckConclusion = "skipped"
23
+	CheckConclusionTimedOut       CheckConclusion = "timed_out"
24
+	CheckConclusionActionRequired CheckConclusion = "action_required"
25
+	CheckConclusionStale          CheckConclusion = "stale"
26
+)
27
+
28
+func (e *CheckConclusion) Scan(src interface{}) error {
29
+	switch s := src.(type) {
30
+	case []byte:
31
+		*e = CheckConclusion(s)
32
+	case string:
33
+		*e = CheckConclusion(s)
34
+	default:
35
+		return fmt.Errorf("unsupported scan type for CheckConclusion: %T", src)
36
+	}
37
+	return nil
38
+}
39
+
40
+type NullCheckConclusion struct {
41
+	CheckConclusion CheckConclusion
42
+	Valid           bool // Valid is true if CheckConclusion is not NULL
43
+}
44
+
45
+// Scan implements the Scanner interface.
46
+func (ns *NullCheckConclusion) Scan(value interface{}) error {
47
+	if value == nil {
48
+		ns.CheckConclusion, ns.Valid = "", false
49
+		return nil
50
+	}
51
+	ns.Valid = true
52
+	return ns.CheckConclusion.Scan(value)
53
+}
54
+
55
+// Value implements the driver Valuer interface.
56
+func (ns NullCheckConclusion) Value() (driver.Value, error) {
57
+	if !ns.Valid {
58
+		return nil, nil
59
+	}
60
+	return string(ns.CheckConclusion), nil
61
+}
62
+
63
+type CheckStatus string
64
+
65
+const (
66
+	CheckStatusQueued     CheckStatus = "queued"
67
+	CheckStatusInProgress CheckStatus = "in_progress"
68
+	CheckStatusCompleted  CheckStatus = "completed"
69
+	CheckStatusPending    CheckStatus = "pending"
70
+)
71
+
72
+func (e *CheckStatus) Scan(src interface{}) error {
73
+	switch s := src.(type) {
74
+	case []byte:
75
+		*e = CheckStatus(s)
76
+	case string:
77
+		*e = CheckStatus(s)
78
+	default:
79
+		return fmt.Errorf("unsupported scan type for CheckStatus: %T", src)
80
+	}
81
+	return nil
82
+}
83
+
84
+type NullCheckStatus struct {
85
+	CheckStatus CheckStatus
86
+	Valid       bool // Valid is true if CheckStatus is not NULL
87
+}
88
+
89
+// Scan implements the Scanner interface.
90
+func (ns *NullCheckStatus) Scan(value interface{}) error {
91
+	if value == nil {
92
+		ns.CheckStatus, ns.Valid = "", false
93
+		return nil
94
+	}
95
+	ns.Valid = true
96
+	return ns.CheckStatus.Scan(value)
97
+}
98
+
99
+// Value implements the driver Valuer interface.
100
+func (ns NullCheckStatus) Value() (driver.Value, error) {
101
+	if !ns.Valid {
102
+		return nil, nil
103
+	}
104
+	return string(ns.CheckStatus), nil
105
+}
106
+
15107
 type CollabRole string
16108
 
17109
 const (
@@ -651,6 +743,35 @@ type BranchProtectionRule struct {
651743
 	RequiredReviewCount            int32
652744
 	DismissStaleReviewsOnPush      bool
653745
 	RequireCodeOwnerReview         bool
746
+	DismissStaleStatusChecksOnPush bool
747
+}
748
+
749
+type CheckRun struct {
750
+	ID          int64
751
+	SuiteID     int64
752
+	RepoID      int64
753
+	HeadSha     string
754
+	Name        string
755
+	Status      CheckStatus
756
+	Conclusion  NullCheckConclusion
757
+	StartedAt   pgtype.Timestamptz
758
+	CompletedAt pgtype.Timestamptz
759
+	DetailsUrl  string
760
+	Output      []byte
761
+	ExternalID  pgtype.Text
762
+	CreatedAt   pgtype.Timestamptz
763
+	UpdatedAt   pgtype.Timestamptz
764
+}
765
+
766
+type CheckSuite struct {
767
+	ID         int64
768
+	RepoID     int64
769
+	HeadSha    string
770
+	AppSlug    string
771
+	Status     CheckStatus
772
+	Conclusion NullCheckConclusion
773
+	CreatedAt  pgtype.Timestamptz
774
+	UpdatedAt  pgtype.Timestamptz
654775
 }
655776
 
656777
 type EmailVerification struct {
internal/meta/sqlc/models.gomodified
@@ -12,6 +12,98 @@ import (
1212
 	"github.com/jackc/pgx/v5/pgtype"
1313
 )
1414
 
15
+type CheckConclusion string
16
+
17
+const (
18
+	CheckConclusionSuccess        CheckConclusion = "success"
19
+	CheckConclusionFailure        CheckConclusion = "failure"
20
+	CheckConclusionNeutral        CheckConclusion = "neutral"
21
+	CheckConclusionCancelled      CheckConclusion = "cancelled"
22
+	CheckConclusionSkipped        CheckConclusion = "skipped"
23
+	CheckConclusionTimedOut       CheckConclusion = "timed_out"
24
+	CheckConclusionActionRequired CheckConclusion = "action_required"
25
+	CheckConclusionStale          CheckConclusion = "stale"
26
+)
27
+
28
+func (e *CheckConclusion) Scan(src interface{}) error {
29
+	switch s := src.(type) {
30
+	case []byte:
31
+		*e = CheckConclusion(s)
32
+	case string:
33
+		*e = CheckConclusion(s)
34
+	default:
35
+		return fmt.Errorf("unsupported scan type for CheckConclusion: %T", src)
36
+	}
37
+	return nil
38
+}
39
+
40
+type NullCheckConclusion struct {
41
+	CheckConclusion CheckConclusion
42
+	Valid           bool // Valid is true if CheckConclusion is not NULL
43
+}
44
+
45
+// Scan implements the Scanner interface.
46
+func (ns *NullCheckConclusion) Scan(value interface{}) error {
47
+	if value == nil {
48
+		ns.CheckConclusion, ns.Valid = "", false
49
+		return nil
50
+	}
51
+	ns.Valid = true
52
+	return ns.CheckConclusion.Scan(value)
53
+}
54
+
55
+// Value implements the driver Valuer interface.
56
+func (ns NullCheckConclusion) Value() (driver.Value, error) {
57
+	if !ns.Valid {
58
+		return nil, nil
59
+	}
60
+	return string(ns.CheckConclusion), nil
61
+}
62
+
63
+type CheckStatus string
64
+
65
+const (
66
+	CheckStatusQueued     CheckStatus = "queued"
67
+	CheckStatusInProgress CheckStatus = "in_progress"
68
+	CheckStatusCompleted  CheckStatus = "completed"
69
+	CheckStatusPending    CheckStatus = "pending"
70
+)
71
+
72
+func (e *CheckStatus) Scan(src interface{}) error {
73
+	switch s := src.(type) {
74
+	case []byte:
75
+		*e = CheckStatus(s)
76
+	case string:
77
+		*e = CheckStatus(s)
78
+	default:
79
+		return fmt.Errorf("unsupported scan type for CheckStatus: %T", src)
80
+	}
81
+	return nil
82
+}
83
+
84
+type NullCheckStatus struct {
85
+	CheckStatus CheckStatus
86
+	Valid       bool // Valid is true if CheckStatus is not NULL
87
+}
88
+
89
+// Scan implements the Scanner interface.
90
+func (ns *NullCheckStatus) Scan(value interface{}) error {
91
+	if value == nil {
92
+		ns.CheckStatus, ns.Valid = "", false
93
+		return nil
94
+	}
95
+	ns.Valid = true
96
+	return ns.CheckStatus.Scan(value)
97
+}
98
+
99
+// Value implements the driver Valuer interface.
100
+func (ns NullCheckStatus) Value() (driver.Value, error) {
101
+	if !ns.Valid {
102
+		return nil, nil
103
+	}
104
+	return string(ns.CheckStatus), nil
105
+}
106
+
15107
 type CollabRole string
16108
 
17109
 const (
@@ -651,6 +743,35 @@ type BranchProtectionRule struct {
651743
 	RequiredReviewCount            int32
652744
 	DismissStaleReviewsOnPush      bool
653745
 	RequireCodeOwnerReview         bool
746
+	DismissStaleStatusChecksOnPush bool
747
+}
748
+
749
+type CheckRun struct {
750
+	ID          int64
751
+	SuiteID     int64
752
+	RepoID      int64
753
+	HeadSha     string
754
+	Name        string
755
+	Status      CheckStatus
756
+	Conclusion  NullCheckConclusion
757
+	StartedAt   pgtype.Timestamptz
758
+	CompletedAt pgtype.Timestamptz
759
+	DetailsUrl  string
760
+	Output      []byte
761
+	ExternalID  pgtype.Text
762
+	CreatedAt   pgtype.Timestamptz
763
+	UpdatedAt   pgtype.Timestamptz
764
+}
765
+
766
+type CheckSuite struct {
767
+	ID         int64
768
+	RepoID     int64
769
+	HeadSha    string
770
+	AppSlug    string
771
+	Status     CheckStatus
772
+	Conclusion NullCheckConclusion
773
+	CreatedAt  pgtype.Timestamptz
774
+	UpdatedAt  pgtype.Timestamptz
654775
 }
655776
 
656777
 type EmailVerification struct {
internal/migrationsfs/migrations/0025_check_runs.sqladded
@@ -0,0 +1,94 @@
1
+-- SPDX-License-Identifier: AGPL-3.0-or-later
2
+--
3
+-- S24 PR-checks subsystem.
4
+--
5
+--   check_suites — one row per (repo_id, head_sha, app_slug). Suites
6
+--                  group runs from a single CI app/integration. Status
7
+--                  + conclusion are derived from runs (suite_rollup.go).
8
+--                  app_slug='external' is the default catch-all for
9
+--                  generic CI integrations posting via PAT.
10
+--   check_runs   — individual checks (e.g. "lint", "unit-tests") for
11
+--                  a specific head_sha. Status moves queued → in_progress
12
+--                  → completed; conclusion is set on completion. The
13
+--                  output jsonb mirrors GitHub's {title, summary, text}
14
+--                  shape so existing CI adapters port cleanly.
15
+--
16
+-- Branch protection: status_checks_required already exists from S20
17
+-- (text[]). This migration adds dismiss_stale_status_checks_on_push so
18
+-- the optional stale-on-push behavior can be opted into.
19
+
20
+-- +goose Up
21
+
22
+CREATE TYPE check_status     AS ENUM ('queued', 'in_progress', 'completed', 'pending');
23
+CREATE TYPE check_conclusion AS ENUM (
24
+    'success', 'failure', 'neutral', 'cancelled',
25
+    'skipped', 'timed_out', 'action_required', 'stale'
26
+);
27
+
28
+CREATE TABLE check_suites (
29
+    id          bigserial         PRIMARY KEY,
30
+    repo_id     bigint            NOT NULL REFERENCES repos(id) ON DELETE CASCADE,
31
+    head_sha    text              NOT NULL,
32
+    app_slug    text              NOT NULL DEFAULT 'external',
33
+    status      check_status      NOT NULL DEFAULT 'queued',
34
+    conclusion  check_conclusion,
35
+    created_at  timestamptz       NOT NULL DEFAULT now(),
36
+    updated_at  timestamptz       NOT NULL DEFAULT now(),
37
+
38
+    UNIQUE (repo_id, head_sha, app_slug),
39
+    CONSTRAINT check_suites_app_slug_length CHECK (char_length(app_slug) BETWEEN 1 AND 64),
40
+    CONSTRAINT check_suites_head_sha_format CHECK (char_length(head_sha) BETWEEN 7 AND 64)
41
+);
42
+
43
+CREATE INDEX check_suites_repo_head_idx ON check_suites (repo_id, head_sha);
44
+CREATE INDEX check_suites_status_idx    ON check_suites (repo_id, status);
45
+
46
+CREATE TRIGGER set_updated_at BEFORE UPDATE ON check_suites
47
+    FOR EACH ROW EXECUTE FUNCTION tg_set_updated_at();
48
+
49
+
50
+CREATE TABLE check_runs (
51
+    id            bigserial         PRIMARY KEY,
52
+    suite_id      bigint            NOT NULL REFERENCES check_suites(id) ON DELETE CASCADE,
53
+    repo_id       bigint            NOT NULL REFERENCES repos(id) ON DELETE CASCADE,
54
+    head_sha      text              NOT NULL,
55
+    name          text              NOT NULL,
56
+    status        check_status      NOT NULL DEFAULT 'queued',
57
+    conclusion    check_conclusion,
58
+    started_at    timestamptz,
59
+    completed_at  timestamptz,
60
+    details_url   text              NOT NULL DEFAULT '',
61
+    output        jsonb             NOT NULL DEFAULT '{}'::jsonb,
62
+    -- external_id lets external systems dedupe POST creates: the same
63
+    -- (repo, head_sha, name, external_id) returns the existing run.
64
+    external_id   text,
65
+    created_at    timestamptz       NOT NULL DEFAULT now(),
66
+    updated_at    timestamptz       NOT NULL DEFAULT now(),
67
+
68
+    CONSTRAINT check_runs_name_length CHECK (char_length(name) BETWEEN 1 AND 200),
69
+    CONSTRAINT check_runs_completed_has_conclusion CHECK (
70
+        status <> 'completed' OR conclusion IS NOT NULL
71
+    )
72
+);
73
+
74
+CREATE INDEX check_runs_repo_head_idx       ON check_runs (repo_id, head_sha);
75
+CREATE INDEX check_runs_suite_idx           ON check_runs (suite_id);
76
+CREATE INDEX check_runs_external_id_idx     ON check_runs (repo_id, head_sha, name, external_id)
77
+    WHERE external_id IS NOT NULL;
78
+CREATE INDEX check_runs_required_lookup_idx ON check_runs (repo_id, head_sha, name);
79
+
80
+CREATE TRIGGER set_updated_at BEFORE UPDATE ON check_runs
81
+    FOR EACH ROW EXECUTE FUNCTION tg_set_updated_at();
82
+
83
+
84
+ALTER TABLE branch_protection_rules
85
+    ADD COLUMN dismiss_stale_status_checks_on_push boolean NOT NULL DEFAULT false;
86
+
87
+
88
+-- +goose Down
89
+ALTER TABLE branch_protection_rules
90
+    DROP COLUMN IF EXISTS dismiss_stale_status_checks_on_push;
91
+DROP TABLE IF EXISTS check_runs;
92
+DROP TABLE IF EXISTS check_suites;
93
+DROP TYPE IF EXISTS check_conclusion;
94
+DROP TYPE IF EXISTS check_status;
internal/pulls/sqlc/models.gomodified
@@ -12,6 +12,98 @@ import (
1212
 	"github.com/jackc/pgx/v5/pgtype"
1313
 )
1414
 
15
+type CheckConclusion string
16
+
17
+const (
18
+	CheckConclusionSuccess        CheckConclusion = "success"
19
+	CheckConclusionFailure        CheckConclusion = "failure"
20
+	CheckConclusionNeutral        CheckConclusion = "neutral"
21
+	CheckConclusionCancelled      CheckConclusion = "cancelled"
22
+	CheckConclusionSkipped        CheckConclusion = "skipped"
23
+	CheckConclusionTimedOut       CheckConclusion = "timed_out"
24
+	CheckConclusionActionRequired CheckConclusion = "action_required"
25
+	CheckConclusionStale          CheckConclusion = "stale"
26
+)
27
+
28
+func (e *CheckConclusion) Scan(src interface{}) error {
29
+	switch s := src.(type) {
30
+	case []byte:
31
+		*e = CheckConclusion(s)
32
+	case string:
33
+		*e = CheckConclusion(s)
34
+	default:
35
+		return fmt.Errorf("unsupported scan type for CheckConclusion: %T", src)
36
+	}
37
+	return nil
38
+}
39
+
40
+type NullCheckConclusion struct {
41
+	CheckConclusion CheckConclusion
42
+	Valid           bool // Valid is true if CheckConclusion is not NULL
43
+}
44
+
45
+// Scan implements the Scanner interface.
46
+func (ns *NullCheckConclusion) Scan(value interface{}) error {
47
+	if value == nil {
48
+		ns.CheckConclusion, ns.Valid = "", false
49
+		return nil
50
+	}
51
+	ns.Valid = true
52
+	return ns.CheckConclusion.Scan(value)
53
+}
54
+
55
+// Value implements the driver Valuer interface.
56
+func (ns NullCheckConclusion) Value() (driver.Value, error) {
57
+	if !ns.Valid {
58
+		return nil, nil
59
+	}
60
+	return string(ns.CheckConclusion), nil
61
+}
62
+
63
+type CheckStatus string
64
+
65
+const (
66
+	CheckStatusQueued     CheckStatus = "queued"
67
+	CheckStatusInProgress CheckStatus = "in_progress"
68
+	CheckStatusCompleted  CheckStatus = "completed"
69
+	CheckStatusPending    CheckStatus = "pending"
70
+)
71
+
72
+func (e *CheckStatus) Scan(src interface{}) error {
73
+	switch s := src.(type) {
74
+	case []byte:
75
+		*e = CheckStatus(s)
76
+	case string:
77
+		*e = CheckStatus(s)
78
+	default:
79
+		return fmt.Errorf("unsupported scan type for CheckStatus: %T", src)
80
+	}
81
+	return nil
82
+}
83
+
84
+type NullCheckStatus struct {
85
+	CheckStatus CheckStatus
86
+	Valid       bool // Valid is true if CheckStatus is not NULL
87
+}
88
+
89
+// Scan implements the Scanner interface.
90
+func (ns *NullCheckStatus) Scan(value interface{}) error {
91
+	if value == nil {
92
+		ns.CheckStatus, ns.Valid = "", false
93
+		return nil
94
+	}
95
+	ns.Valid = true
96
+	return ns.CheckStatus.Scan(value)
97
+}
98
+
99
+// Value implements the driver Valuer interface.
100
+func (ns NullCheckStatus) Value() (driver.Value, error) {
101
+	if !ns.Valid {
102
+		return nil, nil
103
+	}
104
+	return string(ns.CheckStatus), nil
105
+}
106
+
15107
 type CollabRole string
16108
 
17109
 const (
@@ -651,6 +743,35 @@ type BranchProtectionRule struct {
651743
 	RequiredReviewCount            int32
652744
 	DismissStaleReviewsOnPush      bool
653745
 	RequireCodeOwnerReview         bool
746
+	DismissStaleStatusChecksOnPush bool
747
+}
748
+
749
+type CheckRun struct {
750
+	ID          int64
751
+	SuiteID     int64
752
+	RepoID      int64
753
+	HeadSha     string
754
+	Name        string
755
+	Status      CheckStatus
756
+	Conclusion  NullCheckConclusion
757
+	StartedAt   pgtype.Timestamptz
758
+	CompletedAt pgtype.Timestamptz
759
+	DetailsUrl  string
760
+	Output      []byte
761
+	ExternalID  pgtype.Text
762
+	CreatedAt   pgtype.Timestamptz
763
+	UpdatedAt   pgtype.Timestamptz
764
+}
765
+
766
+type CheckSuite struct {
767
+	ID         int64
768
+	RepoID     int64
769
+	HeadSha    string
770
+	AppSlug    string
771
+	Status     CheckStatus
772
+	Conclusion NullCheckConclusion
773
+	CreatedAt  pgtype.Timestamptz
774
+	UpdatedAt  pgtype.Timestamptz
654775
 }
655776
 
656777
 type EmailVerification struct {
internal/repos/queries/branch_protection.sqlmodified
@@ -6,7 +6,8 @@ SELECT id, repo_id, pattern,
66
        allowed_pusher_user_ids,
77
        require_signed_commits, status_checks_required,
88
        created_at, updated_at, created_by_user_id,
9
-       required_review_count, dismiss_stale_reviews_on_push, require_code_owner_review
9
+       required_review_count, dismiss_stale_reviews_on_push, require_code_owner_review,
10
+       dismiss_stale_status_checks_on_push
1011
 FROM branch_protection_rules
1112
 WHERE repo_id = $1
1213
 ORDER BY pattern;
@@ -17,7 +18,8 @@ SELECT id, repo_id, pattern,
1718
        allowed_pusher_user_ids,
1819
        require_signed_commits, status_checks_required,
1920
        created_at, updated_at, created_by_user_id,
20
-       required_review_count, dismiss_stale_reviews_on_push, require_code_owner_review
21
+       required_review_count, dismiss_stale_reviews_on_push, require_code_owner_review,
22
+       dismiss_stale_status_checks_on_push
2123
 FROM branch_protection_rules
2224
 WHERE id = $1;
2325
 
@@ -49,6 +51,14 @@ SET required_review_count = $2,
4951
     require_code_owner_review = $4
5052
 WHERE id = $1;
5153
 
54
+-- name: UpdateBranchProtectionCheckSettings :exec
55
+-- S24 surface for the required-status-check knobs. Branch-protection
56
+-- edit handler calls this alongside UpdateBranchProtectionRule.
57
+UPDATE branch_protection_rules
58
+SET status_checks_required = $2,
59
+    dismiss_stale_status_checks_on_push = $3
60
+WHERE id = $1;
61
+
5262
 -- name: DeleteBranchProtectionRule :exec
5363
 DELETE FROM branch_protection_rules WHERE id = $1;
5464
 
internal/repos/sqlc/branch_protection.sql.gomodified
@@ -26,7 +26,8 @@ SELECT id, repo_id, pattern,
2626
        allowed_pusher_user_ids,
2727
        require_signed_commits, status_checks_required,
2828
        created_at, updated_at, created_by_user_id,
29
-       required_review_count, dismiss_stale_reviews_on_push, require_code_owner_review
29
+       required_review_count, dismiss_stale_reviews_on_push, require_code_owner_review,
30
+       dismiss_stale_status_checks_on_push
3031
 FROM branch_protection_rules
3132
 WHERE id = $1
3233
 `
@@ -50,6 +51,7 @@ func (q *Queries) GetBranchProtectionRule(ctx context.Context, db DBTX, id int64
5051
 		&i.RequiredReviewCount,
5152
 		&i.DismissStaleReviewsOnPush,
5253
 		&i.RequireCodeOwnerReview,
54
+		&i.DismissStaleStatusChecksOnPush,
5355
 	)
5456
 	return i, err
5557
 }
@@ -61,7 +63,8 @@ SELECT id, repo_id, pattern,
6163
        allowed_pusher_user_ids,
6264
        require_signed_commits, status_checks_required,
6365
        created_at, updated_at, created_by_user_id,
64
-       required_review_count, dismiss_stale_reviews_on_push, require_code_owner_review
66
+       required_review_count, dismiss_stale_reviews_on_push, require_code_owner_review,
67
+       dismiss_stale_status_checks_on_push
6568
 FROM branch_protection_rules
6669
 WHERE repo_id = $1
6770
 ORDER BY pattern
@@ -93,6 +96,7 @@ func (q *Queries) ListBranchProtectionRules(ctx context.Context, db DBTX, repoID
9396
 			&i.RequiredReviewCount,
9497
 			&i.DismissStaleReviewsOnPush,
9598
 			&i.RequireCodeOwnerReview,
99
+			&i.DismissStaleStatusChecksOnPush,
96100
 		); err != nil {
97101
 			return nil, err
98102
 		}
@@ -104,6 +108,26 @@ func (q *Queries) ListBranchProtectionRules(ctx context.Context, db DBTX, repoID
104108
 	return items, nil
105109
 }
106110
 
111
+const updateBranchProtectionCheckSettings = `-- name: UpdateBranchProtectionCheckSettings :exec
112
+UPDATE branch_protection_rules
113
+SET status_checks_required = $2,
114
+    dismiss_stale_status_checks_on_push = $3
115
+WHERE id = $1
116
+`
117
+
118
+type UpdateBranchProtectionCheckSettingsParams struct {
119
+	ID                             int64
120
+	StatusChecksRequired           []string
121
+	DismissStaleStatusChecksOnPush bool
122
+}
123
+
124
+// S24 surface for the required-status-check knobs. Branch-protection
125
+// edit handler calls this alongside UpdateBranchProtectionRule.
126
+func (q *Queries) UpdateBranchProtectionCheckSettings(ctx context.Context, db DBTX, arg UpdateBranchProtectionCheckSettingsParams) error {
127
+	_, err := db.Exec(ctx, updateBranchProtectionCheckSettings, arg.ID, arg.StatusChecksRequired, arg.DismissStaleStatusChecksOnPush)
128
+	return err
129
+}
130
+
107131
 const updateBranchProtectionReviewSettings = `-- name: UpdateBranchProtectionReviewSettings :exec
108132
 UPDATE branch_protection_rules
109133
 SET required_review_count = $2,
internal/repos/sqlc/models.gomodified
@@ -12,6 +12,98 @@ import (
1212
 	"github.com/jackc/pgx/v5/pgtype"
1313
 )
1414
 
15
+type CheckConclusion string
16
+
17
+const (
18
+	CheckConclusionSuccess        CheckConclusion = "success"
19
+	CheckConclusionFailure        CheckConclusion = "failure"
20
+	CheckConclusionNeutral        CheckConclusion = "neutral"
21
+	CheckConclusionCancelled      CheckConclusion = "cancelled"
22
+	CheckConclusionSkipped        CheckConclusion = "skipped"
23
+	CheckConclusionTimedOut       CheckConclusion = "timed_out"
24
+	CheckConclusionActionRequired CheckConclusion = "action_required"
25
+	CheckConclusionStale          CheckConclusion = "stale"
26
+)
27
+
28
+func (e *CheckConclusion) Scan(src interface{}) error {
29
+	switch s := src.(type) {
30
+	case []byte:
31
+		*e = CheckConclusion(s)
32
+	case string:
33
+		*e = CheckConclusion(s)
34
+	default:
35
+		return fmt.Errorf("unsupported scan type for CheckConclusion: %T", src)
36
+	}
37
+	return nil
38
+}
39
+
40
+type NullCheckConclusion struct {
41
+	CheckConclusion CheckConclusion
42
+	Valid           bool // Valid is true if CheckConclusion is not NULL
43
+}
44
+
45
+// Scan implements the Scanner interface.
46
+func (ns *NullCheckConclusion) Scan(value interface{}) error {
47
+	if value == nil {
48
+		ns.CheckConclusion, ns.Valid = "", false
49
+		return nil
50
+	}
51
+	ns.Valid = true
52
+	return ns.CheckConclusion.Scan(value)
53
+}
54
+
55
+// Value implements the driver Valuer interface.
56
+func (ns NullCheckConclusion) Value() (driver.Value, error) {
57
+	if !ns.Valid {
58
+		return nil, nil
59
+	}
60
+	return string(ns.CheckConclusion), nil
61
+}
62
+
63
+type CheckStatus string
64
+
65
+const (
66
+	CheckStatusQueued     CheckStatus = "queued"
67
+	CheckStatusInProgress CheckStatus = "in_progress"
68
+	CheckStatusCompleted  CheckStatus = "completed"
69
+	CheckStatusPending    CheckStatus = "pending"
70
+)
71
+
72
+func (e *CheckStatus) Scan(src interface{}) error {
73
+	switch s := src.(type) {
74
+	case []byte:
75
+		*e = CheckStatus(s)
76
+	case string:
77
+		*e = CheckStatus(s)
78
+	default:
79
+		return fmt.Errorf("unsupported scan type for CheckStatus: %T", src)
80
+	}
81
+	return nil
82
+}
83
+
84
+type NullCheckStatus struct {
85
+	CheckStatus CheckStatus
86
+	Valid       bool // Valid is true if CheckStatus is not NULL
87
+}
88
+
89
+// Scan implements the Scanner interface.
90
+func (ns *NullCheckStatus) Scan(value interface{}) error {
91
+	if value == nil {
92
+		ns.CheckStatus, ns.Valid = "", false
93
+		return nil
94
+	}
95
+	ns.Valid = true
96
+	return ns.CheckStatus.Scan(value)
97
+}
98
+
99
+// Value implements the driver Valuer interface.
100
+func (ns NullCheckStatus) Value() (driver.Value, error) {
101
+	if !ns.Valid {
102
+		return nil, nil
103
+	}
104
+	return string(ns.CheckStatus), nil
105
+}
106
+
15107
 type CollabRole string
16108
 
17109
 const (
@@ -651,6 +743,35 @@ type BranchProtectionRule struct {
651743
 	RequiredReviewCount            int32
652744
 	DismissStaleReviewsOnPush      bool
653745
 	RequireCodeOwnerReview         bool
746
+	DismissStaleStatusChecksOnPush bool
747
+}
748
+
749
+type CheckRun struct {
750
+	ID          int64
751
+	SuiteID     int64
752
+	RepoID      int64
753
+	HeadSha     string
754
+	Name        string
755
+	Status      CheckStatus
756
+	Conclusion  NullCheckConclusion
757
+	StartedAt   pgtype.Timestamptz
758
+	CompletedAt pgtype.Timestamptz
759
+	DetailsUrl  string
760
+	Output      []byte
761
+	ExternalID  pgtype.Text
762
+	CreatedAt   pgtype.Timestamptz
763
+	UpdatedAt   pgtype.Timestamptz
764
+}
765
+
766
+type CheckSuite struct {
767
+	ID         int64
768
+	RepoID     int64
769
+	HeadSha    string
770
+	AppSlug    string
771
+	Status     CheckStatus
772
+	Conclusion NullCheckConclusion
773
+	CreatedAt  pgtype.Timestamptz
774
+	UpdatedAt  pgtype.Timestamptz
654775
 }
655776
 
656777
 type EmailVerification struct {
internal/repos/sqlc/querier.gomodified
@@ -90,6 +90,9 @@ type Querier interface {
9090
 	// so a user→org transfer flips both columns atomically.
9191
 	TransferRepoOwner(ctx context.Context, db DBTX, arg TransferRepoOwnerParams) error
9292
 	UnarchiveRepo(ctx context.Context, db DBTX, id int64) error
93
+	// S24 surface for the required-status-check knobs. Branch-protection
94
+	// edit handler calls this alongside UpdateBranchProtectionRule.
95
+	UpdateBranchProtectionCheckSettings(ctx context.Context, db DBTX, arg UpdateBranchProtectionCheckSettingsParams) error
9396
 	// S23 surface for the review-related knobs. Branch-protection edit
9497
 	// handler calls this alongside UpdateBranchProtectionRule.
9598
 	UpdateBranchProtectionReviewSettings(ctx context.Context, db DBTX, arg UpdateBranchProtectionReviewSettingsParams) error
internal/users/sqlc/models.gomodified
@@ -12,6 +12,98 @@ import (
1212
 	"github.com/jackc/pgx/v5/pgtype"
1313
 )
1414
 
15
+type CheckConclusion string
16
+
17
+const (
18
+	CheckConclusionSuccess        CheckConclusion = "success"
19
+	CheckConclusionFailure        CheckConclusion = "failure"
20
+	CheckConclusionNeutral        CheckConclusion = "neutral"
21
+	CheckConclusionCancelled      CheckConclusion = "cancelled"
22
+	CheckConclusionSkipped        CheckConclusion = "skipped"
23
+	CheckConclusionTimedOut       CheckConclusion = "timed_out"
24
+	CheckConclusionActionRequired CheckConclusion = "action_required"
25
+	CheckConclusionStale          CheckConclusion = "stale"
26
+)
27
+
28
+func (e *CheckConclusion) Scan(src interface{}) error {
29
+	switch s := src.(type) {
30
+	case []byte:
31
+		*e = CheckConclusion(s)
32
+	case string:
33
+		*e = CheckConclusion(s)
34
+	default:
35
+		return fmt.Errorf("unsupported scan type for CheckConclusion: %T", src)
36
+	}
37
+	return nil
38
+}
39
+
40
+type NullCheckConclusion struct {
41
+	CheckConclusion CheckConclusion
42
+	Valid           bool // Valid is true if CheckConclusion is not NULL
43
+}
44
+
45
+// Scan implements the Scanner interface.
46
+func (ns *NullCheckConclusion) Scan(value interface{}) error {
47
+	if value == nil {
48
+		ns.CheckConclusion, ns.Valid = "", false
49
+		return nil
50
+	}
51
+	ns.Valid = true
52
+	return ns.CheckConclusion.Scan(value)
53
+}
54
+
55
+// Value implements the driver Valuer interface.
56
+func (ns NullCheckConclusion) Value() (driver.Value, error) {
57
+	if !ns.Valid {
58
+		return nil, nil
59
+	}
60
+	return string(ns.CheckConclusion), nil
61
+}
62
+
63
+type CheckStatus string
64
+
65
+const (
66
+	CheckStatusQueued     CheckStatus = "queued"
67
+	CheckStatusInProgress CheckStatus = "in_progress"
68
+	CheckStatusCompleted  CheckStatus = "completed"
69
+	CheckStatusPending    CheckStatus = "pending"
70
+)
71
+
72
+func (e *CheckStatus) Scan(src interface{}) error {
73
+	switch s := src.(type) {
74
+	case []byte:
75
+		*e = CheckStatus(s)
76
+	case string:
77
+		*e = CheckStatus(s)
78
+	default:
79
+		return fmt.Errorf("unsupported scan type for CheckStatus: %T", src)
80
+	}
81
+	return nil
82
+}
83
+
84
+type NullCheckStatus struct {
85
+	CheckStatus CheckStatus
86
+	Valid       bool // Valid is true if CheckStatus is not NULL
87
+}
88
+
89
+// Scan implements the Scanner interface.
90
+func (ns *NullCheckStatus) Scan(value interface{}) error {
91
+	if value == nil {
92
+		ns.CheckStatus, ns.Valid = "", false
93
+		return nil
94
+	}
95
+	ns.Valid = true
96
+	return ns.CheckStatus.Scan(value)
97
+}
98
+
99
+// Value implements the driver Valuer interface.
100
+func (ns NullCheckStatus) Value() (driver.Value, error) {
101
+	if !ns.Valid {
102
+		return nil, nil
103
+	}
104
+	return string(ns.CheckStatus), nil
105
+}
106
+
15107
 type CollabRole string
16108
 
17109
 const (
@@ -651,6 +743,35 @@ type BranchProtectionRule struct {
651743
 	RequiredReviewCount            int32
652744
 	DismissStaleReviewsOnPush      bool
653745
 	RequireCodeOwnerReview         bool
746
+	DismissStaleStatusChecksOnPush bool
747
+}
748
+
749
+type CheckRun struct {
750
+	ID          int64
751
+	SuiteID     int64
752
+	RepoID      int64
753
+	HeadSha     string
754
+	Name        string
755
+	Status      CheckStatus
756
+	Conclusion  NullCheckConclusion
757
+	StartedAt   pgtype.Timestamptz
758
+	CompletedAt pgtype.Timestamptz
759
+	DetailsUrl  string
760
+	Output      []byte
761
+	ExternalID  pgtype.Text
762
+	CreatedAt   pgtype.Timestamptz
763
+	UpdatedAt   pgtype.Timestamptz
764
+}
765
+
766
+type CheckSuite struct {
767
+	ID         int64
768
+	RepoID     int64
769
+	HeadSha    string
770
+	AppSlug    string
771
+	Status     CheckStatus
772
+	Conclusion NullCheckConclusion
773
+	CreatedAt  pgtype.Timestamptz
774
+	UpdatedAt  pgtype.Timestamptz
654775
 }
655776
 
656777
 type EmailVerification struct {
internal/worker/sqlc/models.gomodified
@@ -12,6 +12,98 @@ import (
1212
 	"github.com/jackc/pgx/v5/pgtype"
1313
 )
1414
 
15
+type CheckConclusion string
16
+
17
+const (
18
+	CheckConclusionSuccess        CheckConclusion = "success"
19
+	CheckConclusionFailure        CheckConclusion = "failure"
20
+	CheckConclusionNeutral        CheckConclusion = "neutral"
21
+	CheckConclusionCancelled      CheckConclusion = "cancelled"
22
+	CheckConclusionSkipped        CheckConclusion = "skipped"
23
+	CheckConclusionTimedOut       CheckConclusion = "timed_out"
24
+	CheckConclusionActionRequired CheckConclusion = "action_required"
25
+	CheckConclusionStale          CheckConclusion = "stale"
26
+)
27
+
28
+func (e *CheckConclusion) Scan(src interface{}) error {
29
+	switch s := src.(type) {
30
+	case []byte:
31
+		*e = CheckConclusion(s)
32
+	case string:
33
+		*e = CheckConclusion(s)
34
+	default:
35
+		return fmt.Errorf("unsupported scan type for CheckConclusion: %T", src)
36
+	}
37
+	return nil
38
+}
39
+
40
+type NullCheckConclusion struct {
41
+	CheckConclusion CheckConclusion
42
+	Valid           bool // Valid is true if CheckConclusion is not NULL
43
+}
44
+
45
+// Scan implements the Scanner interface.
46
+func (ns *NullCheckConclusion) Scan(value interface{}) error {
47
+	if value == nil {
48
+		ns.CheckConclusion, ns.Valid = "", false
49
+		return nil
50
+	}
51
+	ns.Valid = true
52
+	return ns.CheckConclusion.Scan(value)
53
+}
54
+
55
+// Value implements the driver Valuer interface.
56
+func (ns NullCheckConclusion) Value() (driver.Value, error) {
57
+	if !ns.Valid {
58
+		return nil, nil
59
+	}
60
+	return string(ns.CheckConclusion), nil
61
+}
62
+
63
+type CheckStatus string
64
+
65
+const (
66
+	CheckStatusQueued     CheckStatus = "queued"
67
+	CheckStatusInProgress CheckStatus = "in_progress"
68
+	CheckStatusCompleted  CheckStatus = "completed"
69
+	CheckStatusPending    CheckStatus = "pending"
70
+)
71
+
72
+func (e *CheckStatus) Scan(src interface{}) error {
73
+	switch s := src.(type) {
74
+	case []byte:
75
+		*e = CheckStatus(s)
76
+	case string:
77
+		*e = CheckStatus(s)
78
+	default:
79
+		return fmt.Errorf("unsupported scan type for CheckStatus: %T", src)
80
+	}
81
+	return nil
82
+}
83
+
84
+type NullCheckStatus struct {
85
+	CheckStatus CheckStatus
86
+	Valid       bool // Valid is true if CheckStatus is not NULL
87
+}
88
+
89
+// Scan implements the Scanner interface.
90
+func (ns *NullCheckStatus) Scan(value interface{}) error {
91
+	if value == nil {
92
+		ns.CheckStatus, ns.Valid = "", false
93
+		return nil
94
+	}
95
+	ns.Valid = true
96
+	return ns.CheckStatus.Scan(value)
97
+}
98
+
99
+// Value implements the driver Valuer interface.
100
+func (ns NullCheckStatus) Value() (driver.Value, error) {
101
+	if !ns.Valid {
102
+		return nil, nil
103
+	}
104
+	return string(ns.CheckStatus), nil
105
+}
106
+
15107
 type CollabRole string
16108
 
17109
 const (
@@ -651,6 +743,35 @@ type BranchProtectionRule struct {
651743
 	RequiredReviewCount            int32
652744
 	DismissStaleReviewsOnPush      bool
653745
 	RequireCodeOwnerReview         bool
746
+	DismissStaleStatusChecksOnPush bool
747
+}
748
+
749
+type CheckRun struct {
750
+	ID          int64
751
+	SuiteID     int64
752
+	RepoID      int64
753
+	HeadSha     string
754
+	Name        string
755
+	Status      CheckStatus
756
+	Conclusion  NullCheckConclusion
757
+	StartedAt   pgtype.Timestamptz
758
+	CompletedAt pgtype.Timestamptz
759
+	DetailsUrl  string
760
+	Output      []byte
761
+	ExternalID  pgtype.Text
762
+	CreatedAt   pgtype.Timestamptz
763
+	UpdatedAt   pgtype.Timestamptz
764
+}
765
+
766
+type CheckSuite struct {
767
+	ID         int64
768
+	RepoID     int64
769
+	HeadSha    string
770
+	AppSlug    string
771
+	Status     CheckStatus
772
+	Conclusion NullCheckConclusion
773
+	CreatedAt  pgtype.Timestamptz
774
+	UpdatedAt  pgtype.Timestamptz
654775
 }
655776
 
656777
 type EmailVerification struct {
sqlc.yamlmodified
@@ -82,6 +82,22 @@ sql:
8282
         emit_empty_slices: true
8383
         emit_methods_with_db_argument: true
8484
 
85
+  - engine: postgresql
86
+    schema: internal/migrationsfs/migrations
87
+    queries: internal/checks/queries
88
+    gen:
89
+      go:
90
+        package: checksdb
91
+        out: internal/checks/sqlc
92
+        sql_package: pgx/v5
93
+        emit_json_tags: false
94
+        emit_pointers_for_null_types: false
95
+        emit_prepared_queries: false
96
+        emit_interface: true
97
+        emit_exact_table_names: false
98
+        emit_empty_slices: true
99
+        emit_methods_with_db_argument: true
100
+
85101
   - engine: postgresql
86102
     schema: internal/migrationsfs/migrations
87103
     queries: internal/auth/policy/queries