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

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