Skip to content
1,340 linesCodeBlameRaw

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.

GitHub Actions on g1t, part two: running workflows1//! The actions service: GitHub Actions workflows, run on g1t as they are.
2//!
GitHub Actions on g1t, part three: .g1t/workflows, the pages, the docs3//! A repository's `.g1t/workflows/*.yml`, in GitHub's format, are read
4//! from the commit an
GitHub Actions on g1t, part two: running workflows5//! 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,
GitHub Actions on g1t, part three: .g1t/workflows, the pages, the docs37 /// `.g1t/workflows/ci.yml`.
GitHub Actions on g1t, part two: running workflows38 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>,
Merge branch 'worktree-agent-a3abfcce648e87dca'126 /// Why it did not run, what stopped it, or what it waits for.
GitHub Actions on g1t, part two: running workflows127 pub reason: Option<String>,
128 pub started_at: Option<String>,
129 pub finished_at: Option<String>,
Merge branch 'worktree-agent-a3abfcce648e87dca'130 /// The environment it names, once its needs are done (an expression
131 /// read by then). A job held by the environment's protection rules is
132 /// `pending` until they let it through.
133 #[serde(default)]
134 pub environment: Option<String>,
Fast pages, required checks on the branch, self-hosted runners, honest incidents135 /// Its `runs-on` names self-hosted runners (see `runners`).
136 #[serde(default)]
137 pub self_hosted: bool,
138 /// The self-hosted runner that took it, by name.
139 #[serde(default)]
140 pub runner: Option<String>,
Merge Actions runs: summaries, attempts and re-runs, graceful cancel, log downloads, badges (actions 0009)141 /// It was cancelled and is running its `if: always()` and `cancelled()`
142 /// steps and its post steps before it ends.
143 #[serde(default)]
144 pub cancelling: bool,
GitHub Actions on g1t, part two: running workflows145}
146
147#[derive(Clone, Debug, Serialize, Deserialize)]
148#[serde(rename_all = "camelCase")]
149pub struct RunDetail {
150 pub run: WorkflowRun,
151 pub jobs: Vec<Job>,
152 /// The workflow's notes, as of the run's commit.
153 pub notes: Vec<WorkflowNote>,
Merge branch 'worktree-agent-a3abfcce648e87dca'154 /// For a run of a pull request from outside: whether it waits for, or
155 /// had, someone's approval (`status` is `action_required` while it waits).
156 #[serde(default)]
157 pub approval: Option<RunApproval>,
158 /// The environments whose protection rules hold its jobs, this attempt.
159 #[serde(default)]
160 pub pending_deployments: Vec<PendingDeployment>,
Merge Actions runs: summaries, attempts and re-runs, graceful cancel, log downloads, badges (actions 0009)161 /// Every attempt of the run, oldest first, the one shown included.
162 /// `run.attempt` says which one `jobs` belong to.
163 #[serde(default)]
164 pub attempts: Vec<RunAttempt>,
Merge branch 'worktree-agent-a3abfcce648e87dca'165}
166
Merge Actions runs: summaries, attempts and re-runs, graceful cancel, log downloads, badges (actions 0009)167/// One attempt of a run: the first, or a re-run.
168#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
169#[serde(rename_all = "camelCase")]
170pub struct RunAttempt {
171 /// From 1.
172 pub attempt: u64,
173 /// `queued`, `in_progress` or `completed`; earlier attempts are completed.
174 pub status: String,
175 pub conclusion: Option<String>,
176 /// Who started it: whoever caused the run for the first, whoever re-ran
177 /// it for the rest.
178 pub actor: Option<String>,
179 /// It ran with debug logging (`RUNNER_DEBUG=1`).
180 pub debug: bool,
181 pub started_at: Option<String>,
182 pub finished_at: Option<String>,
183}
184
185/// One job's summary: what its steps wrote to `$GITHUB_STEP_SUMMARY`, in
186/// Markdown, masked.
187#[derive(Clone, Debug, Serialize, Deserialize)]
188#[serde(rename_all = "camelCase")]
189pub struct JobSummary {
190 /// The job's id, as `RunDetail.jobs` gives it for the attempt.
191 pub job_id: String,
192 pub name: String,
193 pub steps: Vec<StepSummary>,
194}
195
196#[derive(Clone, Debug, Serialize, Deserialize)]
197#[serde(rename_all = "camelCase")]
198pub struct StepSummary {
199 /// The step, from 1 (post steps follow the job's own).
200 pub step: u32,
201 pub markdown: String,
202}
203
204/// A job's whole log, for downloading: its steps, to split the text by.
205#[derive(Clone, Debug, Serialize, Deserialize)]
206#[serde(rename_all = "camelCase")]
207pub struct JobLogText {
208 pub job_id: String,
209 pub name: String,
210 pub steps: Vec<StepState>,
211 pub chunks: Vec<LogChunk>,
212 /// Whether the job has finished.
213 pub done: bool,
214 /// Its log was left out: the run's logs reached `MAX_RUN_LOG_BYTES`.
215 #[serde(default)]
216 pub omitted: bool,
217}
218
Merge branch 'worktree-agent-a3abfcce648e87dca'219/// A run that needed approval before it started.
220#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
221#[serde(rename_all = "camelCase")]
222pub struct RunApproval {
223 /// `required` while it waits, then `approved`.
224 pub state: String,
225 /// Why it waits, in words.
226 pub reason: String,
227 /// Who approved it.
228 pub approved_by: Option<String>,
229}
230
231/// One person or team who may approve a job's deployment to an
232/// environment.
233#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
234pub struct EnvironmentReviewer {
235 /// `user` or `team`.
236 #[serde(rename = "type")]
237 pub kind: String,
238 /// A username, or a team's slug in the repository's workspace.
239 pub name: String,
240}
241
242/// A branch or tag pattern an environment lets deploy.
243#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
244pub struct BranchPattern {
245 /// fnmatch-style, as branch filters are: `main`, `release/*`, `v*`.
246 pub name: String,
247 /// `branch` or `tag`.
248 #[serde(rename = "type", default = "branch_kind")]
249 pub kind: String,
250}
251
252fn branch_kind() -> String {
253 "branch".to_owned()
254}
255
256/// The most reviewers an environment may have, as on GitHub.
257pub const MAX_ENVIRONMENT_REVIEWERS: usize = 6;
258/// The longest wait timer, in minutes: 30 days.
259pub const MAX_WAIT_MINUTES: u32 = 43_200;
260
261/// An environment and its protection rules. Jobs that name it with
262/// `environment:` wait until the rules let them through; only then does the
263/// job get the environment's secrets.
264#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
265#[serde(rename_all = "camelCase")]
266pub struct Environment {
267 /// Lowercase.
268 pub name: String,
269 /// Who may approve its jobs; none means no review is needed.
270 pub reviewers: Vec<EnvironmentReviewer>,
271 /// Whoever started a run may not approve its jobs, even as a reviewer.
272 pub prevent_self_review: bool,
273 /// Minutes each job waits before it may start.
274 pub wait_minutes: u32,
275 /// Which refs may deploy: `all`, `protected` (branches the rules
276 /// protect, the default branch included) or `selected` (`branch_patterns`).
277 pub branch_policy: String,
278 pub branch_patterns: Vec<BranchPattern>,
279 /// Admins may approve without being reviewers, which also skips the wait.
280 pub admins_bypass: bool,
281 /// Whether it has rules saved; false for one only named by a workflow,
282 /// a secret or a deployment.
283 pub protected: bool,
284 pub updated_at: Option<String>,
285 pub updated_by: Option<String>,
GitHub Actions on g1t, part two: running workflows286}
287
Merge branch 'worktree-agent-a3abfcce648e87dca'288/// An environment holding a run's jobs, and where its rules stand.
289#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
290#[serde(rename_all = "camelCase")]
291pub struct PendingDeployment {
292 pub environment: String,
293 /// `waiting`, `approved` or `rejected`.
294 pub state: String,
295 /// Whether a reviewer must approve it before its jobs start.
296 pub needs_review: bool,
297 /// When its wait timer lets its jobs start, if it has one.
298 pub wait_until: Option<String>,
299 pub reviewers: Vec<EnvironmentReviewer>,
300 /// The jobs it holds, by name.
301 pub jobs: Vec<String>,
302 /// Whether the viewer may approve or reject it now.
303 #[serde(default)]
304 pub can_review: bool,
305 pub reviewed_by: Option<String>,
306 pub comment: Option<String>,
307 pub reviewed_at: Option<String>,
308}
309
310/// A repository's choices for its workflows.
311#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
312#[serde(rename_all = "camelCase")]
313pub struct ActionsSettings {
314 /// What a workflow without `permissions:` gets: `read` (contents and
315 /// packages read) or `write` (every permission). Unchosen, a repository
316 /// made before restricted tokens keeps `write`; a newer one takes its
317 /// workspace's default. Never more than the workspace's maximum.
318 pub default_permissions: String,
319 /// Whether the repository chose it, rather than taking it as above.
320 #[serde(default)]
321 pub default_chosen: bool,
322 /// The most the workspace lets a repository's default be.
323 #[serde(default = "write")]
324 pub max_permissions: String,
325 /// Which pull requests' runs wait for approval: `first_time_contributors`,
326 /// `outside_contributors` (the default) or `all_external_contributors`.
327 pub approval_policy: String,
328 /// Whether a job's token may open pull requests and approve them. Off
329 /// unless the repository turns it on, and only where the workspace
330 /// allows it.
331 #[serde(default)]
332 pub can_approve_pull_requests: bool,
333 /// Whether the workspace lets its repositories turn that on.
334 #[serde(default)]
335 pub workspace_allows_pull_requests: bool,
Merge Actions: cross-repo workflows and actions, release and deployment triggers, step timeouts336 /// Who may use this repository's actions and reusable workflows from
337 /// their workflows, when it is private: `none` (only itself, the
338 /// default) or `organization` (private repositories of its workspace).
339 /// A public repository's are anyone's. See [`ACCESS_LEVELS`].
340 #[serde(default = "no_access")]
341 pub access_level: String,
342}
343
344fn no_access() -> String {
345 "none".to_owned()
346}
347
348/// The values of `access_level`. `user` is read as `organization`: a
349/// personal account's repositories are its own workspace's.
350pub const ACCESS_LEVELS: [&str; 2] = ["none", "organization"];
351
352/// `access_level` as given, as one of [`ACCESS_LEVELS`]; None when it is
353/// not one.
354pub fn access_level(given: &str) -> Option<&'static str> {
355 match given.trim().to_ascii_lowercase().as_str() {
356 "none" | "" => Some("none"),
357 "organization" | "user" | "workspace" => Some("organization"),
358 _ => None,
359 }
Merge branch 'worktree-agent-a3abfcce648e87dca'360}
361
362fn write() -> String {
363 "write".to_owned()
364}
365
366/// A workspace's policy for its repositories' tokens.
367#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
368#[serde(rename_all = "camelCase")]
369pub struct WorkspaceActionsSettings {
370 /// What a repository made from now on gets by default: `read` (the
371 /// default) or `write`.
372 pub default_permissions: String,
373 /// The most any repository's default may be: `write` (the default) or
374 /// `read`, which holds every repository to read-only.
375 pub max_permissions: String,
376 /// Whether its repositories may let jobs open and approve pull
377 /// requests. Off by default.
378 pub can_approve_pull_requests: bool,
379}
380
381/// `workspace_actions_settings`: members only. Returns
382/// `Outcome<WorkspaceActionsSettings>`.
383#[derive(Debug, Serialize, Deserialize)]
384pub struct WorkspaceActionsSettingsArgs {
385 pub viewer: Viewer,
386 pub workspace: String,
387}
388
389/// `set_workspace_actions_settings`: owners only. Fields left out stay as
390/// they are. Returns `Outcome<WorkspaceActionsSettings>`.
391#[derive(Debug, Serialize, Deserialize)]
392#[serde(rename_all = "camelCase")]
393pub struct SetWorkspaceActionsSettingsArgs {
394 pub actor: User,
395 pub workspace: String,
396 #[serde(default)]
397 pub default_permissions: Option<String>,
398 #[serde(default)]
399 pub max_permissions: Option<String>,
400 #[serde(default)]
401 pub can_approve_pull_requests: Option<bool>,
402}
403
404/// The approval policies, least strict first.
405pub const APPROVAL_POLICIES: [&str; 3] = ["first_time_contributors", "outside_contributors", "all_external_contributors"];
406
407/// `actions_settings`. Returns `Outcome<ActionsSettings>`; anyone who can
408/// read the repository may see them.
409#[derive(Debug, Serialize, Deserialize)]
410pub struct ActionsSettingsArgs {
411 pub viewer: Viewer,
412 pub repo: RepoPath,
413}
414
415/// `set_actions_settings`: Admins only. Fields left out stay as they are.
416/// Returns `Outcome<ActionsSettings>`.
417#[derive(Debug, Serialize, Deserialize)]
418#[serde(rename_all = "camelCase")]
419pub struct SetActionsSettingsArgs {
420 pub actor: User,
421 pub repo: RepoPath,
422 /// `read` or `write`; `inherit` goes back to the workspace's (or, for a
423 /// repository made before restricted tokens, `write`).
424 #[serde(default)]
425 pub default_permissions: Option<String>,
426 #[serde(default)]
427 pub approval_policy: Option<String>,
428 #[serde(default)]
429 pub can_approve_pull_requests: Option<bool>,
Merge Actions: cross-repo workflows and actions, release and deployment triggers, step timeouts430 /// `none`, or `organization` (`user` reads the same). See
431 /// [`ActionsSettings::access_level`].
432 #[serde(default)]
433 pub access_level: Option<String>,
Merge branch 'worktree-agent-a3abfcce648e87dca'434}
435
436/// `environments`: every environment a repository's workflows, secrets,
437/// deployments or rules name, with its rules. `environment`: one, by
438/// `name`. Returns `Outcome<Vec<Environment>>` and `Outcome<Environment>`.
439#[derive(Debug, Serialize, Deserialize)]
440pub struct EnvironmentsArgs {
441 pub viewer: Viewer,
442 pub repo: RepoPath,
443 #[serde(default)]
444 pub name: Option<String>,
445}
446
447/// `set_environment`: create an environment's rules or change them. Fields
448/// left out stay as they are (none, for a new one). Admins only. Returns
449/// `Outcome<Environment>`.
450#[derive(Debug, Serialize, Deserialize)]
451#[serde(rename_all = "camelCase")]
452pub struct SetEnvironmentArgs {
453 pub actor: User,
454 pub repo: RepoPath,
455 pub name: String,
456 #[serde(default)]
457 pub reviewers: Option<Vec<EnvironmentReviewer>>,
458 #[serde(default)]
459 pub prevent_self_review: Option<bool>,
460 #[serde(default)]
461 pub wait_minutes: Option<u32>,
462 #[serde(default)]
463 pub branch_policy: Option<String>,
464 #[serde(default)]
465 pub branch_patterns: Option<Vec<BranchPattern>>,
466 #[serde(default)]
467 pub admins_bypass: Option<bool>,
468}
469
470/// `delete_environment`: its rules go; jobs naming it run without them.
471/// Its secrets' rows stay. Admins only. Returns `Outcome<bool>`.
472#[derive(Debug, Serialize, Deserialize)]
473pub struct DeleteEnvironmentArgs {
474 pub actor: User,
475 pub repo: RepoPath,
476 pub name: String,
477}
478
479/// `pending_deployments`: the environments holding a run's jobs. Returns
480/// `Outcome<Vec<PendingDeployment>>`.
481#[derive(Debug, Serialize, Deserialize)]
482pub struct PendingDeploymentsArgs {
483 pub viewer: Viewer,
484 pub repo: RepoPath,
485 pub id: String,
486}
487
488/// `review_deployments`: approve or reject a run's jobs for `environments`
489/// (every one waiting, if empty). Returns `Outcome<Vec<PendingDeployment>>`.
490#[derive(Debug, Serialize, Deserialize)]
491pub struct ReviewDeploymentsArgs {
492 pub actor: User,
493 pub repo: RepoPath,
494 pub id: String,
495 #[serde(default)]
496 pub environments: Vec<String>,
497 /// `approved` or `rejected`.
498 pub state: String,
499 #[serde(default)]
500 pub comment: Option<String>,
501}
502
503/// `repository_dispatch`: start the default branch's workflows that run
504/// `on: repository_dispatch` for `event_type`. Needs the Write role (a
505/// token's `code:write`). Returns `Outcome<u32>`: how many started.
506#[derive(Debug, Serialize, Deserialize)]
507#[serde(rename_all = "camelCase")]
508pub struct RepositoryDispatchArgs {
509 pub actor: User,
510 pub repo: RepoPath,
511 pub event_type: String,
512 #[serde(default)]
513 pub client_payload: Value,
514}
515
GitHub Actions on g1t, part two: running workflows516#[derive(Clone, Debug, Serialize, Deserialize)]
517#[serde(rename_all = "camelCase")]
518pub struct LogChunk {
519 pub seq: u64,
520 /// The step it belongs to, from 1; 0 for the job's setup.
521 pub step: u32,
522 pub text: String,
523}
524
525#[derive(Clone, Debug, Serialize, Deserialize)]
526#[serde(rename_all = "camelCase")]
527pub struct JobLog {
528 pub chunks: Vec<LogChunk>,
529 /// Whether the job has finished, so no more will come.
530 pub done: bool,
531}
532
Secrets and variables: one list, rows per environment, for workflows and deployments533/// Who may read a secret or variable: workflows (`secrets.*` and `vars.*`
534/// in GitHub Actions) and deployments (a deploy build's environment and the
535/// running app's bindings). Agents, checks and the merge queue read none.
536pub const CONSUMERS: [&str; 2] = ["workflows", "deployments"];
537
538/// One row of a repository's or workspace's secrets and variables, as
539/// Vercel lists environment variables: a key, its type, the environments
540/// it applies to and who reads it. A key may have one row per environment.
541/// Secrets' values are never returned.
GitHub Actions on g1t, part two: running workflows542#[derive(Clone, Debug, Serialize, Deserialize)]
543#[serde(rename_all = "camelCase")]
544pub struct Setting {
Secrets and variables: one list, rows per environment, for workflows and deployments545 #[serde(default)]
546 pub id: String,
GitHub Actions on g1t, part two: running workflows547 pub name: String,
Secrets and variables: one list, rows per environment, for workflows and deployments548 /// `secret`, or `variable` (shown as Config).
549 #[serde(default)]
550 pub kind: String,
551 /// A variable's value; secrets' are never returned.
GitHub Actions on g1t, part two: running workflows552 pub value: Option<String>,
Projects: what a workspace builds and runs, first on every page553 /// `project` (a repository's, which belong to its project) or
554 /// `workspace`.
GitHub Actions on g1t, part two: running workflows555 pub scope: String,
556 pub updated_at: String,
Secrets and variables: one list, rows per environment, for workflows and deployments557 /// `workflows` and/or `deployments`.
558 #[serde(default)]
559 pub available_to: Vec<String>,
560 /// The environments it applies to; empty is every environment.
561 #[serde(default)]
562 pub environments: Vec<String>,
Projects: what a workspace builds and runs, first on every page563 /// A workspace's row: the projects it reaches, by slug; empty is every
564 /// project.
Secrets and variables: one list, rows per environment, for workflows and deployments565 #[serde(default)]
Projects: what a workspace builds and runs, first on every page566 pub projects: Vec<String>,
Secrets and variables: one list, rows per environment, for workflows and deployments567 #[serde(default)]
568 pub note: Option<String>,
569 #[serde(default)]
570 pub updated_by: Option<String>,
GitHub Actions on g1t, part two: running workflows571}
572
573// --- Methods ---------------------------------------------------------------
574
575/// `workflows`. Returns `Outcome<Vec<Workflow>>`.
576#[derive(Debug, Serialize, Deserialize)]
577pub struct WorkflowsArgs {
578 pub repo: RepoPath,
579 pub viewer: Viewer,
580}
581
582/// `runs`: newest first. Returns `Outcome<Vec<WorkflowRun>>`.
583#[derive(Debug, Serialize, Deserialize)]
584pub struct RunsArgs {
585 pub repo: RepoPath,
586 pub viewer: Viewer,
587 /// A workflow's id or file name.
588 #[serde(default)]
589 pub workflow: Option<String>,
590 #[serde(default)]
591 pub branch: Option<String>,
592 #[serde(default)]
593 pub event: Option<String>,
594 /// The pull request's number.
595 #[serde(default)]
596 pub pull: Option<u32>,
597 #[serde(default)]
598 pub sha: Option<String>,
599 #[serde(default)]
600 pub limit: Option<u32>,
601}
602
603/// `run`. Returns `Outcome<RunDetail>`.
604#[derive(Debug, Serialize, Deserialize)]
605pub struct RunArgs {
606 pub repo: RepoPath,
607 pub viewer: Viewer,
608 pub id: String,
Merge Actions runs: summaries, attempts and re-runs, graceful cancel, log downloads, badges (actions 0009)609 /// An earlier attempt; the latest when absent.
610 #[serde(default)]
611 pub attempt: Option<u64>,
612}
613
614/// `summaries`: the job summaries of a run's attempt (the latest when
615/// `attempt` is absent), jobs in the run's order, those with none left
616/// out. Returns `Outcome<Vec<JobSummary>>`.
617#[derive(Debug, Serialize, Deserialize)]
618pub struct SummariesArgs {
619 pub repo: RepoPath,
620 pub viewer: Viewer,
621 pub id: String,
622 #[serde(default)]
623 pub attempt: Option<u64>,
624}
625
626/// `job_log_text`: one job's whole log, any attempt's (by the id the run
627/// gave the job). Returns `Outcome<JobLogText>`.
628#[derive(Debug, Serialize, Deserialize)]
629pub struct JobLogTextArgs {
630 pub repo: RepoPath,
631 pub viewer: Viewer,
632 pub job: String,
633}
634
635/// `run_logs`: every job's whole log for an attempt of a run (the latest
636/// when `attempt` is absent), until they add up to `MAX_RUN_LOG_BYTES`;
637/// jobs past it come `omitted`, with no chunks. Returns
638/// `Outcome<Vec<JobLogText>>`.
639#[derive(Debug, Serialize, Deserialize)]
640pub struct RunLogsArgs {
641 pub repo: RepoPath,
642 pub viewer: Viewer,
643 pub id: String,
644 #[serde(default)]
645 pub attempt: Option<u64>,
GitHub Actions on g1t, part two: running workflows646}
647
Merge Actions runs: summaries, attempts and re-runs, graceful cancel, log downloads, badges (actions 0009)648/// The most log `run_logs` returns at once, in bytes.
649pub const MAX_RUN_LOG_BYTES: usize = 24 * 1024 * 1024;
650
GitHub Actions on g1t, part two: running workflows651/// `logs`: a job's log after `after`. Returns `Outcome<JobLog>`.
652#[derive(Debug, Serialize, Deserialize)]
653pub struct LogsArgs {
654 pub repo: RepoPath,
655 pub viewer: Viewer,
656 pub job: String,
657 #[serde(default)]
658 pub after: u64,
659}
660
661/// `dispatch`: run a workflow that has `workflow_dispatch`. Members only.
662/// Returns `Outcome<WorkflowRun>`.
663#[derive(Debug, Serialize, Deserialize)]
664pub struct DispatchArgs {
665 pub actor: User,
666 pub repo: RepoPath,
667 /// A workflow's id or file name.
668 pub workflow: String,
669 /// A branch or tag; the default branch when absent.
670 #[serde(default, rename = "ref")]
671 pub git_ref: Option<String>,
672 #[serde(default)]
673 pub inputs: serde_json::Map<String, Value>,
674}
675
Merge Actions runs: summaries, attempts and re-runs, graceful cancel, log downloads, badges (actions 0009)676/// `cancel` and `rerun`: every job, with `failed_only` the ones that did
677/// not succeed, or with `job` that one job (by its id in the run's latest
678/// attempt); each with the jobs that need them. `debug` runs the new
679/// attempt with debug logging. Members only. Returns `Outcome<WorkflowRun>`.
GitHub Actions on g1t, part two: running workflows680#[derive(Debug, Serialize, Deserialize)]
681pub struct RunActionArgs {
682 pub actor: User,
683 pub repo: RepoPath,
684 pub id: String,
685 #[serde(default)]
686 pub failed_only: bool,
Merge Actions runs: summaries, attempts and re-runs, graceful cancel, log downloads, badges (actions 0009)687 #[serde(default)]
688 pub job: Option<String>,
689 #[serde(default)]
690 pub debug: bool,
691 /// `cancel`: stop running jobs outright, without their cleanup steps.
692 #[serde(default)]
693 pub force: bool,
GitHub Actions on g1t, part two: running workflows694}
695
696/// `set_workflow_enabled`. Members only. Returns `Outcome<Workflow>`.
697#[derive(Debug, Serialize, Deserialize)]
698pub struct SetWorkflowEnabledArgs {
699 pub actor: User,
700 pub repo: RepoPath,
701 pub workflow: String,
702 pub enabled: bool,
703}
704
705/// Whose secrets or variables: a repository's, or with only `workspace`,
706/// a workspace's.
707#[derive(Clone, Debug, Serialize, Deserialize)]
708pub struct SettingsOwner {
709 #[serde(default)]
710 pub repo: Option<RepoPath>,
711 #[serde(default)]
712 pub workspace: Option<String>,
713}
714
715/// `settings`: the secrets (`kind: secret`) or variables (`kind: variable`)
716/// of a repository, with its workspace's, or of a workspace. Members only.
717/// Returns `Outcome<Vec<Setting>>`.
718#[derive(Debug, Serialize, Deserialize)]
719pub struct SettingsArgs {
720 pub actor: User,
721 #[serde(flatten)]
722 pub owner: SettingsOwner,
723 pub kind: String,
724}
725
726/// `set_setting`: add or replace one. A repository's need a member; a
727/// workspace's an owner. Returns `Outcome<Setting>`.
728#[derive(Debug, Serialize, Deserialize)]
729pub struct SetSettingArgs {
730 pub actor: User,
731 #[serde(flatten)]
732 pub owner: SettingsOwner,
Secrets and variables: one list, rows per environment, for workflows and deployments733 /// `secret` or `variable`. Changing a variable's row to `secret` seals
734 /// it; a secret cannot become a variable.
GitHub Actions on g1t, part two: running workflows735 pub kind: String,
736 pub name: String,
Secrets and variables: one list, rows per environment, for workflows and deployments737 /// The row to change. Left out, the key's row for every environment, as
738 /// GitHub's API addresses a secret by name alone.
739 #[serde(default)]
740 pub id: Option<String>,
741 /// Needed for a new row; left out, an existing row keeps its value.
742 #[serde(default)]
743 pub value: Option<String>,
744 /// `workflows` and/or `deployments`; left out, unchanged (both, for a
745 /// new row).
Deployments work end to end: fixes from the first live run746 // Named as callers send it: an `alias` is not honoured beside the
747 // flattened owner in the Worker's build.
748 #[serde(default, rename = "availableTo")]
Secrets and variables: one list, rows per environment, for workflows and deployments749 pub available_to: Option<Vec<String>>,
750 /// The environments it applies to; empty is every one. Left out,
751 /// unchanged.
752 #[serde(default)]
753 pub environments: Option<Vec<String>>,
Projects: what a workspace builds and runs, first on every page754 /// A workspace's row: project slugs; empty for every one.
Secrets and variables: one list, rows per environment, for workflows and deployments755 #[serde(default)]
Projects: what a workspace builds and runs, first on every page756 pub projects: Option<Vec<String>>,
Secrets and variables: one list, rows per environment, for workflows and deployments757 #[serde(default)]
758 pub note: Option<String>,
759}
760
761/// `resolve_settings`: the secrets and variables one reader gets, for the
762/// services that hand them out (the deployments service). Returns
763/// `ResolvedSettings`.
764#[derive(Debug, Serialize, Deserialize)]
765#[serde(rename_all = "camelCase")]
766pub struct ResolveSettingsArgs {
767 pub repo_id: String,
768 pub repo: RepoPath,
Projects: what a workspace builds and runs, first on every page769 /// The project being read for; its repository's primary project if left
770 /// out.
771 #[serde(default)]
772 pub project_id: Option<String>,
773 #[serde(default)]
774 pub project_slug: Option<String>,
Secrets and variables: one list, rows per environment, for workflows and deployments775 /// `workflows` or `deployments`.
776 pub consumer: String,
777 /// The environment being read for, such as `production` or `preview`.
778 #[serde(default)]
779 pub environment: Option<String>,
780 /// Whether the run is trusted; an untrusted one gets no secrets.
781 pub trusted: bool,
782}
783
784#[derive(Debug, Default, Serialize, Deserialize)]
785pub struct ResolvedSettings {
786 pub secrets: serde_json::Map<String, serde_json::Value>,
787 pub variables: serde_json::Map<String, serde_json::Value>,
GitHub Actions on g1t, part two: running workflows788}
789
790/// `delete_setting`. Returns `Outcome<bool>`.
791#[derive(Debug, Serialize, Deserialize)]
792pub struct DeleteSettingArgs {
793 pub actor: User,
794 #[serde(flatten)]
795 pub owner: SettingsOwner,
796 pub kind: String,
797 pub name: String,
Secrets and variables: one list, rows per environment, for workflows and deployments798 /// One row; left out, every row of the key.
799 #[serde(default)]
800 pub id: Option<String>,
GitHub Actions on g1t, part two: running workflows801}
802
803/// `job_spec` and `job_report`: the sandbox running a job, with the job's
804/// own token. `report` is one of:
805/// `{"kind": "step", "number", "status", "conclusion"}`,
806/// `{"kind": "log", "step", "text"}`,
807/// `{"kind": "annotation", "level", "message", "title", "file", "line"}`,
808/// `{"kind": "done", "conclusion", "outputs", "reason"}`.
809#[derive(Debug, Serialize, Deserialize)]
810pub struct JobCallArgs {
811 pub job: String,
812 pub token: String,
813 #[serde(default)]
814 pub report: Value,
815}
816
817/// What the runner needs to start a job's sandbox.
818#[derive(Debug, Serialize, Deserialize)]
819#[serde(rename_all = "camelCase")]
820pub struct StartJobArgs {
821 pub job: String,
822 pub token: String,
823 pub repo: RepoPath,
824 /// Minutes before the job is stopped.
825 pub timeout_minutes: u32,
Fast pages, required checks on the branch, self-hosted runners, honest incidents826 /// The workflow file the job is in (`.g1t/workflows/deploy.yml`), for
827 /// the guardrails' workflow-only domains.
828 #[serde(default)]
829 pub workflow: Option<String>,
830 /// The environment the job names with `environment:`, when it names
831 /// one plainly (not with an expression).
832 #[serde(default)]
833 pub environment: Option<String>,
834 /// Whether its run is trusted: not a pull request from a fork. Only a
835 /// trusted run's jobs reach workflow-only domains.
836 #[serde(default)]
837 pub trusted: bool,
838 /// The machine its `runs-on` asked for, by label (`instance_for`):
839 /// `g1t-2core` or `g1t-4core`; absent, the standard one.
840 #[serde(default)]
841 pub instance: Option<String>,
842}
843
844/// A size of machine g1t runs workflow jobs on, asked for by a label in
845/// `runs-on`. Each is a Cloudflare Containers instance type; it costs what
846/// that instance costs g1t, plus the margin, like any sandbox time.
847#[derive(Clone, Copy, Debug, PartialEq)]
848pub struct InstanceType {
849 /// The `runs-on` label, or `standard` for the default.
850 pub label: &'static str,
851 /// The Containers instance type.
852 pub container: &'static str,
853 pub vcpu: f64,
854 pub memory_gib: f64,
855 pub disk_gb: f64,
856 /// What a second of it costs g1t as a multiple of the standard
857 /// machine's, with its vCPUs as busy (Cloudflare's list prices:
858 /// memory $0.0000025 a GiB-second, disk $0.00000007 a GB-second, vCPU
859 /// $0.00002 a second). Used to reserve before a job starts, and to
860 /// price a job that did not report its own CPU.
861 pub price_scale: f64,
862}
863
864/// The default: what `ubuntu-latest` and every other hosted label get.
865pub const STANDARD_INSTANCE: InstanceType =
866 InstanceType { label: "standard", container: "standard-1", vcpu: 0.5, memory_gib: 4.0, disk_gb: 8.0, price_scale: 1.0 };
867
868/// Every machine a workflow job can ask for, the default first.
869pub const INSTANCE_TYPES: [InstanceType; 3] = [
870 STANDARD_INSTANCE,
871 InstanceType { label: "g1t-2core", container: "standard-3", vcpu: 2.0, memory_gib: 8.0, disk_gb: 16.0, price_scale: 2.8 },
872 InstanceType { label: "g1t-4core", container: "standard-4", vcpu: 4.0, memory_gib: 12.0, disk_gb: 20.0, price_scale: 5.1 },
873];
874
875/// The machine a job's `runs-on` labels ask for: the largest named, or the
876/// standard one. Labels compare without regard to case.
877pub fn instance_for(labels: &[String]) -> InstanceType {
878 INSTANCE_TYPES
879 .iter()
880 .rev()
881 .find(|instance| instance.label != STANDARD_INSTANCE.label && labels.iter().any(|label| label.trim().eq_ignore_ascii_case(instance.label)))
882 .copied()
883 .unwrap_or(STANDARD_INSTANCE)
884}
885
886/// An instance type by its label, if it is one.
887pub fn instance_named(label: &str) -> Option<InstanceType> {
888 INSTANCE_TYPES.iter().find(|instance| instance.label.eq_ignore_ascii_case(label.trim())).copied()
889}
890
891// ── The cache (actions/cache) ─────────────────────────────────────────────
892//
893// Entries are kept in R2 by the API (the ACTIONS_CACHE bucket) and listed
894// here, by the actions service, which decides what is found, what fits and
895// what is evicted. A sandbox reaches these through the API with its job's
896// token: `/actions/jobs/{job}/cache` (see apps/api/src/blobs.rs).
897
898/// The largest one cache entry may be, compressed.
899pub const CACHE_MAX_ENTRY_BYTES: u64 = 2 * 1024 * 1024 * 1024;
900/// What one repository's entries may hold together. Saving past it evicts
901/// the entries restored longest ago.
902pub const CACHE_REPO_QUOTA_BYTES: u64 = 10 * 1024 * 1024 * 1024;
903/// An entry not restored for this long is deleted.
904pub const CACHE_UNUSED_DAYS: u64 = 7;
905/// An entry is deleted this long after it was saved, however often it is
906/// restored (the bucket's own lifecycle rule deletes objects at 30 days).
907pub const CACHE_MAX_AGE_DAYS: u64 = 28;
908/// An upload is sent in parts of this size (the last may be smaller).
909pub const CACHE_PART_BYTES: u64 = 32 * 1024 * 1024;
910/// What R2 charges g1t to store a GB for a month, in millionths of a
911/// dollar ($0.015): what the cache's storage is charged at, plus the margin.
912pub const CACHE_MICROS_PER_GB_MONTH: i64 = 15_000;
913
914/// `cache_lookup`: the entry a job restores: its key exactly, else the
915/// newest whose key starts with one of `restore`, in order.
916/// Returns `Outcome<Option<CacheHit>>`.
917#[derive(Debug, Serialize, Deserialize)]
918pub struct CacheLookupArgs {
919 pub job: String,
920 pub token: String,
921 pub key: String,
922 #[serde(default)]
923 pub restore: Vec<String>,
Merge branch 'worktree-agent-a3abfcce648e87dca'924 /// The entry's version, a hash of its paths and compression, as the
925 /// toolkit's client and g1t's runner both send it: only an entry of the
926 /// same version is found. `None` from runners that send none, whose
927 /// entries have none.
Actions: OIDC tokens, the toolkit's cache and artifact services, and artifacts in R2928 #[serde(default)]
929 pub version: Option<String>,
Fast pages, required checks on the branch, self-hosted runners, honest incidents930}
931
932#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
933pub struct CacheHit {
934 pub key: String,
935 pub object: String,
936 pub size: u64,
Actions: OIDC tokens, the toolkit's cache and artifact services, and artifacts in R2937 /// When it was saved, RFC 3339.
938 #[serde(default)]
939 pub created_at: String,
940 /// A signed token for downloading it through the toolkit's blob
941 /// endpoint, when the lookup came with a version.
942 #[serde(default)]
943 pub blob: Option<String>,
Fast pages, required checks on the branch, self-hosted runners, honest incidents944}
945
946/// `cache_reserve`: a job about to save `size` bytes under `key`. Refused
947/// when the key is taken (`conflict`: keys are written once) or the entry
948/// is too large. Returns `Outcome<CacheReservation>`.
949#[derive(Debug, Serialize, Deserialize)]
950pub struct CacheReserveArgs {
951 pub job: String,
952 pub token: String,
953 pub key: String,
Actions: OIDC tokens, the toolkit's cache and artifact services, and artifacts in R2954 /// Its size, when known before it is sent (the toolkit's newer client
955 /// says only when it finishes: 0 then).
Fast pages, required checks on the branch, self-hosted runners, honest incidents956 pub size: u64,
Merge branch 'worktree-agent-a3abfcce648e87dca'957 /// As in `CacheLookupArgs`.
Actions: OIDC tokens, the toolkit's cache and artifact services, and artifacts in R2958 #[serde(default)]
959 pub version: Option<String>,
Fast pages, required checks on the branch, self-hosted runners, honest incidents960}
961
962#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
963pub struct CacheReservation {
964 pub id: String,
965 /// Where the API puts it in R2.
966 pub object: String,
Actions: OIDC tokens, the toolkit's cache and artifact services, and artifacts in R2967 /// The entry's number, which the toolkit's older protocol names it by.
968 #[serde(default)]
969 pub number: u64,
970 /// Its R2 upload, once one is started.
971 #[serde(default)]
972 pub upload: Option<String>,
973 /// A signed token for sending its parts through the toolkit's blob
974 /// endpoint, once its upload is started.
975 #[serde(default)]
976 pub blob: Option<String>,
Fast pages, required checks on the branch, self-hosted runners, honest incidents977}
978
Actions: OIDC tokens, the toolkit's cache and artifact services, and artifacts in R2979/// `cache_upload`: an entry a job is still uploading, by its number or by
980/// key and version. Returns `Outcome<CacheReservation>`, with `upload` and
981/// `blob` set once its upload has been started.
982#[derive(Debug, Serialize, Deserialize)]
983pub struct CacheUploadArgs {
984 pub job: String,
985 pub token: String,
986 #[serde(default)]
987 pub number: Option<u64>,
988 #[serde(default)]
989 pub key: Option<String>,
990 #[serde(default)]
991 pub version: Option<String>,
992}
993
Fast pages, required checks on the branch, self-hosted runners, honest incidents994/// `cache_commit`: the upload of `id` is complete, at `size` bytes. Returns
995/// `Outcome<CacheCommitted>`: the objects of entries it evicted, which the
996/// API deletes from R2.
997#[derive(Debug, Serialize, Deserialize)]
998pub struct CacheCommitArgs {
999 pub job: String,
1000 pub token: String,
1001 pub id: String,
1002 pub size: u64,
1003}
1004
1005#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
1006pub struct CacheCommitted {
1007 pub evicted: Vec<String>,
1008}
1009
1010/// `cache_abort`: an upload that will not finish; its reservation goes.
1011/// Returns `Outcome<bool>`.
1012#[derive(Debug, Serialize, Deserialize)]
1013pub struct CacheAbortArgs {
1014 pub job: String,
1015 pub token: String,
1016 pub id: String,
1017}
1018
Actions: OIDC tokens, the toolkit's cache and artifact services, and artifacts in R21019// ── Artifacts (actions/upload-artifact) ───────────────────────────────────
1020//
1021// Kept in R2 by the API (the ACTIONS_CACHE bucket, under `a/`) and listed
1022// here, by the actions service, which decides names, sizes and how long
1023// each is kept. A sandbox reaches them with its job's token
1024// (`/actions/jobs/{job}/artifacts…`) or, through the toolkit's protocol,
1025// with its runtime token (`ACTIONS_RUNTIME_TOKEN`); people through the
1026// REST API and the run's page.
1027
1028/// The largest one artifact may be.
1029pub const ARTIFACT_MAX_BYTES: u64 = 5 * 1024 * 1024 * 1024;
1030/// What one run's artifacts may hold together.
1031pub const RUN_ARTIFACTS_MAX_BYTES: u64 = 10 * 1024 * 1024 * 1024;
1032/// How long artifacts are kept unless a repository says otherwise.
1033pub const ARTIFACT_RETENTION_DEFAULT_DAYS: u32 = 14;
1034/// The longest a repository may keep them.
1035pub const ARTIFACT_RETENTION_MAX_DAYS: u32 = 90;
1036/// A native upload is sent in parts of this size (the last may be smaller).
1037pub const ARTIFACT_PART_BYTES: u64 = 32 * 1024 * 1024;
1038
1039/// An artifact, as the API and the site show it.
1040#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
1041pub struct Artifact {
1042 pub id: u64,
1043 pub name: String,
1044 pub size: u64,
1045 /// `sha256:<hex>`, when the uploader said.
1046 pub digest: Option<String>,
1047 /// `zip`, or `tgz` for one an older runner sent.
1048 pub format: String,
1049 pub run_id: String,
1050 pub job_id: String,
1051 pub repo_id: String,
1052 /// Whether it has expired or been deleted (its bytes are gone).
1053 pub expired: bool,
1054 pub created_at: String,
1055 pub updated_at: String,
1056 pub expires_at: String,
1057 /// The run's branch and commit, for the REST shape.
1058 #[serde(default)]
1059 pub head_branch: Option<String>,
1060 #[serde(default)]
1061 pub head_sha: Option<String>,
1062}
1063
1064/// An artifact with where its bytes are, and a signed token for them.
1065#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
1066pub struct ArtifactBlob {
1067 pub artifact: Artifact,
1068 pub object: String,
1069 /// For the toolkit's blob endpoint (`/actions/toolkit/blobs/{blob}`).
1070 pub blob: String,
1071}
1072
1073/// A page of artifacts, in GitHub's shape.
1074#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
1075pub struct ArtifactList {
1076 pub total_count: u64,
1077 pub artifacts: Vec<Artifact>,
1078}
1079
1080/// `artifact_reserve`: a job about to upload an artifact. Refused when its
1081/// run has one of that name and `overwrite` is not set (`conflict`), or it
1082/// is too large. Returns `Outcome<ArtifactReservation>`.
1083#[derive(Debug, Default, Serialize, Deserialize)]
1084pub struct ArtifactReserveArgs {
1085 pub job: String,
1086 /// The job's token, or its runtime token.
1087 pub token: String,
1088 pub name: String,
1089 /// Its size, when known before it is sent (0 otherwise).
1090 #[serde(default)]
1091 pub size: u64,
1092 /// Days to keep it: 0 for the repository's default; at most the
1093 /// repository's setting.
1094 #[serde(default)]
1095 pub retention_days: u32,
1096 /// When to expire it, RFC 3339, as the toolkit says it (in place of
1097 /// `retention_days`).
1098 #[serde(default)]
1099 pub expires_at: Option<String>,
1100 #[serde(default)]
1101 pub overwrite: bool,
1102 /// `zip` (the default) or `tgz`.
1103 #[serde(default)]
1104 pub format: Option<String>,
1105}
1106
1107#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
1108pub struct ArtifactReservation {
1109 pub id: u64,
1110 /// Where the API puts it in R2.
1111 pub object: String,
1112 /// The days it will be kept, and until when.
1113 pub retention_days: u32,
1114 pub expires_at: String,
1115}
1116
1117/// `artifact_commit`: its upload is complete, at `size` bytes. The artifact
1118/// is named by `id`, or by `name` in the job's run (the toolkit's way).
1119/// Returns `Outcome<Artifact>`.
1120#[derive(Debug, Default, Serialize, Deserialize)]
1121pub struct ArtifactCommitArgs {
1122 pub job: String,
1123 pub token: String,
1124 #[serde(default)]
1125 pub id: Option<u64>,
1126 #[serde(default)]
1127 pub name: Option<String>,
1128 pub size: u64,
1129 #[serde(default)]
1130 pub digest: Option<String>,
1131}
1132
1133/// `job_artifacts`: a running job listing the artifacts of its own run, or
1134/// of another run of its repository (`run_id`), narrowed by `name` or
1135/// `id`: `Outcome<Vec<Artifact>>`. `job_artifact` gives the one named, with
1136/// a token to download it: `Outcome<ArtifactBlob>`. `job_delete_artifact`
1137/// deletes one of its own run's: `Outcome<Artifact>`. `artifact_abort`
1138/// gives up an upload by `id`: `Outcome<bool>`.
1139#[derive(Debug, Default, Serialize, Deserialize)]
1140pub struct JobArtifactsArgs {
1141 pub job: String,
1142 pub token: String,
1143 #[serde(default)]
1144 pub run_id: Option<String>,
1145 #[serde(default)]
1146 pub name: Option<String>,
1147 #[serde(default)]
1148 pub id: Option<u64>,
1149}
1150
1151/// `artifacts`: a repository's artifacts, newest first, or one run's.
1152/// Anyone who can see the repository. Returns `Outcome<ArtifactList>`.
1153#[derive(Debug, Serialize, Deserialize)]
1154pub struct ArtifactsArgs {
1155 pub repo: RepoPath,
1156 pub viewer: Viewer,
1157 #[serde(default)]
1158 pub run: Option<String>,
1159 #[serde(default)]
1160 pub name: Option<String>,
1161 #[serde(default)]
1162 pub page: Option<u32>,
1163 #[serde(default)]
1164 pub per_page: Option<u32>,
1165}
1166
1167/// `artifact` (`Outcome<Artifact>`) and `artifact_download`
1168/// (`Outcome<ArtifactBlob>`, with a token good for a few minutes): one
1169/// artifact by `id`, or by `name` within `run`. Anyone who can see the
1170/// repository.
1171#[derive(Debug, Serialize, Deserialize)]
1172pub struct ArtifactArgs {
1173 pub repo: RepoPath,
1174 pub viewer: Viewer,
1175 #[serde(default)]
1176 pub id: Option<u64>,
1177 #[serde(default)]
1178 pub run: Option<String>,
1179 #[serde(default)]
1180 pub name: Option<String>,
1181}
1182
1183/// `delete_artifact`: needs the Write role. Returns `Outcome<Artifact>`.
1184#[derive(Debug, Serialize, Deserialize)]
1185pub struct DeleteArtifactArgs {
1186 pub actor: User,
1187 pub repo: RepoPath,
1188 pub id: u64,
1189}
1190
1191/// `artifact_retention`: anyone who can see the repository. With `days`,
1192/// sets it, which needs the Maintain role. Returns
1193/// `Outcome<ArtifactRetention>`.
1194#[derive(Debug, Serialize, Deserialize)]
1195pub struct ArtifactRetentionArgs {
1196 pub repo: RepoPath,
1197 pub viewer: Viewer,
1198 #[serde(default)]
1199 pub days: Option<u32>,
1200}
1201
1202/// GitHub's shape: the days artifacts are kept by default, and the most a
1203/// repository may choose.
1204#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
1205pub struct ArtifactRetention {
1206 pub days: u32,
1207 pub maximum_allowed_days: u32,
1208}
1209
1210// ── The toolkit's protocols ───────────────────────────────────────────────
1211//
1212// Actions built on GitHub's toolkit (`@actions/cache`, `@actions/artifact`,
1213// `@actions/core`'s `getIDToken`) reach g1t with the job's runtime token,
1214// `ACTIONS_RUNTIME_TOKEN`: a JSON Web Token whose `scp` names the run and
1215// job, signed with a key derived from the job's own token, so the actions
1216// service checks it without keeping another secret. Cache and artifact
1217// operations above take it in place of the job's token.
1218
1219/// `runtime_auth`: which job a runtime token is, while it runs:
1220/// `Outcome<RuntimeJob>`. `oidc_claims` takes the same and returns
1221/// `Outcome<Value>`: the claims of the job's OIDC token, less `iss`, `aud`,
1222/// `jti` and the times, or `forbidden` when the job's `permissions` do not
1223/// give it `id-token: write`.
1224#[derive(Debug, Serialize, Deserialize)]
1225pub struct RuntimeAuthArgs {
1226 pub job: String,
1227 pub token: String,
1228}
1229
1230#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
1231pub struct RuntimeJob {
1232 pub job: String,
1233 pub run: String,
1234 pub repo_id: String,
1235 pub namespace: String,
1236 /// `owner/name`.
1237 pub repository: String,
1238}
1239
1240/// What a signed blob token lets its holder do.
1241#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
1242pub struct BlobGrant {
1243 /// `cache` or `artifact`.
1244 pub kind: String,
1245 /// The entry's id: a cache entry's `cache_…`, an artifact's number.
1246 pub id: String,
1247 pub object: String,
1248 /// The R2 upload it sends parts to; `None` for a download.
1249 pub upload: Option<String>,
1250 /// For a download: what to call the file, and its type.
1251 #[serde(default)]
1252 pub filename: Option<String>,
1253 #[serde(default)]
1254 pub content_type: Option<String>,
1255}
1256
1257/// `blob_sign`: a token for uploading an entry the job reserved, to the R2
1258/// upload the API started for it. Returns `Outcome<String>`.
1259#[derive(Debug, Serialize, Deserialize)]
1260pub struct BlobSignArgs {
1261 pub job: String,
1262 pub token: String,
1263 /// `cache` or `artifact`.
1264 pub kind: String,
1265 pub id: String,
1266 pub upload: String,
1267}
1268
1269/// `blob_open`: what a signed token grants, while it is good and its entry
1270/// is there: `Outcome<BlobGrant>`. `blob_part` records a part sent with an
1271/// upload token (`part`, `etag`, `size`): `Outcome<bool>`. `blob_parts`
1272/// gives the parts recorded, in order: `Outcome<Vec<BlobPart>>`, and
1273/// `blob_done` forgets them: `Outcome<bool>`.
1274#[derive(Debug, Default, Serialize, Deserialize)]
1275pub struct BlobArgs {
1276 pub blob: String,
1277 #[serde(default)]
1278 pub part: u32,
1279 #[serde(default)]
1280 pub etag: String,
1281 #[serde(default)]
1282 pub size: u64,
1283}
1284
1285#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
1286pub struct BlobPart {
1287 pub part: u32,
1288 pub etag: String,
1289 pub size: u64,
1290}
1291
Fast pages, required checks on the branch, self-hosted runners, honest incidents1292#[cfg(test)]
1293mod instance_tests {
1294 use super::*;
1295
1296 fn labels(given: &[&str]) -> Vec<String> {
1297 given.iter().map(|l| (*l).to_owned()).collect()
1298 }
1299
1300 #[test]
1301 fn runs_on_picks_the_machine() {
1302 assert_eq!(instance_for(&labels(&["ubuntu-latest"])).container, "standard-1");
1303 assert_eq!(instance_for(&labels(&[])).label, "standard");
1304 assert_eq!(instance_for(&labels(&["g1t-4core"])).container, "standard-4");
1305 assert_eq!(instance_for(&labels(&["ubuntu-latest", "G1T-2Core"])).container, "standard-3");
1306 // Both named: the larger.
1307 assert_eq!(instance_for(&labels(&["g1t-2core", "g1t-4core"])).label, "g1t-4core");
1308 assert_eq!(instance_named("g1t-4core").map(|i| i.vcpu), Some(4.0));
1309 assert_eq!(instance_named("standard"), Some(STANDARD_INSTANCE));
1310 assert_eq!(instance_named("g1t-64core"), None);
1311 }
1312
1313 #[test]
1314 fn start_args_from_older_callers_read() {
1315 let args: StartJobArgs = serde_json::from_value(serde_json::json!({
1316 "job": "job_1", "token": "t", "repo": { "namespace": "acme", "name": "web" }, "timeoutMinutes": 30
1317 }))
1318 .unwrap();
1319 assert!(args.workflow.is_none() && args.environment.is_none() && !args.trusted && args.instance.is_none());
1320 }
GitHub Actions on g1t, part two: running workflows1321}
Deployments work end to end: fixes from the first live run1322
1323#[cfg(test)]
1324mod setting_args_tests {
1325 use super::*;
1326
1327 #[test]
1328 fn who_reads_a_row_is_read_as_the_site_and_api_send_it() {
1329 let args: SetSettingArgs = serde_json::from_value(serde_json::json!({
1330 "actor": { "id": "usr_1", "username": "a" },
1331 "repo": { "namespace": "acme", "name": "web" },
1332 "kind": "secret",
1333 "name": "STRIPE_KEY",
1334 "availableTo": ["deployments"],
1335 "environments": ["production"],
1336 }))
1337 .unwrap();
1338 assert_eq!(args.available_to, Some(vec!["deployments".to_owned()]));
1339 }
1340}

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