1616import logging
1717import os
1818import re
19- from typing import Dict , List
19+ from typing import Dict
20+ from typing import List
21+ from typing import Optional
2022
2123import github
2224from github import Github , InputFileContent
@@ -207,27 +209,35 @@ def validate_and_fetch_pull_list(
207209
208210
209211def format_ci_details (
210- gist_url : str ,
212+ * ,
213+ gist_url : Optional [str ],
211214 extra_build_args : str ,
212215 extra_test_args : str ,
213216 target_release : str ,
214- target_pulls : List [str ],
217+ target_pulls : Optional [List [str ]],
218+ branch_name : Optional [str ],
215219) -> str :
216- pull_text = ', ' .join (target_pulls )
217- return '\n ' .join ([
218- f'Pulls: { pull_text } ' ,
219- f'Gist: { gist_url } ' ,
220+ details = []
221+ if target_pulls :
222+ details .append (f"Pulls: { ', ' .join (target_pulls )} " )
223+ if gist_url :
224+ details .append (f'Gist: { gist_url } ' )
225+ if branch_name :
226+ details .append (f'Branch: { branch_name } ' )
227+ return details + [
220228 f'BUILD args: { extra_build_args } ' ,
221229 f'TEST args: { extra_test_args } ' ,
222230 f'ROS Distro: { target_release } ' ,
223231 'Job: {}' .format (DEFAULT_JOB ),
224- ])
232+ ]
225233
226234
227235def run_jenkins_build (
236+ * ,
228237 build_args : str ,
229238 test_args : str ,
230- gist_url : str ,
239+ gist_url : Optional [str ],
240+ branch_name : Optional [str ],
231241 github_login : str ,
232242 github_token : str ,
233243 target_release : str ,
@@ -237,6 +247,8 @@ def run_jenkins_build(
237247
238248 :returns: Text containing markdown of the build status badges for the launched build.
239249 """
250+ assert gist_url or branch_name , 'Either a gist URL or a branch name must be provided'
251+
240252 # intentionally raises key_error on unknown distro
241253 ubuntu_distro = ROS_DISTRO_TO_UBUNTU_DISTRO [target_release ]
242254 rhel_distro = ROS_DISTRO_TO_RHEL_DISTRO [target_release ]
@@ -264,7 +276,10 @@ def run_jenkins_build(
264276 for p in param_spec
265277 }
266278 # augment with specific values for this PR
267- build_params ['CI_ROS2_REPOS_URL' ] = gist_url
279+ if gist_url :
280+ build_params ['CI_ROS2_REPOS_URL' ] = gist_url
281+ if branch_name :
282+ build_params ['CI_BRANCH_TO_TEST' ] = branch_name
268283 build_params ['CI_ROS_DISTRO' ] = target_release
269284 build_params ['CI_BUILD_ARGS' ] += f' { build_args } '
270285 build_params ['CI_TEST_ARGS' ] += f' { test_args } '
@@ -325,39 +340,56 @@ def comment_results(
325340
326341def parse_args ():
327342 parser = argparse .ArgumentParser (
328- description = 'Generate a CI build request for Pull Request(s)' )
329- group = parser .add_mutually_exclusive_group ()
330- group .add_argument (
343+ description = 'Generate a CI build request for Pull Request(s)' ,
344+ add_help = False )
345+
346+ select_group = parser .add_argument_group (
347+ title = 'change selection' ,
348+ description = 'Select the PRs or branch to test.' )
349+ select_group .add_argument (
350+ '--branch' , type = str ,
351+ help = 'Branch to test across the repositories in the .repos files that have it. Corresponds '
352+ 'to the CI_BRANCH_TO_TEST ci.ros2.org parameter, which means that this branch gets '
353+ 'merged into the distro target branch for testing. When using this option with '
354+ '--comment, the list of PRs to comment on must be specified using the --pulls or '
355+ '--interactive option.' )
356+ pulls_group = select_group .add_mutually_exclusive_group ()
357+ pulls_group .add_argument (
331358 '-p' , '--pulls' , type = str , nargs = '+' ,
332359 help = 'Space-separated list of pull requests to process, in format ORG/REPO#PULLNUMBER '
333- '(e.g. ros2/rclpy#353) or https://github.com/ORG/REPO/pull/PULLNUMBER' )
334- group .add_argument (
360+ '(e.g. ros2/rclpy#353) or https://github.com/ORG/REPO/pull/PULLNUMBER. When using '
361+ 'the --branch and --comment options, comments will be posted on these PRs.' )
362+ pulls_group .add_argument (
335363 '-i' , '--interactive' , action = 'store_true' ,
336- help = 'Prompt me to select my pull requests from a list, instead of specifying.' )
364+ help = 'Prompt me to select my pull requests from a list, instead of specifying. When using '
365+ 'the --branch and --comment options, comments will be posted on these PRs.' )
337366
338- parser .add_argument (
367+ # Create a group for these so that they are displayed below the 'change selection' group
368+ group = parser .add_argument_group (title = 'other options' )
369+ group .add_argument ('-h' , '--help' , action = 'help' )
370+ group .add_argument (
339371 '-k' , '--packages' , type = str , nargs = '+' , default = None ,
340372 help = 'Space-separated list of packages to be built and tested.' )
341- parser .add_argument (
373+ group .add_argument (
342374 '-t' , '--target' , type = str , default = DEFAULT_TARGET ,
343375 help = 'Target distro for PRs; assumes {}.' .format (DEFAULT_TARGET ))
344- parser .add_argument (
376+ group .add_argument (
345377 '-b' , '--build' , action = 'store_true' ,
346378 help = 'Automatically start the build job on Jenkins and print out the resulting badges. '
347379 'Only works if your GitHub user is authorized to run builds.' )
348- parser .add_argument (
380+ group .add_argument (
349381 '-c' , '--comment' , action = 'store_true' ,
350382 help = 'Automatically post a comment on the PRs being built, containing relevant content.' )
351- parser .add_argument (
383+ group .add_argument (
352384 '--only-fixes-test' , action = 'store_true' ,
353385 help = 'The fix being tested only fixes a test, which causes CI to be shorter' )
354- parser .add_argument (
386+ group .add_argument (
355387 '--colcon-build-args' , type = str , default = '' ,
356388 help = 'Arbitrary colcon arguments to specify to build; must be specified with -b' )
357- parser .add_argument (
389+ group .add_argument (
358390 '--colcon-test-args' , type = str , default = '' ,
359391 help = 'Arbitrary colcon arguments to specify to test; must be specified with -b' )
360- parser .add_argument (
392+ group .add_argument (
361393 '--cmake-args' , type = str , default = '' ,
362394 help = 'Arbitrary CMake arguments to specify to build; Each argument shall be prefixed'
363395 ' with -D. CMake arguments shall only be used with -b --build option.' )
@@ -374,17 +406,32 @@ def main():
374406 panic ('Neither environment variable GITHUB_ACCESS_TOKEN nor GITHUB_TOKEN are set' )
375407 github_instance = Github (github_access_token )
376408
377- pull_texts = parsed .pulls
409+ branch_name = parsed .branch
410+ pull_texts = None
411+ chosen_pulls = []
378412 if parsed .interactive :
379413 all_user_pulls = fetch_user_pulls (github_instance )
380414 pull_texts , chosen_pulls = prompt_pull_selection (all_user_pulls )
381- elif not parsed .pulls :
382- panic ('You must either choose --interactive or provide --pulls' )
383- else :
415+ elif parsed .pulls :
384416 chosen_pulls = validate_and_fetch_pull_list (github_instance , parsed .pulls )
385417
386- gist = create_ci_gist (github_instance , chosen_pulls , parsed .target )
387- gist_url = gist .files ['ros2.repos' ].raw_url
418+ # Have to select PRs when not providing branch
419+ if not branch_name and not chosen_pulls :
420+ panic (
421+ 'When not using --branch, you must select PRs either using --interactive '
422+ 'or by providing them using --pulls' )
423+ # Have to select PRs when providing branch and enabling comments
424+ if branch_name and parsed .comment and not chosen_pulls :
425+ panic (
426+ 'When using --branch and --comment, you must select PRs to comment on either using '
427+ '--interactive or by providing them using --pulls' )
428+
429+ # Only create a gist if we specified PRs and not a branch
430+ # We can set both options for ci.ros2.org, but it does not make sense if we select PRs
431+ gist_url = None
432+ if chosen_pulls and not branch_name :
433+ gist = create_ci_gist (github_instance , chosen_pulls , parsed .target )
434+ gist_url = gist .files ['ros2.repos' ].raw_url
388435
389436 if not parsed .build and \
390437 (parsed .colcon_build_args or parsed .colcon_test_args or parsed .cmake_args ):
@@ -407,16 +454,22 @@ def main():
407454 comment_texts = []
408455 comment_texts .append (
409456 format_ci_details (
410- gist_url , extra_build_args , extra_test_args , parsed .target , pull_texts ))
457+ gist_url = gist_url ,
458+ extra_build_args = extra_build_args ,
459+ extra_test_args = extra_test_args ,
460+ target_release = parsed .target ,
461+ target_pulls = pull_texts ,
462+ branch_name = branch_name ))
411463 if parsed .build :
412464 user = github_instance .get_user ().login
413465 comment_texts .append (
414466 run_jenkins_build (
415- extra_build_args ,
416- extra_test_args ,
417- gist_url ,
418- user ,
419- github_access_token ,
467+ build_args = extra_build_args ,
468+ test_args = extra_test_args ,
469+ gist_url = gist_url ,
470+ branch_name = branch_name ,
471+ github_login = user ,
472+ github_token = github_access_token ,
420473 target_release = parsed .target ))
421474
422475 comment_results (parsed .comment , '\n ' .join (comment_texts ), chosen_pulls )
0 commit comments