Skip to content

Where people and agents ship software together. The open-source git platform for the whole job: issues, agents, checks and deploys to the edge.

g1t.sh
1,032 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.

Deploys as code: a manifest of every Worker, a deploy tool that ships only what changed in parallel stages, and a g1t Actions workflow1//! `github.event`: the webhook-shaped payload GitHub gives a workflow,
2//! built from g1t's own records so `github.event.pull_request.number`,
3//! `github.event.issue.labels.*.name` and the like read as they do there.
A workflow's event payload (`github.event` and the file at `GITHUB_EVENT_PATH`) reads as GitHub's webhook payload does. Ids are whole numbers, the same for an object wherever it appears and safe in JavaScript: `repository.id`, `pull_request.id`, `issue.id`, `review.id`, `sender.id` and every user's and owner's `id`, with g1t's own id as `node_id`; `github.repository_id`, `github.repository_owner_id`, `github.actor_id` and their `GITHUB_*` variables are the same numbers. What g1t's API takes back by id (comments, releases, deployments, workflow runs) keeps g1t's id, so `github.event.comment.id` still edits the comment. A repository in a person's own workspace is owned by a `User`, not an `Organization`. A push says whether it was `forced`, `created` or `deleted`, and its `head_commit` is the commit pushed. A pull request's `base.sha` is the tip of the branch it merges into at the event, not the merge base, and `merge_commit_sha` is the commit it landed as once merged; pull requests and issues carry `node_id`, `assignee`, `locked`, dates and label and milestone ids, and a fork's head names the fork. `workflow_run` has the followed run's attempt, times, actor, head commit, workflow id and URLs. Tests compare each payload's keys and types with trimmed copies of GitHub's documented payloads, and the Actions guide says what differs. OIDC claims keep g1t's ids, so trust policies already written still match.4//!
5//! Ids are as GitHub's are: `id` a whole number, the same for an object
6//! wherever it appears ([`github_id`] of its g1t id, [`account_id`] of a
7//! person's or workspace's name), and `node_id` g1t's own id. What g1t's
8//! API addresses by its own id keeps that id as `id`, so a payload's id
9//! can be passed straight back to the API: a comment (`PATCH
10//! /repos/{owner}/{repo}/issues/comments/{comment_id}`), a release, a
11//! deployment and its statuses, and a workflow run.
Deploys as code: a manifest of every Worker, a deploy tool that ships only what changed in parallel stages, and a g1t Actions workflow12
A workflow's event payload (`github.event` and the file at `GITHUB_EVENT_PATH`) reads as GitHub's webhook payload does. Ids are whole numbers, the same for an object wherever it appears and safe in JavaScript: `repository.id`, `pull_request.id`, `issue.id`, `review.id`, `sender.id` and every user's and owner's `id`, with g1t's own id as `node_id`; `github.repository_id`, `github.repository_owner_id`, `github.actor_id` and their `GITHUB_*` variables are the same numbers. What g1t's API takes back by id (comments, releases, deployments, workflow runs) keeps g1t's id, so `github.event.comment.id` still edits the comment. A repository in a person's own workspace is owned by a `User`, not an `Organization`. A push says whether it was `forced`, `created` or `deleted`, and its `head_commit` is the commit pushed. A pull request's `base.sha` is the tip of the branch it merges into at the event, not the merge base, and `merge_commit_sha` is the commit it landed as once merged; pull requests and issues carry `node_id`, `assignee`, `locked`, dates and label and milestone ids, and a fork's head names the fork. `workflow_run` has the followed run's attempt, times, actor, head commit, workflow id and URLs. Tests compare each payload's keys and types with trimmed copies of GitHub's documented payloads, and the Actions guide says what differs. OIDC claims keep g1t's ids, so trust policies already written still match.13use g1t_actions::events::{account_id, github_id};
g1t is the stored author of what it opens; the person who asked is requested_by and keeps the author's rights14use g1t_contracts::{PrincipalKind, User};
A workflow's event payload (`github.event` and the file at `GITHUB_EVENT_PATH`) reads as GitHub's webhook payload does. Ids are whole numbers, the same for an object wherever it appears and safe in JavaScript: `repository.id`, `pull_request.id`, `issue.id`, `review.id`, `sender.id` and every user's and owner's `id`, with g1t's own id as `node_id`; `github.repository_id`, `github.repository_owner_id`, `github.actor_id` and their `GITHUB_*` variables are the same numbers. What g1t's API takes back by id (comments, releases, deployments, workflow runs) keeps g1t's id, so `github.event.comment.id` still edits the comment. A repository in a person's own workspace is owned by a `User`, not an `Organization`. A push says whether it was `forced`, `created` or `deleted`, and its `head_commit` is the commit pushed. A pull request's `base.sha` is the tip of the branch it merges into at the event, not the merge base, and `merge_commit_sha` is the commit it landed as once merged; pull requests and issues carry `node_id`, `assignee`, `locked`, dates and label and milestone ids, and a fork's head names the fork. `workflow_run` has the followed run's attempt, times, actor, head commit, workflow id and URLs. Tests compare each payload's keys and types with trimmed copies of GitHub's documented payloads, and the Actions guide says what differs. OIDC claims keep g1t's ids, so trust policies already written still match.15use g1t_contracts::repos::{Commit, Repo, RepoPath};
Merge branch 'worktree-agent-ab6bf4195fcb97f7c' into claude/cool-newton-7nm8r916use g1t_contracts::repos::FileStatus;
17use g1t_contracts::work::{Comment, DEFAULT_LABELS, Issue, Label, MilestoneRef, Pull, PullStatus, State, label_color_for};
Deploys as code: a manifest of every Worker, a deploy tool that ships only what changed in parallel stages, and a g1t Actions workflow18use serde_json::{Value, json};
19
20use crate::{API, SITE};
21
A workflow's event payload (`github.event` and the file at `GITHUB_EVENT_PATH`) reads as GitHub's webhook payload does. Ids are whole numbers, the same for an object wherever it appears and safe in JavaScript: `repository.id`, `pull_request.id`, `issue.id`, `review.id`, `sender.id` and every user's and owner's `id`, with g1t's own id as `node_id`; `github.repository_id`, `github.repository_owner_id`, `github.actor_id` and their `GITHUB_*` variables are the same numbers. What g1t's API takes back by id (comments, releases, deployments, workflow runs) keeps g1t's id, so `github.event.comment.id` still edits the comment. A repository in a person's own workspace is owned by a `User`, not an `Organization`. A push says whether it was `forced`, `created` or `deleted`, and its `head_commit` is the commit pushed. A pull request's `base.sha` is the tip of the branch it merges into at the event, not the merge base, and `merge_commit_sha` is the commit it landed as once merged; pull requests and issues carry `node_id`, `assignee`, `locked`, dates and label and milestone ids, and a fork's head names the fork. `workflow_run` has the followed run's attempt, times, actor, head commit, workflow id and URLs. Tests compare each payload's keys and types with trimmed copies of GitHub's documented payloads, and the Actions guide says what differs. OIDC claims keep g1t's ids, so trust policies already written still match.22/// The commit hash GitHub gives for no commit: a branch made or deleted.
23pub const ZERO: &str = "0000000000000000000000000000000000000000";
24
25/// A repository's owner, as a workspace (an `Organization`). A personal
26/// workspace's repositories are owned by a `User` instead: see
27/// [`owned_by_person`].
28fn owner(login: &str) -> Value {
29 json!({
30 "login": login,
31 "id": account_id(login),
32 "type": "Organization",
33 "html_url": format!("{SITE}/{login}"),
34 "url": format!("{API}/users/{login}"),
35 })
36}
37
Deploys as code: a manifest of every Worker, a deploy tool that ships only what changed in parallel stages, and a g1t Actions workflow38pub fn repository(repo: &Repo) -> Value {
39 let full_name = format!("{}/{}", repo.namespace, repo.name);
40 json!({
A workflow's event payload (`github.event` and the file at `GITHUB_EVENT_PATH`) reads as GitHub's webhook payload does. Ids are whole numbers, the same for an object wherever it appears and safe in JavaScript: `repository.id`, `pull_request.id`, `issue.id`, `review.id`, `sender.id` and every user's and owner's `id`, with g1t's own id as `node_id`; `github.repository_id`, `github.repository_owner_id`, `github.actor_id` and their `GITHUB_*` variables are the same numbers. What g1t's API takes back by id (comments, releases, deployments, workflow runs) keeps g1t's id, so `github.event.comment.id` still edits the comment. A repository in a person's own workspace is owned by a `User`, not an `Organization`. A push says whether it was `forced`, `created` or `deleted`, and its `head_commit` is the commit pushed. A pull request's `base.sha` is the tip of the branch it merges into at the event, not the merge base, and `merge_commit_sha` is the commit it landed as once merged; pull requests and issues carry `node_id`, `assignee`, `locked`, dates and label and milestone ids, and a fork's head names the fork. `workflow_run` has the followed run's attempt, times, actor, head commit, workflow id and URLs. Tests compare each payload's keys and types with trimmed copies of GitHub's documented payloads, and the Actions guide says what differs. OIDC claims keep g1t's ids, so trust policies already written still match.41 "id": github_id(&repo.id),
Deploys as code: a manifest of every Worker, a deploy tool that ships only what changed in parallel stages, and a g1t Actions workflow42 "node_id": repo.id,
43 "name": repo.name,
44 "full_name": full_name,
45 "private": repo.is_private,
A workflow's event payload (`github.event` and the file at `GITHUB_EVENT_PATH`) reads as GitHub's webhook payload does. Ids are whole numbers, the same for an object wherever it appears and safe in JavaScript: `repository.id`, `pull_request.id`, `issue.id`, `review.id`, `sender.id` and every user's and owner's `id`, with g1t's own id as `node_id`; `github.repository_id`, `github.repository_owner_id`, `github.actor_id` and their `GITHUB_*` variables are the same numbers. What g1t's API takes back by id (comments, releases, deployments, workflow runs) keeps g1t's id, so `github.event.comment.id` still edits the comment. A repository in a person's own workspace is owned by a `User`, not an `Organization`. A push says whether it was `forced`, `created` or `deleted`, and its `head_commit` is the commit pushed. A pull request's `base.sha` is the tip of the branch it merges into at the event, not the merge base, and `merge_commit_sha` is the commit it landed as once merged; pull requests and issues carry `node_id`, `assignee`, `locked`, dates and label and milestone ids, and a fork's head names the fork. `workflow_run` has the followed run's attempt, times, actor, head commit, workflow id and URLs. Tests compare each payload's keys and types with trimmed copies of GitHub's documented payloads, and the Actions guide says what differs. OIDC claims keep g1t's ids, so trust policies already written still match.46 "owner": owner(&repo.namespace),
Deploys as code: a manifest of every Worker, a deploy tool that ships only what changed in parallel stages, and a g1t Actions workflow47 "html_url": format!("{SITE}/{full_name}"),
48 "url": format!("{API}/repos/{full_name}"),
49 "clone_url": format!("{SITE}/{full_name}.git"),
50 "description": repo.description,
A workflow's event payload (`github.event` and the file at `GITHUB_EVENT_PATH`) reads as GitHub's webhook payload does. Ids are whole numbers, the same for an object wherever it appears and safe in JavaScript: `repository.id`, `pull_request.id`, `issue.id`, `review.id`, `sender.id` and every user's and owner's `id`, with g1t's own id as `node_id`; `github.repository_id`, `github.repository_owner_id`, `github.actor_id` and their `GITHUB_*` variables are the same numbers. What g1t's API takes back by id (comments, releases, deployments, workflow runs) keeps g1t's id, so `github.event.comment.id` still edits the comment. A repository in a person's own workspace is owned by a `User`, not an `Organization`. A push says whether it was `forced`, `created` or `deleted`, and its `head_commit` is the commit pushed. A pull request's `base.sha` is the tip of the branch it merges into at the event, not the merge base, and `merge_commit_sha` is the commit it landed as once merged; pull requests and issues carry `node_id`, `assignee`, `locked`, dates and label and milestone ids, and a fork's head names the fork. `workflow_run` has the followed run's attempt, times, actor, head commit, workflow id and URLs. Tests compare each payload's keys and types with trimmed copies of GitHub's documented payloads, and the Actions guide says what differs. OIDC claims keep g1t's ids, so trust policies already written still match.51 "homepage": repo.website,
52 "topics": repo.topics,
Deploys as code: a manifest of every Worker, a deploy tool that ships only what changed in parallel stages, and a g1t Actions workflow53 "default_branch": repo.default_branch,
54 "fork": false,
A workflow's event payload (`github.event` and the file at `GITHUB_EVENT_PATH`) reads as GitHub's webhook payload does. Ids are whole numbers, the same for an object wherever it appears and safe in JavaScript: `repository.id`, `pull_request.id`, `issue.id`, `review.id`, `sender.id` and every user's and owner's `id`, with g1t's own id as `node_id`; `github.repository_id`, `github.repository_owner_id`, `github.actor_id` and their `GITHUB_*` variables are the same numbers. What g1t's API takes back by id (comments, releases, deployments, workflow runs) keeps g1t's id, so `github.event.comment.id` still edits the comment. A repository in a person's own workspace is owned by a `User`, not an `Organization`. A push says whether it was `forced`, `created` or `deleted`, and its `head_commit` is the commit pushed. A pull request's `base.sha` is the tip of the branch it merges into at the event, not the merge base, and `merge_commit_sha` is the commit it landed as once merged; pull requests and issues carry `node_id`, `assignee`, `locked`, dates and label and milestone ids, and a fork's head names the fork. `workflow_run` has the followed run's attempt, times, actor, head commit, workflow id and URLs. Tests compare each payload's keys and types with trimmed copies of GitHub's documented payloads, and the Actions guide says what differs. OIDC claims keep g1t's ids, so trust policies already written still match.55 "archived": repo.archived(),
56 "created_at": repo.created_at,
Deploys as code: a manifest of every Worker, a deploy tool that ships only what changed in parallel stages, and a g1t Actions workflow57 "visibility": if repo.is_private { "private" } else { "public" },
58 })
59}
60
A workflow's event payload (`github.event` and the file at `GITHUB_EVENT_PATH`) reads as GitHub's webhook payload does. Ids are whole numbers, the same for an object wherever it appears and safe in JavaScript: `repository.id`, `pull_request.id`, `issue.id`, `review.id`, `sender.id` and every user's and owner's `id`, with g1t's own id as `node_id`; `github.repository_id`, `github.repository_owner_id`, `github.actor_id` and their `GITHUB_*` variables are the same numbers. What g1t's API takes back by id (comments, releases, deployments, workflow runs) keeps g1t's id, so `github.event.comment.id` still edits the comment. A repository in a person's own workspace is owned by a `User`, not an `Organization`. A push says whether it was `forced`, `created` or `deleted`, and its `head_commit` is the commit pushed. A pull request's `base.sha` is the tip of the branch it merges into at the event, not the merge base, and `merge_commit_sha` is the commit it landed as once merged; pull requests and issues carry `node_id`, `assignee`, `locked`, dates and label and milestone ids, and a fork's head names the fork. `workflow_run` has the followed run's attempt, times, actor, head commit, workflow id and URLs. Tests compare each payload's keys and types with trimmed copies of GitHub's documented payloads, and the Actions guide says what differs. OIDC claims keep g1t's ids, so trust policies already written still match.61/// A pull request's fork, from what the pull request knows of it.
62fn fork_repository(fork: &RepoPath, id: Option<&str>) -> Value {
63 let full_name = format!("{}/{}", fork.namespace, fork.name);
64 json!({
65 "id": id.map(github_id),
66 "node_id": id,
67 "name": fork.name,
68 "full_name": full_name,
69 "owner": owner(&fork.namespace),
70 "html_url": format!("{SITE}/{full_name}"),
71 "url": format!("{API}/repos/{full_name}"),
72 "clone_url": format!("{SITE}/{full_name}.git"),
73 "fork": true,
74 })
75}
76
77/// Marks the owner of `namespace`'s repositories as a `User` everywhere
78/// in a payload: for a personal workspace, whose name is its person's.
79pub fn owned_by_person(payload: &mut Value, namespace: &str) {
80 match payload {
81 Value::Object(map) => {
82 if map.get("login").and_then(Value::as_str).is_some_and(|login| login.eq_ignore_ascii_case(namespace))
83 && map.get("type").and_then(Value::as_str) == Some("Organization")
84 {
85 map.insert("type".into(), json!("User"));
86 }
87 map.values_mut().for_each(|value| owned_by_person(value, namespace));
88 }
89 Value::Array(items) => items.iter_mut().for_each(|value| owned_by_person(value, namespace)),
90 _ => {}
91 }
92}
93
Deploys as code: a manifest of every Worker, a deploy tool that ships only what changed in parallel stages, and a g1t Actions workflow94pub fn user(login: &str) -> Value {
A workflow's event payload (`github.event` and the file at `GITHUB_EVENT_PATH`) reads as GitHub's webhook payload does. Ids are whole numbers, the same for an object wherever it appears and safe in JavaScript: `repository.id`, `pull_request.id`, `issue.id`, `review.id`, `sender.id` and every user's and owner's `id`, with g1t's own id as `node_id`; `github.repository_id`, `github.repository_owner_id`, `github.actor_id` and their `GITHUB_*` variables are the same numbers. What g1t's API takes back by id (comments, releases, deployments, workflow runs) keeps g1t's id, so `github.event.comment.id` still edits the comment. A repository in a person's own workspace is owned by a `User`, not an `Organization`. A push says whether it was `forced`, `created` or `deleted`, and its `head_commit` is the commit pushed. A pull request's `base.sha` is the tip of the branch it merges into at the event, not the merge base, and `merge_commit_sha` is the commit it landed as once merged; pull requests and issues carry `node_id`, `assignee`, `locked`, dates and label and milestone ids, and a fork's head names the fork. `workflow_run` has the followed run's attempt, times, actor, head commit, workflow id and URLs. Tests compare each payload's keys and types with trimmed copies of GitHub's documented payloads, and the Actions guide says what differs. OIDC claims keep g1t's ids, so trust policies already written still match.95 json!({
96 "login": login,
97 "id": account_id(login),
98 "type": "User",
99 "html_url": format!("{SITE}/{login}"),
100 "url": format!("{API}/users/{login}"),
101 })
Deploys as code: a manifest of every Worker, a deploy tool that ships only what changed in parallel stages, and a g1t Actions workflow102}
103
g1t is the stored author of what it opens; the person who asked is requested_by and keeps the author's rights104/// Someone as GitHub names them. g1t, the author of what it makes and
105/// files, is a `Bot`, as an app is there.
Deploys as code: a manifest of every Worker, a deploy tool that ships only what changed in parallel stages, and a g1t Actions workflow106fn person(user: &User) -> Value {
g1t is the stored author of what it opens; the person who asked is requested_by and keeps the author's rights107 let mut named = self::user(&user.username);
A workflow's event payload (`github.event` and the file at `GITHUB_EVENT_PATH`) reads as GitHub's webhook payload does. Ids are whole numbers, the same for an object wherever it appears and safe in JavaScript: `repository.id`, `pull_request.id`, `issue.id`, `review.id`, `sender.id` and every user's and owner's `id`, with g1t's own id as `node_id`; `github.repository_id`, `github.repository_owner_id`, `github.actor_id` and their `GITHUB_*` variables are the same numbers. What g1t's API takes back by id (comments, releases, deployments, workflow runs) keeps g1t's id, so `github.event.comment.id` still edits the comment. A repository in a person's own workspace is owned by a `User`, not an `Organization`. A push says whether it was `forced`, `created` or `deleted`, and its `head_commit` is the commit pushed. A pull request's `base.sha` is the tip of the branch it merges into at the event, not the merge base, and `merge_commit_sha` is the commit it landed as once merged; pull requests and issues carry `node_id`, `assignee`, `locked`, dates and label and milestone ids, and a fork's head names the fork. `workflow_run` has the followed run's attempt, times, actor, head commit, workflow id and URLs. Tests compare each payload's keys and types with trimmed copies of GitHub's documented payloads, and the Actions guide says what differs. OIDC claims keep g1t's ids, so trust policies already written still match.108 named["node_id"] = json!(user.id);
g1t is the stored author of what it opens; the person who asked is requested_by and keeps the author's rights109 if matches!(user.kind, PrincipalKind::Agent | PrincipalKind::System) {
110 named["type"] = json!("Bot");
111 }
112 named
Deploys as code: a manifest of every Worker, a deploy tool that ships only what changed in parallel stages, and a g1t Actions workflow113}
114
A workflow's event payload (`github.event` and the file at `GITHUB_EVENT_PATH`) reads as GitHub's webhook payload does. Ids are whole numbers, the same for an object wherever it appears and safe in JavaScript: `repository.id`, `pull_request.id`, `issue.id`, `review.id`, `sender.id` and every user's and owner's `id`, with g1t's own id as `node_id`; `github.repository_id`, `github.repository_owner_id`, `github.actor_id` and their `GITHUB_*` variables are the same numbers. What g1t's API takes back by id (comments, releases, deployments, workflow runs) keeps g1t's id, so `github.event.comment.id` still edits the comment. A repository in a person's own workspace is owned by a `User`, not an `Organization`. A push says whether it was `forced`, `created` or `deleted`, and its `head_commit` is the commit pushed. A pull request's `base.sha` is the tip of the branch it merges into at the event, not the merge base, and `merge_commit_sha` is the commit it landed as once merged; pull requests and issues carry `node_id`, `assignee`, `locked`, dates and label and milestone ids, and a fork's head names the fork. `workflow_run` has the followed run's attempt, times, actor, head commit, workflow id and URLs. Tests compare each payload's keys and types with trimmed copies of GitHub's documented payloads, and the Actions guide says what differs. OIDC claims keep g1t's ids, so trust policies already written still match.115fn people(logins: &[String]) -> Vec<Value> {
116 logins.iter().map(|login| user(login)).collect()
117}
118
119fn labels(repo: &Repo, names: &[String]) -> Value {
120 Value::Array(names.iter().map(|name| label(repo, name, None)).collect())
121}
122
Merge branch 'worktree-agent-ab6bf4195fcb97f7c' into claude/cool-newton-7nm8r9123/// A label, by its name in `repo`. Its `color` is the one g1t gives a
124/// label of that name until [`color_labels`] sets the repository's own;
125/// `default` is whether it is one of the labels a repository starts with.
A workflow's event payload (`github.event` and the file at `GITHUB_EVENT_PATH`) reads as GitHub's webhook payload does. Ids are whole numbers, the same for an object wherever it appears and safe in JavaScript: `repository.id`, `pull_request.id`, `issue.id`, `review.id`, `sender.id` and every user's and owner's `id`, with g1t's own id as `node_id`; `github.repository_id`, `github.repository_owner_id`, `github.actor_id` and their `GITHUB_*` variables are the same numbers. What g1t's API takes back by id (comments, releases, deployments, workflow runs) keeps g1t's id, so `github.event.comment.id` still edits the comment. A repository in a person's own workspace is owned by a `User`, not an `Organization`. A push says whether it was `forced`, `created` or `deleted`, and its `head_commit` is the commit pushed. A pull request's `base.sha` is the tip of the branch it merges into at the event, not the merge base, and `merge_commit_sha` is the commit it landed as once merged; pull requests and issues carry `node_id`, `assignee`, `locked`, dates and label and milestone ids, and a fork's head names the fork. `workflow_run` has the followed run's attempt, times, actor, head commit, workflow id and URLs. Tests compare each payload's keys and types with trimmed copies of GitHub's documented payloads, and the Actions guide says what differs. OIDC claims keep g1t's ids, so trust policies already written still match.126fn label(repo: &Repo, name: &str, color: Option<&Value>) -> Value {
Merge branch 'worktree-agent-ab6bf4195fcb97f7c' into claude/cool-newton-7nm8r9127 json!({
128 "id": github_id(&format!("{}:label:{name}", repo.id)),
129 "node_id": format!("{}:label:{name}", repo.id),
130 "name": name,
131 "color": color.filter(|c| c.is_string()).cloned().unwrap_or_else(|| json!(label_color_for(name))),
132 "description": DEFAULT_LABELS.iter().find(|(known, _, _)| *known == name).map(|(_, _, about)| *about),
133 "default": DEFAULT_LABELS.iter().any(|(known, _, _)| *known == name),
134 })
135}
136
137/// Gives every label in a payload (`labels[]` and `label`) the color and
138/// description the repository has for it (work's `list_labels`).
139pub fn color_labels(payload: &mut Value, known: &[Label]) {
140 fn set(label: &mut Value, known: &[Label]) {
141 let Some(found) = label["name"].as_str().and_then(|name| known.iter().find(|k| k.name == name)) else { return };
142 label["color"] = json!(found.color);
143 label["description"] = if found.description.is_empty() { Value::Null } else { json!(found.description) };
144 }
145 if let Value::Object(map) = payload {
146 for (key, value) in map.iter_mut() {
147 match (key.as_str(), value) {
148 ("labels", Value::Array(labels)) => labels.iter_mut().for_each(|label| set(label, known)),
149 ("label", label @ Value::Object(_)) => set(label, known),
150 (_, value) => color_labels(value, known),
151 }
152 }
153 }
154}
155
156/// Whether a payload has any label, so its colors are worth reading.
157pub fn has_labels(payload: &Value) -> bool {
158 match payload {
159 Value::Object(map) => map.iter().any(|(key, value)| match (key.as_str(), value) {
160 ("labels", Value::Array(labels)) => !labels.is_empty(),
161 ("label", Value::Object(_)) => true,
162 (_, value) => has_labels(value),
163 }),
164 _ => false,
A workflow's event payload (`github.event` and the file at `GITHUB_EVENT_PATH`) reads as GitHub's webhook payload does. Ids are whole numbers, the same for an object wherever it appears and safe in JavaScript: `repository.id`, `pull_request.id`, `issue.id`, `review.id`, `sender.id` and every user's and owner's `id`, with g1t's own id as `node_id`; `github.repository_id`, `github.repository_owner_id`, `github.actor_id` and their `GITHUB_*` variables are the same numbers. What g1t's API takes back by id (comments, releases, deployments, workflow runs) keeps g1t's id, so `github.event.comment.id` still edits the comment. A repository in a person's own workspace is owned by a `User`, not an `Organization`. A push says whether it was `forced`, `created` or `deleted`, and its `head_commit` is the commit pushed. A pull request's `base.sha` is the tip of the branch it merges into at the event, not the merge base, and `merge_commit_sha` is the commit it landed as once merged; pull requests and issues carry `node_id`, `assignee`, `locked`, dates and label and milestone ids, and a fork's head names the fork. `workflow_run` has the followed run's attempt, times, actor, head commit, workflow id and URLs. Tests compare each payload's keys and types with trimmed copies of GitHub's documented payloads, and the Actions guide says what differs. OIDC claims keep g1t's ids, so trust policies already written still match.165 }
Deploys as code: a manifest of every Worker, a deploy tool that ships only what changed in parallel stages, and a g1t Actions workflow166}
167
Teams and CODEOWNERS, labels and milestones, dependency updates, the security suite, and a clearer top bar168/// A milestone as an issue or a pull request names it.
A workflow's event payload (`github.event` and the file at `GITHUB_EVENT_PATH`) reads as GitHub's webhook payload does. Ids are whole numbers, the same for an object wherever it appears and safe in JavaScript: `repository.id`, `pull_request.id`, `issue.id`, `review.id`, `sender.id` and every user's and owner's `id`, with g1t's own id as `node_id`; `github.repository_id`, `github.repository_owner_id`, `github.actor_id` and their `GITHUB_*` variables are the same numbers. What g1t's API takes back by id (comments, releases, deployments, workflow runs) keeps g1t's id, so `github.event.comment.id` still edits the comment. A repository in a person's own workspace is owned by a `User`, not an `Organization`. A push says whether it was `forced`, `created` or `deleted`, and its `head_commit` is the commit pushed. A pull request's `base.sha` is the tip of the branch it merges into at the event, not the merge base, and `merge_commit_sha` is the commit it landed as once merged; pull requests and issues carry `node_id`, `assignee`, `locked`, dates and label and milestone ids, and a fork's head names the fork. `workflow_run` has the followed run's attempt, times, actor, head commit, workflow id and URLs. Tests compare each payload's keys and types with trimmed copies of GitHub's documented payloads, and the Actions guide says what differs. OIDC claims keep g1t's ids, so trust policies already written still match.169fn milestone(repo: &Repo, milestone: Option<&MilestoneRef>) -> Value {
170 milestone.map_or(Value::Null, |milestone| milestone_of(repo, milestone.number, &json!(milestone.title)))
171}
172
173fn milestone_of(repo: &Repo, number: u32, title: &Value) -> Value {
174 json!({
175 "id": github_id(&format!("{}:milestone:{number}", repo.id)),
176 "number": number,
177 "title": title,
178 "html_url": format!("{SITE}/{}/{}/milestones/{number}", repo.namespace, repo.name),
179 })
Teams and CODEOWNERS, labels and milestones, dependency updates, the security suite, and a clearer top bar180}
181
Deploys as code: a manifest of every Worker, a deploy tool that ships only what changed in parallel stages, and a g1t Actions workflow182pub fn commit(repo: &Repo, commit: &Commit) -> Value {
183 json!({
184 "id": commit.hash,
185 "tree_id": commit.tree_hash,
186 "message": commit.message,
187 "timestamp": commit.authored_at,
188 "url": format!("{SITE}/{}/{}/commit/{}", repo.namespace, repo.name, commit.hash),
189 "author": { "name": commit.author.name, "email": commit.author.email },
190 "committer": { "name": commit.author.name, "email": commit.author.email },
191 "distinct": true,
A workflow's event payload (`github.event` and the file at `GITHUB_EVENT_PATH`) reads as GitHub's webhook payload does. Ids are whole numbers, the same for an object wherever it appears and safe in JavaScript: `repository.id`, `pull_request.id`, `issue.id`, `review.id`, `sender.id` and every user's and owner's `id`, with g1t's own id as `node_id`; `github.repository_id`, `github.repository_owner_id`, `github.actor_id` and their `GITHUB_*` variables are the same numbers. What g1t's API takes back by id (comments, releases, deployments, workflow runs) keeps g1t's id, so `github.event.comment.id` still edits the comment. A repository in a person's own workspace is owned by a `User`, not an `Organization`. A push says whether it was `forced`, `created` or `deleted`, and its `head_commit` is the commit pushed. A pull request's `base.sha` is the tip of the branch it merges into at the event, not the merge base, and `merge_commit_sha` is the commit it landed as once merged; pull requests and issues carry `node_id`, `assignee`, `locked`, dates and label and milestone ids, and a fork's head names the fork. `workflow_run` has the followed run's attempt, times, actor, head commit, workflow id and URLs. Tests compare each payload's keys and types with trimmed copies of GitHub's documented payloads, and the Actions guide says what differs. OIDC claims keep g1t's ids, so trust policies already written still match.192 "added": [],
193 "removed": [],
194 "modified": [],
Deploys as code: a manifest of every Worker, a deploy tool that ships only what changed in parallel stages, and a g1t Actions workflow195 })
196}
197
Merge branch 'worktree-agent-ab6bf4195fcb97f7c' into claude/cool-newton-7nm8r9198/// Sets a one-commit push's `added`, `removed` and `modified` (on its
199/// commit and `head_commit`) from what the push changed, compared as its
200/// `paths` filters are. A push of several commits keeps them empty: the
201/// comparison is of the whole push, not of each commit.
202pub fn push_changes(payload: &mut Value, changes: &[(String, FileStatus)]) {
203 if payload["commits"].as_array().map(Vec::len) != Some(1) {
204 return;
205 }
206 let of = |status: FileStatus| -> Value {
207 changes.iter().filter(|(_, s)| *s == status).map(|(path, _)| json!(path)).collect::<Vec<_>>().into()
208 };
209 for commit in ["commits", "head_commit"] {
210 let commit = if commit == "commits" { &mut payload["commits"][0] } else { &mut payload["head_commit"] };
211 commit["added"] = of(FileStatus::Added);
212 commit["removed"] = of(FileStatus::Deleted);
213 commit["modified"] = of(FileStatus::Modified);
214 }
215}
216
A workflow's event payload (`github.event` and the file at `GITHUB_EVENT_PATH`) reads as GitHub's webhook payload does. Ids are whole numbers, the same for an object wherever it appears and safe in JavaScript: `repository.id`, `pull_request.id`, `issue.id`, `review.id`, `sender.id` and every user's and owner's `id`, with g1t's own id as `node_id`; `github.repository_id`, `github.repository_owner_id`, `github.actor_id` and their `GITHUB_*` variables are the same numbers. What g1t's API takes back by id (comments, releases, deployments, workflow runs) keeps g1t's id, so `github.event.comment.id` still edits the comment. A repository in a person's own workspace is owned by a `User`, not an `Organization`. A push says whether it was `forced`, `created` or `deleted`, and its `head_commit` is the commit pushed. A pull request's `base.sha` is the tip of the branch it merges into at the event, not the merge base, and `merge_commit_sha` is the commit it landed as once merged; pull requests and issues carry `node_id`, `assignee`, `locked`, dates and label and milestone ids, and a fork's head names the fork. `workflow_run` has the followed run's attempt, times, actor, head commit, workflow id and URLs. Tests compare each payload's keys and types with trimmed copies of GitHub's documented payloads, and the Actions guide says what differs. OIDC claims keep g1t's ids, so trust policies already written still match.217/// A push. `forced` is whether `before` is not in `after`'s history, when
218/// that is known; a push whose history is too long to read says `false`.
Merge branch 'worktree-agent-ab6bf4195fcb97f7c' into claude/cool-newton-7nm8r9219/// `pusher_email` is the pusher's noreply address, when the push was a
220/// person's.
221#[allow(clippy::too_many_arguments)]
222pub fn push(
223 repo: &Repo,
224 git_ref: &str,
225 before: Option<&str>,
226 after: &str,
227 commits: &[Commit],
228 pusher: &str,
229 pusher_email: Option<&str>,
230 forced: bool,
231) -> Value {
A workflow's event payload (`github.event` and the file at `GITHUB_EVENT_PATH`) reads as GitHub's webhook payload does. Ids are whole numbers, the same for an object wherever it appears and safe in JavaScript: `repository.id`, `pull_request.id`, `issue.id`, `review.id`, `sender.id` and every user's and owner's `id`, with g1t's own id as `node_id`; `github.repository_id`, `github.repository_owner_id`, `github.actor_id` and their `GITHUB_*` variables are the same numbers. What g1t's API takes back by id (comments, releases, deployments, workflow runs) keeps g1t's id, so `github.event.comment.id` still edits the comment. A repository in a person's own workspace is owned by a `User`, not an `Organization`. A push says whether it was `forced`, `created` or `deleted`, and its `head_commit` is the commit pushed. A pull request's `base.sha` is the tip of the branch it merges into at the event, not the merge base, and `merge_commit_sha` is the commit it landed as once merged; pull requests and issues carry `node_id`, `assignee`, `locked`, dates and label and milestone ids, and a fork's head names the fork. `workflow_run` has the followed run's attempt, times, actor, head commit, workflow id and URLs. Tests compare each payload's keys and types with trimmed copies of GitHub's documented payloads, and the Actions guide says what differs. OIDC claims keep g1t's ids, so trust policies already written still match.232 let before = before.unwrap_or(ZERO);
233 let created = before == ZERO;
234 let deleted = after == ZERO;
Deploys as code: a manifest of every Worker, a deploy tool that ships only what changed in parallel stages, and a g1t Actions workflow235 let commits: Vec<Value> = commits.iter().map(|c| commit(repo, c)).collect();
A workflow's event payload (`github.event` and the file at `GITHUB_EVENT_PATH`) reads as GitHub's webhook payload does. Ids are whole numbers, the same for an object wherever it appears and safe in JavaScript: `repository.id`, `pull_request.id`, `issue.id`, `review.id`, `sender.id` and every user's and owner's `id`, with g1t's own id as `node_id`; `github.repository_id`, `github.repository_owner_id`, `github.actor_id` and their `GITHUB_*` variables are the same numbers. What g1t's API takes back by id (comments, releases, deployments, workflow runs) keeps g1t's id, so `github.event.comment.id` still edits the comment. A repository in a person's own workspace is owned by a `User`, not an `Organization`. A push says whether it was `forced`, `created` or `deleted`, and its `head_commit` is the commit pushed. A pull request's `base.sha` is the tip of the branch it merges into at the event, not the merge base, and `merge_commit_sha` is the commit it landed as once merged; pull requests and issues carry `node_id`, `assignee`, `locked`, dates and label and milestone ids, and a fork's head names the fork. `workflow_run` has the followed run's attempt, times, actor, head commit, workflow id and URLs. Tests compare each payload's keys and types with trimmed copies of GitHub's documented payloads, and the Actions guide says what differs. OIDC claims keep g1t's ids, so trust policies already written still match.236 let full_name = format!("{}/{}", repo.namespace, repo.name);
237 let compare = if created {
238 format!("{SITE}/{full_name}/commit/{after}")
239 } else {
240 format!("{SITE}/{full_name}/compare/{before}...{after}")
241 };
Deploys as code: a manifest of every Worker, a deploy tool that ships only what changed in parallel stages, and a g1t Actions workflow242 json!({
243 "ref": git_ref,
A workflow's event payload (`github.event` and the file at `GITHUB_EVENT_PATH`) reads as GitHub's webhook payload does. Ids are whole numbers, the same for an object wherever it appears and safe in JavaScript: `repository.id`, `pull_request.id`, `issue.id`, `review.id`, `sender.id` and every user's and owner's `id`, with g1t's own id as `node_id`; `github.repository_id`, `github.repository_owner_id`, `github.actor_id` and their `GITHUB_*` variables are the same numbers. What g1t's API takes back by id (comments, releases, deployments, workflow runs) keeps g1t's id, so `github.event.comment.id` still edits the comment. A repository in a person's own workspace is owned by a `User`, not an `Organization`. A push says whether it was `forced`, `created` or `deleted`, and its `head_commit` is the commit pushed. A pull request's `base.sha` is the tip of the branch it merges into at the event, not the merge base, and `merge_commit_sha` is the commit it landed as once merged; pull requests and issues carry `node_id`, `assignee`, `locked`, dates and label and milestone ids, and a fork's head names the fork. `workflow_run` has the followed run's attempt, times, actor, head commit, workflow id and URLs. Tests compare each payload's keys and types with trimmed copies of GitHub's documented payloads, and the Actions guide says what differs. OIDC claims keep g1t's ids, so trust policies already written still match.244 "before": before,
Deploys as code: a manifest of every Worker, a deploy tool that ships only what changed in parallel stages, and a g1t Actions workflow245 "after": after,
A workflow's event payload (`github.event` and the file at `GITHUB_EVENT_PATH`) reads as GitHub's webhook payload does. Ids are whole numbers, the same for an object wherever it appears and safe in JavaScript: `repository.id`, `pull_request.id`, `issue.id`, `review.id`, `sender.id` and every user's and owner's `id`, with g1t's own id as `node_id`; `github.repository_id`, `github.repository_owner_id`, `github.actor_id` and their `GITHUB_*` variables are the same numbers. What g1t's API takes back by id (comments, releases, deployments, workflow runs) keeps g1t's id, so `github.event.comment.id` still edits the comment. A repository in a person's own workspace is owned by a `User`, not an `Organization`. A push says whether it was `forced`, `created` or `deleted`, and its `head_commit` is the commit pushed. A pull request's `base.sha` is the tip of the branch it merges into at the event, not the merge base, and `merge_commit_sha` is the commit it landed as once merged; pull requests and issues carry `node_id`, `assignee`, `locked`, dates and label and milestone ids, and a fork's head names the fork. `workflow_run` has the followed run's attempt, times, actor, head commit, workflow id and URLs. Tests compare each payload's keys and types with trimmed copies of GitHub's documented payloads, and the Actions guide says what differs. OIDC claims keep g1t's ids, so trust policies already written still match.246 "created": created,
247 "deleted": deleted,
248 "forced": forced && !created && !deleted,
Deploys as code: a manifest of every Worker, a deploy tool that ships only what changed in parallel stages, and a g1t Actions workflow249 "base_ref": null,
A workflow's event payload (`github.event` and the file at `GITHUB_EVENT_PATH`) reads as GitHub's webhook payload does. Ids are whole numbers, the same for an object wherever it appears and safe in JavaScript: `repository.id`, `pull_request.id`, `issue.id`, `review.id`, `sender.id` and every user's and owner's `id`, with g1t's own id as `node_id`; `github.repository_id`, `github.repository_owner_id`, `github.actor_id` and their `GITHUB_*` variables are the same numbers. What g1t's API takes back by id (comments, releases, deployments, workflow runs) keeps g1t's id, so `github.event.comment.id` still edits the comment. A repository in a person's own workspace is owned by a `User`, not an `Organization`. A push says whether it was `forced`, `created` or `deleted`, and its `head_commit` is the commit pushed. A pull request's `base.sha` is the tip of the branch it merges into at the event, not the merge base, and `merge_commit_sha` is the commit it landed as once merged; pull requests and issues carry `node_id`, `assignee`, `locked`, dates and label and milestone ids, and a fork's head names the fork. `workflow_run` has the followed run's attempt, times, actor, head commit, workflow id and URLs. Tests compare each payload's keys and types with trimmed copies of GitHub's documented payloads, and the Actions guide says what differs. OIDC claims keep g1t's ids, so trust policies already written still match.250 "compare": compare,
251 // GitHub's head commit is the one pushed: the last.
252 "head_commit": commits.last().cloned().unwrap_or(Value::Null),
Deploys as code: a manifest of every Worker, a deploy tool that ships only what changed in parallel stages, and a g1t Actions workflow253 "commits": commits,
Merge branch 'worktree-agent-ab6bf4195fcb97f7c' into claude/cool-newton-7nm8r9254 "pusher": { "name": pusher, "email": pusher_email },
Deploys as code: a manifest of every Worker, a deploy tool that ships only what changed in parallel stages, and a g1t Actions workflow255 "repository": repository(repo),
256 "sender": user(pusher),
257 })
258}
259
260pub fn issue(repo: &Repo, issue: &Issue) -> Value {
261 let full_name = format!("{}/{}", repo.namespace, repo.name);
262 json!({
A workflow's event payload (`github.event` and the file at `GITHUB_EVENT_PATH`) reads as GitHub's webhook payload does. Ids are whole numbers, the same for an object wherever it appears and safe in JavaScript: `repository.id`, `pull_request.id`, `issue.id`, `review.id`, `sender.id` and every user's and owner's `id`, with g1t's own id as `node_id`; `github.repository_id`, `github.repository_owner_id`, `github.actor_id` and their `GITHUB_*` variables are the same numbers. What g1t's API takes back by id (comments, releases, deployments, workflow runs) keeps g1t's id, so `github.event.comment.id` still edits the comment. A repository in a person's own workspace is owned by a `User`, not an `Organization`. A push says whether it was `forced`, `created` or `deleted`, and its `head_commit` is the commit pushed. A pull request's `base.sha` is the tip of the branch it merges into at the event, not the merge base, and `merge_commit_sha` is the commit it landed as once merged; pull requests and issues carry `node_id`, `assignee`, `locked`, dates and label and milestone ids, and a fork's head names the fork. `workflow_run` has the followed run's attempt, times, actor, head commit, workflow id and URLs. Tests compare each payload's keys and types with trimmed copies of GitHub's documented payloads, and the Actions guide says what differs. OIDC claims keep g1t's ids, so trust policies already written still match.263 "id": github_id(&issue.id),
264 "node_id": issue.id,
Deploys as code: a manifest of every Worker, a deploy tool that ships only what changed in parallel stages, and a g1t Actions workflow265 "number": issue.number,
266 "title": issue.title,
267 "body": issue.body,
268 "state": if issue.state == State::Open { "open" } else { "closed" },
269 "state_reason": issue.reason,
A workflow's event payload (`github.event` and the file at `GITHUB_EVENT_PATH`) reads as GitHub's webhook payload does. Ids are whole numbers, the same for an object wherever it appears and safe in JavaScript: `repository.id`, `pull_request.id`, `issue.id`, `review.id`, `sender.id` and every user's and owner's `id`, with g1t's own id as `node_id`; `github.repository_id`, `github.repository_owner_id`, `github.actor_id` and their `GITHUB_*` variables are the same numbers. What g1t's API takes back by id (comments, releases, deployments, workflow runs) keeps g1t's id, so `github.event.comment.id` still edits the comment. A repository in a person's own workspace is owned by a `User`, not an `Organization`. A push says whether it was `forced`, `created` or `deleted`, and its `head_commit` is the commit pushed. A pull request's `base.sha` is the tip of the branch it merges into at the event, not the merge base, and `merge_commit_sha` is the commit it landed as once merged; pull requests and issues carry `node_id`, `assignee`, `locked`, dates and label and milestone ids, and a fork's head names the fork. `workflow_run` has the followed run's attempt, times, actor, head commit, workflow id and URLs. Tests compare each payload's keys and types with trimmed copies of GitHub's documented payloads, and the Actions guide says what differs. OIDC claims keep g1t's ids, so trust policies already written still match.270 "locked": false,
271 "labels": labels(repo, &issue.labels),
272 "milestone": milestone(repo, issue.milestone.as_ref()),
Deploys as code: a manifest of every Worker, a deploy tool that ships only what changed in parallel stages, and a g1t Actions workflow273 "user": person(&issue.author),
g1t is the stored author of what it opens; the person who asked is requested_by and keeps the author's rights274 // g1t's own field: for an issue its agent filed, who it worked for.
275 "requested_by": issue.requested_by.as_ref().map(person),
A workflow's event payload (`github.event` and the file at `GITHUB_EVENT_PATH`) reads as GitHub's webhook payload does. Ids are whole numbers, the same for an object wherever it appears and safe in JavaScript: `repository.id`, `pull_request.id`, `issue.id`, `review.id`, `sender.id` and every user's and owner's `id`, with g1t's own id as `node_id`; `github.repository_id`, `github.repository_owner_id`, `github.actor_id` and their `GITHUB_*` variables are the same numbers. What g1t's API takes back by id (comments, releases, deployments, workflow runs) keeps g1t's id, so `github.event.comment.id` still edits the comment. A repository in a person's own workspace is owned by a `User`, not an `Organization`. A push says whether it was `forced`, `created` or `deleted`, and its `head_commit` is the commit pushed. A pull request's `base.sha` is the tip of the branch it merges into at the event, not the merge base, and `merge_commit_sha` is the commit it landed as once merged; pull requests and issues carry `node_id`, `assignee`, `locked`, dates and label and milestone ids, and a fork's head names the fork. `workflow_run` has the followed run's attempt, times, actor, head commit, workflow id and URLs. Tests compare each payload's keys and types with trimmed copies of GitHub's documented payloads, and the Actions guide says what differs. OIDC claims keep g1t's ids, so trust policies already written still match.276 "assignee": issue.assignees.first().map(|a| user(a)),
277 "assignees": people(&issue.assignees),
Deploys as code: a manifest of every Worker, a deploy tool that ships only what changed in parallel stages, and a g1t Actions workflow278 "comments": issue.comment_count,
279 "created_at": issue.created_at,
280 "updated_at": issue.updated_at,
281 "closed_at": issue.closed_at,
282 "html_url": format!("{SITE}/{full_name}/issues/{}", issue.number),
283 "url": format!("{API}/repos/{full_name}/issues/{}", issue.number),
A workflow's event payload (`github.event` and the file at `GITHUB_EVENT_PATH`) reads as GitHub's webhook payload does. Ids are whole numbers, the same for an object wherever it appears and safe in JavaScript: `repository.id`, `pull_request.id`, `issue.id`, `review.id`, `sender.id` and every user's and owner's `id`, with g1t's own id as `node_id`; `github.repository_id`, `github.repository_owner_id`, `github.actor_id` and their `GITHUB_*` variables are the same numbers. What g1t's API takes back by id (comments, releases, deployments, workflow runs) keeps g1t's id, so `github.event.comment.id` still edits the comment. A repository in a person's own workspace is owned by a `User`, not an `Organization`. A push says whether it was `forced`, `created` or `deleted`, and its `head_commit` is the commit pushed. A pull request's `base.sha` is the tip of the branch it merges into at the event, not the merge base, and `merge_commit_sha` is the commit it landed as once merged; pull requests and issues carry `node_id`, `assignee`, `locked`, dates and label and milestone ids, and a fork's head names the fork. `workflow_run` has the followed run's attempt, times, actor, head commit, workflow id and URLs. Tests compare each payload's keys and types with trimmed copies of GitHub's documented payloads, and the Actions guide says what differs. OIDC claims keep g1t's ids, so trust policies already written still match.284 "repository_url": format!("{API}/repos/{full_name}"),
Deploys as code: a manifest of every Worker, a deploy tool that ships only what changed in parallel stages, and a g1t Actions workflow285 })
286}
287
A workflow's event payload (`github.event` and the file at `GITHUB_EVENT_PATH`) reads as GitHub's webhook payload does. Ids are whole numbers, the same for an object wherever it appears and safe in JavaScript: `repository.id`, `pull_request.id`, `issue.id`, `review.id`, `sender.id` and every user's and owner's `id`, with g1t's own id as `node_id`; `github.repository_id`, `github.repository_owner_id`, `github.actor_id` and their `GITHUB_*` variables are the same numbers. What g1t's API takes back by id (comments, releases, deployments, workflow runs) keeps g1t's id, so `github.event.comment.id` still edits the comment. A repository in a person's own workspace is owned by a `User`, not an `Organization`. A push says whether it was `forced`, `created` or `deleted`, and its `head_commit` is the commit pushed. A pull request's `base.sha` is the tip of the branch it merges into at the event, not the merge base, and `merge_commit_sha` is the commit it landed as once merged; pull requests and issues carry `node_id`, `assignee`, `locked`, dates and label and milestone ids, and a fork's head names the fork. `workflow_run` has the followed run's attempt, times, actor, head commit, workflow id and URLs. Tests compare each payload's keys and types with trimmed copies of GitHub's documented payloads, and the Actions guide says what differs. OIDC claims keep g1t's ids, so trust policies already written still match.288/// A pull request, with its own labels. `base.sha` is the pull request's
289/// merge base until the trigger sets the base branch's tip, as GitHub
290/// gives it (trigger.rs).
Teams and CODEOWNERS, labels and milestones, dependency updates, the security suite, and a clearer top bar291pub fn pull(repo: &Repo, pull: &Pull) -> Value {
Deploys as code: a manifest of every Worker, a deploy tool that ships only what changed in parallel stages, and a g1t Actions workflow292 let full_name = format!("{}/{}", repo.namespace, repo.name);
293 let head_ref = head_ref(pull);
Teams and CODEOWNERS, labels and milestones, dependency updates, the security suite, and a clearer top bar294 let base_ref = pull.base_branch(&repo.default_branch);
A workflow's event payload (`github.event` and the file at `GITHUB_EVENT_PATH`) reads as GitHub's webhook payload does. Ids are whole numbers, the same for an object wherever it appears and safe in JavaScript: `repository.id`, `pull_request.id`, `issue.id`, `review.id`, `sender.id` and every user's and owner's `id`, with g1t's own id as `node_id`; `github.repository_id`, `github.repository_owner_id`, `github.actor_id` and their `GITHUB_*` variables are the same numbers. What g1t's API takes back by id (comments, releases, deployments, workflow runs) keeps g1t's id, so `github.event.comment.id` still edits the comment. A repository in a person's own workspace is owned by a `User`, not an `Organization`. A push says whether it was `forced`, `created` or `deleted`, and its `head_commit` is the commit pushed. A pull request's `base.sha` is the tip of the branch it merges into at the event, not the merge base, and `merge_commit_sha` is the commit it landed as once merged; pull requests and issues carry `node_id`, `assignee`, `locked`, dates and label and milestone ids, and a fork's head names the fork. `workflow_run` has the followed run's attempt, times, actor, head commit, workflow id and URLs. Tests compare each payload's keys and types with trimmed copies of GitHub's documented payloads, and the Actions guide says what differs. OIDC claims keep g1t's ids, so trust policies already written still match.295 let (head_repo, head_owner) = match &pull.fork {
296 Some(fork) => (fork_repository(fork, pull.fork_repo_id.as_deref()), fork.namespace.as_str()),
297 None => (repository(repo), repo.namespace.as_str()),
Deploys as code: a manifest of every Worker, a deploy tool that ships only what changed in parallel stages, and a g1t Actions workflow298 };
A workflow's event payload (`github.event` and the file at `GITHUB_EVENT_PATH`) reads as GitHub's webhook payload does. Ids are whole numbers, the same for an object wherever it appears and safe in JavaScript: `repository.id`, `pull_request.id`, `issue.id`, `review.id`, `sender.id` and every user's and owner's `id`, with g1t's own id as `node_id`; `github.repository_id`, `github.repository_owner_id`, `github.actor_id` and their `GITHUB_*` variables are the same numbers. What g1t's API takes back by id (comments, releases, deployments, workflow runs) keeps g1t's id, so `github.event.comment.id` still edits the comment. A repository in a person's own workspace is owned by a `User`, not an `Organization`. A push says whether it was `forced`, `created` or `deleted`, and its `head_commit` is the commit pushed. A pull request's `base.sha` is the tip of the branch it merges into at the event, not the merge base, and `merge_commit_sha` is the commit it landed as once merged; pull requests and issues carry `node_id`, `assignee`, `locked`, dates and label and milestone ids, and a fork's head names the fork. `workflow_run` has the followed run's attempt, times, actor, head commit, workflow id and URLs. Tests compare each payload's keys and types with trimmed copies of GitHub's documented payloads, and the Actions guide says what differs. OIDC claims keep g1t's ids, so trust policies already written still match.299 let merged = pull.status == PullStatus::Merged;
300 let closed_at = match pull.status {
301 PullStatus::Merged => pull.merged_at.clone(),
302 PullStatus::Closed => Some(pull.updated_at.clone()),
303 _ => None,
304 };
Deploys as code: a manifest of every Worker, a deploy tool that ships only what changed in parallel stages, and a g1t Actions workflow305 json!({
A workflow's event payload (`github.event` and the file at `GITHUB_EVENT_PATH`) reads as GitHub's webhook payload does. Ids are whole numbers, the same for an object wherever it appears and safe in JavaScript: `repository.id`, `pull_request.id`, `issue.id`, `review.id`, `sender.id` and every user's and owner's `id`, with g1t's own id as `node_id`; `github.repository_id`, `github.repository_owner_id`, `github.actor_id` and their `GITHUB_*` variables are the same numbers. What g1t's API takes back by id (comments, releases, deployments, workflow runs) keeps g1t's id, so `github.event.comment.id` still edits the comment. A repository in a person's own workspace is owned by a `User`, not an `Organization`. A push says whether it was `forced`, `created` or `deleted`, and its `head_commit` is the commit pushed. A pull request's `base.sha` is the tip of the branch it merges into at the event, not the merge base, and `merge_commit_sha` is the commit it landed as once merged; pull requests and issues carry `node_id`, `assignee`, `locked`, dates and label and milestone ids, and a fork's head names the fork. `workflow_run` has the followed run's attempt, times, actor, head commit, workflow id and URLs. Tests compare each payload's keys and types with trimmed copies of GitHub's documented payloads, and the Actions guide says what differs. OIDC claims keep g1t's ids, so trust policies already written still match.306 "id": github_id(&pull.id),
307 "node_id": pull.id,
Deploys as code: a manifest of every Worker, a deploy tool that ships only what changed in parallel stages, and a g1t Actions workflow308 "number": pull.number,
309 "title": pull.title,
310 "body": pull.body,
311 "state": if pull.status.is_active() { "open" } else { "closed" },
A workflow's event payload (`github.event` and the file at `GITHUB_EVENT_PATH`) reads as GitHub's webhook payload does. Ids are whole numbers, the same for an object wherever it appears and safe in JavaScript: `repository.id`, `pull_request.id`, `issue.id`, `review.id`, `sender.id` and every user's and owner's `id`, with g1t's own id as `node_id`; `github.repository_id`, `github.repository_owner_id`, `github.actor_id` and their `GITHUB_*` variables are the same numbers. What g1t's API takes back by id (comments, releases, deployments, workflow runs) keeps g1t's id, so `github.event.comment.id` still edits the comment. A repository in a person's own workspace is owned by a `User`, not an `Organization`. A push says whether it was `forced`, `created` or `deleted`, and its `head_commit` is the commit pushed. A pull request's `base.sha` is the tip of the branch it merges into at the event, not the merge base, and `merge_commit_sha` is the commit it landed as once merged; pull requests and issues carry `node_id`, `assignee`, `locked`, dates and label and milestone ids, and a fork's head names the fork. `workflow_run` has the followed run's attempt, times, actor, head commit, workflow id and URLs. Tests compare each payload's keys and types with trimmed copies of GitHub's documented payloads, and the Actions guide says what differs. OIDC claims keep g1t's ids, so trust policies already written still match.312 "locked": false,
Deploys as code: a manifest of every Worker, a deploy tool that ships only what changed in parallel stages, and a g1t Actions workflow313 "draft": pull.status == PullStatus::Draft,
A workflow's event payload (`github.event` and the file at `GITHUB_EVENT_PATH`) reads as GitHub's webhook payload does. Ids are whole numbers, the same for an object wherever it appears and safe in JavaScript: `repository.id`, `pull_request.id`, `issue.id`, `review.id`, `sender.id` and every user's and owner's `id`, with g1t's own id as `node_id`; `github.repository_id`, `github.repository_owner_id`, `github.actor_id` and their `GITHUB_*` variables are the same numbers. What g1t's API takes back by id (comments, releases, deployments, workflow runs) keeps g1t's id, so `github.event.comment.id` still edits the comment. A repository in a person's own workspace is owned by a `User`, not an `Organization`. A push says whether it was `forced`, `created` or `deleted`, and its `head_commit` is the commit pushed. A pull request's `base.sha` is the tip of the branch it merges into at the event, not the merge base, and `merge_commit_sha` is the commit it landed as once merged; pull requests and issues carry `node_id`, `assignee`, `locked`, dates and label and milestone ids, and a fork's head names the fork. `workflow_run` has the followed run's attempt, times, actor, head commit, workflow id and URLs. Tests compare each payload's keys and types with trimmed copies of GitHub's documented payloads, and the Actions guide says what differs. OIDC claims keep g1t's ids, so trust policies already written still match.314 "merged": merged,
Deploys as code: a manifest of every Worker, a deploy tool that ships only what changed in parallel stages, and a g1t Actions workflow315 "merged_at": pull.merged_at,
316 "merged_by": pull.merged_by.as_deref().map(user),
A workflow's event payload (`github.event` and the file at `GITHUB_EVENT_PATH`) reads as GitHub's webhook payload does. Ids are whole numbers, the same for an object wherever it appears and safe in JavaScript: `repository.id`, `pull_request.id`, `issue.id`, `review.id`, `sender.id` and every user's and owner's `id`, with g1t's own id as `node_id`; `github.repository_id`, `github.repository_owner_id`, `github.actor_id` and their `GITHUB_*` variables are the same numbers. What g1t's API takes back by id (comments, releases, deployments, workflow runs) keeps g1t's id, so `github.event.comment.id` still edits the comment. A repository in a person's own workspace is owned by a `User`, not an `Organization`. A push says whether it was `forced`, `created` or `deleted`, and its `head_commit` is the commit pushed. A pull request's `base.sha` is the tip of the branch it merges into at the event, not the merge base, and `merge_commit_sha` is the commit it landed as once merged; pull requests and issues carry `node_id`, `assignee`, `locked`, dates and label and milestone ids, and a fork's head names the fork. `workflow_run` has the followed run's attempt, times, actor, head commit, workflow id and URLs. Tests compare each payload's keys and types with trimmed copies of GitHub's documented payloads, and the Actions guide says what differs. OIDC claims keep g1t's ids, so trust policies already written still match.317 // Only once merged, as on GitHub; the trigger sets the commit it
318 // landed as when the event says.
319 "merge_commit_sha": if merged { pull.head_commit.clone() } else { None },
320 "labels": labels(repo, &pull.labels),
321 "milestone": milestone(repo, pull.milestone.as_ref()),
Deploys as code: a manifest of every Worker, a deploy tool that ships only what changed in parallel stages, and a g1t Actions workflow322 "user": person(&pull.author),
g1t is the stored author of what it opens; the person who asked is requested_by and keeps the author's rights323 // g1t's own field: for a change g1t made, who asked for it.
324 "requested_by": pull.requested_by.as_ref().map(person),
A workflow's event payload (`github.event` and the file at `GITHUB_EVENT_PATH`) reads as GitHub's webhook payload does. Ids are whole numbers, the same for an object wherever it appears and safe in JavaScript: `repository.id`, `pull_request.id`, `issue.id`, `review.id`, `sender.id` and every user's and owner's `id`, with g1t's own id as `node_id`; `github.repository_id`, `github.repository_owner_id`, `github.actor_id` and their `GITHUB_*` variables are the same numbers. What g1t's API takes back by id (comments, releases, deployments, workflow runs) keeps g1t's id, so `github.event.comment.id` still edits the comment. A repository in a person's own workspace is owned by a `User`, not an `Organization`. A push says whether it was `forced`, `created` or `deleted`, and its `head_commit` is the commit pushed. A pull request's `base.sha` is the tip of the branch it merges into at the event, not the merge base, and `merge_commit_sha` is the commit it landed as once merged; pull requests and issues carry `node_id`, `assignee`, `locked`, dates and label and milestone ids, and a fork's head names the fork. `workflow_run` has the followed run's attempt, times, actor, head commit, workflow id and URLs. Tests compare each payload's keys and types with trimmed copies of GitHub's documented payloads, and the Actions guide says what differs. OIDC claims keep g1t's ids, so trust policies already written still match.325 "assignee": pull.assignees.first().map(|a| user(a)),
326 "assignees": people(&pull.assignees),
327 "requested_reviewers": people(&pull.reviewers),
Deploys as code: a manifest of every Worker, a deploy tool that ships only what changed in parallel stages, and a g1t Actions workflow328 "head": {
329 "ref": head_ref,
330 "sha": pull.head_commit,
A workflow's event payload (`github.event` and the file at `GITHUB_EVENT_PATH`) reads as GitHub's webhook payload does. Ids are whole numbers, the same for an object wherever it appears and safe in JavaScript: `repository.id`, `pull_request.id`, `issue.id`, `review.id`, `sender.id` and every user's and owner's `id`, with g1t's own id as `node_id`; `github.repository_id`, `github.repository_owner_id`, `github.actor_id` and their `GITHUB_*` variables are the same numbers. What g1t's API takes back by id (comments, releases, deployments, workflow runs) keeps g1t's id, so `github.event.comment.id` still edits the comment. A repository in a person's own workspace is owned by a `User`, not an `Organization`. A push says whether it was `forced`, `created` or `deleted`, and its `head_commit` is the commit pushed. A pull request's `base.sha` is the tip of the branch it merges into at the event, not the merge base, and `merge_commit_sha` is the commit it landed as once merged; pull requests and issues carry `node_id`, `assignee`, `locked`, dates and label and milestone ids, and a fork's head names the fork. `workflow_run` has the followed run's attempt, times, actor, head commit, workflow id and URLs. Tests compare each payload's keys and types with trimmed copies of GitHub's documented payloads, and the Actions guide says what differs. OIDC claims keep g1t's ids, so trust policies already written still match.331 "label": format!("{head_owner}:{head_ref}"),
332 "user": owner(head_owner),
Deploys as code: a manifest of every Worker, a deploy tool that ships only what changed in parallel stages, and a g1t Actions workflow333 "repo": head_repo,
334 },
335 "base": {
Teams and CODEOWNERS, labels and milestones, dependency updates, the security suite, and a clearer top bar336 "ref": base_ref,
Deploys as code: a manifest of every Worker, a deploy tool that ships only what changed in parallel stages, and a g1t Actions workflow337 "sha": pull.merge_base,
Teams and CODEOWNERS, labels and milestones, dependency updates, the security suite, and a clearer top bar338 "label": format!("{}:{base_ref}", repo.namespace),
A workflow's event payload (`github.event` and the file at `GITHUB_EVENT_PATH`) reads as GitHub's webhook payload does. Ids are whole numbers, the same for an object wherever it appears and safe in JavaScript: `repository.id`, `pull_request.id`, `issue.id`, `review.id`, `sender.id` and every user's and owner's `id`, with g1t's own id as `node_id`; `github.repository_id`, `github.repository_owner_id`, `github.actor_id` and their `GITHUB_*` variables are the same numbers. What g1t's API takes back by id (comments, releases, deployments, workflow runs) keeps g1t's id, so `github.event.comment.id` still edits the comment. A repository in a person's own workspace is owned by a `User`, not an `Organization`. A push says whether it was `forced`, `created` or `deleted`, and its `head_commit` is the commit pushed. A pull request's `base.sha` is the tip of the branch it merges into at the event, not the merge base, and `merge_commit_sha` is the commit it landed as once merged; pull requests and issues carry `node_id`, `assignee`, `locked`, dates and label and milestone ids, and a fork's head names the fork. `workflow_run` has the followed run's attempt, times, actor, head commit, workflow id and URLs. Tests compare each payload's keys and types with trimmed copies of GitHub's documented payloads, and the Actions guide says what differs. OIDC claims keep g1t's ids, so trust policies already written still match.339 "user": owner(&repo.namespace),
Deploys as code: a manifest of every Worker, a deploy tool that ships only what changed in parallel stages, and a g1t Actions workflow340 "repo": repository(repo),
341 },
A workflow's event payload (`github.event` and the file at `GITHUB_EVENT_PATH`) reads as GitHub's webhook payload does. Ids are whole numbers, the same for an object wherever it appears and safe in JavaScript: `repository.id`, `pull_request.id`, `issue.id`, `review.id`, `sender.id` and every user's and owner's `id`, with g1t's own id as `node_id`; `github.repository_id`, `github.repository_owner_id`, `github.actor_id` and their `GITHUB_*` variables are the same numbers. What g1t's API takes back by id (comments, releases, deployments, workflow runs) keeps g1t's id, so `github.event.comment.id` still edits the comment. A repository in a person's own workspace is owned by a `User`, not an `Organization`. A push says whether it was `forced`, `created` or `deleted`, and its `head_commit` is the commit pushed. A pull request's `base.sha` is the tip of the branch it merges into at the event, not the merge base, and `merge_commit_sha` is the commit it landed as once merged; pull requests and issues carry `node_id`, `assignee`, `locked`, dates and label and milestone ids, and a fork's head names the fork. `workflow_run` has the followed run's attempt, times, actor, head commit, workflow id and URLs. Tests compare each payload's keys and types with trimmed copies of GitHub's documented payloads, and the Actions guide says what differs. OIDC claims keep g1t's ids, so trust policies already written still match.342 "changed_files": pull.files.len(),
343 "additions": pull.files.iter().map(|f| u64::from(f.additions)).sum::<u64>(),
344 "deletions": pull.files.iter().map(|f| u64::from(f.deletions)).sum::<u64>(),
345 "created_at": pull.created_at,
346 "updated_at": pull.updated_at,
347 "closed_at": closed_at,
Deploys as code: a manifest of every Worker, a deploy tool that ships only what changed in parallel stages, and a g1t Actions workflow348 "html_url": format!("{SITE}/{full_name}/pull/{}", pull.number),
349 "url": format!("{API}/repos/{full_name}/pulls/{}", pull.number),
A workflow's event payload (`github.event` and the file at `GITHUB_EVENT_PATH`) reads as GitHub's webhook payload does. Ids are whole numbers, the same for an object wherever it appears and safe in JavaScript: `repository.id`, `pull_request.id`, `issue.id`, `review.id`, `sender.id` and every user's and owner's `id`, with g1t's own id as `node_id`; `github.repository_id`, `github.repository_owner_id`, `github.actor_id` and their `GITHUB_*` variables are the same numbers. What g1t's API takes back by id (comments, releases, deployments, workflow runs) keeps g1t's id, so `github.event.comment.id` still edits the comment. A repository in a person's own workspace is owned by a `User`, not an `Organization`. A push says whether it was `forced`, `created` or `deleted`, and its `head_commit` is the commit pushed. A pull request's `base.sha` is the tip of the branch it merges into at the event, not the merge base, and `merge_commit_sha` is the commit it landed as once merged; pull requests and issues carry `node_id`, `assignee`, `locked`, dates and label and milestone ids, and a fork's head names the fork. `workflow_run` has the followed run's attempt, times, actor, head commit, workflow id and URLs. Tests compare each payload's keys and types with trimmed copies of GitHub's documented payloads, and the Actions guide says what differs. OIDC claims keep g1t's ids, so trust policies already written still match.350 "issue_url": format!("{API}/repos/{full_name}/issues/{}", pull.number),
Deploys as code: a manifest of every Worker, a deploy tool that ships only what changed in parallel stages, and a g1t Actions workflow351 })
352}
353
Merge branch 'worktree-agent-a8b78c62188153aa3' into claude/cool-newton-7nm8r9354/// What a `labeled`, `unlabeled`, `milestoned`, `demilestoned`,
355/// `assigned` or base change was about, from the g1t event: `label`,
356/// `milestone`, `assignee` (the first of those newly assigned; g1t sends
357/// one event for them all, GitHub one each), and for a new base,
358/// `changes.base.ref.from` is not known, so only the new base is in
359/// `pull_request.base`.
A workflow's event payload (`github.event` and the file at `GITHUB_EVENT_PATH`) reads as GitHub's webhook payload does. Ids are whole numbers, the same for an object wherever it appears and safe in JavaScript: `repository.id`, `pull_request.id`, `issue.id`, `review.id`, `sender.id` and every user's and owner's `id`, with g1t's own id as `node_id`; `github.repository_id`, `github.repository_owner_id`, `github.actor_id` and their `GITHUB_*` variables are the same numbers. What g1t's API takes back by id (comments, releases, deployments, workflow runs) keeps g1t's id, so `github.event.comment.id` still edits the comment. A repository in a person's own workspace is owned by a `User`, not an `Organization`. A push says whether it was `forced`, `created` or `deleted`, and its `head_commit` is the commit pushed. A pull request's `base.sha` is the tip of the branch it merges into at the event, not the merge base, and `merge_commit_sha` is the commit it landed as once merged; pull requests and issues carry `node_id`, `assignee`, `locked`, dates and label and milestone ids, and a fork's head names the fork. `workflow_run` has the followed run's attempt, times, actor, head commit, workflow id and URLs. Tests compare each payload's keys and types with trimmed copies of GitHub's documented payloads, and the Actions guide says what differs. OIDC claims keep g1t's ids, so trust policies already written still match.360pub fn changed(repo: &Repo, payload: &mut Value, data: &Value) {
Merge branch 'worktree-agent-a8b78c62188153aa3' into claude/cool-newton-7nm8r9361 if let Some(first) = data["added"].as_array().and_then(|added| added.first()).and_then(Value::as_str) {
362 payload["assignee"] = user(first);
363 }
A workflow's event payload (`github.event` and the file at `GITHUB_EVENT_PATH`) reads as GitHub's webhook payload does. Ids are whole numbers, the same for an object wherever it appears and safe in JavaScript: `repository.id`, `pull_request.id`, `issue.id`, `review.id`, `sender.id` and every user's and owner's `id`, with g1t's own id as `node_id`; `github.repository_id`, `github.repository_owner_id`, `github.actor_id` and their `GITHUB_*` variables are the same numbers. What g1t's API takes back by id (comments, releases, deployments, workflow runs) keeps g1t's id, so `github.event.comment.id` still edits the comment. A repository in a person's own workspace is owned by a `User`, not an `Organization`. A push says whether it was `forced`, `created` or `deleted`, and its `head_commit` is the commit pushed. A pull request's `base.sha` is the tip of the branch it merges into at the event, not the merge base, and `merge_commit_sha` is the commit it landed as once merged; pull requests and issues carry `node_id`, `assignee`, `locked`, dates and label and milestone ids, and a fork's head names the fork. `workflow_run` has the followed run's attempt, times, actor, head commit, workflow id and URLs. Tests compare each payload's keys and types with trimmed copies of GitHub's documented payloads, and the Actions guide says what differs. OIDC claims keep g1t's ids, so trust policies already written still match.364 if let Some(found) = data.get("label").filter(|label| label.is_object()) {
365 payload["label"] = label(repo, found["name"].as_str().unwrap_or_default(), Some(&found["color"]));
Teams and CODEOWNERS, labels and milestones, dependency updates, the security suite, and a clearer top bar366 }
A workflow's event payload (`github.event` and the file at `GITHUB_EVENT_PATH`) reads as GitHub's webhook payload does. Ids are whole numbers, the same for an object wherever it appears and safe in JavaScript: `repository.id`, `pull_request.id`, `issue.id`, `review.id`, `sender.id` and every user's and owner's `id`, with g1t's own id as `node_id`; `github.repository_id`, `github.repository_owner_id`, `github.actor_id` and their `GITHUB_*` variables are the same numbers. What g1t's API takes back by id (comments, releases, deployments, workflow runs) keeps g1t's id, so `github.event.comment.id` still edits the comment. A repository in a person's own workspace is owned by a `User`, not an `Organization`. A push says whether it was `forced`, `created` or `deleted`, and its `head_commit` is the commit pushed. A pull request's `base.sha` is the tip of the branch it merges into at the event, not the merge base, and `merge_commit_sha` is the commit it landed as once merged; pull requests and issues carry `node_id`, `assignee`, `locked`, dates and label and milestone ids, and a fork's head names the fork. `workflow_run` has the followed run's attempt, times, actor, head commit, workflow id and URLs. Tests compare each payload's keys and types with trimmed copies of GitHub's documented payloads, and the Actions guide says what differs. OIDC claims keep g1t's ids, so trust policies already written still match.367 if let Some(found) = data.get("milestone").filter(|milestone| milestone.is_object()) {
368 payload["milestone"] = match found["number"].as_u64() {
369 Some(number) => milestone_of(repo, number as u32, &found["title"]),
370 None => json!({ "number": found["number"], "title": found["title"] }),
371 };
Teams and CODEOWNERS, labels and milestones, dependency updates, the security suite, and a clearer top bar372 }
373}
374
Deploys as code: a manifest of every Worker, a deploy tool that ships only what changed in parallel stages, and a g1t Actions workflow375/// The branch a pull request comes from, or a name for its fork.
376pub fn head_ref(pull: &Pull) -> String {
377 pull.branch.clone().unwrap_or_else(|| format!("pull/{}", pull.number))
378}
379
A workflow's event payload (`github.event` and the file at `GITHUB_EVENT_PATH`) reads as GitHub's webhook payload does. Ids are whole numbers, the same for an object wherever it appears and safe in JavaScript: `repository.id`, `pull_request.id`, `issue.id`, `review.id`, `sender.id` and every user's and owner's `id`, with g1t's own id as `node_id`; `github.repository_id`, `github.repository_owner_id`, `github.actor_id` and their `GITHUB_*` variables are the same numbers. What g1t's API takes back by id (comments, releases, deployments, workflow runs) keeps g1t's id, so `github.event.comment.id` still edits the comment. A repository in a person's own workspace is owned by a `User`, not an `Organization`. A push says whether it was `forced`, `created` or `deleted`, and its `head_commit` is the commit pushed. A pull request's `base.sha` is the tip of the branch it merges into at the event, not the merge base, and `merge_commit_sha` is the commit it landed as once merged; pull requests and issues carry `node_id`, `assignee`, `locked`, dates and label and milestone ids, and a fork's head names the fork. `workflow_run` has the followed run's attempt, times, actor, head commit, workflow id and URLs. Tests compare each payload's keys and types with trimmed copies of GitHub's documented payloads, and the Actions guide says what differs. OIDC claims keep g1t's ids, so trust policies already written still match.380/// A comment. Its `id` is g1t's (`cmt_…`), as the API takes it back to
381/// edit or delete it.
Deploys as code: a manifest of every Worker, a deploy tool that ships only what changed in parallel stages, and a g1t Actions workflow382pub fn comment(repo: &Repo, number: u32, comment: &Comment, on_pull: bool) -> Value {
383 let full_name = format!("{}/{}", repo.namespace, repo.name);
384 let page = if on_pull { "pull" } else { "issues" };
385 json!({
386 "id": comment.id,
A workflow's event payload (`github.event` and the file at `GITHUB_EVENT_PATH`) reads as GitHub's webhook payload does. Ids are whole numbers, the same for an object wherever it appears and safe in JavaScript: `repository.id`, `pull_request.id`, `issue.id`, `review.id`, `sender.id` and every user's and owner's `id`, with g1t's own id as `node_id`; `github.repository_id`, `github.repository_owner_id`, `github.actor_id` and their `GITHUB_*` variables are the same numbers. What g1t's API takes back by id (comments, releases, deployments, workflow runs) keeps g1t's id, so `github.event.comment.id` still edits the comment. A repository in a person's own workspace is owned by a `User`, not an `Organization`. A push says whether it was `forced`, `created` or `deleted`, and its `head_commit` is the commit pushed. A pull request's `base.sha` is the tip of the branch it merges into at the event, not the merge base, and `merge_commit_sha` is the commit it landed as once merged; pull requests and issues carry `node_id`, `assignee`, `locked`, dates and label and milestone ids, and a fork's head names the fork. `workflow_run` has the followed run's attempt, times, actor, head commit, workflow id and URLs. Tests compare each payload's keys and types with trimmed copies of GitHub's documented payloads, and the Actions guide says what differs. OIDC claims keep g1t's ids, so trust policies already written still match.387 "node_id": comment.id,
Deploys as code: a manifest of every Worker, a deploy tool that ships only what changed in parallel stages, and a g1t Actions workflow388 "body": comment.body,
389 "user": person(&comment.author),
390 "created_at": comment.created_at,
A workflow's event payload (`github.event` and the file at `GITHUB_EVENT_PATH`) reads as GitHub's webhook payload does. Ids are whole numbers, the same for an object wherever it appears and safe in JavaScript: `repository.id`, `pull_request.id`, `issue.id`, `review.id`, `sender.id` and every user's and owner's `id`, with g1t's own id as `node_id`; `github.repository_id`, `github.repository_owner_id`, `github.actor_id` and their `GITHUB_*` variables are the same numbers. What g1t's API takes back by id (comments, releases, deployments, workflow runs) keeps g1t's id, so `github.event.comment.id` still edits the comment. A repository in a person's own workspace is owned by a `User`, not an `Organization`. A push says whether it was `forced`, `created` or `deleted`, and its `head_commit` is the commit pushed. A pull request's `base.sha` is the tip of the branch it merges into at the event, not the merge base, and `merge_commit_sha` is the commit it landed as once merged; pull requests and issues carry `node_id`, `assignee`, `locked`, dates and label and milestone ids, and a fork's head names the fork. `workflow_run` has the followed run's attempt, times, actor, head commit, workflow id and URLs. Tests compare each payload's keys and types with trimmed copies of GitHub's documented payloads, and the Actions guide says what differs. OIDC claims keep g1t's ids, so trust policies already written still match.391 "updated_at": comment.edited_at.as_deref().unwrap_or(&comment.created_at),
Deploys as code: a manifest of every Worker, a deploy tool that ships only what changed in parallel stages, and a g1t Actions workflow392 "path": comment.path,
393 "line": comment.line,
394 "html_url": format!("{SITE}/{full_name}/{page}/{number}#{}", comment.id),
A workflow's event payload (`github.event` and the file at `GITHUB_EVENT_PATH`) reads as GitHub's webhook payload does. Ids are whole numbers, the same for an object wherever it appears and safe in JavaScript: `repository.id`, `pull_request.id`, `issue.id`, `review.id`, `sender.id` and every user's and owner's `id`, with g1t's own id as `node_id`; `github.repository_id`, `github.repository_owner_id`, `github.actor_id` and their `GITHUB_*` variables are the same numbers. What g1t's API takes back by id (comments, releases, deployments, workflow runs) keeps g1t's id, so `github.event.comment.id` still edits the comment. A repository in a person's own workspace is owned by a `User`, not an `Organization`. A push says whether it was `forced`, `created` or `deleted`, and its `head_commit` is the commit pushed. A pull request's `base.sha` is the tip of the branch it merges into at the event, not the merge base, and `merge_commit_sha` is the commit it landed as once merged; pull requests and issues carry `node_id`, `assignee`, `locked`, dates and label and milestone ids, and a fork's head names the fork. `workflow_run` has the followed run's attempt, times, actor, head commit, workflow id and URLs. Tests compare each payload's keys and types with trimmed copies of GitHub's documented payloads, and the Actions guide says what differs. OIDC claims keep g1t's ids, so trust policies already written still match.395 "url": format!("{API}/repos/{full_name}/issues/comments/{}", comment.id),
396 "issue_url": format!("{API}/repos/{full_name}/issues/{number}"),
397 })
398}
399
400/// A review, for `pull_request_review`: g1t keeps a review as a comment
401/// with a verdict, and its id is that comment's.
402pub fn review(repo: &Repo, pull: &Pull, review: Option<&Comment>) -> Value {
403 let full_name = format!("{}/{}", repo.namespace, repo.name);
404 let Some(review) = review else {
405 return json!({ "state": null, "body": null, "user": null });
406 };
407 json!({
408 "id": github_id(&review.id),
409 "node_id": review.id,
410 "state": review.verdict.map(review_state),
411 "body": review.body,
412 "user": person(&review.author),
413 "commit_id": pull.head_commit,
414 "submitted_at": review.created_at,
415 "html_url": format!("{SITE}/{full_name}/pull/{}#{}", pull.number, review.id),
416 "pull_request_url": format!("{API}/repos/{full_name}/pulls/{}", pull.number),
Deploys as code: a manifest of every Worker, a deploy tool that ships only what changed in parallel stages, and a g1t Actions workflow417 })
418}
419
420/// An issue as `issue_comment` gives it for a pull request: the pull
A workflow's event payload (`github.event` and the file at `GITHUB_EVENT_PATH`) reads as GitHub's webhook payload does. Ids are whole numbers, the same for an object wherever it appears and safe in JavaScript: `repository.id`, `pull_request.id`, `issue.id`, `review.id`, `sender.id` and every user's and owner's `id`, with g1t's own id as `node_id`; `github.repository_id`, `github.repository_owner_id`, `github.actor_id` and their `GITHUB_*` variables are the same numbers. What g1t's API takes back by id (comments, releases, deployments, workflow runs) keeps g1t's id, so `github.event.comment.id` still edits the comment. A repository in a person's own workspace is owned by a `User`, not an `Organization`. A push says whether it was `forced`, `created` or `deleted`, and its `head_commit` is the commit pushed. A pull request's `base.sha` is the tip of the branch it merges into at the event, not the merge base, and `merge_commit_sha` is the commit it landed as once merged; pull requests and issues carry `node_id`, `assignee`, `locked`, dates and label and milestone ids, and a fork's head names the fork. `workflow_run` has the followed run's attempt, times, actor, head commit, workflow id and URLs. Tests compare each payload's keys and types with trimmed copies of GitHub's documented payloads, and the Actions guide says what differs. OIDC claims keep g1t's ids, so trust policies already written still match.421/// request's number and title, with `pull_request` set. Its id is not the
422/// pull request's, as on GitHub, where the two are different objects.
Teams and CODEOWNERS, labels and milestones, dependency updates, the security suite, and a clearer top bar423pub fn pull_as_issue(repo: &Repo, pull: &Pull) -> Value {
Deploys as code: a manifest of every Worker, a deploy tool that ships only what changed in parallel stages, and a g1t Actions workflow424 let full_name = format!("{}/{}", repo.namespace, repo.name);
425 json!({
A workflow's event payload (`github.event` and the file at `GITHUB_EVENT_PATH`) reads as GitHub's webhook payload does. Ids are whole numbers, the same for an object wherever it appears and safe in JavaScript: `repository.id`, `pull_request.id`, `issue.id`, `review.id`, `sender.id` and every user's and owner's `id`, with g1t's own id as `node_id`; `github.repository_id`, `github.repository_owner_id`, `github.actor_id` and their `GITHUB_*` variables are the same numbers. What g1t's API takes back by id (comments, releases, deployments, workflow runs) keeps g1t's id, so `github.event.comment.id` still edits the comment. A repository in a person's own workspace is owned by a `User`, not an `Organization`. A push says whether it was `forced`, `created` or `deleted`, and its `head_commit` is the commit pushed. A pull request's `base.sha` is the tip of the branch it merges into at the event, not the merge base, and `merge_commit_sha` is the commit it landed as once merged; pull requests and issues carry `node_id`, `assignee`, `locked`, dates and label and milestone ids, and a fork's head names the fork. `workflow_run` has the followed run's attempt, times, actor, head commit, workflow id and URLs. Tests compare each payload's keys and types with trimmed copies of GitHub's documented payloads, and the Actions guide says what differs. OIDC claims keep g1t's ids, so trust policies already written still match.426 "id": github_id(&format!("issue:{}", pull.id)),
427 "node_id": pull.id,
Deploys as code: a manifest of every Worker, a deploy tool that ships only what changed in parallel stages, and a g1t Actions workflow428 "number": pull.number,
429 "title": pull.title,
430 "body": pull.body,
431 "state": if pull.status.is_active() { "open" } else { "closed" },
A workflow's event payload (`github.event` and the file at `GITHUB_EVENT_PATH`) reads as GitHub's webhook payload does. Ids are whole numbers, the same for an object wherever it appears and safe in JavaScript: `repository.id`, `pull_request.id`, `issue.id`, `review.id`, `sender.id` and every user's and owner's `id`, with g1t's own id as `node_id`; `github.repository_id`, `github.repository_owner_id`, `github.actor_id` and their `GITHUB_*` variables are the same numbers. What g1t's API takes back by id (comments, releases, deployments, workflow runs) keeps g1t's id, so `github.event.comment.id` still edits the comment. A repository in a person's own workspace is owned by a `User`, not an `Organization`. A push says whether it was `forced`, `created` or `deleted`, and its `head_commit` is the commit pushed. A pull request's `base.sha` is the tip of the branch it merges into at the event, not the merge base, and `merge_commit_sha` is the commit it landed as once merged; pull requests and issues carry `node_id`, `assignee`, `locked`, dates and label and milestone ids, and a fork's head names the fork. `workflow_run` has the followed run's attempt, times, actor, head commit, workflow id and URLs. Tests compare each payload's keys and types with trimmed copies of GitHub's documented payloads, and the Actions guide says what differs. OIDC claims keep g1t's ids, so trust policies already written still match.432 "locked": false,
433 "draft": pull.status == PullStatus::Draft,
434 "labels": labels(repo, &pull.labels),
435 "milestone": milestone(repo, pull.milestone.as_ref()),
Deploys as code: a manifest of every Worker, a deploy tool that ships only what changed in parallel stages, and a g1t Actions workflow436 "user": person(&pull.author),
g1t is the stored author of what it opens; the person who asked is requested_by and keeps the author's rights437 "requested_by": pull.requested_by.as_ref().map(person),
A workflow's event payload (`github.event` and the file at `GITHUB_EVENT_PATH`) reads as GitHub's webhook payload does. Ids are whole numbers, the same for an object wherever it appears and safe in JavaScript: `repository.id`, `pull_request.id`, `issue.id`, `review.id`, `sender.id` and every user's and owner's `id`, with g1t's own id as `node_id`; `github.repository_id`, `github.repository_owner_id`, `github.actor_id` and their `GITHUB_*` variables are the same numbers. What g1t's API takes back by id (comments, releases, deployments, workflow runs) keeps g1t's id, so `github.event.comment.id` still edits the comment. A repository in a person's own workspace is owned by a `User`, not an `Organization`. A push says whether it was `forced`, `created` or `deleted`, and its `head_commit` is the commit pushed. A pull request's `base.sha` is the tip of the branch it merges into at the event, not the merge base, and `merge_commit_sha` is the commit it landed as once merged; pull requests and issues carry `node_id`, `assignee`, `locked`, dates and label and milestone ids, and a fork's head names the fork. `workflow_run` has the followed run's attempt, times, actor, head commit, workflow id and URLs. Tests compare each payload's keys and types with trimmed copies of GitHub's documented payloads, and the Actions guide says what differs. OIDC claims keep g1t's ids, so trust policies already written still match.438 "assignee": pull.assignees.first().map(|a| user(a)),
439 "assignees": people(&pull.assignees),
440 "created_at": pull.created_at,
441 "updated_at": pull.updated_at,
Deploys as code: a manifest of every Worker, a deploy tool that ships only what changed in parallel stages, and a g1t Actions workflow442 "html_url": format!("{SITE}/{full_name}/pull/{}", pull.number),
A workflow's event payload (`github.event` and the file at `GITHUB_EVENT_PATH`) reads as GitHub's webhook payload does. Ids are whole numbers, the same for an object wherever it appears and safe in JavaScript: `repository.id`, `pull_request.id`, `issue.id`, `review.id`, `sender.id` and every user's and owner's `id`, with g1t's own id as `node_id`; `github.repository_id`, `github.repository_owner_id`, `github.actor_id` and their `GITHUB_*` variables are the same numbers. What g1t's API takes back by id (comments, releases, deployments, workflow runs) keeps g1t's id, so `github.event.comment.id` still edits the comment. A repository in a person's own workspace is owned by a `User`, not an `Organization`. A push says whether it was `forced`, `created` or `deleted`, and its `head_commit` is the commit pushed. A pull request's `base.sha` is the tip of the branch it merges into at the event, not the merge base, and `merge_commit_sha` is the commit it landed as once merged; pull requests and issues carry `node_id`, `assignee`, `locked`, dates and label and milestone ids, and a fork's head names the fork. `workflow_run` has the followed run's attempt, times, actor, head commit, workflow id and URLs. Tests compare each payload's keys and types with trimmed copies of GitHub's documented payloads, and the Actions guide says what differs. OIDC claims keep g1t's ids, so trust policies already written still match.443 "url": format!("{API}/repos/{full_name}/issues/{}", pull.number),
444 "repository_url": format!("{API}/repos/{full_name}"),
Deploys as code: a manifest of every Worker, a deploy tool that ships only what changed in parallel stages, and a g1t Actions workflow445 "pull_request": {
446 "url": format!("{API}/repos/{full_name}/pulls/{}", pull.number),
447 "html_url": format!("{SITE}/{full_name}/pull/{}", pull.number),
448 "merged_at": pull.merged_at,
449 },
450 })
451}
452
Merge Actions: cross-repo workflows and actions, release and deployment triggers, step timeouts453/// A comment as the event that deleted it kept it (`comment.deleted`'s
454/// `comment`), since it can no longer be read.
455pub fn deleted_comment(repo: &Repo, number: u32, kept: &Value, on_pull: bool) -> Value {
456 let full_name = format!("{}/{}", repo.namespace, repo.name);
457 let page = if on_pull { "pull" } else { "issues" };
458 let id = kept["id"].as_str().unwrap_or_default();
459 let login = kept["author"]["username"].as_str().unwrap_or_default();
460 json!({
461 "id": id,
A workflow's event payload (`github.event` and the file at `GITHUB_EVENT_PATH`) reads as GitHub's webhook payload does. Ids are whole numbers, the same for an object wherever it appears and safe in JavaScript: `repository.id`, `pull_request.id`, `issue.id`, `review.id`, `sender.id` and every user's and owner's `id`, with g1t's own id as `node_id`; `github.repository_id`, `github.repository_owner_id`, `github.actor_id` and their `GITHUB_*` variables are the same numbers. What g1t's API takes back by id (comments, releases, deployments, workflow runs) keeps g1t's id, so `github.event.comment.id` still edits the comment. A repository in a person's own workspace is owned by a `User`, not an `Organization`. A push says whether it was `forced`, `created` or `deleted`, and its `head_commit` is the commit pushed. A pull request's `base.sha` is the tip of the branch it merges into at the event, not the merge base, and `merge_commit_sha` is the commit it landed as once merged; pull requests and issues carry `node_id`, `assignee`, `locked`, dates and label and milestone ids, and a fork's head names the fork. `workflow_run` has the followed run's attempt, times, actor, head commit, workflow id and URLs. Tests compare each payload's keys and types with trimmed copies of GitHub's documented payloads, and the Actions guide says what differs. OIDC claims keep g1t's ids, so trust policies already written still match.462 "node_id": id,
Merge Actions: cross-repo workflows and actions, release and deployment triggers, step timeouts463 "body": kept["body"],
464 "user": user(login),
465 "created_at": kept["createdAt"],
A workflow's event payload (`github.event` and the file at `GITHUB_EVENT_PATH`) reads as GitHub's webhook payload does. Ids are whole numbers, the same for an object wherever it appears and safe in JavaScript: `repository.id`, `pull_request.id`, `issue.id`, `review.id`, `sender.id` and every user's and owner's `id`, with g1t's own id as `node_id`; `github.repository_id`, `github.repository_owner_id`, `github.actor_id` and their `GITHUB_*` variables are the same numbers. What g1t's API takes back by id (comments, releases, deployments, workflow runs) keeps g1t's id, so `github.event.comment.id` still edits the comment. A repository in a person's own workspace is owned by a `User`, not an `Organization`. A push says whether it was `forced`, `created` or `deleted`, and its `head_commit` is the commit pushed. A pull request's `base.sha` is the tip of the branch it merges into at the event, not the merge base, and `merge_commit_sha` is the commit it landed as once merged; pull requests and issues carry `node_id`, `assignee`, `locked`, dates and label and milestone ids, and a fork's head names the fork. `workflow_run` has the followed run's attempt, times, actor, head commit, workflow id and URLs. Tests compare each payload's keys and types with trimmed copies of GitHub's documented payloads, and the Actions guide says what differs. OIDC claims keep g1t's ids, so trust policies already written still match.466 "updated_at": kept["editedAt"].as_str().map_or(kept["createdAt"].clone(), |at| json!(at)),
Merge Actions: cross-repo workflows and actions, release and deployment triggers, step timeouts467 "path": kept["path"],
468 "line": kept["line"],
469 "html_url": format!("{SITE}/{full_name}/{page}/{number}#{id}"),
A workflow's event payload (`github.event` and the file at `GITHUB_EVENT_PATH`) reads as GitHub's webhook payload does. Ids are whole numbers, the same for an object wherever it appears and safe in JavaScript: `repository.id`, `pull_request.id`, `issue.id`, `review.id`, `sender.id` and every user's and owner's `id`, with g1t's own id as `node_id`; `github.repository_id`, `github.repository_owner_id`, `github.actor_id` and their `GITHUB_*` variables are the same numbers. What g1t's API takes back by id (comments, releases, deployments, workflow runs) keeps g1t's id, so `github.event.comment.id` still edits the comment. A repository in a person's own workspace is owned by a `User`, not an `Organization`. A push says whether it was `forced`, `created` or `deleted`, and its `head_commit` is the commit pushed. A pull request's `base.sha` is the tip of the branch it merges into at the event, not the merge base, and `merge_commit_sha` is the commit it landed as once merged; pull requests and issues carry `node_id`, `assignee`, `locked`, dates and label and milestone ids, and a fork's head names the fork. `workflow_run` has the followed run's attempt, times, actor, head commit, workflow id and URLs. Tests compare each payload's keys and types with trimmed copies of GitHub's documented payloads, and the Actions guide says what differs. OIDC claims keep g1t's ids, so trust policies already written still match.470 "url": format!("{API}/repos/{full_name}/issues/comments/{id}"),
471 "issue_url": format!("{API}/repos/{full_name}/issues/{number}"),
Merge Actions: cross-repo workflows and actions, release and deployment triggers, step timeouts472 })
473}
474
A workflow's event payload (`github.event` and the file at `GITHUB_EVENT_PATH`) reads as GitHub's webhook payload does. Ids are whole numbers, the same for an object wherever it appears and safe in JavaScript: `repository.id`, `pull_request.id`, `issue.id`, `review.id`, `sender.id` and every user's and owner's `id`, with g1t's own id as `node_id`; `github.repository_id`, `github.repository_owner_id`, `github.actor_id` and their `GITHUB_*` variables are the same numbers. What g1t's API takes back by id (comments, releases, deployments, workflow runs) keeps g1t's id, so `github.event.comment.id` still edits the comment. A repository in a person's own workspace is owned by a `User`, not an `Organization`. A push says whether it was `forced`, `created` or `deleted`, and its `head_commit` is the commit pushed. A pull request's `base.sha` is the tip of the branch it merges into at the event, not the merge base, and `merge_commit_sha` is the commit it landed as once merged; pull requests and issues carry `node_id`, `assignee`, `locked`, dates and label and milestone ids, and a fork's head names the fork. `workflow_run` has the followed run's attempt, times, actor, head commit, workflow id and URLs. Tests compare each payload's keys and types with trimmed copies of GitHub's documented payloads, and the Actions guide says what differs. OIDC claims keep g1t's ids, so trust policies already written still match.475/// What `workflow_run` is told of the run it follows: the
476/// `workflow.completed` event's data, and the run's row when it is still
477/// there. Its `id` and `workflow_id` are g1t's (`run_…`, `wfl_…`), which
478/// `GITHUB_RUN_ID` and the API use too, so `actions/download-artifact`
479/// with `run-id: ${{ github.event.workflow_run.id }}` finds its artifacts.
480pub struct FollowedRun<'a> {
481 pub data: &'a Value,
482 pub workflow_id: Option<&'a str>,
483 pub attempt: Option<u64>,
484 pub created_at: Option<&'a str>,
485 pub started_at: Option<&'a str>,
486 pub updated_at: Option<&'a str>,
487 pub actor: Option<&'a str>,
488 pub triggering_actor: Option<&'a str>,
489 pub title: Option<&'a str>,
490 pub head_commit: Option<&'a Commit>,
Merge branch 'worktree-agent-ab6bf4195fcb97f7c' into claude/cool-newton-7nm8r9491 /// The pull request the run was for (`data.pull`), when it can be
492 /// read, and its base branch's latest commit.
493 pub pull: Option<&'a Pull>,
494 pub base_sha: Option<&'a str>,
A workflow's event payload (`github.event` and the file at `GITHUB_EVENT_PATH`) reads as GitHub's webhook payload does. Ids are whole numbers, the same for an object wherever it appears and safe in JavaScript: `repository.id`, `pull_request.id`, `issue.id`, `review.id`, `sender.id` and every user's and owner's `id`, with g1t's own id as `node_id`; `github.repository_id`, `github.repository_owner_id`, `github.actor_id` and their `GITHUB_*` variables are the same numbers. What g1t's API takes back by id (comments, releases, deployments, workflow runs) keeps g1t's id, so `github.event.comment.id` still edits the comment. A repository in a person's own workspace is owned by a `User`, not an `Organization`. A push says whether it was `forced`, `created` or `deleted`, and its `head_commit` is the commit pushed. A pull request's `base.sha` is the tip of the branch it merges into at the event, not the merge base, and `merge_commit_sha` is the commit it landed as once merged; pull requests and issues carry `node_id`, `assignee`, `locked`, dates and label and milestone ids, and a fork's head names the fork. `workflow_run` has the followed run's attempt, times, actor, head commit, workflow id and URLs. Tests compare each payload's keys and types with trimmed copies of GitHub's documented payloads, and the Actions guide says what differs. OIDC claims keep g1t's ids, so trust policies already written still match.495}
496
Merge branch 'worktree-agent-ab6bf4195fcb97f7c' into claude/cool-newton-7nm8r9497/// The run's pull request as `workflow_run.pull_requests[]` gives it. One
498/// from a fork is left out, as on GitHub, where only pull requests whose
499/// head is in the repository are listed.
500fn run_pulls(repo: &Repo, run: &FollowedRun) -> Vec<Value> {
501 let full_name = format!("{}/{}", repo.namespace, repo.name);
502 let Some(number) = run.data["pull"].as_u64() else { return Vec::new() };
503 let url = format!("{API}/repos/{full_name}/pulls/{number}");
504 let Some(pull) = run.pull else {
505 return vec![json!({ "number": number, "url": url })];
506 };
507 if pull.fork.is_some() {
508 return Vec::new();
509 }
510 let short = json!({ "id": github_id(&repo.id), "url": format!("{API}/repos/{full_name}"), "name": repo.name });
511 vec![json!({
512 "id": github_id(&pull.id),
513 "number": number,
514 "url": url,
515 "head": { "ref": head_ref(pull), "sha": pull.head_commit, "repo": short },
516 "base": {
517 "ref": pull.base_branch(&repo.default_branch),
518 "sha": run.base_sha.map(str::to_owned).or_else(|| pull.merge_base.clone()),
519 "repo": short,
520 },
521 })]
522}
523
A workflow's event payload (`github.event` and the file at `GITHUB_EVENT_PATH`) reads as GitHub's webhook payload does. Ids are whole numbers, the same for an object wherever it appears and safe in JavaScript: `repository.id`, `pull_request.id`, `issue.id`, `review.id`, `sender.id` and every user's and owner's `id`, with g1t's own id as `node_id`; `github.repository_id`, `github.repository_owner_id`, `github.actor_id` and their `GITHUB_*` variables are the same numbers. What g1t's API takes back by id (comments, releases, deployments, workflow runs) keeps g1t's id, so `github.event.comment.id` still edits the comment. A repository in a person's own workspace is owned by a `User`, not an `Organization`. A push says whether it was `forced`, `created` or `deleted`, and its `head_commit` is the commit pushed. A pull request's `base.sha` is the tip of the branch it merges into at the event, not the merge base, and `merge_commit_sha` is the commit it landed as once merged; pull requests and issues carry `node_id`, `assignee`, `locked`, dates and label and milestone ids, and a fork's head names the fork. `workflow_run` has the followed run's attempt, times, actor, head commit, workflow id and URLs. Tests compare each payload's keys and types with trimmed copies of GitHub's documented payloads, and the Actions guide says what differs. OIDC claims keep g1t's ids, so trust policies already written still match.524pub fn workflow_run(repo: &Repo, run: &FollowedRun) -> Value {
525 let full_name = format!("{}/{}", repo.namespace, repo.name);
526 let data = run.data;
527 let id = data["runId"].as_str().unwrap_or_default();
528 let name = data["workflow"].as_str().unwrap_or_default();
529 let head_branch = data["ref"].as_str().unwrap_or_default().trim_start_matches("refs/heads/").to_owned();
530 let url = format!("{API}/repos/{full_name}/actions/runs/{id}");
531 let actor = run.actor.map(user);
532 json!({
533 "id": id,
534 "node_id": id,
535 "name": name,
536 "display_title": run.title.unwrap_or(name),
537 "path": data["path"],
538 "event": data["event"],
539 "status": "completed",
540 "conclusion": data["conclusion"],
541 "workflow_id": run.workflow_id,
542 "head_sha": data["sha"],
543 "head_branch": head_branch,
544 "head_commit": run.head_commit.map(|c| json!({
545 "id": c.hash,
546 "tree_id": c.tree_hash,
547 "message": c.message,
548 "timestamp": c.authored_at,
549 "author": { "name": c.author.name, "email": c.author.email },
550 "committer": { "name": c.author.name, "email": c.author.email },
551 })),
552 "run_number": data["number"],
553 "run_attempt": run.attempt.unwrap_or(1),
554 "created_at": run.created_at,
555 "run_started_at": run.started_at.or(run.created_at),
556 "updated_at": run.updated_at.or(run.created_at),
557 "actor": actor,
558 "triggering_actor": run.triggering_actor.map(user).or_else(|| run.actor.map(user)),
559 "html_url": format!("{SITE}/{full_name}/actions/runs/{id}"),
560 "url": url,
561 "jobs_url": format!("{url}/jobs"),
562 "logs_url": format!("{url}/logs"),
563 "artifacts_url": format!("{url}/artifacts"),
564 "workflow_url": run.workflow_id.map(|w| format!("{API}/repos/{full_name}/actions/workflows/{w}")),
Merge branch 'worktree-agent-ab6bf4195fcb97f7c' into claude/cool-newton-7nm8r9565 "pull_requests": run_pulls(repo, run),
A workflow's event payload (`github.event` and the file at `GITHUB_EVENT_PATH`) reads as GitHub's webhook payload does. Ids are whole numbers, the same for an object wherever it appears and safe in JavaScript: `repository.id`, `pull_request.id`, `issue.id`, `review.id`, `sender.id` and every user's and owner's `id`, with g1t's own id as `node_id`; `github.repository_id`, `github.repository_owner_id`, `github.actor_id` and their `GITHUB_*` variables are the same numbers. What g1t's API takes back by id (comments, releases, deployments, workflow runs) keeps g1t's id, so `github.event.comment.id` still edits the comment. A repository in a person's own workspace is owned by a `User`, not an `Organization`. A push says whether it was `forced`, `created` or `deleted`, and its `head_commit` is the commit pushed. A pull request's `base.sha` is the tip of the branch it merges into at the event, not the merge base, and `merge_commit_sha` is the commit it landed as once merged; pull requests and issues carry `node_id`, `assignee`, `locked`, dates and label and milestone ids, and a fork's head names the fork. `workflow_run` has the followed run's attempt, times, actor, head commit, workflow id and URLs. Tests compare each payload's keys and types with trimmed copies of GitHub's documented payloads, and the Actions guide says what differs. OIDC claims keep g1t's ids, so trust policies already written still match.566 "repository": repository(repo),
567 "head_repository": repository(repo),
568 })
569}
570
Merge Actions: cross-repo workflows and actions, release and deployment triggers, step timeouts571/// A release, from what a `release.*` event carries
A workflow's event payload (`github.event` and the file at `GITHUB_EVENT_PATH`) reads as GitHub's webhook payload does. Ids are whole numbers, the same for an object wherever it appears and safe in JavaScript: `repository.id`, `pull_request.id`, `issue.id`, `review.id`, `sender.id` and every user's and owner's `id`, with g1t's own id as `node_id`; `github.repository_id`, `github.repository_owner_id`, `github.actor_id` and their `GITHUB_*` variables are the same numbers. What g1t's API takes back by id (comments, releases, deployments, workflow runs) keeps g1t's id, so `github.event.comment.id` still edits the comment. A repository in a person's own workspace is owned by a `User`, not an `Organization`. A push says whether it was `forced`, `created` or `deleted`, and its `head_commit` is the commit pushed. A pull request's `base.sha` is the tip of the branch it merges into at the event, not the merge base, and `merge_commit_sha` is the commit it landed as once merged; pull requests and issues carry `node_id`, `assignee`, `locked`, dates and label and milestone ids, and a fork's head names the fork. `workflow_run` has the followed run's attempt, times, actor, head commit, workflow id and URLs. Tests compare each payload's keys and types with trimmed copies of GitHub's documented payloads, and the Actions guide says what differs. OIDC claims keep g1t's ids, so trust policies already written still match.572/// (`g1t_contracts::about::Release`). Its `id` is g1t's, as
573/// `/repos/{owner}/{repo}/releases/{id}` takes it.
Merge Actions: cross-repo workflows and actions, release and deployment triggers, step timeouts574pub fn release(repo: &Repo, release: &Value) -> Value {
575 let full_name = format!("{}/{}", repo.namespace, repo.name);
576 let tag = release["tagName"].as_str().unwrap_or_default();
577 let id = release["id"].as_str().unwrap_or_default();
578 json!({
579 "id": id,
580 "node_id": id,
581 "tag_name": tag,
582 "target_commitish": release["target"],
583 "name": release["name"].as_str().unwrap_or(tag),
584 "body": release["body"],
585 "draft": release["draft"].as_bool().unwrap_or(false),
586 "prerelease": release["prerelease"].as_bool().unwrap_or(false),
587 "created_at": release["createdAt"],
588 "published_at": release["publishedAt"],
589 "author": user(release["author"].as_str().unwrap_or(&repo.namespace)),
590 "assets": [],
591 "html_url": format!("{SITE}/{full_name}/releases/tag/{tag}"),
592 "url": format!("{API}/repos/{full_name}/releases/{id}"),
A workflow's event payload (`github.event` and the file at `GITHUB_EVENT_PATH`) reads as GitHub's webhook payload does. Ids are whole numbers, the same for an object wherever it appears and safe in JavaScript: `repository.id`, `pull_request.id`, `issue.id`, `review.id`, `sender.id` and every user's and owner's `id`, with g1t's own id as `node_id`; `github.repository_id`, `github.repository_owner_id`, `github.actor_id` and their `GITHUB_*` variables are the same numbers. What g1t's API takes back by id (comments, releases, deployments, workflow runs) keeps g1t's id, so `github.event.comment.id` still edits the comment. A repository in a person's own workspace is owned by a `User`, not an `Organization`. A push says whether it was `forced`, `created` or `deleted`, and its `head_commit` is the commit pushed. A pull request's `base.sha` is the tip of the branch it merges into at the event, not the merge base, and `merge_commit_sha` is the commit it landed as once merged; pull requests and issues carry `node_id`, `assignee`, `locked`, dates and label and milestone ids, and a fork's head names the fork. `workflow_run` has the followed run's attempt, times, actor, head commit, workflow id and URLs. Tests compare each payload's keys and types with trimmed copies of GitHub's documented payloads, and the Actions guide says what differs. OIDC claims keep g1t's ids, so trust policies already written still match.593 "zipball_url": format!("{SITE}/{full_name}/archive/{tag}.zip"),
Merge Actions: cross-repo workflows and actions, release and deployment triggers, step timeouts594 })
595}
596
597/// A deployment, from what `deployment.created` and
598/// `deployment_status.created` carry (`RepoDeployment`, already in GitHub's
599/// spelling).
600pub fn deployment(repo: &Repo, deployment: &Value) -> Value {
601 let full_name = format!("{}/{}", repo.namespace, repo.name);
602 let id = deployment["id"].as_str().unwrap_or_default();
603 json!({
604 "id": id,
605 "node_id": id,
606 "sha": deployment["sha"],
607 "ref": deployment["ref"],
608 "task": deployment["task"].as_str().unwrap_or("deploy"),
609 "payload": deployment.get("payload").filter(|p| p.is_object()).cloned().unwrap_or_else(|| json!({})),
610 "environment": deployment["environment"],
611 "original_environment": deployment["environment"],
612 "description": deployment["description"],
613 "creator": user(deployment["creator"].as_str().unwrap_or("g1t")),
614 "transient_environment": deployment["transient_environment"].as_bool().unwrap_or(false),
615 "production_environment": deployment["production_environment"].as_bool().unwrap_or(false),
616 "created_at": deployment["created_at"],
617 "updated_at": deployment["updated_at"],
618 "url": format!("{API}/repos/{full_name}/deployments/{id}"),
619 "statuses_url": format!("{API}/repos/{full_name}/deployments/{id}/statuses"),
620 })
621}
622
623/// A deployment's status (`DeploymentStatus`), for `deployment_status`.
624pub fn deployment_status(repo: &Repo, status: &Value, deployment: &Value) -> Value {
625 let full_name = format!("{}/{}", repo.namespace, repo.name);
626 let deployment_id = deployment["id"].as_str().unwrap_or_default();
627 let id = status["id"].as_str().unwrap_or_default();
628 json!({
629 "id": id,
630 "node_id": id,
631 "state": status["state"],
632 "description": status["description"].as_str().unwrap_or_default(),
633 "environment": deployment["environment"],
634 "environment_url": status["environment_url"].as_str().unwrap_or_default(),
635 "log_url": status["log_url"].as_str().unwrap_or_default(),
636 "target_url": status["log_url"].as_str().unwrap_or_default(),
637 "creator": user(status["creator"].as_str().unwrap_or("g1t")),
638 "created_at": status["created_at"],
639 "updated_at": status["created_at"],
640 "deployment_url": format!("{API}/repos/{full_name}/deployments/{deployment_id}"),
641 "url": format!("{API}/repos/{full_name}/deployments/{deployment_id}/statuses/{id}"),
642 })
643}
644
What runs differently on g1t's machines is said before it surprises anyone, and four things now behave as on GitHub. A commit whose message says `[skip ci]`, `[ci skip]`, `[no ci]`, `[skip actions]` or `[actions skip]`, or ends with `skip-checks: true`, starts no `push` or `pull_request` workflows. A `pull_request_review` event's `review.state` is `approved` or `changes_requested`, not `approve` or `requestchanges`. A self-hosted job that names no `timeout-minutes` runs for 360 minutes, not 60. A JavaScript action's `::debug::` lines show on a debug run, as `run:` steps' do. The workflow's page now warns when a job asks for more than the 60 minutes g1t's machines give it, when an Arm label will run on x64, and when a matrix on a job that calls a reusable workflow will run it once; it no longer says artifacts are kept up to 60 MB (they are kept up to 5 GiB), nor that `setup-node` with `cache:` runs without its cache (the toolkit's cache works). The desktop release's two hosted jobs ask for the 60 minutes they get. The Actions and self-hosted runners guides say so.645
646/// A review's `state` as GitHub's `pull_request_review` event spells it.
647pub(crate) fn review_state(verdict: g1t_contracts::work::Verdict) -> &'static str {
648 match verdict {
649 g1t_contracts::work::Verdict::Approve => "approved",
650 g1t_contracts::work::Verdict::RequestChanges => "changes_requested",
651 }
652}
653
654#[cfg(test)]
655mod review_tests {
656 use super::*;
657
658 #[test]
659 fn review_states_are_spelled_as_githubs() {
660 assert_eq!(review_state(g1t_contracts::work::Verdict::Approve), "approved");
661 assert_eq!(review_state(g1t_contracts::work::Verdict::RequestChanges), "changes_requested");
662 }
663}
A workflow's event payload (`github.event` and the file at `GITHUB_EVENT_PATH`) reads as GitHub's webhook payload does. Ids are whole numbers, the same for an object wherever it appears and safe in JavaScript: `repository.id`, `pull_request.id`, `issue.id`, `review.id`, `sender.id` and every user's and owner's `id`, with g1t's own id as `node_id`; `github.repository_id`, `github.repository_owner_id`, `github.actor_id` and their `GITHUB_*` variables are the same numbers. What g1t's API takes back by id (comments, releases, deployments, workflow runs) keeps g1t's id, so `github.event.comment.id` still edits the comment. A repository in a person's own workspace is owned by a `User`, not an `Organization`. A push says whether it was `forced`, `created` or `deleted`, and its `head_commit` is the commit pushed. A pull request's `base.sha` is the tip of the branch it merges into at the event, not the merge base, and `merge_commit_sha` is the commit it landed as once merged; pull requests and issues carry `node_id`, `assignee`, `locked`, dates and label and milestone ids, and a fork's head names the fork. `workflow_run` has the followed run's attempt, times, actor, head commit, workflow id and URLs. Tests compare each payload's keys and types with trimmed copies of GitHub's documented payloads, and the Actions guide says what differs. OIDC claims keep g1t's ids, so trust policies already written still match.664
665/// g1t's payloads against GitHub's: each fixture in `tests/fixtures` is a
666/// trimmed webhook payload in GitHub's documented shape, and every key it
667/// has must be in g1t's payload for the same event with the same JSON type
668/// (a whole number where GitHub's is one). `null` in a fixture takes any
669/// type. Where g1t differs on purpose, `KNOWN` says how and why.
670#[cfg(test)]
671mod github_shapes {
672 use super::*;
673 use g1t_contracts::work::Verdict;
674
675 /// Paths where g1t's payload differs from GitHub's on purpose, and
676 /// what g1t has there: a JSON type, or `absent`.
677 const KNOWN: &[(&str, &str, &str)] = &[
678 // The API addresses these by g1t's own id, so the payload gives
679 // that id, to be passed straight back.
680 ("issue_comment", "comment.id", "string"),
681 ("release", "release.id", "string"),
682 ("workflow_run", "workflow_run.id", "string"),
683 ("workflow_run", "workflow_run.workflow_id", "string"),
684 ("workflow_run", "workflow.id", "string"),
685 ];
686
687 fn kind(value: &Value) -> &'static str {
688 match value {
689 Value::Null => "null",
690 Value::Bool(_) => "boolean",
691 Value::Number(_) => "number",
692 Value::String(_) => "string",
693 Value::Array(_) => "array",
694 Value::Object(_) => "object",
695 }
696 }
697
698 fn compare(event: &str, github: &Value, ours: Option<&Value>, path: &str, problems: &mut Vec<String>) {
699 if let Some((_, _, known)) = KNOWN.iter().find(|(e, p, _)| *e == event && *p == path) {
700 let had = ours.map_or("absent", kind);
701 if had != *known {
702 problems.push(format!("{path}: g1t is known to have {known} here, but has {had}"));
703 }
704 return;
705 }
706 let Some(ours) = ours else {
707 problems.push(format!("{path}: missing"));
708 return;
709 };
710 if github.is_null() {
711 return;
712 }
713 if kind(github) != kind(ours) {
714 problems.push(format!("{path}: GitHub's is {}, g1t's {}", kind(github), kind(ours)));
715 return;
716 }
717 match github {
718 Value::Number(n) if n.is_u64() => {
719 if !ours.as_u64().is_some_and(|n| n < 1 << 53) {
720 problems.push(format!("{path}: GitHub's is a whole number, g1t's {ours}"));
721 }
722 }
723 Value::Object(map) => {
724 for (key, inner) in map {
725 let at = if path.is_empty() { key.clone() } else { format!("{path}.{key}") };
726 compare(event, inner, ours.get(key), &at, problems);
727 }
728 }
729 Value::Array(items) => {
730 if let (Some(first), Some(our_first)) = (items.first(), ours.as_array().and_then(|o| o.first())) {
731 compare(event, first, Some(our_first), &format!("{path}[]"), problems);
732 }
733 }
734 _ => {}
735 }
736 }
737
738 fn repo() -> Repo {
739 serde_json::from_value(json!({
740 "id": "rep_01kpw0aaaaaaaaaaaaaaaaaaaa", "namespace": "acme", "name": "web", "description": null, "isPrivate": false,
741 "ownerId": "wsp_1", "defaultBranch": "main", "forkOf": null, "createdAt": "2026-05-15T15:19:25Z"
742 }))
743 .unwrap()
744 }
745
746 fn someone(id: &str, username: &str) -> User {
747 User { id: id.into(), username: username.into(), kind: PrincipalKind::User, ..User::default() }
748 }
749
750 fn a_pull() -> Pull {
751 serde_json::from_value(json!({
752 "id": "pr_01kq000000000000000000000a", "repoId": "rep_1", "number": 2, "issue": null,
753 "title": "Update the README with new information.", "body": "A simple change.",
754 "agent": "", "runtime": "external", "status": "open",
755 "fork": null, "forkRepoId": null, "branch": "changes",
756 "headCommit": "ec26c3e57ca3a959ca5aad62de7213c562f8c821", "mergeBase": "f95f852bd8fca8fcc58a9a2d6c842781e32a215e",
757 "mergedBy": null, "mergedAt": null, "supersededBy": null, "checkStatus": null,
758 "files": [{ "path": "README.md", "additions": 1, "deletions": 1 }],
759 "assignees": ["bo"], "reviewers": ["cy"], "labels": ["bug"], "milestone": { "number": 1, "title": "v1.0" },
760 "author": someone("usr_1", "ada"), "requestedBy": null,
761 "createdAt": "2026-05-15T15:20:33Z", "updatedAt": "2026-05-15T15:20:33Z"
762 }))
763 .unwrap()
764 }
765
766 fn an_issue() -> Issue {
767 serde_json::from_value(json!({
768 "id": "iss_01kq000000000000000000000a", "repoId": "rep_1", "number": 1,
769 "title": "Spelling error in the README file", "body": "Two t's.", "labels": ["bug"], "state": "open",
770 "reason": null, "resolvedBy": null, "author": someone("usr_1", "ada"), "requestedBy": null,
771 "createdAt": "2026-05-15T15:20:18Z", "updatedAt": "2026-05-15T15:20:18Z", "closedAt": null,
772 "pullCount": 0, "commentCount": 0, "assignees": ["bo"], "milestone": { "number": 1, "title": "v1.0" }
773 }))
774 .unwrap()
775 }
776
777 fn a_comment(verdict: Option<Verdict>) -> Comment {
778 serde_json::from_value(json!({
779 "id": "cmt_01kq000000000000000000000a", "author": someone("usr_3", "cy"), "body": "Looks good.",
780 "path": null, "line": null, "verdict": verdict, "createdAt": "2026-05-15T15:20:38Z"
781 }))
782 .unwrap()
783 }
784
785 fn a_commit() -> Commit {
786 serde_json::from_value(json!({
787 "hash": "0d1a26e67d8f5eaf1f6ba5c57fc3c7d91ac0fd1c", "treeHash": "f9d2a07e9488b91af2641b26b9407fe22a451433",
788 "message": "Update README.md", "author": { "name": "Ada", "email": "ada@example.com" },
789 "parents": ["6113728f27ae82c7b1a177c8d03f9e96e0adf246"], "authoredAt": "2026-05-15T15:20:30Z"
790 }))
791 .unwrap()
792 }
793
794 /// g1t's payload for each event, put together as trigger.rs does.
795 fn payloads() -> Vec<(&'static str, Value)> {
796 let repo = repo();
797 let pull = a_pull();
Merge branch 'worktree-agent-ab6bf4195fcb97f7c' into claude/cool-newton-7nm8r9798 let mut push = push(&repo, "refs/heads/main", Some("6113728f27ae82c7b1a177c8d03f9e96e0adf246"), &a_commit().hash, &[a_commit()], "ada", Some("0d0efg+ada@users.noreply.g1t.sh"), false);
799 push_changes(&mut push, &[("README.md".into(), FileStatus::Modified)]);
800 let known = [Label { name: "bug".into(), color: "d73a4a".into(), description: "Something isn't working".into(), issues: 1, pulls: 1 }];
801 let mut pull_request = json!({
A workflow's event payload (`github.event` and the file at `GITHUB_EVENT_PATH`) reads as GitHub's webhook payload does. Ids are whole numbers, the same for an object wherever it appears and safe in JavaScript: `repository.id`, `pull_request.id`, `issue.id`, `review.id`, `sender.id` and every user's and owner's `id`, with g1t's own id as `node_id`; `github.repository_id`, `github.repository_owner_id`, `github.actor_id` and their `GITHUB_*` variables are the same numbers. What g1t's API takes back by id (comments, releases, deployments, workflow runs) keeps g1t's id, so `github.event.comment.id` still edits the comment. A repository in a person's own workspace is owned by a `User`, not an `Organization`. A push says whether it was `forced`, `created` or `deleted`, and its `head_commit` is the commit pushed. A pull request's `base.sha` is the tip of the branch it merges into at the event, not the merge base, and `merge_commit_sha` is the commit it landed as once merged; pull requests and issues carry `node_id`, `assignee`, `locked`, dates and label and milestone ids, and a fork's head names the fork. `workflow_run` has the followed run's attempt, times, actor, head commit, workflow id and URLs. Tests compare each payload's keys and types with trimmed copies of GitHub's documented payloads, and the Actions guide says what differs. OIDC claims keep g1t's ids, so trust policies already written still match.802 "action": "opened", "number": 2, "pull_request": self::pull(&repo, &pull),
803 "repository": repository(&repo), "sender": user("ada"),
804 });
Merge branch 'worktree-agent-ab6bf4195fcb97f7c' into claude/cool-newton-7nm8r9805 color_labels(&mut pull_request, &known);
A workflow's event payload (`github.event` and the file at `GITHUB_EVENT_PATH`) reads as GitHub's webhook payload does. Ids are whole numbers, the same for an object wherever it appears and safe in JavaScript: `repository.id`, `pull_request.id`, `issue.id`, `review.id`, `sender.id` and every user's and owner's `id`, with g1t's own id as `node_id`; `github.repository_id`, `github.repository_owner_id`, `github.actor_id` and their `GITHUB_*` variables are the same numbers. What g1t's API takes back by id (comments, releases, deployments, workflow runs) keeps g1t's id, so `github.event.comment.id` still edits the comment. A repository in a person's own workspace is owned by a `User`, not an `Organization`. A push says whether it was `forced`, `created` or `deleted`, and its `head_commit` is the commit pushed. A pull request's `base.sha` is the tip of the branch it merges into at the event, not the merge base, and `merge_commit_sha` is the commit it landed as once merged; pull requests and issues carry `node_id`, `assignee`, `locked`, dates and label and milestone ids, and a fork's head names the fork. `workflow_run` has the followed run's attempt, times, actor, head commit, workflow id and URLs. Tests compare each payload's keys and types with trimmed copies of GitHub's documented payloads, and the Actions guide says what differs. OIDC claims keep g1t's ids, so trust policies already written still match.806 let review = json!({
807 "action": "submitted", "review": self::review(&repo, &pull, Some(&a_comment(Some(Verdict::Approve)))),
808 "pull_request": self::pull(&repo, &pull), "repository": repository(&repo), "sender": user("cy"),
809 });
810 let mut issues = json!({ "action": "labeled", "issue": issue(&repo, &an_issue()), "repository": repository(&repo), "sender": user("ada") });
811 changed(&repo, &mut issues, &json!({ "label": { "name": "bug", "color": "d73a4a" } }));
Merge branch 'worktree-agent-ab6bf4195fcb97f7c' into claude/cool-newton-7nm8r9812 color_labels(&mut issues, &known);
A workflow's event payload (`github.event` and the file at `GITHUB_EVENT_PATH`) reads as GitHub's webhook payload does. Ids are whole numbers, the same for an object wherever it appears and safe in JavaScript: `repository.id`, `pull_request.id`, `issue.id`, `review.id`, `sender.id` and every user's and owner's `id`, with g1t's own id as `node_id`; `github.repository_id`, `github.repository_owner_id`, `github.actor_id` and their `GITHUB_*` variables are the same numbers. What g1t's API takes back by id (comments, releases, deployments, workflow runs) keeps g1t's id, so `github.event.comment.id` still edits the comment. A repository in a person's own workspace is owned by a `User`, not an `Organization`. A push says whether it was `forced`, `created` or `deleted`, and its `head_commit` is the commit pushed. A pull request's `base.sha` is the tip of the branch it merges into at the event, not the merge base, and `merge_commit_sha` is the commit it landed as once merged; pull requests and issues carry `node_id`, `assignee`, `locked`, dates and label and milestone ids, and a fork's head names the fork. `workflow_run` has the followed run's attempt, times, actor, head commit, workflow id and URLs. Tests compare each payload's keys and types with trimmed copies of GitHub's documented payloads, and the Actions guide says what differs. OIDC claims keep g1t's ids, so trust policies already written still match.813 let mut on_pull = pull.clone();
814 on_pull.labels.clear();
815 on_pull.assignees.clear();
816 on_pull.milestone = None;
817 let mut comment = a_comment(None);
818 comment.author = someone("usr_1", "ada");
819 let issue_comment = json!({
820 "action": "created", "issue": pull_as_issue(&repo, &on_pull), "comment": self::comment(&repo, 2, &comment, true),
821 "repository": repository(&repo), "sender": user("ada"),
822 });
823 let data = json!({
824 "runId": "run_01kq000000000000000000000a", "workflow": "Build", "path": ".g1t/workflows/build.yml", "number": 562,
825 "event": "push", "conclusion": "success", "ref": "refs/heads/main", "sha": "acb5820ced9479c074f688cc328bf03f341a511d", "pull": 2,
826 });
827 let head = Commit { hash: "acb5820ced9479c074f688cc328bf03f341a511d".into(), ..a_commit() };
828 let followed = FollowedRun {
829 data: &data,
830 workflow_id: Some("wfl_1"),
831 attempt: Some(1),
832 created_at: Some("2026-05-15T15:20:35Z"),
833 started_at: Some("2026-05-15T15:20:35Z"),
834 updated_at: Some("2026-05-15T15:21:10Z"),
835 actor: Some("ada"),
836 triggering_actor: None,
837 title: Some("Update README.md"),
838 head_commit: Some(&head),
Merge branch 'worktree-agent-ab6bf4195fcb97f7c' into claude/cool-newton-7nm8r9839 pull: Some(&pull),
840 base_sha: Some("f95f852bd8fca8fcc58a9a2d6c842781e32a215e"),
A workflow's event payload (`github.event` and the file at `GITHUB_EVENT_PATH`) reads as GitHub's webhook payload does. Ids are whole numbers, the same for an object wherever it appears and safe in JavaScript: `repository.id`, `pull_request.id`, `issue.id`, `review.id`, `sender.id` and every user's and owner's `id`, with g1t's own id as `node_id`; `github.repository_id`, `github.repository_owner_id`, `github.actor_id` and their `GITHUB_*` variables are the same numbers. What g1t's API takes back by id (comments, releases, deployments, workflow runs) keeps g1t's id, so `github.event.comment.id` still edits the comment. A repository in a person's own workspace is owned by a `User`, not an `Organization`. A push says whether it was `forced`, `created` or `deleted`, and its `head_commit` is the commit pushed. A pull request's `base.sha` is the tip of the branch it merges into at the event, not the merge base, and `merge_commit_sha` is the commit it landed as once merged; pull requests and issues carry `node_id`, `assignee`, `locked`, dates and label and milestone ids, and a fork's head names the fork. `workflow_run` has the followed run's attempt, times, actor, head commit, workflow id and URLs. Tests compare each payload's keys and types with trimmed copies of GitHub's documented payloads, and the Actions guide says what differs. OIDC claims keep g1t's ids, so trust policies already written still match.841 };
842 // As trigger.rs gives it.
843 let workflow_run = json!({
844 "action": "completed",
845 "workflow_run": self::workflow_run(&repo, &followed),
846 "workflow": { "id": "wfl_1", "node_id": "wfl_1", "name": "Build", "path": data["path"], "state": "active", "html_url": "https://g1t.sh/acme/web/actions" },
847 "repository": repository(&repo),
848 "sender": user("ada"),
849 });
850 let release = json!({
851 "action": "published",
852 "release": self::release(&repo, &json!({ "id": "rel_1", "tagName": "v1.2.0", "target": "main", "name": "v1.2.0", "body": "Notes",
853 "draft": false, "prerelease": false, "author": "ada", "createdAt": "2026-05-15T15:19:53Z", "publishedAt": "2026-05-15T15:20:05Z" })),
854 "repository": repository(&repo),
855 "sender": user("ada"),
856 });
857 vec![
858 ("push", push),
859 ("pull_request", pull_request),
860 ("pull_request_review", review),
861 ("issues", issues),
862 ("issue_comment", issue_comment),
863 ("workflow_run", workflow_run),
864 ("release", release),
865 ]
866 }
867
868 fn fixture(event: &str) -> Value {
869 let text = match event {
870 "push" => include_str!("../tests/fixtures/push.json"),
871 "pull_request" => include_str!("../tests/fixtures/pull_request.json"),
872 "pull_request_review" => include_str!("../tests/fixtures/pull_request_review.json"),
873 "issues" => include_str!("../tests/fixtures/issues.json"),
874 "issue_comment" => include_str!("../tests/fixtures/issue_comment.json"),
875 "workflow_run" => include_str!("../tests/fixtures/workflow_run.json"),
876 "release" => include_str!("../tests/fixtures/release.json"),
877 other => panic!("no fixture for {other}"),
878 };
879 serde_json::from_str(text).unwrap()
880 }
881
882 #[test]
883 fn payloads_have_githubs_keys_and_types() {
884 let mut problems = Vec::new();
885 for (event, ours) in payloads() {
886 let mut found = Vec::new();
887 compare(event, &fixture(event), Some(&ours), "", &mut found);
888 problems.extend(found.into_iter().map(|problem| format!("{event}: {problem}")));
889 }
890 assert!(problems.is_empty(), "g1t's payloads differ from GitHub's:\n{}", problems.join("\n"));
891 }
892
893 #[test]
894 fn the_comparison_finds_what_differs() {
895 let mut found = Vec::new();
896 let github = json!({ "id": 1, "user": { "login": "a" }, "labels": [{ "name": "x" }], "body": null });
897 compare("x", &github, Some(&json!({ "id": "pr_1", "labels": [{}], "body": 3 })), "", &mut found);
898 assert_eq!(found, ["id: GitHub's is number, g1t's string", "user: missing", "labels[].name: missing"]);
899 found.clear();
900 compare("x", &json!({ "id": 1 }), Some(&json!({ "id": 1.5 })), "", &mut found);
901 assert_eq!(found, ["id: GitHub's is a whole number, g1t's 1.5"]);
902 }
903
904 #[test]
905 fn the_same_object_has_the_same_number_everywhere() {
906 let all = payloads();
907 let by = |event: &str| all.iter().find(|(e, _)| *e == event).map(|(_, v)| v.clone()).unwrap();
908 let (pr, issues, run) = (by("pull_request"), by("issues"), by("workflow_run"));
909 let repo_id = &pr["repository"]["id"];
910 assert_eq!(repo_id, &json!(github_id(&repo().id)), "github.repository_id is the same number");
911 assert_eq!(&pr["pull_request"]["base"]["repo"]["id"], repo_id);
912 assert_eq!(&run["workflow_run"]["repository"]["id"], repo_id);
913 // ada as sender, author and run actor; acme as owner and head user.
914 assert_eq!(pr["sender"]["id"], pr["pull_request"]["user"]["id"]);
915 assert_eq!(pr["sender"]["id"], run["workflow_run"]["actor"]["id"]);
916 assert_eq!(pr["sender"]["id"], json!(account_id("ada")), "github.actor_id is the same number");
917 assert_eq!(pr["repository"]["owner"]["id"], pr["pull_request"]["head"]["user"]["id"]);
918 assert_eq!(pr["repository"]["owner"]["id"], json!(account_id("acme")));
919 assert_eq!(pr["pull_request"]["labels"][0]["id"], issues["label"]["id"]);
920 // A pull request's own id and its issue's are different objects.
921 assert_ne!(pull_as_issue(&repo(), &a_pull())["id"], pr["pull_request"]["id"]);
922 assert_eq!(pr["pull_request"]["node_id"], a_pull().id);
923 }
924
925 #[test]
926 fn a_personal_workspaces_repositories_are_a_users() {
927 let mut event = json!({ "pull_request": pull(&repo(), &a_pull()), "repository": repository(&repo()), "sender": user("ada") });
928 assert_eq!(event["repository"]["owner"]["type"], "Organization");
929 owned_by_person(&mut event, "Acme");
930 assert_eq!(event["repository"]["owner"]["type"], "User");
931 assert_eq!(event["pull_request"]["base"]["repo"]["owner"]["type"], "User");
932 assert_eq!(event["pull_request"]["head"]["user"]["type"], "User");
933 // Nobody else changes, a bot least of all.
934 assert_eq!(event["sender"]["type"], "User");
935 let mut bot = json!({ "user": { "login": "acme", "type": "Bot" } });
936 owned_by_person(&mut bot, "acme");
937 assert_eq!(bot["user"]["type"], "Bot");
938 }
939
940 #[test]
941 fn a_push_says_whether_it_made_deleted_or_forced_its_ref() {
942 let repo = repo();
943 let after = "0d1a26e67d8f5eaf1f6ba5c57fc3c7d91ac0fd1c";
Merge branch 'worktree-agent-ab6bf4195fcb97f7c' into claude/cool-newton-7nm8r9944 let made = push(&repo, "refs/heads/new", None, after, &[a_commit()], "ada", None, false);
A workflow's event payload (`github.event` and the file at `GITHUB_EVENT_PATH`) reads as GitHub's webhook payload does. Ids are whole numbers, the same for an object wherever it appears and safe in JavaScript: `repository.id`, `pull_request.id`, `issue.id`, `review.id`, `sender.id` and every user's and owner's `id`, with g1t's own id as `node_id`; `github.repository_id`, `github.repository_owner_id`, `github.actor_id` and their `GITHUB_*` variables are the same numbers. What g1t's API takes back by id (comments, releases, deployments, workflow runs) keeps g1t's id, so `github.event.comment.id` still edits the comment. A repository in a person's own workspace is owned by a `User`, not an `Organization`. A push says whether it was `forced`, `created` or `deleted`, and its `head_commit` is the commit pushed. A pull request's `base.sha` is the tip of the branch it merges into at the event, not the merge base, and `merge_commit_sha` is the commit it landed as once merged; pull requests and issues carry `node_id`, `assignee`, `locked`, dates and label and milestone ids, and a fork's head names the fork. `workflow_run` has the followed run's attempt, times, actor, head commit, workflow id and URLs. Tests compare each payload's keys and types with trimmed copies of GitHub's documented payloads, and the Actions guide says what differs. OIDC claims keep g1t's ids, so trust policies already written still match.945 assert_eq!((made["created"].clone(), made["deleted"].clone(), made["forced"].clone()), (json!(true), json!(false), json!(false)));
946 assert_eq!(made["before"], ZERO);
Merge branch 'worktree-agent-ab6bf4195fcb97f7c' into claude/cool-newton-7nm8r9947 let forced = push(&repo, "refs/heads/main", Some("6113728f27ae82c7b1a177c8d03f9e96e0adf246"), after, &[a_commit()], "ada", None, true);
A workflow's event payload (`github.event` and the file at `GITHUB_EVENT_PATH`) reads as GitHub's webhook payload does. Ids are whole numbers, the same for an object wherever it appears and safe in JavaScript: `repository.id`, `pull_request.id`, `issue.id`, `review.id`, `sender.id` and every user's and owner's `id`, with g1t's own id as `node_id`; `github.repository_id`, `github.repository_owner_id`, `github.actor_id` and their `GITHUB_*` variables are the same numbers. What g1t's API takes back by id (comments, releases, deployments, workflow runs) keeps g1t's id, so `github.event.comment.id` still edits the comment. A repository in a person's own workspace is owned by a `User`, not an `Organization`. A push says whether it was `forced`, `created` or `deleted`, and its `head_commit` is the commit pushed. A pull request's `base.sha` is the tip of the branch it merges into at the event, not the merge base, and `merge_commit_sha` is the commit it landed as once merged; pull requests and issues carry `node_id`, `assignee`, `locked`, dates and label and milestone ids, and a fork's head names the fork. `workflow_run` has the followed run's attempt, times, actor, head commit, workflow id and URLs. Tests compare each payload's keys and types with trimmed copies of GitHub's documented payloads, and the Actions guide says what differs. OIDC claims keep g1t's ids, so trust policies already written still match.948 assert_eq!(forced["forced"], true);
949 assert_eq!(forced["compare"], format!("https://g1t.sh/acme/web/compare/6113728f27ae82c7b1a177c8d03f9e96e0adf246...{after}"));
950 assert_eq!(forced["head_commit"]["id"], after);
Merge branch 'worktree-agent-ab6bf4195fcb97f7c' into claude/cool-newton-7nm8r9951 let gone = push(&repo, "refs/heads/old", Some("6113728f27ae82c7b1a177c8d03f9e96e0adf246"), ZERO, &[], "ada", None, true);
A workflow's event payload (`github.event` and the file at `GITHUB_EVENT_PATH`) reads as GitHub's webhook payload does. Ids are whole numbers, the same for an object wherever it appears and safe in JavaScript: `repository.id`, `pull_request.id`, `issue.id`, `review.id`, `sender.id` and every user's and owner's `id`, with g1t's own id as `node_id`; `github.repository_id`, `github.repository_owner_id`, `github.actor_id` and their `GITHUB_*` variables are the same numbers. What g1t's API takes back by id (comments, releases, deployments, workflow runs) keeps g1t's id, so `github.event.comment.id` still edits the comment. A repository in a person's own workspace is owned by a `User`, not an `Organization`. A push says whether it was `forced`, `created` or `deleted`, and its `head_commit` is the commit pushed. A pull request's `base.sha` is the tip of the branch it merges into at the event, not the merge base, and `merge_commit_sha` is the commit it landed as once merged; pull requests and issues carry `node_id`, `assignee`, `locked`, dates and label and milestone ids, and a fork's head names the fork. `workflow_run` has the followed run's attempt, times, actor, head commit, workflow id and URLs. Tests compare each payload's keys and types with trimmed copies of GitHub's documented payloads, and the Actions guide says what differs. OIDC claims keep g1t's ids, so trust policies already written still match.952 assert_eq!((gone["deleted"].clone(), gone["forced"].clone()), (json!(true), json!(false)));
953 }
954
955 #[test]
Merge branch 'worktree-agent-ab6bf4195fcb97f7c' into claude/cool-newton-7nm8r9956 fn a_one_commit_push_lists_what_it_changed() {
957 let repo = repo();
958 let changes = [
959 ("new.txt".to_owned(), FileStatus::Added),
960 ("README.md".to_owned(), FileStatus::Modified),
961 ("old.txt".to_owned(), FileStatus::Deleted),
962 ];
963 let mut one = push(&repo, "refs/heads/main", None, &a_commit().hash, &[a_commit()], "ada", None, false);
964 push_changes(&mut one, &changes);
965 for commit in [&one["commits"][0], &one["head_commit"]] {
966 assert_eq!(commit["added"], json!(["new.txt"]));
967 assert_eq!(commit["modified"], json!(["README.md"]));
968 assert_eq!(commit["removed"], json!(["old.txt"]));
969 }
970 // Several commits: the comparison is not any one commit's.
971 let mut two = push(&repo, "refs/heads/main", None, &a_commit().hash, &[a_commit(), a_commit()], "ada", None, false);
972 push_changes(&mut two, &changes);
973 assert_eq!(two["head_commit"]["modified"], json!([]));
974 }
975
976 #[test]
977 fn labels_have_the_repositorys_colors() {
978 let repo = repo();
979 let mut event = json!({ "issue": issue(&repo, &an_issue()), "label": label(&repo, "bug", None) });
980 // Before the repository's are known, g1t's default for the name.
981 assert_eq!(event["issue"]["labels"][0]["color"], "d73a4a");
982 assert_eq!(event["issue"]["labels"][0]["default"], true);
983 assert!(has_labels(&event));
984 let known = [Label { name: "bug".into(), color: "123456".into(), description: String::new(), issues: 1, pulls: 0 }];
985 color_labels(&mut event, &known);
986 assert_eq!(event["issue"]["labels"][0]["color"], "123456");
987 assert_eq!(event["issue"]["labels"][0]["description"], Value::Null);
988 assert_eq!(event["label"]["color"], "123456");
989 assert!(!has_labels(&json!({ "issue": { "labels": [] } })));
990 }
991
992 #[test]
993 fn a_run_names_its_pull_request_unless_it_is_from_a_fork() {
994 let repo = repo();
995 let data = json!({ "runId": "run_1", "pull": 2 });
996 let pull = a_pull();
997 let run = |pull: Option<&Pull>| {
998 workflow_run(&repo, &FollowedRun {
999 data: &data, workflow_id: None, attempt: None, created_at: None, started_at: None, updated_at: None,
1000 actor: None, triggering_actor: None, title: None, head_commit: None, pull, base_sha: Some("b4se"),
1001 })
1002 };
1003 let named = run(Some(&pull));
1004 let first = &named["pull_requests"][0];
1005 assert_eq!(first["number"], 2);
1006 assert_eq!(first["id"], json!(github_id(&pull.id)));
1007 assert_eq!(first["head"]["ref"], "changes");
1008 assert_eq!(first["head"]["sha"], "ec26c3e57ca3a959ca5aad62de7213c562f8c821");
1009 assert_eq!(first["base"]["ref"], "main");
1010 assert_eq!(first["base"]["sha"], "b4se");
1011 assert_eq!(first["base"]["repo"]["id"], json!(github_id(&repo.id)));
1012 let mut forked = a_pull();
1013 forked.fork = Some(RepoPath { namespace: "ana".into(), name: "web".into() });
1014 assert_eq!(run(Some(&forked))["pull_requests"], json!([]));
1015 assert_eq!(run(None)["pull_requests"][0]["number"], 2, "unread, still numbered");
1016 }
1017
1018 #[test]
A workflow's event payload (`github.event` and the file at `GITHUB_EVENT_PATH`) reads as GitHub's webhook payload does. Ids are whole numbers, the same for an object wherever it appears and safe in JavaScript: `repository.id`, `pull_request.id`, `issue.id`, `review.id`, `sender.id` and every user's and owner's `id`, with g1t's own id as `node_id`; `github.repository_id`, `github.repository_owner_id`, `github.actor_id` and their `GITHUB_*` variables are the same numbers. What g1t's API takes back by id (comments, releases, deployments, workflow runs) keeps g1t's id, so `github.event.comment.id` still edits the comment. A repository in a person's own workspace is owned by a `User`, not an `Organization`. A push says whether it was `forced`, `created` or `deleted`, and its `head_commit` is the commit pushed. A pull request's `base.sha` is the tip of the branch it merges into at the event, not the merge base, and `merge_commit_sha` is the commit it landed as once merged; pull requests and issues carry `node_id`, `assignee`, `locked`, dates and label and milestone ids, and a fork's head names the fork. `workflow_run` has the followed run's attempt, times, actor, head commit, workflow id and URLs. Tests compare each payload's keys and types with trimmed copies of GitHub's documented payloads, and the Actions guide says what differs. OIDC claims keep g1t's ids, so trust policies already written still match.1019 fn a_pull_request_from_a_fork_names_the_fork() {
1020 let mut pull = a_pull();
1021 pull.fork = Some(RepoPath { namespace: "ana".into(), name: "web".into() });
1022 pull.fork_repo_id = Some("rep_f".into());
1023 pull.branch = None;
1024 let event = self::pull(&repo(), &pull);
1025 assert_eq!(event["head"]["repo"]["full_name"], "ana/web");
1026 assert_eq!(event["head"]["repo"]["fork"], true);
1027 assert_eq!(event["head"]["repo"]["id"], json!(github_id("rep_f")));
1028 assert_eq!(event["head"]["label"], "ana:pull/2");
1029 assert_eq!(event["head"]["user"]["login"], "ana");
1030 assert_eq!(event["merge_commit_sha"], Value::Null, "only once merged");
1031 }
1032}

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