g1t/packages/contracts/src/repos.ts

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