| 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 | |
| 6 | use serde::{Deserialize, Serialize}; |
| 7 | |
| 8 | use crate::{User, Viewer}; |
| 9 | |
| 10 | #[derive(Clone, Debug, Serialize, Deserialize)] |
| 11 | #[serde(rename_all = "camelCase")] |
| 12 | pub 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 | /// RFC 3339. |
| 24 | pub created_at: String, |
| 25 | } |
| 26 | |
| 27 | #[derive(Clone, Debug, Serialize, Deserialize)] |
| 28 | pub struct RepoPath { |
| 29 | pub namespace: String, |
| 30 | pub name: String, |
| 31 | } |
| 32 | |
| 33 | #[derive(Clone, Debug, Serialize, Deserialize)] |
| 34 | pub struct Signature { |
| 35 | pub name: String, |
| 36 | pub email: String, |
| 37 | } |
| 38 | |
| 39 | #[derive(Clone, Debug, Serialize, Deserialize)] |
| 40 | #[serde(rename_all = "camelCase")] |
| 41 | pub struct Commit { |
| 42 | pub hash: String, |
| 43 | pub tree_hash: String, |
| 44 | pub message: String, |
| 45 | pub author: Signature, |
| 46 | pub parents: Vec<String>, |
| 47 | /// RFC 3339. |
| 48 | pub authored_at: String, |
| 49 | } |
| 50 | |
| 51 | #[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)] |
| 52 | #[serde(rename_all = "lowercase")] |
| 53 | pub enum EntryKind { |
| 54 | Tree, |
| 55 | Blob, |
| 56 | Symlink, |
| 57 | Gitlink, |
| 58 | Exec, |
| 59 | } |
| 60 | |
| 61 | #[derive(Clone, Debug, Serialize, Deserialize)] |
| 62 | pub struct TreeEntry { |
| 63 | pub name: String, |
| 64 | pub hash: String, |
| 65 | pub kind: EntryKind, |
| 66 | } |
| 67 | |
| 68 | #[derive(Clone, Debug, Serialize, Deserialize)] |
| 69 | pub struct Readme { |
| 70 | pub name: String, |
| 71 | /// Null when the file is binary or too large to show. |
| 72 | pub text: Option<String>, |
| 73 | } |
| 74 | |
| 75 | #[derive(Clone, Debug, Serialize, Deserialize)] |
| 76 | pub struct TreeView { |
| 77 | pub repo: Repo, |
| 78 | #[serde(rename = "ref")] |
| 79 | pub git_ref: String, |
| 80 | pub path: String, |
| 81 | /// Null when the repo has no commits yet. |
| 82 | pub head: Option<Commit>, |
| 83 | pub entries: Vec<TreeEntry>, |
| 84 | pub readme: Option<Readme>, |
| 85 | } |
| 86 | |
| 87 | #[derive(Clone, Debug, Serialize, Deserialize)] |
| 88 | pub struct BlobView { |
| 89 | pub repo: Repo, |
| 90 | #[serde(rename = "ref")] |
| 91 | pub git_ref: String, |
| 92 | pub path: String, |
| 93 | pub size: u64, |
| 94 | /// Null when the file is binary or too large to show. |
| 95 | pub text: Option<String>, |
| 96 | } |
| 97 | |
| 98 | /// A git remote and a short-lived credential for it. |
| 99 | #[derive(Clone, Debug, Serialize, Deserialize)] |
| 100 | pub struct GitAccess { |
| 101 | pub remote: String, |
| 102 | pub token: String, |
| 103 | } |
| 104 | |
| 105 | #[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)] |
| 106 | pub enum GitService { |
| 107 | #[serde(rename = "git-upload-pack")] |
| 108 | UploadPack, |
| 109 | #[serde(rename = "git-receive-pack")] |
| 110 | ReceivePack, |
| 111 | } |
| 112 | |
| 113 | /// The result of landing a pull request. |
| 114 | #[derive(Clone, Debug, Serialize, Deserialize)] |
| 115 | pub struct Landed { |
| 116 | /// The commit the branch points to now. |
| 117 | pub commit: String, |
| 118 | /// The commit it pointed to before, if it had one. Comparing against |
| 119 | /// this shows what the pull request changed. |
| 120 | pub previous: Option<String>, |
| 121 | } |
| 122 | |
| 123 | /// `get`. Returns `Outcome<Repo>`. |
| 124 | #[derive(Debug, Serialize, Deserialize)] |
| 125 | pub struct GetArgs { |
| 126 | pub path: RepoPath, |
| 127 | pub viewer: Viewer, |
| 128 | } |
| 129 | |
| 130 | /// `get_by_id`. Returns `Outcome<Repo>`. |
| 131 | #[derive(Debug, Serialize, Deserialize)] |
| 132 | pub struct GetByIdArgs { |
| 133 | pub id: String, |
| 134 | pub viewer: Viewer, |
| 135 | } |
| 136 | |
| 137 | /// `list`: repos the viewer may see, newest first. Returns `Vec<Repo>`. |
| 138 | #[derive(Debug, Default, Serialize, Deserialize)] |
| 139 | #[serde(rename_all = "camelCase")] |
| 140 | pub struct ListArgs { |
| 141 | pub viewer: Viewer, |
| 142 | #[serde(default)] |
| 143 | pub query: Option<String>, |
| 144 | /// Only repos in this workspace. |
| 145 | #[serde(default)] |
| 146 | pub namespace: Option<String>, |
| 147 | /// Only repos in workspaces the viewer belongs to. |
| 148 | #[serde(default)] |
| 149 | pub member_only: bool, |
| 150 | } |
| 151 | |
| 152 | /// `create`. Returns `Outcome<Repo>`. |
| 153 | #[derive(Debug, Serialize, Deserialize)] |
| 154 | #[serde(rename_all = "camelCase")] |
| 155 | pub struct CreateArgs { |
| 156 | /// Who is creating it; they must belong to the workspace. |
| 157 | pub owner: User, |
| 158 | /// The workspace it is created in. |
| 159 | pub namespace: String, |
| 160 | pub name: String, |
| 161 | #[serde(default)] |
| 162 | pub description: Option<String>, |
| 163 | #[serde(default)] |
| 164 | pub is_private: bool, |
| 165 | } |
| 166 | |
| 167 | /// `tree`. Returns `Outcome<TreeView>`. |
| 168 | #[derive(Debug, Serialize, Deserialize)] |
| 169 | #[serde(rename_all = "camelCase")] |
| 170 | pub struct TreeArgs { |
| 171 | pub path: RepoPath, |
| 172 | pub viewer: Viewer, |
| 173 | /// The default branch when absent. |
| 174 | #[serde(default, rename = "ref")] |
| 175 | pub git_ref: Option<String>, |
| 176 | #[serde(default)] |
| 177 | pub tree_path: String, |
| 178 | } |
| 179 | |
| 180 | /// `blob`. Returns `Outcome<BlobView>`. |
| 181 | #[derive(Debug, Serialize, Deserialize)] |
| 182 | #[serde(rename_all = "camelCase")] |
| 183 | pub struct BlobArgs { |
| 184 | pub path: RepoPath, |
| 185 | pub viewer: Viewer, |
| 186 | #[serde(rename = "ref")] |
| 187 | pub git_ref: String, |
| 188 | pub file_path: String, |
| 189 | } |
| 190 | |
| 191 | /// `log`. Returns `Outcome<Vec<Commit>>`. |
| 192 | #[derive(Debug, Serialize, Deserialize)] |
| 193 | pub struct LogArgs { |
| 194 | pub path: RepoPath, |
| 195 | pub viewer: Viewer, |
| 196 | #[serde(default, rename = "ref")] |
| 197 | pub git_ref: Option<String>, |
| 198 | pub limit: u32, |
| 199 | } |
| 200 | |
| 201 | /// `fork_for_pull`: a copy-on-write copy of the source repo, hidden from |
| 202 | /// listings, for one pull request to be made in. Returns `Outcome<Repo>`. |
| 203 | #[derive(Debug, Serialize, Deserialize)] |
| 204 | #[serde(rename_all = "camelCase")] |
| 205 | pub struct ForkArgs { |
| 206 | pub source_id: String, |
| 207 | pub pull_id: String, |
| 208 | pub actor: User, |
| 209 | } |
| 210 | |
| 211 | /// `git_access`: authorizes a git operation and says where to send it. |
| 212 | /// Pushing to a repo that does not exist creates it in the pusher's own |
| 213 | /// namespace. Returns `Outcome<GitAccess>`. |
| 214 | #[derive(Debug, Serialize, Deserialize)] |
| 215 | pub struct GitAccessArgs { |
| 216 | pub path: RepoPath, |
| 217 | pub viewer: Viewer, |
| 218 | pub service: GitService, |
| 219 | } |
| 220 | |
| 221 | /// `land`: moves a repository's default branch to the head of a pull |
| 222 | /// request's source. Refused with `conflict` when the source is behind, |
| 223 | /// since that would discard commits. Returns `Outcome<Landed>`. |
| 224 | #[derive(Debug, Serialize, Deserialize)] |
| 225 | #[serde(rename_all = "camelCase")] |
| 226 | pub struct LandArgs { |
| 227 | /// The repository holding the commits: a pull request's fork, or the |
| 228 | /// target itself when landing one of its own branches. |
| 229 | pub source_id: String, |
| 230 | /// The branch of the source to land. Required when the source is the |
| 231 | /// target; a fork lands its default branch. |
| 232 | #[serde(default)] |
| 233 | pub branch: Option<String>, |
| 234 | pub actor: User, |
| 235 | } |
| 236 | |
| 237 | #[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)] |
| 238 | #[serde(rename_all = "lowercase")] |
| 239 | pub enum FileStatus { |
| 240 | Added, |
| 241 | Modified, |
| 242 | Deleted, |
| 243 | } |
| 244 | |
| 245 | #[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)] |
| 246 | #[serde(rename_all = "lowercase")] |
| 247 | pub enum LineKind { |
| 248 | /// Unchanged, shown for context. |
| 249 | Context, |
| 250 | Add, |
| 251 | Delete, |
| 252 | } |
| 253 | |
| 254 | #[derive(Clone, Debug, Serialize, Deserialize)] |
| 255 | pub struct DiffLine { |
| 256 | pub kind: LineKind, |
| 257 | /// Line number in the old file; absent for added lines. |
| 258 | pub old: Option<u32>, |
| 259 | /// Line number in the new file; absent for deleted lines. |
| 260 | pub new: Option<u32>, |
| 261 | pub text: String, |
| 262 | } |
| 263 | |
| 264 | /// A run of changed lines with their surrounding context. |
| 265 | #[derive(Clone, Debug, Serialize, Deserialize)] |
| 266 | pub struct Hunk { |
| 267 | pub lines: Vec<DiffLine>, |
| 268 | } |
| 269 | |
| 270 | #[derive(Clone, Debug, Serialize, Deserialize)] |
| 271 | pub struct FileDiff { |
| 272 | pub path: String, |
| 273 | pub status: FileStatus, |
| 274 | pub additions: u32, |
| 275 | pub deletions: u32, |
| 276 | /// True when the file is binary or too large, so no lines are shown. |
| 277 | pub binary: bool, |
| 278 | pub hunks: Vec<Hunk>, |
| 279 | } |
| 280 | |
| 281 | /// What changed between two commits. |
| 282 | #[derive(Clone, Debug, Serialize, Deserialize)] |
| 283 | pub struct Comparison { |
| 284 | /// Null when the head has no earlier commit to compare against. |
| 285 | pub base: Option<String>, |
| 286 | pub head: String, |
| 287 | pub files: Vec<FileDiff>, |
| 288 | /// True when the change was too large to return in full. |
| 289 | pub truncated: bool, |
| 290 | } |
| 291 | |
| 292 | /// `compare`: what `head` changes relative to `base`. |
| 293 | /// |
| 294 | /// `head` is a branch or a commit, and defaults to the default branch. |
| 295 | /// With no `base`, a fork is compared against the point where it and the |
| 296 | /// repository it came from last agreed; a branch against the point where it |
| 297 | /// left the default branch; and the default branch against its head's |
| 298 | /// parent. Returns `Outcome<Comparison>`. |
| 299 | #[derive(Debug, Serialize, Deserialize)] |
| 300 | #[serde(rename_all = "camelCase")] |
| 301 | pub struct CompareArgs { |
| 302 | pub repo_id: String, |
| 303 | pub viewer: Viewer, |
| 304 | #[serde(default)] |
| 305 | pub base: Option<String>, |
| 306 | #[serde(default)] |
| 307 | pub head: Option<String>, |
| 308 | } |
| 309 | |
| 310 | /// A branch and the commit it points to. |
| 311 | #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] |
| 312 | pub struct Branch { |
| 313 | pub name: String, |
| 314 | pub hash: String, |
| 315 | } |
| 316 | |
| 317 | /// `branches`: the repository's branches, default branch first. |
| 318 | /// Returns `Outcome<Vec<Branch>>`. |
| 319 | #[derive(Debug, Serialize, Deserialize)] |
| 320 | pub struct BranchesArgs { |
| 321 | pub path: RepoPath, |
| 322 | pub viewer: Viewer, |
| 323 | } |
| 324 | |
| 325 | /// `head`: the commit a branch points to, or null. For services reacting |
| 326 | /// to a push, which have no viewer; it reveals nothing but a commit hash. |
| 327 | /// Returns `Option<String>`. |
| 328 | #[derive(Debug, Serialize, Deserialize)] |
| 329 | #[serde(rename_all = "camelCase")] |
| 330 | pub struct HeadArgs { |
| 331 | pub repo_id: String, |
| 332 | pub branch: String, |
| 333 | } |