mod common;
use common::fixtures::WorkspaceBuilder;
use common::git_helpers;
use common::mock_platform::{
mock_check_runs, mock_get_pr, mock_list_prs, mock_merge_pr, mock_merge_pr_behind,
mock_pr_reviews, setup_github_mock,
};
use gitgrip::core::manifest::{PlatformConfig, PlatformType};
use wiremock::http::Method;
#[tokio::test]
async fn test_pr_merge_no_open_prs() {
let ws = WorkspaceBuilder::new()
.add_repo("frontend")
.add_repo("backend")
.build();
let manifest = ws.load_manifest();
let result = gitgrip::cli::commands::pr::run_pr_merge(
&ws.workspace_root,
&manifest,
&gitgrip::cli::commands::pr::MergeOptions {
method: None,
force: false,
update: false,
auto: false,
json: false,
wait: false,
timeout: 600,
delete_branch: true,
},
)
.await;
assert!(
result.is_ok(),
"pr merge with all repos on default branch should succeed: {:?}",
result.err()
);
}
#[tokio::test]
async fn test_pr_merge_skip_default_branch() {
let ws = WorkspaceBuilder::new()
.add_repo("frontend")
.add_repo("backend")
.build();
let manifest = ws.load_manifest();
git_helpers::create_branch(&ws.repo_path("frontend"), "feat/test");
git_helpers::commit_file(
&ws.repo_path("frontend"),
"test.txt",
"test content",
"Add test file",
);
let result = gitgrip::cli::commands::pr::run_pr_merge(
&ws.workspace_root,
&manifest,
&gitgrip::cli::commands::pr::MergeOptions {
method: None,
force: false,
update: false,
auto: false,
json: false,
wait: false,
timeout: 600,
delete_branch: true,
},
)
.await;
let _ = result; }
#[tokio::test]
async fn test_pr_merge_skip_reference_repos() {
let ws = WorkspaceBuilder::new()
.add_reference_repo("ref-lib")
.add_reference_repo("ref-sdk")
.build();
let manifest = ws.load_manifest();
git_helpers::create_branch(&ws.repo_path("ref-lib"), "feat/update");
git_helpers::commit_file(&ws.repo_path("ref-lib"), "update.txt", "update", "Update");
let result = gitgrip::cli::commands::pr::run_pr_merge(
&ws.workspace_root,
&manifest,
&gitgrip::cli::commands::pr::MergeOptions {
method: None,
force: false,
update: false,
auto: false,
json: false,
wait: false,
timeout: 600,
delete_branch: true,
},
)
.await;
assert!(
result.is_ok(),
"pr merge with only reference repos should succeed: {:?}",
result.err()
);
}
#[tokio::test]
async fn test_pr_merge_mixed_repos_all_skipped() {
let ws = WorkspaceBuilder::new()
.add_repo("app") .add_reference_repo("lib") .build();
let manifest = ws.load_manifest();
git_helpers::create_branch(&ws.repo_path("lib"), "feat/lib-update");
git_helpers::commit_file(&ws.repo_path("lib"), "lib.txt", "lib", "Update lib");
let result = gitgrip::cli::commands::pr::run_pr_merge(
&ws.workspace_root,
&manifest,
&gitgrip::cli::commands::pr::MergeOptions {
method: None,
force: false,
update: false,
auto: false,
json: false,
wait: false,
timeout: 600,
delete_branch: true,
},
)
.await;
assert!(
result.is_ok(),
"pr merge should succeed when all repos are skipped: {:?}",
result.err()
);
}
#[tokio::test]
async fn test_pr_merge_force_bypasses_checks() {
let (server, _adapter) = setup_github_mock().await;
let ws = WorkspaceBuilder::new().add_repo("app").build();
let mut manifest = ws.load_manifest();
git_helpers::create_branch(&ws.repo_path("app"), "feat/test");
git_helpers::commit_file(
&ws.repo_path("app"),
"feature.txt",
"feature",
"Add feature",
);
let repo_config = manifest.repos.get_mut("app").unwrap();
repo_config.url = Some("https://github.com/owner/repo.git".to_string());
repo_config.platform = Some(PlatformConfig {
platform_type: PlatformType::GitHub,
base_url: Some(server.uri()),
});
mock_list_prs(&server, vec![(42, "feat/test")]).await;
mock_get_pr(&server, 42, "open", false).await;
mock_pr_reviews(&server, 42, vec![("COMMENTED", "alice")]).await;
mock_check_runs(&server, "feat/test", vec![("CI", "in_progress", None)]).await;
mock_merge_pr(&server, 42, true).await;
let result = gitgrip::cli::commands::pr::run_pr_merge(
&ws.workspace_root,
&manifest,
&gitgrip::cli::commands::pr::MergeOptions {
method: None,
force: true,
update: false,
auto: false,
json: false,
wait: false,
timeout: 600,
delete_branch: true,
},
)
.await;
assert!(
result.is_ok(),
"force merge should not error: {:?}",
result.err()
);
let requests = server.received_requests().await.unwrap();
assert!(
requests
.iter()
.any(|r| r.method == Method::PUT && r.url.path().ends_with("/merge")),
"expected merge request to be sent"
);
}
#[tokio::test]
async fn test_pr_merge_branch_behind_suggests_update() {
let (server, _adapter) = setup_github_mock().await;
let ws = WorkspaceBuilder::new().add_repo("app").build();
let mut manifest = ws.load_manifest();
git_helpers::create_branch(&ws.repo_path("app"), "feat/test");
git_helpers::commit_file(
&ws.repo_path("app"),
"feature.txt",
"feature",
"Add feature",
);
let repo_config = manifest.repos.get_mut("app").unwrap();
repo_config.url = Some("https://github.com/owner/repo.git".to_string());
repo_config.platform = Some(PlatformConfig {
platform_type: PlatformType::GitHub,
base_url: Some(server.uri()),
});
mock_list_prs(&server, vec![(42, "feat/test")]).await;
mock_get_pr(&server, 42, "open", false).await;
mock_pr_reviews(&server, 42, vec![("APPROVED", "alice")]).await;
mock_check_runs(
&server,
"feat/test",
vec![("CI", "completed", Some("success"))],
)
.await;
mock_merge_pr_behind(&server, 42).await;
let result = gitgrip::cli::commands::pr::run_pr_merge(
&ws.workspace_root,
&manifest,
&gitgrip::cli::commands::pr::MergeOptions {
method: None,
force: true,
update: false,
auto: false,
json: false,
wait: false,
timeout: 600,
delete_branch: true,
},
)
.await;
assert!(
result.is_ok(),
"branch-behind merge should be handled without crashing: {:?}",
result.err()
);
let requests = server.received_requests().await.unwrap();
assert!(
requests
.iter()
.any(|r| r.method == Method::PUT && r.url.path().ends_with("/merge")),
"expected merge attempt for branch-behind case"
);
}
#[tokio::test]
#[ignore = "requires platform injection for API mocking"]
async fn test_pr_merge_all_or_nothing_stops_on_failure() {
}