MySQL · 9976 bytes Raw Blame History
1 -- SPDX-License-Identifier: AGPL-3.0-or-later
2
3 -- name: InsertWorkflowRun :one
4 INSERT INTO workflow_runs (
5 repo_id, run_index, workflow_file, workflow_name,
6 head_sha, head_ref, event, event_payload,
7 actor_user_id, parent_run_id, concurrency_group, need_approval
8 ) VALUES (
9 $1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12
10 )
11 RETURNING id, repo_id, run_index, workflow_file, workflow_name,
12 head_sha, head_ref, event, event_payload,
13 actor_user_id, parent_run_id, concurrency_group,
14 status, conclusion, pinned, need_approval, approved_by_user_id,
15 started_at, completed_at, version, created_at, updated_at, trigger_event_id;
16
17 -- name: EnqueueWorkflowRun :one
18 -- Idempotent insert: if a row with the same (repo_id, workflow_file,
19 -- trigger_event_id) already exists, returns no rows (pgx.ErrNoRows in
20 -- Go). The handler treats that as a successful no-op so worker
21 -- retries and admin replays of the same triggering event don't
22 -- duplicate runs.
23 --
24 -- The ON CONFLICT predicate matches the partial unique index defined
25 -- in migration 0051; both must agree for postgres to infer the
26 -- target.
27 INSERT INTO workflow_runs (
28 repo_id, run_index, workflow_file, workflow_name,
29 head_sha, head_ref, event, event_payload,
30 actor_user_id, parent_run_id, concurrency_group, need_approval,
31 trigger_event_id
32 ) VALUES (
33 $1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13
34 )
35 ON CONFLICT (repo_id, workflow_file, trigger_event_id) WHERE trigger_event_id <> ''
36 DO NOTHING
37 RETURNING id, repo_id, run_index, workflow_file, workflow_name,
38 head_sha, head_ref, event, event_payload,
39 actor_user_id, parent_run_id, concurrency_group,
40 status, conclusion, pinned, need_approval, approved_by_user_id,
41 started_at, completed_at, version, created_at, updated_at, trigger_event_id;
42
43 -- name: LookupWorkflowRunByTriggerEvent :one
44 -- Companion to EnqueueWorkflowRun for the conflict path: when an
45 -- INSERT ... ON CONFLICT DO NOTHING returns no rows, the trigger
46 -- handler uses this to find the existing row so it can surface a
47 -- stable RunID. Matches the partial-unique index from migration 0051.
48 SELECT id, repo_id, run_index, workflow_file, workflow_name,
49 head_sha, head_ref, event, event_payload,
50 actor_user_id, parent_run_id, concurrency_group,
51 status, conclusion, pinned, need_approval, approved_by_user_id,
52 started_at, completed_at, version, created_at, updated_at, trigger_event_id
53 FROM workflow_runs
54 WHERE repo_id = $1 AND workflow_file = $2 AND trigger_event_id = $3;
55
56 -- name: GetWorkflowRunByID :one
57 SELECT id, repo_id, run_index, workflow_file, workflow_name,
58 head_sha, head_ref, event, event_payload,
59 actor_user_id, parent_run_id, concurrency_group,
60 status, conclusion, pinned, need_approval, approved_by_user_id,
61 started_at, completed_at, version, created_at, updated_at, trigger_event_id
62 FROM workflow_runs
63 WHERE id = $1;
64
65 -- name: ListBlockingConcurrencyRunsForUpdate :many
66 -- Older queued/running runs with the same group block the new run while they
67 -- still have at least one queued/running job that has not already received a
68 -- cancel request. cancel-in-progress releases the slot by flipping that job
69 -- flag even if the runner is still draining the old container.
70 SELECT r.id, r.repo_id, r.run_index, r.workflow_file, r.workflow_name,
71 r.head_sha, r.head_ref, r.event, r.event_payload,
72 r.actor_user_id, r.parent_run_id, r.concurrency_group,
73 r.status, r.conclusion, r.pinned, r.need_approval, r.approved_by_user_id,
74 r.started_at, r.completed_at, r.version, r.created_at, r.updated_at, r.trigger_event_id
75 FROM workflow_runs r
76 JOIN workflow_runs current_run ON current_run.id = sqlc.arg(run_id)::bigint
77 WHERE r.repo_id = sqlc.arg(repo_id)::bigint
78 AND r.concurrency_group = sqlc.arg(concurrency_group)::text
79 AND r.concurrency_group <> ''
80 AND r.id <> current_run.id
81 AND r.status IN ('queued', 'running')
82 AND (r.created_at, r.id) < (current_run.created_at, current_run.id)
83 AND EXISTS (
84 SELECT 1
85 FROM workflow_jobs j
86 WHERE j.run_id = r.id
87 AND j.status IN ('queued', 'running')
88 AND j.cancel_requested = false
89 )
90 ORDER BY r.created_at ASC, r.id ASC
91 FOR UPDATE OF r;
92
93 -- name: GetWorkflowRunForRepoByIndex :one
94 SELECT r.id, r.repo_id, r.run_index, r.workflow_file, r.workflow_name,
95 r.head_sha, r.head_ref, r.event, r.event_payload,
96 r.actor_user_id, COALESCE(u.username::text, '')::text AS actor_username,
97 r.parent_run_id, r.concurrency_group,
98 r.status, r.conclusion, r.pinned, r.need_approval, r.approved_by_user_id,
99 r.started_at, r.completed_at, r.version, r.created_at, r.updated_at, r.trigger_event_id
100 FROM workflow_runs r
101 LEFT JOIN users u ON u.id = r.actor_user_id
102 WHERE r.repo_id = $1 AND r.run_index = $2;
103
104 -- name: MarkWorkflowRunRunning :exec
105 UPDATE workflow_runs
106 SET status = 'running',
107 started_at = COALESCE(started_at, now()),
108 version = version + 1,
109 updated_at = now()
110 WHERE id = $1 AND status = 'queued';
111
112 -- name: StartWorkflowRun :one
113 UPDATE workflow_runs
114 SET status = 'running',
115 started_at = COALESCE(started_at, now()),
116 version = version + 1,
117 updated_at = now()
118 WHERE id = $1 AND status = 'queued'
119 RETURNING id, repo_id, run_index, workflow_file, workflow_name,
120 head_sha, head_ref, event, event_payload,
121 actor_user_id, parent_run_id, concurrency_group,
122 status, conclusion, pinned, need_approval, approved_by_user_id,
123 started_at, completed_at, version, created_at, updated_at, trigger_event_id;
124
125 -- name: CompleteWorkflowRun :one
126 UPDATE workflow_runs
127 SET status = 'completed',
128 conclusion = sqlc.arg(conclusion)::check_conclusion,
129 started_at = COALESCE(started_at, now()),
130 completed_at = COALESCE(completed_at, now()),
131 version = version + 1,
132 updated_at = now()
133 WHERE id = $1
134 RETURNING id, repo_id, run_index, workflow_file, workflow_name,
135 head_sha, head_ref, event, event_payload,
136 actor_user_id, parent_run_id, concurrency_group,
137 status, conclusion, pinned, need_approval, approved_by_user_id,
138 started_at, completed_at, version, created_at, updated_at, trigger_event_id;
139
140 -- name: NextRunIndexForRepo :one
141 -- Atomic next-index emitter: take the max + 1 for this repo. Pairs
142 -- with the (repo_id, run_index) UNIQUE so concurrent inserts that
143 -- race here will catch a unique-violation and the caller retries.
144 -- Cast to bigint so sqlc generates int64 (the column type) rather
145 -- than int32 (the type the +1 literal would default to).
146 SELECT (COALESCE(MAX(run_index), 0) + 1)::bigint AS next_index
147 FROM workflow_runs
148 WHERE repo_id = $1;
149
150 -- name: ListWorkflowRunsForRepo :many
151 SELECT r.id, r.repo_id, r.run_index, r.workflow_file, r.workflow_name,
152 r.head_sha, r.head_ref, r.event, r.status, r.conclusion,
153 r.actor_user_id, COALESCE(u.username::text, '')::text AS actor_username,
154 r.started_at, r.completed_at, r.created_at, r.updated_at
155 FROM workflow_runs r
156 LEFT JOIN users u ON u.id = r.actor_user_id
157 WHERE r.repo_id = sqlc.arg(repo_id)::bigint
158 AND (sqlc.narg(workflow_file)::text IS NULL OR r.workflow_file = sqlc.narg(workflow_file)::text)
159 AND (sqlc.narg(head_ref)::text IS NULL OR r.head_ref = sqlc.narg(head_ref)::text)
160 AND (sqlc.narg(event)::workflow_run_event IS NULL OR r.event = sqlc.narg(event)::workflow_run_event)
161 AND (sqlc.narg(status)::workflow_run_status IS NULL OR r.status = sqlc.narg(status)::workflow_run_status)
162 AND (sqlc.narg(conclusion)::check_conclusion IS NULL OR r.conclusion = sqlc.narg(conclusion)::check_conclusion)
163 AND (sqlc.narg(actor_username)::text IS NULL OR u.username = sqlc.narg(actor_username)::citext)
164 ORDER BY r.created_at DESC, r.id DESC
165 LIMIT sqlc.arg(page_limit) OFFSET sqlc.arg(page_offset);
166
167 -- name: CountWorkflowRunsForRepo :one
168 SELECT COUNT(*)::bigint
169 FROM workflow_runs r
170 LEFT JOIN users u ON u.id = r.actor_user_id
171 WHERE r.repo_id = sqlc.arg(repo_id)::bigint
172 AND (sqlc.narg(workflow_file)::text IS NULL OR r.workflow_file = sqlc.narg(workflow_file)::text)
173 AND (sqlc.narg(head_ref)::text IS NULL OR r.head_ref = sqlc.narg(head_ref)::text)
174 AND (sqlc.narg(event)::workflow_run_event IS NULL OR r.event = sqlc.narg(event)::workflow_run_event)
175 AND (sqlc.narg(status)::workflow_run_status IS NULL OR r.status = sqlc.narg(status)::workflow_run_status)
176 AND (sqlc.narg(conclusion)::check_conclusion IS NULL OR r.conclusion = sqlc.narg(conclusion)::check_conclusion)
177 AND (sqlc.narg(actor_username)::text IS NULL OR u.username = sqlc.narg(actor_username)::citext);
178
179 -- name: ListActiveWorkflowRunsForAdmin :many
180 SELECT id, repo_id, run_index, workflow_file, workflow_name,
181 head_sha, head_ref, event, event_payload,
182 actor_user_id, parent_run_id, concurrency_group,
183 status, conclusion, pinned, need_approval, approved_by_user_id,
184 started_at, completed_at, version, created_at, updated_at, trigger_event_id
185 FROM workflow_runs
186 WHERE status IN ('queued', 'running')
187 AND (sqlc.arg(repo_id)::bigint = 0 OR repo_id = sqlc.arg(repo_id)::bigint)
188 ORDER BY created_at ASC, id ASC
189 LIMIT sqlc.arg(limit_count)::int;
190
191 -- name: ListWorkflowRunWorkflowsForRepo :many
192 WITH ranked AS (
193 SELECT workflow_file,
194 workflow_name,
195 (COUNT(*) OVER (PARTITION BY workflow_file))::bigint AS run_count,
196 ROW_NUMBER() OVER (PARTITION BY workflow_file ORDER BY created_at DESC, id DESC) AS rn
197 FROM workflow_runs
198 WHERE repo_id = $1
199 )
200 SELECT workflow_file,
201 COALESCE(NULLIF(workflow_name, ''), workflow_file) AS workflow_name,
202 run_count
203 FROM ranked
204 WHERE rn = 1
205 ORDER BY lower(COALESCE(NULLIF(workflow_name, ''), workflow_file)), workflow_file;
206
207 -- name: DeleteOldWorkflowRunsForCleanup :execrows
208 DELETE FROM workflow_runs
209 WHERE pinned = false
210 AND status IN ('completed', 'cancelled')
211 AND completed_at IS NOT NULL
212 AND completed_at < $1;
213