[F] Fix default branch

This commit is contained in:
2026-05-10 15:23:50 +00:00
parent fe1aa19ce3
commit 73d5127ee2
4 changed files with 335 additions and 5 deletions
+92 -2
View File
@@ -172,6 +172,19 @@ impl<'a> ProviderClient<'a> {
)
}
pub fn set_default_branch(
&self,
endpoint: &EndpointConfig,
repo_name: &str,
branch: &str,
) -> Result<()> {
dispatch_provider!(self.site.provider,
github => self.github_set_default_branch(endpoint, repo_name, branch),
gitlab => self.gitlab_set_default_branch(endpoint, repo_name, branch),
gitea_like => self.gitea_set_default_branch(endpoint, repo_name, branch),
)
}
pub fn install_webhook(
&self,
endpoint: &EndpointConfig,
@@ -317,6 +330,17 @@ impl<'a> ProviderClient<'a> {
self.delete(&url).map(|_| ())
}
fn github_set_default_branch(
&self,
endpoint: &EndpointConfig,
repo_name: &str,
branch: &str,
) -> Result<()> {
let url = self.repo_url(endpoint, repo_name, "GitHub")?;
self.patch_json::<serde_json::Value>(&url, &json!({ "default_branch": branch }))
.map(|_| ())
}
fn github_install_webhook(
&self,
endpoint: &EndpointConfig,
@@ -441,7 +465,11 @@ impl<'a> ProviderClient<'a> {
projects.push(project);
}
}
Ok(projects.into_iter().map(Into::into).collect())
Ok(projects
.into_iter()
.filter(|project| !project.is_deletion_scheduled())
.map(Into::into)
.collect())
}
NamespaceKind::Org | NamespaceKind::Group => {
let encoded = urlencoding(&endpoint.namespace);
@@ -450,7 +478,12 @@ impl<'a> ProviderClient<'a> {
self.site.api_base(),
encoded
);
self.paged_remote_repos::<GitlabProject>(&url)
Ok(self
.paged_get::<GitlabProject>(&url)?
.into_iter()
.filter(|project| !project.is_deletion_scheduled())
.map(Into::into)
.collect())
}
}
}
@@ -502,6 +535,17 @@ impl<'a> ProviderClient<'a> {
self.delete(&url).map(|_| ())
}
fn gitlab_set_default_branch(
&self,
endpoint: &EndpointConfig,
repo_name: &str,
branch: &str,
) -> Result<()> {
let url = self.gitlab_project_url(endpoint, repo_name);
self.put_json::<serde_json::Value>(&url, &json!({ "default_branch": branch }))
.map(|_| ())
}
fn gitlab_group(&self, namespace: &str) -> Result<GitlabGroup> {
let url = format!("{}/groups/{}", self.site.api_base(), urlencoding(namespace));
self.get_json(&url)
@@ -695,6 +739,17 @@ impl<'a> ProviderClient<'a> {
self.delete(&url).map(|_| ())
}
fn gitea_set_default_branch(
&self,
endpoint: &EndpointConfig,
repo_name: &str,
branch: &str,
) -> Result<()> {
let url = self.repo_url(endpoint, repo_name, "Gitea/Forgejo")?;
self.patch_json::<serde_json::Value>(&url, &json!({ "default_branch": branch }))
.map(|_| ())
}
fn gitea_install_webhook(
&self,
endpoint: &EndpointConfig,
@@ -1163,6 +1218,10 @@ struct GitlabProject {
http_url_to_repo: String,
visibility: String,
description: Option<String>,
marked_for_deletion_at: Option<String>,
marked_for_deletion_on: Option<String>,
#[serde(default)]
pending_delete: bool,
}
impl GitlabProject {
@@ -1190,6 +1249,37 @@ impl GitlabProject {
.eq_ignore_ascii_case(other.project_path()),
}
}
fn is_deletion_scheduled(&self) -> bool {
self.pending_delete
|| self
.marked_for_deletion_at
.as_deref()
.is_some_and(|value| !value.is_empty())
|| self
.marked_for_deletion_on
.as_deref()
.is_some_and(|value| !value.is_empty())
|| is_gitlab_deletion_scheduled_path(&self.name)
|| self
.path
.as_deref()
.is_some_and(is_gitlab_deletion_scheduled_path)
|| self
.path_with_namespace
.as_deref()
.and_then(|path| path.rsplit('/').next())
.is_some_and(is_gitlab_deletion_scheduled_path)
}
}
fn is_gitlab_deletion_scheduled_path(path: &str) -> bool {
let Some((name, project_id)) = path.rsplit_once("-deletion_scheduled-") else {
return false;
};
!name.is_empty()
&& !project_id.is_empty()
&& project_id.bytes().all(|byte| byte.is_ascii_digit())
}
#[derive(Deserialize)]
+45
View File
@@ -38,6 +38,7 @@ use self::state::{
};
const CONFLICT_BRANCH_ROOT: &str = "refray/conflicts/";
const DEFAULT_BRANCH: &str = "main";
#[derive(Clone, Debug)]
pub struct SyncOptions {
@@ -842,6 +843,7 @@ fn sync_repo(
let Some(refs) = check_remote_refs(context, repo_name, &remotes)? else {
return Ok(RepoSyncOutcome::default());
};
set_default_branch_for_created_repos(context, repo_name, &created_repos, &refs)?;
refs
} else {
initial_ref_state
@@ -857,6 +859,48 @@ fn sync_repo(
})
}
fn set_default_branch_for_created_repos(
context: &RepoSyncContext<'_>,
repo_name: &str,
created_repos: &[EndpointRepo],
refs: &BTreeMap<String, RemoteRefState>,
) -> Result<()> {
if created_repos.is_empty() {
return Ok(());
}
let targets = created_repos
.iter()
.filter(|repo| {
refs.get(&remote_name_for_endpoint_repo(repo))
.is_some_and(|refs| refs.branches.contains_key(DEFAULT_BRANCH))
})
.cloned()
.collect::<Vec<_>>();
crate::parallel::map(targets, context.jobs, |repo| {
crate::logln!(
" {} branch {} {}",
style("default").green().bold(),
style(DEFAULT_BRANCH).cyan(),
style(format!("on {}", repo.endpoint.label())).dim()
);
let site = context.config.site(&repo.endpoint.site).unwrap();
ProviderClient::new(site)?
.set_default_branch(&repo.endpoint, repo_name, DEFAULT_BRANCH)
.with_context(|| {
format!(
"failed to set default branch for {} on {}",
repo_name,
repo.endpoint.label()
)
})?;
Ok(())
})?;
Ok(())
}
fn sync_assumed_repo(
context: &RepoSyncContext<'_>,
repo_name: &str,
@@ -972,6 +1016,7 @@ fn sync_assumed_repo(
..RepoSyncOutcome::default()
});
};
set_default_branch_for_created_repos(context, repo_name, &created_repos, &refs)?;
refs
} else {
initial_ref_check.refs