| 1 | -- SPDX-License-Identifier: AGPL-3.0-or-later |
| 2 | -- |
| 3 | -- S22 pull requests subsystem. PRs reuse the S21 issues table for |
| 4 | -- title/body/state/timeline/comments/labels/milestones/assignees; |
| 5 | -- this migration adds the PR-specific surface: |
| 6 | -- |
| 7 | -- pull_requests — keyed on issue_id; PR-only fields |
| 8 | -- pull_request_commits — head-side commit list (refreshed on sync) |
| 9 | -- pull_request_files — changed-files list (refreshed on sync) |
| 10 | -- |
| 11 | -- Plus the merge-method config columns on `repos` that S11 deferred: |
| 12 | -- `allow_squash_merge`, `allow_rebase_merge`, `allow_merge_commit`, |
| 13 | -- `default_merge_method`. UI hides disallowed methods at merge time. |
| 14 | |
| 15 | -- +goose Up |
| 16 | |
| 17 | CREATE TYPE pr_merge_method AS ENUM ('merge', 'squash', 'rebase'); |
| 18 | CREATE TYPE pr_mergeable_state AS ENUM ('unknown', 'clean', 'dirty', 'blocked', 'behind'); |
| 19 | CREATE TYPE pr_file_status AS ENUM ('added', 'modified', 'deleted', 'renamed', 'copied'); |
| 20 | |
| 21 | ALTER TABLE repos |
| 22 | ADD COLUMN allow_squash_merge boolean NOT NULL DEFAULT true, |
| 23 | ADD COLUMN allow_rebase_merge boolean NOT NULL DEFAULT true, |
| 24 | ADD COLUMN allow_merge_commit boolean NOT NULL DEFAULT true, |
| 25 | ADD COLUMN default_merge_method pr_merge_method NOT NULL DEFAULT 'merge', |
| 26 | ADD CONSTRAINT repos_at_least_one_merge_method CHECK ( |
| 27 | allow_squash_merge OR allow_rebase_merge OR allow_merge_commit |
| 28 | ); |
| 29 | |
| 30 | |
| 31 | CREATE TABLE pull_requests ( |
| 32 | issue_id bigint PRIMARY KEY REFERENCES issues(id) ON DELETE CASCADE, |
| 33 | base_ref text NOT NULL, -- e.g. "trunk" |
| 34 | head_ref text NOT NULL, -- e.g. "feature/x" |
| 35 | head_repo_id bigint NOT NULL REFERENCES repos(id) ON DELETE CASCADE, |
| 36 | -- Snapshotted at PR open + every synchronize so the diff renderer |
| 37 | -- and merge-tree probe always have stable inputs even if the |
| 38 | -- branches move between job ticks. |
| 39 | base_oid text NOT NULL DEFAULT '', |
| 40 | head_oid text NOT NULL DEFAULT '', |
| 41 | draft boolean NOT NULL DEFAULT false, |
| 42 | mergeable boolean, -- NULL until first probe |
| 43 | mergeable_state pr_mergeable_state NOT NULL DEFAULT 'unknown', |
| 44 | merge_commit_sha text, |
| 45 | merged_at timestamptz, |
| 46 | merged_by_user_id bigint REFERENCES users(id) ON DELETE SET NULL, |
| 47 | merge_method pr_merge_method, |
| 48 | base_oid_at_merge text, |
| 49 | head_oid_at_merge text, |
| 50 | last_synchronized_at timestamptz, |
| 51 | |
| 52 | -- Same-repo PR can't merge a branch into itself. Cross-fork PRs |
| 53 | -- (S27) will need a richer invariant covering head_repo_id != repo_id. |
| 54 | CONSTRAINT pull_requests_base_head_distinct CHECK (base_ref <> head_ref) |
| 55 | ); |
| 56 | |
| 57 | CREATE INDEX pull_requests_head_idx ON pull_requests (head_repo_id, head_ref); |
| 58 | CREATE INDEX pull_requests_state_idx ON pull_requests (head_repo_id, mergeable_state); |
| 59 | |
| 60 | |
| 61 | CREATE TABLE pull_request_commits ( |
| 62 | pr_id bigint NOT NULL REFERENCES pull_requests(issue_id) ON DELETE CASCADE, |
| 63 | sha text NOT NULL, |
| 64 | position int NOT NULL, -- 0-based, head-side order |
| 65 | author_name text NOT NULL DEFAULT '', |
| 66 | author_email text NOT NULL DEFAULT '', |
| 67 | committer_name text NOT NULL DEFAULT '', |
| 68 | committer_email text NOT NULL DEFAULT '', |
| 69 | subject text NOT NULL DEFAULT '', |
| 70 | body text NOT NULL DEFAULT '', |
| 71 | authored_at timestamptz, |
| 72 | committed_at timestamptz, |
| 73 | |
| 74 | PRIMARY KEY (pr_id, sha) |
| 75 | ); |
| 76 | |
| 77 | CREATE INDEX pull_request_commits_position_idx |
| 78 | ON pull_request_commits (pr_id, position); |
| 79 | |
| 80 | |
| 81 | CREATE TABLE pull_request_files ( |
| 82 | pr_id bigint NOT NULL REFERENCES pull_requests(issue_id) ON DELETE CASCADE, |
| 83 | path text NOT NULL, |
| 84 | status pr_file_status NOT NULL, |
| 85 | old_path text, |
| 86 | additions int NOT NULL DEFAULT 0, |
| 87 | deletions int NOT NULL DEFAULT 0, |
| 88 | changes int NOT NULL DEFAULT 0, |
| 89 | |
| 90 | PRIMARY KEY (pr_id, path) |
| 91 | ); |
| 92 | |
| 93 | |
| 94 | -- +goose Down |
| 95 | DROP TABLE IF EXISTS pull_request_files; |
| 96 | DROP TABLE IF EXISTS pull_request_commits; |
| 97 | DROP TABLE IF EXISTS pull_requests; |
| 98 | ALTER TABLE repos |
| 99 | DROP CONSTRAINT IF EXISTS repos_at_least_one_merge_method, |
| 100 | DROP COLUMN IF EXISTS default_merge_method, |
| 101 | DROP COLUMN IF EXISTS allow_merge_commit, |
| 102 | DROP COLUMN IF EXISTS allow_rebase_merge, |
| 103 | DROP COLUMN IF EXISTS allow_squash_merge; |
| 104 | DROP TYPE IF EXISTS pr_file_status; |
| 105 | DROP TYPE IF EXISTS pr_mergeable_state; |
| 106 | DROP TYPE IF EXISTS pr_merge_method; |
| 107 |