Merge pull request #303 from aplanas/master
Add a test for accept command when there are multiple SPECs
This commit is contained in:
commit
acb862db43
@ -109,7 +109,10 @@ def _check_repo_download(self, request):
|
|||||||
_errors_printed = set()
|
_errors_printed = set()
|
||||||
|
|
||||||
|
|
||||||
def _check_repo_group(self, id_, requests, debug=False):
|
def _check_repo_group(self, id_, requests, skip_cycle=None, debug=False):
|
||||||
|
if skip_cycle is None:
|
||||||
|
skip_cycle = []
|
||||||
|
|
||||||
print '> Check group [%s]' % ', '.join(r.str_compact() for r in requests)
|
print '> Check group [%s]' % ', '.join(r.str_compact() for r in requests)
|
||||||
|
|
||||||
# XXX TODO - If the requests comes from command line, the group is
|
# XXX TODO - If the requests comes from command line, the group is
|
||||||
@ -198,6 +201,14 @@ def _check_repo_group(self, id_, requests, debug=False):
|
|||||||
print
|
print
|
||||||
print ' - New cycle detected:', sorted(cycle)
|
print ' - New cycle detected:', sorted(cycle)
|
||||||
print ' - New edges:', new_edges
|
print ' - New edges:', new_edges
|
||||||
|
|
||||||
|
if skip_cycle:
|
||||||
|
print ' - Skiping this cycle and moving to the next check.'
|
||||||
|
continue
|
||||||
|
else:
|
||||||
|
print ' - If you want to skip this cycle, run manually the ' \
|
||||||
|
'check repo with -c / --skipcycle option.'
|
||||||
|
|
||||||
for request in requests:
|
for request in requests:
|
||||||
request.updated = True
|
request.updated = True
|
||||||
|
|
||||||
@ -428,6 +439,7 @@ def _print_request_and_specs(self, request_and_specs):
|
|||||||
@cmdln.option('-p', '--project', dest='project', metavar='PROJECT', default='Factory',
|
@cmdln.option('-p', '--project', dest='project', metavar='PROJECT', default='Factory',
|
||||||
help='select a different project instead of openSUSE:Factory')
|
help='select a different project instead of openSUSE:Factory')
|
||||||
@cmdln.option('-s', '--skip', action='store_true', help='skip review')
|
@cmdln.option('-s', '--skip', action='store_true', help='skip review')
|
||||||
|
@cmdln.option('-c', '--skipcycle', action='store_true', help='skip cycle check')
|
||||||
@cmdln.option('-n', '--dry', action='store_true', help='dry run, don\'t change review state')
|
@cmdln.option('-n', '--dry', action='store_true', help='dry run, don\'t change review state')
|
||||||
@cmdln.option('-v', '--verbose', action='store_true', help='verbose output')
|
@cmdln.option('-v', '--verbose', action='store_true', help='verbose output')
|
||||||
def do_check_repo(self, subcmd, opts, *args):
|
def do_check_repo(self, subcmd, opts, *args):
|
||||||
@ -542,7 +554,9 @@ def do_check_repo(self, subcmd, opts, *args):
|
|||||||
# projects also
|
# projects also
|
||||||
for id_, reqs in sorted(groups.items(), reverse=True):
|
for id_, reqs in sorted(groups.items(), reverse=True):
|
||||||
try:
|
try:
|
||||||
self._check_repo_group(id_, reqs, debug=opts.verbose)
|
self._check_repo_group(id_, reqs,
|
||||||
|
skip_cycle=opts.skipcycle,
|
||||||
|
debug=opts.verbose)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print 'ERROR -- An exception happends while checking a group [%s]' % e
|
print 'ERROR -- An exception happends while checking a group [%s]' % e
|
||||||
if conf.config['debug']:
|
if conf.config['debug']:
|
||||||
|
@ -57,7 +57,7 @@ def _full_project_name(self, project):
|
|||||||
return 'SUSE:%s' % project
|
return 'SUSE:%s' % project
|
||||||
|
|
||||||
# If we can't guess, raise a Warning
|
# If we can't guess, raise a Warning
|
||||||
warnings.warn('% project not recognized.' % project)
|
warnings.warn('%s project not recognized.' % project)
|
||||||
return project
|
return project
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import re
|
import re
|
||||||
|
import urllib2
|
||||||
import warnings
|
import warnings
|
||||||
from xml.etree import cElementTree as ET
|
from xml.etree import cElementTree as ET
|
||||||
|
|
||||||
@ -33,7 +34,7 @@ class AcceptCommand(object):
|
|||||||
return rqs
|
return rqs
|
||||||
|
|
||||||
def perform(self, project):
|
def perform(self, project):
|
||||||
"""Accept the staging LETTER for review and submit to Factory /
|
"""Accept the staging project for review and submit to Factory /
|
||||||
openSUSE 13.2 ...
|
openSUSE 13.2 ...
|
||||||
|
|
||||||
Then disable the build to disabled
|
Then disable the build to disabled
|
||||||
@ -57,15 +58,23 @@ class AcceptCommand(object):
|
|||||||
msg = 'Accepting staging review for {}'.format(req['package'])
|
msg = 'Accepting staging review for {}'.format(req['package'])
|
||||||
print(msg)
|
print(msg)
|
||||||
|
|
||||||
oldspecs = self.api.get_filelist_for_package(pkgname=req['package'], project=self.api.project, extension='spec')
|
oldspecs = self.api.get_filelist_for_package(pkgname=req['package'],
|
||||||
change_request_state(self.api.apiurl, str(req['id']), 'accepted', message='Accept to %s' % self.api.project)
|
project=self.api.project,
|
||||||
|
extension='spec')
|
||||||
|
change_request_state(self.api.apiurl,
|
||||||
|
str(req['id']),
|
||||||
|
'accepted',
|
||||||
|
message='Accept to %s' % self.api.project)
|
||||||
self.create_new_links(self.api.project, req['package'], oldspecs)
|
self.create_new_links(self.api.project, req['package'], oldspecs)
|
||||||
|
|
||||||
# A single comment should be enough to notify everybody, since
|
# A single comment should be enough to notify everybody, since
|
||||||
# they are already mentioned in the comments created by
|
# they are already mentioned in the comments created by
|
||||||
# select/unselect
|
# select/unselect
|
||||||
pkg_list = ", ".join(packages)
|
pkg_list = ", ".join(packages)
|
||||||
cmmt = 'Project "{}" accepted. The following packages have been submitted to {}: {}.'.format(project, self.api.project, pkg_list)
|
cmmt = 'Project "{}" accepted.' \
|
||||||
|
' The following packages have been submitted to {}: {}.'.format(project,
|
||||||
|
self.api.project,
|
||||||
|
pkg_list)
|
||||||
self.comment.add_comment(project_name=project, comment=cmmt)
|
self.comment.add_comment(project_name=project, comment=cmmt)
|
||||||
|
|
||||||
# XXX CAUTION - AFAIK the 'accept' command is expected to clean the messages here.
|
# XXX CAUTION - AFAIK the 'accept' command is expected to clean the messages here.
|
||||||
@ -113,7 +122,7 @@ class AcceptCommand(object):
|
|||||||
# There is more than one .spec file in the package; link package containers as needed
|
# There is more than one .spec file in the package; link package containers as needed
|
||||||
origmeta = self.api.load_file_content(project, pkgname, '_meta')
|
origmeta = self.api.load_file_content(project, pkgname, '_meta')
|
||||||
for specfile in filelist:
|
for specfile in filelist:
|
||||||
package = specfile[:-5] # stripping .spec off the filename gives the packagename
|
package = specfile[:-5] # stripping .spec off the filename gives the packagename
|
||||||
if package == pkgname:
|
if package == pkgname:
|
||||||
# This is the original package and does not need to be linked to itself
|
# This is the original package and does not need to be linked to itself
|
||||||
continue
|
continue
|
||||||
@ -121,10 +130,18 @@ class AcceptCommand(object):
|
|||||||
if not self.api.item_exists(project, package):
|
if not self.api.item_exists(project, package):
|
||||||
print "Creating new package %s linked to %s" % (package, pkgname)
|
print "Creating new package %s linked to %s" % (package, pkgname)
|
||||||
# new package does not exist. Let's link it with new metadata
|
# new package does not exist. Let's link it with new metadata
|
||||||
newmeta = re.sub(r'(<package.*name=.){}'.format(pkgname),r'\1{}'.format(package), origmeta)
|
newmeta = re.sub(r'(<package.*name=.){}'.format(pkgname),
|
||||||
newmeta = re.sub(r'<devel.*>\$',r'<devel package=\'{}\'/>'.format(pkgname), newmeta)
|
r'\1{}'.format(package),
|
||||||
newmeta = re.sub(r'<bcntsynctag>.*</bcntsynctag>',r'', newmeta)
|
origmeta)
|
||||||
newmeta = re.sub(r'</package>',r'<bcntsynctag>{}</bcntsynctag></package>'.format(pkgname), newmeta)
|
newmeta = re.sub(r'<devel.*>\$',
|
||||||
|
r'<devel package=\'{}\'/>'.format(pkgname),
|
||||||
|
newmeta)
|
||||||
|
newmeta = re.sub(r'<bcntsynctag>.*</bcntsynctag>',
|
||||||
|
r'',
|
||||||
|
newmeta)
|
||||||
|
newmeta = re.sub(r'</package>',
|
||||||
|
r'<bcntsynctag>{}</bcntsynctag></package>'.format(pkgname),
|
||||||
|
newmeta)
|
||||||
self.api.save_file_content(project, package, '_meta', newmeta)
|
self.api.save_file_content(project, package, '_meta', newmeta)
|
||||||
link = "<link package=\"{}\" cicount=\"copy\" />".format(pkgname)
|
link = "<link package=\"{}\" cicount=\"copy\" />".format(pkgname)
|
||||||
self.api.save_file_content(project, package, '_link', link)
|
self.api.save_file_content(project, package, '_link', link)
|
||||||
|
@ -51,7 +51,7 @@ DEFAULT = {
|
|||||||
'openqa': None,
|
'openqa': None,
|
||||||
'lock': None,
|
'lock': None,
|
||||||
'lock-ns': 'OBS',
|
'lock-ns': 'OBS',
|
||||||
}
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
#
|
#
|
||||||
|
@ -293,7 +293,7 @@ class CycleDetector(object):
|
|||||||
#
|
#
|
||||||
# To do that, we store in `project_cycles_pkgs` all the
|
# To do that, we store in `project_cycles_pkgs` all the
|
||||||
# project (i.e Factory) cycles as a set of packages, so we can
|
# project (i.e Factory) cycles as a set of packages, so we can
|
||||||
# check in the new cycle (also as a set of package) is
|
# check if the new cycle (also as a set of packages) is
|
||||||
# included here.
|
# included here.
|
||||||
project_cycles_pkgs = [set(cycle) for cycle in project_cycles]
|
project_cycles_pkgs = [set(cycle) for cycle in project_cycles]
|
||||||
for cycle in current_graph.cycles():
|
for cycle in current_graph.cycles():
|
||||||
|
@ -84,7 +84,7 @@ class OBSLock(object):
|
|||||||
now = datetime.utcnow()
|
now = datetime.utcnow()
|
||||||
if now < ts:
|
if now < ts:
|
||||||
raise Exception('Lock acquired from the future [%s] by [%s]. Try later.' % (ts, user))
|
raise Exception('Lock acquired from the future [%s] by [%s]. Try later.' % (ts, user))
|
||||||
if user != self.user and (now - ts).seconds < self.ttl:
|
if (now - ts).seconds < self.ttl:
|
||||||
print 'Lock acquired by [%s]. Try later.' % user
|
print 'Lock acquired by [%s]. Try later.' % user
|
||||||
exit(-1)
|
exit(-1)
|
||||||
# raise Exception('Lock acquired by [%s]. Try later.' % user)
|
# raise Exception('Lock acquired by [%s]. Try later.' % user)
|
||||||
|
@ -58,6 +58,7 @@ class StagingAPI(object):
|
|||||||
self.copenqa = conf.config[project]['openqa']
|
self.copenqa = conf.config[project]['openqa']
|
||||||
|
|
||||||
# If the project support rings, inititialize some variables.
|
# If the project support rings, inititialize some variables.
|
||||||
|
self.ring_packages = {}
|
||||||
if self.crings:
|
if self.crings:
|
||||||
self.rings = (
|
self.rings = (
|
||||||
'{}:0-Bootstrap'.format(self.crings),
|
'{}:0-Bootstrap'.format(self.crings),
|
||||||
|
11
tests/fixtures/source/openSUSE:Factory/apparmor-doc/_meta
vendored
Normal file
11
tests/fixtures/source/openSUSE:Factory/apparmor-doc/_meta
vendored
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
<package name="apparmor-doc" project="openSUSE:Factory">
|
||||||
|
<title>AppArmor userlevel parser utility</title>
|
||||||
|
<description>
|
||||||
|
The AppArmor Parser is a userlevel program that is used to load in
|
||||||
|
program profiles to the AppArmor Security kernel module.
|
||||||
|
|
||||||
|
This package is part of a suite of tools that used to be named
|
||||||
|
SubDomain.
|
||||||
|
</description>
|
||||||
|
<devel project="security:apparmor" package="apparmor-doc"/>
|
||||||
|
</package>
|
1
tests/fixtures/source/openSUSE:Factory/apparmor/_entry.xml
vendored
Normal file
1
tests/fixtures/source/openSUSE:Factory/apparmor/_entry.xml
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
<entry name="${spec}" md5="84ae6c8586c7e12b44d835af641d6a74" size="27360" mtime="1423765380"/>
|
11
tests/fixtures/source/openSUSE:Factory/apparmor/_meta
vendored
Normal file
11
tests/fixtures/source/openSUSE:Factory/apparmor/_meta
vendored
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
<package name="apparmor" project="openSUSE:Factory">
|
||||||
|
<title>AppArmor userlevel parser utility</title>
|
||||||
|
<description>
|
||||||
|
The AppArmor Parser is a userlevel program that is used to load in
|
||||||
|
program profiles to the AppArmor Security kernel module.
|
||||||
|
|
||||||
|
This package is part of a suite of tools that used to be named
|
||||||
|
SubDomain.
|
||||||
|
</description>
|
||||||
|
<devel project="security:apparmor" package="apparmor"/>
|
||||||
|
</package>
|
3
tests/fixtures/source/openSUSE:Factory/apparmor/apparmor.xml
vendored
Normal file
3
tests/fixtures/source/openSUSE:Factory/apparmor/apparmor.xml
vendored
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
<directory name="apparmor" rev="82" vrev="4" srcmd5="4120eb2ba3d265f7dceb65bbd5923d76">
|
||||||
|
${entries}
|
||||||
|
</directory>
|
3
tests/fixtures/source/openSUSE:Factory/emacs
vendored
Normal file
3
tests/fixtures/source/openSUSE:Factory/emacs
vendored
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
<directory name="emacs" rev="113" vrev="4" srcmd5="e894cd3965cf1d930a5c058a82a6040e">
|
||||||
|
<entry name="emacs.spec" md5="320973b1eb3eaee437e0f882163c2819" size="237405" mtime="1423338472"/>
|
||||||
|
</directory>
|
38
tests/obs.py
38
tests/obs.py
@ -367,10 +367,20 @@ class OBS(object):
|
|||||||
'openSUSE:Factory:Staging:J': [],
|
'openSUSE:Factory:Staging:J': [],
|
||||||
}
|
}
|
||||||
|
|
||||||
# To track comments created during test execution, even if they have
|
# To track comments created during test execution, even if
|
||||||
# been deleted afterward
|
# they have been deleted afterward
|
||||||
self.comment_bodies = []
|
self.comment_bodies = []
|
||||||
|
|
||||||
|
# Different spec files stored in some openSUSE:Factory
|
||||||
|
# projects
|
||||||
|
self.spec_list = {
|
||||||
|
'openSUSE:Factory/apparmor': [
|
||||||
|
{
|
||||||
|
'spec': 'apparmor.spec',
|
||||||
|
}
|
||||||
|
],
|
||||||
|
}
|
||||||
|
|
||||||
#
|
#
|
||||||
# /request/
|
# /request/
|
||||||
#
|
#
|
||||||
@ -560,6 +570,30 @@ class OBS(object):
|
|||||||
|
|
||||||
return response
|
return response
|
||||||
|
|
||||||
|
@GET(re.compile(r'/source/openSUSE:Factory/apparmor$'))
|
||||||
|
def source_project_apparmor(self, request, uri, headers):
|
||||||
|
"""Return apparmor spec list."""
|
||||||
|
package = re.search(r'/source/([\w:]+/\w+)', uri).group(1)
|
||||||
|
response = (404, headers, '<result>Not found</result>')
|
||||||
|
try:
|
||||||
|
template = string.Template(self._fixture(uri, filename='apparmor.xml'))
|
||||||
|
entry_template = string.Template(self._fixture(uri, filename='_entry.xml'))
|
||||||
|
entries = ''.join(entry_template.substitute(entry) for entry in self.spec_list[package])
|
||||||
|
response = (200, headers, template.substitute({'entries': entries}))
|
||||||
|
|
||||||
|
# The next call len() will be 2
|
||||||
|
if len(self.spec_list[package]) == 1:
|
||||||
|
self.spec_list[package].append({'spec': 'apparmor-doc.spec'})
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
if DEBUG:
|
||||||
|
print uri, e
|
||||||
|
|
||||||
|
if DEBUG:
|
||||||
|
print 'SOURCE APPARMOR', uri, response
|
||||||
|
|
||||||
|
return response
|
||||||
|
|
||||||
@GET(re.compile(r'/source/home:Admin/\w+'))
|
@GET(re.compile(r'/source/home:Admin/\w+'))
|
||||||
def source_project(self, request, uri, headers):
|
def source_project(self, request, uri, headers):
|
||||||
"""Return information of a source package."""
|
"""Return information of a source package."""
|
||||||
|
Loading…
x
Reference in New Issue
Block a user