[O] Clean up codebase
This commit is contained in:
+163
-173
@@ -29,6 +29,38 @@ pub struct ProviderClient<'a> {
|
|||||||
http: Client,
|
http: Client,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
macro_rules! dispatch_provider {
|
||||||
|
($provider:expr, github => $github:expr, gitlab => $gitlab:expr, gitea_like => $gitea_like:expr $(,)?) => {
|
||||||
|
match $provider {
|
||||||
|
ProviderKind::Github => $github,
|
||||||
|
ProviderKind::Gitlab => $gitlab,
|
||||||
|
ProviderKind::Gitea | ProviderKind::Forgejo => $gitea_like,
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! owned_repos {
|
||||||
|
($client:expr, $repo:ty, $url:expr, $namespace:expr) => {{
|
||||||
|
Ok($client
|
||||||
|
.paged_get::<$repo>($url)?
|
||||||
|
.into_iter()
|
||||||
|
.filter(|repo: &$repo| repo.owner.login.eq_ignore_ascii_case($namespace))
|
||||||
|
.map(Into::into)
|
||||||
|
.collect())
|
||||||
|
}};
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! json_method {
|
||||||
|
($name:ident, $method:literal, $request:ident) => {
|
||||||
|
fn $name<T>(&self, url: &str, body: &serde_json::Value) -> Result<T>
|
||||||
|
where
|
||||||
|
T: for<'de> Deserialize<'de>,
|
||||||
|
{
|
||||||
|
self.send_json($method, self.http.$request(url), url, body)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
impl<'a> ProviderClient<'a> {
|
impl<'a> ProviderClient<'a> {
|
||||||
pub fn new(site: &'a SiteConfig) -> Result<Self> {
|
pub fn new(site: &'a SiteConfig) -> Result<Self> {
|
||||||
let token = site.token()?;
|
let token = site.token()?;
|
||||||
@@ -40,12 +72,11 @@ impl<'a> ProviderClient<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn list_repos(&self, endpoint: &EndpointConfig) -> Result<Vec<RemoteRepo>> {
|
pub fn list_repos(&self, endpoint: &EndpointConfig) -> Result<Vec<RemoteRepo>> {
|
||||||
match self.site.provider {
|
dispatch_provider!(self.site.provider,
|
||||||
ProviderKind::Github => self.github_list_repos(endpoint),
|
github => self.github_list_repos(endpoint),
|
||||||
ProviderKind::Gitlab => self.gitlab_list_repos(endpoint),
|
gitlab => self.gitlab_list_repos(endpoint),
|
||||||
ProviderKind::Gitea => self.gitea_list_repos(endpoint),
|
gitea_like => self.gitea_list_repos(endpoint),
|
||||||
ProviderKind::Forgejo => self.gitea_list_repos(endpoint),
|
)
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn create_repo(
|
pub fn create_repo(
|
||||||
@@ -55,18 +86,11 @@ impl<'a> ProviderClient<'a> {
|
|||||||
visibility: &Visibility,
|
visibility: &Visibility,
|
||||||
description: Option<&str>,
|
description: Option<&str>,
|
||||||
) -> Result<RemoteRepo> {
|
) -> Result<RemoteRepo> {
|
||||||
match self.site.provider {
|
dispatch_provider!(self.site.provider,
|
||||||
ProviderKind::Github => {
|
github => self.github_create_repo(endpoint, name, visibility, description),
|
||||||
self.github_create_repo(endpoint, name, visibility, description)
|
gitlab => self.gitlab_create_repo(endpoint, name, visibility, description),
|
||||||
}
|
gitea_like => self.gitea_create_repo(endpoint, name, visibility, description),
|
||||||
ProviderKind::Gitlab => {
|
)
|
||||||
self.gitlab_create_repo(endpoint, name, visibility, description)
|
|
||||||
}
|
|
||||||
ProviderKind::Gitea => self.gitea_create_repo(endpoint, name, visibility, description),
|
|
||||||
ProviderKind::Forgejo => {
|
|
||||||
self.gitea_create_repo(endpoint, name, visibility, description)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn install_webhook(
|
pub fn install_webhook(
|
||||||
@@ -76,13 +100,11 @@ impl<'a> ProviderClient<'a> {
|
|||||||
url: &str,
|
url: &str,
|
||||||
secret: &str,
|
secret: &str,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
match self.site.provider {
|
dispatch_provider!(self.site.provider,
|
||||||
ProviderKind::Github => self.github_install_webhook(endpoint, repo, url, secret),
|
github => self.github_install_webhook(endpoint, repo, url, secret),
|
||||||
ProviderKind::Gitlab => self.gitlab_install_webhook(endpoint, repo, url, secret),
|
gitlab => self.gitlab_install_webhook(endpoint, repo, url, secret),
|
||||||
ProviderKind::Gitea | ProviderKind::Forgejo => {
|
gitea_like => self.gitea_install_webhook(endpoint, repo, url, secret),
|
||||||
self.gitea_install_webhook(endpoint, repo, url, secret)
|
)
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn uninstall_webhook(
|
pub fn uninstall_webhook(
|
||||||
@@ -91,13 +113,11 @@ impl<'a> ProviderClient<'a> {
|
|||||||
repo_name: &str,
|
repo_name: &str,
|
||||||
url: &str,
|
url: &str,
|
||||||
) -> Result<bool> {
|
) -> Result<bool> {
|
||||||
match self.site.provider {
|
dispatch_provider!(self.site.provider,
|
||||||
ProviderKind::Github => self.github_uninstall_webhook(endpoint, repo_name, url),
|
github => self.github_uninstall_webhook(endpoint, repo_name, url),
|
||||||
ProviderKind::Gitlab => self.gitlab_uninstall_webhook(endpoint, repo_name, url),
|
gitlab => self.gitlab_uninstall_webhook(endpoint, repo_name, url),
|
||||||
ProviderKind::Gitea | ProviderKind::Forgejo => {
|
gitea_like => self.gitea_uninstall_webhook(endpoint, repo_name, url),
|
||||||
self.gitea_uninstall_webhook(endpoint, repo_name, url)
|
)
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn validate_token(&self) -> Result<()> {
|
pub fn validate_token(&self) -> Result<()> {
|
||||||
@@ -106,12 +126,11 @@ impl<'a> ProviderClient<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn detect_namespace_kind(&self, namespace: &str) -> Result<Option<NamespaceKind>> {
|
pub fn detect_namespace_kind(&self, namespace: &str) -> Result<Option<NamespaceKind>> {
|
||||||
match self.site.provider {
|
dispatch_provider!(self.site.provider,
|
||||||
ProviderKind::Github => self.github_detect_namespace_kind(namespace),
|
github => self.github_detect_namespace_kind(namespace),
|
||||||
ProviderKind::Gitlab => self.gitlab_detect_namespace_kind(namespace),
|
gitlab => self.gitlab_detect_namespace_kind(namespace),
|
||||||
ProviderKind::Gitea => self.gitea_detect_namespace_kind(namespace),
|
gitea_like => self.gitea_detect_namespace_kind(namespace),
|
||||||
ProviderKind::Forgejo => self.gitea_detect_namespace_kind(namespace),
|
)
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn authenticated_clone_url(&self, clone_url: &str) -> Result<String> {
|
pub fn authenticated_clone_url(&self, clone_url: &str) -> Result<String> {
|
||||||
@@ -126,12 +145,7 @@ impl<'a> ProviderClient<'a> {
|
|||||||
.site
|
.site
|
||||||
.git_username
|
.git_username
|
||||||
.clone()
|
.clone()
|
||||||
.unwrap_or_else(|| match self.site.provider {
|
.unwrap_or_else(|| default_git_username(&self.site.provider).to_string());
|
||||||
ProviderKind::Github => "x-access-token".to_string(),
|
|
||||||
ProviderKind::Gitlab | ProviderKind::Gitea | ProviderKind::Forgejo => {
|
|
||||||
"oauth2".to_string()
|
|
||||||
}
|
|
||||||
});
|
|
||||||
url.set_username(&username)
|
url.set_username(&username)
|
||||||
.map_err(|_| anyhow!("failed to set username on clone URL"))?;
|
.map_err(|_| anyhow!("failed to set username on clone URL"))?;
|
||||||
url.set_password(Some(&self.token))
|
url.set_password(Some(&self.token))
|
||||||
@@ -146,14 +160,7 @@ impl<'a> ProviderClient<'a> {
|
|||||||
"{}/user/repos?affiliation=owner&visibility=all&per_page=100",
|
"{}/user/repos?affiliation=owner&visibility=all&per_page=100",
|
||||||
self.site.api_base()
|
self.site.api_base()
|
||||||
);
|
);
|
||||||
let repos: Vec<GithubRepo> = self
|
owned_repos!(self, GithubRepo, &url, &endpoint.namespace)
|
||||||
.paged_get(&url)?
|
|
||||||
.into_iter()
|
|
||||||
.filter(|repo: &GithubRepo| {
|
|
||||||
repo.owner.login.eq_ignore_ascii_case(&endpoint.namespace)
|
|
||||||
})
|
|
||||||
.collect();
|
|
||||||
Ok(repos.into_iter().map(Into::into).collect())
|
|
||||||
}
|
}
|
||||||
NamespaceKind::Org => {
|
NamespaceKind::Org => {
|
||||||
let url = format!(
|
let url = format!(
|
||||||
@@ -161,8 +168,7 @@ impl<'a> ProviderClient<'a> {
|
|||||||
self.site.api_base(),
|
self.site.api_base(),
|
||||||
endpoint.namespace
|
endpoint.namespace
|
||||||
);
|
);
|
||||||
let repos: Vec<GithubRepo> = self.paged_get(&url)?;
|
self.paged_remote_repos::<GithubRepo>(&url)
|
||||||
Ok(repos.into_iter().map(Into::into).collect())
|
|
||||||
}
|
}
|
||||||
NamespaceKind::Group => bail!("GitHub endpoints use kind 'user' or 'org'"),
|
NamespaceKind::Group => bail!("GitHub endpoints use kind 'user' or 'org'"),
|
||||||
}
|
}
|
||||||
@@ -207,15 +213,7 @@ impl<'a> ProviderClient<'a> {
|
|||||||
url: &str,
|
url: &str,
|
||||||
secret: &str,
|
secret: &str,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
if matches!(endpoint.kind, NamespaceKind::Group) {
|
let hooks_url = self.repo_hooks_url(endpoint, &repo.name, "GitHub")?;
|
||||||
bail!("GitHub endpoints use kind 'user' or 'org'");
|
|
||||||
}
|
|
||||||
let hooks_url = format!(
|
|
||||||
"{}/repos/{}/{}/hooks",
|
|
||||||
self.site.api_base(),
|
|
||||||
endpoint.namespace,
|
|
||||||
repo.name
|
|
||||||
);
|
|
||||||
let body = json!({
|
let body = json!({
|
||||||
"name": "web",
|
"name": "web",
|
||||||
"active": true,
|
"active": true,
|
||||||
@@ -227,13 +225,7 @@ impl<'a> ProviderClient<'a> {
|
|||||||
"insecure_ssl": "0",
|
"insecure_ssl": "0",
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
if let Some(hook) = self.find_existing_hook(&hooks_url, url)? {
|
self.upsert_hook(&hooks_url, url, &body, false)
|
||||||
let update_url = format!("{hooks_url}/{}", hook.id);
|
|
||||||
self.patch_json::<serde_json::Value>(&update_url, &body)?;
|
|
||||||
} else {
|
|
||||||
self.post_json::<serde_json::Value>(&hooks_url, &body)?;
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn github_uninstall_webhook(
|
fn github_uninstall_webhook(
|
||||||
@@ -242,15 +234,7 @@ impl<'a> ProviderClient<'a> {
|
|||||||
repo_name: &str,
|
repo_name: &str,
|
||||||
url: &str,
|
url: &str,
|
||||||
) -> Result<bool> {
|
) -> Result<bool> {
|
||||||
if matches!(endpoint.kind, NamespaceKind::Group) {
|
let hooks_url = self.repo_hooks_url(endpoint, repo_name, "GitHub")?;
|
||||||
bail!("GitHub endpoints use kind 'user' or 'org'");
|
|
||||||
}
|
|
||||||
let hooks_url = format!(
|
|
||||||
"{}/repos/{}/{}/hooks",
|
|
||||||
self.site.api_base(),
|
|
||||||
endpoint.namespace,
|
|
||||||
repo_name
|
|
||||||
);
|
|
||||||
self.delete_matching_hook(&hooks_url, url)
|
self.delete_matching_hook(&hooks_url, url)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -262,8 +246,7 @@ impl<'a> ProviderClient<'a> {
|
|||||||
self.site.api_base(),
|
self.site.api_base(),
|
||||||
endpoint.namespace
|
endpoint.namespace
|
||||||
);
|
);
|
||||||
let repos: Vec<GitlabProject> = self.paged_get(&url)?;
|
self.paged_remote_repos::<GitlabProject>(&url)
|
||||||
Ok(repos.into_iter().map(Into::into).collect())
|
|
||||||
}
|
}
|
||||||
NamespaceKind::Org | NamespaceKind::Group => {
|
NamespaceKind::Org | NamespaceKind::Group => {
|
||||||
let encoded = urlencoding(&endpoint.namespace);
|
let encoded = urlencoding(&endpoint.namespace);
|
||||||
@@ -272,8 +255,7 @@ impl<'a> ProviderClient<'a> {
|
|||||||
self.site.api_base(),
|
self.site.api_base(),
|
||||||
encoded
|
encoded
|
||||||
);
|
);
|
||||||
let repos: Vec<GitlabProject> = self.paged_get(&url)?;
|
self.paged_remote_repos::<GitlabProject>(&url)
|
||||||
Ok(repos.into_iter().map(Into::into).collect())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -339,12 +321,7 @@ impl<'a> ProviderClient<'a> {
|
|||||||
url: &str,
|
url: &str,
|
||||||
secret: &str,
|
secret: &str,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
let project = format!("{}/{}", endpoint.namespace, repo.name);
|
let hooks_url = self.gitlab_hooks_url(endpoint, &repo.name);
|
||||||
let hooks_url = format!(
|
|
||||||
"{}/projects/{}/hooks",
|
|
||||||
self.site.api_base(),
|
|
||||||
urlencoding(&project)
|
|
||||||
);
|
|
||||||
let body = json!({
|
let body = json!({
|
||||||
"url": url,
|
"url": url,
|
||||||
"push_events": true,
|
"push_events": true,
|
||||||
@@ -352,13 +329,7 @@ impl<'a> ProviderClient<'a> {
|
|||||||
"token": secret,
|
"token": secret,
|
||||||
"enable_ssl_verification": true,
|
"enable_ssl_verification": true,
|
||||||
});
|
});
|
||||||
if let Some(hook) = self.find_existing_hook(&hooks_url, url)? {
|
self.upsert_hook(&hooks_url, url, &body, true)
|
||||||
let update_url = format!("{hooks_url}/{}", hook.id);
|
|
||||||
self.put_json::<serde_json::Value>(&update_url, &body)?;
|
|
||||||
} else {
|
|
||||||
self.post_json::<serde_json::Value>(&hooks_url, &body)?;
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn gitlab_uninstall_webhook(
|
fn gitlab_uninstall_webhook(
|
||||||
@@ -367,12 +338,7 @@ impl<'a> ProviderClient<'a> {
|
|||||||
repo_name: &str,
|
repo_name: &str,
|
||||||
url: &str,
|
url: &str,
|
||||||
) -> Result<bool> {
|
) -> Result<bool> {
|
||||||
let project = format!("{}/{}", endpoint.namespace, repo_name);
|
let hooks_url = self.gitlab_hooks_url(endpoint, repo_name);
|
||||||
let hooks_url = format!(
|
|
||||||
"{}/projects/{}/hooks",
|
|
||||||
self.site.api_base(),
|
|
||||||
urlencoding(&project)
|
|
||||||
);
|
|
||||||
self.delete_matching_hook(&hooks_url, url)
|
self.delete_matching_hook(&hooks_url, url)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -380,14 +346,7 @@ impl<'a> ProviderClient<'a> {
|
|||||||
match endpoint.kind {
|
match endpoint.kind {
|
||||||
NamespaceKind::User => {
|
NamespaceKind::User => {
|
||||||
let url = format!("{}/user/repos?limit=50", self.site.api_base());
|
let url = format!("{}/user/repos?limit=50", self.site.api_base());
|
||||||
let repos: Vec<GiteaRepo> = self
|
owned_repos!(self, GiteaRepo, &url, &endpoint.namespace)
|
||||||
.paged_get(&url)?
|
|
||||||
.into_iter()
|
|
||||||
.filter(|repo: &GiteaRepo| {
|
|
||||||
repo.owner.login.eq_ignore_ascii_case(&endpoint.namespace)
|
|
||||||
})
|
|
||||||
.collect();
|
|
||||||
Ok(repos.into_iter().map(Into::into).collect())
|
|
||||||
}
|
}
|
||||||
NamespaceKind::Org => {
|
NamespaceKind::Org => {
|
||||||
let url = format!(
|
let url = format!(
|
||||||
@@ -395,8 +354,7 @@ impl<'a> ProviderClient<'a> {
|
|||||||
self.site.api_base(),
|
self.site.api_base(),
|
||||||
endpoint.namespace
|
endpoint.namespace
|
||||||
);
|
);
|
||||||
let repos: Vec<GiteaRepo> = self.paged_get(&url)?;
|
self.paged_remote_repos::<GiteaRepo>(&url)
|
||||||
Ok(repos.into_iter().map(Into::into).collect())
|
|
||||||
}
|
}
|
||||||
NamespaceKind::Group => bail!("Gitea/Forgejo endpoints use kind 'user' or 'org'"),
|
NamespaceKind::Group => bail!("Gitea/Forgejo endpoints use kind 'user' or 'org'"),
|
||||||
}
|
}
|
||||||
@@ -446,15 +404,7 @@ impl<'a> ProviderClient<'a> {
|
|||||||
url: &str,
|
url: &str,
|
||||||
secret: &str,
|
secret: &str,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
if matches!(endpoint.kind, NamespaceKind::Group) {
|
let hooks_url = self.repo_hooks_url(endpoint, &repo.name, "Gitea/Forgejo")?;
|
||||||
bail!("Gitea endpoints use kind 'user' or 'org'");
|
|
||||||
}
|
|
||||||
let hooks_url = format!(
|
|
||||||
"{}/repos/{}/{}/hooks",
|
|
||||||
self.site.api_base(),
|
|
||||||
endpoint.namespace,
|
|
||||||
repo.name
|
|
||||||
);
|
|
||||||
let body = json!({
|
let body = json!({
|
||||||
"type": "gitea",
|
"type": "gitea",
|
||||||
"active": true,
|
"active": true,
|
||||||
@@ -465,13 +415,7 @@ impl<'a> ProviderClient<'a> {
|
|||||||
"secret": secret,
|
"secret": secret,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
if let Some(hook) = self.find_existing_hook(&hooks_url, url)? {
|
self.upsert_hook(&hooks_url, url, &body, false)
|
||||||
let update_url = format!("{hooks_url}/{}", hook.id);
|
|
||||||
self.patch_json::<serde_json::Value>(&update_url, &body)?;
|
|
||||||
} else {
|
|
||||||
self.post_json::<serde_json::Value>(&hooks_url, &body)?;
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn gitea_uninstall_webhook(
|
fn gitea_uninstall_webhook(
|
||||||
@@ -480,18 +424,35 @@ impl<'a> ProviderClient<'a> {
|
|||||||
repo_name: &str,
|
repo_name: &str,
|
||||||
url: &str,
|
url: &str,
|
||||||
) -> Result<bool> {
|
) -> Result<bool> {
|
||||||
if matches!(endpoint.kind, NamespaceKind::Group) {
|
let hooks_url = self.repo_hooks_url(endpoint, repo_name, "Gitea/Forgejo")?;
|
||||||
bail!("Gitea endpoints use kind 'user' or 'org'");
|
|
||||||
}
|
|
||||||
let hooks_url = format!(
|
|
||||||
"{}/repos/{}/{}/hooks",
|
|
||||||
self.site.api_base(),
|
|
||||||
endpoint.namespace,
|
|
||||||
repo_name
|
|
||||||
);
|
|
||||||
self.delete_matching_hook(&hooks_url, url)
|
self.delete_matching_hook(&hooks_url, url)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn repo_hooks_url(
|
||||||
|
&self,
|
||||||
|
endpoint: &EndpointConfig,
|
||||||
|
repo_name: &str,
|
||||||
|
provider: &str,
|
||||||
|
) -> Result<String> {
|
||||||
|
if matches!(endpoint.kind, NamespaceKind::Group) {
|
||||||
|
bail!("{provider} endpoints use kind 'user' or 'org'");
|
||||||
|
}
|
||||||
|
Ok(format!(
|
||||||
|
"{}/repos/{}/{repo_name}/hooks",
|
||||||
|
self.site.api_base(),
|
||||||
|
endpoint.namespace
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn gitlab_hooks_url(&self, endpoint: &EndpointConfig, repo_name: &str) -> String {
|
||||||
|
let project = format!("{}/{repo_name}", endpoint.namespace);
|
||||||
|
format!(
|
||||||
|
"{}/projects/{}/hooks",
|
||||||
|
self.site.api_base(),
|
||||||
|
urlencoding(&project)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
fn find_existing_hook(&self, hooks_url: &str, target_url: &str) -> Result<Option<RepoHook>> {
|
fn find_existing_hook(&self, hooks_url: &str, target_url: &str) -> Result<Option<RepoHook>> {
|
||||||
let hooks: Vec<RepoHook> = self.paged_get(hooks_url)?;
|
let hooks: Vec<RepoHook> = self.paged_get(hooks_url)?;
|
||||||
Ok(hooks
|
Ok(hooks
|
||||||
@@ -499,6 +460,27 @@ impl<'a> ProviderClient<'a> {
|
|||||||
.find(|hook| hook.url() == Some(target_url)))
|
.find(|hook| hook.url() == Some(target_url)))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn upsert_hook(
|
||||||
|
&self,
|
||||||
|
hooks_url: &str,
|
||||||
|
target_url: &str,
|
||||||
|
body: &serde_json::Value,
|
||||||
|
put_on_update: bool,
|
||||||
|
) -> Result<()> {
|
||||||
|
let Some(hook) = self.find_existing_hook(hooks_url, target_url)? else {
|
||||||
|
self.post_json::<serde_json::Value>(hooks_url, body)?;
|
||||||
|
return Ok(());
|
||||||
|
};
|
||||||
|
|
||||||
|
let update_url = format!("{hooks_url}/{}", hook.id);
|
||||||
|
if put_on_update {
|
||||||
|
self.put_json::<serde_json::Value>(&update_url, body)?;
|
||||||
|
} else {
|
||||||
|
self.patch_json::<serde_json::Value>(&update_url, body)?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
fn delete_matching_hook(&self, hooks_url: &str, target_url: &str) -> Result<bool> {
|
fn delete_matching_hook(&self, hooks_url: &str, target_url: &str) -> Result<bool> {
|
||||||
let Some(hook) = self.find_existing_hook(hooks_url, target_url)? else {
|
let Some(hook) = self.find_existing_hook(hooks_url, target_url)? else {
|
||||||
return Ok(false);
|
return Ok(false);
|
||||||
@@ -527,6 +509,17 @@ impl<'a> ProviderClient<'a> {
|
|||||||
Ok(output)
|
Ok(output)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn paged_remote_repos<T>(&self, url: &str) -> Result<Vec<RemoteRepo>>
|
||||||
|
where
|
||||||
|
T: for<'de> Deserialize<'de> + Into<RemoteRepo>,
|
||||||
|
{
|
||||||
|
Ok(self
|
||||||
|
.paged_get::<T>(url)?
|
||||||
|
.into_iter()
|
||||||
|
.map(Into::into)
|
||||||
|
.collect())
|
||||||
|
}
|
||||||
|
|
||||||
fn get_json<T>(&self, url: &str) -> Result<T>
|
fn get_json<T>(&self, url: &str) -> Result<T>
|
||||||
where
|
where
|
||||||
T: for<'de> Deserialize<'de>,
|
T: for<'de> Deserialize<'de>,
|
||||||
@@ -536,57 +529,47 @@ impl<'a> ProviderClient<'a> {
|
|||||||
.with_context(|| format!("invalid JSON from {url}"))
|
.with_context(|| format!("invalid JSON from {url}"))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn post_json<T>(&self, url: &str, body: &serde_json::Value) -> Result<T>
|
json_method!(post_json, "POST", post);
|
||||||
where
|
json_method!(put_json, "PUT", put);
|
||||||
T: for<'de> Deserialize<'de>,
|
json_method!(patch_json, "PATCH", patch);
|
||||||
{
|
|
||||||
self.request_headers(self.http.post(url))?
|
|
||||||
.json(body)
|
|
||||||
.send()
|
|
||||||
.with_context(|| format!("POST {url} failed"))
|
|
||||||
.and_then(|response| check_response("POST", url, response))?
|
|
||||||
.json()
|
|
||||||
.with_context(|| format!("invalid JSON from {url}"))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn put_json<T>(&self, url: &str, body: &serde_json::Value) -> Result<T>
|
fn send_json<T>(
|
||||||
|
&self,
|
||||||
|
method: &str,
|
||||||
|
request: reqwest::blocking::RequestBuilder,
|
||||||
|
url: &str,
|
||||||
|
body: &serde_json::Value,
|
||||||
|
) -> Result<T>
|
||||||
where
|
where
|
||||||
T: for<'de> Deserialize<'de>,
|
T: for<'de> Deserialize<'de>,
|
||||||
{
|
{
|
||||||
self.request_headers(self.http.put(url))?
|
self.request_headers(request)?
|
||||||
.json(body)
|
.json(body)
|
||||||
.send()
|
.send()
|
||||||
.with_context(|| format!("PUT {url} failed"))
|
.with_context(|| format!("{method} {url} failed"))
|
||||||
.and_then(|response| check_response("PUT", url, response))?
|
.and_then(|response| check_response(method, url, response))?
|
||||||
.json()
|
|
||||||
.with_context(|| format!("invalid JSON from {url}"))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn patch_json<T>(&self, url: &str, body: &serde_json::Value) -> Result<T>
|
|
||||||
where
|
|
||||||
T: for<'de> Deserialize<'de>,
|
|
||||||
{
|
|
||||||
self.request_headers(self.http.patch(url))?
|
|
||||||
.json(body)
|
|
||||||
.send()
|
|
||||||
.with_context(|| format!("PATCH {url} failed"))
|
|
||||||
.and_then(|response| check_response("PATCH", url, response))?
|
|
||||||
.json()
|
.json()
|
||||||
.with_context(|| format!("invalid JSON from {url}"))
|
.with_context(|| format!("invalid JSON from {url}"))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get(&self, url: &str) -> Result<Response> {
|
fn get(&self, url: &str) -> Result<Response> {
|
||||||
self.request_headers(self.http.get(url))?
|
self.send("GET", self.http.get(url), url)
|
||||||
.send()
|
|
||||||
.with_context(|| format!("GET {url} failed"))
|
|
||||||
.and_then(|response| check_response("GET", url, response))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn delete(&self, url: &str) -> Result<Response> {
|
fn delete(&self, url: &str) -> Result<Response> {
|
||||||
self.request_headers(self.http.delete(url))?
|
self.send("DELETE", self.http.delete(url), url)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn send(
|
||||||
|
&self,
|
||||||
|
method: &str,
|
||||||
|
request: reqwest::blocking::RequestBuilder,
|
||||||
|
url: &str,
|
||||||
|
) -> Result<Response> {
|
||||||
|
self.request_headers(request)?
|
||||||
.send()
|
.send()
|
||||||
.with_context(|| format!("DELETE {url} failed"))
|
.with_context(|| format!("{method} {url} failed"))
|
||||||
.and_then(|response| check_response("DELETE", url, response))
|
.and_then(|response| check_response(method, url, response))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn request_headers(
|
fn request_headers(
|
||||||
@@ -656,6 +639,13 @@ fn urlencoding(value: &str) -> String {
|
|||||||
url::form_urlencoded::byte_serialize(value.as_bytes()).collect()
|
url::form_urlencoded::byte_serialize(value.as_bytes()).collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn default_git_username(provider: &ProviderKind) -> &'static str {
|
||||||
|
match provider {
|
||||||
|
ProviderKind::Github => "x-access-token",
|
||||||
|
ProviderKind::Gitlab | ProviderKind::Gitea | ProviderKind::Forgejo => "oauth2",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
#[derive(Deserialize)]
|
||||||
struct GithubRepo {
|
struct GithubRepo {
|
||||||
name: String,
|
name: String,
|
||||||
|
|||||||
Reference in New Issue
Block a user