d27c7ff9db
Instead of getting a confusing stacktrace when someone adds a new file that is missing the final project entry we now give a friendlier error that also recommends way to address the issue. Change-Id: I5a84d3a20e847eeb2d5d843ef970b5790532683c
173 lines
5.5 KiB
Python
Executable File
173 lines
5.5 KiB
Python
Executable File
#!/usr/bin/env python
|
|
#
|
|
# Copyright 2019 Red Hat, Inc.
|
|
#
|
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
|
# not use this file except in compliance with the License. You may obtain
|
|
# a copy of the License at
|
|
#
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
#
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
# License for the specific language governing permissions and limitations
|
|
# under the License.
|
|
|
|
# Update job definitions for multi-platform jobs, and make sure every
|
|
# in-repo test job appears in a project definition. This script
|
|
# re-writes the files in zuul-tests.d. It should be run from the root
|
|
# of the repo.
|
|
|
|
import os
|
|
import sys
|
|
|
|
from ruamel.yaml.comments import CommentedMap
|
|
|
|
import ruamellib
|
|
|
|
# There are fedora- and debian-latest nodesets, but they can't be used
|
|
# in the multinode jobs, so just use the real labels everywhere.
|
|
|
|
PLATFORMS = [
|
|
'centos-7',
|
|
'centos-8',
|
|
'centos-8-stream',
|
|
'debian-stretch',
|
|
'fedora-32',
|
|
'gentoo-17-0-systemd',
|
|
'opensuse-15',
|
|
'opensuse-tumbleweed',
|
|
'ubuntu-bionic',
|
|
'ubuntu-xenial',
|
|
'ubuntu-focal',
|
|
]
|
|
|
|
# insert a platform from above to make it non-voting
|
|
NON_VOTING = [
|
|
'opensuse-tumbleweed',
|
|
]
|
|
|
|
# Insert a job to make that single job non-voting
|
|
NON_VOTING_JOBS = [
|
|
'zuul-jobs-test-multinode-roles-gentoo-17-0-systemd',
|
|
]
|
|
|
|
|
|
def get_nodeset(platform, multinode):
|
|
d = CommentedMap()
|
|
if not multinode:
|
|
d['nodes'] = [
|
|
CommentedMap([('name', platform), ('label', platform)]),
|
|
]
|
|
else:
|
|
d['nodes'] = [
|
|
CommentedMap([('name', 'primary'), ('label', platform)]),
|
|
CommentedMap([('name', 'secondary'), ('label', platform)]),
|
|
]
|
|
d['groups'] = [
|
|
CommentedMap([('name', 'switch'), ('nodes', ['primary'])]),
|
|
CommentedMap([('name', 'peers'), ('nodes', ['secondary'])]),
|
|
]
|
|
return d
|
|
|
|
|
|
def handle_file(fn):
|
|
yaml = ruamellib.YAML()
|
|
data = yaml.load(open(fn))
|
|
outdata = []
|
|
outprojects = []
|
|
joblist_check = []
|
|
joblist_gate = []
|
|
has_non_voting = False
|
|
for obj in data:
|
|
if 'job' in obj:
|
|
job = obj['job']
|
|
if 'auto-generated' in job.get('tags', []):
|
|
continue
|
|
outdata.append(obj)
|
|
tags = job.get('tags', [])
|
|
all_platforms = False
|
|
if 'all-platforms-multinode' in tags:
|
|
multinode = True
|
|
all_platforms = True
|
|
elif 'all-platforms' in tags:
|
|
all_platforms = True
|
|
multinode = False
|
|
if all_platforms:
|
|
for platform in PLATFORMS:
|
|
voting = False if platform in NON_VOTING else True
|
|
ojob = CommentedMap()
|
|
ojob['name'] = job['name'] + '-' + platform
|
|
if ojob['name'] in NON_VOTING_JOBS:
|
|
voting = False
|
|
if not voting:
|
|
ojob['name'] += '-nv'
|
|
ojob['voting'] = False
|
|
has_non_voting = True
|
|
desc = job['description'].split('\n')[0]
|
|
ojob['description'] = desc + ' on ' \
|
|
+ platform
|
|
ojob['parent'] = job['name']
|
|
ojob['tags'] = 'auto-generated'
|
|
ojob['nodeset'] = get_nodeset(platform, multinode)
|
|
outdata.append({'job': ojob})
|
|
joblist_check.append(ojob['name'])
|
|
if voting:
|
|
joblist_gate.append(ojob['name'])
|
|
elif not job.get('abstract', False):
|
|
joblist_check.append(job['name'])
|
|
# don't append non-voting jobs to gate
|
|
if job.get('voting', True):
|
|
joblist_gate.append(job['name'])
|
|
else:
|
|
has_non_voting = True
|
|
elif 'project' in obj:
|
|
outprojects.append(obj)
|
|
else:
|
|
outdata.append(obj)
|
|
# We control the last project stanza
|
|
outdata.extend(outprojects)
|
|
if not outprojects:
|
|
seed = """
|
|
- project:
|
|
check:
|
|
jobs: []
|
|
gate:
|
|
jobs: []
|
|
"""
|
|
print(
|
|
f"FATAL: File {fn} last item is not a project definition. "
|
|
f"Try adding something like:\n{seed}")
|
|
sys.exit(1)
|
|
project = outprojects[-1]['project']
|
|
project['check']['jobs'] = joblist_check
|
|
# Use the same dictionary if there are no non-voting jobs
|
|
# (i.e. check is the same as gate); this gives nicer YAML output
|
|
# using dictionary anchors
|
|
project['gate']['jobs'] = joblist_gate if has_non_voting else joblist_check
|
|
# gate jobs should also be in periodic in order to assure they do not rot
|
|
periodic_pipeline = 'periodic-weekly'
|
|
if periodic_pipeline not in project:
|
|
project[periodic_pipeline] = {}
|
|
if 'jobs' not in project[periodic_pipeline]:
|
|
project[periodic_pipeline]['jobs'] = []
|
|
project[periodic_pipeline]['jobs'] = joblist_gate \
|
|
if has_non_voting else joblist_check
|
|
|
|
with open(fn, 'w') as f:
|
|
yaml.dump(outdata, stream=f)
|
|
|
|
|
|
def main():
|
|
for f in os.listdir('zuul-tests.d'):
|
|
if not f.endswith('.yaml'):
|
|
continue
|
|
if f == 'project.yaml':
|
|
continue
|
|
handle_file(os.path.join('zuul-tests.d', f))
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|