1#!/usr/local/bin/python3.8
2# -*- mode: python; py-indent-offset: 4; py-continuation-offset: 4 -*-
3#
4# Change shebang line to '/usr/bin/python -3' for python 3.x porting warnings
5"""
6This script drives a PR testing build.  It assume that Trilinos is already
7cloned under $WORKSPACE/Trilinos and that the 'origin' remote points to
8$TRILINOS_TARGET_REPO (but that is not checked here).
9
10As long as the ${WORKSPACE}/Trilinos git repo has the correct 'origin', this
11script will automatically set it up to do the merge correctly, no matter
12what its state before this script is called (i.e. from a past PR
13attempt). Unless the Trilinos/.git directory becomes corrupted, there should
14*NEVER* be any need to delete and reclone this Trilinos git repo.
15
16This script can be run in a mode where the driver scripts are run from one
17Trilinos git repo and operate on another Trilinos git repo that gets
18manipulated in order to merge the "source" topic branch into the "target"
19branch.  This makes it easy to test changes to the PR scripts.  But if this
20script is run from ${WORKSPACE}/Trilinos, then these repos are one and the same
21and we get the correct behavior for PR testing.
22
23Expectations
24------------
25
26### Environment Variables
27- WORKSPACE : Root level directory for the Jenkins job.
28- MODULESHOME : Path to the location where modulefiles are.
29- CC : C Compiler
30- FC : Fortran Compiler
31- PULLREQUEST_CDASH_TRACK : Which CDash track should this result be published to?
32- JENKINS_JOB_WEIGHT : Number of cores to use to build Trilinos
33
34### Other Expectations?
35
36"""
37from __future__ import print_function
38
39# turn off generation of the .pyc/.pyo files.
40import sys
41sys.dont_write_bytecode = True
42
43import argparse
44import os
45import re
46import sys
47from textwrap import dedent
48
49import subprocess
50from multiprocessing import cpu_count
51
52sys.path.insert(1, os.path.join(os.environ['MODULESHOME'], 'init'))
53
54try:
55    from env_modules_python import module
56except ImportError:
57    def module(*args):
58        if type(args[0]) == type([]):
59            args = args[0]
60        else:
61            args = list(args)
62        (output, error) = subprocess.Popen(['/usr/bin/modulecmd', 'python'] +
63                                           args,
64                                           stdout=subprocess.PIPE).communicate()
65        exec(output)
66
67
68
69def parse_args():
70    parser = argparse.ArgumentParser(description='Parse the repo and build information')
71
72    parser.add_argument('sourceRepo',   action='store', help='Repo with the new changes')
73    parser.add_argument('sourceBranch', action='store', help='Branch with the new changes')
74    parser.add_argument('targetRepo',   action='store', help='Repo to merge into')
75    parser.add_argument('targetBranch', action='store', help='Branch to merge to')
76
77    parser.add_argument('job_base_name',    help='The jenkins job base name')
78    parser.add_argument('github_pr_number', help='The github PR number')
79    parser.add_argument('job_number',       help='The jenkins build number')
80    parser.add_argument('workspaceDir',     help='The local workspace directory jenkins set up')
81
82    arguments = parser.parse_args()
83
84    return arguments
85
86
87def print_input_variables(arguments):
88    print("\n" + "="*90)
89    print("Jenkins Input Variables:")
90    print("- JOB_BASE_NAME: {job_base_name}".format(**vars(arguments)))
91    print("- WORKSPACE    : {workspaceDir}".format(**vars(arguments)))
92    print("\n" + "="*90)
93    print("Parameters:")
94    print("- TRILINOS_SOURCE_REPO  : {sourceRepo}".format(**vars(arguments)))
95    print("- TRILINOS_SOURCE_BRANCH: {sourceBranch}\n".format(**vars(arguments)))
96    print("- TRILINOS_TARGET_REPO  : {targetRepo}".format(**vars(arguments)))
97    print("- TRILINOS_TARGET_BRANCH: {targetBranch}\n".format(**vars(arguments)))
98    print("- PULLREQUESTNUM        : {github_pr_number}".format(**vars(arguments)))
99    print("- BUILD_NUMBER          : {job_number}".format(**vars(arguments)))
100    print("\n" + "="*90)
101
102
103def confirmGitVersion():
104    """
105    Verify that the version of Git we're using is > 2.10
106    """
107    git_version_string = subprocess.check_output(['git', '--version'])
108    git_version_number_string = git_version_string[git_version_string.rfind(' '):]
109    major_git_version = int(git_version_number_string[:git_version_number_string.find('.')])
110    minor_git_version = int(git_version_number_string[git_version_number_string.find('.')+1:
111                                                      git_version_number_string.rfind('.')])
112
113    if major_git_version  <  2 or (major_git_version == 2 and minor_git_version < 10):
114        raise SystemExit("Git version  should be 2.10 or better - Exiting!")
115    else:
116        print(git_version_string)
117
118    return None
119
120
121
122# TODO: moduleMap & environMap should be moved into files.
123#       Let's try YAML since it allows comments, etc.
124def setBuildEnviron(arguments):
125    """
126    TODO: Needs explanation.
127          - How is environMap structured?
128          - How is moduleMap structured?
129    TODO: wcm: Could it be possible to offload environMap and moduleMap into a
130          JSON or Yaml file?  (Yaml allows comments which is more helpful
131          than JSON IMO.)
132    """
133
134    moduleMap = {"Trilinos_pullrequest_gcc_4.8.4":
135                     ["sems-env",
136                     "sems-git/2.10.1",
137                     "sems-gcc/4.8.4",
138                     "sems-openmpi/1.10.1",
139                     "sems-python/2.7.9",
140                     "sems-boost/1.63.0/base",
141                     "sems-zlib/1.2.8/base",
142                     "sems-hdf5/1.10.6/parallel",
143                     "sems-netcdf/4.7.3/parallel",
144                     "sems-parmetis/4.0.3/parallel",
145                     "sems-scotch/6.0.3/nopthread_64bit_parallel",
146                     "sems-superlu/4.3/base",
147                     "sems-cmake/3.10.3",
148                     "atdm-env",
149                     "atdm-ninja_fortran/1.7.2"],
150                 "Trilinos_pullrequest_gcc_4.9.3_SERIAL":
151                     ["sems-env",
152                      "sems-git/2.10.1",
153                      "sems-gcc/4.9.3",
154                      "sems-python/2.7.9",
155                      "sems-boost/1.63.0/base",
156                      "sems-zlib/1.2.8/base",
157                      "sems-hdf5/1.10.6/base",
158                      "sems-netcdf/4.7.3/base",
159                      "sems-metis/5.1.0/base",
160                      "sems-superlu/4.3/base",
161                      "sems-cmake/3.10.3",
162                      "atdm-env",
163                      "atdm-ninja_fortran/1.7.2"],
164                 "Trilinos_pullrequest_python_2":
165                     ["sems-git/2.10.1",
166                      "sems-gcc/7.2.0",
167                      ("", "sems-python/2.7.9"),
168                      "sems-cmake/3.10.3",
169                      "atdm-env",
170                      "atdm-ninja_fortran/1.7.2"],
171                "Trilinos_pullrequest_python_3":
172                     ["sems-git/2.10.1",
173                      "sems-gcc/7.2.0",
174                      ("", "sems-python/2.7.9"),
175                      "sems-cmake/3.10.3",
176                      "atdm-env",
177                      "atdm-ninja_fortran/1.7.2"],
178                "Trilinos_pullrequest_gcc_7.2.0":
179                     ["sems-env",
180                     "sems-git/2.10.1",
181                     "sems-gcc/7.2.0",
182                     "sems-openmpi/1.10.1",
183                     "sems-python/2.7.9",
184                     "sems-boost/1.63.0/base",
185                     "sems-zlib/1.2.8/base",
186                     "sems-hdf5/1.10.6/parallel",
187                     "sems-netcdf/4.7.3/parallel",
188                     "sems-parmetis/4.0.3/parallel",
189                     "sems-scotch/6.0.3/nopthread_64bit_parallel",
190                     "sems-superlu/4.3/base",
191                     "sems-cmake/3.10.3",
192                     "atdm-env",
193                     "atdm-ninja_fortran/1.7.2"],
194                "Trilinos_pullrequest_gcc_7.2.0_debug":
195                     ["sems-env",
196                     "sems-git/2.10.1",
197                     "sems-gcc/7.2.0",
198                     "sems-openmpi/1.10.1",
199                     "sems-python/2.7.9",
200                     "sems-boost/1.63.0/base",
201                     "sems-zlib/1.2.8/base",
202                     "sems-hdf5/1.10.6/parallel",
203                     "sems-netcdf/4.7.3/parallel",
204                     "sems-parmetis/4.0.3/parallel",
205                     "sems-scotch/6.0.3/nopthread_64bit_parallel",
206                     "sems-superlu/4.3/base",
207                     "sems-cmake/3.10.3",
208                     "atdm-env",
209                     "atdm-ninja_fortran/1.7.2"],
210                "Trilinos_pullrequest_gcc_8.3.0":
211                     ["sems-env",
212                     "sems-git/2.10.1",
213                     "sems-gcc/8.3.0",
214                     "sems-openmpi/1.10.1",
215                     "sems-python/2.7.9",
216                     "sems-boost/1.66.0/base",
217                     "sems-zlib/1.2.8/base",
218                     "sems-hdf5/1.10.6/parallel",
219                     "sems-netcdf/4.7.3/parallel",
220                     "sems-parmetis/4.0.3/parallel",
221                     "sems-scotch/6.0.3/nopthread_64bit_parallel",
222                     "sems-superlu/4.3/base",
223                     "sems-cmake/3.17.1",
224                     "sems-ninja_fortran/1.10.0",
225                     "atdm-env"
226                     ],
227                "Trilinos_pullrequest_intel_17.0.1":
228                     ["sems-env",
229                     "sems-git/2.10.1",
230                     "sems-gcc/4.9.3",
231                     "sems-intel/17.0.1",
232                     "sems-mpich/3.2",
233                     "sems-python/2.7.9",
234                     "sems-boost/1.63.0/base",
235                     "sems-zlib/1.2.8/base",
236                     "sems-hdf5/1.10.6/parallel",
237                     "sems-netcdf/4.7.3/parallel",
238                     "sems-parmetis/4.0.3/parallel",
239                     "sems-scotch/6.0.3/nopthread_64bit_parallel",
240                     "sems-superlu/4.3/base",
241                     "sems-cmake/3.10.3",
242                     "atdm-env",
243                     "atdm-ninja_fortran/1.7.2"],
244                "Trilinos_pullrequest_clang_7.0.1":
245                     ["sems-env",
246                     "sems-git/2.10.1",
247                     "sems-gcc/5.3.0",
248                     "sems-clang/7.0.1",
249                     "sems-openmpi/1.10.1",
250                     "sems-python/2.7.9",
251                     "sems-boost/1.63.0/base",
252                     "sems-zlib/1.2.8/base",
253                     "sems-hdf5/1.10.6/parallel",
254                     "sems-netcdf/4.7.3/parallel",
255                     "sems-parmetis/4.0.3/parallel",
256                     "sems-scotch/6.0.3/nopthread_64bit_parallel",
257                     "sems-superlu/4.3/base",
258                     "sems-cmake/3.12.2",
259                     "atdm-env",
260                     "atdm-ninja_fortran/1.7.2"],
261                "Trilinos_pullrequest_clang_9.0.0":
262                     ["sems-env",
263                     "sems-git/2.10.1",
264                     "sems-gcc/5.3.0",
265                     "sems-clang/9.0.0",
266                     "sems-openmpi/1.10.1",
267                     "sems-python/2.7.9",
268                     "sems-boost/1.63.0/base",
269                     "sems-zlib/1.2.8/base",
270                     "sems-hdf5/1.10.6/parallel",
271                     "sems-netcdf/4.7.3/parallel",
272                     "sems-parmetis/4.0.3/parallel",
273                     "sems-scotch/6.0.3/nopthread_64bit_parallel",
274                     "sems-superlu/4.3/base",
275                     "sems-cmake/3.12.2",
276                     "atdm-env",
277                     "atdm-ninja_fortran/1.7.2"],
278                "Trilinos_pullrequest_clang_10.0.0":
279                     ["sems-env",
280                     "sems-git/2.10.1",
281                     "sems-gcc/5.3.0",
282                     "sems-clang/10.0.0",
283                     "sems-openmpi/1.10.1",
284                     "sems-python/2.7.9",
285                     "sems-boost/1.69.0/base",
286                     "sems-zlib/1.2.8/base",
287                     "sems-hdf5/1.10.6/parallel",
288                     "sems-netcdf/4.7.3/parallel",
289                     "sems-parmetis/4.0.3/parallel",
290                     "sems-scotch/6.0.3/nopthread_64bit_parallel",
291                     "sems-superlu/4.3/base",
292                     "sems-cmake/3.17.1",
293                     "sems-ninja_fortran/1.10.0"],
294                "Trilinos_pullrequest_cuda_9.2":
295                     ["git/2.10.1",
296                     "devpack/20180521/openmpi/2.1.2/gcc/7.2.0/cuda/9.2.88",
297                      ("openblas/0.2.20/gcc/7.2.0", "netlib/3.8.0/gcc/7.2.0")]}
298
299    environMap = {
300                 "Trilinos_pullrequest_gcc_4.8.4":
301                      {"OMP_NUM_THREADS": "2"},
302                  "Trilinos_pullrequest_gcc_4.9.3_SERIAL":
303                      {"OMP_NUM_THREADS": "2"},
304                 "Trilinos_pullrequest_python_2":
305                      {"PYTHONPATH":
306                           os.path.join(os.path.sep,
307                                        "projects",
308                                        "sierra",
309                                        "linux_rh7",
310                                        "install",
311                                        "Python",
312                                        "extras",
313                                        "lib",
314                                        "python2.7",
315                                        "site-packages"),
316                       "MANPATH":
317                           os.path.join(os.path.sep,
318                                        "projects",
319                                        "sierra",
320                                        "linux_rh7",
321                                        "install",
322                                        "Python",
323                                        "2.7.15",
324                                        "share",
325                                        "man"),
326                       "PATH": os.path.join(os.path.sep,
327                                            "projects",
328                                            "sierra",
329                                            "linux_rh7",
330                                            "install",
331                                            "Python",
332                                            "2.7.15",
333                                            "bin") + os.pathsep +
334                               os.path.join(os.path.sep,
335                                            "projects",
336                                            "sierra",
337                                            "linux_rh7",
338                                            "install",
339                                            "Python",
340                                            "extras"
341                                            "bin")},
342                 "Trilinos_pullrequest_python_3":
343                      {"PYTHONPATH":
344                           os.path.join(os.path.sep,
345                                        "projects",
346                                        "sierra",
347                                        "linux_rh7",
348                                        "install",
349                                        "Python",
350                                        "extras",
351                                        "lib",
352                                        "python3.6",
353                                        "site-packages"),
354                       "MANPATH":
355                           os.path.join(os.path.sep,
356                                        "projects",
357                                        "sierra",
358                                        "linux_rh7",
359                                        "install",
360                                        "Python",
361                                        "3.6.3",
362                                        "share",
363                                        "man"),
364                       "PATH": os.path.join(os.path.sep,
365                                            "projects",
366                                            "sierra",
367                                            "linux_rh7",
368                                            "install",
369                                            "Python",
370                                            "3.6.3",
371                                            "bin") + os.pathsep +
372                               os.path.join(os.path.sep,
373                                            "projects",
374                                            "sierra",
375                                            "linux_rh7",
376                                            "install",
377                                            "Python",
378                                            "extras"
379                                            "bin")},
380                 "Trilinos_pullrequest_gcc_7.2.0":
381                      {"SEMS_FORCE_LOCAL_COMPILER_VERSION": "4.9.3",
382                       "OMP_NUM_THREADS": "2"},
383                 "Trilinos_pullrequest_gcc_7.2.0_debug":
384                      {"SEMS_FORCE_LOCAL_COMPILER_VERSION": "4.9.3",
385                       "OMP_NUM_THREADS": "2"},
386                 "Trilinos_pullrequest_gcc_8.3.0":
387                      {"SEMS_FORCE_LOCAL_COMPILER_VERSION": "4.9.3",
388                       "OMP_NUM_THREADS": "2"},
389                 "Trilinos_pullrequest_intel_17.0.1":
390                      {"SEMS_FORCE_LOCAL_COMPILER_VERSION": "4.9.3",
391                       "OMP_NUM_THREADS": "2"},
392                 "Trilinos_pullrequest_clang_7.0.1":
393                      {"SEMS_FORCE_LOCAL_COMPILER_VERSION": "5.3.0",
394                       "OMP_NUM_THREADS": "2"},
395                 "Trilinos_pullrequest_clang_9.0.0":
396                      {"SEMS_FORCE_LOCAL_COMPILER_VERSION": "5.3.0",
397                       "OMP_NUM_THREADS": "2"},
398                 "Trilinos_pullrequest_clang_10.0.0":
399                      {"SEMS_FORCE_LOCAL_COMPILER_VERSION": "5.3.0",
400                       "OMP_NUM_THREADS": "2"},
401                 "Trilinos_pullrequest_cuda_9.2":
402                      {"OMPI_CXX":
403                       os.path.join(os.environ["WORKSPACE"],
404                                    "Trilinos",
405                                    "packages",
406                                    "kokkos",
407                                    "bin",
408                                    "nvcc_wrapper"),
409                       "OMPI_CC": os.environ.get("CC", ""),
410                       "OMPI_FC": os.environ.get("FC", ""),
411                       "CUDA_LAUNCH_BLOCKING": "1",
412                       "CUDA_MANAGED_FORCE_DEVICE_ALLOC": "1",
413                       "PATH": os.path.join(os.path.sep,
414                                            "ascldap",
415                                            "users",
416                                            "rabartl",
417                                            "install",
418                                            "white-ride",
419                                            "cmake-3.11.2",
420                                            "bin") + os.pathsep +
421                               os.path.join(os.path.sep,
422                                            "ascldap",
423                                            "users",
424                                            "rabartl",
425                                            "install",
426                                            "white-ride",
427                                            "ninja-1.8.2",
428                                            "bin")}
429    }
430
431    try:
432        moduleList = moduleMap[arguments.job_base_name]
433        l_environMap = environMap[arguments.job_base_name]
434    except KeyError:
435        sys.exit(dedent("""\
436            ERROR: Unable to find matching environment for job: Trilinos_pullrequest_UNKOWN
437                   Error code was: 42"""))
438
439    if 'sems-env' == moduleList[0]:
440        module('use', '/projects/sems/modulefiles/projects')
441
442    for mod in moduleList:
443        if isinstance(mod, str):
444            module('load', mod)
445        else:
446            unl_mod, load_mod = mod
447            if '' == unl_mod:
448                module('unload', load_mod)
449            else:
450                module('swap', unl_mod, load_mod)
451
452    if 'OMPI_CC' in l_environMap:
453        l_environMap['OMPI_CC'] = os.environ.get('CC', '')
454
455    if 'OMPI_FC' in l_environMap:
456        l_environMap['OMPI_FC'] = os.environ.get('FC', '')
457
458    for key, value in l_environMap.items():
459        if key in os.environ:
460            # we are assuming these are paths to be prepended
461            os.environ[key] = str(value) + os.pathsep + os.environ[key]
462        else:
463            os.environ[key] = str(value)
464
465    confirmGitVersion()
466
467    print ("Environment:\n")
468    print("  pwd = {cwd}".format(cwd=os.getcwd()))
469    print("")
470    for key in os.environ:
471        print(key + ' = ' + os.environ[key],
472              file=sys.stdout)
473
474    print("\n"+"="*90)
475    print(module('list'))
476
477    return None
478
479
480def getCDashTrack():
481    returnValue = 'Pull Request'
482    if 'PULLREQUEST_CDASH_TRACK' in os.environ:
483        returnValue = os.environ['PULLREQUEST_CDASH_TRACK']
484        print('PULLREQUEST_CDASH_TRACK is set. Setting CDASH_TRACK={}'.format(returnValue) )
485        returnValue = os.environ['PULLREQUEST_CDASH_TRACK']
486    else:
487        print('PULLREQUEST_CDASH_TRACK isn\'t set, using default value')
488
489    return returnValue
490
491
492def get_memory_info():
493    """
494    Get memory information
495
496    Returns dictionary : ["mem_gb": <Gigabytes of Memory>, "mem_kb": <Kilobytes of Memory>]
497    """
498    mem_kb = None
499
500    try:
501        # if psutil isn't there, it can be installed via `pip install psutil`
502        import psutil
503        mem_total = psutil.virtual_memory().total
504        mem_kb = mem_total/1024
505    except:
506        # If we can't load psutil then just look for /proc/meminfo
507        # - Note: /proc/meminfo assumes a unix/linux system and will fail on
508        #         windows or OSX systems that don't have that file.
509        #         The nearest OSX equivalent would be to run vm_stat and parse
510        #         the output but this isn't a 100% analog.
511        try:
512            with open('/proc/meminfo') as f_ptr:
513                meminfo = dict((i.split()[0].rstrip(':'), int(i.split()[1])) for i in f_ptr.readlines())
514            mem_kb = meminfo['MemTotal']
515        except IOError:
516            raise IOError(dedent('''\
517                                 Import psutil failed and /proc/meminfo not found.
518                                 Testing cannot proceed because we can't determine system information.
519                                 Try running '$ pip install psutil'
520                                 '''))
521
522    output = {}
523    output["mem_kb"] = mem_kb
524    output["mem_gb"] = mem_kb / (1024*1024)
525
526    return output
527
528
529def compute_n():
530    '''
531    Given the default and the hardware environment determine the
532    number of processors  to use
533    '''
534    try:
535        environment_weight = int(os.environ['JENKINS_JOB_WEIGHT'])
536    except KeyError:
537        environment_weight = 29
538
539    requested_mem_per_core =  3.0
540
541    n_cpu = cpu_count()
542
543    mem = get_memory_info()
544    mem_kib = mem["mem_kb"]
545    mem_G   = mem["mem_gb"]
546
547    number_possible_jobs = max(1, int(n_cpu/environment_weight))
548    parallel_level = int(mem_G/(requested_mem_per_core*number_possible_jobs))
549
550    if parallel_level > environment_weight:
551        parallel_level = environment_weight
552
553    return parallel_level
554
555
556def createPackageEnables(arguments):
557    """
558    """
559    enable_map = {'Trilinos_pullrequest_python_2': 'TrilinosFrameworkTests',
560                  'Trilinos_pullrequest_python_3': 'TrilinosFrameworkTests'}
561
562    try:
563        if arguments.job_base_name not in enable_map:
564            subprocess.check_call([os.path.join(arguments.workspaceDir,
565                                                'Trilinos',
566                                                'commonTools',
567                                                'framework',
568                                                'get-changed-trilinos-packages.sh'),
569                                   os.path.join('origin', arguments.targetBranch),
570                                   'HEAD',
571                                   'packageEnables.cmake',
572                                   'package_subproject_list.cmake'])
573        else:
574            with open('packageEnables.cmake',  'w') as f_out:
575                f_out.write(dedent('''\
576                    MACRO(PR_ENABLE_BOOL  VAR_NAME  VAR_VAL)
577                      MESSAGE("-- Setting ${VAR_NAME} = ${VAR_VAL}")
578                      SET(${VAR_NAME} ${VAR_VAL} CACHE BOOL "Set in $CMAKE_PACKAGE_ENABLES_OUT")
579                    ENDMACRO()
580
581                    PR_ENABLE_BOOL(Trilinos_ENABLE_''' + enable_map[arguments.job_base_name] + ''' ON)
582                    '''))
583            with open ('package_subproject_list.cmake', 'w') as f_out:
584                f_out.write(dedent('''\
585                    set(CTEST_LABELS_FOR_SUBPROJECTS ''' + enable_map[arguments.job_base_name] + ''')
586                    '''))
587        print('Enabled packages:')
588        cmake_rstring = subprocess.check_output(['cmake',
589                                                 '-P',
590                                                 'packageEnables.cmake'],
591                                                stderr=subprocess.STDOUT)
592        if(sys.version_info.major != 3):
593            print(cmake_rstring)
594        else:
595            print(str(cmake_rstring, 'ASCII'))
596    except subprocess.CalledProcessError as cpe:
597        print('There was an issue generating packageEnables.cmake.  '
598              'The error code was: {}'.format(cpe.returncode))
599
600    return None
601
602
603def validateSourceBranchIfDestBranchIsMaster(arguments):
604    """
605    We only allow special branches to be merged into master.
606    These should be protected branches that not everyone can create.
607    This routine checks that the source branch name is matches this form:
608    -  master_merge_YYYYMMDD_HHMMSS
609
610    Script will exit with nonzero exit code if this test fails.
611    """
612    re_src_branchname = "master_merge_[0-9]{8}_[0-9]{6}"
613    if "master" == arguments.targetBranch:
614        if re.match(re_src_branchname, arguments.sourceBranch) is None:
615            # If destination is master and source isn't master_merge_YYYYMMDD_HHMMSS
616            # then we exit here with nonzero exit status.
617            sys.exit(dedent("""\
618            ------------------------------------------------------------------------------------------
619            NOTICE: Destination branch is trilinos/Trilnos::master
620            ERROR : Source branch is NOT trilinos/Trilinos::master_merge_YYYYMMDD_HHMMSS
621                  : This violates Trilinos policy, pull requests into the master branch are restricted.
622                  : Perhaps you forgot to specify the develop branch as the target in your PR?
623            ------------------------------------------------------------------------------------------
624            """))
625        else:
626            print(dedent("""\
627                NOTICE: Source branch IS trilinos/Trilinos::{sourceBranch}
628                        : This is allowed, proceeding with testing.""".format(**vars(arguments))
629                        )
630                 )
631    else:
632        print(dedent("""\
633            NOTICE: Destination branch is NOT trilinos/Trilinos::master"
634                  : PR testing will proceed."""))
635
636    return 0
637
638
639def generateBuildNameString(arguments):
640    """
641    Generate the build name string
642    PR-<PR Number>-test-<Jenkins Job Name>-<Jenkins Build Number>
643    """
644    output = "PR-{github_pr_number}-test-{job_base_name}-{job_number}".format(**vars(arguments))
645    return output
646
647
648
649config_map = {
650    'Trilinos_pullrequest_gcc_4.8.4':        'PullRequestLinuxGCC4.8.4TestingSettings.cmake',
651    'Trilinos_pullrequest_intel_17.0.1':     'PullRequestLinuxIntelTestingSettings.cmake',
652    'Trilinos_pullrequest_gcc_4.9.3_SERIAL': 'PullRequestLinuxGCC4.9.3TestingSettingsSERIAL.cmake',
653    'Trilinos_pullrequest_gcc_7.2.0':        'PullRequestLinuxGCC7.2.0TestingSettings.cmake',
654    'Trilinos_pullrequest_gcc_8.3.0':        'PullRequestLinuxGCC8.3.0TestingSettings.cmake',
655    'Trilinos_pullrequest_clang_7.0.1':      'PullRequestLinuxClang7.0.1TestingSettings.cmake',
656    'Trilinos_pullrequest_clang_9.0.0':      'PullRequestLinuxClang9.0.0TestingSettings.cmake',
657    'Trilinos_pullrequest_clang_10.0.0':      'PullRequestLinuxClang10.0.0TestingSettings.cmake',
658    'Trilinos_pullrequest_cuda_9.2':         'PullRequestLinuxCuda9.2TestingSettings.cmake',
659    'Trilinos_pullrequest_python_2':         'PullRequestLinuxPython2.cmake',
660    'Trilinos_pullrequest_python_3':         'PullRequestLinuxPython3.cmake'
661    }
662
663
664
665def run():
666    """
667    Top level function to execute in this script.
668    """
669    return_value = True
670    arguments = parse_args()
671
672    os.chdir(arguments.workspaceDir)
673
674    print_input_variables(arguments)
675
676    validateSourceBranchIfDestBranchIsMaster(arguments)
677
678    setBuildEnviron(arguments)
679
680    CDash_Track = getCDashTrack()
681
682    createPackageEnables(arguments)
683
684    parallel_level = compute_n()
685
686    if 'JENKINS_TEST_WEIGHT' in os.environ:
687        test_parallel_level = os.environ['JENKINS_TEST_WEIGHT']
688    else:
689        test_parallel_level = parallel_level
690
691    build_name = generateBuildNameString(arguments)
692
693    config_script = config_map[arguments.job_base_name]
694
695    os.chdir('TFW_testing_single_configure_prototype')
696    print('Set CWD = {}'.format(os.getcwd()))
697
698    # Execute the call to ctest.
699    # - NOTE: simple_testing.cmake can be found in the TFW_single_configure_support_scripts
700    #         repository.
701    subprocess.check_call(['ctest', '-S', 'simple_testing.cmake',
702                           '-Dbuild_name={}'.format(build_name),
703                           '-Dskip_by_parts_submit=OFF',
704                           '-Dskip_update_step=ON',
705                           '-Ddashboard_model=Experimental',
706                           '-Ddashboard_track={}'.format(CDash_Track),
707                           '-DPARALLEL_LEVEL={}'.format(parallel_level),
708                           '-DTEST_PARALLEL_LEVEL={}'.format(test_parallel_level),
709                           '-Dbuild_dir={}/pull_request_test'.format(arguments.workspaceDir),
710                           '-Dconfigure_script=' +
711                               os.path.join(arguments.workspaceDir,
712                                            'Trilinos',
713                                            'cmake',
714                                            'std',
715                                            config_script),
716                           '-Dpackage_enables=../packageEnables.cmake',
717                           '-Dsubprojects_file=../package_subproject_list.cmake'])
718
719    return return_value
720
721
722
723if __name__ == '__main__':  # pragma nocover
724    returnValue = run()
725    if returnValue:
726        exit(0)
727    else:
728        exit(1)
729