The Code panel offers git clone when the Git mirror is on 7b17d570d7ee
oxy clone first, then git clone with the mirror's address and a copy button, then the downloads; without the mirror the panel is as before. Tested both ways in the mirror test. Closes #215
- Author
- Andy McCall @andymccall <[email protected]>
- via
- agent
Claude Code <[email protected]> · delegate for changes, until 2026-11-13 19:00Z · key ea5f78160088
- When
- · 2026-10-16 02:13 UTC
- Signature
- ✔ signed by Claude Code
- Hash
7b17d570d7ee61ba1da2460188fdd55f92c2013c6d56e0181e11088788440768- Depends on
- 19bb31ff1f5c 3f4b0ea6eabf 67b24adbf35a 83d5052bf76c d23464c0ac60
- Depended on by
- 84e3c09656b2 a7aa76ac52d7
- In bookmarks
- api-unknown-fields cancel-landed-runs diffusion-pin-bookmark draft-ready main oh-comment-body-file proposal-list-fast
- In tags
- v0.6.0 v0.6.1 v0.7.0 v0.8.0 v0.9.0 v0.9.1 v0.9.11 v0.9.15 v0.9.16 v0.9.19 v0.9.2 v0.9.20 v0.9.21 v0.9.22 v0.9.23 v0.9.24 v0.9.3 v0.9.4 v0.9.5 v0.9.6 v0.9.7 v0.9.8 v0.9.9
- Edits
- 5 atoms, 0 tree operations, 3 files
Browse the tree at this change
modified crates/hub/src/web/mod.rs +3 −0
| … | 304 unchanged lines |
||
| 305 | 305 | pub visibility: String, |
|
| 306 | 306 | pub tab: &'static str, |
|
| 307 | 307 | pub clone_url: String, |
|
| 308 | + | /// The Git mirror's address, when the mirror is on (oxygenhub#215). |
|
| 309 | + | pub git_url: Option<String>, |
|
| 308 | 310 | /// The viewer's role, for showing settings and write actions. |
|
| 309 | 311 | pub role: Option<Role>, |
|
| 310 | 312 | /// Open issues and proposals, shown on their tabs. |
|
| … | 12 unchanged lines |
||
| 323 | 325 | visibility: row.visibility.clone(), |
|
| 324 | 326 | tab, |
|
| 325 | 327 | clone_url: format!("{}/{}/{}", app.config.base_url(), row.owner, row.name), |
|
| 328 | + | git_url: row.git_mirror.then(|| format!("{}/{}/{}.git", app.config.base_url(), row.owner, row.name)), |
|
| 326 | 329 | role: None, |
|
| 327 | 330 | open_issues: row.open_issues, |
|
| 328 | 331 | open_proposals: row.open_proposals, |
|
| … | 248 unchanged lines |
modified crates/hub/tests/releases.rs +7 −0
| … | 229 unchanged lines |
||
| 230 | 230 | send(app, "GET", "/andy/demo.git/info/refs?service=git-upload-pack", None, None, None, vec![]).await.status, |
|
| 231 | 231 | StatusCode::NOT_FOUND |
|
| 232 | 232 | ); |
|
| 233 | + | let overview = send(app, "GET", "/andy/demo", Some(&andy), None, None, vec![]).await.text(); |
|
| 234 | + | assert!(overview.contains("oxy clone ") && !overview.contains("git clone "), "no Git in the Code panel without the mirror"); |
|
| 233 | 235 | let settings = send(app, "GET", "/andy/demo/settings", Some(&andy), None, None, vec![]).await.text(); |
|
| 234 | 236 | let r = form(app, "/andy/demo/settings/mirror", &andy, &format!("_csrf={}&enabled=1", csrf_of(&settings))).await; |
|
| 235 | 237 | assert!(r.text().contains("mirror is on"), "{}", r.text()); |
|
| 238 | + | // The Code panel then offers git clone too: oxy first, then git, then the downloads (#215). |
|
| 239 | + | let overview = send(app, "GET", "/andy/demo", Some(&andy), None, None, vec![]).await.text(); |
|
| 240 | + | let at = |s: &str| overview.find(s).unwrap_or_else(|| panic!("{s} in the Code panel")); |
|
| 241 | + | assert!(at("oxy clone ") < at(&format!("git clone {base}/andy/demo.git")), "oxy first"); |
|
| 242 | + | assert!(at(&format!("data-copy=\"git clone {base}/andy/demo.git\"")) < at("Download ZIP"), "then git, then the downloads"); |
|
| 236 | 243 | let clone_dir = tempfile::tempdir().unwrap(); |
|
| 237 | 244 | let url = format!("{base}/andy/demo.git"); |
|
| 238 | 245 | let target = clone_dir.path().join("demo"); |
|
| … | 89 unchanged lines |
modified templates/overview.html +5 −0
| … | 18 unchanged lines |
||
| 19 | 19 | <label for="clone-cmd" class="small mute">Clone with oxy</label> |
|
| 20 | 20 | <div class="clone"><input id="clone-cmd" type="text" readonly value="oxy clone {{ repo.clone_url }}" onfocus="this.select()" onclick="this.select()"><button type="button" class="small" data-copy="oxy clone {{ repo.clone_url }}">copy</button></div> |
|
| 21 | 21 | <p class="small mute">The URL alone: <code>{{ repo.clone_url }}</code></p> |
|
| 22 | + | {% if let Some(git) = repo.git_url %} |
|
| 23 | + | <label for="git-clone-cmd" class="small mute">Clone with Git (a read-only mirror)</label> |
|
| 24 | + | <div class="clone"><input id="git-clone-cmd" type="text" readonly value="git clone {{ git }}" onfocus="this.select()" onclick="this.select()"><button type="button" class="small" data-copy="git clone {{ git }}">copy</button></div> |
|
| 25 | + | <p class="small mute">For tools that only speak Git. Push with oxy: the mirror refuses pushes.</p> |
|
| 26 | + | {% endif %} |
|
| 22 | 27 | {% if quickstart.is_none() %} |
|
| 23 | 28 | <a class="download" href="{{ repo.url }}/archive?ref={{ repo.default_bookmark|urlencode }}&format=zip" download><span aria-hidden="true">⤓</span> Download ZIP</a> |
|
| 24 | 29 | <p class="small mute">{{ repo.default_bookmark }} as it is now, without its history. Also as <a href="{{ repo.url }}/archive?ref={{ repo.default_bookmark|urlencode }}&format=tar.zst" download>.tar.zst</a>.</p> |
|
| … | 54 unchanged lines |