use trusty_mpm::core::policy_labels;
use super::GhRun;
use super::GhRunner;
use super::open::{OpenPlan, created_pr_url};
pub(crate) fn missing_label(stderr: &str) -> Option<&str> {
let rest = stderr.split("could not add label: '").nth(1)?;
let (name, tail) = rest.split_once('\'')?;
tail.trim_start()
.starts_with("not found")
.then_some(name)
.filter(|n| !n.is_empty())
}
pub(crate) fn create<R: GhRunner>(
gh: &R,
plan: &OpenPlan,
repo: Option<&str>,
) -> anyhow::Result<(GhRun, Vec<String>)> {
let mut argv = plan.argv.clone();
let mut pending = plan.create_labels();
let mut dropped = Vec::new();
loop {
let out = gh.run(&argv)?;
if out.success || created_pr_url(&out.stdout).is_some() {
return Ok((out, dropped));
}
let Some(name) = missing_label(&out.stderr).map(str::to_owned) else {
return Ok((out, dropped));
};
if name != policy_labels::CONVENTION_LABEL {
return Ok((out, dropped));
}
let Some(at) = pending.iter().position(|l| *l == name) else {
return Ok((out, dropped));
};
pending.remove(at);
if seed_convention_label(gh, repo) {
continue;
}
eprintln!(
" warning: this repository has no `{name}` label and it could not be created; \
opening the PR without it"
);
remove_label(&mut argv, &name);
dropped.push(name);
}
}
fn seed_convention_label<R: GhRunner>(gh: &R, repo: Option<&str>) -> bool {
let argv = policy_labels::create_label_argv(&policy_labels::convention_label(), repo, false);
match gh.run(&argv) {
Ok(run) if run.success => {
eprintln!(
" note: created the missing `{}` label",
policy_labels::CONVENTION_LABEL
);
true
}
Ok(run) if label_already_exists(&run.stderr) => {
eprintln!(
" note: the `{}` label already exists (created concurrently)",
policy_labels::CONVENTION_LABEL
);
true
}
Ok(run) => {
eprintln!(
" warning: could not create the `{}` label: {}",
policy_labels::CONVENTION_LABEL,
run.stderr.trim()
);
false
}
Err(e) => {
eprintln!(
" warning: could not create the `{}` label: {e:#}",
policy_labels::CONVENTION_LABEL
);
false
}
}
}
fn label_already_exists(stderr: &str) -> bool {
stderr.to_ascii_lowercase().contains("already exists")
}
fn remove_label(argv: &mut Vec<String>, name: &str) {
if let Some(i) = argv
.windows(2)
.position(|w| w[0] == "--label" && w[1] == name)
{
argv.drain(i..i + 2);
}
}