1616
1717TIME_FORMAT = '%Y-%m-%d-%H-%M-%S'
1818
19- # target -> required branch
19+ # target -> allowed branch(es)
20+ # To lock a target, just assign an empty set: "{}"
21+ # Unlisted targets are not protected then any branch will be allowed
2022PROTECTED_TARGETS = {
21- "v8.2-ci" : "8.2" ,
22- "v8.2-fasttrack" : "8.2" ,
23- "v8.2-incoming" : "8.2" ,
24- "v8.3-ci" : "master" ,
25- "v8.3-fasttrack" : "master" ,
26- "v8.3-incoming" : "master" ,
23+ "v8.2-ci" : { "8.2" } ,
24+ "v8.2-fasttrack" : { "8.2" } ,
25+ "v8.2-incoming" : { "8.2" } ,
26+ "v8.3-ci" : { "master" , "8.3" } ,
27+ "v8.3-fasttrack" : { "master" , "8.3" } ,
28+ "v8.3-incoming" : { "master" , "8.3" } ,
2729}
2830
2931@contextmanager
@@ -46,20 +48,30 @@ def check_git_repo(dirpath):
4648 with cd (dirpath ):
4749 return subprocess .run (['git' , 'diff-index' , '--quiet' , 'HEAD' , '--' ]).returncode == 0
4850
49- def check_commit_is_available_remotely (dirpath , hash , target , warn ):
51+ def check_commit_is_available_remotely (dirpath , sha , target , warn ):
5052 with cd (dirpath ):
51- if not subprocess .check_output (['git' , 'branch' , '-r' , '--contains' , hash ]):
53+ output = subprocess .check_output (['git' , 'branch' , '-r' , '--contains' , sha ])
54+ if not output :
5255 raise Exception ("The current commit is not available in the remote repository" )
56+ logging .debug ('Commit %s is contained in remote branch: %s' , sha , output .decode ().strip ())
57+
5358 if target is not None and re .match (r'v\d+\.\d+-u-.+' , target ):
5459 raise Exception ("Building with a user target requires using --pre-build or --test-build.\n " )
5560 try :
56- expected_branch = PROTECTED_TARGETS .get (target )
57- if (
58- expected_branch is not None
59- and not is_remote_branch_commit (dirpath , hash , expected_branch )
60- ):
61- raise Exception (f"The current commit is not the last commit in the remote branch { expected_branch } .\n "
62- f"This is required when using the protected target { target } .\n " )
61+ allowed_branches = PROTECTED_TARGETS .get (target )
62+ if allowed_branches is None :
63+ logging .debug ('Target %s is not protected, any branch is allowed' , target )
64+ else :
65+ for branch in allowed_branches :
66+ try :
67+ if is_remote_branch_commit (dirpath , sha , branch ):
68+ logging .debug ('Commit %s is on top of branch %s (target: %s)' , sha , branch , target )
69+ break
70+ except Exception as e :
71+ logging .debug ('Ignoring %s' , e )
72+ else :
73+ raise Exception (f"The current commit is not the last commit of any remote allowed branches: { allowed_branches } .\n "
74+ f"This is required when using the protected target { target } ." )
6375 except Exception as e :
6476 if warn :
6577 print (f"warning: { e } " , flush = True )
@@ -152,10 +164,20 @@ def push_bumped_release(git_repo, target, test_build_id, pre_build_id):
152164 return commit
153165
154166def is_remote_branch_commit (git_repo , sha , branch ):
167+ """ Args:
168+ git_repo: URL of git repository
169+ sha: Git hash
170+ branch: remote branch in repository
171+ Returns:
172+ True if commit is on top of an assumed remote branch, false otherwise
173+ Raises:
174+ Exception: If branch is missing from repo, or not reachable
175+ """
155176 with cd (git_repo ):
156- remote_sha = (
157- subprocess .check_output (['git' , 'ls-remote' , 'origin' , f'refs/heads/{ branch } ' ]).decode ().strip ().split ()[0 ]
158- )
177+ references = subprocess .check_output (['git' , 'ls-remote' , 'origin' , f'refs/heads/{ branch } ' ]).decode ().strip ().split ()
178+ if not references :
179+ raise Exception (f'Remote branch "{ branch } " missing or unreachable' )
180+ remote_sha = references [0 ]
159181 return sha == remote_sha
160182
161183def build_id_of (name , candidate ):
0 commit comments