use anyhow::Context;
use log::info;
use crate::forge::CodeForgeClient;
use crate::model::config::Config;
use super::ReleaseInfo;
pub(crate) async fn upsert_pull_request(
client: &dyn CodeForgeClient,
title: &str,
body: &str,
head: &str,
base: &str,
) -> anyhow::Result<String> {
match client.find_open_pull_request(head).await? {
Some(pr) => client.update_pull_request(pr.number, title, body).await,
None => client.create_pull_request(title, body, head, base).await,
}
}
pub(crate) fn build_pr_body(releases: &[ReleaseInfo], base_branch: &str) -> String {
let mut body = format!(
"This PR was opened by Cursus. When ready to release, you should merge this PR \
which will trigger a release. If you're not ready to do a release then simply leave \
this PR and it will be updated as you merge more changesets into `{base_branch}`.\n\
\n\
# Releases\n"
);
for r in releases {
let _ = std::fmt::Write::write_fmt(
&mut body,
format_args!(
"\n## {}@{}\n\n{}",
r.package_name, r.new_version, r.changelog_entry
),
);
}
body
}
pub(super) async fn upsert_release_pull_request(
config: &Config,
env: &crate::Env,
release_infos: &[ReleaseInfo],
branch: &str,
original_branch: Option<&str>,
dry_run: bool,
) -> anyhow::Result<()> {
if dry_run {
info!(
"Would attempt to create or update a release request on {}.",
env.code_forge_name()
);
return Ok(());
}
let Ok(client) = env.code_forge_client() else {
return Ok(());
};
let base = original_branch.context("HEAD is detached; cannot determine release base branch")?;
let title = config.release_request_title();
let pr_body = build_pr_body(release_infos, base);
upsert_pull_request(client, title, &pr_body, branch, base)
.await
.with_context(|| {
format!(
"Failed to create or update release request on {}",
client.forge_name()
)
})?;
Ok(())
}