@@ -4,11 +4,12 @@ use serde::{Deserialize, Serialize};
44use std:: collections:: HashSet ;
55use std:: env;
66use std:: fs;
7+ use std:: path:: PathBuf ;
78
89const REGEX_URL : & str = r"https?://(www\.)?[-a-zA-Z0-9@:%._+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()@:%_+.~#?&/=]*)" ;
910
1011/// Generate a unique directory name using repo owner and name
11- fn generate_dir_name ( repo_url : & str , branch : Option < String > ) -> String {
12+ fn generate_dir_name ( repo_url : & str , branch : Option < & str > ) -> String {
1213 let parts: Vec < & str > = repo_url
1314 . trim_start_matches ( "https://github.com/" )
1415 . split ( '/' )
@@ -18,7 +19,7 @@ fn generate_dir_name(repo_url: &str, branch: Option<String>) -> String {
1819 "queensac_temp_repo/{}/{}/{}" ,
1920 user_name,
2021 repo_name,
21- branch. unwrap_or( "default" . to_string ( ) )
22+ branch. unwrap_or( "default" )
2223 )
2324}
2425
@@ -49,42 +50,33 @@ impl std::hash::Hash for LinkInfo {
4950
5051/// Checkout a specific branch in the repository
5152fn checkout_branch ( repo : & Repository , branch_name : & str ) -> Result < ( ) , git2:: Error > {
52- let remote_branch_name = format ! ( "origin/{}" , branch_name) ;
53- let mut remote = repo. find_remote ( "origin" ) ?;
54-
55- // 특정 브랜치만 fetch
56- let refspec = format ! (
57- "refs/heads/{}:refs/remotes/origin/{}" ,
58- branch_name, branch_name
59- ) ;
60- remote. fetch ( & [ & refspec] , None , None ) ?;
61-
62- let remote_ref = format ! ( "refs/remotes/{}" , remote_branch_name) ;
53+ let remote_branch = format ! ( "origin/{}" , branch_name) ;
6354 let reference = repo
64- . find_reference ( & remote_ref )
55+ . find_reference ( & format ! ( "refs/remotes/{}" , remote_branch ) )
6556 . map_err ( |_| git2:: Error :: from_str ( & format ! ( "Branch not found: {}" , branch_name) ) ) ?;
6657
67- // Create a local branch tracking the remote branch
6858 let commit = reference. peel_to_commit ( ) ?;
69- let branch = repo. branch ( branch_name, & commit, false ) ?;
70- repo. set_head ( branch. get ( ) . name ( ) . unwrap ( ) ) ?;
71- repo. checkout_head ( None ) ?;
72-
59+ repo. checkout_tree ( commit. as_object ( ) , None ) ?;
60+ repo. set_head ( & format ! ( "refs/heads/{}" , branch_name) ) ?;
7361 Ok ( ( ) )
7462}
7563
7664pub fn extract_links_from_repo_url (
7765 repo_url : & str ,
7866 branch : Option < String > ,
7967) -> Result < HashSet < LinkInfo > , git2:: Error > {
80- let temp_dir = env:: temp_dir ( ) . join ( generate_dir_name ( repo_url, branch. clone ( ) ) ) ;
68+ let temp_dir = env:: temp_dir ( ) . join ( generate_dir_name ( repo_url, branch. as_deref ( ) ) ) ;
8169 let _temp_dir_guard = TempDirGuard :: new ( temp_dir. clone ( ) ) . map_err ( |e| {
8270 git2:: Error :: from_str ( & format ! ( "Failed to create temporary directory: {}" , e) )
8371 } ) ?;
72+
73+ // Clone repository
8474 let repo = Repository :: clone ( repo_url, & temp_dir) ?;
8575
86- // 체크아웃 브랜치
76+ // 브랜치가 지정된 경우에만 fetch와 체크아웃 수행
8777 if let Some ( branch_name) = branch {
78+ let mut remote = repo. find_remote ( "origin" ) ?;
79+ remote. fetch ( & [ "refs/heads/*:refs/remotes/origin/*" ] , None , None ) ?;
8880 checkout_branch ( & repo, & branch_name) ?;
8981 }
9082
@@ -118,9 +110,7 @@ pub fn extract_links_from_repo_url(
118110}
119111
120112fn find_link_in_content ( content : & str , file_path : String ) -> HashSet < LinkInfo > {
121- // TODO 정규표현식 캐싱
122113 let url_regex = Regex :: new ( REGEX_URL ) . unwrap ( ) ;
123-
124114 let mut result = HashSet :: new ( ) ;
125115
126116 for ( line_num, line) in content. lines ( ) . enumerate ( ) {
@@ -133,19 +123,19 @@ fn find_link_in_content(content: &str, file_path: String) -> HashSet<LinkInfo> {
133123 result. insert ( LinkInfo {
134124 url,
135125 file_path : file_path. clone ( ) ,
136- line_number : line_num + 1 , // 1-based line number
126+ line_number : line_num + 1 ,
137127 } ) ;
138128 }
139129 }
140130 result
141131}
142132
143133struct TempDirGuard {
144- path : std :: path :: PathBuf ,
134+ path : PathBuf ,
145135}
146136
147137impl TempDirGuard {
148- fn new ( path : std :: path :: PathBuf ) -> std:: io:: Result < Self > {
138+ fn new ( path : PathBuf ) -> std:: io:: Result < Self > {
149139 if path. exists ( ) {
150140 fs:: remove_dir_all ( & path) ?;
151141 }
@@ -284,4 +274,58 @@ mod tests {
284274 ) ;
285275 }
286276 }
277+
278+ #[ test]
279+ #[ serial]
280+ fn test_checkout_branch_with_valid_branch ( ) {
281+ let repo_url = "https://github.com/reddevilmidzy/woowalog" ;
282+ let temp_dir = env:: temp_dir ( ) . join ( "test_checkout_branch" ) ;
283+ let _temp_dir_guard = TempDirGuard :: new ( temp_dir. clone ( ) ) . unwrap ( ) ;
284+
285+ // Clone repository
286+ let repo = Repository :: clone ( repo_url, & temp_dir) . unwrap ( ) ;
287+
288+ // Fetch all branches
289+ let mut remote = repo. find_remote ( "origin" ) . unwrap ( ) ;
290+ remote
291+ . fetch ( & [ "refs/heads/*:refs/remotes/origin/*" ] , None , None )
292+ . unwrap ( ) ;
293+
294+ // Test checkout with a known existing branch
295+ let result = checkout_branch ( & repo, "main" ) ;
296+ assert ! (
297+ result. is_ok( ) ,
298+ "Should successfully checkout existing branch"
299+ ) ;
300+ }
301+
302+ #[ test]
303+ #[ serial]
304+ fn test_checkout_branch_with_invalid_branch ( ) {
305+ let repo_url = "https://github.com/reddevilmidzy/woowalog" ;
306+ let temp_dir = env:: temp_dir ( ) . join ( "test_checkout_invalid_branch" ) ;
307+ let _temp_dir_guard = TempDirGuard :: new ( temp_dir. clone ( ) ) . unwrap ( ) ;
308+
309+ // Clone repository
310+ let repo = Repository :: clone ( repo_url, & temp_dir) . unwrap ( ) ;
311+
312+ // Fetch all branches
313+ let mut remote = repo. find_remote ( "origin" ) . unwrap ( ) ;
314+ remote
315+ . fetch ( & [ "refs/heads/*:refs/remotes/origin/*" ] , None , None )
316+ . unwrap ( ) ;
317+
318+ // Test checkout with a non-existent branch
319+ let result = checkout_branch ( & repo, "non-existent-branch" ) ;
320+ assert ! (
321+ result. is_err( ) ,
322+ "Should fail to checkout non-existent branch"
323+ ) ;
324+ if let Err ( e) = result {
325+ assert ! (
326+ e. message( ) . contains( "non-existent-branch" ) ,
327+ "Error message should contain the branch name"
328+ ) ;
329+ }
330+ }
287331}
0 commit comments