Blog/Models/GitRepositories.cs 6.4 K · 163 lines · raw · history

1 namespace Blog.Models;
2
3 /// <summary>
4 /// A name, an address and a time — git's author and committer lines, flattened out of libgit2's
5 /// handles so a page can still read them after the repository has been closed.
6 /// </summary>
7 public sealed record GitSignature(string Name, string Email, DateTimeOffset When);
8
9 /// <summary>One repository under the repository root, as the index lists it.</summary>
10 /// <param name="Name">The directory name, which is also the route segment: <c>blog.git</c>.</param>
11 /// <param name="DisplayName">The same without the suffix, for headings: <c>blog</c>.</param>
12 /// <param name="Description">
13 /// The <c>description</c> file, unless it still holds the placeholder <c>git init</c> writes.
14 /// </param>
15 /// <param name="Owner"><c>gitweb.owner</c> from the repository config, which is what cgit reads.</param>
16 /// <param name="Head">The branch HEAD points at, or null when it is unborn.</param>
17 /// <param name="Tip">The commit on that branch, and when it landed.</param>
18 public sealed record GitRepoSummary(
19 string Name,
20 string DisplayName,
21 string? Description,
22 string? Owner,
23 string? Head,
24 GitCommitInfo? Tip);
25
26 /// <summary>A commit, with everything a page shows about it.</summary>
27 /// <param name="Refs">
28 /// The branch and tag names whose tips are this commit. Filled in on the log, where the badges
29 /// mark where each branch has got to; empty everywhere else.
30 /// </param>
31 public sealed record GitCommitInfo(
32 string Sha,
33 string Summary,
34 string Body,
35 GitSignature Author,
36 GitSignature Committer,
37 IReadOnlyList<string> Parents,
38 IReadOnlyList<string> Refs)
39 {
40 /// <summary>Enough of the hash to be unambiguous, and short enough to sit in a table.</summary>
41 public string ShortSha => Sha.Length >= 10 ? Sha[..10] : Sha;
42
43 /// <summary>A commit with two or more parents is diffed against the first, as git does.</summary>
44 public bool IsMerge => Parents.Count > 1;
45 }
46
47 /// <summary>A page of history, and whether there is another one behind it.</summary>
48 public sealed record GitLogPage(IReadOnlyList<GitCommitInfo> Commits, bool HasMore);
49
50 /// <summary>What a tree entry is, as far as the listing cares.</summary>
51 public enum GitEntryKind
52 {
53 Directory,
54 File,
55
56 /// <summary>Mode 100755. Worth marking: it is the difference between a script and a text file.</summary>
57 Executable,
58
59 Symlink,
60
61 /// <summary>Another repository, pinned at a commit. There is nothing here to browse into.</summary>
62 Submodule
63 }
64
65 /// <param name="Path">Full path from the repository root, which is what the tree links carry.</param>
66 public sealed record GitTreeEntry(string Name, string Path, GitEntryKind Kind, long Size, string Sha);
67
68 /// <param name="IsBinary">
69 /// Decided the way git decides it: a NUL byte anywhere in the first few kilobytes. Binary blobs
70 /// are linked to the raw endpoint instead of being printed.
71 /// </param>
72 /// <param name="Text">
73 /// The file, newlines normalised to <c>\n</c> and the final one removed, or null when there is
74 /// nothing to print. Whole rather than split into lines: the highlighter needs the whole of it to
75 /// see that a block comment or a fenced code block carries on past the end of a line.
76 /// </param>
77 public sealed record GitBlob(
78 string Path,
79 string Sha,
80 long Size,
81 bool IsBinary,
82 bool TooLarge,
83 string? Text);
84
85 /// <summary>
86 /// One path in one revision: a directory listing, or a file. Which of the two is set says which
87 /// the path turned out to be.
88 /// </summary>
89 /// <param name="Reference">The revision as it was asked for, for links that stay on this branch.</param>
90 public sealed record GitPathView(
91 GitCommitInfo Commit,
92 string Reference,
93 string Path,
94 IReadOnlyList<GitTreeEntry>? Entries,
95 GitBlob? Blob);
96
97 public enum GitChange
98 {
99 Added,
100 Deleted,
101 Modified,
102 Renamed,
103 Copied,
104 TypeChanged
105 }
106
107 /// <param name="Origin">
108 /// <c>' '</c> context, <c>'+'</c> added, <c>'-'</c> removed, <c>'\'</c> for git's
109 /// "No newline at end of file" note.
110 /// </param>
111 public sealed record GitDiffLine(char Origin, int? OldNumber, int? NewNumber, string Text);
112
113 /// <param name="Header">The <c>@@ -a,b +c,d @@</c> line, section heading and all.</param>
114 public sealed record GitDiffHunk(string Header, IReadOnlyList<GitDiffLine> Lines);
115
116 /// <param name="Hunks">Empty for a binary file, and for one dropped to keep the page finite.</param>
117 public sealed record GitDiffFile(
118 string Path,
119 string? OldPath,
120 GitChange Change,
121 int Added,
122 int Deleted,
123 bool IsBinary,
124 bool Skipped,
125 IReadOnlyList<GitDiffHunk> Hunks);
126
127 /// <param name="Truncated">
128 /// Set when the diff ran past the line budget and the rest of the files kept their stats but lost
129 /// their hunks. A commit that vendors a 4 MB file should not render 4 MB of green.
130 /// </param>
131 public sealed record GitDiff(IReadOnlyList<GitDiffFile> Files, int Added, int Deleted, bool Truncated);
132
133 /// <summary>
134 /// One file's bytes at one revision, for the raw endpoint. <paramref name="IsBinary"/> decides
135 /// whether it is handed over as text or as a download.
136 /// </summary>
137 public sealed record GitRawBlob(byte[] Bytes, bool IsBinary, string Name);
138
139 /// <summary>
140 /// What the index found under the repository root, and why it found nothing when it found nothing.
141 /// </summary>
142 /// <remarks>
143 /// A failure is a value here, as it is for the drop tables and for the rvrb node. An unreadable
144 /// root is a deployment problem, and the page that says which deployment problem is worth more
145 /// than a stack trace: "there are no repositories" and "this process cannot read them" look
146 /// identical from the outside and are fixed in completely different places.
147 /// </remarks>
148 public sealed record GitIndexView(IReadOnlyList<GitRepoSummary> Repositories, string? Error);
149
150 /// <summary>A commit and the diff that goes with it — everything the commit page renders.</summary>
151 public sealed record GitCommitView(GitCommitInfo Commit, GitDiff Diff);
152
153 /// <summary>A branch or a tag, with the commit it points at.</summary>
154 /// <param name="Message">An annotated tag's own message. Null for branches and lightweight tags.</param>
155 public sealed record GitRef(
156 string Name,
157 bool IsTag,
158 string Sha,
159 GitCommitInfo? Tip,
160 string? Message);
161
162 /// <summary>Every ref in a repository, branches and tags kept apart as the refs page shows them.</summary>
163 public sealed record GitRefsView(IReadOnlyList<GitRef> Branches, IReadOnlyList<GitRef> Tags);