use fabro_github::{ AutoMergeMethod, GitHubAppCredentials, close_pull_request, create_installation_access_token_for_pr, create_pull_request, enable_auto_merge, get_pull_request, merge_pull_request, resolve_authenticated_url, sign_app_jwt, }; use fabro_test::{GitHubAppOptions, GitHubAppState, TwinGitHub}; const TEST_RSA_KEY: &str = include_str!("../src/testdata/rsa_private.pem"); fn github_credentials() -> GitHubAppCredentials { GitHubAppCredentials { app_id: "42".to_string(), private_key_pem: TEST_RSA_KEY.to_string(), } } fn standard_app_state() -> GitHubAppState { let mut state = GitHubAppState::new(); state.register_app(GitHubAppOptions { app_id: "42".into(), slug: "test-app".into(), owner_login: "acme".into(), public: true, private_key_pem: TEST_RSA_KEY.into(), webhook_secret: None, }); state.add_installation("42", "acme", vec!["widgets".into()], false); state.add_repository( "acme", "widgets", vec!["main".into(), "feature".into()], false, ); state } #[fabro_macros::e2e_test(twin)] async fn create_and_get_pull_request() { let twin = TwinGitHub::start(standard_app_state()).await; let creds = github_credentials(); let created = create_pull_request( &creds, "acme", "widgets", "main", "feature", "Add widgets", "PR body", false, &twin.base_url, ) .await .unwrap(); let pr = get_pull_request(&creds, "acme", "widgets", created.number, &twin.base_url) .await .unwrap(); assert_eq!(pr.title, "Add widgets"); assert_eq!(pr.state, "open"); assert_eq!(pr.head.ref_name, "feature"); assert_eq!(pr.base.ref_name, "main"); twin.shutdown().await; } #[fabro_macros::e2e_test(twin)] async fn create_merge_and_verify_state() { let twin = TwinGitHub::start(standard_app_state()).await; let creds = github_credentials(); let created = create_pull_request( &creds, "acme", "widgets", "main", "feature", "Merge me", "PR body", false, &twin.base_url, ) .await .unwrap(); merge_pull_request( &creds, "acme", "widgets", created.number, "squash", &twin.base_url, ) .await .unwrap(); let pr = get_pull_request(&creds, "acme", "widgets", created.number, &twin.base_url) .await .unwrap(); assert_eq!(pr.state, "closed"); assert_eq!(pr.mergeable, Some(false)); twin.shutdown().await; } #[fabro_macros::e2e_test(twin)] async fn create_close_and_verify_state() { let twin = TwinGitHub::start(standard_app_state()).await; let creds = github_credentials(); let created = create_pull_request( &creds, "acme", "widgets", "main", "feature", "Close me", "PR body", false, &twin.base_url, ) .await .unwrap(); close_pull_request(&creds, "acme", "widgets", created.number, &twin.base_url) .await .unwrap(); let pr = get_pull_request(&creds, "acme", "widgets", created.number, &twin.base_url) .await .unwrap(); assert_eq!(pr.state, "closed"); twin.shutdown().await; } #[fabro_macros::e2e_test(twin)] async fn enable_auto_merge_persists() { let twin = TwinGitHub::start(standard_app_state()).await; let creds = github_credentials(); let created = create_pull_request( &creds, "acme", "widgets", "main", "feature", "Auto merge me", "PR body", false, &twin.base_url, ) .await .unwrap(); enable_auto_merge( &creds, "acme", "widgets", &created.node_id, AutoMergeMethod::Squash, &twin.base_url, ) .await .unwrap(); let jwt = sign_app_jwt(&creds.app_id, &creds.private_key_pem).unwrap(); let client = fabro_test::test_http_client(); let token = create_installation_access_token_for_pr(&client, &jwt, "acme", "widgets", &twin.base_url) .await .unwrap(); let detail: serde_json::Value = fabro_test::test_http_client() .get(format!( "{}/repos/acme/widgets/pulls/{}", twin.base_url, created.number )) .header("Authorization", format!("Bearer {token}")) .header("Accept", "application/vnd.github+json") .header("User-Agent", "fabro") .send() .await .unwrap() .json() .await .unwrap(); assert_eq!( detail["auto_merge"]["merge_method"].as_str(), Some("SQUASH") ); twin.shutdown().await; } #[fabro_macros::e2e_test(twin)] async fn resolve_authenticated_url_embeds_token() { let twin = TwinGitHub::start(standard_app_state()).await; let creds = github_credentials(); let url = resolve_authenticated_url( &creds, "https://github.com/acme/widgets.git", &twin.base_url, ) .await .unwrap(); assert!(url.starts_with("https://x-access-token:ghs_")); assert!(url.contains("github.com/acme/widgets.git")); twin.shutdown().await; } #[fabro_macros::e2e_test(twin)] async fn resolve_authenticated_url_errors_on_non_github_url() { let twin = TwinGitHub::start(standard_app_state()).await; let creds = github_credentials(); let error = resolve_authenticated_url(&creds, "https://gitlab.com/foo/bar", &twin.base_url) .await .unwrap_err(); assert!(error.contains("Not a GitHub HTTPS URL")); twin.shutdown().await; }