Skip to content

g1t/services/work/migrations/0028_rulesets.sql

144 lines5,819 bytesCodeBlame

Pick any line to see why it is the way it is: the commit, the pull request and issue it came from, and what the agent was thinking.

Merge rulesets: branch and tag rules, agent-first, enforced on push and merge1-- Rulesets: what may happen to a repository's branches and tags, and what
2-- a pull request needs before it merges. See crates/rules and
3-- src/rulesets.rs. Every timestamp is RFC 3339 UTC.
4
5-- A repository's rulesets (level 'repository', with repo_id) and a
6-- workspace's (level 'workspace'). `spec` is the ruleset as the API shows
7-- it (g1t_contracts::rules::RulesetSpec, JSON); name, enforcement and
8-- target are copied out of it for listing.
9CREATE TABLE rulesets (
10 id TEXT PRIMARY KEY,
11 level TEXT NOT NULL,
12 -- The workspace's slug; for a repository's, its workspace when saved.
13 workspace TEXT NOT NULL,
14 repo_id TEXT,
15 name TEXT NOT NULL,
16 enforcement TEXT NOT NULL,
17 target TEXT NOT NULL,
18 spec TEXT NOT NULL,
19 -- 'branch_protection' for the one made from branch protection settings.
20 source TEXT,
21 created_by TEXT NOT NULL,
22 created_at TEXT NOT NULL,
23 updated_by TEXT NOT NULL,
24 updated_at TEXT NOT NULL
25);
26CREATE INDEX rulesets_by_repo ON rulesets (repo_id);
27CREATE INDEX rulesets_by_workspace ON rulesets (workspace, level);
28
29-- Every evaluation of a ruleset on a push, a merge or another change to a
30-- branch or tag: the audit trail, and what `evaluate` rulesets would have
31-- refused. `violations` is JSON (Vec<Violation>). Ids sort by time.
32CREATE TABLE rule_evaluations (
33 id TEXT PRIMARY KEY,
34 repo_id TEXT NOT NULL,
35 workspace TEXT NOT NULL,
36 ruleset_id TEXT NOT NULL,
37 ruleset_name TEXT NOT NULL,
38 enforcement TEXT NOT NULL,
39 -- push, merge, create_ref, delete_ref, rename_ref or commit.
40 action TEXT NOT NULL,
41 git_ref TEXT NOT NULL,
42 actor TEXT NOT NULL,
43 -- person, agent, g1t or token.
44 actor_kind TEXT NOT NULL,
45 -- pass, fail or bypass.
46 verdict TEXT NOT NULL,
47 violations TEXT NOT NULL DEFAULT '[]',
48 number INTEGER,
49 sha TEXT,
50 created_at TEXT NOT NULL
51);
52CREATE INDEX rule_evaluations_by_repo ON rule_evaluations (repo_id, id);
53CREATE INDEX rule_evaluations_by_workspace ON rule_evaluations (workspace, id);
54CREATE INDEX rule_evaluations_by_ruleset ON rule_evaluations (ruleset_id, id);
55
56-- The repos service kept whether pushes to the default branch were refused
57-- (its `protected` flag). The first time g1t reads a repository's rulesets
58-- after this, it folds that flag into its branch protection ruleset, once.
59CREATE TABLE ruleset_adoptions (
60 repo_id TEXT PRIMARY KEY,
61 adopted_at TEXT NOT NULL
62);
63
64-- Who moved a pull request's head last, and when: for approving the most
65-- recent push and dismissing approvals that came before it.
66ALTER TABLE pulls ADD COLUMN head_pushed_by TEXT;
67ALTER TABLE pulls ADD COLUMN head_pushed_at TEXT;
68
69-- The integration that reported a status: actions, deployments, security
70-- or g1t. A required check can insist on one.
71ALTER TABLE commit_statuses ADD COLUMN source TEXT;
72
73-- Branch protection becomes a ruleset, holding exactly what it held: the
74-- default branch's pull request rule (approvals, code owners), required
75-- status checks and merge queue. Pushes stay allowed here; repositories
76-- that refused them are adopted as described above. Only for repositories
77-- whose settings protect anything.
78INSERT INTO rulesets (id, level, workspace, repo_id, name, enforcement, target, spec, source, created_by, created_at, updated_by, updated_at)
79SELECT
80 'rs_' || lower(hex(randomblob(12))),
81 'repository',
82 '',
83 s.repo_id,
84 'Default branch protection',
85 'active',
86 'branch',
87 json_object(
88 'name', 'Default branch protection',
89 'enforcement', 'active',
90 'target', 'branch',
91 'conditions', json_object('ref_name', json_object('include', json_array('~DEFAULT_BRANCH'), 'exclude', json_array())),
92 'bypass_actors', json_array(),
93 'rules', (
94 SELECT json_group_array(json(rule.value))
95 FROM json_each(json_array(
96 CASE WHEN s.required_approvals > 0 OR s.require_code_owner_review != 0 THEN json_object(
97 'type', 'pull_request',
98 'parameters', json_object(
99 'required_approvals', s.required_approvals,
100 'count_agent_approvals', json(CASE WHEN s.count_agent_approvals != 0 THEN 'true' ELSE 'false' END),
101 'dismiss_stale_reviews_on_push', json('false'),
102 'require_code_owner_review', json(CASE WHEN s.require_code_owner_review != 0 THEN 'true' ELSE 'false' END),
103 'require_last_push_approval', json('false'),
104 'allowed_merge_methods', json_array(),
105 'allow_direct_pushes', json('true')
106 ),
107 'applies_to', 'everyone'
108 ) END,
109 CASE WHEN s.required_checks != '[]' OR s.require_up_to_date != 0 THEN json_object(
110 'type', 'required_status_checks',
111 'parameters', json_object(
112 'checks', (SELECT json_group_array(json_object('context', checks.value)) FROM json_each(s.required_checks) AS checks),
113 'strict', json(CASE WHEN s.require_up_to_date != 0 THEN 'true' ELSE 'false' END),
114 'paths', json_array(),
115 'allow_bypass_on_merge', json(CASE WHEN s.allow_ignoring_checks != 0 THEN 'true' ELSE 'false' END)
116 ),
117 'applies_to', 'everyone'
118 ) END,
119 CASE WHEN s.merge_queue != 0 THEN json_object(
120 'type', 'merge_queue',
121 'parameters', json_object(
122 'merge_method', 'merge',
123 'max_entries_to_build', 4,
124 'min_entries_to_merge', 1,
125 'min_entries_wait_minutes', 0,
126 'check_response_timeout_minutes', 45
127 ),
128 'applies_to', 'everyone'
129 ) END
130 )) AS rule
131 WHERE rule.type != 'null'
132 )
133 ),
134 'branch_protection',
135 s.updated_by,
136 s.updated_at,
137 s.updated_by,
138 s.updated_at
139FROM repo_settings s
140WHERE s.required_approvals > 0
141 OR s.require_code_owner_review != 0
142 OR s.required_checks != '[]'
143 OR s.require_up_to_date != 0
144 OR s.merge_queue != 0;

This file's history is long; its oldest lines are credited to the oldest commit read.