codeberg_cli/actions/repo/
clone.rs1use miette::{Context, IntoDiagnostic};
2use url::Url;
3
4use crate::actions::GlobalArgs;
5use crate::render::spinner::spin_until_ready;
6use crate::render::ui::confirm_with_prompt;
7use crate::types::context::BergContext;
8use crate::types::git::{Git, OwnerRepo};
9
10use clap::Parser;
11
12#[derive(Parser, Debug)]
14pub struct RepoCloneArgs {
15 #[arg(value_name = "OWNER/REPO")]
17 pub owner_and_repo: OwnerRepo,
18 #[arg(long, default_value_t = false)]
20 pub use_ssh: bool,
21 #[arg(value_name = "DESTINATION")]
23 pub destination: Option<String>,
24}
25
26impl RepoCloneArgs {
27 pub async fn run(self, global_args: GlobalArgs) -> miette::Result<()> {
28 let _ = global_args;
29 let ctx = BergContext::new(self, global_args.clone()).await?;
30
31 let owner_repo = ctx.args.owner_and_repo.clone();
32 let url = if ctx.args.use_ssh {
33 spin_until_ready(get_ssh_url(
34 &ctx,
35 owner_repo.owner.as_str(),
36 owner_repo.repo.as_str(),
37 ))
38 .await?
39 } else {
40 ctx.config
41 .url()?
42 .join(format!("/{owner_repo}.git").as_str())
43 .into_diagnostic()?
44 };
45
46 if !global_args.non_interactive
47 && !confirm_with_prompt(format!(
48 "Do you want to clone the repository '{owner_repo}' into {pwd}/{repo}",
49 pwd = std::env::current_dir().into_diagnostic()?.display(),
50 repo = owner_repo.repo
51 ))?
52 {
53 println!("Canceled clone!");
54 std::process::exit(0);
55 }
56
57 Git::clone(
58 url,
59 ctx.args.destination.unwrap_or(owner_repo.repo).as_str(),
60 )?;
61
62 Ok(())
63 }
64}
65
66async fn get_ssh_url(
67 ctx: &BergContext<RepoCloneArgs>,
68 ownername: &str,
69 reponame: &str,
70) -> miette::Result<Url> {
71 ctx.client
72 .repo_get(ownername, reponame)
73 .await
74 .into_diagnostic()
75 .inspect(|x| tracing::debug!("{x:#?}"))
76 .and_then(|repo| repo.ssh_url.context("No SSH url on repo"))
77 .and_then(|url| {
78 Url::parse(url.as_str())
79 .into_diagnostic()
80 .with_context(|| format!("Url wasn't a valid SSH Url: {url}", url = url.as_str()))
81 })
82 .context("User doesn't own the repo that was specified or at least doesn't have access'.")
83}