ATLAS Offline Software
Loading...
Searching...
No Matches
python.update_ci_reference_files Namespace Reference

Classes

class  CITest

Functions

 process_log_file (url, branch, test_name)
 process_diffpool_change (text, ami_tag, mr_number, human_readable_date, test_name)
 process_digest_change (text, ami_tag, mr_number, human_readable_date, test_name)
 update_reference_files (actually_update=True, update_local_files=False)
 create_dir_and_copy_refs (test, actually_update=False)
 process_CI_Tests_json (data)
 strip_url (href)
 strip_href (href)
 process_CI_Builds_Summary (project)
 extract_links_from_json (url)
 handle_shared_refs ()
 summarise_failing_tests (check_for_duplicates=True)

Variables

 failing_tests = defaultdict(list)
list dirs_created = []
bool debug = False
 parser
 help
 action
 args = parser.parse_args()
 mr_url = summarise_failing_tests(not args.test_run)
 gl_project = gitlab.Gitlab("https://gitlab.cern.ch").projects.get("atlas/athena")
 mr = gl_project.mergerequests.get(mr_url.split('/')[-1])
 author = mr.author['username']
str remote = f'https://:@gitlab.cern.ch:8443/{author}/athena.git'
str local_branch = f'mr-{mr.iid}'
str msg = 'Would you like to (locally) update digest ref files and/or versions in References.py?'
bool update_local_files = False
 not_in_athena_dir = subprocess.call("git rev-parse --is-inside-work-tree", shell=True)
 commands = update_reference_files(not args.test_run, update_local_files)

Detailed Description

Updates reference files for a given MR, as well as related files (digest ref files, References.py)

This script should be run in the root directory of the athena repository, 
and you should pass in the URL of "CI Builds Summary" page for the MR you are interested in.
i.e. the link that you get from the MR under "Full details available on <this CI monitor view>"

So, for example, if you are interested in MR 66303, you would run this script as follows:
Tools/PROCTools/scripts/update_ci_reference_files.py https://bigpanda.cern.ch/ciview/?rel=MR-63410-2023-10-09-12-27

Running with --test-run will modify local files (so you can test that the changes make sense), and will also print out the commands which would have been executed. Nothing remote is changed! 
This is a good way to check that the proposed changes look rational before actually making in earnest.

Function Documentation

◆ create_dir_and_copy_refs()

python.update_ci_reference_files.create_dir_and_copy_refs ( test,
actually_update = False )
If called with actually_update=False, this function will return a list of commands which would have been executed.

Definition at line 297 of file update_ci_reference_files.py.

297def create_dir_and_copy_refs(test, actually_update=False):
298 """
299 If called with actually_update=False, this function will return a list of commands which would have been executed.
300 """
301 commands = []
302
303 # Nothing to do if test uses a shared reference
304 if test.shared_ref is True:
305 return commands
306
307 if test.new_version_directory not in dirs_created:
308 commands.append("mkdir -p " + test.new_version_directory)
309 dirs_created.append(test.new_version_directory)
310
311 # Copy new directory first, then copy old (in case the new MR did not touch all files)
312 # Important! Use no-clobber for second copy or we will overwrite the new data with old!
313 commands.append("cp " + test.copied_file_path + "* "+ test.new_version_directory+"/")
314 commands.append("cp -n " + test.existing_ref + "/* "+ test.new_version_directory+"/")
315 if actually_update:
316 print(' -> Copying files from {} to {}'.format(test.copied_file_path, test.new_version_directory))
317 try:
318 for command in commands:
319 try:
320 subprocess.call( command, shell=True)
321 except Exception as e:
322 print('Command failed due to:', e)
323 print('Do you have EOS available on this machine?')
324 except Exception as e:
325 print('FATAL: Unable to copy files due to:', e)
326 sys.exit(1)
327
328 f = open(test.new_version_directory+'/info.txt', 'w')
329 f.write('Merge URL: https://gitlab.cern.ch/atlas/athena/-/merge_requests/{}\n'.format(test.mr))
330 f.write('Date: {}\n'.format(test.date))
331 f.write('AMI: {}\n'.format(test.tag))
332 f.write('Test name: {}\n'.format(test.name))
333 f.write('Files copied from: {}\n'.format(test.copied_file_path))
334 f.close()
335
336 return commands
337
void print(char *figname, TCanvas *c1)

◆ extract_links_from_json()

python.update_ci_reference_files.extract_links_from_json ( url)

Definition at line 369 of file update_ci_reference_files.py.

369def extract_links_from_json(url):
370 headers = {'Accept': 'application/json'}
371 r = requests.get(url+'&json', headers=headers)
372 data = r.json()["rows_s"]
373 # First row is header.
374 # Currently this is: 'Release', 'Platform', 'Project', 'git branch<BR>(link to MR)', 'Job time stamp', 'git clone', 'Externals build', 'CMake config', 'Build time', 'Comp. Errors (w/warnings)', 'Test time', 'CI tests errors (w/warnings)', 'Host'
375 for project in data[1:]:
376 process_CI_Builds_Summary(project)
377
378

◆ handle_shared_refs()

python.update_ci_reference_files.handle_shared_refs ( )

Definition at line 379 of file update_ci_reference_files.py.

379def handle_shared_refs():
380 # Tests that are allowed to use the same reference. The key is the test that uses the
381 # reference of its value.
382 shared_refs = {
383 'CITest_DerivationRun2Data_PHYS_MT-test': 'CITest_DerivationRun2Data_PHYS-test',
384 'CITest_DerivationRun2MC_PHYS_MT-test': 'CITest_DerivationRun2MC_PHYS-test',
385 'CITest_DerivationRun3Data_PHYS_MT-test': 'CITest_DerivationRun3Data_PHYS-test',
386 'CITest_DerivationRun3MC_PHYS_MT-test': 'CITest_DerivationRun3MC_PHYS-test',
387 'CITest_DerivationRun2Data_PHYSLITE_MT-test': 'CITest_DerivationRun2Data_PHYSLITE-test',
388 'CITest_DerivationRun2MC_PHYSLITE_MT-test': 'CITest_DerivationRun2MC_PHYSLITE-test',
389 'CITest_DerivationRun3Data_PHYSLITE_MT-test': 'CITest_DerivationRun3Data_PHYSLITE-test',
390 'CITest_DerivationRun3MC_PHYSLITE_MT-test': 'CITest_DerivationRun3MC_PHYSLITE-test',
391 }
392
393 for branch,tests in failing_tests.items():
394 # Create dictionary of ref vs tests
395 refs = defaultdict(list) # tag : [test,...]
396 for test in tests:
397 refs[test.tag].append(test)
398
399 for r, dups in refs.items():
400 if len(dups) <= 1:
401 continue
402 for test in dups:
403 # Mark test as having shared ref if itself and its reference is in the list
404 if (name := shared_refs.get(test.name)) and any(name==t.name for t in dups):
405 test.shared_ref = True
406
407

◆ process_CI_Builds_Summary()

python.update_ci_reference_files.process_CI_Builds_Summary ( project)

Definition at line 354 of file update_ci_reference_files.py.

354def process_CI_Builds_Summary(project):
355 # Each entry is one column in the table. 11th is the tests column.
356 # URL to tests page is in form:
357 # <a href="/testsview/?nightly=MR-CI-builds&rel=MR-66303-2023-10-10-19-08&ar=x86_64-centos7-gcc112-opt&proj=AthGeneration">0 (0)</a>
358 test_counts = strip_href(project[11])
359 # This is e.g. '0 (0)'
360 test_error_counts = int(test_counts.split(' ')[0])
361 if test_error_counts > 0:
362 # Okay, we have an error!
363 project_url = 'https://bigpanda.cern.ch'+strip_url(project[11])
364 headers = {'Accept': 'application/json'}
365 r = requests.get(project_url+'&json', headers=headers)
366 data = r.json()["rows_s"]
367 process_CI_Tests_json(data[1:])
368

◆ process_CI_Tests_json()

python.update_ci_reference_files.process_CI_Tests_json ( data)

Definition at line 338 of file update_ci_reference_files.py.

338def process_CI_Tests_json(data):
339 # Each list entry is one column in the table.
340 for row in data:
341 if ('ERROR' in row[0]):
342 process_log_file(strip_url(row[2]), branch = row[1], test_name=strip_href(row[2]))
343

◆ process_diffpool_change()

python.update_ci_reference_files.process_diffpool_change ( text,
ami_tag,
mr_number,
human_readable_date,
test_name )

Definition at line 115 of file update_ci_reference_files.py.

115def process_diffpool_change(text, ami_tag, mr_number, human_readable_date, test_name):
116 eos_path_root = '/eos/atlas/atlascerngroupdisk/data-art/grid-input/WorkflowReferences/'
117
118 # Copied file path
119 # e.g. from ERROR Copied '../SimulationRun3FullSim/run_s4006/myHITS.pool.root' to '/eos/atlas/atlascerngroupdisk/proj-ascig/gitlabci/MR63410_a84345c776e93f0d7f25d00c9e91e35bcb965d09/SimulationRun3FullSimChecks'
120 copied_file_match = re.search(r'^ERROR Copied.*', text, flags=re.MULTILINE)
121 if not copied_file_match:
122 print("FATAL: Could not find matching copied file")
123 sys.exit(1)
124 copied_file_path = copied_file_match.group().split('to')[1].strip().strip("'").strip("&#x27;")+'/'
125
126 # Reference file paths
127 ref_file_match = re.search(r'INFO Reading the reference file from location.*', text)
128 if not ref_file_match:
129 print("FATAL: Could not find matching reference file")
130 sys.exit(1)
131
132 ref_file_path = ref_file_match.group().split('location')[1].strip()
133 existing_version_number= ref_file_path.split('/')[-2]
134 branch = ref_file_path.split('/')[-4]
135 new_version_number = 'v'+str(int(existing_version_number[1:])+1)
136 new_version_directory = eos_path_root+branch+'/'+ami_tag+'/'+new_version_number
137 old_version_directory = eos_path_root+branch+'/'+ami_tag+'/'+existing_version_number
138 # Copied file path
139 # e.g. from ERROR Copied '../SimulationRun3FullSim/run_s4006/myHITS.pool.root' to '/eos/atlas/atlascerngroupdisk/proj-ascig/gitlabci/MR63410_a84345c776e93f0d7f25d00c9e91e35bcb965d09/SimulationRun3FullSimChecks'
140 copied_file_match = re.search(r'^ERROR Copied.*', text, flags=re.MULTILINE)
141 if not copied_file_match:
142 print("FATAL: Could not find matching copied file")
143 sys.exit(1)
144
145 # Sanity checks
146 ami_tag_check = ref_file_path.split('/')[-3].strip()
147 if ami_tag_check!=ami_tag:
148 print('FATAL: Sanity check: "{}" from reference file path "{}" does not match ami tag "{}" extracted previously.'.format(ami_tag_check, ref_file_path, ami_tag))
149 sys.exit(1)
150
151
152 test = CITest(name=test_name, tag=ami_tag, mr=mr_number, date=human_readable_date, existing_ref = old_version_directory, existing_version = existing_version_number, new_version = new_version_number, new_version_directory = new_version_directory, copied_file_path = copied_file_path, diff=None, type='DiffPool')
153 return test
154
std::vector< std::string > split(const std::string &s, const std::string &t=":")
Definition hcg.cxx:179

◆ process_digest_change()

python.update_ci_reference_files.process_digest_change ( text,
ami_tag,
mr_number,
human_readable_date,
test_name )

Definition at line 155 of file update_ci_reference_files.py.

155def process_digest_change(text, ami_tag, mr_number, human_readable_date, test_name):
156 # Some things aren't so relevant for digest changes
157 existing_version_number = None
158 new_version_directory = None
159 copied_file_path = None
160 new_version_number=None
161
162 # differs from the reference 'q447_AOD_digest.ref' (<):
163 ref_file_match = re.search(
164 r"differs from the reference (?:'|&#x27;)([^'&]+?)(?:'|&#x27;)",
165 text
166 )
167 if not ref_file_match:
168 print("FATAL: Could not find matching reference file")
169 sys.exit(1)
170 ref_file_path = ref_file_match.group(1)
171
172 diff_lines = []
173 diff_started = False # Once we hit the beginning of the diff, we start recording
174 # Diff starts with e.g.
175 # ERROR The output 'q449_AOD_digest.txt' (>) differs from the reference 'q449_AOD_digest.ref' (<):
176 # and ends with next INFO line
177
178 for line in text.split('\n'):
179 if 'differs from the reference' in line:
180 # Start of the diff
181 diff_started = True
182 elif diff_started:
183 if 'INFO' in line:
184 # End of the diff
185 break
186 elif len(line)>0:
187 diff_lines.append(html.unescape(line))
188
189 test = CITest(name=test_name, tag=ami_tag, mr=mr_number, date=human_readable_date, existing_ref = ref_file_path, existing_version = existing_version_number, new_version = new_version_number, new_version_directory = new_version_directory, copied_file_path = copied_file_path, diff=diff_lines, type='Content' if 'content.ref' in ref_file_path else 'Digest')
190 return test
191

◆ process_log_file()

python.update_ci_reference_files.process_log_file ( url,
branch,
test_name )
So now we have a URL to a failing test.
We need to check that the test is failing for the correct reason - namely a reference file which needs updating
The information we need to collect is:
- the AMI tag of the failing tests
- the merge request number
- the location of the reference file
- the location of the copied file
- the name of the test
- the new version number
- the new version directory

Definition at line 64 of file update_ci_reference_files.py.

64def process_log_file(url, branch, test_name):
65 """So now we have a URL to a failing test.
66 We need to check that the test is failing for the correct reason - namely a reference file which needs updating
67 The information we need to collect is:
68 - the AMI tag of the failing tests
69 - the merge request number
70 - the location of the reference file
71 - the location of the copied file
72 - the name of the test
73 - the new version number
74 - the new version directory
75 """
76 page = requests.get(url)
77 text = page.text
78
79 # First check that this looks like a test whose ref files need updating, bail otherwise
80 # INFO All q442 athena steps completed successfully
81 test_match = re.search(r'All (?P<ami_tag>\w+) athena steps completed successfully', text)
82 ami_tag = test_match.group('ami_tag') if test_match else None
83
84 # We have two types of tests, but lets try to extract some common information
85 if not ami_tag:
86 # Okay, maybe it was truncated? Try again.
87 match_attempt_2 = re.search(r'AMIConfig (?P<ami_tag>\w+)', text)
88 if match_attempt_2:
89 ami_tag = match_attempt_2.group('ami_tag')
90
91 if not ami_tag:
92 print('WARNING: Did not find an AMI tag in the test "{}". Ignoring.'.format(test_name))
93 return
94
95 mr_match = re.search(r'ARDOC_TestLog_MR-(?P<mr_number>\d+)-(?P<date>\d{4}-\d{2}-\d{2}-\d{2}-\d{2})', url)
96 if not mr_match:
97 print('FATAL: Could not process the URL as expected. Aborting.')
98 print(url)
99 sys.exit(1)
100
101 mr_number = mr_match.group('mr_number')
102 date = mr_match.group('date')
103 human_readable_date = ':'.join(date.split('-')[0:3]) + " at " + ':'.join(date.split('-')[3:])
104
105 if "Your change breaks the digest in test" in text or 'ERROR Your change modifies the output in test' in text:
106 # Okay, we have a digest change
107 failing_tests[branch].append(process_digest_change(text, ami_tag, mr_number, human_readable_date, test_name))
108
109 if 'ERROR Your change breaks the frozen tier0 policy in test' in text or 'ERROR Your change breaks the frozen derivation policy in test' in text:
110 # DiffPool change
111 failing_tests[branch].append(process_diffpool_change(text, ami_tag, mr_number, human_readable_date, test_name))
112
113 return
114

◆ strip_href()

python.update_ci_reference_files.strip_href ( href)

Definition at line 349 of file update_ci_reference_files.py.

349def strip_href(href):
350 value = href[href.find('>')+1:] # Strip everything up to first >
351 value = value[:value.find('<')]
352 return value
353

◆ strip_url()

python.update_ci_reference_files.strip_url ( href)

Definition at line 344 of file update_ci_reference_files.py.

344def strip_url(href):
345 url = href[href.find('"')+1:] # Strip everything up to first quotation mark
346 url = url[:url.find('"')]
347 return url
348

◆ summarise_failing_tests()

python.update_ci_reference_files.summarise_failing_tests ( check_for_duplicates = True)

Definition at line 408 of file update_ci_reference_files.py.

408def summarise_failing_tests(check_for_duplicates = True):
409 print('Summary of tests which need work:')
410
411 if not failing_tests:
412 print(" -> None found. Aborting.")
413 return None
414
415 mr = None
416 reference_folders = []
417 for branch,tests in failing_tests.items():
418 print (' * Branch: {}'.format(branch))
419 for test in tests:
420 print(' - ', test)
421 if test.type == 'DiffPool':
422 if not test.new_version_directory:
423 print('FATAL: No path to "new version" for test {} of type DiffPool.'.format(test.name))
424 sys.exit(1)
425
426 if os.path.exists(test.new_version_directory):
427 msg = f'WARNING: The directory {test.new_version_directory} already exists. Are you sure you want to overwrite the existing references?'
428 if input("%s (y/N) " % msg).lower() != 'y':
429 sys.exit(1)
430
431 if (not test.shared_ref and test.existing_ref not in reference_folders):
432 reference_folders.append(test.existing_ref)
433 elif check_for_duplicates and not test.shared_ref:
434 print('FATAL: Found two tests which both change the same reference file: {}, which is not supported.'.format(test.existing_ref))
435 print('Consider running again in --test-run mode, to get a copy of the copy commands that could be run.')
436 print('The general advice is to take the largest file (since it will have the most events).')
437 sys.exit(1)
438 mr = test.mr
439 return 'https://gitlab.cern.ch/atlas/athena/-/merge_requests/'+mr
440

◆ update_reference_files()

python.update_ci_reference_files.update_reference_files ( actually_update = True,
update_local_files = False )

Definition at line 192 of file update_ci_reference_files.py.

192def update_reference_files(actually_update=True, update_local_files=False):
193 print()
194 print('Updating reference files')
195 print('========================')
196 commands = []
197 for branch, tests in failing_tests.items():
198 for test in tests:
199 print('Processing test: {} on branch {}'.format(test.name, branch))
200 if test.type == 'DiffPool':
201 if test.shared_ref:
202 print(' * This is a DiffPool test but uses a shared reference. No update needed.')
203 continue
204
205 print(' * This is a DiffPool test, and currently has version {} of {}. Will update References.py with new version.'.format(test.existing_version, test.tag))
206 if actually_update:
207 print(' -> The new version is: {}. Creating directory and copying files on EOS now.'.format(test.new_version))
208 create_dir_and_copy_refs(test, True)
209 else:
210 # We will print these later, so we can sanity check them when in test mode
211 commands.extend(create_dir_and_copy_refs(test, False))
212 # Remove any duplicates, whilst preserving the order
213 commands = list(dict.fromkeys(commands))
214
215 # Now, update local References.py file
216 if update_local_files:
217 data = []
218 if debug:
219 print ('Updating local References.py file with new version {} for tag {}'.format(test.new_version, test.tag))
220 line_found = False
221 with open('Tools/WorkflowTestRunner/python/References.py', 'r') as f:
222 lines = f.readlines()
223 for line in lines:
224 if test.tag in line:
225 if test.existing_version in line:
226 line = line.replace(test.existing_version, test.new_version)
227 else:
228 print('')
229 print('** WARNING: For tag {} we were looking for existing version {}, but the line in the file is: {}'.format(test.tag, test.existing_version, line), end='')
230 print('** Are you sure your branch is up-to-date with main? We cannot update an older version of References.py!')
231 line_found = True
232 data.append(line)
233
234 if not line_found:
235 print('** WARNING - no matching line was found for the AMI tag {} in References.py. Are you sure your branch is up-to-date with main? We cannot update an older version of References.py!'.format(test.tag))
236
237 with open('Tools/WorkflowTestRunner/python/References.py', 'w') as f:
238 f.writelines(data)
239 elif test.type == 'Digest' and update_local_files:
240 print(' * This is a Digest test. Need to update reference file {}.'.format(test.existing_ref))
241 data = []
242
243 diff_line=0 # We will use this to keep track of which line in the diff we are on
244 digest_old = [line for line in test.diff if line.startswith('<')]
245 digest_new = [line for line in test.diff if line.startswith('>')]
246
247 with open('Tools/PROCTools/data/'+test.existing_ref, 'r') as f:
248 lines = f.readlines()
249 for current_line, line in enumerate(lines):
250 split_curr_line = line.split()
251 if (split_curr_line[0] == 'run'): # Skip header line
252 data.append(line)
253 continue
254
255 # So, we expect first two numbers to be run/event respectively
256 if (not split_curr_line[0].isnumeric()) or (not split_curr_line[1].isnumeric()):
257 print('FATAL: Found a line in current digest which does not start with run/event numbers: {}'.format(line))
258 sys.exit(1)
259
260 split_old_diff_line = digest_old[diff_line].split()
261 split_old_diff_line.pop(0) # Remove the < character
262 split_new_diff_line = digest_new[diff_line].split()
263 split_new_diff_line.pop(0) # Remove the > character
264
265 # Let's check to see if the run/event numbers match
266 if split_curr_line[0] == split_old_diff_line[0] and split_curr_line[1] == split_old_diff_line[1]:
267 # Okay so run/event numbers match. Let's just double-check it wasn't already updated
268 if split_curr_line!=split_old_diff_line:
269 print('FATAL: It seems like this line was already changed.')
270 print('Line we expected: {}'.format(test.old_diff_lines[diff_line]))
271 print('Line we got : {}'.format(line))
272 sys.exit(1)
273
274 # Check if the new run/event numbers match
275 if split_curr_line[0] == split_new_diff_line[0] and split_curr_line[1] == split_new_diff_line[1]:
276 #Replace the existing line with the new one, making sure we right align within 12 characters
277 data.append("".join(["{:>12}".format(x) for x in split_new_diff_line])+ '\n')
278 if ((diff_line+1)<len(digest_old)):
279 diff_line+=1
280 continue
281
282 # Otherwise, we just keep the existing line
283 data.append(line)
284
285 print(' -> Updating PROCTools digest file {}'.format(test.existing_ref))
286 with open('Tools/PROCTools/data/'+test.existing_ref, 'w') as f:
287 f.writelines(data)
288 elif test.type == 'Content' and update_local_files:
289 print(' * This is a Content test. Need to update reference file {}.'.format(test.existing_ref))
290 subprocess.run(f'patch --quiet Tools/PROCTools/data/{test.existing_ref}',
291 input='\n'.join(test.diff)+'\n',
292 text=True, shell=True, check=True)
293
294 return commands
295
296

Variable Documentation

◆ action

python.update_ci_reference_files.action

Definition at line 445 of file update_ci_reference_files.py.

◆ args

python.update_ci_reference_files.args = parser.parse_args()

Definition at line 446 of file update_ci_reference_files.py.

◆ author

python.update_ci_reference_files.author = mr.author['username']

Definition at line 469 of file update_ci_reference_files.py.

◆ commands

python.update_ci_reference_files.commands = update_reference_files(not args.test_run, update_local_files)

Definition at line 489 of file update_ci_reference_files.py.

◆ debug

bool python.update_ci_reference_files.debug = False

Definition at line 62 of file update_ci_reference_files.py.

◆ dirs_created

list python.update_ci_reference_files.dirs_created = []

Definition at line 61 of file update_ci_reference_files.py.

◆ failing_tests

python.update_ci_reference_files.failing_tests = defaultdict(list)

Definition at line 60 of file update_ci_reference_files.py.

◆ gl_project

python.update_ci_reference_files.gl_project = gitlab.Gitlab("https://gitlab.cern.ch").projects.get("atlas/athena")

Definition at line 467 of file update_ci_reference_files.py.

◆ help

python.update_ci_reference_files.help

Definition at line 444 of file update_ci_reference_files.py.

◆ local_branch

str python.update_ci_reference_files.local_branch = f'mr-{mr.iid}'

Definition at line 471 of file update_ci_reference_files.py.

◆ mr

python.update_ci_reference_files.mr = gl_project.mergerequests.get(mr_url.split('/')[-1])

Definition at line 468 of file update_ci_reference_files.py.

◆ mr_url

python.update_ci_reference_files.mr_url = summarise_failing_tests(not args.test_run)

Definition at line 461 of file update_ci_reference_files.py.

◆ msg

str python.update_ci_reference_files.msg = 'Would you like to (locally) update digest ref files and/or versions in References.py?'

Definition at line 480 of file update_ci_reference_files.py.

◆ not_in_athena_dir

python.update_ci_reference_files.not_in_athena_dir = subprocess.call("git rev-parse --is-inside-work-tree", shell=True)

Definition at line 483 of file update_ci_reference_files.py.

◆ parser

python.update_ci_reference_files.parser
Initial value:
1= argparse.ArgumentParser(description=__doc__,
2 formatter_class=argparse.RawDescriptionHelpFormatter)

Definition at line 442 of file update_ci_reference_files.py.

◆ remote

str python.update_ci_reference_files.remote = f'https://:@gitlab.cern.ch:8443/{author}/athena.git'

Definition at line 470 of file update_ci_reference_files.py.

◆ update_local_files

bool python.update_ci_reference_files.update_local_files = False

Definition at line 481 of file update_ci_reference_files.py.