@@ -64,35 +64,53 @@ except OSError as import_jenkins_error:
64
64
else :
65
65
raise
66
66
67
- def determine_job_name ( cassandra_dir : Path ) -> str :
67
+ def base_job_name ( args ) -> str :
68
68
"""
69
69
Determines the default Jenkins job name based on the Cassandra version.
70
70
Separate jobs are required because Jenkinsfiles are baked into the job configuration.
71
71
ref: .jenkins/k8s/jenkins-deployment.yaml JCasC.configScripts.test-job
72
- TODO: add new version each release branching
73
72
"""
74
- with open (cassandra_dir / "build.xml" , "r" , encoding = "utf-8" ) as build_file :
75
- for line in build_file :
73
+ if not hasattr (base_job_name , "_cached_result" ):
74
+ raw_url = args .repository .replace ("https://github.com/" , "https://raw.githubusercontent.com/" ).removesuffix (".git" ) + f"/{ args .branch } /build.xml"
75
+ if 200 != requests .head (raw_url ).status_code :
76
+ raise ValueError (f"GitHub unavailable, or this branch has not been pushed yet: { args .repository } @ { args .branch } (or remote tracking not setup up: `git config --get branch.{ args .branch } .remote` and `git config --get branch.{ args .branch } .merge`)" )
77
+ response = requests .get (raw_url )
78
+ response .raise_for_status ()
79
+ for line in response .text .splitlines ():
76
80
if 'property' in line and 'name="base.version"' in line :
77
81
version = line .split ('value="' )[1 ].split ('"' )[0 ]
82
+ # TODO: add new version each release branching
78
83
if version .startswith ("5.0." ):
79
- return "cassandra-5.0"
80
- return "cassandra"
84
+ base_job_name ._cached_result = "cassandra-5.0"
85
+ else :
86
+ base_job_name ._cached_result = "cassandra"
87
+ break
88
+ return base_job_name ._cached_result
81
89
82
90
def get_current_branch () -> str :
83
91
"""Returns the current branch."""
84
92
return subprocess .run (["git" , "-C" , str (CASSANDRA_DIR ), "branch" , "--show-current" ],
85
93
capture_output = True , text = True , check = True ).stdout .strip ()
86
94
95
+ def is_local_git_dirty (args ) -> bool :
96
+ """Returns True if there are uncommitted/unpushed changes in the local git repository."""
97
+ # use base_job_name to verify the remote branch exists
98
+ base_job_name (args )
99
+ # check if the working directory is clean
100
+ clean = subprocess .run (["git" , "-C" , str (CASSANDRA_DIR ), "diff-index" , "--quiet" , "HEAD" , "--" ]).returncode
101
+ # check if there are unpushed committed changes
102
+ unpushed_commits = bool (subprocess .run (["git" , "-C" , str (CASSANDRA_DIR ), "log" , "@{u}..HEAD" , "--name-only" ],
103
+ capture_output = True , text = True , check = False ).stdout .strip ())
104
+ return 0 != clean or unpushed_commits
105
+
87
106
def get_tracking_remote_url () -> str :
88
107
"""
89
108
Returns the tracking remote URL of the current branch, falling back to the 'origin' remote URL.
90
109
"""
91
110
try :
92
111
# Get the tracking remote URL of the current branch
93
- remote_name = subprocess .run (
94
- ["git" , "-C" , str (CASSANDRA_DIR ), "config" , "--get" , f"branch.{ DEFAULT_REPO_BRANCH } .remote" ],
95
- capture_output = True , text = True , check = True ).stdout .strip ()
112
+ remote_name = subprocess .run (["git" , "-C" , str (CASSANDRA_DIR ), "config" , "--get" , f"branch.{ DEFAULT_REPO_BRANCH } .remote" ],
113
+ capture_output = True , text = True , check = True ).stdout .strip ()
96
114
97
115
except subprocess .CalledProcessError :
98
116
# Fallback to the 'origin' remote URL
@@ -102,7 +120,9 @@ def get_tracking_remote_url() -> str:
102
120
capture_output = True , text = True , check = True ).stdout .strip ()
103
121
if repo_url .
startswith (
"[email protected] :" ):
104
122
repo_url = repo_url .
replace (
"[email protected] :" ,
"https://github.com/" )
105
- return repo_url
123
+
124
+ # and change gitbox to github
125
+ return repo_url .replace ("https://gitbox.apache.org/repos/asf/cassandra.git" , "https://github.com/apache/cassandra.git" )
106
126
107
127
# Constants
108
128
DEFAULT_KUBE_NS = "default"
@@ -113,7 +133,6 @@ DEFAULT_REPO_URL = get_tracking_remote_url()
113
133
DEFAULT_DTEST_REPO_URL = "https://github.com/apache/cassandra-dtest.git"
114
134
DEFAULT_DTEST_REPO_BRANCH = "trunk"
115
135
DEFAULT_PROFILE = "skinny"
116
- DEFAULT_JOB_NAME = determine_job_name (CASSANDRA_DIR )
117
136
DEFAULT_POD_NAME = "cassius-jenkins-0"
118
137
DEFAULT_CONTAINER_NAME = "jenkins"
119
138
LOCAL_RESULTS_BASEDIR = CASSANDRA_DIR / "build/ci/"
@@ -306,7 +325,7 @@ def trigger_jenkins_build(server: jenkins.Jenkins, job_name: str, **build_params
306
325
print ("Parameters should now be available." )
307
326
308
327
# Check and trigger non-parameter build if parameters are not visible
309
- check_for_parameter_build (server , DEFAULT_JOB_NAME )
328
+ check_for_parameter_build (server , job_name )
310
329
print ("Triggering Jenkins build… " )
311
330
return server .build_job (job_name , parameters = build_params )
312
331
@@ -587,9 +606,9 @@ def node_cleaner(k8s_client: client.CoreV1Api, kubeconfig: Optional[str], kubeco
587
606
time .sleep (10 )
588
607
589
608
590
- def delete_remote_junit_files (k8s_client , pod_name : str , kube_ns : str , build_number : int ):
609
+ def delete_remote_junit_files (k8s_client , pod_name : str , kube_ns : str , base_job_name : str , build_number : int ):
591
610
debug ("Cleaning remote individual JUnit XML files..." )
592
- exec_command = ['rm' , '-rf' , f'/var/jenkins_home/jobs/{ DEFAULT_JOB_NAME } /builds/{ build_number } /archive/test/output' ]
611
+ exec_command = ['rm' , '-rf' , f'/var/jenkins_home/jobs/{ base_job_name } /builds/{ build_number } /archive/test/output' ]
593
612
stream .stream (k8s_client .connect_get_namespaced_pod_exec ,
594
613
pod_name , kube_ns , container = DEFAULT_CONTAINER_NAME , command = exec_command , stderr = True , stdin = False , stdout = True , tty = False , _preload_content = False )
595
614
debug ("Remote JUnit XML files cleaned." )
@@ -702,8 +721,8 @@ def download_results_and_print_summary(k8s_client, pod_name: str, kube_ns: str,
702
721
ci_summary_file = local_results_dir / f"ci_summary_{ repo_owner } _{ args .branch .replace ('/' , '-' )} _{ build_number } .html"
703
722
ci_details_file = local_results_dir / f"results_details_{ repo_owner } _{ args .branch .replace ('/' , '-' )} _{ build_number } .tar.xz"
704
723
if args .url :
705
- download_url (f"http://{ ip } /job/{ DEFAULT_JOB_NAME } /{ build_number } /artifact/ci_summary.html" , ci_summary_file )
706
- download_url (f"http://{ ip } /job/{ DEFAULT_JOB_NAME } /{ build_number } /artifact/results_details.tar.xz" , ci_details_file )
724
+ download_url (f"http://{ ip } /job/{ base_job_name ( args ) } /{ build_number } /artifact/ci_summary.html" , ci_summary_file )
725
+ download_url (f"http://{ ip } /job/{ base_job_name ( args ) } /{ build_number } /artifact/results_details.tar.xz" , ci_details_file )
707
726
if (ci_summary_file ).exists ():
708
727
print (f"CI summary saved as { ci_summary_file } " )
709
728
if (ci_details_file ).exists ():
@@ -716,7 +735,7 @@ def download_results_and_print_summary(k8s_client, pod_name: str, kube_ns: str,
716
735
kubecontext = args .kubecontext
717
736
local_console_log = local_results_dir / "console_log.txt"
718
737
local_archive_tar = local_results_dir / "archive.tar.gz"
719
- remote_build_dir = f"/var/jenkins_home/jobs/{ DEFAULT_JOB_NAME } /builds/{ build_number } "
738
+ remote_build_dir = f"/var/jenkins_home/jobs/{ base_job_name ( args ) } /builds/{ build_number } "
720
739
remote_console_log_path = f"{ remote_build_dir } /log"
721
740
remote_archive_dir = f"{ remote_build_dir } /archive"
722
741
@@ -822,14 +841,23 @@ def main():
822
841
"dtest_branch" : args .dtest_branch or ""
823
842
}
824
843
825
- queue_item = trigger_jenkins_build (server , DEFAULT_JOB_NAME , ** build_params )
844
+ if DEFAULT_REPO_URL == args .repository and DEFAULT_REPO_BRANCH == args .branch and is_local_git_dirty (args ):
845
+ print ("Local uncommitted/unpushed changes." )
846
+ print (f"CI only runs on what is pushed in { args .repository } @ { args .branch } " )
847
+ print (" See `git diff-index HEAD --` for uncommitted changes" )
848
+ print (" See `git log @{u}.. --name-only` for unpushed changes" )
849
+ print (" Do you want to continue anyway (y/N):" )
850
+ if "y" != input ().strip ().lower ():
851
+ return
852
+
853
+ queue_item = trigger_jenkins_build (server , base_job_name (args ), ** build_params )
826
854
build_number = wait_for_build_number (server , queue_item )
827
- print (f"Jenkins UI at http://{ ip } /job/{ DEFAULT_JOB_NAME } /{ build_number } /pipeline-overview/" )
828
- wait_for_build_complete (server , DEFAULT_JOB_NAME , build_number )
855
+ print (f"Jenkins UI at http://{ ip } /job/{ base_job_name ( args ) } /{ build_number } /pipeline-overview/" )
856
+ wait_for_build_complete (server , base_job_name ( args ) , build_number )
829
857
830
858
# Post-build processing and cleanup
831
859
if not args .url :
832
- delete_remote_junit_files (k8s_client , DEFAULT_POD_NAME , DEFAULT_KUBE_NS , build_number )
860
+ delete_remote_junit_files (k8s_client , DEFAULT_POD_NAME , DEFAULT_KUBE_NS , base_job_name ( args ), build_number )
833
861
download_results_and_print_summary (k8s_client , DEFAULT_POD_NAME , DEFAULT_KUBE_NS , build_number , ip , args )
834
862
cleanup_and_maybe_teardown (args .kubeconfig , args .kubecontext , DEFAULT_KUBE_NS , args .tear_down )
835
863
0 commit comments