@@ -75,6 +75,20 @@ def check_parallel_results(results, op):
75
75
76
76
77
77
def confirm_tag_in_repo (tag , repo_name ):
78
+ # type: (str, str) -> str | None
79
+ """Confirm that a given tag exists in a git repository. This function
80
+ assumes that the repository is already a current working directory before
81
+ it's called.
82
+
83
+ Args:
84
+ tag (str): tag to look up in the repository
85
+ repo_name (str): name the repository for the look up, used for logging
86
+
87
+ Returns:
88
+ str | None: returns `tag` argument value or `None` if the tag doesn't
89
+ exist.
90
+ """
91
+
78
92
tag_exists = shell .capture (['git' , 'ls-remote' , '--tags' ,
79
93
'origin' , tag ], echo = False )
80
94
if not tag_exists :
@@ -97,6 +111,21 @@ def find_rev_by_timestamp(timestamp, repo_name, refspec):
97
111
98
112
def get_branch_for_repo (config , repo_name , scheme_name , scheme_map ,
99
113
cross_repos_pr ):
114
+ """Infer, fetch, and return a branch corresponding to a given PR, otherwise
115
+ return a branch found in the config for this repository name.
116
+
117
+ Args:
118
+ config (Dict[str, Any]): deserialized `update-checkout-config.json`
119
+ repo_name (str): name of the repository for checking out the branch
120
+ scheme_name (str): name of the scheme to look up in the config
121
+ scheme_map (Dict[str, str]): map of repo names to branches to check out
122
+ cross_repos_pr (Dict[str, str]): map of repo ids to PRs to check out
123
+
124
+ Returns:
125
+ Tuple[str, bool]: a pair of a checked out branch and a boolean
126
+ indicating whether this repo matched any `cross_repos_pr`.
127
+ """
128
+
100
129
cross_repo = False
101
130
repo_branch = scheme_name
102
131
if scheme_map :
@@ -240,28 +269,54 @@ def update_single_repository(pool_args):
240
269
return value
241
270
242
271
243
- def get_timestamp_to_match (args ):
244
- if not args .match_timestamp :
272
+ def get_timestamp_to_match (match_timestamp , source_root ):
273
+ # type: (str | None, str) -> str | None
274
+ """Computes a timestamp of the last commit on the current branch in
275
+ the `swift` repository.
276
+
277
+ Args:
278
+ match_timestamp (str | None): value of `--match-timestamp` to check.
279
+ source_root (str): directory that contains sources of the Swift project.
280
+
281
+ Returns:
282
+ str | None: a timestamp of the last commit of `swift` repository if
283
+ `match_timestamp` argument has a value, `None` if `match_timestamp` is
284
+ falsy.
285
+ """
286
+ if not match_timestamp :
245
287
return None
246
- with shell .pushd (os .path .join (args . source_root , "swift" ),
288
+ with shell .pushd (os .path .join (source_root , "swift" ),
247
289
dry_run = False , echo = False ):
248
290
return shell .capture (["git" , "log" , "-1" , "--format=%cI" ],
249
291
echo = False ).strip ()
250
292
251
293
252
- def update_all_repositories (args , config , scheme_name , cross_repos_pr ):
253
- scheme_map = None
294
+ def get_scheme_map (config , scheme_name ):
295
+ """Find a mapping from repository IDs to branches in the config.
296
+
297
+ Args:
298
+ config (Dict[str, Any]): deserialized `update-checkout-config.json`
299
+ scheme_name (str): name of the scheme to look up in `config`
300
+
301
+ Returns:
302
+ Dict[str, str]: a mapping from repos to branches for the given scheme.
303
+ """
304
+
254
305
if scheme_name :
255
306
# This loop is only correct, since we know that each alias set has
256
307
# unique contents. This is checked by validate_config. Thus the first
257
308
# branch scheme data that has scheme_name as one of its aliases is
258
309
# the only possible correct answer.
259
310
for v in config ['branch-schemes' ].values ():
260
311
if scheme_name in v ['aliases' ]:
261
- scheme_map = v ['repos' ]
262
- break
312
+ return v ['repos' ]
313
+
314
+ return None
315
+
316
+
317
+ def update_all_repositories (args , config , scheme_name , scheme_map , cross_repos_pr ):
263
318
pool_args = []
264
- timestamp = get_timestamp_to_match (args )
319
+ timestamp = get_timestamp_to_match (args . match_timestamp , args . source_root )
265
320
for repo_name in config ['repos' ].keys ():
266
321
if repo_name in args .skip_repository_list :
267
322
print ("Skipping update of '" + repo_name + "', requested by user" )
@@ -471,6 +526,18 @@ def full_target_name(repository, target):
471
526
472
527
473
528
def skip_list_for_platform (config , all_repos ):
529
+ """Computes a list of repositories to skip when updating or cloning, if not
530
+ overriden by `--all-repositories` CLI argument.
531
+
532
+ Args:
533
+ config (Dict[str, Any]): deserialized `update-checkout-config.json`
534
+ all_repos (List[str]): repositories not required for current platform.
535
+
536
+ Returns:
537
+ List[str]: a resulting list of repositories to skip or empty list if
538
+ `all_repos` is not empty.
539
+ """
540
+
474
541
if all_repos :
475
542
return [] # Do not skip any platform-specific repositories
476
543
@@ -598,22 +665,14 @@ def main():
598
665
clone_with_ssh = args .clone_with_ssh
599
666
skip_history = args .skip_history
600
667
skip_tags = args .skip_tags
601
- scheme = args .scheme
668
+ scheme_name = args .scheme
602
669
github_comment = args .github_comment
603
670
all_repos = args .all_repositories
604
671
605
672
with open (args .config ) as f :
606
673
config = json .load (f )
607
674
validate_config (config )
608
675
609
- if args .dump_hashes :
610
- dump_repo_hashes (args , config )
611
- return (None , None )
612
-
613
- if args .dump_hashes_config :
614
- dump_repo_hashes (args , config , args .dump_hashes_config )
615
- return (None , None )
616
-
617
676
cross_repos_pr = {}
618
677
if github_comment :
619
678
regex_pr = r'(apple/[-a-zA-Z0-9_]+/pull/\d+|apple/[-a-zA-Z0-9_]+#\d+)'
@@ -622,22 +681,51 @@ def main():
622
681
repos_with_pr = [pr .replace ('/pull/' , '#' ) for pr in repos_with_pr ]
623
682
cross_repos_pr = dict (pr .split ('#' ) for pr in repos_with_pr )
624
683
684
+ # If branch is None, default to using the default branch alias
685
+ # specified by our configuration file.
686
+ if scheme_name is None :
687
+ scheme_name = config ['default-branch-scheme' ]
688
+
689
+ scheme_map = get_scheme_map (config , scheme_name )
690
+
625
691
clone_results = None
692
+ skip_repo_list = []
626
693
if clone or clone_with_ssh :
627
- # If branch is None, default to using the default branch alias
628
- # specified by our configuration file.
629
- if scheme is None :
630
- scheme = config ['default-branch-scheme' ]
631
-
632
694
skip_repo_list = skip_list_for_platform (config , all_repos )
633
695
skip_repo_list .extend (args .skip_repository_list )
634
696
clone_results = obtain_all_additional_swift_sources (args , config ,
635
697
clone_with_ssh ,
636
- scheme ,
698
+ scheme_name ,
637
699
skip_history ,
638
700
skip_tags ,
639
701
skip_repo_list )
640
702
703
+ swift_repo_path = os .path .join (args .source_root , 'swift' )
704
+ if 'swift' not in skip_repo_list and os .path .exists (swift_repo_path ):
705
+ with shell .pushd (swift_repo_path , dry_run = False , echo = True ):
706
+ # Check if `swift` repo itself needs to switch to a cross-repo branch.
707
+ branch_name , cross_repo = get_branch_for_repo (config , 'swift' ,
708
+ scheme_name ,
709
+ scheme_map ,
710
+ cross_repos_pr )
711
+
712
+ if cross_repo :
713
+ shell .run (['git' , 'checkout' , branch_name ], echo = True ,
714
+ prefix = "[swift] " )
715
+
716
+ # Re-read the config after checkout.
717
+ with open (args .config ) as f :
718
+ config = json .load (f )
719
+ validate_config (config )
720
+
721
+ if args .dump_hashes :
722
+ dump_repo_hashes (args , config )
723
+ return (None , None )
724
+
725
+ if args .dump_hashes_config :
726
+ dump_repo_hashes (args , config , args .dump_hashes_config )
727
+ return (None , None )
728
+
641
729
# Quick check whether somebody is calling update in an empty directory
642
730
directory_contents = os .listdir (args .source_root )
643
731
if not ('cmark' in directory_contents or
@@ -646,8 +734,8 @@ def main():
646
734
print ("You don't have all swift sources. "
647
735
"Call this script with --clone to get them." )
648
736
649
- update_results = update_all_repositories (args , config , scheme ,
650
- cross_repos_pr )
737
+ update_results = update_all_repositories (args , config , scheme_name ,
738
+ scheme_map , cross_repos_pr )
651
739
fail_count = 0
652
740
fail_count += check_parallel_results (clone_results , "CLONE" )
653
741
fail_count += check_parallel_results (update_results , "UPDATE" )
0 commit comments