draft builds
This commit is contained in:
parent
124450cec0
commit
87409499a3
30 changed files with 1763 additions and 186 deletions
|
|
@ -1102,6 +1102,8 @@ class BuildTask(BaseTaskHandler):
|
|||
% (data['name'], target_info['dest_tag_name']))
|
||||
# TODO - more pre tests
|
||||
archlist = self.getArchList(build_tag, h, extra=extra_arches)
|
||||
# pass draft option in
|
||||
data['draft'] = opts.get('draft')
|
||||
# let the system know about the build we're attempting
|
||||
if not self.opts.get('scratch'):
|
||||
# scratch builds do not get imported
|
||||
|
|
@ -2176,6 +2178,8 @@ class WrapperRPMTask(BaseBuildTask):
|
|||
data['extra'] = {'source': {'original_url': source['url']}}
|
||||
if opts.get('custom_user_metadata'):
|
||||
data['extra']['custom_user_metadata'] = opts['custom_user_metadata']
|
||||
# pass draft option in
|
||||
data['draft'] = opts.get('draft')
|
||||
self.logger.info("Reading package config for %(name)s" % data)
|
||||
pkg_cfg = self.session.getPackageConfig(build_target['dest_tag'], data['name'])
|
||||
if not opts.get('skip_tag'):
|
||||
|
|
@ -5249,6 +5253,7 @@ Subject: %(nvr)s %(result)s %(operation)s by %(user_name)s\r
|
|||
To: %(to_addrs)s\r
|
||||
X-Koji-Package: %(pkg_name)s\r
|
||||
X-Koji-NVR: %(nvr)s\r
|
||||
X-Koji-Draft: %(draft)s\r
|
||||
X-Koji-User: %(user_name)s\r
|
||||
X-Koji-Status: %(status)s\r
|
||||
%(tag_headers)s\r
|
||||
|
|
@ -5278,6 +5283,7 @@ Status: %(status)s\r
|
|||
user = self.session.getUser(user_info)
|
||||
pkg_name = build['package_name']
|
||||
nvr = koji.buildLabel(build)
|
||||
draft = build.get('draft', False)
|
||||
user_name = user['name']
|
||||
|
||||
from_addr = self.options.from_addr
|
||||
|
|
@ -5349,6 +5355,7 @@ X-Koji-Tag: %(dest_tag)s\r
|
|||
X-Koji-Package: %(build_pkg_name)s\r
|
||||
X-Koji-Builder: %(build_owner)s\r
|
||||
X-Koji-Status: %(status)s\r
|
||||
X-Koji-Draft: %(draft)s\r
|
||||
\r
|
||||
Package: %(build_nvr)s\r
|
||||
Tag: %(dest_tag)s\r
|
||||
|
|
@ -5448,6 +5455,7 @@ Build Info: %(weburl)s/buildinfo?buildID=%(build_id)i\r
|
|||
build_nvr = koji.buildLabel(build)
|
||||
build_id = build['id']
|
||||
build_owner = build['owner_name']
|
||||
draft = build.get('draft', False)
|
||||
# target comes from session.py:_get_build_target()
|
||||
dest_tag = None
|
||||
if target is not None:
|
||||
|
|
|
|||
|
|
@ -580,6 +580,8 @@ def handle_build(options, session, args):
|
|||
parser.add_option("--custom-user-metadata", type="str",
|
||||
help="Provide a JSON string of custom metadata to be deserialized and "
|
||||
"stored under the build's extra.custom_user_metadata field")
|
||||
parser.add_option("--draft", action="store_true",
|
||||
help="Build draft build instead")
|
||||
(build_opts, args) = parser.parse_args(args)
|
||||
if len(args) != 2:
|
||||
parser.error("Exactly two arguments (a build target and a SCM URL or srpm file) are "
|
||||
|
|
@ -588,6 +590,8 @@ def handle_build(options, session, args):
|
|||
parser.error("--no-/rebuild-srpm is only allowed for --scratch builds")
|
||||
if build_opts.arch_override and not build_opts.scratch:
|
||||
parser.error("--arch_override is only allowed for --scratch builds")
|
||||
if build_opts.scratch and build_opts.draft:
|
||||
parser.error("--scratch and --draft cannot be both specfied")
|
||||
custom_user_metadata = {}
|
||||
if build_opts.custom_user_metadata:
|
||||
try:
|
||||
|
|
@ -618,7 +622,7 @@ def handle_build(options, session, args):
|
|||
if build_opts.arch_override:
|
||||
opts['arch_override'] = koji.parse_arches(build_opts.arch_override)
|
||||
for key in ('skip_tag', 'scratch', 'repo_id', 'fail_fast', 'wait_repo', 'wait_builds',
|
||||
'rebuild_srpm'):
|
||||
'rebuild_srpm', 'draft'):
|
||||
val = getattr(build_opts, key)
|
||||
if val is not None:
|
||||
opts[key] = val
|
||||
|
|
@ -830,6 +834,8 @@ def handle_wrapper_rpm(options, session, args):
|
|||
parser.add_option("--nowait", action="store_false", dest="wait", help="Don't wait on build")
|
||||
parser.add_option("--background", action="store_true",
|
||||
help="Run the build at a lower priority")
|
||||
parser.add_option("--draft", action="store_true",
|
||||
help="Build draft build instead")
|
||||
|
||||
(build_opts, args) = parser.parse_args(args)
|
||||
if build_opts.inis:
|
||||
|
|
@ -839,6 +845,8 @@ def handle_wrapper_rpm(options, session, args):
|
|||
if len(args) < 3:
|
||||
parser.error("You must provide a build target, a build ID or NVR, "
|
||||
"and a SCM URL to a specfile fragment")
|
||||
if build_opts.scratch and build_opts.draft:
|
||||
parser.error("--scratch and --draft cannot be both specfied")
|
||||
activate_session(session, options)
|
||||
|
||||
target = args[0]
|
||||
|
|
@ -874,6 +882,8 @@ def handle_wrapper_rpm(options, session, args):
|
|||
opts['skip_tag'] = True
|
||||
if build_opts.scratch:
|
||||
opts['scratch'] = True
|
||||
if build_opts.draft:
|
||||
opts['draft'] = True
|
||||
task_id = session.wrapperRPM(build_id, url, target, priority, opts=opts)
|
||||
print("Created task: %d" % task_id)
|
||||
print("Task info: %s/taskinfo?taskID=%s" % (options.weburl, task_id))
|
||||
|
|
@ -1314,6 +1324,10 @@ def handle_import(goptions, session, args):
|
|||
parser.add_option("--test", action="store_true", help="Don't actually import")
|
||||
parser.add_option("--create-build", action="store_true", help="Auto-create builds as needed")
|
||||
parser.add_option("--src-epoch", help="When auto-creating builds, use this epoch")
|
||||
parser.add_option("--create-draft", action="store_true",
|
||||
help="Auto-create draft builds instead as needed")
|
||||
parser.add_option("--draft-build", metavar='NVR|ID',
|
||||
help="The target draft build to import to")
|
||||
(options, args) = parser.parse_args(args)
|
||||
if len(args) < 1:
|
||||
parser.error("At least one package must be specified")
|
||||
|
|
@ -1324,6 +1338,35 @@ def handle_import(goptions, session, args):
|
|||
options.src_epoch = int(options.src_epoch)
|
||||
except (ValueError, TypeError):
|
||||
parser.error("Invalid value for epoch: %s" % options.src_epoch)
|
||||
if options.create_draft:
|
||||
print("Will create draft build instead if desired nvr doesn't exist")
|
||||
options.create_build = True
|
||||
draft_build = None
|
||||
draft_target_nvr = None
|
||||
if options.draft_build:
|
||||
if options.create_build:
|
||||
parser.error(
|
||||
"To ensure no misuse, don't specify --draft-build while auto-creating."
|
||||
)
|
||||
try:
|
||||
draft_build = int(options.draft_build)
|
||||
except ValueError:
|
||||
draft_build = options.draft_build
|
||||
draft_build = session.getBuild(draft_build)
|
||||
if not draft_build:
|
||||
error("No such build: %s" % options.draft_build)
|
||||
if not draft_build.get('draft'):
|
||||
error("%s is not a draft build" % draft_build['nvr'])
|
||||
b_state = koji.BUILD_STATES[draft_build['state']]
|
||||
if b_state != 'COMPLETE':
|
||||
error("draft build %s is expected as COMPLETE, got %s" % (draft_build['nvr'], b_state))
|
||||
target_release = draft_build.get('extra', {}).get('draft', {}).get('target_release')
|
||||
if not target_release:
|
||||
error("Invalid draft build: %s,"
|
||||
" no draft.target_release found in extra" % draft_build['nvr'])
|
||||
draft_target_nvr = "%s-%s-%s" % (
|
||||
draft_build['name'], draft_build['version'], target_release
|
||||
)
|
||||
activate_session(session, goptions)
|
||||
to_import = {}
|
||||
for path in args:
|
||||
|
|
@ -1335,6 +1378,7 @@ def handle_import(goptions, session, args):
|
|||
else:
|
||||
nvr = "%(name)s-%(version)s-%(release)s" % koji.parse_NVRA(data['sourcerpm'])
|
||||
to_import.setdefault(nvr, []).append((path, data))
|
||||
|
||||
builds_missing = False
|
||||
nvrs = sorted(to_list(to_import.keys()))
|
||||
for nvr in nvrs:
|
||||
|
|
@ -1343,29 +1387,41 @@ def handle_import(goptions, session, args):
|
|||
if data['sourcepackage']:
|
||||
break
|
||||
else:
|
||||
if nvr == draft_target_nvr:
|
||||
continue
|
||||
# when no srpm and create_draft
|
||||
elif options.create_draft:
|
||||
print("Missing srpm for draft build creating with target nvr: %s" % nvr)
|
||||
builds_missing = True
|
||||
continue
|
||||
# no srpm included, check for build
|
||||
binfo = session.getBuild(nvr)
|
||||
if not binfo:
|
||||
print("Missing build or srpm: %s" % nvr)
|
||||
builds_missing = True
|
||||
if builds_missing and not options.create_build:
|
||||
if builds_missing and (not options.create_build or options.create_draft):
|
||||
print("Aborting import")
|
||||
return
|
||||
|
||||
# local function to help us out below
|
||||
def do_import(path, data):
|
||||
def do_import(path, data, draft_build=None):
|
||||
draft = bool(draft_build) or options.create_draft
|
||||
rinfo = dict([(k, data[k]) for k in ('name', 'version', 'release', 'arch')])
|
||||
prev = session.getRPM(rinfo)
|
||||
if prev and not prev.get('external_repo_id', 0):
|
||||
if prev['payloadhash'] == koji.hex_string(data['sigmd5']):
|
||||
print("RPM already imported: %s" % path)
|
||||
else:
|
||||
warn("md5sum mismatch for %s" % path)
|
||||
warn(" A different rpm with the same name has already been imported")
|
||||
warn(" Existing sigmd5 is %r, your import has %r" % (
|
||||
prev['payloadhash'], koji.hex_string(data['sigmd5'])))
|
||||
print("Skipping import")
|
||||
return
|
||||
if draft_build or not options.create_draft:
|
||||
opts = {}
|
||||
if draft_build:
|
||||
opts['build'] = draft_build
|
||||
prev = session.getRPM(rinfo, **opts)
|
||||
if prev and not prev.get('external_repo_id', 0):
|
||||
if prev['payloadhash'] == koji.hex_string(data['sigmd5']):
|
||||
print("RPM already imported: %s" % path)
|
||||
else:
|
||||
warn("md5sum mismatch for %s" % path)
|
||||
warn(" A different rpm with the same name has already been imported")
|
||||
warn(" Existing sigmd5 is %r, your import has %r" % (
|
||||
prev['payloadhash'], koji.hex_string(data['sigmd5'])))
|
||||
print("Skipping import")
|
||||
return
|
||||
if options.test:
|
||||
print("Test mode -- skipping import for %s" % path)
|
||||
return
|
||||
|
|
@ -1381,41 +1437,69 @@ def handle_import(goptions, session, args):
|
|||
sys.stdout.write("importing %s... " % path)
|
||||
sys.stdout.flush()
|
||||
try:
|
||||
session.importRPM(serverdir, os.path.basename(path))
|
||||
opts = {}
|
||||
if draft_build:
|
||||
opts['build'] = draft_build
|
||||
if draft:
|
||||
opts['draft'] = draft
|
||||
rpminfo = session.importRPM(serverdir, os.path.basename(path), **opts)
|
||||
except koji.GenericError as e:
|
||||
rpminfo = None
|
||||
print("\nError importing: %s" % str(e).splitlines()[-1])
|
||||
sys.stdout.flush()
|
||||
else:
|
||||
print("done")
|
||||
sys.stdout.flush()
|
||||
return rpminfo
|
||||
|
||||
for nvr in nvrs:
|
||||
# check for existing build
|
||||
need_build = True
|
||||
binfo = session.getBuild(nvr)
|
||||
if binfo:
|
||||
b_state = koji.BUILD_STATES[binfo['state']]
|
||||
if b_state == 'COMPLETE':
|
||||
need_build = False
|
||||
elif b_state in ['FAILED', 'CANCELED']:
|
||||
if not options.create_build:
|
||||
print("Build %s state is %s. Skipping import" % (nvr, b_state))
|
||||
is_draft = True
|
||||
if nvr == draft_target_nvr:
|
||||
binfo = draft_build
|
||||
need_build = False
|
||||
elif options.create_draft:
|
||||
binfo = None
|
||||
need_build = True
|
||||
else:
|
||||
is_draft = False
|
||||
binfo = session.getBuild(nvr)
|
||||
if binfo:
|
||||
b_state = koji.BUILD_STATES[binfo['state']]
|
||||
if b_state == 'COMPLETE':
|
||||
need_build = False
|
||||
elif b_state in ['FAILED', 'CANCELED']:
|
||||
if not options.create_build:
|
||||
print("Build %s state is %s. Skipping import" % (nvr, b_state))
|
||||
continue
|
||||
else:
|
||||
print("Build %s exists with state=%s. Skipping import" % (nvr, b_state))
|
||||
continue
|
||||
else:
|
||||
print("Build %s exists with state=%s. Skipping import" % (nvr, b_state))
|
||||
continue
|
||||
|
||||
# import srpms first, if any
|
||||
for path, data in to_import[nvr]:
|
||||
if data['sourcepackage']:
|
||||
if binfo and b_state != 'COMPLETE':
|
||||
# we can not fix state for draft build by createEmptyBuild
|
||||
if not is_draft and binfo and b_state != 'COMPLETE':
|
||||
# need to fix the state
|
||||
print("Creating empty build: %s" % nvr)
|
||||
b_data = koji.util.dslice(binfo, ['name', 'version', 'release'])
|
||||
b_data['epoch'] = data['epoch']
|
||||
session.createEmptyBuild(**b_data)
|
||||
binfo = session.getBuild(nvr)
|
||||
do_import(path, data)
|
||||
dbld = binfo if is_draft else None
|
||||
will_create = False
|
||||
if options.create_draft and not dbld:
|
||||
will_create = True
|
||||
print("Will create draft build with target nvr: %s while importing" % nvr)
|
||||
rpminfo = do_import(path, data, draft_build=dbld)
|
||||
# only needed for draft build, but
|
||||
# TODO: should be able to apply to regular import
|
||||
if rpminfo and rpminfo.get('build', {}).get('draft'):
|
||||
binfo = rpminfo['build']
|
||||
if will_create:
|
||||
print("Draft build: %s created" % binfo['nvr'])
|
||||
need_build = False
|
||||
|
||||
if need_build:
|
||||
|
|
@ -1424,11 +1508,11 @@ def handle_import(goptions, session, args):
|
|||
if binfo:
|
||||
# should have caught this earlier, but just in case...
|
||||
b_state = koji.BUILD_STATES[binfo['state']]
|
||||
print("Build %s state is %s. Skipping import" % (nvr, b_state))
|
||||
print("Build %s state is %s. Skipping import" % (binfo['nvr'], b_state))
|
||||
continue
|
||||
else:
|
||||
print("No such build: %s (include matching srpm or use "
|
||||
"--create-build option to add it)" % nvr)
|
||||
"--create-build/--create-draft option to add it)" % nvr)
|
||||
continue
|
||||
else:
|
||||
# let's make a new build
|
||||
|
|
@ -1439,17 +1523,22 @@ def handle_import(goptions, session, args):
|
|||
# pull epoch from first rpm
|
||||
data = to_import[nvr][0][1]
|
||||
b_data['epoch'] = data['epoch']
|
||||
if options.test:
|
||||
print("Test mode -- would have created empty build: %s" % nvr)
|
||||
if options.create_draft:
|
||||
b_data['draft'] = True
|
||||
b_display = "empty draft build with target nvr: %s" % nvr
|
||||
else:
|
||||
print("Creating empty build: %s" % nvr)
|
||||
session.createEmptyBuild(**b_data)
|
||||
binfo = session.getBuild(nvr)
|
||||
b_display = "empty build: %s" % nvr
|
||||
if options.test:
|
||||
print("Test mode -- would have created %s" % b_display)
|
||||
else:
|
||||
print("Creating %s" % b_display)
|
||||
buildid = session.createEmptyBuild(**b_data)
|
||||
binfo = session.getBuild(buildid)
|
||||
|
||||
for path, data in to_import[nvr]:
|
||||
if data['sourcepackage']:
|
||||
continue
|
||||
do_import(path, data)
|
||||
do_import(path, data, draft_build=binfo if is_draft else None)
|
||||
|
||||
|
||||
def handle_import_cg(goptions, session, args):
|
||||
|
|
@ -2727,11 +2816,15 @@ def anon_handle_list_tagged(goptions, session, args):
|
|||
parser.add_option("--ts", type='int', metavar="TIMESTAMP",
|
||||
help="query at last event before timestamp")
|
||||
parser.add_option("--repo", type='int', metavar="REPO#", help="query at event for a repo")
|
||||
parser.add_option("--draft-only", action="store_true", help="Only list draft builds/rpms")
|
||||
parser.add_option("--no-draft", action="store_true", help="Only list regular builds/rpms")
|
||||
(options, args) = parser.parse_args(args)
|
||||
if len(args) == 0:
|
||||
parser.error("A tag name must be specified")
|
||||
elif len(args) > 2:
|
||||
parser.error("Only one package name may be specified")
|
||||
if options.no_draft and options.draft_only:
|
||||
parser.error("--draft-only conflicts with --no-draft")
|
||||
ensure_connection(session, goptions)
|
||||
pathinfo = koji.PathInfo()
|
||||
package = None
|
||||
|
|
@ -2753,6 +2846,10 @@ def anon_handle_list_tagged(goptions, session, args):
|
|||
options.rpms = True
|
||||
if options.type:
|
||||
opts['type'] = options.type
|
||||
elif options.no_draft:
|
||||
opts['draft'] = koji.FLAG_REGULAR_BUILD
|
||||
elif options.draft_only:
|
||||
opts['draft'] = koji.FLAG_DRAFT_BUILD
|
||||
event = koji.util.eventFromOpts(session, options)
|
||||
event_id = None
|
||||
if event:
|
||||
|
|
@ -2798,7 +2895,9 @@ def anon_handle_list_tagged(goptions, session, args):
|
|||
fmt = "%(path)s"
|
||||
data = [x for x in data if 'path' in x]
|
||||
else:
|
||||
fmt = "%(name)s-%(version)s-%(release)s.%(arch)s"
|
||||
fmt = "%(name)s-%(version)s-%(release)s.%(arch)s%(draft_suffix)s"
|
||||
for x in data:
|
||||
x['draft_suffix'] = (' (#draft_%s)' % x['build_id']) if x.get('draft') else ''
|
||||
if options.sigs:
|
||||
fmt = "%(sigkey)s " + fmt
|
||||
else:
|
||||
|
|
@ -2861,10 +2960,13 @@ def anon_handle_list_buildroot(goptions, session, args):
|
|||
fmt = "%(nvr)s.%(arch)s"
|
||||
order = sorted([(fmt % x, x) for x in list_rpms])
|
||||
for nvra, rinfo in order:
|
||||
if options.verbose and rinfo.get('is_update'):
|
||||
print("%s [update]" % nvra)
|
||||
else:
|
||||
print(nvra)
|
||||
line = nvra
|
||||
if options.verbose:
|
||||
if rinfo.get('draft'):
|
||||
line += " (#draft_%s)" % rinfo['build_id']
|
||||
if rinfo.get('is_update'):
|
||||
line += " [update]"
|
||||
print(line)
|
||||
|
||||
list_archives = session.listArchives(**opts)
|
||||
if list_archives:
|
||||
|
|
@ -3403,6 +3505,8 @@ def anon_handle_list_builds(goptions, session, args):
|
|||
parser.add_option("--source", help="Only builds where the source field matches (glob pattern)")
|
||||
parser.add_option("--owner", help="List builds built by this owner")
|
||||
parser.add_option("--volume", help="List builds by volume ID")
|
||||
parser.add_option("--draft-only", action="store_true", help="Only list draft builds")
|
||||
parser.add_option("--no-draft", action="store_true", help="Only list regular builds")
|
||||
parser.add_option("-k", "--sort-key", action="append", metavar='FIELD',
|
||||
default=[], help="Sort the list by the named field. Allowed sort keys: "
|
||||
"build_id, owner_name, state")
|
||||
|
|
@ -3419,6 +3523,12 @@ def anon_handle_list_builds(goptions, session, args):
|
|||
value = getattr(options, key)
|
||||
if value is not None:
|
||||
opts[key] = value
|
||||
if options.no_draft and options.draft_only:
|
||||
parser.error("--draft-only conflits with --no-draft")
|
||||
elif options.no_draft:
|
||||
opts['draft'] = koji.FLAG_REGULAR_BUILD
|
||||
elif options.draft_only:
|
||||
opts['draft'] = koji.FLAG_DRAFT_BUILD
|
||||
if options.cg:
|
||||
opts['cgID'] = options.cg
|
||||
if options.package:
|
||||
|
|
@ -3520,13 +3630,24 @@ def anon_handle_rpminfo(goptions, session, args):
|
|||
parser = OptionParser(usage=get_usage_str(usage))
|
||||
parser.add_option("--buildroots", action="store_true",
|
||||
help="show buildroots the rpm was used in")
|
||||
parser.add_option("--build", metavar="NVR|ID",
|
||||
help="show the rpm(s) in the build")
|
||||
|
||||
(options, args) = parser.parse_args(args)
|
||||
if len(args) < 1:
|
||||
parser.error("Please specify an RPM")
|
||||
opts = {}
|
||||
build = options.build
|
||||
if options.build:
|
||||
try:
|
||||
build = int(build)
|
||||
except ValueError:
|
||||
pass
|
||||
opts['build'] = build
|
||||
ensure_connection(session, goptions)
|
||||
error_hit = False
|
||||
for rpm in args:
|
||||
info = session.getRPM(rpm)
|
||||
info = session.getRPM(rpm, **opts)
|
||||
if info is None:
|
||||
warn("No such rpm: %s\n" % rpm)
|
||||
error_hit = True
|
||||
|
|
@ -3536,24 +3657,29 @@ def anon_handle_rpminfo(goptions, session, args):
|
|||
else:
|
||||
info['epoch'] = str(info['epoch']) + ":"
|
||||
if not info.get('external_repo_id', 0):
|
||||
buildinfo = session.getBuild(info['build_id'])
|
||||
buildinfo['name'] = buildinfo['package_name']
|
||||
buildinfo['arch'] = 'src'
|
||||
if buildinfo['epoch'] is None:
|
||||
buildinfo['epoch'] = ""
|
||||
if info['arch'] == 'src':
|
||||
srpminfo = info.copy()
|
||||
else:
|
||||
buildinfo['epoch'] = str(buildinfo['epoch']) + ":"
|
||||
srpminfo = session.listRPMs(buildID=info['build_id'], arches='src')[0]
|
||||
if srpminfo['epoch'] is None:
|
||||
srpminfo['epoch'] = ""
|
||||
else:
|
||||
srpminfo['epoch'] = str(srpminfo['epoch']) + ":"
|
||||
buildinfo = session.getBuild(info['build_id'])
|
||||
print("RPM: %(epoch)s%(name)s-%(version)s-%(release)s.%(arch)s [%(id)d]" % info)
|
||||
if info.get('draft'):
|
||||
print("Draft: YES")
|
||||
if info.get('external_repo_id'):
|
||||
repo = session.getExternalRepo(info['external_repo_id'])
|
||||
print("External Repository: %(name)s [%(id)i]" % repo)
|
||||
print("External Repository url: %(url)s" % repo)
|
||||
else:
|
||||
print("Build: %(nvr)s [%(id)d]" % buildinfo)
|
||||
print("RPM Path: %s" %
|
||||
os.path.join(koji.pathinfo.build(buildinfo), koji.pathinfo.rpm(info)))
|
||||
print("SRPM: %(epoch)s%(name)s-%(version)s-%(release)s [%(id)d]" % buildinfo)
|
||||
print("SRPM: %(epoch)s%(name)s-%(version)s-%(release)s [%(id)d]" % srpminfo)
|
||||
print("SRPM Path: %s" %
|
||||
os.path.join(koji.pathinfo.build(buildinfo), koji.pathinfo.rpm(buildinfo)))
|
||||
os.path.join(koji.pathinfo.build(buildinfo), koji.pathinfo.rpm(srpminfo)))
|
||||
print("Built: %s" % time.strftime('%a, %d %b %Y %H:%M:%S %Z',
|
||||
time.localtime(info['buildtime'])))
|
||||
print("SIGMD5: %(payloadhash)s" % info)
|
||||
|
|
@ -3563,6 +3689,7 @@ def anon_handle_rpminfo(goptions, session, args):
|
|||
headers=["license"])
|
||||
if 'license' in headers:
|
||||
print("License: %(license)s" % headers)
|
||||
# kept for backward compatibility
|
||||
print("Build ID: %(build_id)s" % info)
|
||||
if info['buildroot_id'] is None:
|
||||
print("No buildroot data available")
|
||||
|
|
@ -3619,6 +3746,8 @@ def anon_handle_buildinfo(goptions, session, args):
|
|||
info['arch'] = 'src'
|
||||
info['state'] = koji.BUILD_STATES[info['state']]
|
||||
print("BUILD: %(name)s-%(version)s-%(release)s [%(id)d]" % info)
|
||||
if info.get('draft'):
|
||||
print("Draft: YES")
|
||||
print("State: %(state)s" % info)
|
||||
if info['state'] == 'BUILDING':
|
||||
print("Reserved by: %(cg_name)s" % info)
|
||||
|
|
|
|||
|
|
@ -925,3 +925,10 @@ class DatetimeJSONEncoder(json.JSONEncoder):
|
|||
if isinstance(o, xmlrpc_client.DateTime):
|
||||
return str(o)
|
||||
return json.JSONEncoder.default(self, o)
|
||||
|
||||
|
||||
def yesno(x):
|
||||
if x:
|
||||
return 'Y'
|
||||
else:
|
||||
return 'N'
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@ from __future__ import absolute_import, division
|
|||
import base64
|
||||
import datetime
|
||||
import errno
|
||||
import functools
|
||||
import hashlib
|
||||
import json
|
||||
import logging
|
||||
|
|
@ -274,6 +275,7 @@ TAG_UPDATE_TYPES = Enum((
|
|||
'VOLUME_CHANGE',
|
||||
'IMPORT',
|
||||
'MANUAL',
|
||||
'DRAFT_PROMOTION',
|
||||
))
|
||||
|
||||
# BEGIN kojikamid dup #
|
||||
|
|
@ -295,6 +297,44 @@ PRIO_DEFAULT = 20
|
|||
DEFAULT_REQUEST_TIMEOUT = 60 * 60 * 12
|
||||
DEFAULT_AUTH_TIMEOUT = 60
|
||||
|
||||
# draft release format
|
||||
DRAFT_RELEASE_FORMAT = '{release}#draft_{id}'
|
||||
|
||||
FLAG_DRAFT_BUILD = 1
|
||||
FLAG_REGULAR_BUILD = 2
|
||||
FLAG_ALL_BUILD = FLAG_DRAFT_BUILD | FLAG_REGULAR_BUILD
|
||||
|
||||
if six.PY3:
|
||||
from enum import IntFlag
|
||||
|
||||
# draft build bit FLAGs
|
||||
class DRAFT_FLAG(IntFlag):
|
||||
|
||||
DRAFT = FLAG_DRAFT_BUILD
|
||||
REGULAR = FLAG_REGULAR_BUILD
|
||||
ALL = FLAG_ALL_BUILD
|
||||
|
||||
@classmethod
|
||||
def _missing_(cls, value):
|
||||
if not isinstance(value, int):
|
||||
raise ValueError("%r is not a valid %s" % (value, cls.__name__))
|
||||
# diable member creation and negative integer
|
||||
return cls._value2member_map_.get(value)
|
||||
|
||||
def convert_draft_option(func=None, kw='draft'):
|
||||
def wrapper(func):
|
||||
@functools.wraps(func)
|
||||
def convert(*args, **kwargs):
|
||||
if kw in kwargs:
|
||||
kwargs[kw] = DRAFT_FLAG(kwargs[kw])
|
||||
return func(*args, **kwargs)
|
||||
return convert
|
||||
if func is None:
|
||||
return wrapper
|
||||
else:
|
||||
return wrapper(func)
|
||||
|
||||
|
||||
# BEGIN kojikamid dup #
|
||||
|
||||
# Exceptions
|
||||
|
|
@ -2363,6 +2403,39 @@ class PathInfo(object):
|
|||
return self.volumedir(build.get('volume_name')) + \
|
||||
("/packages/%(name)s/%(version)s/%(release)s" % build)
|
||||
|
||||
def to_buildinfo(self, path):
|
||||
"""Revert build dir path (<topdir>/[<volumedir>/]packages/<name>/<version>/<release>)
|
||||
to build map with the data below:
|
||||
|
||||
- name
|
||||
- version
|
||||
- release
|
||||
- volume_name
|
||||
"""
|
||||
path = path.rstrip('/')
|
||||
parts = path.rsplit('/', 4)
|
||||
if len(parts) != 5:
|
||||
raise GenericError("Invalid build path: %s" % path)
|
||||
if parts[-4] != 'packages':
|
||||
raise GenericError("Invalid build path: %s, packages subdir not found" % path)
|
||||
nvr = parts[-3:]
|
||||
rest = parts[0]
|
||||
if not rest.startswith(self.topdir):
|
||||
raise GenericError("Invalid build path: %s, topdir is not %r" % (path, self.topdir))
|
||||
vol_part = rest[len(self.topdir):]
|
||||
if not vol_part:
|
||||
vol = 'DEFAULT'
|
||||
elif vol_part.startswith('/vol/'):
|
||||
vol = vol_part[5:]
|
||||
else:
|
||||
raise GenericError(
|
||||
"Invalid build path: %s, volume dir: %s is incorrect" % (path, vol_part)
|
||||
)
|
||||
return {'name': nvr[0],
|
||||
'version': nvr[1],
|
||||
'release': nvr[2],
|
||||
'volume_name': vol}
|
||||
|
||||
def mavenbuild(self, build):
|
||||
"""Return the directory where the Maven build exists in the global store
|
||||
(/mnt/koji/packages)"""
|
||||
|
|
@ -2410,6 +2483,27 @@ class PathInfo(object):
|
|||
"""Return the path (relative to build_dir) where an rpm belongs"""
|
||||
return "%(arch)s/%(name)s-%(version)s-%(release)s.%(arch)s.rpm" % rpminfo
|
||||
|
||||
def to_rpminfo(self, path, full=False):
|
||||
"""Revert rpm path in build dir to rpm nvra map with/without build dir"""
|
||||
if path.endswith('/'):
|
||||
raise GenericError("Invalid path: %s, cannot be a directory" % path)
|
||||
parts = path.rsplit('/', 2)
|
||||
if full:
|
||||
if len(parts) != 3:
|
||||
raise GenericError("No build dir in path: %s" % path)
|
||||
return self.to_buildinfo(parts[-3]), self._to_rpminfo(parts[-2:])
|
||||
return self._to_rpminfo(parts)
|
||||
|
||||
def _to_rpminfo(self, parts):
|
||||
if len(parts) != 2 or not parts[0]:
|
||||
raise GenericError("Invalid path: %s" % '/'.join(parts))
|
||||
rpminfo = parse_NVRA(parts[-1])
|
||||
if parts[0] != rpminfo['arch']:
|
||||
raise GenericError(
|
||||
'mismatch between arch dir (%s) and arch (%s) in rpm' % (parts[0], rpminfo)
|
||||
)
|
||||
return rpminfo
|
||||
|
||||
def signed(self, rpminfo, sigkey):
|
||||
"""Return the path (relative to build dir) where a signed rpm lives"""
|
||||
return "data/signed/%s/" % sigkey + self.rpm(rpminfo)
|
||||
|
|
|
|||
|
|
@ -60,6 +60,8 @@ callbacks = {
|
|||
'postRepoInit': [],
|
||||
'preRepoDone': [],
|
||||
'postRepoDone': [],
|
||||
'preBuildPromote': [],
|
||||
'postBuildPromote': [],
|
||||
'preCommit': [],
|
||||
'postCommit': [],
|
||||
# builder
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -610,6 +610,11 @@ _default_policies = {
|
|||
'priority': '''
|
||||
all :: stay
|
||||
''',
|
||||
'draft_promotion': '''
|
||||
has_perm draft-promoter :: allow
|
||||
is_build_owner :: allow
|
||||
all :: deny Only draft-promoter and build owner can do this via default policy
|
||||
'''
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -320,6 +320,22 @@ def prep_repo_done(cbtype, *args, **kws):
|
|||
queue_msg(address, props, kws)
|
||||
|
||||
|
||||
@convert_datetime
|
||||
@callback('postBuildPromote')
|
||||
def prep_build_promote(cbtype, *args, **kws):
|
||||
kws['build'] = _strip_extra(kws['build'])
|
||||
address = 'build.promote'
|
||||
props = {'type': cbtype[4:],
|
||||
'build_id': kws['build']['id'],
|
||||
'name': kws['build']['name'],
|
||||
'version': kws['build']['version'],
|
||||
'release': kws['build']['release'],
|
||||
'draft_release': kws['draft_release'],
|
||||
'target_release': kws['target_release'],
|
||||
'user': kws['user']['name']}
|
||||
queue_msg(address, props, kws)
|
||||
|
||||
|
||||
def _send_msgs(urls, msgs, CONFIG):
|
||||
random.shuffle(urls)
|
||||
for url in urls:
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
-- from version 1.33 to 1.34
|
||||
|
||||
BEGIN;
|
||||
|
||||
-- scheduler tables
|
||||
CREATE TABLE scheduler_task_runs (
|
||||
id SERIAL NOT NULL PRIMARY KEY,
|
||||
|
|
@ -48,4 +49,27 @@ BEGIN;
|
|||
) WITHOUT OIDS;
|
||||
|
||||
INSERT INTO locks(name) VALUES('scheduler');
|
||||
|
||||
-- draft builds
|
||||
INSERT INTO permissions (name, description) VALUES ('draft-promoter', 'The permission required in the default "draft_promotion" hub policy rule to promote draft build.');
|
||||
|
||||
ALTER TABLE build ADD COLUMN draft BOOLEAN NOT NULL DEFAULT 'false';
|
||||
ALTER TABLE build ADD CONSTRAINT draft_for_rpminfo UNIQUE (id, draft);
|
||||
ALTER TABLE build ADD CONSTRAINT draft_release_sane CHECK
|
||||
((draft AND release ~ ('^.*#draft_' || id::TEXT || '$'))
|
||||
OR NOT draft);
|
||||
|
||||
ALTER TABLE rpminfo ADD COLUMN draft BOOLEAN;
|
||||
ALTER TABLE rpminfo DROP CONSTRAINT rpminfo_build_id_fkey;
|
||||
ALTER TABLE rpminfo ADD CONSTRAINT rpminfo_build_id_draft_fkey
|
||||
FOREIGN KEY (build_id, draft) REFERENCES build(id, draft)
|
||||
ON UPDATE CASCADE;
|
||||
ALTER TABLE rpminfo DROP CONSTRAINT rpminfo_unique_nvra;
|
||||
ALTER TABLE rpminfo ADD CONSTRAINT build_id_draft_external_repo_id_sane
|
||||
CHECK ((draft IS NULL AND build_id IS NULL AND external_repo_id <> 0)
|
||||
OR (draft IS NOT NULL AND build_id IS NOT NULL AND external_repo_id = 0));
|
||||
CREATE UNIQUE INDEX rpminfo_unique_nvra_not_draft
|
||||
ON rpminfo(name,version,release,arch,external_repo_id)
|
||||
WHERE draft IS NOT TRUE;
|
||||
|
||||
COMMIT;
|
||||
|
|
|
|||
|
|
@ -66,6 +66,7 @@ INSERT INTO permissions (name, description) VALUES ('tag', 'Manage packages in t
|
|||
INSERT INTO permissions (name, description) VALUES ('target', 'Add, edit, and remove targets.');
|
||||
INSERT INTO permissions (name, description) VALUES ('win-admin', 'The default hub policy rule for "vm" requires this permission to trigger Windows builds.');
|
||||
INSERT INTO permissions (name, description) VALUES ('win-import', 'Import win archives.');
|
||||
INSERT INTO permissions (name, description) VALUES ('draft-promoter', 'The permission required in the default "draft_promotion" hub policy rule to promote draft build.');
|
||||
|
||||
CREATE TABLE user_perms (
|
||||
user_id INTEGER NOT NULL REFERENCES users(id),
|
||||
|
|
@ -279,11 +280,12 @@ CREATE TABLE content_generator (
|
|||
-- null, or may point to a deleted task.
|
||||
CREATE TABLE build (
|
||||
id SERIAL NOT NULL PRIMARY KEY,
|
||||
volume_id INTEGER NOT NULL REFERENCES volume (id),
|
||||
volume_id INTEGER NOT NULL REFERENCES volume (id),
|
||||
pkg_id INTEGER NOT NULL REFERENCES package (id) DEFERRABLE,
|
||||
version TEXT NOT NULL,
|
||||
release TEXT NOT NULL,
|
||||
epoch INTEGER,
|
||||
draft BOOLEAN NOT NULL DEFAULT 'false',
|
||||
source TEXT,
|
||||
create_event INTEGER NOT NULL REFERENCES events(id) DEFAULT get_event(),
|
||||
start_time TIMESTAMPTZ,
|
||||
|
|
@ -294,8 +296,11 @@ CREATE TABLE build (
|
|||
cg_id INTEGER REFERENCES content_generator(id),
|
||||
extra TEXT,
|
||||
CONSTRAINT build_pkg_ver_rel UNIQUE (pkg_id, version, release),
|
||||
CONSTRAINT draft_for_rpminfo UNIQUE (id, draft),
|
||||
CONSTRAINT completion_sane CHECK ((state = 0 AND completion_time IS NULL) OR
|
||||
(state != 0 AND completion_time IS NOT NULL))
|
||||
(state <> 0 AND completion_time IS NOT NULL)),
|
||||
CONSTRAINT draft_release_sane CHECK ((draft AND release ~ ('^.*#draft_' || id::TEXT || '$')) OR
|
||||
NOT draft)
|
||||
) WITHOUT OIDS;
|
||||
|
||||
CREATE INDEX build_by_pkg_id ON build (pkg_id);
|
||||
|
|
@ -721,22 +726,28 @@ CREATE TABLE group_package_listing (
|
|||
-- we don't store filename b/c filename should be N-V-R.A.rpm
|
||||
CREATE TABLE rpminfo (
|
||||
id SERIAL NOT NULL PRIMARY KEY,
|
||||
build_id INTEGER REFERENCES build (id),
|
||||
build_id INTEGER,
|
||||
buildroot_id INTEGER REFERENCES buildroot (id),
|
||||
name TEXT NOT NULL,
|
||||
version TEXT NOT NULL,
|
||||
release TEXT NOT NULL,
|
||||
epoch INTEGER,
|
||||
arch VARCHAR(16) NOT NULL,
|
||||
draft BOOLEAN,
|
||||
external_repo_id INTEGER NOT NULL REFERENCES external_repo(id),
|
||||
payloadhash TEXT NOT NULL,
|
||||
size BIGINT NOT NULL,
|
||||
buildtime BIGINT NOT NULL,
|
||||
metadata_only BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
extra TEXT,
|
||||
CONSTRAINT rpminfo_unique_nvra UNIQUE (name,version,release,arch,external_repo_id)
|
||||
FOREIGN KEY (build_id, draft) REFERENCES build (id, draft) ON UPDATE CASCADE,
|
||||
CONSTRAINT build_id_draft_external_repo_id_sane CHECK (
|
||||
(draft IS NULL AND build_id IS NULL AND external_repo_id <> 0)
|
||||
OR (draft IS NOT NULL AND build_id IS NOT NULL AND external_repo_id = 0))
|
||||
) WITHOUT OIDS;
|
||||
CREATE INDEX rpminfo_build ON rpminfo(build_id);
|
||||
CREATE UNIQUE INDEX rpminfo_unique_nvra_not_draft ON rpminfo(name,version,release,arch,external_repo_id)
|
||||
WHERE draft IS NOT TRUE;
|
||||
-- index for default search method for rpms, PG11+ can benefit from new include method
|
||||
DO $$
|
||||
DECLARE version integer;
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ X-Koji-Tag: f23
|
|||
X-Koji-Package: sisu
|
||||
X-Koji-Builder: user
|
||||
X-Koji-Status: complete
|
||||
X-Koji-Draft: False
|
||||
|
||||
Package: sisu-0.3.0-0.2.M1.fc23
|
||||
Tag: f23
|
||||
|
|
|
|||
|
|
@ -22,7 +22,8 @@
|
|||
"completion_ts": 1424271457.10787,
|
||||
"id": 612609,
|
||||
"volume_name": "DEFAULT",
|
||||
"nvr": "sisu-0.3.0-0.2.M1.fc23"
|
||||
"nvr": "sisu-0.3.0-0.2.M1.fc23",
|
||||
"draft": false
|
||||
},
|
||||
"target": {
|
||||
"dest_tag": 292,
|
||||
|
|
|
|||
|
|
@ -176,6 +176,7 @@ Options:
|
|||
Provide a JSON string of custom metadata to be
|
||||
deserialized and stored under the build's
|
||||
extra.custom_user_metadata field
|
||||
--draft Build draft build instead
|
||||
""" % (self.progname, self.progname))
|
||||
|
||||
# Finally, assert that things were called as we expected.
|
||||
|
|
|
|||
|
|
@ -69,6 +69,37 @@ Volume: DEFAULT
|
|||
Task: 8 build (target, src)
|
||||
Finished: Thu, 04 Mar 2021 14:45:40 UTC
|
||||
Tags:
|
||||
"""
|
||||
anon_handle_buildinfo(self.options, self.session, [build])
|
||||
self.assert_console_message(stdout, expected_stdout)
|
||||
self.session.listTags.assert_called_once_with(build)
|
||||
self.session.getBuild.assert_called_once_with(build)
|
||||
self.session.getTaskInfo.assert_called_once_with(self.buildinfo['task_id'], request=True)
|
||||
self.session.getMavenBuild.assert_called_once_with(self.buildinfo['id'])
|
||||
self.session.getWinBuild.assert_called_once_with(self.buildinfo['id'])
|
||||
self.session.listRPMs.assert_called_once_with(buildID=self.buildinfo['id'])
|
||||
self.assertEqual(self.session.listArchives.call_count, 4)
|
||||
|
||||
@mock.patch('sys.stdout', new_callable=StringIO)
|
||||
def test_buildinfo_draft(self, stdout):
|
||||
build = 'test-build-1-1'
|
||||
binfo = copy.deepcopy(self.buildinfo)
|
||||
binfo['draft'] = True
|
||||
self.session.getBuild.return_value = binfo
|
||||
self.session.getTaskInfo.return_value = self.taskinfo
|
||||
self.session.listTags.return_value = []
|
||||
self.session.getMavenBuild.return_value = None
|
||||
self.session.getWinBuild.return_value = None
|
||||
self.session.listArchives.return_value = []
|
||||
self.session.listRPMs.return_value = []
|
||||
expected_stdout = """BUILD: test-build-1-1 [1]
|
||||
Draft: YES
|
||||
State: COMPLETE
|
||||
Built by: kojiadmin
|
||||
Volume: DEFAULT
|
||||
Task: 8 build (target, src)
|
||||
Finished: Thu, 04 Mar 2021 14:45:40 UTC
|
||||
Tags:
|
||||
"""
|
||||
anon_handle_buildinfo(self.options, self.session, [build])
|
||||
self.assert_console_message(stdout, expected_stdout)
|
||||
|
|
|
|||
|
|
@ -87,15 +87,22 @@ class TestImport(utils.CliTestCase):
|
|||
def __do_import_test(self, options, session, arguments, **kwargs):
|
||||
expected = kwargs.get('expected', None)
|
||||
rpm_header = kwargs.get('rpm_header', {})
|
||||
rpm_headers = kwargs.get('rpm_headers', [])
|
||||
if not rpm_headers:
|
||||
rpm_headers = [rpm_header]
|
||||
fake_srv_path = kwargs.get('srv_path', '/path/to/server/import')
|
||||
upload_rpm_mock = kwargs.get('upload_rpm_mock', session.uploadWrapper)
|
||||
getrpm_called = kwargs.get('getrpm_called', True)
|
||||
getrpm_calls = kwargs.get('getrpm_calls', [])
|
||||
import_opts = kwargs.get('import_opts', {})
|
||||
import_rpm_calls = kwargs.get('import_rpm_calls', None)
|
||||
|
||||
with mock.patch('koji.get_header_fields') as get_header_fields_mock:
|
||||
with mock.patch('koji_cli.commands.unique_path') as unique_path_mock:
|
||||
with mock.patch('koji_cli.commands.activate_session') as activate_session_mock:
|
||||
with mock.patch('sys.stdout', new_callable=six.StringIO) as stdout:
|
||||
with upload_rpm_mock:
|
||||
get_header_fields_mock.return_value = rpm_header
|
||||
get_header_fields_mock.side_effect = rpm_headers
|
||||
unique_path_mock.return_value = fake_srv_path
|
||||
handle_import(options, session, arguments)
|
||||
|
||||
|
|
@ -104,21 +111,33 @@ class TestImport(utils.CliTestCase):
|
|||
|
||||
# check mock calls
|
||||
activate_session_mock.assert_called_with(session, options)
|
||||
get_header_fields_mock.assert_called_with(
|
||||
arguments[0],
|
||||
('name', 'version', 'release', 'epoch',
|
||||
'arch', 'sigmd5', 'sourcepackage', 'sourcerpm')
|
||||
)
|
||||
|
||||
get_header_fields_calls = [
|
||||
mock.call(arguments[i],
|
||||
('name', 'version', 'release', 'epoch',
|
||||
'arch', 'sigmd5', 'sourcepackage', 'sourcerpm')
|
||||
) for i in range(len(rpm_headers) - 1)
|
||||
]
|
||||
|
||||
session.getRPM.assert_called_with(
|
||||
dict((k, rpm_header.get(k, ''))
|
||||
for k in ['release', 'version', 'arch', 'name'])
|
||||
)
|
||||
get_header_fields_mock.assert_has_calls(get_header_fields_calls)
|
||||
|
||||
if getrpm_calls:
|
||||
session.getRPM.assert_has_calls(getrpm_calls)
|
||||
elif getrpm_called:
|
||||
session.getRPM.assert_called_with(
|
||||
dict((k, rpm_header.get(k, ''))
|
||||
for k in ['release', 'version', 'arch', 'name'])
|
||||
)
|
||||
else:
|
||||
session.getRPM.assert_not_called()
|
||||
|
||||
unique_path_mock.assert_called_with('cli-import')
|
||||
upload_rpm_mock.assert_called_with(arguments[0], self.fake_srv_dir)
|
||||
session.importRPM.assert_called_with(
|
||||
self.fake_srv_dir, os.path.basename(arguments[0]))
|
||||
if import_rpm_calls:
|
||||
session.importRPM.assert_has_calls(import_rpm_calls)
|
||||
else:
|
||||
session.importRPM.assert_called_with(
|
||||
self.fake_srv_dir, os.path.basename(arguments[0]), **import_opts)
|
||||
|
||||
# reset for next test
|
||||
activate_session_mock.reset_mock()
|
||||
|
|
@ -136,6 +155,7 @@ class TestImport(utils.CliTestCase):
|
|||
expected = kwargs.get('expected', None)
|
||||
expected_warn = kwargs.get('expected_warn', None)
|
||||
rpm_header = kwargs.get('rpm_header', {})
|
||||
getrpm_called = kwargs.get('getrpm_called', True)
|
||||
|
||||
with mock.patch('koji.get_header_fields') as get_header_fields_mock:
|
||||
get_header_fields_mock.return_value = rpm_header
|
||||
|
|
@ -152,11 +172,13 @@ class TestImport(utils.CliTestCase):
|
|||
('name', 'version', 'release', 'epoch',
|
||||
'arch', 'sigmd5', 'sourcepackage', 'sourcerpm')
|
||||
)
|
||||
|
||||
session.getRPM.assert_called_with(
|
||||
dict((k, rpm_header.get(k, ''))
|
||||
for k in ['release', 'version', 'arch', 'name'])
|
||||
)
|
||||
if getrpm_called:
|
||||
session.getRPM.assert_called_with(
|
||||
dict((k, rpm_header.get(k, ''))
|
||||
for k in ['release', 'version', 'arch', 'name'])
|
||||
)
|
||||
else:
|
||||
session.getRPM.assert_not_called()
|
||||
|
||||
session.uploadWrapper.assert_not_called()
|
||||
session.importRPM.assert_not_called()
|
||||
|
|
@ -677,6 +699,225 @@ class TestImport(utils.CliTestCase):
|
|||
activate_session=None)
|
||||
activate_session_mock.assert_not_called()
|
||||
|
||||
@mock.patch('sys.stdout', new_callable=six.StringIO)
|
||||
@mock.patch('sys.stderr', new_callable=six.StringIO)
|
||||
@mock.patch('koji_cli.commands.activate_session')
|
||||
def test_handle_import_src_rpm_with_create_draft(
|
||||
self,
|
||||
activate_session_mock,
|
||||
stderr,
|
||||
stdout):
|
||||
"""Test handle_import SRPM import with creating draft build case."""
|
||||
arguments = ['/path/to/bash-4.4.12-5.fc26.rpm', '--create-draft']
|
||||
options = mock.MagicMock()
|
||||
session = mock.MagicMock()
|
||||
session.importRPM.return_value = {'build': {'nvr': 'a-draft-build', 'draft': True}}
|
||||
|
||||
nvr = '%(name)s-%(version)s-%(release)s' % self.srpm_header
|
||||
|
||||
# Case 1. import src rpm with --create-draft
|
||||
# result: success
|
||||
expected = "Will create draft build instead if desired nvr doesn't exist\n"
|
||||
expected += "Will create draft build with target nvr: %s while importing\n" % nvr
|
||||
expected += "uploading %s... done\n" % arguments[0]
|
||||
expected += "importing %s... done\n" % arguments[0]
|
||||
expected += "Draft build: a-draft-build created\n"
|
||||
|
||||
self.__do_import_test(
|
||||
options, session, arguments,
|
||||
rpm_header=self.srpm_header,
|
||||
expected=expected,
|
||||
getrpm_called=False,
|
||||
import_opts={'draft': True})
|
||||
|
||||
@mock.patch('sys.stdout', new_callable=six.StringIO)
|
||||
@mock.patch('sys.stderr', new_callable=six.StringIO)
|
||||
@mock.patch('koji_cli.commands.activate_session')
|
||||
def test_handle_import_binary_rpm_with_create_draft(
|
||||
self,
|
||||
activate_session_mock,
|
||||
stderr,
|
||||
stdout):
|
||||
"""Test handle_import binary RPM import with creating draft build case."""
|
||||
arguments = ['/path/to/bash-4.4.12-5.fc26.rpm', '--create-draft']
|
||||
options = mock.MagicMock()
|
||||
session = mock.MagicMock()
|
||||
|
||||
nvr = '%(name)s-%(version)s-%(release)s' % self.rpm_header
|
||||
|
||||
# Case 1. import bin rpm with --create-draft
|
||||
# result: Aborting import
|
||||
expected = "Will create draft build instead if desired nvr doesn't exist\n"
|
||||
expected += "Missing srpm for draft build creating with target nvr: %s\n" % nvr
|
||||
expected += "Aborting import\n"
|
||||
self.__skip_import_test(
|
||||
options, session, arguments,
|
||||
rpm_header=self.rpm_header,
|
||||
expected=expected,
|
||||
getrpm_called=False)
|
||||
|
||||
@mock.patch('sys.stdout', new_callable=six.StringIO)
|
||||
@mock.patch('sys.stderr', new_callable=six.StringIO)
|
||||
@mock.patch('koji_cli.commands.activate_session')
|
||||
def test_handle_import_src_bin_rpm_with_create_draft(
|
||||
self,
|
||||
activate_session_mock,
|
||||
stderr,
|
||||
stdout):
|
||||
"""Test handle_import SRPM & RPM import with creating draft build case."""
|
||||
arguments = ['/path/to/bash-4.4.12-5.fc26.rpm', '/path/to/bash-4.4.12-5.fc26.src.rpm',
|
||||
'--create-draft']
|
||||
options = mock.MagicMock()
|
||||
session = mock.MagicMock()
|
||||
session.getRPM.return_value = None
|
||||
session.importRPM.return_value = {'build': {'nvr': 'a-draft-build', 'draft': True}}
|
||||
|
||||
nvr = '%(name)s-%(version)s-%(release)s' % self.srpm_header
|
||||
|
||||
# Case 1. import src & bin rpm with --create-draft
|
||||
# result: success
|
||||
expected = "Will create draft build instead if desired nvr doesn't exist\n"
|
||||
expected += "Will create draft build with target nvr: %s while importing\n" % nvr
|
||||
expected += "uploading %s... done\n" % arguments[1]
|
||||
expected += "importing %s... done\n" % arguments[1]
|
||||
expected += "Draft build: a-draft-build created\n"
|
||||
expected += "uploading %s... done\n" % arguments[0]
|
||||
expected += "importing %s... done\n" % arguments[0]
|
||||
|
||||
self.__do_import_test(
|
||||
options, session, arguments,
|
||||
rpm_headers=[self.rpm_header, self.srpm_header],
|
||||
expected=expected,
|
||||
getrpm_calls=[
|
||||
mock.call(
|
||||
{'name': 'bash', 'version': '4.4.12', 'release': '5.fc26', 'arch': 'x86_64'},
|
||||
build=session.importRPM.return_value['build']
|
||||
)
|
||||
],
|
||||
import_rpm_calls=[
|
||||
mock.call(
|
||||
self.fake_srv_dir, os.path.basename(arguments[1]), draft=True
|
||||
),
|
||||
mock.call(
|
||||
self.fake_srv_dir, os.path.basename(arguments[0]),
|
||||
build=session.importRPM.return_value['build'], draft=True
|
||||
)
|
||||
])
|
||||
|
||||
@mock.patch('sys.stdout', new_callable=six.StringIO)
|
||||
@mock.patch('sys.stderr', new_callable=six.StringIO)
|
||||
@mock.patch('koji_cli.commands.activate_session')
|
||||
def test_handle_import_src_rpm_with_specified_draft_build(
|
||||
self,
|
||||
activate_session_mock,
|
||||
stderr,
|
||||
stdout):
|
||||
"""Test handle_import SRPM import with --draft-build case."""
|
||||
arguments = ['/path/to/bash-4.4.12-5.fc26.rpm', '--draft-build', 'a-draft-build']
|
||||
options = mock.MagicMock()
|
||||
session = mock.MagicMock()
|
||||
build = {
|
||||
'name': 'bash',
|
||||
'version': '4.4.12',
|
||||
'release': '5.fc26#draft_123',
|
||||
'nvr': 'bash-4.4.12-5.fc26',
|
||||
'draft': True,
|
||||
'extra': {
|
||||
'draft': {
|
||||
'target_release': '5.fc26'
|
||||
}
|
||||
},
|
||||
'state': self.bstate['COMPLETE']
|
||||
}
|
||||
session.getBuild.return_value = build
|
||||
|
||||
# Case 1. import src rpm with --draft-build
|
||||
# result: success
|
||||
expected = "uploading %s... done\n" % arguments[0]
|
||||
expected += "importing %s... done\n" % arguments[0]
|
||||
|
||||
self.__do_import_test(
|
||||
options, session, arguments,
|
||||
rpm_header=self.srpm_header,
|
||||
expected=expected,
|
||||
getrpm_calls=[mock.call(
|
||||
{'name': 'bash', 'version': '4.4.12', 'release': '5.fc26', 'arch': 'src'},
|
||||
build=build)],
|
||||
import_opts={'build': build, 'draft': True})
|
||||
|
||||
@mock.patch('sys.stdout', new_callable=six.StringIO)
|
||||
@mock.patch('sys.stderr', new_callable=six.StringIO)
|
||||
@mock.patch('koji_cli.commands.activate_session')
|
||||
def test_handle_import_binary_rpm_with_specified_draft_build(
|
||||
self,
|
||||
activate_session_mock,
|
||||
stderr,
|
||||
stdout):
|
||||
"""Test handle_import RPM import with --draft-build case."""
|
||||
arguments = ['/path/to/bash-4.4.12-5.fc26.rpm', '--draft-build', 'a-draft-build']
|
||||
options = mock.MagicMock()
|
||||
session = mock.MagicMock()
|
||||
session.getRPM.return_value = None
|
||||
build = {
|
||||
'name': 'bash',
|
||||
'version': '4.4.12',
|
||||
'release': '5.fc26#draft_123',
|
||||
'nvr': 'bash-4.4.12-5.fc26',
|
||||
'draft': True,
|
||||
'extra': {
|
||||
'draft': {
|
||||
'target_release': '5.fc26'
|
||||
}
|
||||
},
|
||||
'state': self.bstate['COMPLETE']
|
||||
}
|
||||
session.getBuild.return_value = build
|
||||
|
||||
# Case 1. import bin rpm with --draft-build
|
||||
# result: success
|
||||
expected = "uploading %s... done\n" % arguments[0]
|
||||
expected += "importing %s... done\n" % arguments[0]
|
||||
|
||||
self.__do_import_test(
|
||||
options, session, arguments,
|
||||
rpm_header=self.rpm_header,
|
||||
expected=expected,
|
||||
getrpm_calls=[mock.call(
|
||||
{'name': 'bash', 'version': '4.4.12', 'release': '5.fc26', 'arch': 'x86_64'},
|
||||
build=build)],
|
||||
import_opts={'build': build, 'draft': True})
|
||||
|
||||
def test_handle_import_specified_draft_build_invalid(self):
|
||||
"""Test handle_import RPM import with --draft-build case."""
|
||||
arguments = ['/path/to/bash-4.4.12-5.fc26.rpm', '--draft-build', '286']
|
||||
options = mock.MagicMock()
|
||||
session = mock.MagicMock()
|
||||
|
||||
cases = [
|
||||
# build, stderr
|
||||
(None, "No such build: 286"),
|
||||
({'draft': False, 'nvr': 'a-bad-draft'}, "a-bad-draft is not a draft build"),
|
||||
({'draft': True, 'nvr': 'a-bad-draft', 'state': koji.BUILD_STATES['DELETED']},
|
||||
"draft build a-bad-draft is expected as COMPLETE, got DELETED"),
|
||||
({'draft': True, 'nvr': 'a-bad-draft', 'state': koji.BUILD_STATES['COMPLETE'],
|
||||
'extra': {'draft': {'no_target_release': 'omg'}}},
|
||||
"Invalid draft build: a-bad-draft, no draft.target_release found in extra")
|
||||
]
|
||||
for build, expected in cases:
|
||||
session.getBuild.return_value = build
|
||||
# result: error
|
||||
expected += "\n"
|
||||
self.assert_system_exit(
|
||||
handle_import,
|
||||
options,
|
||||
session,
|
||||
arguments,
|
||||
stderr=expected,
|
||||
activate_session=None,
|
||||
exit_code=1)
|
||||
options.reset_mock()
|
||||
session.reset_mock()
|
||||
|
||||
def test_handle_import_help(self):
|
||||
"""Test handle_import function help message"""
|
||||
self.assert_help(
|
||||
|
|
@ -691,6 +932,8 @@ Options:
|
|||
--create-build Auto-create builds as needed
|
||||
--src-epoch=SRC_EPOCH
|
||||
When auto-creating builds, use this epoch
|
||||
--create-draft Auto-create draft builds instead as needed
|
||||
--draft-build=NVR|ID The target draft build to import to
|
||||
""" % self.progname)
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -609,6 +609,8 @@ Options:
|
|||
pattern)
|
||||
--owner=OWNER List builds built by this owner
|
||||
--volume=VOLUME List builds by volume ID
|
||||
--draft-only Only list draft builds
|
||||
--no-draft Only list regular builds
|
||||
-k FIELD, --sort-key=FIELD
|
||||
Sort the list by the named field. Allowed sort keys:
|
||||
build_id, owner_name, state
|
||||
|
|
|
|||
|
|
@ -42,6 +42,15 @@ class TestCliListTagged(utils.CliTestCase):
|
|||
'release': '1.el6',
|
||||
'arch': 'x86_64',
|
||||
'sigkey': 'sigkey',
|
||||
'extra': None},
|
||||
{'id': 102,
|
||||
'build_id': 2,
|
||||
'name': 'rpmA',
|
||||
'version': '0.0.1',
|
||||
'release': '2.el6',
|
||||
'arch': 'x86_64',
|
||||
'sigkey': 'sigkey',
|
||||
'draft': True,
|
||||
'extra': None}
|
||||
], [{'id': 1,
|
||||
'name': 'packagename',
|
||||
|
|
@ -50,6 +59,15 @@ class TestCliListTagged(utils.CliTestCase):
|
|||
'nvr': 'n-v-r',
|
||||
'tag_name': 'tag',
|
||||
'owner_name': 'owner',
|
||||
'extra': 'extra-value-2'},
|
||||
{'id': 2,
|
||||
'name': 'packagename',
|
||||
'version': 'version',
|
||||
'release': '2.el6#draft_2',
|
||||
'nvr': 'n-v-r',
|
||||
'draft': True,
|
||||
'tag_name': 'tag',
|
||||
'owner_name': 'owner',
|
||||
'extra': 'extra-value-2'}]]
|
||||
self.session.listTagged.return_value = [{'id': 1,
|
||||
'name': 'packagename',
|
||||
|
|
@ -77,13 +95,15 @@ Build Tag Built by
|
|||
---------------------------------------- -------------------- ----------------
|
||||
n-v-r tag owner
|
||||
"""
|
||||
args = [self.tag, self.pkg, '--latest', '--inherit', '--event', str(self.event_id)]
|
||||
args = [self.tag, self.pkg, '--no-draft', '--latest', '--inherit',
|
||||
'--event', str(self.event_id)]
|
||||
|
||||
anon_handle_list_tagged(self.options, self.session, args)
|
||||
self.ensure_connection_mock.assert_called_once_with(self.session, self.options)
|
||||
self.session.getTag.assert_called_once_with(self.tag, event=self.event_id)
|
||||
self.session.listTagged.assert_called_once_with(
|
||||
self.tag, event=self.event_id, inherit=True, latest=True, package=self.pkg)
|
||||
self.tag, event=self.event_id, inherit=True, latest=True, package=self.pkg,
|
||||
draft=2)
|
||||
self.session.listTaggedRPMS.assert_not_called()
|
||||
self.assert_console_message(stdout, expected)
|
||||
|
||||
|
|
@ -94,14 +114,14 @@ n-v-r tag owner
|
|||
---------------------------------------- -------------------- ----------------
|
||||
/mnt/koji/packages/packagename/version/1.el6 tag owner
|
||||
"""
|
||||
args = [self.tag, self.pkg, '--latest', '--inherit', '--paths']
|
||||
args = [self.tag, self.pkg, '--latest', '--inherit', '--paths', '--draft-only']
|
||||
|
||||
anon_handle_list_tagged(self.options, self.session, args)
|
||||
self.assert_console_message(stdout, expected)
|
||||
self.ensure_connection_mock.assert_called_once_with(self.session, self.options)
|
||||
self.session.getTag.assert_called_once_with(self.tag, event=None)
|
||||
self.session.listTagged.assert_called_once_with(
|
||||
self.tag, inherit=True, latest=True, package=self.pkg)
|
||||
self.tag, inherit=True, latest=True, package=self.pkg, draft=1)
|
||||
self.session.listTaggedRPMS.assert_not_called()
|
||||
|
||||
@mock.patch('sys.stdout', new_callable=six.StringIO)
|
||||
|
|
@ -109,6 +129,7 @@ n-v-r tag owner
|
|||
def test_list_tagged_rpms(self, event_from_opts_mock, stdout):
|
||||
expected = """sigkey rpmA-0.0.1-1.el6.noarch
|
||||
sigkey rpmA-0.0.1-1.el6.x86_64
|
||||
sigkey rpmA-0.0.1-2.el6.x86_64 (#draft_2)
|
||||
"""
|
||||
args = [self.tag, self.pkg, '--latest-n=3', '--rpms', '--sigs',
|
||||
'--arch=x86_64', '--arch=noarch']
|
||||
|
|
@ -129,6 +150,7 @@ sigkey rpmA-0.0.1-1.el6.x86_64
|
|||
def test_list_tagged_rpms_paths(self, event_from_opts_mock, stdout, os_path_exists, isdir):
|
||||
expected = """/mnt/koji/packages/packagename/version/1.el6/noarch/rpmA-0.0.1-1.el6.noarch.rpm
|
||||
/mnt/koji/packages/packagename/version/1.el6/x86_64/rpmA-0.0.1-1.el6.x86_64.rpm
|
||||
/mnt/koji/packages/packagename/version/2.el6#draft_2/x86_64/rpmA-0.0.1-2.el6.x86_64.rpm
|
||||
"""
|
||||
args = [self.tag, self.pkg, '--latest-n=3', '--rpms', '--arch=x86_64', '--paths']
|
||||
|
||||
|
|
@ -233,6 +255,15 @@ n-v-r tag group
|
|||
self.session.listTaggedRPMS.assert_not_called()
|
||||
self.session.listTagged.assert_not_called()
|
||||
|
||||
def test_list_tagged_draft_opts_conflict(self):
|
||||
self.assert_system_exit(
|
||||
anon_handle_list_tagged,
|
||||
self.options, self.session, ['--draft-only', '--no-draft', 'tag', 'pkg1'],
|
||||
stderr=self.format_error_message("--draft-only conflicts with --no-draft"),
|
||||
activate_session=None,
|
||||
exit_code=2)
|
||||
self.ensure_connection_mock.assert_not_called()
|
||||
|
||||
def test_list_tagged_tag_not_found(self):
|
||||
self.session.getTag.return_value = None
|
||||
self.assert_system_exit(
|
||||
|
|
@ -267,4 +298,6 @@ Options:
|
|||
--event=EVENT# query at event
|
||||
--ts=TIMESTAMP query at last event before timestamp
|
||||
--repo=REPO# query at event for a repo
|
||||
--draft-only Only list draft builds/rpms
|
||||
--no-draft Only list regular builds/rpms
|
||||
""" % self.progname)
|
||||
|
|
|
|||
|
|
@ -53,6 +53,17 @@ class TestRpminfo(utils.CliTestCase):
|
|||
'version': '1.1',
|
||||
'payloadhash': 'b2b95550390e5f213fc25f33822425f7',
|
||||
'size': 7030}
|
||||
self.listrpminfos = [{'arch': 'src',
|
||||
'build_id': 1,
|
||||
'buildroot_id': 3,
|
||||
'buildtime': 1615877809,
|
||||
'epoch': 7,
|
||||
'id': 290,
|
||||
'name': 'test-rpm',
|
||||
'release': '11',
|
||||
'version': '1.1',
|
||||
'payloadhash': 'b2b95550390e5f213fc25f33822425f7',
|
||||
'size': 7030}]
|
||||
self.error_format = """Usage: %s rpminfo [options] <n-v-r.a> [<n-v-r.a> ...]
|
||||
(Specify the --help global option for a list of other help options)
|
||||
|
||||
|
|
@ -74,9 +85,11 @@ class TestRpminfo(utils.CliTestCase):
|
|||
self.session.listBuildroots.return_value = [self.buildroot_info]
|
||||
self.session.getBuild.return_value = self.buildinfo
|
||||
self.session.getRPM.return_value = self.getrpminfo
|
||||
self.session.listRPMs.return_value = self.listrpminfos
|
||||
expected_output = """RPM: 7:test-rpm-1.1-11.noarch [294]
|
||||
Build: test-rpm-1.1-11 [1]
|
||||
RPM Path: /mnt/koji/packages/test-rpm/1.1/11/noarch/test-rpm-1.1-11.noarch.rpm
|
||||
SRPM: 7:test-rpm-1.1-11 [1]
|
||||
SRPM: 7:test-rpm-1.1-11 [290]
|
||||
SRPM Path: /mnt/koji/packages/test-rpm/1.1/11/src/test-rpm-1.1-11.src.rpm
|
||||
Built: Tue, 16 Mar 2021 06:56:49 UTC
|
||||
SIGMD5: b2b95550390e5f213fc25f33822425f7
|
||||
|
|
@ -98,6 +111,8 @@ Used in 1 buildroots:
|
|||
rpmID=self.getrpminfo['id'])
|
||||
self.session.getBuild.assert_called_once_with(self.getrpminfo['build_id'])
|
||||
self.session.getRPM.assert_called_once_with(rpm_nvra)
|
||||
self.session.listRPMs.assert_called_once_with(buildID=self.getrpminfo['build_id'],
|
||||
arches='src')
|
||||
|
||||
def test_handle_rpminfo_non_exist_nvra(self):
|
||||
rpm_nvra = 'test-rpm-nvra.arch'
|
||||
|
|
@ -119,9 +134,11 @@ Used in 1 buildroots:
|
|||
self.session.listBuildroots.return_value = [self.buildroot_info]
|
||||
self.session.getBuild.return_value = self.buildinfo
|
||||
self.session.getRPM.side_effect = [None, self.getrpminfo]
|
||||
self.session.listRPMs.return_value = self.listrpminfos
|
||||
expected_output = """RPM: 7:test-rpm-1.1-11.noarch [294]
|
||||
Build: test-rpm-1.1-11 [1]
|
||||
RPM Path: /mnt/koji/packages/test-rpm/1.1/11/noarch/test-rpm-1.1-11.noarch.rpm
|
||||
SRPM: 7:test-rpm-1.1-11 [1]
|
||||
SRPM: 7:test-rpm-1.1-11 [290]
|
||||
SRPM Path: /mnt/koji/packages/test-rpm/1.1/11/src/test-rpm-1.1-11.src.rpm
|
||||
Built: Tue, 16 Mar 2021 06:56:49 UTC
|
||||
SIGMD5: b2b95550390e5f213fc25f33822425f7
|
||||
|
|
@ -150,6 +167,45 @@ Used in 1 buildroots:
|
|||
rpmID=self.getrpminfo['id'])
|
||||
self.session.getBuild.assert_called_once_with(self.getrpminfo['build_id'])
|
||||
self.assertEqual(self.session.getRPM.call_count, 2)
|
||||
self.session.listRPMs.assert_called_once_with(buildID=self.getrpminfo['build_id'],
|
||||
arches='src')
|
||||
|
||||
|
||||
@mock.patch('sys.stdout', new_callable=StringIO)
|
||||
def test_handle_rpminfo_with_build(self, stdout):
|
||||
rpm_nvra = 'test-rpm-1.1-11.noarch'
|
||||
self.session.getBuildroot.return_value = self.buildroot_info
|
||||
self.session.listBuildroots.return_value = [self.buildroot_info]
|
||||
self.session.getBuild.return_value = self.buildinfo
|
||||
self.session.getRPM.return_value = self.getrpminfo
|
||||
self.session.listRPMs.return_value = self.listrpminfos
|
||||
expected_output = """RPM: 7:test-rpm-1.1-11.noarch [294]
|
||||
Build: test-rpm-1.1-11 [1]
|
||||
RPM Path: /mnt/koji/packages/test-rpm/1.1/11/noarch/test-rpm-1.1-11.noarch.rpm
|
||||
SRPM: 7:test-rpm-1.1-11 [290]
|
||||
SRPM Path: /mnt/koji/packages/test-rpm/1.1/11/src/test-rpm-1.1-11.src.rpm
|
||||
Built: Tue, 16 Mar 2021 06:56:49 UTC
|
||||
SIGMD5: b2b95550390e5f213fc25f33822425f7
|
||||
Size: 7030
|
||||
Build ID: 1
|
||||
Buildroot: 3 (tag test-tag, arch x86_64, repo 2)
|
||||
Build Host: kojibuilder
|
||||
Build Task: 10
|
||||
Used in 1 buildroots:
|
||||
id build tag arch build host
|
||||
-------- ---------------------------- -------- -----------------------------
|
||||
3 test-tag x86_64 kojibuilder
|
||||
"""
|
||||
|
||||
anon_handle_rpminfo(self.options, self.session, ['--buildroot', '--build', 'any', rpm_nvra])
|
||||
self.assert_console_message(stdout, expected_output)
|
||||
self.session.getBuildroot.assert_called_once_with(self.getrpminfo['buildroot_id'])
|
||||
self.session.listBuildroots.assert_called_once_with(queryOpts={'order': 'buildroot.id'},
|
||||
rpmID=self.getrpminfo['id'])
|
||||
self.session.getBuild.assert_called_once_with(self.getrpminfo['build_id'])
|
||||
self.session.getRPM.assert_called_once_with(rpm_nvra, build='any')
|
||||
self.session.listRPMs.assert_called_once_with(buildID=self.getrpminfo['build_id'],
|
||||
arches='src')
|
||||
|
||||
def test_rpminfo_without_option(self):
|
||||
arguments = []
|
||||
|
|
@ -171,6 +227,7 @@ Used in 1 buildroots:
|
|||
(Specify the --help global option for a list of other help options)
|
||||
|
||||
Options:
|
||||
-h, --help show this help message and exit
|
||||
--buildroots show buildroots the rpm was used in
|
||||
-h, --help show this help message and exit
|
||||
--buildroots show buildroots the rpm was used in
|
||||
--build=NVR|ID show the rpm(s) in the build
|
||||
""" % self.progname)
|
||||
|
|
|
|||
|
|
@ -237,6 +237,7 @@ Options:
|
|||
--wait Wait on build, even if running in the background
|
||||
--nowait Don't wait on build
|
||||
--background Run the build at a lower priority
|
||||
--draft Build draft build instead
|
||||
""" % self.progname)
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -16,6 +16,10 @@ class TestGetRPM(DBQueryTestCase):
|
|||
self.exports = kojihub.RootExports()
|
||||
self.context = mock.patch('kojihub.kojihub.context').start()
|
||||
self.get_external_repo_id = mock.patch('kojihub.kojihub.get_external_repo_id').start()
|
||||
self.find_build_id = mock.patch('kojihub.kojihub.find_build_id').start()
|
||||
|
||||
def tearDown(self):
|
||||
mock.patch.stopall()
|
||||
|
||||
def test_wrong_type_rpminfo(self):
|
||||
rpminfo = ['test-user']
|
||||
|
|
@ -31,11 +35,10 @@ class TestGetRPM(DBQueryTestCase):
|
|||
|
||||
self.assertEqual(len(self.queries), 1)
|
||||
query = self.queries[0]
|
||||
str(query)
|
||||
self.assertEqual(query.tables, ['rpminfo'])
|
||||
columns = ['rpminfo.id', 'build_id', 'buildroot_id', 'rpminfo.name', 'version', 'release',
|
||||
'epoch', 'arch', 'external_repo_id', 'external_repo.name', 'payloadhash',
|
||||
'size', 'buildtime', 'metadata_only', 'extra']
|
||||
'epoch', 'arch', 'draft', 'external_repo_id', 'external_repo.name',
|
||||
'payloadhash', 'size', 'buildtime', 'metadata_only', 'extra']
|
||||
self.assertEqual(set(query.columns), set(columns))
|
||||
self.assertEqual(query.clauses, ['external_repo_id = 0', "rpminfo.id=%(id)s"])
|
||||
self.assertEqual(query.joins,
|
||||
|
|
@ -50,11 +53,10 @@ class TestGetRPM(DBQueryTestCase):
|
|||
|
||||
self.assertEqual(len(self.queries), 1)
|
||||
query = self.queries[0]
|
||||
str(query)
|
||||
self.assertEqual(query.tables, ['rpminfo'])
|
||||
columns = ['rpminfo.id', 'build_id', 'buildroot_id', 'rpminfo.name', 'version', 'release',
|
||||
'epoch', 'arch', 'external_repo_id', 'external_repo.name', 'payloadhash',
|
||||
'size', 'buildtime', 'metadata_only', 'extra']
|
||||
'epoch', 'arch', 'draft', 'external_repo_id', 'external_repo.name',
|
||||
'payloadhash', 'size', 'buildtime', 'metadata_only', 'extra']
|
||||
self.assertEqual(set(query.columns), set(columns))
|
||||
self.assertEqual(query.clauses, ["rpminfo.id=%(id)s"])
|
||||
self.assertEqual(query.joins,
|
||||
|
|
@ -70,11 +72,10 @@ class TestGetRPM(DBQueryTestCase):
|
|||
|
||||
self.assertEqual(len(self.queries), 1)
|
||||
query = self.queries[0]
|
||||
str(query)
|
||||
self.assertEqual(query.tables, ['rpminfo'])
|
||||
columns = ['rpminfo.id', 'build_id', 'buildroot_id', 'rpminfo.name', 'version', 'release',
|
||||
'epoch', 'arch', 'external_repo_id', 'external_repo.name', 'payloadhash',
|
||||
'size', 'buildtime', 'metadata_only', 'extra']
|
||||
'epoch', 'arch', 'draft', 'external_repo_id', 'external_repo.name',
|
||||
'payloadhash', 'size', 'buildtime', 'metadata_only', 'extra']
|
||||
self.assertEqual(set(query.columns), set(columns))
|
||||
self.assertEqual(query.clauses, ["rpminfo.id=%(id)s"])
|
||||
self.assertEqual(query.joins,
|
||||
|
|
@ -87,11 +88,10 @@ class TestGetRPM(DBQueryTestCase):
|
|||
|
||||
self.assertEqual(len(self.queries), 1)
|
||||
query = self.queries[0]
|
||||
str(query)
|
||||
self.assertEqual(query.tables, ['rpminfo'])
|
||||
columns = ['rpminfo.id', 'build_id', 'buildroot_id', 'rpminfo.name', 'version', 'release',
|
||||
'epoch', 'arch', 'external_repo_id', 'external_repo.name', 'payloadhash',
|
||||
'size', 'buildtime', 'metadata_only', 'extra']
|
||||
'epoch', 'arch', 'draft', 'external_repo_id', 'external_repo.name',
|
||||
'payloadhash', 'size', 'buildtime', 'metadata_only', 'extra']
|
||||
self.assertEqual(set(query.columns), set(columns))
|
||||
self.assertEqual(query.clauses, ["rpminfo.name=%(name)s AND version=%(version)s "
|
||||
"AND release=%(release)s AND arch=%(arch)s"])
|
||||
|
|
@ -110,17 +110,36 @@ class TestGetRPM(DBQueryTestCase):
|
|||
|
||||
self.assertEqual(len(self.queries), 1)
|
||||
query = self.queries[0]
|
||||
str(query)
|
||||
self.assertEqual(query.tables, ['rpminfo'])
|
||||
columns = ['rpminfo.id', 'build_id', 'buildroot_id', 'rpminfo.name', 'version', 'release',
|
||||
'epoch', 'arch', 'external_repo_id', 'external_repo.name', 'payloadhash',
|
||||
'size', 'buildtime', 'metadata_only', 'extra']
|
||||
'epoch', 'arch', 'draft', 'external_repo_id', 'external_repo.name',
|
||||
'payloadhash', 'size', 'buildtime', 'metadata_only', 'extra']
|
||||
self.assertEqual(set(query.columns), set(columns))
|
||||
self.assertEqual(query.clauses,
|
||||
["external_repo_id = %(external_repo_id)i", "rpminfo.id=%(id)s"])
|
||||
self.assertEqual(query.joins,
|
||||
['external_repo ON rpminfo.external_repo_id = external_repo.id'])
|
||||
self.assertEqual(query.values, rpminfo_data)
|
||||
|
||||
def test_rpm_info_with_build(self):
|
||||
rpminfo = {'id': 123, 'name': 'testrpm-1.23-4.x86_64.rpm', 'build_id': 101}
|
||||
self.find_build_id.return_value = 101
|
||||
rpminfo_data = rpminfo.copy()
|
||||
|
||||
kojihub.get_rpm(rpminfo, multi=True, build='any')
|
||||
|
||||
self.assertEqual(len(self.queries), 1)
|
||||
query = self.queries[0]
|
||||
self.assertEqual(query.tables, ['rpminfo'])
|
||||
columns = ['rpminfo.id', 'build_id', 'buildroot_id', 'rpminfo.name', 'version', 'release',
|
||||
'epoch', 'arch', 'draft', 'external_repo_id', 'external_repo.name',
|
||||
'payloadhash', 'size', 'buildtime', 'metadata_only', 'extra']
|
||||
self.assertEqual(set(query.columns), set(columns))
|
||||
self.assertEqual(query.clauses,
|
||||
["rpminfo.build_id = %(build_id)s", "rpminfo.id=%(id)s"])
|
||||
self.assertEqual(query.joins,
|
||||
['external_repo ON rpminfo.external_repo_id = external_repo.id'])
|
||||
self.assertEqual(query.values, rpminfo_data)
|
||||
|
||||
|
||||
class TestGetRPMHeaders(unittest.TestCase):
|
||||
|
|
|
|||
|
|
@ -39,8 +39,8 @@ class TestGetBuild(DBQueryTestCase):
|
|||
self.assertEqual(query.columns,
|
||||
['build.id', 'build.cg_id', 'build.completion_time',
|
||||
"date_part('epoch', build.completion_time)", 'events.id', 'events.time',
|
||||
"date_part('epoch', events.time)", 'build.epoch', 'build.extra',
|
||||
'build.id', 'package.name',
|
||||
"date_part('epoch', events.time)", 'build.draft', 'build.epoch',
|
||||
'build.extra', 'build.id', 'package.name',
|
||||
"package.name || '-' || build.version || '-' || build.release",
|
||||
'users.id', 'users.name', 'package.id', 'package.name', 'build.release',
|
||||
'build.source', 'build.start_time',
|
||||
|
|
@ -64,8 +64,8 @@ class TestGetBuild(DBQueryTestCase):
|
|||
self.assertEqual(query.columns,
|
||||
['build.id', 'build.cg_id', 'build.completion_time',
|
||||
"date_part('epoch', build.completion_time)", 'events.id', 'events.time',
|
||||
"date_part('epoch', events.time)", 'build.epoch', 'build.extra',
|
||||
'build.id', 'package.name',
|
||||
"date_part('epoch', events.time)", 'build.draft', 'build.epoch',
|
||||
'build.extra', 'build.id', 'package.name',
|
||||
"package.name || '-' || build.version || '-' || build.release",
|
||||
'users.id', 'users.name', 'package.id', 'package.name', 'build.release',
|
||||
'build.source', 'build.start_time',
|
||||
|
|
@ -111,8 +111,8 @@ class TestGetBuild(DBQueryTestCase):
|
|||
self.assertEqual(query.columns,
|
||||
['build.id', 'build.cg_id', 'build.completion_time',
|
||||
"date_part('epoch', build.completion_time)", 'events.id', 'events.time',
|
||||
"date_part('epoch', events.time)", 'build.epoch', 'build.extra',
|
||||
'build.id', 'package.name',
|
||||
"date_part('epoch', events.time)", 'build.draft', 'build.epoch',
|
||||
'build.extra', 'build.id', 'package.name',
|
||||
"package.name || '-' || build.version || '-' || build.release",
|
||||
'users.id', 'users.name', 'package.id', 'package.name', 'build.release',
|
||||
'build.source', 'build.start_time',
|
||||
|
|
@ -138,8 +138,8 @@ class TestGetBuild(DBQueryTestCase):
|
|||
self.assertEqual(query.columns,
|
||||
['build.id', 'build.cg_id', 'build.completion_time',
|
||||
"date_part('epoch', build.completion_time)", 'events.id', 'events.time',
|
||||
"date_part('epoch', events.time)", 'build.epoch', 'build.extra',
|
||||
'build.id', 'package.name',
|
||||
"date_part('epoch', events.time)", 'build.draft', 'build.epoch',
|
||||
'build.extra', 'build.id', 'package.name',
|
||||
"package.name || '-' || build.version || '-' || build.release",
|
||||
'users.id', 'users.name', 'package.id', 'package.name', 'build.release',
|
||||
'build.source', 'build.start_time',
|
||||
|
|
|
|||
|
|
@ -22,7 +22,8 @@ class TestGetNextRelease(DBQueryTestCase):
|
|||
self.assertEqual(query.tables, ['build'])
|
||||
self.assertEqual(query.joins, ['package ON build.pkg_id = package.id'])
|
||||
self.assertEqual(query.clauses,
|
||||
['name = %(name)s', 'state in %(states)s', 'version = %(version)s'])
|
||||
['NOT draft', 'name = %(name)s', 'state in %(states)s',
|
||||
'version = %(version)s'])
|
||||
self.assertEqual(query.values, {'name': self.binfo['name'],
|
||||
'version': self.binfo['version'],
|
||||
'states': (1, 2, 0)
|
||||
|
|
|
|||
|
|
@ -92,6 +92,7 @@ class TestImportBuild(unittest.TestCase):
|
|||
|
||||
fields = [
|
||||
'completion_time',
|
||||
'draft',
|
||||
'epoch',
|
||||
'extra',
|
||||
'id',
|
||||
|
|
@ -123,6 +124,7 @@ class TestImportBuild(unittest.TestCase):
|
|||
'release': 'release',
|
||||
'pkg_id': mock.ANY,
|
||||
'id': mock.ANY,
|
||||
'draft': False
|
||||
}
|
||||
self._dml.assert_called_once_with(statement, values)
|
||||
|
||||
|
|
|
|||
|
|
@ -42,11 +42,12 @@ class TestImportRPM(unittest.TestCase):
|
|||
1003: 'epoch',
|
||||
1006: 'buildtime',
|
||||
1022: 'arch',
|
||||
1044: 'name-version-release.arch',
|
||||
1044: 'name-version-release.src.rpm',
|
||||
1106: 'sourcepackage',
|
||||
261: 'payload hash',
|
||||
}
|
||||
self.get_build = mock.patch('kojihub.kojihub.get_build').start()
|
||||
self.new_build = mock.patch('kojihub.kojihub.new_build').start()
|
||||
self.get_rpm_header = mock.patch('koji.get_rpm_header').start()
|
||||
self.new_typed_build = mock.patch('kojihub.kojihub.new_typed_build').start()
|
||||
self.nextval = mock.patch('kojihub.kojihub.nextval').start()
|
||||
|
|
@ -65,6 +66,7 @@ class TestImportRPM(unittest.TestCase):
|
|||
kojihub.import_rpm("this does not exist")
|
||||
|
||||
def test_import_rpm_failed_build(self):
|
||||
self.os_path_basename.return_value = 'name-version-release.arch.rpm'
|
||||
self.get_rpm_header.return_value = self.rpm_header_retval
|
||||
self.get_build.return_value = {
|
||||
'state': koji.BUILD_STATES['FAILED'],
|
||||
|
|
@ -72,9 +74,11 @@ class TestImportRPM(unittest.TestCase):
|
|||
'version': 'version',
|
||||
'release': 'release',
|
||||
}
|
||||
with self.assertRaises(koji.GenericError):
|
||||
with self.assertRaises(koji.GenericError) as cm:
|
||||
kojihub.import_rpm(self.filename)
|
||||
self.assertEqual("Build is FAILED: name-version-release", str(cm.exception))
|
||||
self.assertEqual(len(self.inserts), 0)
|
||||
|
||||
|
||||
def test_import_rpm_completed_build(self):
|
||||
self.os_path_basename.return_value = 'name-version-release.arch.rpm'
|
||||
|
|
@ -94,6 +98,7 @@ class TestImportRPM(unittest.TestCase):
|
|||
'name': 'name',
|
||||
'arch': 'arch',
|
||||
'buildtime': 'buildtime',
|
||||
'draft': False,
|
||||
'payloadhash': '7061796c6f61642068617368',
|
||||
'epoch': 'epoch',
|
||||
'version': 'version',
|
||||
|
|
@ -114,7 +119,7 @@ class TestImportRPM(unittest.TestCase):
|
|||
retval = copy.copy(self.rpm_header_retval)
|
||||
retval.update({
|
||||
'filename': 'name-version-release.arch.rpm',
|
||||
1044: 'name-version-release.src',
|
||||
1044: 'name-version-release.src.rpm.bad',
|
||||
1022: 'src',
|
||||
1106: 1,
|
||||
})
|
||||
|
|
@ -133,6 +138,7 @@ class TestImportRPM(unittest.TestCase):
|
|||
'name': 'name',
|
||||
'arch': 'src',
|
||||
'buildtime': 'buildtime',
|
||||
'draft': False,
|
||||
'payloadhash': '7061796c6f61642068617368',
|
||||
'epoch': 'epoch',
|
||||
'version': 'version',
|
||||
|
|
@ -149,10 +155,9 @@ class TestImportRPM(unittest.TestCase):
|
|||
self.assertEqual(insert.rawdata, {})
|
||||
|
||||
def test_non_exist_file(self):
|
||||
basename = 'rpm-1-34'
|
||||
self.os_path_exists.return_value = False
|
||||
with self.assertRaises(koji.GenericError) as cm:
|
||||
kojihub.import_rpm(self.filename, basename)
|
||||
kojihub.import_rpm(self.filename)
|
||||
self.assertEqual(f"No such file: {self.filename}", str(cm.exception))
|
||||
self.assertEqual(len(self.inserts), 0)
|
||||
|
||||
|
|
@ -172,3 +177,211 @@ class TestImportRPM(unittest.TestCase):
|
|||
kojihub.import_rpm(self.src_filename)
|
||||
self.assertEqual("No such build", str(cm.exception))
|
||||
self.assertEqual(len(self.inserts), 0)
|
||||
|
||||
def test_import_draft_rpm_completed_build(self):
|
||||
self.os_path_basename.return_value = 'name-version-release.arch.rpm'
|
||||
self.get_rpm_header.return_value = self.rpm_header_retval
|
||||
self.get_build.return_value = {
|
||||
'state': koji.BUILD_STATES['COMPLETE'],
|
||||
'name': 'name',
|
||||
'version': 'version',
|
||||
'release': 'release',
|
||||
'id': 12345,
|
||||
}
|
||||
self.nextval.return_value = 9876
|
||||
kojihub.import_rpm(self.filename)
|
||||
|
||||
data = {
|
||||
'build_id': 12345,
|
||||
'name': 'name',
|
||||
'arch': 'arch',
|
||||
'buildtime': 'buildtime',
|
||||
'draft': False,
|
||||
'payloadhash': '7061796c6f61642068617368',
|
||||
'epoch': 'epoch',
|
||||
'version': 'version',
|
||||
'buildroot_id': None,
|
||||
'release': 'release',
|
||||
'external_repo_id': 0,
|
||||
'id': 9876,
|
||||
'size': 0,
|
||||
}
|
||||
self.assertEqual(len(self.inserts), 1)
|
||||
insert = self.inserts[0]
|
||||
self.assertEqual(insert.table, 'rpminfo')
|
||||
self.assertEqual(insert.data, data)
|
||||
self.assertEqual(insert.rawdata, {})
|
||||
|
||||
|
||||
def test_import_draft_conflict(self):
|
||||
with self.assertRaises(koji.GenericError) as cm:
|
||||
kojihub.import_rpm(self.filename, buildinfo={'id': 1024, 'draft': False}, draft=True)
|
||||
self.assertEqual("draft property: False of build: 1024 mismatch, True is expected",
|
||||
str(cm.exception))
|
||||
self.assertEqual(len(self.inserts), 0)
|
||||
|
||||
def test_import_draft_rpm_without_buildinfo(self):
|
||||
self.os_path_basename.return_value = 'name-version-release.arch.rpm'
|
||||
self.get_rpm_header.return_value = self.rpm_header_retval
|
||||
|
||||
with self.assertRaises(koji.GenericError) as cm:
|
||||
kojihub.import_rpm(self.filename, draft=True)
|
||||
self.assertEqual(f"Cannot import draft rpm: {self.os_path_basename.return_value}"
|
||||
" without specifying a build", str(cm.exception))
|
||||
self.assertEqual(len(self.inserts), 0)
|
||||
|
||||
def test_import_draft_rpm_non_extra_target_release(self):
|
||||
self.os_path_basename.return_value = 'name-version-release.arch.rpm'
|
||||
self.get_rpm_header.return_value = self.rpm_header_retval
|
||||
|
||||
buildinfo = {
|
||||
'state': koji.BUILD_STATES['DELETED'],
|
||||
'name': 'name',
|
||||
'version': 'version',
|
||||
'release': 'release',
|
||||
'id': 12345,
|
||||
'draft': True
|
||||
}
|
||||
|
||||
with self.assertRaises(koji.GenericError) as cm:
|
||||
kojihub.import_rpm(self.filename, buildinfo=buildinfo, draft=True)
|
||||
self.assertEqual(
|
||||
f'target release of draft build not found in extra of build: {buildinfo}',
|
||||
str(cm.exception)
|
||||
)
|
||||
self.assertEqual(len(self.inserts), 0)
|
||||
|
||||
def test_import_draft_rpm_valid(self):
|
||||
self.os_path_basename.return_value = 'name-version-release.arch.rpm'
|
||||
self.get_rpm_header.return_value = self.rpm_header_retval
|
||||
|
||||
buildinfo = {
|
||||
'state': koji.BUILD_STATES['COMPLETE'],
|
||||
'name': 'name',
|
||||
'version': 'version',
|
||||
'release': 'release',
|
||||
'id': 12345,
|
||||
'draft': True,
|
||||
'extra': {
|
||||
'draft': {
|
||||
'target_release': 'release'
|
||||
}
|
||||
}
|
||||
}
|
||||
self.nextval.return_value = 9876
|
||||
kojihub.import_rpm(self.filename, buildinfo=buildinfo, draft=True)
|
||||
data = {
|
||||
'build_id': 12345,
|
||||
'name': 'name',
|
||||
'arch': 'arch',
|
||||
'buildtime': 'buildtime',
|
||||
'draft': True,
|
||||
'payloadhash': '7061796c6f61642068617368',
|
||||
'epoch': 'epoch',
|
||||
'version': 'version',
|
||||
'buildroot_id': None,
|
||||
'release': 'release',
|
||||
'external_repo_id': 0,
|
||||
'id': 9876,
|
||||
'size': 0,
|
||||
}
|
||||
self.assertEqual(len(self.inserts), 1)
|
||||
insert = self.inserts[0]
|
||||
self.assertEqual(insert.table, 'rpminfo')
|
||||
self.assertEqual(insert.data, data)
|
||||
self.assertEqual(insert.rawdata, {})
|
||||
|
||||
def test_import_draft_srpm_with_buildinfo(self):
|
||||
self.os_path_basename.return_value = 'name-version-release.src.rpm'
|
||||
retval = copy.copy(self.rpm_header_retval)
|
||||
retval.update({
|
||||
'filename': 'name-version-release.src.rpm',
|
||||
1044: 'name-version-release.src.rpm.bad',
|
||||
1022: 'src',
|
||||
1106: 1,
|
||||
})
|
||||
self.get_rpm_header.return_value = retval
|
||||
buildinfo = {
|
||||
'state': koji.BUILD_STATES['COMPLETE'],
|
||||
'name': 'name',
|
||||
'version': 'version',
|
||||
'release': 'release',
|
||||
'id': 12345,
|
||||
'draft': True,
|
||||
'extra': {
|
||||
'draft': {
|
||||
'target_release': 'release'
|
||||
}
|
||||
}
|
||||
}
|
||||
self.nextval.return_value = 9876
|
||||
kojihub.import_rpm(self.src_filename, buildinfo=buildinfo, draft=True)
|
||||
data = {
|
||||
'build_id': 12345,
|
||||
'name': 'name',
|
||||
'arch': 'src',
|
||||
'buildtime': 'buildtime',
|
||||
'draft': True,
|
||||
'payloadhash': '7061796c6f61642068617368',
|
||||
'epoch': 'epoch',
|
||||
'version': 'version',
|
||||
'buildroot_id': None,
|
||||
'release': 'release',
|
||||
'external_repo_id': 0,
|
||||
'id': 9876,
|
||||
'size': 0,
|
||||
}
|
||||
self.assertEqual(len(self.inserts), 1)
|
||||
insert = self.inserts[0]
|
||||
self.assertEqual(insert.table, 'rpminfo')
|
||||
self.assertEqual(insert.data, data)
|
||||
self.assertEqual(insert.rawdata, {})
|
||||
|
||||
def test_import_draft_srpm_without_buildinfo(self):
|
||||
self.os_path_basename.return_value = 'name-version-release.src.rpm'
|
||||
retval = copy.copy(self.rpm_header_retval)
|
||||
retval.update({
|
||||
'filename': 'name-version-release.src.rpm',
|
||||
1044: 'name-version-release.src.rpm.bad',
|
||||
1022: 'src',
|
||||
1106: 1,
|
||||
})
|
||||
self.get_rpm_header.return_value = retval
|
||||
self.get_build.return_value = {
|
||||
'state': koji.BUILD_STATES['COMPLETE'],
|
||||
'name': 'name',
|
||||
'version': 'version',
|
||||
'release': 'release',
|
||||
'id': 5566,
|
||||
'draft': True,
|
||||
'extra': {
|
||||
'draft': {
|
||||
'target_release': 'release'
|
||||
}
|
||||
}
|
||||
}
|
||||
self.new_build.return_value = 5566
|
||||
self.nextval.return_value = 9876
|
||||
kojihub.import_rpm(self.src_filename, draft=True)
|
||||
data = {
|
||||
'build_id': 5566,
|
||||
'name': 'name',
|
||||
'arch': 'src',
|
||||
'buildtime': 'buildtime',
|
||||
'draft': True,
|
||||
'payloadhash': '7061796c6f61642068617368',
|
||||
'epoch': 'epoch',
|
||||
'version': 'version',
|
||||
'buildroot_id': None,
|
||||
'release': 'release',
|
||||
'external_repo_id': 0,
|
||||
'id': 9876,
|
||||
'size': 0,
|
||||
}
|
||||
self.assertEqual(len(self.inserts), 1)
|
||||
insert = self.inserts[0]
|
||||
self.assertEqual(insert.table, 'rpminfo')
|
||||
self.assertEqual(insert.data, data)
|
||||
self.assertEqual(insert.rawdata, {})
|
||||
self.get_build.assert_called_once_with(5566, strict=True)
|
||||
self.assertEqual(self.get_build.call_count, 1)
|
||||
|
|
@ -17,6 +17,32 @@ class TestListBuilds(unittest.TestCase):
|
|||
return query
|
||||
|
||||
def setUp(self):
|
||||
|
||||
# defaults
|
||||
self.tables= ['build']
|
||||
self.columns = [
|
||||
'build.id', 'build.completion_time',
|
||||
"date_part('epoch', build.completion_time)",
|
||||
'events.id', 'events.time',
|
||||
"date_part('epoch', events.time)",
|
||||
'build.draft',
|
||||
'build.epoch',
|
||||
'build.extra', 'package.name',
|
||||
"package.name || '-' || build.version || '-' || "
|
||||
"build.release", 'users.id', 'users.name', 'package.id',
|
||||
'package.name', 'build.release', 'build.source',
|
||||
'build.start_time', "date_part('epoch', build.start_time)",
|
||||
'build.state', 'build.task_id', 'build.version',
|
||||
'volume.id', 'volume.name'
|
||||
]
|
||||
self.clauses = ['package.id = %(packageID)i']
|
||||
self.joins = [
|
||||
'LEFT JOIN events ON build.create_event = events.id',
|
||||
'LEFT JOIN package ON build.pkg_id = package.id',
|
||||
'LEFT JOIN volume ON build.volume_id = volume.id',
|
||||
'LEFT JOIN users ON build.owner = users.id'
|
||||
]
|
||||
|
||||
self.maxDiff = None
|
||||
self.exports = kojihub.RootExports()
|
||||
self.query_executeOne = mock.MagicMock()
|
||||
|
|
@ -41,7 +67,8 @@ class TestListBuilds(unittest.TestCase):
|
|||
'task_id': 879,
|
||||
'version': '11',
|
||||
'volume_id': 0,
|
||||
'volume_name': 'DEFAULT'}]
|
||||
'volume_name': 'DEFAULT',
|
||||
'draft': False},]
|
||||
|
||||
def test_wrong_package(self):
|
||||
package = 'test-package'
|
||||
|
|
@ -58,26 +85,27 @@ class TestListBuilds(unittest.TestCase):
|
|||
self.assertEqual(len(self.queries), 1)
|
||||
args, kwargs = self.QueryProcessor.call_args
|
||||
qp = QP(**kwargs)
|
||||
self.assertEqual(qp.tables, ['build'])
|
||||
self.assertEqual(qp.columns, ['build.id', 'build.completion_time',
|
||||
"date_part('epoch', build.completion_time)",
|
||||
'events.id', 'events.time',
|
||||
"date_part('epoch', events.time)", 'build.epoch',
|
||||
'build.extra', 'package.name',
|
||||
"package.name || '-' || build.version || '-' || "
|
||||
"build.release", 'users.id', 'users.name', 'package.id',
|
||||
'package.name', 'build.release', 'build.source',
|
||||
'build.start_time', "date_part('epoch', build.start_time)",
|
||||
'build.state', 'build.task_id', 'build.version',
|
||||
'volume.id', 'volume.name'])
|
||||
self.assertEqual(qp.clauses, ['package.id = %(packageID)i'])
|
||||
self.assertEqual(qp.joins, ['LEFT JOIN events ON build.create_event = events.id',
|
||||
'LEFT JOIN package ON build.pkg_id = package.id',
|
||||
'LEFT JOIN volume ON build.volume_id = volume.id',
|
||||
'LEFT JOIN users ON build.owner = users.id'])
|
||||
self.assertEqual(qp.tables, self.tables)
|
||||
self.assertEqual(qp.columns, self.columns)
|
||||
self.assertEqual(qp.clauses, self.clauses)
|
||||
self.assertEqual(qp.joins, self.joins)
|
||||
|
||||
def test_wrong_user(self):
|
||||
user = 'test-user'
|
||||
self.get_user.return_value = None
|
||||
rv = self.exports.listBuilds(userID=user)
|
||||
self.assertEqual(rv, [])
|
||||
|
||||
def test_draft(self):
|
||||
package = 'test-package'
|
||||
package_id = 1
|
||||
self.get_package_id.return_value = package_id
|
||||
self.query_executeOne.return_value = None
|
||||
self.exports.listBuilds(packageID=package, draft=1)
|
||||
self.assertEqual(len(self.queries), 1)
|
||||
args, kwargs = self.QueryProcessor.call_args
|
||||
qp = QP(**kwargs)
|
||||
self.assertEqual(qp.tables, self.tables)
|
||||
self.assertEqual(qp.columns, self.columns)
|
||||
self.assertEqual(qp.clauses, ['draft IS TRUE'] + self.clauses)
|
||||
self.assertEqual(qp.joins, self.joins)
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ import mock
|
|||
import unittest
|
||||
|
||||
import koji
|
||||
from koji.util import dslice
|
||||
import kojihub
|
||||
|
||||
IP = kojihub.InsertProcessor
|
||||
|
|
@ -23,6 +24,7 @@ class TestNewBuild(unittest.TestCase):
|
|||
self.get_build = mock.patch('kojihub.kojihub.get_build').start()
|
||||
self.recycle_build = mock.patch('kojihub.kojihub.recycle_build').start()
|
||||
self.context = mock.patch('kojihub.kojihub.context').start()
|
||||
self.find_build_id = mock.patch('kojihub.kojihub.find_build_id').start()
|
||||
|
||||
def tearDown(self):
|
||||
mock.patch.stopall()
|
||||
|
|
@ -64,6 +66,7 @@ class TestNewBuild(unittest.TestCase):
|
|||
'start_time': 'NOW',
|
||||
'state': 1,
|
||||
'task_id': None,
|
||||
'draft': False,
|
||||
'version': 'test_version',
|
||||
'volume_id': 0
|
||||
})
|
||||
|
|
@ -156,3 +159,48 @@ class TestNewBuild(unittest.TestCase):
|
|||
|
||||
self.assertEqual(len(self.inserts), 0)
|
||||
self.assertEqual("No such build extra data: %(extra)r" % data, str(cm.exception))
|
||||
|
||||
def test_draft(self):
|
||||
data = {
|
||||
'owner': 123456,
|
||||
'name': 'test_name',
|
||||
'version': 'test_version',
|
||||
'release': 'test_release',
|
||||
'epoch': 'test_epoch',
|
||||
'draft': True
|
||||
}
|
||||
insert_data = {
|
||||
'completion_time': 'NOW',
|
||||
'epoch': 'test_epoch',
|
||||
'extra': '{"draft": {"target_release": "test_release", "promoted": false}}',
|
||||
'id': 108,
|
||||
'owner': 123,
|
||||
'pkg_id': 54,
|
||||
'release': 'test_release#draft_108',
|
||||
'source': None,
|
||||
'start_time': 'NOW',
|
||||
'state': 1,
|
||||
'task_id': None,
|
||||
'draft': True,
|
||||
'version': 'test_version',
|
||||
'volume_id': 0
|
||||
}
|
||||
self.nextval.return_value = 108
|
||||
self.new_package.return_value = 54
|
||||
self.get_user.return_value = {'id': 123}
|
||||
self.find_build_id.return_value = None
|
||||
|
||||
kojihub.new_build(data)
|
||||
|
||||
self.assertEqual(len(self.inserts), 1)
|
||||
insert = self.inserts[0]
|
||||
self.assertEqual(insert.table, 'build')
|
||||
self.assertEqual(insert.data, insert_data)
|
||||
self.get_build.assert_called_once_with(108, strict=True)
|
||||
self.assertEqual(self.get_build.call_count, 1)
|
||||
self.find_build_id.assert_called_once_with(
|
||||
{
|
||||
'name': 'test_name',
|
||||
'version': 'test_version',
|
||||
'release': 'test_release#draft_108'
|
||||
})
|
||||
|
|
|
|||
179
tests/test_hub/test_promote_build.py
Normal file
179
tests/test_hub/test_promote_build.py
Normal file
|
|
@ -0,0 +1,179 @@
|
|||
import datetime
|
||||
import json
|
||||
import mock
|
||||
import unittest
|
||||
import koji
|
||||
import kojihub
|
||||
|
||||
|
||||
UP = kojihub.UpdateProcessor
|
||||
|
||||
|
||||
class TestPromoteBuild(unittest.TestCase):
|
||||
|
||||
def getUpdate(self, *args, **kwargs):
|
||||
update = UP(*args, **kwargs)
|
||||
update.execute = mock.MagicMock()
|
||||
self.updates.append(update)
|
||||
return update
|
||||
|
||||
def setUp(self):
|
||||
self.exports = kojihub.RootExports()
|
||||
self.UpdateProcessor = mock.patch('kojihub.kojihub.UpdateProcessor',
|
||||
side_effect=self.getUpdate).start()
|
||||
self.updates = []
|
||||
self.context = mock.patch('kojihub.kojihub.context').start()
|
||||
self.context.session.assertLogin = mock.MagicMock()
|
||||
self.user = {'id': 1, 'name': 'jdoe'}
|
||||
self.getLoggedInUser = mock.patch.object(self.exports, 'getLoggedInUser',
|
||||
return_value=self.user).start()
|
||||
self.get_build = mock.patch('kojihub.kojihub.get_build').start()
|
||||
self.assert_policy = mock.patch('kojihub.kojihub.assert_policy').start()
|
||||
self.apply_volume_policy = mock.patch('kojihub.kojihub.apply_volume_policy',
|
||||
return_value=None).start()
|
||||
self.move_and_symlink = mock.patch('kojihub.kojihub.move_and_symlink').start()
|
||||
self.ensure_volume_symlink = mock.patch('kojihub.kojihub.ensure_volume_symlink').start()
|
||||
self.list_tags = mock.patch('kojihub.kojihub.list_tags',
|
||||
return_value=[{'id': 101}]).start()
|
||||
self.set_tag_update = mock.patch('kojihub.kojihub.set_tag_update').start()
|
||||
self.encode_datetime = mock.patch('kojihub.kojihub.encode_datetime', return_value='NOW').start()
|
||||
self._now = datetime.datetime.now()
|
||||
self._datetime = mock.patch('kojihub.kojihub.datetime.datetime').start()
|
||||
self.now = self._datetime.now = mock.MagicMock(return_value=self._now)
|
||||
|
||||
self.draft_build = {
|
||||
'id': 1,
|
||||
'name': 'foo',
|
||||
'version': 'bar',
|
||||
'release': 'dftrel_1',
|
||||
'extra': {
|
||||
'draft': {
|
||||
'promoted': False,
|
||||
'target_release': 'tgtrel_1'
|
||||
}},
|
||||
'draft': True,
|
||||
'volume_id': 99,
|
||||
'volume_name': 'X'
|
||||
}
|
||||
|
||||
self.new_build = {
|
||||
# no check on the info
|
||||
'id': 1,
|
||||
'name': 'foo',
|
||||
'version': 'bar',
|
||||
'release': 'tgtrel_1',
|
||||
'volume_name': 'X'
|
||||
}
|
||||
|
||||
def tearDown(self):
|
||||
mock.patch.stopall()
|
||||
|
||||
def test_promote_build_valid(self):
|
||||
self.get_build.side_effect = [
|
||||
self.draft_build,
|
||||
None,
|
||||
self.new_build
|
||||
]
|
||||
|
||||
extra = json.dumps(
|
||||
{
|
||||
'draft': {
|
||||
'promoted': True,
|
||||
'target_release': 'tgtrel_1',
|
||||
'old_release': 'dftrel_1',
|
||||
'promotion_time': 'NOW',
|
||||
'promotion_ts': self._now.timestamp(),
|
||||
'promoter': self.user['name']
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
ret = self.exports.promoteBuild('a-draft-build', strict=True)
|
||||
self.assertEqual(ret, self.new_build)
|
||||
self.assertEqual(len(self.updates), 1)
|
||||
update = self.updates[0]
|
||||
self.assertEqual(update.table, 'build')
|
||||
self.assertEqual(update.values, self.draft_build)
|
||||
self.assertEqual(update.data, {'draft': False,
|
||||
'release': 'tgtrel_1',
|
||||
'extra': extra})
|
||||
self.assertEqual(update.rawdata, {})
|
||||
self.assertEqual(update.clauses, ['id=%(id)i'])
|
||||
|
||||
def test_promote_build_not_draft(self):
|
||||
self.get_build.return_value = {'draft': False}
|
||||
|
||||
with self.assertRaises(koji.GenericError) as cm:
|
||||
self.exports.promoteBuild('a-regular-build', strict=True)
|
||||
self.assertEqual(str(cm.exception), "Not a draft build: {'draft': False}")
|
||||
self.assertEqual(len(self.updates), 0)
|
||||
|
||||
ret = self.exports.promoteBuild('a-regular-build', strict=False)
|
||||
self.assertIsNone(ret)
|
||||
self.assertEqual(len(self.updates), 0)
|
||||
|
||||
def test_promote_build_no_target_release(self):
|
||||
draft = {
|
||||
'id': 1,
|
||||
'name': 'foo',
|
||||
'version': 'bar',
|
||||
'release': 'dftrel_1',
|
||||
'extra': {
|
||||
'draft': {
|
||||
'promoted': False
|
||||
# no target_release
|
||||
}},
|
||||
'draft': True,
|
||||
'volume_id': 99,
|
||||
'volume_name': 'X'
|
||||
}
|
||||
|
||||
self.get_build.return_value = draft
|
||||
|
||||
with self.assertRaises(koji.GenericError) as cm:
|
||||
self.exports.promoteBuild('a-regular-build', strict=True)
|
||||
self.assertEqual(str(cm.exception), f"draft.target_release not found in extra of build: {draft}")
|
||||
self.assertEqual(len(self.updates), 0)
|
||||
|
||||
ret = self.exports.promoteBuild('a-regular-build', strict=False)
|
||||
self.assertIsNone(ret)
|
||||
self.assertEqual(len(self.updates), 0)
|
||||
|
||||
def test_promote_build_target_build_exists(self):
|
||||
old = {
|
||||
'id': 'any'
|
||||
}
|
||||
self.get_build.side_effect = [self.draft_build, old]
|
||||
|
||||
with self.assertRaises(koji.GenericError) as cm:
|
||||
self.exports.promoteBuild('a-regular-build', strict=True)
|
||||
self.assertEqual(str(cm.exception), f"Target build already exists: {old}")
|
||||
self.assertEqual(len(self.updates), 0)
|
||||
self.get_build.assert_called_with({
|
||||
'name': 'foo',
|
||||
'version': 'bar',
|
||||
'release': 'tgtrel_1'
|
||||
})
|
||||
|
||||
self.get_build.reset_mock()
|
||||
self.get_build.side_effect = [self.draft_build, old]
|
||||
ret = self.exports.promoteBuild('a-regular-build', strict=False)
|
||||
self.assertIsNone(ret)
|
||||
self.assertEqual(len(self.updates), 0)
|
||||
|
||||
def test_promote_build_volume_changed(self):
|
||||
self.get_build.side_effect = [self.draft_build, None]
|
||||
self.apply_volume_policy.return_value = {
|
||||
'id': 100,
|
||||
'name': 'Y'
|
||||
}
|
||||
with self.assertRaises(koji.GenericError) as cm:
|
||||
self.exports.promoteBuild('a-regular-build', strict=True)
|
||||
self.assertEqual(str(cm.exception), f"Denial as volume will be changed to Y")
|
||||
self.assertEqual(len(self.updates), 0)
|
||||
|
||||
self.get_build.reset_mock()
|
||||
self.get_build.side_effect = [self.draft_build, None]
|
||||
ret = self.exports.promoteBuild('a-regular-build', strict=False)
|
||||
self.assertIsNone(ret)
|
||||
self.assertEqual(len(self.updates), 0)
|
||||
|
|
@ -31,7 +31,7 @@ class TestReadTaggedBuilds(unittest.TestCase):
|
|||
self.tag_name = 'test-tag'
|
||||
self.columns = ['tag.id', 'tag.name', 'build.id', 'build.version', 'build.release',
|
||||
'build.epoch', 'build.state', 'build.completion_time', 'build.start_time',
|
||||
'build.task_id', 'users.id', 'users.name', 'events.id', 'events.time',
|
||||
'build.task_id', 'build.draft', 'users.id', 'users.name', 'events.id', 'events.time',
|
||||
'volume.id', 'volume.name', 'package.id', 'package.name',
|
||||
'package.name || \'-\' || build.version || \'-\' || build.release',
|
||||
'tag_listing.create_event']
|
||||
|
|
@ -40,6 +40,7 @@ class TestReadTaggedBuilds(unittest.TestCase):
|
|||
('build.release', 'release'), ('build.epoch', 'epoch'),
|
||||
('build.state', 'state'), ('build.completion_time', 'completion_time'),
|
||||
('build.start_time', 'start_time'), ('build.task_id', 'task_id'),
|
||||
('build.draft', 'draft'),
|
||||
('users.id', 'owner_id'), ('users.name', 'owner_name'),
|
||||
('events.id', 'creation_event_id'), ('events.time', 'creation_time'),
|
||||
('volume.id', 'volume_id'), ('volume.name', 'volume_name'),
|
||||
|
|
@ -54,7 +55,7 @@ class TestReadTaggedBuilds(unittest.TestCase):
|
|||
'volume ON volume.id = build.volume_id',
|
||||
'users ON users.id = build.owner', ]
|
||||
self.aliases = ['tag_id', 'tag_name', 'id', 'build_id', 'version', 'release', 'epoch',
|
||||
'state', 'completion_time', 'start_time', 'task_id', 'owner_id',
|
||||
'state', 'completion_time', 'start_time', 'task_id', 'draft', 'owner_id',
|
||||
'owner_name', 'creation_event_id', 'creation_time', 'volume_id',
|
||||
'volume_name', 'package_id', 'package_name', 'name', 'nvr', 'create_event']
|
||||
self.clauses = ['(tag_listing.active = TRUE)',
|
||||
|
|
@ -83,7 +84,7 @@ class TestReadTaggedBuilds(unittest.TestCase):
|
|||
'package': None, 'packages': self.package_list,
|
||||
'queryOpts': {'order': '-create_event'}, 'st_complete': 1, 'tables': self.tables,
|
||||
'tag': self.tag_name, 'tagid': self.tag_name, 'taglist': [self.tag_name],
|
||||
'type': None
|
||||
'type': None, 'draft': 3
|
||||
}
|
||||
self.assertEqual(query.tables, self.tables)
|
||||
self.assertEqual(query.joins, self.joins)
|
||||
|
|
@ -119,7 +120,7 @@ class TestReadTaggedBuilds(unittest.TestCase):
|
|||
'package': self.pkg_name, 'packages': self.package_list,
|
||||
'queryOpts': {'order': '-create_event'}, 'st_complete': 1, 'tables': self.tables,
|
||||
'tag': self.tag_name, 'tagid': self.tag_name, 'taglist': [self.tag_name],
|
||||
'type': 'maven'}
|
||||
'type': 'maven', 'draft': 3}
|
||||
self.assertEqual(query.tables, self.tables)
|
||||
self.assertEqual(query.joins, joins)
|
||||
self.assertEqual(set(query.columns), set(columns))
|
||||
|
|
@ -148,7 +149,7 @@ class TestReadTaggedBuilds(unittest.TestCase):
|
|||
'package': None, 'packages': self.package_list,
|
||||
'queryOpts': {'order': '-create_event'}, 'st_complete': 1, 'tables': self.tables,
|
||||
'tag': self.tag_name, 'tagid': self.tag_name, 'taglist': [self.tag_name],
|
||||
'type': 'win'}
|
||||
'type': 'win', 'draft': 3}
|
||||
self.assertEqual(query.tables, self.tables)
|
||||
self.assertEqual(query.joins, joins)
|
||||
self.assertEqual(set(query.columns), set(columns))
|
||||
|
|
@ -177,7 +178,7 @@ class TestReadTaggedBuilds(unittest.TestCase):
|
|||
'package': None, 'packages': self.package_list,
|
||||
'queryOpts': {'order': '-create_event'}, 'st_complete': 1, 'tables': self.tables,
|
||||
'tag': self.tag_name, 'tagid': self.tag_name, 'taglist': [self.tag_name],
|
||||
'type': 'image'}
|
||||
'type': 'image', 'draft': 3}
|
||||
self.assertEqual(query.tables, self.tables)
|
||||
self.assertEqual(query.joins, joins)
|
||||
self.assertEqual(set(query.columns), set(columns))
|
||||
|
|
@ -212,10 +213,35 @@ class TestReadTaggedBuilds(unittest.TestCase):
|
|||
'package': None, 'packages': self.package_list,
|
||||
'queryOpts': {'order': '-create_event'}, 'st_complete': 1, 'tables': self.tables,
|
||||
'tag': self.tag_name, 'tagid': self.tag_name, 'taglist': [self.tag_name],
|
||||
'type': type}
|
||||
'type': type, 'draft': 3}
|
||||
self.assertEqual(query.tables, self.tables)
|
||||
self.assertEqual(query.joins, joins)
|
||||
self.assertEqual(set(query.columns), set(self.columns))
|
||||
self.assertEqual(set(query.aliases), set(self.aliases))
|
||||
self.assertEqual(set(query.clauses), set(self.clauses))
|
||||
self.assertEqual(query.values, values)
|
||||
|
||||
def test_get_tagged_builds_draft(self):
|
||||
self.readPackageList.return_value = self.package_list
|
||||
kojihub.readTaggedBuilds(self.tag_name, draft=koji.DRAFT_FLAG.DRAFT)
|
||||
|
||||
self.assertEqual(len(self.queries), 1)
|
||||
query = self.queries[0]
|
||||
|
||||
clauses = copy.deepcopy(self.clauses)
|
||||
clauses.extend(['draft IS TRUE'])
|
||||
|
||||
values = {'clauses': clauses, 'event': None, 'extra': False, 'fields': self.fields,
|
||||
'inherit': False, 'joins': self.joins, 'latest': False, 'owner': None,
|
||||
'package': None, 'packages': self.package_list,
|
||||
'queryOpts': {'order': '-create_event'}, 'st_complete': 1, 'tables': self.tables,
|
||||
'tag': self.tag_name, 'tagid': self.tag_name, 'taglist': [self.tag_name],
|
||||
'type': None, 'draft': koji.DRAFT_FLAG.DRAFT
|
||||
}
|
||||
|
||||
self.assertEqual(query.tables, self.tables)
|
||||
self.assertEqual(query.joins, self.joins)
|
||||
self.assertEqual(set(query.columns), set(self.columns))
|
||||
self.assertEqual(set(query.aliases), set(self.aliases))
|
||||
self.assertEqual(set(query.clauses), set(clauses))
|
||||
self.assertEqual(query.values, values)
|
||||
|
|
|
|||
|
|
@ -29,12 +29,13 @@ class TestReadTaggedRPMS(unittest.TestCase):
|
|||
self.readTaggedBuilds = mock.patch('kojihub.kojihub.readTaggedBuilds').start()
|
||||
self.tag_name = 'test-tag'
|
||||
self.columns = ['rpminfo.name', 'rpminfo.version', 'rpminfo.release', 'rpminfo.arch',
|
||||
'rpminfo.id', 'rpminfo.epoch', 'rpminfo.payloadhash', 'rpminfo.size',
|
||||
'rpminfo.buildtime', 'rpminfo.buildroot_id', 'rpminfo.build_id',
|
||||
'rpminfo.metadata_only']
|
||||
'rpminfo.id', 'rpminfo.epoch', 'rpminfo.draft', 'rpminfo.payloadhash',
|
||||
'rpminfo.size', 'rpminfo.buildtime', 'rpminfo.buildroot_id',
|
||||
'rpminfo.build_id', 'rpminfo.metadata_only']
|
||||
self.joins = ['tag_listing ON rpminfo.build_id = tag_listing.build_id']
|
||||
self.aliases = ['name', 'version', 'release', 'arch', 'id', 'epoch', 'payloadhash',
|
||||
'size', 'buildtime', 'buildroot_id', 'build_id', 'metadata_only']
|
||||
self.aliases = ['name', 'version', 'release', 'arch', 'id', 'epoch', 'draft',
|
||||
'payloadhash', 'size', 'buildtime', 'buildroot_id', 'build_id',
|
||||
'metadata_only']
|
||||
self.clauses = ['(tag_listing.active = TRUE)',
|
||||
'tag_id=%(tagid)s']
|
||||
self.tables = ['rpminfo']
|
||||
|
|
@ -101,3 +102,20 @@ class TestReadTaggedRPMS(unittest.TestCase):
|
|||
self.assertEqual(set(query.aliases), set(aliases))
|
||||
self.assertEqual(set(query.clauses), set(clauses))
|
||||
self.assertEqual(query.values, values)
|
||||
|
||||
def test_get_tagged_rpms_draft(self):
|
||||
self.readTaggedBuilds.return_value = self.build_list
|
||||
kojihub.readTaggedRPMS(self.tag_name, draft=2, extra=False)
|
||||
|
||||
self.assertEqual(len(self.queries), 1)
|
||||
query = self.queries[0]
|
||||
|
||||
clauses = copy.deepcopy(self.clauses)
|
||||
clauses.extend(['rpminfo.draft IS NOT TRUE'])
|
||||
|
||||
self.assertEqual(query.tables, self.tables)
|
||||
self.assertEqual(set(query.columns), set(self.columns))
|
||||
self.assertEqual(set(query.joins), set(self.joins))
|
||||
self.assertEqual(set(query.aliases), set(self.aliases))
|
||||
self.assertEqual(set(query.clauses), set(clauses))
|
||||
self.assertEqual(query.values, {})
|
||||
|
|
@ -44,6 +44,9 @@ class TestResetBuild(unittest.TestCase):
|
|||
self.get_build = mock.patch('kojihub.kojihub.get_build').start()
|
||||
self.context = mock.patch('kojihub.kojihub.context').start()
|
||||
self.context.session.assertPerm = mock.MagicMock()
|
||||
# don't remove anything unexpected
|
||||
self.rmtree = mock.patch('koji.util.rmtree').start()
|
||||
self.unlink = mock.patch('os.unlink').start()
|
||||
self.build_id = 3
|
||||
self.binfo = {'id': 3, 'state': koji.BUILD_STATES['COMPLETE'], 'name': 'test_nvr',
|
||||
'nvr': 'test_nvr-3.3-20.el8', 'version': '3.3', 'release': '20',
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue