g1t/packages/contracts/src/repos.ts

133 lines4,078 bytesCodeBlame
1import type { User, Viewer } from "./identity";
2import type { Result } from "./result";
3
4export type Repo = {
5 id: string;
6 /** The owning user's (later, workspace's) name: the first URL segment. */
7 namespace: string;
8 name: string;
9 description: string | null;
10 isPrivate: boolean;
11 ownerId: string;
12 defaultBranch: string;
13 /** Set when this repo is an attempt's working copy of another repo. */
14 forkOf: string | null;
15 createdAt: number;
16};
17
18export type RepoPath = { namespace: string; name: string };
19
20export type Commit = {
21 hash: string;
22 treeHash: string;
23 message: string;
24 author: { name: string; email: string };
25 parents: string[];
26 authoredAt: number;
27};
28
29export type TreeEntry = {
30 name: string;
31 hash: string;
32 kind: "tree" | "blob" | "symlink" | "gitlink" | "exec";
33};
34
35export type TreeView = {
36 repo: Repo;
37 ref: string;
38 path: string;
39 /** Null when the repo has no commits yet. */
40 head: Commit | null;
41 entries: TreeEntry[];
42 readme: { name: string; text: string | null } | null;
43};
44
45export type BlobView = {
46 repo: Repo;
47 ref: string;
48 path: string;
49 size: number;
50 /** Null when the file is binary or too large to show. */
51 text: string | null;
52};
53
54/** A git remote and a short-lived credential for it. */
55export type GitAccess = { remote: string; token: string };
56
57export type GitService = "git-upload-pack" | "git-receive-pack";
58
59export type CreateRepoInput = {
60 name: string;
61 description?: string | null;
62 isPrivate?: boolean;
63};
64
65/** Repositories: metadata, contents and git access. */
66export interface ReposApi {
67 get(path: RepoPath, viewer: Viewer): Promise<Result<Repo>>;
68 getById(id: string, viewer: Viewer): Promise<Result<Repo>>;
69 /** Repos the viewer may see, newest first, optionally matching `query`. */
70 list(viewer: Viewer, options?: { query?: string; namespace?: string }): Promise<Repo[]>;
71 create(owner: User, input: CreateRepoInput): Promise<Result<Repo>>;
72
73 tree(path: RepoPath, viewer: Viewer, ref: string | null, treePath: string): Promise<Result<TreeView>>;
74 blob(path: RepoPath, viewer: Viewer, ref: string, filePath: string): Promise<Result<BlobView>>;
75 log(path: RepoPath, viewer: Viewer, ref: string | null, limit: number): Promise<Result<Commit[]>>;
76
77 /**
78 * A copy-on-write copy of `source`, hidden from listings, for one attempt
79 * to work in.
80 */
81 forkForAttempt(sourceId: string, attemptId: string, actor: User): Promise<Result<Repo>>;
82
83 /**
84 * Authorizes a git operation and returns where to send it. Pushing to a
85 * repo that does not exist creates it in the pusher's own namespace.
86 */
87 gitAccess(path: RepoPath, viewer: Viewer, service: GitService): Promise<Result<GitAccess>>;
88
89 /**
90 * Moves the default branch of the repo a fork came from to the fork's
91 * head. Refused with "conflict" when the fork is behind, since that would
92 * discard commits.
93 */
94 land(forkId: string, actor: User): Promise<Result<{ commit: string; previous: string | null }>>;
95
96 /**
97 * What a repository's head changes. An attempt's fork is compared with the
98 * last commit it shares with the repository it came from, unless `base`
99 * says otherwise.
100 */
101 compare(repoId: string, viewer: Viewer, base?: string | null): Promise<Result<Comparison>>;
102}
103
104export type DiffLine = {
105 kind: "context" | "add" | "delete";
106 /** Line number in the old file; null for added lines. */
107 old: number | null;
108 /** Line number in the new file; null for deleted lines. */
109 new: number | null;
110 text: string;
111};
112
113/** A run of changed lines with their surrounding context. */
114export type Hunk = { lines: DiffLine[] };
115
116export type FileDiff = {
117 path: string;
118 status: "added" | "modified" | "deleted";
119 additions: number;
120 deletions: number;
121 /** True when the file is binary or too large, so no lines are shown. */
122 binary: boolean;
123 hunks: Hunk[];
124};
125
126/** What changed between two commits. */
127export type Comparison = {
128 base: string | null;
129 head: string;
130 files: FileDiff[];
131 /** True when the change was too large to return in full. */
132 truncated: boolean;
133};