xref: /petsc/lib/petsc/bin/maint/runjobs.py (revision bd00f7f07346bd94eecebd6cb318bef8fbb8f4e9)
1#!/usr/bin/env python3
2
3import sys
4from subprocess import check_output
5
6#  runjobs.py [-f] [job1 job2 ... jobN]
7#
8#  Sets a list of jobs to run upon the next push of the branch that is in a merge request.
9#
10#  -f: when commits in the local "branch" are not in sync with "origin/branch" - runjobs.py will not create a new local CI commit
11#      for the specified "jobs list". Use '-f' to force the creation of this commit [and then use 'git push -f' to update this
12#      branch's contents at GitLab] - if the intention is to overwrite these differences with your local files.
13#      Otherwise, sync your local branch with "origin/branch" changes before running runjobs.py.
14#
15#  Example usages:
16#      lib/petsc/bin/maint/runjobs.py -f linux-cuda-pkgs
17#      lib/petsc/bin/maint/runjobs.py -f freebsd-cxx-pkgs-opt linux-clang-avx linux-clang-ubsan
18#      lib/petsc/bin/maint/runjobs.py -f $(grep -lE "download-(mpich|openmpi)" config/examples/arch-ci-*.py | cut -d '/' -f 3 | sed -e 's/arch-ci-//' | sed -e 's/.py$//')
19#
20#  Note: If no jobs are listed, then all jobs in the pipeline are run but without a need to un-pause the pipeline on the GitLab site.
21#  i.e., usage:
22#      lib/petsc/bin/maint/runjobs.py
23#
24
25jobs = sorted(set(sys.argv[1:]))
26force = False
27if ('-f' in jobs):
28  force = True
29  jobs.remove('-f')
30alljobs = (jobs == [])
31
32try:
33  check_output(r'git diff-index --quiet HEAD --', shell=True)
34except Exception:
35  print('Do not run on a repository with any uncommited changes')
36  sys.exit(0)
37
38if not force:
39  try:
40    check_output('git fetch', shell=True).decode('utf-8')
41    branch = check_output('git rev-parse --abbrev-ref HEAD', shell=True).decode('utf-8').strip()
42    base   = check_output('git merge-base ' + branch + ' remotes/origin/' + branch, shell=True).decode('utf-8').strip()
43    aref   = check_output('git rev-parse ' + branch, shell=True).decode('utf-8').strip()
44    bref   = check_output('git rev-parse remotes/origin/' + branch, shell=True).decode('utf-8').strip()
45  except Exception:
46    print('Unable to run git commits, not submitting jobs')
47    sys.exit(0)
48  if not aref == bref and not bref == base:
49    print('Your repository is behind or has diverged from GitLab, not running jobs')
50    print('If you plan to run git push with -f then use -f with this command')
51    sys.exit(0)
52
53with open('.gitlab-ci.yml','r') as fd:
54  ci = fd.read()
55
56Success_Message = 'Do a git push to start the job(s); after the pipeline finishes REMOVE commit '
57File_Header = '# .gitlab-ci.yml was automatically generated by the command:\n'
58Run_CMD = '# ' + ' '.join(sys.argv) + '\n'
59
60if (ci.find(File_Header) >= 0):
61  try: commit = check_output('git rev-list -1 HEAD .gitlab-ci.yml', shell=True).decode('utf-8').strip()
62  except Exception: commit = ''
63  saved_jobs = sorted(set((ci.splitlines()[1]).split()[2:]))
64  if ('-f' in saved_jobs): saved_jobs.remove('-f')
65  if (saved_jobs == jobs):
66    print(Success_Message + commit)
67  else:
68    print('runjobs.py was previously run (with different jobs), rerun after you REMOVE commit '+commit)
69  sys.exit(0)
70
71arches = list(jobs)
72for arch in arches.copy():
73  if ci.find('TEST_ARCH: arch-ci-'+arch) > -1:
74    arches.remove(arch)
75if arches:
76  print('Could not locate job(s) '+str(arches))
77  sys.exit(0)
78
79extraJob='''
80using-runjobs:
81  extends: .test-basic
82  stage: .pre
83  tags:
84    - gce-stage1
85  script:
86    - exit 5
87  variables:
88    GIT_STRATEGY: none
89  allow_failure: true
90
91'''
92
93with open('.gitlab-ci.yml','w') as fd:
94  fd.write(File_Header)
95  fd.write(Run_CMD)
96  for a in ci.split('\n\n'):
97    if a.startswith('pause-for-approval:'): continue
98    if not alljobs:
99      if a.startswith('# job for analyzing the coverage results '): break
100      if a.find('CONFIG_OPTS: ') > -1: continue
101      if a.find('petsc4py-') > -1: continue
102      if a.find('check-each-commit:') > -1: continue
103      if a.find('petsc-dist:') > -1: continue
104      test_arch =  a.find('TEST_ARCH: ')
105      if test_arch > -1:
106        arch = a[test_arch+19:]
107        n = arch.find('\n')
108        if n > -1:
109          arch = arch[:n]
110        if arch in jobs:
111          fd.write(a+'\n\n')
112      else:
113        fd.write(a+'\n\n')
114    else:
115      fd.write(a+'\n\n')
116  if not alljobs: fd.write(extraJob)
117
118try:
119  output = check_output('git add .gitlab-ci.yml', shell=True)
120  if not alljobs:
121    output = check_output('git commit -m"DRAFT: CI: Temporary commit, remove before merge! Runs only jobs: '+' '.join(jobs)+'"', shell=True)
122  else:
123    output = check_output('git commit -m"DRAFT: CI: Temporary commit, remove before merge! Runs all jobs immediately, no unpause needed at GitLab"', shell=True)
124except Exception:
125  print('Unable to commit changed .gitlab-ci.yml file')
126  sys.exit(0)
127
128try: commit = check_output('git rev-list -1 HEAD .gitlab-ci.yml', shell=True).decode('utf-8').strip()
129except Exception: commit = ''
130print(Success_Message + commit)
131