flagon-io/g1t

public

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

g1t/crates/contracts/src/repos.rs

432 lines12,956 bytesCodeBlame
1//! The repos service: repository metadata, contents, forks and git access.
2//!
3//! Each `*Args` struct is the argument of the method of the same name,
4//! served at `POST /rpc/<method>`.
5
6use serde::{Deserialize, Serialize};
7
8use crate::{User, Viewer};
9
10#[derive(Clone, Debug, Serialize, Deserialize)]
11#[serde(rename_all = "camelCase")]
12pub struct Repo {
13 pub id: String,
14 /// The slug of the workspace that owns it: the first URL segment.
15 pub namespace: String,
16 pub name: String,
17 pub description: Option<String>,
18 pub is_private: bool,
19 pub owner_id: String,
20 pub default_branch: String,
21 /// Set when this repo is a pull request's working copy of another repo.
22 pub fork_of: Option<String>,
23 /// Whether the default branch is protected: it changes only by merging
24 /// a pull request, and pushes to it are refused.
25 #[serde(default)]
26 pub protected: bool,
27 /// RFC 3339.
28 pub created_at: String,
29}
30
31#[derive(Clone, Debug, Serialize, Deserialize)]
32pub struct RepoPath {
33 pub namespace: String,
34 pub name: String,
35}
36
37#[derive(Clone, Debug, Serialize, Deserialize)]
38pub struct Signature {
39 pub name: String,
40 pub email: String,
41}
42
43#[derive(Clone, Debug, Serialize, Deserialize)]
44#[serde(rename_all = "camelCase")]
45pub struct Commit {
46 pub hash: String,
47 pub tree_hash: String,
48 pub message: String,
49 pub author: Signature,
50 pub parents: Vec<String>,
51 /// RFC 3339.
52 pub authored_at: String,
53}
54
55#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
56#[serde(rename_all = "lowercase")]
57pub enum EntryKind {
58 Tree,
59 Blob,
60 Symlink,
61 Gitlink,
62 Exec,
63}
64
65#[derive(Clone, Debug, Serialize, Deserialize)]
66pub struct TreeEntry {
67 pub name: String,
68 pub hash: String,
69 pub kind: EntryKind,
70}
71
72#[derive(Clone, Debug, Serialize, Deserialize)]
73pub struct Readme {
74 pub name: String,
75 /// Null when the file is binary or too large to show.
76 pub text: Option<String>,
77}
78
79#[derive(Clone, Debug, Serialize, Deserialize)]
80pub struct TreeView {
81 pub repo: Repo,
82 #[serde(rename = "ref")]
83 pub git_ref: String,
84 pub path: String,
85 /// Null when the repo has no commits yet.
86 pub head: Option<Commit>,
87 pub entries: Vec<TreeEntry>,
88 pub readme: Option<Readme>,
89}
90
91#[derive(Clone, Debug, Serialize, Deserialize)]
92pub struct BlobView {
93 pub repo: Repo,
94 #[serde(rename = "ref")]
95 pub git_ref: String,
96 pub path: String,
97 pub size: u64,
98 /// Null when the file is binary or too large to show.
99 pub text: Option<String>,
100}
101
102/// A git remote and a short-lived credential for it.
103#[derive(Clone, Debug, Serialize, Deserialize)]
104pub struct GitAccess {
105 pub remote: String,
106 pub token: String,
107}
108
109#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
110pub enum GitService {
111 #[serde(rename = "git-upload-pack")]
112 UploadPack,
113 #[serde(rename = "git-receive-pack")]
114 ReceivePack,
115}
116
117/// The result of landing a pull request.
118#[derive(Clone, Debug, Serialize, Deserialize)]
119pub struct Landed {
120 /// The commit the branch points to now.
121 pub commit: String,
122 /// The commit it pointed to before, if it had one. Comparing against
123 /// this shows what the pull request changed.
124 pub previous: Option<String>,
125}
126
127/// `get`. Returns `Outcome<Repo>`.
128#[derive(Debug, Serialize, Deserialize)]
129pub struct GetArgs {
130 pub path: RepoPath,
131 pub viewer: Viewer,
132}
133
134/// `path_by_id`: where a repository is, whoever may see it. For g1t's own
135/// services, which hold a repository's id from an event and act for its
136/// workspace; nothing outside reaches it. Returns `Option<RepoPath>`, null
137/// for a fork or an unknown id.
138#[derive(Debug, Serialize, Deserialize)]
139pub struct PathByIdArgs {
140 pub id: String,
141}
142
143/// `get_by_id`. Returns `Outcome<Repo>`.
144#[derive(Debug, Serialize, Deserialize)]
145pub struct GetByIdArgs {
146 pub id: String,
147 pub viewer: Viewer,
148}
149
150/// `list`: repos the viewer may see, newest first. Returns `Vec<Repo>`.
151#[derive(Debug, Default, Serialize, Deserialize)]
152#[serde(rename_all = "camelCase")]
153pub struct ListArgs {
154 pub viewer: Viewer,
155 #[serde(default)]
156 pub query: Option<String>,
157 /// Only repos in this workspace.
158 #[serde(default)]
159 pub namespace: Option<String>,
160 /// Only repos in workspaces the viewer belongs to.
161 #[serde(default)]
162 pub member_only: bool,
163}
164
165/// `create`. Returns `Outcome<Repo>`.
166#[derive(Debug, Serialize, Deserialize)]
167#[serde(rename_all = "camelCase")]
168pub struct CreateArgs {
169 /// Who is creating it; they must belong to the workspace.
170 pub owner: User,
171 /// The workspace it is created in.
172 pub namespace: String,
173 pub name: String,
174 #[serde(default)]
175 pub description: Option<String>,
176 #[serde(default)]
177 pub is_private: bool,
178 /// The https address of a public git repository to copy the default
179 /// branch of, such as `https://github.com/owner/repo`.
180 #[serde(default)]
181 pub import_url: Option<String>,
182}
183
184/// `update`: changes whichever of a repository's details are given.
185/// Members of its workspace only. Returns `Outcome<Repo>`.
186#[derive(Debug, Serialize, Deserialize)]
187#[serde(rename_all = "camelCase")]
188pub struct UpdateArgs {
189 pub actor: User,
190 pub path: RepoPath,
191 /// An empty description clears it.
192 #[serde(default)]
193 pub description: Option<String>,
194 #[serde(default)]
195 pub is_private: Option<bool>,
196 #[serde(default)]
197 pub protected: Option<bool>,
198}
199
200/// `tree`. Returns `Outcome<TreeView>`.
201#[derive(Debug, Serialize, Deserialize)]
202#[serde(rename_all = "camelCase")]
203pub struct TreeArgs {
204 pub path: RepoPath,
205 pub viewer: Viewer,
206 /// The default branch when absent.
207 #[serde(default, rename = "ref")]
208 pub git_ref: Option<String>,
209 #[serde(default)]
210 pub tree_path: String,
211}
212
213/// `blob`. Returns `Outcome<BlobView>`.
214#[derive(Debug, Serialize, Deserialize)]
215#[serde(rename_all = "camelCase")]
216pub struct BlobArgs {
217 pub path: RepoPath,
218 pub viewer: Viewer,
219 #[serde(rename = "ref")]
220 pub git_ref: String,
221 pub file_path: String,
222}
223
224/// `log`. Returns `Outcome<Vec<Commit>>`.
225#[derive(Debug, Serialize, Deserialize)]
226pub struct LogArgs {
227 pub path: RepoPath,
228 pub viewer: Viewer,
229 #[serde(default, rename = "ref")]
230 pub git_ref: Option<String>,
231 pub limit: u32,
232}
233
234/// `fork_for_pull`: a copy-on-write copy of the source repo, hidden from
235/// listings, for one pull request to be made in. Returns `Outcome<Repo>`.
236#[derive(Debug, Serialize, Deserialize)]
237#[serde(rename_all = "camelCase")]
238pub struct ForkArgs {
239 pub source_id: String,
240 pub pull_id: String,
241 pub actor: User,
242}
243
244/// `git_access`: authorizes a git operation and says where to send it.
245/// Pushing to a repo that does not exist creates it in the pusher's own
246/// namespace. Returns `Outcome<GitAccess>`.
247#[derive(Debug, Serialize, Deserialize)]
248pub struct GitAccessArgs {
249 pub path: RepoPath,
250 pub viewer: Viewer,
251 pub service: GitService,
252}
253
254/// `land`: moves a repository's default branch to the head of a pull
255/// request's source. Refused with `conflict` when the source is behind,
256/// since that would discard commits. Returns `Outcome<Landed>`.
257#[derive(Debug, Serialize, Deserialize)]
258#[serde(rename_all = "camelCase")]
259pub struct LandArgs {
260 /// The repository holding the commits: a pull request's fork, or the
261 /// target itself when landing one of its own branches.
262 pub source_id: String,
263 /// The branch of the source to land. Required when the source is the
264 /// target; a fork lands its default branch.
265 #[serde(default)]
266 pub branch: Option<String>,
267 pub actor: User,
268}
269
270#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
271#[serde(rename_all = "lowercase")]
272pub enum FileStatus {
273 Added,
274 Modified,
275 Deleted,
276}
277
278#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
279#[serde(rename_all = "lowercase")]
280pub enum LineKind {
281 /// Unchanged, shown for context.
282 Context,
283 Add,
284 Delete,
285}
286
287#[derive(Clone, Debug, Serialize, Deserialize)]
288pub struct DiffLine {
289 pub kind: LineKind,
290 /// Line number in the old file; absent for added lines.
291 pub old: Option<u32>,
292 /// Line number in the new file; absent for deleted lines.
293 pub new: Option<u32>,
294 pub text: String,
295}
296
297/// A run of changed lines with their surrounding context.
298#[derive(Clone, Debug, Serialize, Deserialize)]
299pub struct Hunk {
300 pub lines: Vec<DiffLine>,
301}
302
303#[derive(Clone, Debug, Serialize, Deserialize)]
304pub struct FileDiff {
305 pub path: String,
306 pub status: FileStatus,
307 pub additions: u32,
308 pub deletions: u32,
309 /// True when the file is binary or too large, so no lines are shown.
310 pub binary: bool,
311 pub hunks: Vec<Hunk>,
312}
313
314/// What changed between two commits.
315#[derive(Clone, Debug, Serialize, Deserialize)]
316pub struct Comparison {
317 /// Null when the head has no earlier commit to compare against.
318 pub base: Option<String>,
319 pub head: String,
320 pub files: Vec<FileDiff>,
321 /// True when the change was too large to return in full.
322 pub truncated: bool,
323}
324
325/// `compare`: what `head` changes relative to `base`.
326///
327/// `head` is a branch or a commit, and defaults to the default branch.
328/// With no `base`, a fork is compared against the point where it and the
329/// repository it came from last agreed; a branch against the point where it
330/// left the default branch; and the default branch against its head's
331/// parent. Returns `Outcome<Comparison>`.
332#[derive(Debug, Serialize, Deserialize)]
333#[serde(rename_all = "camelCase")]
334pub struct CompareArgs {
335 pub repo_id: String,
336 pub viewer: Viewer,
337 #[serde(default)]
338 pub base: Option<String>,
339 #[serde(default)]
340 pub head: Option<String>,
341}
342
343/// Lines `start` to `end` of a file, inclusive and counted from 1, last
344/// changed by `commit`.
345#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
346pub struct BlameRange {
347 pub start: u32,
348 pub end: u32,
349 pub commit: String,
350}
351
352/// Who last changed each line of a file.
353#[derive(Clone, Debug, Serialize, Deserialize)]
354pub struct Blame {
355 /// The commit the file was read at.
356 pub head: String,
357 /// Every line, in order, in runs that share a commit.
358 pub ranges: Vec<BlameRange>,
359 /// The commits the ranges name, each once.
360 pub commits: Vec<Commit>,
361 /// True when the history was too long to read in full, so the oldest
362 /// lines are given to the oldest commit read.
363 pub partial: bool,
364}
365
366/// `blame`: who last changed each line of `path` as of `ref` (the default
367/// branch if absent). Returns `Outcome<Blame>`; not found when the file is
368/// missing or is not text.
369#[derive(Debug, Serialize, Deserialize)]
370pub struct BlameArgs {
371 pub path: RepoPath,
372 pub viewer: Viewer,
373 #[serde(default, rename = "ref")]
374 pub git_ref: Option<String>,
375 #[serde(rename = "filePath")]
376 pub file_path: String,
377}
378
379/// A branch and the commit it points to.
380#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
381pub struct Branch {
382 pub name: String,
383 pub hash: String,
384}
385
386/// `branches`: the repository's branches, default branch first.
387/// Returns `Outcome<Vec<Branch>>`.
388#[derive(Debug, Serialize, Deserialize)]
389pub struct BranchesArgs {
390 pub path: RepoPath,
391 pub viewer: Viewer,
392}
393
394/// `behind`: whether the default branch of the repository a pull request
395/// would merge into has commits its source does not. For services that
396/// have already decided the caller may see the pull request; it reveals
397/// one bit. Returns `bool`.
398#[derive(Debug, Serialize, Deserialize)]
399#[serde(rename_all = "camelCase")]
400pub struct BehindArgs {
401 /// The pull request's fork, or the repository itself for a branch.
402 pub source_id: String,
403 /// The branch of the source. A fork is compared on its default branch.
404 #[serde(default)]
405 pub branch: Option<String>,
406}
407
408/// `head`: the commit a branch points to, or null. For services reacting
409/// to a push, which have no viewer; it reveals nothing but a commit hash.
410/// Returns `Option<String>`.
411#[derive(Debug, Serialize, Deserialize)]
412#[serde(rename_all = "camelCase")]
413pub struct HeadArgs {
414 pub repo_id: String,
415 /// Empty for the repository's default branch.
416 pub branch: String,
417}
418
419/// Where g1t keeps branches of its own in a repository, such as the merge
420/// queue's tested states. Only these can be removed with `delete_branch`.
421pub const G1T_BRANCH_PREFIX: &str = "g1t-";
422
423/// `delete_branch`: removes a branch g1t made for itself once it is done
424/// with it, never one of people's: the name must start with
425/// [`G1T_BRANCH_PREFIX`]. For services, which have no viewer. Returns
426/// `Outcome<bool>`: whether there was such a branch.
427#[derive(Debug, Serialize, Deserialize)]
428#[serde(rename_all = "camelCase")]
429pub struct DeleteBranchArgs {
430 pub repo_id: String,
431 pub branch: String,
432}