Skip to content
Snippets Groups Projects
Commit 92ea2092 authored by Emanuele Aina's avatar Emanuele Aina
Browse files

obs-mismatching-source-requests: List OBS request with conflicting .dsc files


Check for OBS submit request updating package sources without bumping the
version number, as that breaks a few invariants on the way packages are handled
on the reprepro/apt side.

Signed-off-by: Emanuele Aina's avatarEmanuele Aina <emanuele.aina@collabora.com>
parent c0a7f59d
No related branches found
No related tags found
No related merge requests found
FROM debian:buster-slim
RUN apt-get update && apt-get install -y \
ca-certificates \
osc \
python-jinja2 \
--no-install-recommends \
&& rm -rf /var/lib/apt/lists/*
pipeline {
agent {
dockerfile {
filename 'obs-mismatching-source-requests/Dockerfile'
}
}
environment {
RELEASE = "v2020dev0"
OSCRC = credentials("349d474d-a6d0-4ab0-987a-a3843916bdff")
}
stages {
stage('Test') {
steps {
sh '''
export HOME=/tmp # switch to a writable folder so OSC can create the `~/.osc_cookiejar` file
./obs-mismatching-source-requests/obs-mismatching-source-requests --oscrc "$OSCRC" --release $RELEASE --junit junit.xml
'''
}
}
}
post {
success {
junit 'junit.xml'
}
}
}
#!/usr/bin/env python
from __future__ import print_function
import argparse
import sys
import textwrap
import jinja2
import osc.conf
import osc.core
try:
from xml.etree import cElementTree as ET
except ImportError:
import cElementTree as ET
class File:
def __init__(self, name, md5):
self.name = name
self.md5 = md5
class Mismatch:
def __init__(self, url, src_project, dsc, rev, tgt_project, src_md5, tgt_md5):
self.url = url
self.src_project = src_project
self.dsc = dsc
self.rev = rev
self.tgt_project = tgt_project
self.tgt_md5 = tgt_md5
self.src_md5 = src_md5
def get_xpath(state, projectprefix):
xpath = 'state/@name="{}"'.format(state)
if projectprefix:
xpath += ' and (starts-with(source/@project, "{0}") or starts-with(target/@project, "{0}"))'.format(projectprefix)
return xpath
def get_requests(apiurl, xpath):
res = osc.core.search(apiurl, request=xpath)
collection = res['request']
requests = []
for root in collection.findall('request'):
r = osc.core.Request()
r.read(root)
requests.append(r)
return requests
def get_files(apiurl, project, package, revision=None):
xml = osc.core.show_files_meta(apiurl, project, package, revision=revision)
filelist = ET.fromstring(xml)
ret = []
for entry in filelist.findall('entry'):
if entry.get('name').startswith('_service:'):
continue
f = File(entry.get('name'), entry.get('md5'))
ret.append(f)
return ret
def requesturl(apiurl, reqid):
return apiurl+"/request/show/"+reqid
def get_mismatches(oscrc=None, projectprefix=None):
osc.conf.get_config(override_conffile = oscrc)
apiurl = osc.conf.config['apiurl']
xpath = get_xpath('review', projectprefix)
requests = get_requests(apiurl, xpath)
mismatches = []
for r in requests:
requrl = requesturl(apiurl, r.reqid)
try:
submit = next(iter(r.get_actions('submit')), None)
if not submit:
continue
src_filelist = get_files(apiurl, submit.src_project, submit.src_package, revision=submit.src_rev)
tgt_filelist = get_files(apiurl, submit.tgt_project, submit.tgt_package)
src_dsc = next((f for f in src_filelist if f.name.endswith('.dsc')), None)
tgt_dsc = next((f for f in tgt_filelist if f.name.endswith('.dsc')), None)
if tgt_dsc and src_dsc.name == tgt_dsc.name and src_dsc.md5 != tgt_dsc.md5:
mismatches.append(Mismatch(requrl, submit.src_project, src_dsc.name, submit.src_rev, submit.tgt_project, src_dsc.md5, tgt_dsc.md5))
except:
print('error while fetching data for request {}'.format(requrl), file=sys.stderr)
raise
return mismatches
def render_junit(project, release, mismatches):
junit_template = textwrap.dedent("""\
<?xml version="1.0" encoding="UTF-8"?>
<testsuites tests="{{mismatches|length}}" failures="{{mismatches|length}}">
<testsuite name="{{project}}:{{release}}">
{%- for m in mismatches %}
<testcase name="{{m.dsc|replace(".dsc", "")}}">
<failure type="failed">
{{m.url}} {{m.src_project}} {{m.dsc}} rev{{m.rev}} ({{m.src_md5}}) -> {{m.tgt_project}} ({{m.tgt_md5}})
</failure>
</testcase>
{%- endfor %}
</testsuite>
</testsuites>
""")
environment = jinja2.Environment(autoescape=True)
template = environment.from_string(junit_template)
result = template.render(
project=project,
release=release,
mismatches=mismatches,
)
return result
def main():
parser = argparse.ArgumentParser(description='List OBS request with conflicting .dsc files')
parser.add_argument('--release', type=str, metavar='RELEASE',
help='restrict the search to requests sourceing or targeting projects in this release')
parser.add_argument('--oscrc', type=str, help='the OSC configuration with the OBS credentials')
parser.add_argument('--junit', type=argparse.FileType('w'), help='file to store results in JUnit format')
args = parser.parse_args()
projectprefix = 'apertis:'+args.release if args.release else None
mismatches = get_mismatches(args.oscrc, projectprefix)
for m in mismatches:
print("{m.url} {m.src_project} {m.dsc} rev{m.rev} ({m.src_md5}) -> {m.tgt_project} ({m.tgt_md5})".format(m=m))
if args.junit:
args.junit.write(render_junit('apertis', args.release, mismatches))
if __name__ == '__main__':
main()
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment