1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
|
use clap::Subcommand;
use forgejo_api::CreateRepoOption;
use url::Url;
use eyre::eyre;
pub struct RepoInfo {
owner: String,
name: String,
url: Url,
}
impl RepoInfo {
pub fn get_current() -> eyre::Result<Self> {
let repo = git2::Repository::open(".")?;
let url = get_remote(&repo)?;
let mut path = url
.path_segments()
.ok_or_else(|| eyre!("bad path"))?;
let owner = path
.next()
.ok_or_else(|| eyre!("path does not have owner name"))?
.to_string();
let name = path
.next()
.ok_or_else(|| eyre!("path does not have repo name"))?
.to_string();
let repo_info = RepoInfo {
owner,
name,
url,
};
Ok(repo_info)
}
pub fn owner(&self) -> &str {
&self.owner
}
pub fn name(&self) -> &str {
&self.name
}
pub fn url(&self) -> &Url {
&self.url
}
}
fn get_remote(repo: &git2::Repository) -> eyre::Result<Url> {
let head = repo.head()?;
let branch_name = head.name().ok_or_else(|| eyre!("branch name not UTF-8"))?;
let remote_name = repo.branch_upstream_remote(branch_name)?;
let remote_name = remote_name
.as_str()
.ok_or_else(|| eyre!("remote name not UTF-8"))?;
let remote = repo.find_remote(remote_name)?;
let url = Url::parse(std::str::from_utf8(remote.url_bytes())?)?;
Ok(url)
}
#[derive(Subcommand, Clone, Debug)]
pub enum RepoCommand {
Create {
host: String,
repo: String,
// flags
#[clap(long, short)]
description: Option<String>,
#[clap(long, short)]
private: bool,
/// Sets the new repo to be the `origin` remote of the current local repo.
#[clap(long, short)]
set_upstream: Option<String>,
/// Pushes the current branch to the default branch on the new repo.
/// Implies `--set-upstream=origin` (setting upstream manual overrides this)
#[clap(long, short)]
push: bool,
},
Info,
Browse,
}
impl RepoCommand {
pub async fn run(self, keys: &crate::KeyInfo) -> eyre::Result<()> {
match self {
RepoCommand::Create {
host,
repo,
description,
private,
set_upstream,
push,
} => {
let host = Url::parse(&host)?;
let login = keys.get_login(&host)?;
let api = login.api_for(&host)?;
let repo_spec = CreateRepoOption {
auto_init: false,
default_branch: "main".into(),
description,
gitignores: String::new(),
issue_labels: String::new(),
license: String::new(),
name: repo.clone(),
private,
readme: String::new(),
template: false,
trust_model: forgejo_api::TrustModel::Default,
};
let new_repo = api.create_repo(repo_spec).await?;
eprintln!(
"created new repo at {}",
host.join(&format!("{}/{}", login.username(), repo))?
);
let upstream = set_upstream.as_deref().unwrap_or("origin");
let repo = git2::Repository::open(".")?;
let mut remote = if set_upstream.is_some() || push {
repo.remote(upstream, new_repo.clone_url.as_str())?
} else {
repo.find_remote(upstream)?
};
if push {
remote.push::<&str>(&[], None)?;
}
}
RepoCommand::Info => {
let repo = RepoInfo::get_current()?;
let api = keys.get_api(repo.url())?;
let repo = api.get_repo(repo.owner(), repo.name()).await?;
match repo {
Some(repo) => {
dbg!(repo);
}
None => eprintln!("repo not found"),
}
}
RepoCommand::Browse => {
let repo = RepoInfo::get_current()?;
let mut url = repo.url().clone();
let new_path = format!(
"{}/{}/{}",
url.path().strip_suffix("/").unwrap_or(url.path()),
repo.owner(),
repo.name(),
);
url.set_path(&new_path);
open::that(url.as_str())?;
}
};
Ok(())
}
}
|