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 workflow | 1 | //! `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 workflow | 12 | |
| 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. | 13 | use 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 rights | 14 | use 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. | 15 | use g1t_contracts::repos::{Commit, Repo, RepoPath}; |
| Merge branch 'worktree-agent-ab6bf4195fcb97f7c' into claude/cool-newton-7nm8r9 | 16 | use g1t_contracts::repos::FileStatus; |
| 17 | use 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 workflow | 18 | use serde_json::{Value, json}; |
| 19 | ||
| 20 | use 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. |
| 23 | pub 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`]. | |
| 28 | fn 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 workflow | 38 | pub 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 workflow | 42 | "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 workflow | 47 | "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 workflow | 53 | "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 workflow | 57 | "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. |
| 62 | fn 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. | |
| 79 | pub 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 workflow | 94 | pub 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 workflow | 102 | } |
| 103 | ||
| g1t is the stored author of what it opens; the person who asked is requested_by and keeps the author's rights | 104 | /// 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 workflow | 106 | fn 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 rights | 107 | 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 rights | 109 | 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 workflow | 113 | } |
| 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. | 115 | fn people(logins: &[String]) -> Vec<Value> { |
| 116 | logins.iter().map(|login| user(login)).collect() | |
| 117 | } | |
| 118 | ||
| 119 | fn 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-7nm8r9 | 123 | /// 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. | 126 | fn label(repo: &Repo, name: &str, color: Option<&Value>) -> Value { |
| Merge branch 'worktree-agent-ab6bf4195fcb97f7c' into claude/cool-newton-7nm8r9 | 127 | 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`). | |
| 139 | pub 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. | |
| 157 | pub 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 workflow | 166 | } |
| 167 | ||
| Teams and CODEOWNERS, labels and milestones, dependency updates, the security suite, and a clearer top bar | 168 | /// 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. | 169 | fn milestone(repo: &Repo, milestone: Option<&MilestoneRef>) -> Value { |
| 170 | milestone.map_or(Value::Null, |milestone| milestone_of(repo, milestone.number, &json!(milestone.title))) | |
| 171 | } | |
| 172 | ||
| 173 | fn 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 bar | 180 | } |
| 181 | ||
| Deploys as code: a manifest of every Worker, a deploy tool that ships only what changed in parallel stages, and a g1t Actions workflow | 182 | pub 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 workflow | 195 | }) |
| 196 | } | |
| 197 | ||
| Merge branch 'worktree-agent-ab6bf4195fcb97f7c' into claude/cool-newton-7nm8r9 | 198 | /// 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. | |
| 202 | pub 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-7nm8r9 | 219 | /// `pusher_email` is the pusher's noreply address, when the push was a |
| 220 | /// person's. | |
| 221 | #[allow(clippy::too_many_arguments)] | |
| 222 | pub 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 workflow | 235 | 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 workflow | 242 | 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 workflow | 245 | "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 workflow | 249 | "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 workflow | 253 | "commits": commits, |
| Merge branch 'worktree-agent-ab6bf4195fcb97f7c' into claude/cool-newton-7nm8r9 | 254 | "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 workflow | 255 | "repository": repository(repo), |
| 256 | "sender": user(pusher), | |
| 257 | }) | |
| 258 | } | |
| 259 | ||
| 260 | pub 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 workflow | 265 | "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 workflow | 273 | "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 rights | 274 | // 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 workflow | 278 | "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 workflow | 285 | }) |
| 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 bar | 291 | pub 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 workflow | 292 | 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 bar | 294 | 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 workflow | 298 | }; |
| 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 workflow | 305 | 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 workflow | 308 | "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 workflow | 313 | "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 workflow | 315 | "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 workflow | 322 | "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 rights | 323 | // 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 workflow | 328 | "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 workflow | 333 | "repo": head_repo, |
| 334 | }, | |
| 335 | "base": { | |
| Teams and CODEOWNERS, labels and milestones, dependency updates, the security suite, and a clearer top bar | 336 | "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 workflow | 337 | "sha": pull.merge_base, |
| Teams and CODEOWNERS, labels and milestones, dependency updates, the security suite, and a clearer top bar | 338 | "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 workflow | 340 | "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 workflow | 348 | "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 workflow | 351 | }) |
| 352 | } | |
| 353 | ||
| Merge branch 'worktree-agent-a8b78c62188153aa3' into claude/cool-newton-7nm8r9 | 354 | /// 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. | 360 | pub fn changed(repo: &Repo, payload: &mut Value, data: &Value) { |
| Merge branch 'worktree-agent-a8b78c62188153aa3' into claude/cool-newton-7nm8r9 | 361 | 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 bar | 366 | } |
| 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 bar | 372 | } |
| 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 workflow | 375 | /// The branch a pull request comes from, or a name for its fork. |
| 376 | pub 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 workflow | 382 | pub 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 workflow | 388 | "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 workflow | 392 | "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. | |
| 402 | pub 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 workflow | 417 | }) |
| 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 bar | 423 | pub 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 workflow | 424 | 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 workflow | 428 | "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 workflow | 436 | "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 rights | 437 | "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 workflow | 442 | "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 workflow | 445 | "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 timeouts | 453 | /// A comment as the event that deleted it kept it (`comment.deleted`'s |
| 454 | /// `comment`), since it can no longer be read. | |
| 455 | pub 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 timeouts | 463 | "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 timeouts | 467 | "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 timeouts | 472 | }) |
| 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. | |
| 480 | pub 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-7nm8r9 | 491 | /// 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-7nm8r9 | 497 | /// 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. | |
| 500 | fn 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. | 524 | pub 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-7nm8r9 | 565 | "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 timeouts | 571 | /// 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 timeouts | 574 | pub 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 timeouts | 594 | }) |
| 595 | } | |
| 596 | ||
| 597 | /// A deployment, from what `deployment.created` and | |
| 598 | /// `deployment_status.created` carry (`RepoDeployment`, already in GitHub's | |
| 599 | /// spelling). | |
| 600 | pub 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`. | |
| 624 | pub 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. | |
| 647 | pub(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)] | |
| 655 | mod 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)] | |
| 671 | mod 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-7nm8r9 | 798 | 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-7nm8r9 | 805 | 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-7nm8r9 | 812 | 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-7nm8r9 | 839 | 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-7nm8r9 | 944 | 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-7nm8r9 | 947 | 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-7nm8r9 | 951 | 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-7nm8r9 | 956 | 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.