Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions server/src/routes/feedback/proposed_edits/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -59,12 +59,13 @@ impl EditRequest {
async fn apply_changes_and_generate_description(
&self,
branch_name: &str,
branch_is_new: bool,
) -> anyhow::Result<String> {
let Some(pat) = crate::external::github::GitHub::github_token() else {
anyhow::bail!("Failed to get GitHub token");
};
let url = format!("https://{pat}@github.com/TUM-Dev/NavigaTUM");
let repo = TempRepo::clone_and_checkout(&url, branch_name).await?;
let repo = TempRepo::clone_and_checkout(&url, branch_name, branch_is_new).await?;
let desc = repo.apply_and_gen_description(self, branch_name);
repo.commit(&desc.title).await?;
repo.push().await?;
Expand Down Expand Up @@ -193,9 +194,10 @@ pub async fn propose_edits(
}
None => (branch_name, None),
};
let branch_is_new = pr_number_opt.is_none();

match req_data
.apply_changes_and_generate_description(&branch_to_use)
.apply_changes_and_generate_description(&branch_to_use, branch_is_new)
.await
{
Ok(description) => {
Expand Down
101 changes: 68 additions & 33 deletions server/src/routes/feedback/proposed_edits/tmp_repo.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,40 +11,75 @@ pub struct TempRepo {
branch_name: String,
}
impl TempRepo {
/// Clone the repository and check out `branch_name`.
///
/// When `branch_is_new` is `true`, the repository is cloned from `main` and a new local
/// branch is created from it. When `branch_is_new` is `false`, the branch already exists on
/// the remote (e.g., as part of an in-progress batch PR), so the repository is cloned
/// directly with `--branch` to check out that existing branch. Cloning from `main` in the
/// latter case would cause a diverging history and a rejected push.
#[tracing::instrument]
pub async fn clone_and_checkout(url: &str, branch_name: &str) -> anyhow::Result<Self> {
pub async fn clone_and_checkout(
url: &str,
branch_name: &str,
branch_is_new: bool,
) -> anyhow::Result<Self> {
let dir = tempfile::tempdir()?;

info!(url, target_dir= ?dir,"Cloning repository");
let out = Command::new("git")
.current_dir(&dir)
.arg("clone")
.arg("--depth=1")
.arg(url)
.arg(dir.path())
.output()
.await?;
debug!(output=?out,"git clone output");
if out.status.code() != Some(0) {
anyhow::bail!("git status failed with output: {out:?}");
}

// checkout + create branch
let out = Command::new("git")
.current_dir(&dir)
.arg("checkout")
.arg("-b")
.arg(branch_name)
.arg("main")
.output()
.await?;
debug!(output=?out,"git checkout output");
match out.status.code() {
Some(0) => Ok(Self {
dir,
branch_name: branch_name.to_string(),
}),
_ => anyhow::bail!("git commit failed with output: {out:?}"),
if branch_is_new {
info!(url, target_dir= ?dir, "Cloning repository (new branch)");
let out = Command::new("git")
.current_dir(&dir)
.arg("clone")
.arg("--depth=1")
.arg(url)
.arg(dir.path())
.output()
.await?;
debug!(output=?out,"git clone output");
if out.status.code() != Some(0) {
anyhow::bail!("git clone (new branch) failed with output: {out:?}");
}

// Create a new local branch from main.
let out = Command::new("git")
.current_dir(&dir)
.arg("checkout")
.arg("-b")
.arg(branch_name)
.arg("main")
.output()
.await?;
debug!(output=?out,"git checkout output");
match out.status.code() {
Some(0) => Ok(Self {
dir,
branch_name: branch_name.to_string(),
}),
_ => anyhow::bail!("git checkout failed with output: {out:?}"),
}
} else {
// The branch already exists on the remote; clone it directly so that the local
// history matches and the subsequent push is a fast-forward.
info!(url, target_dir= ?dir, branch_name, "Cloning repository (existing branch)");
let out = Command::new("git")
.current_dir(&dir)
.arg("clone")
.arg("--depth=1")
.arg("--branch")
.arg(branch_name)
.arg(url)
.arg(dir.path())
.output()
.await?;
debug!(output=?out,"git clone output");
match out.status.code() {
Some(0) => Ok(Self {
dir,
branch_name: branch_name.to_string(),
}),
_ => anyhow::bail!("git clone (existing branch) failed with output: {out:?}"),
}
}
}

Expand Down Expand Up @@ -153,7 +188,7 @@ mod tests {
const GIT_URL: &str = "https://github.com/CommanderStorm/dotfiles.git";
#[tokio::test]
async fn test_new() {
let temp_repo = TempRepo::clone_and_checkout(GIT_URL, "branch_does_not_exist")
let temp_repo = TempRepo::clone_and_checkout(GIT_URL, "branch_does_not_exist", true)
.await
.unwrap();
assert!(temp_repo.dir.path().exists());
Expand All @@ -163,7 +198,7 @@ mod tests {

#[tokio::test]
async fn test_checkout_and_commit() {
let temp_repo = TempRepo::clone_and_checkout(GIT_URL, "branch_does_not_exist")
let temp_repo = TempRepo::clone_and_checkout(GIT_URL, "branch_does_not_exist", true)
.await
.unwrap();
// test the branch was created
Expand Down