pr_01m47d15m3e54sn21z27rpy5n9/crates/contracts/src/actions.rs

393 lines12,770 bytesCodeBlame
1//! The actions service: GitHub Actions workflows, run on g1t as they are.
2//!
3//! A repository's `.g1t/workflows/*.yml`, in GitHub's format, are read
4//! from the commit an
5//! event is about (the default branch for issues, schedules and manual
6//! runs). Each workflow an event starts becomes a run; each job of the run
7//! (one per matrix combination) runs in a sandbox once the jobs it needs
8//! have finished. Jobs report their steps and logs back as they go, and a
9//! run on a pull request's head is a status on that pull request.
10//!
11//! Secrets and variables belong to a repository or to its workspace; a
12//! repository's override its workspace's of the same name. Secret values
13//! are sealed at rest and never returned.
14//!
15//! Mirrors `packages/contracts/src/actions.ts`.
16
17use serde::{Deserialize, Serialize};
18use serde_json::Value;
19
20use crate::repos::RepoPath;
21use crate::{User, Viewer};
22
23/// A note on something in a workflow that runs differently on g1t.
24#[derive(Clone, Debug, Serialize, Deserialize)]
25#[serde(rename_all = "camelCase")]
26pub struct WorkflowNote {
27 /// `info`, `warning` or `unsupported`.
28 pub severity: String,
29 pub job: Option<String>,
30 pub message: String,
31}
32
33#[derive(Clone, Debug, Serialize, Deserialize)]
34#[serde(rename_all = "camelCase")]
35pub struct Workflow {
36 pub id: String,
37 /// `.g1t/workflows/ci.yml`.
38 pub path: String,
39 pub name: String,
40 /// The events that start it, such as `push` and `pull_request`.
41 pub events: Vec<String>,
42 /// `active`, or `disabled` when a member turned it off.
43 pub state: String,
44 /// Why the file cannot be used, if it cannot.
45 pub error: Option<String>,
46 pub notes: Vec<WorkflowNote>,
47 /// `on.workflow_dispatch.inputs` as written, when it can be run by hand.
48 pub dispatch: Option<Value>,
49 pub last_run: Option<WorkflowRun>,
50}
51
52#[derive(Clone, Debug, Serialize, Deserialize)]
53#[serde(rename_all = "camelCase")]
54pub struct WorkflowRun {
55 pub id: String,
56 pub workflow_id: String,
57 pub path: String,
58 /// The workflow's name.
59 pub name: String,
60 /// `run-name`, or what started it: a commit's subject, a pull request's title.
61 pub title: String,
62 /// Counts the workflow's runs: 1, 2, 3…
63 pub number: u64,
64 pub attempt: u64,
65 /// The GitHub event: `push`, `pull_request`, `schedule`…
66 pub event: String,
67 #[serde(rename = "ref")]
68 pub git_ref: String,
69 pub sha: String,
70 /// The pull request it ran for, if any.
71 pub pull: Option<u32>,
72 /// `queued`, `in_progress` or `completed`.
73 pub status: String,
74 /// When completed: `success`, `failure`, `cancelled` or `skipped`.
75 pub conclusion: Option<String>,
76 /// Why it could not start, such as a workflow file that does not read.
77 pub error: Option<String>,
78 /// Username of whoever caused it.
79 pub actor: Option<String>,
80 pub created_at: String,
81 pub started_at: Option<String>,
82 pub finished_at: Option<String>,
83}
84
85#[derive(Clone, Debug, Default, Serialize, Deserialize)]
86#[serde(rename_all = "camelCase")]
87pub struct StepState {
88 /// From 1.
89 pub number: u32,
90 pub name: String,
91 /// `queued`, `in_progress` or `completed`.
92 pub status: String,
93 /// `success`, `failure`, `cancelled` or `skipped`.
94 pub conclusion: Option<String>,
95 pub started_at: Option<String>,
96 pub finished_at: Option<String>,
97}
98
99/// A message a step left with `::error::`, `::warning::` or `::notice::`.
100#[derive(Clone, Debug, Default, Serialize, Deserialize)]
101#[serde(rename_all = "camelCase")]
102pub struct Annotation {
103 /// `error`, `warning` or `notice`.
104 pub level: String,
105 pub message: String,
106 pub title: Option<String>,
107 pub file: Option<String>,
108 pub line: Option<u32>,
109}
110
111#[derive(Clone, Debug, Serialize, Deserialize)]
112#[serde(rename_all = "camelCase")]
113pub struct Job {
114 pub id: String,
115 pub run_id: String,
116 /// Its key under `jobs:`.
117 pub key: String,
118 /// With its matrix combination: `test (ubuntu-latest, 20)`.
119 pub name: String,
120 pub needs: Vec<String>,
121 /// `queued`, `waiting` (for the jobs it needs), `in_progress` or `completed`.
122 pub status: String,
123 pub conclusion: Option<String>,
124 pub steps: Vec<StepState>,
125 pub annotations: Vec<Annotation>,
126 /// Why it did not run, or what stopped it.
127 pub reason: Option<String>,
128 pub started_at: Option<String>,
129 pub finished_at: Option<String>,
130}
131
132#[derive(Clone, Debug, Serialize, Deserialize)]
133#[serde(rename_all = "camelCase")]
134pub struct RunDetail {
135 pub run: WorkflowRun,
136 pub jobs: Vec<Job>,
137 /// The workflow's notes, as of the run's commit.
138 pub notes: Vec<WorkflowNote>,
139}
140
141#[derive(Clone, Debug, Serialize, Deserialize)]
142#[serde(rename_all = "camelCase")]
143pub struct LogChunk {
144 pub seq: u64,
145 /// The step it belongs to, from 1; 0 for the job's setup.
146 pub step: u32,
147 pub text: String,
148}
149
150#[derive(Clone, Debug, Serialize, Deserialize)]
151#[serde(rename_all = "camelCase")]
152pub struct JobLog {
153 pub chunks: Vec<LogChunk>,
154 /// Whether the job has finished, so no more will come.
155 pub done: bool,
156}
157
158/// Who may read a secret or variable: workflows (`secrets.*` and `vars.*`
159/// in GitHub Actions) and deployments (a deploy build's environment and the
160/// running app's bindings). Agents, checks and the merge queue read none.
161pub const CONSUMERS: [&str; 2] = ["workflows", "deployments"];
162
163/// One row of a repository's or workspace's secrets and variables, as
164/// Vercel lists environment variables: a key, its type, the environments
165/// it applies to and who reads it. A key may have one row per environment.
166/// Secrets' values are never returned.
167#[derive(Clone, Debug, Serialize, Deserialize)]
168#[serde(rename_all = "camelCase")]
169pub struct Setting {
170 #[serde(default)]
171 pub id: String,
172 pub name: String,
173 /// `secret`, or `variable` (shown as Config).
174 #[serde(default)]
175 pub kind: String,
176 /// A variable's value; secrets' are never returned.
177 pub value: Option<String>,
178 /// `repository` or `workspace`.
179 pub scope: String,
180 pub updated_at: String,
181 /// `workflows` and/or `deployments`.
182 #[serde(default)]
183 pub available_to: Vec<String>,
184 /// The environments it applies to; empty is every environment.
185 #[serde(default)]
186 pub environments: Vec<String>,
187 /// A workspace's row: the repositories it reaches, by name; empty is
188 /// every repository.
189 #[serde(default)]
190 pub repositories: Vec<String>,
191 #[serde(default)]
192 pub note: Option<String>,
193 #[serde(default)]
194 pub updated_by: Option<String>,
195}
196
197// --- Methods ---------------------------------------------------------------
198
199/// `workflows`. Returns `Outcome<Vec<Workflow>>`.
200#[derive(Debug, Serialize, Deserialize)]
201pub struct WorkflowsArgs {
202 pub repo: RepoPath,
203 pub viewer: Viewer,
204}
205
206/// `runs`: newest first. Returns `Outcome<Vec<WorkflowRun>>`.
207#[derive(Debug, Serialize, Deserialize)]
208pub struct RunsArgs {
209 pub repo: RepoPath,
210 pub viewer: Viewer,
211 /// A workflow's id or file name.
212 #[serde(default)]
213 pub workflow: Option<String>,
214 #[serde(default)]
215 pub branch: Option<String>,
216 #[serde(default)]
217 pub event: Option<String>,
218 /// The pull request's number.
219 #[serde(default)]
220 pub pull: Option<u32>,
221 #[serde(default)]
222 pub sha: Option<String>,
223 #[serde(default)]
224 pub limit: Option<u32>,
225}
226
227/// `run`. Returns `Outcome<RunDetail>`.
228#[derive(Debug, Serialize, Deserialize)]
229pub struct RunArgs {
230 pub repo: RepoPath,
231 pub viewer: Viewer,
232 pub id: String,
233}
234
235/// `logs`: a job's log after `after`. Returns `Outcome<JobLog>`.
236#[derive(Debug, Serialize, Deserialize)]
237pub struct LogsArgs {
238 pub repo: RepoPath,
239 pub viewer: Viewer,
240 pub job: String,
241 #[serde(default)]
242 pub after: u64,
243}
244
245/// `dispatch`: run a workflow that has `workflow_dispatch`. Members only.
246/// Returns `Outcome<WorkflowRun>`.
247#[derive(Debug, Serialize, Deserialize)]
248pub struct DispatchArgs {
249 pub actor: User,
250 pub repo: RepoPath,
251 /// A workflow's id or file name.
252 pub workflow: String,
253 /// A branch or tag; the default branch when absent.
254 #[serde(default, rename = "ref")]
255 pub git_ref: Option<String>,
256 #[serde(default)]
257 pub inputs: serde_json::Map<String, Value>,
258}
259
260/// `cancel` and `rerun` (all jobs, or with `failed_only` the ones that did
261/// not succeed). Members only. Returns `Outcome<WorkflowRun>`.
262#[derive(Debug, Serialize, Deserialize)]
263pub struct RunActionArgs {
264 pub actor: User,
265 pub repo: RepoPath,
266 pub id: String,
267 #[serde(default)]
268 pub failed_only: bool,
269}
270
271/// `set_workflow_enabled`. Members only. Returns `Outcome<Workflow>`.
272#[derive(Debug, Serialize, Deserialize)]
273pub struct SetWorkflowEnabledArgs {
274 pub actor: User,
275 pub repo: RepoPath,
276 pub workflow: String,
277 pub enabled: bool,
278}
279
280/// Whose secrets or variables: a repository's, or with only `workspace`,
281/// a workspace's.
282#[derive(Clone, Debug, Serialize, Deserialize)]
283pub struct SettingsOwner {
284 #[serde(default)]
285 pub repo: Option<RepoPath>,
286 #[serde(default)]
287 pub workspace: Option<String>,
288}
289
290/// `settings`: the secrets (`kind: secret`) or variables (`kind: variable`)
291/// of a repository, with its workspace's, or of a workspace. Members only.
292/// Returns `Outcome<Vec<Setting>>`.
293#[derive(Debug, Serialize, Deserialize)]
294pub struct SettingsArgs {
295 pub actor: User,
296 #[serde(flatten)]
297 pub owner: SettingsOwner,
298 pub kind: String,
299}
300
301/// `set_setting`: add or replace one. A repository's need a member; a
302/// workspace's an owner. Returns `Outcome<Setting>`.
303#[derive(Debug, Serialize, Deserialize)]
304pub struct SetSettingArgs {
305 pub actor: User,
306 #[serde(flatten)]
307 pub owner: SettingsOwner,
308 /// `secret` or `variable`. Changing a variable's row to `secret` seals
309 /// it; a secret cannot become a variable.
310 pub kind: String,
311 pub name: String,
312 /// The row to change. Left out, the key's row for every environment, as
313 /// GitHub's API addresses a secret by name alone.
314 #[serde(default)]
315 pub id: Option<String>,
316 /// Needed for a new row; left out, an existing row keeps its value.
317 #[serde(default)]
318 pub value: Option<String>,
319 /// `workflows` and/or `deployments`; left out, unchanged (both, for a
320 /// new row).
321 #[serde(default, alias = "availableTo")]
322 pub available_to: Option<Vec<String>>,
323 /// The environments it applies to; empty is every one. Left out,
324 /// unchanged.
325 #[serde(default)]
326 pub environments: Option<Vec<String>>,
327 /// A workspace's row: repository names; empty for every one.
328 #[serde(default)]
329 pub repositories: Option<Vec<String>>,
330 #[serde(default)]
331 pub note: Option<String>,
332}
333
334/// `resolve_settings`: the secrets and variables one reader gets, for the
335/// services that hand them out (the deployments service). Returns
336/// `ResolvedSettings`.
337#[derive(Debug, Serialize, Deserialize)]
338#[serde(rename_all = "camelCase")]
339pub struct ResolveSettingsArgs {
340 pub repo_id: String,
341 pub repo: RepoPath,
342 /// `workflows` or `deployments`.
343 pub consumer: String,
344 /// The environment being read for, such as `production` or `preview`.
345 #[serde(default)]
346 pub environment: Option<String>,
347 /// Whether the run is trusted; an untrusted one gets no secrets.
348 pub trusted: bool,
349}
350
351#[derive(Debug, Default, Serialize, Deserialize)]
352pub struct ResolvedSettings {
353 pub secrets: serde_json::Map<String, serde_json::Value>,
354 pub variables: serde_json::Map<String, serde_json::Value>,
355}
356
357/// `delete_setting`. Returns `Outcome<bool>`.
358#[derive(Debug, Serialize, Deserialize)]
359pub struct DeleteSettingArgs {
360 pub actor: User,
361 #[serde(flatten)]
362 pub owner: SettingsOwner,
363 pub kind: String,
364 pub name: String,
365 /// One row; left out, every row of the key.
366 #[serde(default)]
367 pub id: Option<String>,
368}
369
370/// `job_spec` and `job_report`: the sandbox running a job, with the job's
371/// own token. `report` is one of:
372/// `{"kind": "step", "number", "status", "conclusion"}`,
373/// `{"kind": "log", "step", "text"}`,
374/// `{"kind": "annotation", "level", "message", "title", "file", "line"}`,
375/// `{"kind": "done", "conclusion", "outputs", "reason"}`.
376#[derive(Debug, Serialize, Deserialize)]
377pub struct JobCallArgs {
378 pub job: String,
379 pub token: String,
380 #[serde(default)]
381 pub report: Value,
382}
383
384/// What the runner needs to start a job's sandbox.
385#[derive(Debug, Serialize, Deserialize)]
386#[serde(rename_all = "camelCase")]
387pub struct StartJobArgs {
388 pub job: String,
389 pub token: String,
390 pub repo: RepoPath,
391 /// Minutes before the job is stopped.
392 pub timeout_minutes: u32,
393}