MySQL · 4193 bytes Raw Blame History
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;
95