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