[-] Remove unnecessary multiple regex
This commit is contained in:
@@ -69,8 +69,8 @@ token = { value = "gitea_pat_..." }
|
|||||||
[[mirrors]]
|
[[mirrors]]
|
||||||
name = "personal"
|
name = "personal"
|
||||||
sync_visibility = "all"
|
sync_visibility = "all"
|
||||||
repo_whitelist = ["^important-"]
|
repo_whitelist = "^important-"
|
||||||
repo_blacklist = ["-archive$"]
|
repo_blacklist = "-archive$"
|
||||||
create_missing = true
|
create_missing = true
|
||||||
visibility = "private"
|
visibility = "private"
|
||||||
conflict_resolution = "auto_rebase_pull_request"
|
conflict_resolution = "auto_rebase_pull_request"
|
||||||
@@ -179,7 +179,7 @@ Each mirror group is treated as a set of equivalent namespaces. Repositories are
|
|||||||
|
|
||||||
Set `sync_visibility = "all"`, `"private"`, or `"public"` on a mirror group to choose which repository visibility is included in that group. When `refray` creates a missing repository, it mirrors the visibility of the existing repository it is syncing from; `visibility` is only a fallback when no source visibility is available.
|
Set `sync_visibility = "all"`, `"private"`, or `"public"` on a mirror group to choose which repository visibility is included in that group. When `refray` creates a missing repository, it mirrors the visibility of the existing repository it is syncing from; `visibility` is only a fallback when no source visibility is available.
|
||||||
|
|
||||||
Set `repo_whitelist = ["..."]` and/or `repo_blacklist = ["..."]` on a mirror group to filter repository names with regular expressions. An empty whitelist includes all repository names, and blacklist matches are excluded after whitelist matches. These name filters are independent from `sync_visibility`; both must match for a repository to be synced.
|
Set `repo_whitelist = "..."` and/or `repo_blacklist = "..."` on a mirror group to filter repository names with regular expressions. Omit `repo_whitelist` to include all repository names, and blacklist matches are excluded after whitelist matches. These name filters are independent from `sync_visibility`; both must match for a repository to be synced.
|
||||||
|
|
||||||
For every repository name found in any endpoint, `refray` will:
|
For every repository name found in any endpoint, `refray` will:
|
||||||
|
|
||||||
|
|||||||
+29
-23
@@ -56,10 +56,10 @@ pub struct MirrorConfig {
|
|||||||
pub endpoints: Vec<EndpointConfig>,
|
pub endpoints: Vec<EndpointConfig>,
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub sync_visibility: SyncVisibility,
|
pub sync_visibility: SyncVisibility,
|
||||||
#[serde(default, skip_serializing_if = "Vec::is_empty")]
|
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||||
pub repo_whitelist: Vec<String>,
|
pub repo_whitelist: Option<String>,
|
||||||
#[serde(default, skip_serializing_if = "Vec::is_empty")]
|
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||||
pub repo_blacklist: Vec<String>,
|
pub repo_blacklist: Option<String>,
|
||||||
#[serde(default = "default_true")]
|
#[serde(default = "default_true")]
|
||||||
pub create_missing: bool,
|
pub create_missing: bool,
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
@@ -135,8 +135,8 @@ pub enum SyncVisibility {
|
|||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct RepoNameFilter {
|
pub struct RepoNameFilter {
|
||||||
whitelist: Vec<Regex>,
|
whitelist: Option<Regex>,
|
||||||
blacklist: Vec<Regex>,
|
blacklist: Option<Regex>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SyncVisibility {
|
impl SyncVisibility {
|
||||||
@@ -152,35 +152,41 @@ impl SyncVisibility {
|
|||||||
impl MirrorConfig {
|
impl MirrorConfig {
|
||||||
pub fn repo_filter(&self) -> Result<RepoNameFilter> {
|
pub fn repo_filter(&self) -> Result<RepoNameFilter> {
|
||||||
Ok(RepoNameFilter {
|
Ok(RepoNameFilter {
|
||||||
whitelist: compile_repo_patterns(&self.name, "repo_whitelist", &self.repo_whitelist)?,
|
whitelist: compile_repo_pattern(&self.name, "repo_whitelist", &self.repo_whitelist)?,
|
||||||
blacklist: compile_repo_patterns(&self.name, "repo_blacklist", &self.repo_blacklist)?,
|
blacklist: compile_repo_pattern(&self.name, "repo_blacklist", &self.repo_blacklist)?,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl RepoNameFilter {
|
impl RepoNameFilter {
|
||||||
pub fn matches(&self, repo_name: &str) -> bool {
|
pub fn matches(&self, repo_name: &str) -> bool {
|
||||||
let whitelisted = self.whitelist.is_empty()
|
let whitelisted = self
|
||||||
|| self
|
.whitelist
|
||||||
.whitelist
|
.as_ref()
|
||||||
.iter()
|
.is_none_or(|pattern| pattern.is_match(repo_name));
|
||||||
.any(|pattern| pattern.is_match(repo_name));
|
|
||||||
let blacklisted = self
|
let blacklisted = self
|
||||||
.blacklist
|
.blacklist
|
||||||
.iter()
|
.as_ref()
|
||||||
.any(|pattern| pattern.is_match(repo_name));
|
.is_some_and(|pattern| pattern.is_match(repo_name));
|
||||||
whitelisted && !blacklisted
|
whitelisted && !blacklisted
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn compile_repo_patterns(mirror: &str, field: &str, patterns: &[String]) -> Result<Vec<Regex>> {
|
fn compile_repo_pattern(
|
||||||
patterns
|
mirror: &str,
|
||||||
.iter()
|
field: &str,
|
||||||
.map(|pattern| {
|
pattern: &Option<String>,
|
||||||
Regex::new(pattern)
|
) -> Result<Option<Regex>> {
|
||||||
.with_context(|| format!("mirror '{mirror}' has invalid {field} regex '{pattern}'"))
|
let Some(pattern) = pattern
|
||||||
})
|
.as_deref()
|
||||||
.collect()
|
.map(str::trim)
|
||||||
|
.filter(|pattern| !pattern.is_empty())
|
||||||
|
else {
|
||||||
|
return Ok(None);
|
||||||
|
};
|
||||||
|
Regex::new(pattern)
|
||||||
|
.with_context(|| format!("mirror '{mirror}' has invalid {field} regex '{pattern}'"))
|
||||||
|
.map(Some)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn default_true() -> bool {
|
fn default_true() -> bool {
|
||||||
|
|||||||
+27
-36
@@ -38,8 +38,8 @@ struct ParsedProfileUrl {
|
|||||||
|
|
||||||
#[derive(Clone, Debug, Default)]
|
#[derive(Clone, Debug, Default)]
|
||||||
struct RepoFilterInput {
|
struct RepoFilterInput {
|
||||||
whitelist: Vec<String>,
|
whitelist: Option<String>,
|
||||||
blacklist: Vec<String>,
|
blacklist: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run_config_wizard(path: &Path) -> Result<ConfigWizardOutcome> {
|
pub fn run_config_wizard(path: &Path) -> Result<ConfigWizardOutcome> {
|
||||||
@@ -780,7 +780,7 @@ fn prompt_repo_filters_styled(
|
|||||||
existing: Option<&RepoFilterInput>,
|
existing: Option<&RepoFilterInput>,
|
||||||
) -> Result<RepoFilterInput> {
|
) -> Result<RepoFilterInput> {
|
||||||
let existing = existing.cloned().unwrap_or_default();
|
let existing = existing.cloned().unwrap_or_default();
|
||||||
let has_existing = !existing.whitelist.is_empty() || !existing.blacklist.is_empty();
|
let has_existing = existing.whitelist.is_some() || existing.blacklist.is_some();
|
||||||
if !Confirm::with_theme(theme)
|
if !Confirm::with_theme(theme)
|
||||||
.with_prompt("Configure repository name whitelist/blacklist?")
|
.with_prompt("Configure repository name whitelist/blacklist?")
|
||||||
.default(has_existing)
|
.default(has_existing)
|
||||||
@@ -790,51 +790,44 @@ fn prompt_repo_filters_styled(
|
|||||||
}
|
}
|
||||||
|
|
||||||
Ok(RepoFilterInput {
|
Ok(RepoFilterInput {
|
||||||
whitelist: prompt_repo_pattern_list_styled(
|
whitelist: prompt_repo_pattern_styled(
|
||||||
theme,
|
theme,
|
||||||
"Whitelist regexes (comma-separated, empty means all repo names)",
|
"Whitelist regex (empty means all repo names)",
|
||||||
&existing.whitelist,
|
&existing.whitelist,
|
||||||
)?,
|
)?,
|
||||||
blacklist: prompt_repo_pattern_list_styled(
|
blacklist: prompt_repo_pattern_styled(theme, "Blacklist regex", &existing.blacklist)?,
|
||||||
theme,
|
|
||||||
"Blacklist regexes (comma-separated)",
|
|
||||||
&existing.blacklist,
|
|
||||||
)?,
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn prompt_repo_pattern_list_styled(
|
fn prompt_repo_pattern_styled(
|
||||||
theme: &ColorfulTheme,
|
theme: &ColorfulTheme,
|
||||||
prompt: &str,
|
prompt: &str,
|
||||||
existing: &[String],
|
existing: &Option<String>,
|
||||||
) -> Result<Vec<String>> {
|
) -> Result<Option<String>> {
|
||||||
let input = Input::<String>::with_theme(theme)
|
let input = Input::<String>::with_theme(theme)
|
||||||
.with_prompt(prompt)
|
.with_prompt(prompt)
|
||||||
.allow_empty(true)
|
.allow_empty(true)
|
||||||
.validate_with(|value: &String| validate_repo_pattern_list(value));
|
.validate_with(|value: &String| validate_repo_pattern(value));
|
||||||
let input = if existing.is_empty() {
|
let input = if let Some(existing) = existing {
|
||||||
input
|
input.default(existing.clone())
|
||||||
} else {
|
} else {
|
||||||
input.default(existing.join(", "))
|
input
|
||||||
};
|
};
|
||||||
let value = input.interact_text()?;
|
let value = input.interact_text()?;
|
||||||
Ok(parse_repo_pattern_list(&value))
|
Ok(parse_repo_pattern(&value))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn validate_repo_pattern_list(value: &str) -> std::result::Result<(), String> {
|
fn validate_repo_pattern(value: &str) -> std::result::Result<(), String> {
|
||||||
for pattern in parse_repo_pattern_list(value) {
|
let Some(pattern) = parse_repo_pattern(value) else {
|
||||||
Regex::new(&pattern).map_err(|error| format!("invalid regex '{pattern}': {error}"))?;
|
return Ok(());
|
||||||
}
|
};
|
||||||
|
Regex::new(&pattern).map_err(|error| format!("invalid regex '{pattern}': {error}"))?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_repo_pattern_list(value: &str) -> Vec<String> {
|
fn parse_repo_pattern(value: &str) -> Option<String> {
|
||||||
value
|
let value = value.trim();
|
||||||
.split(',')
|
(!value.is_empty()).then(|| value.to_string())
|
||||||
.map(str::trim)
|
|
||||||
.filter(|value| !value.is_empty())
|
|
||||||
.map(ToOwned::to_owned)
|
|
||||||
.collect()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn sync_visibility_index(sync_visibility: &SyncVisibility) -> usize {
|
fn sync_visibility_index(sync_visibility: &SyncVisibility) -> usize {
|
||||||
@@ -937,13 +930,11 @@ fn sync_visibility_label(sync_visibility: &SyncVisibility) -> &'static str {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn repo_filter_label(mirror: &MirrorConfig) -> String {
|
fn repo_filter_label(mirror: &MirrorConfig) -> String {
|
||||||
match (mirror.repo_whitelist.len(), mirror.repo_blacklist.len()) {
|
match (&mirror.repo_whitelist, &mirror.repo_blacklist) {
|
||||||
(0, 0) => "repos: all names".to_string(),
|
(None, None) => "repos: all names".to_string(),
|
||||||
(whitelist, 0) => format!("repos: whitelist {whitelist}"),
|
(Some(_), None) => "repos: whitelist".to_string(),
|
||||||
(0, blacklist) => format!("repos: blacklist {blacklist}"),
|
(None, Some(_)) => "repos: blacklist".to_string(),
|
||||||
(whitelist, blacklist) => {
|
(Some(_), Some(_)) => "repos: whitelist + blacklist".to_string(),
|
||||||
format!("repos: whitelist {whitelist}, blacklist {blacklist}")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -339,7 +339,7 @@ secret = {{ value = "{WEBHOOK_SECRET}" }}
|
|||||||
[[mirrors]]
|
[[mirrors]]
|
||||||
name = "all"
|
name = "all"
|
||||||
sync_visibility = "all"
|
sync_visibility = "all"
|
||||||
repo_whitelist = ['{}']
|
repo_whitelist = '{}'
|
||||||
create_missing = {}
|
create_missing = {}
|
||||||
visibility = "public"
|
visibility = "public"
|
||||||
conflict_resolution = "{}"
|
conflict_resolution = "{}"
|
||||||
@@ -788,7 +788,7 @@ namespace = "{}"
|
|||||||
let contents = fs::read_to_string(&self.config_path)
|
let contents = fs::read_to_string(&self.config_path)
|
||||||
.with_context(|| format!("failed to read {}", self.config_path.display()))?;
|
.with_context(|| format!("failed to read {}", self.config_path.display()))?;
|
||||||
let escaped_pattern = pattern.replace('\'', "''");
|
let escaped_pattern = pattern.replace('\'', "''");
|
||||||
let replacement = format!("repo_whitelist = ['{escaped_pattern}']");
|
let replacement = format!("repo_whitelist = '{escaped_pattern}'");
|
||||||
let mut replaced = false;
|
let mut replaced = false;
|
||||||
let mut updated = contents
|
let mut updated = contents
|
||||||
.lines()
|
.lines()
|
||||||
|
|||||||
+15
-15
@@ -22,8 +22,8 @@ fn parses_value_tokens() {
|
|||||||
[[mirrors]]
|
[[mirrors]]
|
||||||
name = "personal"
|
name = "personal"
|
||||||
sync_visibility = "public"
|
sync_visibility = "public"
|
||||||
repo_whitelist = ["^important-", "-mirror$"]
|
repo_whitelist = "^important-|-mirror$"
|
||||||
repo_blacklist = ["-archive$"]
|
repo_blacklist = "-archive$"
|
||||||
create_missing = true
|
create_missing = true
|
||||||
visibility = "private"
|
visibility = "private"
|
||||||
conflict_resolution = "auto_rebase_pull_request"
|
conflict_resolution = "auto_rebase_pull_request"
|
||||||
@@ -51,11 +51,11 @@ fn parses_value_tokens() {
|
|||||||
assert_eq!(config.mirrors[0].sync_visibility, SyncVisibility::Public);
|
assert_eq!(config.mirrors[0].sync_visibility, SyncVisibility::Public);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
config.mirrors[0].repo_whitelist,
|
config.mirrors[0].repo_whitelist,
|
||||||
vec!["^important-".to_string(), "-mirror$".to_string()]
|
Some("^important-|-mirror$".to_string())
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
config.mirrors[0].repo_blacklist,
|
config.mirrors[0].repo_blacklist,
|
||||||
vec!["-archive$".to_string()]
|
Some("-archive$".to_string())
|
||||||
);
|
);
|
||||||
let webhook = config.webhook.unwrap();
|
let webhook = config.webhook.unwrap();
|
||||||
assert!(webhook.install);
|
assert!(webhook.install);
|
||||||
@@ -105,8 +105,8 @@ fn validation_rejects_unknown_sites_and_single_endpoint_groups() {
|
|||||||
namespace: "alice".to_string(),
|
namespace: "alice".to_string(),
|
||||||
}],
|
}],
|
||||||
sync_visibility: SyncVisibility::All,
|
sync_visibility: SyncVisibility::All,
|
||||||
repo_whitelist: Vec::new(),
|
repo_whitelist: None,
|
||||||
repo_blacklist: Vec::new(),
|
repo_blacklist: None,
|
||||||
create_missing: true,
|
create_missing: true,
|
||||||
visibility: Visibility::Private,
|
visibility: Visibility::Private,
|
||||||
conflict_resolution: ConflictResolutionStrategy::Fail,
|
conflict_resolution: ConflictResolutionStrategy::Fail,
|
||||||
@@ -134,8 +134,8 @@ fn validation_rejects_unknown_sites_and_single_endpoint_groups() {
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
sync_visibility: SyncVisibility::All,
|
sync_visibility: SyncVisibility::All,
|
||||||
repo_whitelist: Vec::new(),
|
repo_whitelist: None,
|
||||||
repo_blacklist: Vec::new(),
|
repo_blacklist: None,
|
||||||
create_missing: true,
|
create_missing: true,
|
||||||
visibility: Visibility::Private,
|
visibility: Visibility::Private,
|
||||||
conflict_resolution: ConflictResolutionStrategy::Fail,
|
conflict_resolution: ConflictResolutionStrategy::Fail,
|
||||||
@@ -199,8 +199,8 @@ fn sync_visibility_matches_repo_privacy() {
|
|||||||
#[test]
|
#[test]
|
||||||
fn repo_name_filter_applies_whitelist_then_blacklist() {
|
fn repo_name_filter_applies_whitelist_then_blacklist() {
|
||||||
let mut mirror = mirror_config();
|
let mut mirror = mirror_config();
|
||||||
mirror.repo_whitelist = vec!["^important-".to_string(), "-mirror$".to_string()];
|
mirror.repo_whitelist = Some("^important-|-mirror$".to_string());
|
||||||
mirror.repo_blacklist = vec!["-archive$".to_string()];
|
mirror.repo_blacklist = Some("-archive$".to_string());
|
||||||
let filter = mirror.repo_filter().unwrap();
|
let filter = mirror.repo_filter().unwrap();
|
||||||
|
|
||||||
assert!(filter.matches("important-api"));
|
assert!(filter.matches("important-api"));
|
||||||
@@ -217,7 +217,7 @@ fn validation_rejects_invalid_repo_filter_regex() {
|
|||||||
mirrors: vec![mirror_config()],
|
mirrors: vec![mirror_config()],
|
||||||
webhook: None,
|
webhook: None,
|
||||||
};
|
};
|
||||||
config.mirrors[0].repo_whitelist = vec!["(".to_string()];
|
config.mirrors[0].repo_whitelist = Some("(".to_string());
|
||||||
|
|
||||||
let err = validate_config(&config).unwrap_err().to_string();
|
let err = validate_config(&config).unwrap_err().to_string();
|
||||||
|
|
||||||
@@ -238,8 +238,8 @@ fn validation_rejects_duplicate_mirror_endpoints() {
|
|||||||
name: "broken".to_string(),
|
name: "broken".to_string(),
|
||||||
endpoints: vec![duplicate.clone(), duplicate],
|
endpoints: vec![duplicate.clone(), duplicate],
|
||||||
sync_visibility: SyncVisibility::All,
|
sync_visibility: SyncVisibility::All,
|
||||||
repo_whitelist: Vec::new(),
|
repo_whitelist: None,
|
||||||
repo_blacklist: Vec::new(),
|
repo_blacklist: None,
|
||||||
create_missing: true,
|
create_missing: true,
|
||||||
visibility: Visibility::Private,
|
visibility: Visibility::Private,
|
||||||
conflict_resolution: ConflictResolutionStrategy::Fail,
|
conflict_resolution: ConflictResolutionStrategy::Fail,
|
||||||
@@ -284,8 +284,8 @@ fn mirror_config() -> MirrorConfig {
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
sync_visibility: SyncVisibility::All,
|
sync_visibility: SyncVisibility::All,
|
||||||
repo_whitelist: Vec::new(),
|
repo_whitelist: None,
|
||||||
repo_blacklist: Vec::new(),
|
repo_blacklist: None,
|
||||||
create_missing: true,
|
create_missing: true,
|
||||||
visibility: Visibility::Private,
|
visibility: Visibility::Private,
|
||||||
conflict_resolution: ConflictResolutionStrategy::Fail,
|
conflict_resolution: ConflictResolutionStrategy::Fail,
|
||||||
|
|||||||
+14
-14
@@ -211,8 +211,8 @@ fn wizard_starts_existing_config_at_sync_group_menu() {
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
sync_visibility: SyncVisibility::All,
|
sync_visibility: SyncVisibility::All,
|
||||||
repo_whitelist: Vec::new(),
|
repo_whitelist: None,
|
||||||
repo_blacklist: Vec::new(),
|
repo_blacklist: None,
|
||||||
create_missing: true,
|
create_missing: true,
|
||||||
visibility: Visibility::Private,
|
visibility: Visibility::Private,
|
||||||
conflict_resolution: ConflictResolutionStrategy::Fail,
|
conflict_resolution: ConflictResolutionStrategy::Fail,
|
||||||
@@ -240,8 +240,8 @@ fn wizard_can_ask_to_run_full_sync_after_config() {
|
|||||||
name: "sync-1".to_string(),
|
name: "sync-1".to_string(),
|
||||||
endpoints: Vec::new(),
|
endpoints: Vec::new(),
|
||||||
sync_visibility: SyncVisibility::All,
|
sync_visibility: SyncVisibility::All,
|
||||||
repo_whitelist: Vec::new(),
|
repo_whitelist: None,
|
||||||
repo_blacklist: Vec::new(),
|
repo_blacklist: None,
|
||||||
create_missing: true,
|
create_missing: true,
|
||||||
visibility: Visibility::Private,
|
visibility: Visibility::Private,
|
||||||
conflict_resolution: ConflictResolutionStrategy::Fail,
|
conflict_resolution: ConflictResolutionStrategy::Fail,
|
||||||
@@ -316,8 +316,8 @@ fn wizard_edits_existing_sync_group_from_menu() {
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
sync_visibility: SyncVisibility::Private,
|
sync_visibility: SyncVisibility::Private,
|
||||||
repo_whitelist: vec!["^important-".to_string()],
|
repo_whitelist: Some("^important-".to_string()),
|
||||||
repo_blacklist: vec!["-archive$".to_string()],
|
repo_blacklist: Some("-archive$".to_string()),
|
||||||
create_missing: false,
|
create_missing: false,
|
||||||
visibility: Visibility::Public,
|
visibility: Visibility::Public,
|
||||||
conflict_resolution: ConflictResolutionStrategy::Fail,
|
conflict_resolution: ConflictResolutionStrategy::Fail,
|
||||||
@@ -357,8 +357,8 @@ fn wizard_edits_existing_sync_group_from_menu() {
|
|||||||
assert_eq!(mirror.endpoints[1].namespace, "bob");
|
assert_eq!(mirror.endpoints[1].namespace, "bob");
|
||||||
assert!(!mirror.create_missing);
|
assert!(!mirror.create_missing);
|
||||||
assert_eq!(mirror.sync_visibility, SyncVisibility::Public);
|
assert_eq!(mirror.sync_visibility, SyncVisibility::Public);
|
||||||
assert_eq!(mirror.repo_whitelist, vec!["^public-".to_string()]);
|
assert_eq!(mirror.repo_whitelist, Some("^public-".to_string()));
|
||||||
assert_eq!(mirror.repo_blacklist, vec!["-skip$".to_string()]);
|
assert_eq!(mirror.repo_blacklist, Some("-skip$".to_string()));
|
||||||
assert_eq!(mirror.visibility, Visibility::Public);
|
assert_eq!(mirror.visibility, Visibility::Public);
|
||||||
let output = String::from_utf8(output).unwrap();
|
let output = String::from_utf8(output).unwrap();
|
||||||
assert!(output.contains("Edit sync group"));
|
assert!(output.contains("Edit sync group"));
|
||||||
@@ -403,8 +403,8 @@ fn wizard_prefills_existing_sync_group_when_editing() {
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
sync_visibility: SyncVisibility::All,
|
sync_visibility: SyncVisibility::All,
|
||||||
repo_whitelist: Vec::new(),
|
repo_whitelist: None,
|
||||||
repo_blacklist: Vec::new(),
|
repo_blacklist: None,
|
||||||
create_missing: true,
|
create_missing: true,
|
||||||
visibility: Visibility::Private,
|
visibility: Visibility::Private,
|
||||||
conflict_resolution: ConflictResolutionStrategy::Fail,
|
conflict_resolution: ConflictResolutionStrategy::Fail,
|
||||||
@@ -467,8 +467,8 @@ fn wizard_deletes_existing_sync_group_from_menu() {
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
sync_visibility: SyncVisibility::All,
|
sync_visibility: SyncVisibility::All,
|
||||||
repo_whitelist: Vec::new(),
|
repo_whitelist: None,
|
||||||
repo_blacklist: Vec::new(),
|
repo_blacklist: None,
|
||||||
create_missing: true,
|
create_missing: true,
|
||||||
visibility: Visibility::Private,
|
visibility: Visibility::Private,
|
||||||
conflict_resolution: ConflictResolutionStrategy::Fail,
|
conflict_resolution: ConflictResolutionStrategy::Fail,
|
||||||
@@ -526,8 +526,8 @@ fn wizard_can_go_back_from_delete_menu() {
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
sync_visibility: SyncVisibility::All,
|
sync_visibility: SyncVisibility::All,
|
||||||
repo_whitelist: Vec::new(),
|
repo_whitelist: None,
|
||||||
repo_blacklist: Vec::new(),
|
repo_blacklist: None,
|
||||||
create_missing: true,
|
create_missing: true,
|
||||||
visibility: Visibility::Private,
|
visibility: Visibility::Private,
|
||||||
conflict_resolution: ConflictResolutionStrategy::Fail,
|
conflict_resolution: ConflictResolutionStrategy::Fail,
|
||||||
|
|||||||
@@ -531,7 +531,7 @@ where
|
|||||||
W: Write,
|
W: Write,
|
||||||
{
|
{
|
||||||
let existing = existing.cloned().unwrap_or_default();
|
let existing = existing.cloned().unwrap_or_default();
|
||||||
let has_existing = !existing.whitelist.is_empty() || !existing.blacklist.is_empty();
|
let has_existing = existing.whitelist.is_some() || existing.blacklist.is_some();
|
||||||
if !prompt_bool(
|
if !prompt_bool(
|
||||||
reader,
|
reader,
|
||||||
writer,
|
writer,
|
||||||
@@ -542,40 +542,34 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
Ok(RepoFilterInput {
|
Ok(RepoFilterInput {
|
||||||
whitelist: prompt_repo_pattern_list(
|
whitelist: prompt_repo_pattern(
|
||||||
reader,
|
reader,
|
||||||
writer,
|
writer,
|
||||||
"Whitelist regexes (comma-separated, empty means all repo names)",
|
"Whitelist regex (empty means all repo names)",
|
||||||
&existing.whitelist,
|
&existing.whitelist,
|
||||||
)?,
|
)?,
|
||||||
blacklist: prompt_repo_pattern_list(
|
blacklist: prompt_repo_pattern(reader, writer, "Blacklist regex", &existing.blacklist)?,
|
||||||
reader,
|
|
||||||
writer,
|
|
||||||
"Blacklist regexes (comma-separated)",
|
|
||||||
&existing.blacklist,
|
|
||||||
)?,
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn prompt_repo_pattern_list<R, W>(
|
fn prompt_repo_pattern<R, W>(
|
||||||
reader: &mut R,
|
reader: &mut R,
|
||||||
writer: &mut W,
|
writer: &mut W,
|
||||||
label: &str,
|
label: &str,
|
||||||
existing: &[String],
|
existing: &Option<String>,
|
||||||
) -> Result<Vec<String>>
|
) -> Result<Option<String>>
|
||||||
where
|
where
|
||||||
R: BufRead,
|
R: BufRead,
|
||||||
W: Write,
|
W: Write,
|
||||||
{
|
{
|
||||||
let value = if existing.is_empty() {
|
let value = match existing {
|
||||||
prompt_optional(reader, writer, label)?
|
Some(existing) => prompt_with_default(reader, writer, label, existing)?,
|
||||||
} else {
|
None => prompt_optional(reader, writer, label)?,
|
||||||
prompt_with_default(reader, writer, label, &existing.join(", "))?
|
|
||||||
};
|
};
|
||||||
if let Err(error) = validate_repo_pattern_list(&value) {
|
if let Err(error) = validate_repo_pattern(&value) {
|
||||||
bail!(error);
|
bail!(error);
|
||||||
}
|
}
|
||||||
Ok(parse_repo_pattern_list(&value))
|
Ok(parse_repo_pattern(&value))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn sync_visibility_value(sync_visibility: &SyncVisibility) -> &'static str {
|
fn sync_visibility_value(sync_visibility: &SyncVisibility) -> &'static str {
|
||||||
|
|||||||
+3
-3
@@ -344,7 +344,7 @@ fn all_visibility_keeps_state_only_repos_for_deletion_detection() {
|
|||||||
#[test]
|
#[test]
|
||||||
fn repo_name_filters_do_not_treat_state_only_repos_as_deleted() {
|
fn repo_name_filters_do_not_treat_state_only_repos_as_deleted() {
|
||||||
let mut mirror = test_mirror();
|
let mut mirror = test_mirror();
|
||||||
mirror.repo_whitelist = vec!["^public-".to_string()];
|
mirror.repo_whitelist = Some("^public-".to_string());
|
||||||
let repo_filter = mirror.repo_filter().unwrap();
|
let repo_filter = mirror.repo_filter().unwrap();
|
||||||
let mut ref_state = RefState::default();
|
let mut ref_state = RefState::default();
|
||||||
ref_state.set_repo(
|
ref_state.set_repo(
|
||||||
@@ -472,8 +472,8 @@ fn test_mirror() -> MirrorConfig {
|
|||||||
name: "sync-1".to_string(),
|
name: "sync-1".to_string(),
|
||||||
endpoints: vec![endpoint("github"), endpoint("gitea")],
|
endpoints: vec![endpoint("github"), endpoint("gitea")],
|
||||||
sync_visibility: crate::config::SyncVisibility::All,
|
sync_visibility: crate::config::SyncVisibility::All,
|
||||||
repo_whitelist: Vec::new(),
|
repo_whitelist: None,
|
||||||
repo_blacklist: Vec::new(),
|
repo_blacklist: None,
|
||||||
create_missing: true,
|
create_missing: true,
|
||||||
visibility: crate::config::Visibility::Private,
|
visibility: crate::config::Visibility::Private,
|
||||||
conflict_resolution: ConflictResolutionStrategy::Fail,
|
conflict_resolution: ConflictResolutionStrategy::Fail,
|
||||||
|
|||||||
@@ -112,8 +112,8 @@ fn matches_jobs_by_provider_and_namespace() {
|
|||||||
endpoint("gitea", NamespaceKind::User, "azalea"),
|
endpoint("gitea", NamespaceKind::User, "azalea"),
|
||||||
],
|
],
|
||||||
sync_visibility: SyncVisibility::All,
|
sync_visibility: SyncVisibility::All,
|
||||||
repo_whitelist: Vec::new(),
|
repo_whitelist: None,
|
||||||
repo_blacklist: Vec::new(),
|
repo_blacklist: None,
|
||||||
create_missing: true,
|
create_missing: true,
|
||||||
visibility: Visibility::Private,
|
visibility: Visibility::Private,
|
||||||
conflict_resolution: ConflictResolutionStrategy::Fail,
|
conflict_resolution: ConflictResolutionStrategy::Fail,
|
||||||
@@ -139,8 +139,8 @@ fn matching_jobs_respects_repo_name_filters() {
|
|||||||
name: "sync-1".to_string(),
|
name: "sync-1".to_string(),
|
||||||
endpoints: vec![endpoint("github", NamespaceKind::User, "alice")],
|
endpoints: vec![endpoint("github", NamespaceKind::User, "alice")],
|
||||||
sync_visibility: SyncVisibility::All,
|
sync_visibility: SyncVisibility::All,
|
||||||
repo_whitelist: vec!["^important-".to_string()],
|
repo_whitelist: Some("^important-".to_string()),
|
||||||
repo_blacklist: vec!["-archive$".to_string()],
|
repo_blacklist: Some("-archive$".to_string()),
|
||||||
create_missing: true,
|
create_missing: true,
|
||||||
visibility: Visibility::Private,
|
visibility: Visibility::Private,
|
||||||
conflict_resolution: ConflictResolutionStrategy::Fail,
|
conflict_resolution: ConflictResolutionStrategy::Fail,
|
||||||
@@ -159,7 +159,7 @@ fn matching_jobs_respects_repo_name_filters() {
|
|||||||
assert!(matching_jobs(&config, &webhook_event("important-archive")).is_empty());
|
assert!(matching_jobs(&config, &webhook_event("important-archive")).is_empty());
|
||||||
assert!(matching_jobs(&config, &webhook_event("random")).is_empty());
|
assert!(matching_jobs(&config, &webhook_event("random")).is_empty());
|
||||||
|
|
||||||
mirror.repo_whitelist.clear();
|
mirror.repo_whitelist = None;
|
||||||
let config = Config {
|
let config = Config {
|
||||||
jobs: crate::config::DEFAULT_JOBS,
|
jobs: crate::config::DEFAULT_JOBS,
|
||||||
sites: vec![site("github", ProviderKind::Github)],
|
sites: vec![site("github", ProviderKind::Github)],
|
||||||
@@ -357,8 +357,8 @@ fn uninstall_webhooks_skips_blocked_provider_access() {
|
|||||||
endpoint("github-peer", NamespaceKind::User, "bob"),
|
endpoint("github-peer", NamespaceKind::User, "bob"),
|
||||||
],
|
],
|
||||||
sync_visibility: SyncVisibility::Public,
|
sync_visibility: SyncVisibility::Public,
|
||||||
repo_whitelist: Vec::new(),
|
repo_whitelist: None,
|
||||||
repo_blacklist: Vec::new(),
|
repo_blacklist: None,
|
||||||
create_missing: true,
|
create_missing: true,
|
||||||
visibility: Visibility::Private,
|
visibility: Visibility::Private,
|
||||||
conflict_resolution: ConflictResolutionStrategy::Fail,
|
conflict_resolution: ConflictResolutionStrategy::Fail,
|
||||||
@@ -710,8 +710,8 @@ fn filtered_mirror() -> MirrorConfig {
|
|||||||
endpoint("github-peer", NamespaceKind::User, "bob"),
|
endpoint("github-peer", NamespaceKind::User, "bob"),
|
||||||
],
|
],
|
||||||
sync_visibility: SyncVisibility::Public,
|
sync_visibility: SyncVisibility::Public,
|
||||||
repo_whitelist: vec!["^important-".to_string()],
|
repo_whitelist: Some("^important-".to_string()),
|
||||||
repo_blacklist: vec!["-archive$".to_string()],
|
repo_blacklist: Some("-archive$".to_string()),
|
||||||
create_missing: true,
|
create_missing: true,
|
||||||
visibility: Visibility::Private,
|
visibility: Visibility::Private,
|
||||||
conflict_resolution: ConflictResolutionStrategy::Fail,
|
conflict_resolution: ConflictResolutionStrategy::Fail,
|
||||||
|
|||||||
Reference in New Issue
Block a user