virtually accept: virtually accept the delete request
Implementation virtually accept the delete request, the delete request will be added another delreq-review review and also wipes the binary in the main project, the backend will sync 'nothing' to ToTest and Snapshot after all. Once all repository has no binary then remove the package in real.
This commit is contained in:
parent
4011159df4
commit
5611411a6f
@ -3,9 +3,9 @@ import urllib2
|
|||||||
import warnings
|
import warnings
|
||||||
from xml.etree import cElementTree as ET
|
from xml.etree import cElementTree as ET
|
||||||
|
|
||||||
from osc.core import change_request_state
|
from osc.core import change_request_state, show_package_meta, wipebinaries
|
||||||
from osc.core import http_GET, http_PUT, http_DELETE, http_POST
|
from osc.core import http_GET, http_PUT, http_DELETE, http_POST
|
||||||
from osc.core import delete_package
|
from osc.core import delete_package, search, set_devel_project
|
||||||
from datetime import date
|
from datetime import date
|
||||||
|
|
||||||
|
|
||||||
@ -14,7 +14,40 @@ class AcceptCommand(object):
|
|||||||
self.api = api
|
self.api = api
|
||||||
|
|
||||||
def find_new_requests(self, project):
|
def find_new_requests(self, project):
|
||||||
query = "match=state/@name='new'+and+(action/target/@project='{}'+and+action/@type='submit')".format(project)
|
query = "match=state/@name='new'+and+action/target/@project='{}'".format(project)
|
||||||
|
url = self.api.makeurl(['search', 'request'], query)
|
||||||
|
|
||||||
|
f = http_GET(url)
|
||||||
|
root = ET.parse(f).getroot()
|
||||||
|
|
||||||
|
rqs = []
|
||||||
|
for rq in root.findall('request'):
|
||||||
|
pkgs = []
|
||||||
|
act_type = None
|
||||||
|
actions = rq.findall('action')
|
||||||
|
for action in actions:
|
||||||
|
act_type = action.get('type')
|
||||||
|
targets = action.findall('target')
|
||||||
|
for t in targets:
|
||||||
|
pkgs.append(str(t.get('package')))
|
||||||
|
|
||||||
|
rqs.append({'id': int(rq.get('id')), 'packages': pkgs, 'type': act_type})
|
||||||
|
return rqs
|
||||||
|
|
||||||
|
def virtual_accept_request_has_no_binary(self, project, package):
|
||||||
|
filelist = self.api.get_filelist_for_package(pkgname=package, project=self.api.project, expand='1', extension='spec')
|
||||||
|
pkgs = self.api.extract_specfile_short(filelist)
|
||||||
|
|
||||||
|
for pkg in pkgs:
|
||||||
|
query = {'view': 'binarylist', 'package': pkg, 'multibuild': '1'}
|
||||||
|
pkg_binarylist = ET.parse(http_GET(self.api.makeurl(['build', project, '_result'], query=query))).getroot()
|
||||||
|
for binary in pkg_binarylist.findall('./result/binarylist/binary'):
|
||||||
|
return False
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
def find_virtually_accepted_requests(self, project):
|
||||||
|
query = "match=state/@name='review'+and+(action/target/@project='{}'+and+action/@type='delete')+and+(review/@state='new'+and+review/@by_group='{}')".format(project, self.api.delreq_review)
|
||||||
url = self.api.makeurl(['search', 'request'], query)
|
url = self.api.makeurl(['search', 'request'], query)
|
||||||
|
|
||||||
f = http_GET(url)
|
f = http_GET(url)
|
||||||
@ -51,6 +84,24 @@ class AcceptCommand(object):
|
|||||||
content = ET.tostring(root)
|
content = ET.tostring(root)
|
||||||
http_PUT(url + '?comment=accept+command+update', data=content)
|
http_PUT(url + '?comment=accept+command+update', data=content)
|
||||||
|
|
||||||
|
def virtually_accept_delete(self, request_id, package):
|
||||||
|
self.api.add_review(request_id, by_group=self.api.delreq_review, msg='Request accepted. Cleanup in progress - DO NOT REVOKE!')
|
||||||
|
|
||||||
|
filelist = self.api.get_filelist_for_package(pkgname=package, project=self.api.project, expand='1', extension='spec')
|
||||||
|
pkgs = self.api.extract_specfile_short(filelist)
|
||||||
|
|
||||||
|
# Disable build and wipes the binary to the package and the sub-package
|
||||||
|
for pkg in pkgs:
|
||||||
|
meta = show_package_meta(self.api.apiurl, self.api.project, pkg)
|
||||||
|
meta = ''.join(meta)
|
||||||
|
# Update package meta to disable build
|
||||||
|
self.api.create_package_container(self.api.project, pkg, meta=meta, disable_build=True)
|
||||||
|
wipebinaries(self.api.apiurl, self.api.project, package=pkg, repo=self.api.main_repo)
|
||||||
|
|
||||||
|
# Remove package from Rings
|
||||||
|
if self.api.ring_packages.get(pkg):
|
||||||
|
delete_package(self.api.apiurl, self.api.ring_packages.get(pkg), pkg, force=True, msg="Cleanup package in Rings")
|
||||||
|
|
||||||
def perform(self, project, force=False):
|
def perform(self, project, force=False):
|
||||||
"""Accept the staging project for review and submit to Factory /
|
"""Accept the staging project for review and submit to Factory /
|
||||||
openSUSE 13.2 ...
|
openSUSE 13.2 ...
|
||||||
@ -73,16 +124,22 @@ class AcceptCommand(object):
|
|||||||
self.api.rm_from_prj(project, request_id=req['id'], msg='ready to accept')
|
self.api.rm_from_prj(project, request_id=req['id'], msg='ready to accept')
|
||||||
packages.append(req['package'])
|
packages.append(req['package'])
|
||||||
msg = 'Accepting staging review for {}'.format(req['package'])
|
msg = 'Accepting staging review for {}'.format(req['package'])
|
||||||
print(msg)
|
|
||||||
|
|
||||||
oldspecs = self.api.get_filelist_for_package(pkgname=req['package'],
|
oldspecs = self.api.get_filelist_for_package(pkgname=req['package'],
|
||||||
project=self.api.project,
|
project=self.api.project,
|
||||||
extension='spec')
|
extension='spec')
|
||||||
change_request_state(self.api.apiurl,
|
if 'type' in req and req['type'] == 'delete' and self.api.delreq_review:
|
||||||
str(req['id']),
|
msg += ' and started handling of virtual accept process'
|
||||||
'accepted',
|
print(msg)
|
||||||
message='Accept to %s' % self.api.project)
|
# Virtually accept the delete request
|
||||||
self.create_new_links(self.api.project, req['package'], oldspecs)
|
self.virtually_accept_delete(req['id'], req['package'])
|
||||||
|
else:
|
||||||
|
print(msg)
|
||||||
|
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.api.accept_status_comment(project, packages)
|
self.api.accept_status_comment(project, packages)
|
||||||
self.api.staging_deactivate(project)
|
self.api.staging_deactivate(project)
|
||||||
@ -128,6 +185,16 @@ class AcceptCommand(object):
|
|||||||
|
|
||||||
def accept_other_new(self):
|
def accept_other_new(self):
|
||||||
changed = False
|
changed = False
|
||||||
|
|
||||||
|
if self.api.delreq_review:
|
||||||
|
rqlist = self.find_virtually_accepted_requests(self.api.project)
|
||||||
|
for req in rqlist:
|
||||||
|
if self.virtual_accept_request_has_no_binary(self.api.project, req['packages'][0]):
|
||||||
|
# Accepting delreq-review review
|
||||||
|
self.api.do_change_review_state(req['id'], 'accepted',
|
||||||
|
by_group=self.api.delreq_review,
|
||||||
|
message='Virtually accepted delete {}'.format(req['packages'][0]))
|
||||||
|
|
||||||
rqlist = self.find_new_requests(self.api.project)
|
rqlist = self.find_new_requests(self.api.project)
|
||||||
if self.api.cnonfree:
|
if self.api.cnonfree:
|
||||||
rqlist += self.find_new_requests(self.api.cnonfree)
|
rqlist += self.find_new_requests(self.api.cnonfree)
|
||||||
@ -135,6 +202,9 @@ class AcceptCommand(object):
|
|||||||
for req in rqlist:
|
for req in rqlist:
|
||||||
oldspecs = self.api.get_filelist_for_package(pkgname=req['packages'][0], project=self.api.project, extension='spec')
|
oldspecs = self.api.get_filelist_for_package(pkgname=req['packages'][0], project=self.api.project, extension='spec')
|
||||||
print 'Accepting request %d: %s' % (req['id'], ','.join(req['packages']))
|
print 'Accepting request %d: %s' % (req['id'], ','.join(req['packages']))
|
||||||
|
if req['type'] == 'delete':
|
||||||
|
# Remove devel project/package tag before accepting the request
|
||||||
|
self.remove_obsoleted_develtag(self.api.project, req['packages'][0])
|
||||||
change_request_state(self.api.apiurl, str(req['id']), 'accepted', message='Accept to %s' % self.api.project)
|
change_request_state(self.api.apiurl, str(req['id']), 'accepted', message='Accept to %s' % self.api.project)
|
||||||
# Check if all .spec files of the package we just accepted has a package container to build
|
# Check if all .spec files of the package we just accepted has a package container to build
|
||||||
self.create_new_links(self.api.project, req['packages'][0], oldspecs)
|
self.create_new_links(self.api.project, req['packages'][0], oldspecs)
|
||||||
@ -142,6 +212,14 @@ class AcceptCommand(object):
|
|||||||
|
|
||||||
return changed
|
return changed
|
||||||
|
|
||||||
|
def remove_obsoleted_develtag(self, project, package):
|
||||||
|
xpath = {
|
||||||
|
'package': "@project='%s' and devel/@project=@project and devel/@package='%s'" % (project, package),
|
||||||
|
}
|
||||||
|
collection = search(self.api.apiurl, **xpath)['package']
|
||||||
|
for pkg in collection.findall('package'):
|
||||||
|
set_devel_project(self.api.apiurl, project, pkg.attrib['name'], devprj=None)
|
||||||
|
|
||||||
def create_new_links(self, project, pkgname, oldspeclist):
|
def create_new_links(self, project, pkgname, oldspeclist):
|
||||||
filelist = self.api.get_filelist_for_package(pkgname=pkgname, project=project, extension='spec')
|
filelist = self.api.get_filelist_for_package(pkgname=pkgname, project=project, extension='spec')
|
||||||
removedspecs = set(oldspeclist) - set(filelist)
|
removedspecs = set(oldspeclist) - set(filelist)
|
||||||
|
@ -44,6 +44,8 @@ DEFAULT = {
|
|||||||
'openqa': 'https://openqa.opensuse.org',
|
'openqa': 'https://openqa.opensuse.org',
|
||||||
'lock': 'openSUSE:%(project)s:Staging',
|
'lock': 'openSUSE:%(project)s:Staging',
|
||||||
'lock-ns': 'openSUSE',
|
'lock-ns': 'openSUSE',
|
||||||
|
'delreq-review': 'factory-maintainers',
|
||||||
|
'main-repo': 'standard',
|
||||||
},
|
},
|
||||||
r'openSUSE:(?P<project>Leap:[\d.]+)': {
|
r'openSUSE:(?P<project>Leap:[\d.]+)': {
|
||||||
'staging': 'openSUSE:%(project)s:Staging',
|
'staging': 'openSUSE:%(project)s:Staging',
|
||||||
|
@ -75,6 +75,8 @@ class StagingAPI(object):
|
|||||||
self.cproduct = conf.config[project]['product']
|
self.cproduct = conf.config[project]['product']
|
||||||
self.copenqa = conf.config[project]['openqa']
|
self.copenqa = conf.config[project]['openqa']
|
||||||
self.user = conf.get_apiurl_usr(apiurl)
|
self.user = conf.get_apiurl_usr(apiurl)
|
||||||
|
self.delreq_review = conf.config[project]['delreq-review']
|
||||||
|
self.main_repo = conf.config[project]['main-repo']
|
||||||
self._ring_packages = None
|
self._ring_packages = None
|
||||||
self._ring_packages_for_links = None
|
self._ring_packages_for_links = None
|
||||||
self._packages_staged = None
|
self._packages_staged = None
|
||||||
@ -260,6 +262,11 @@ class StagingAPI(object):
|
|||||||
|
|
||||||
return package_info
|
return package_info
|
||||||
|
|
||||||
|
def extract_specfile_short(self, filelist):
|
||||||
|
packages = [spec[:-5] for spec in filelist if re.search('\.spec$', spec)]
|
||||||
|
|
||||||
|
return packages
|
||||||
|
|
||||||
def get_filelist_for_package(self, pkgname, project, expand=None, extension=None):
|
def get_filelist_for_package(self, pkgname, project, expand=None, extension=None):
|
||||||
"""
|
"""
|
||||||
Get a list of files inside a package container
|
Get a list of files inside a package container
|
||||||
@ -748,7 +755,7 @@ class StagingAPI(object):
|
|||||||
def clear_prj_pseudometa(self, project):
|
def clear_prj_pseudometa(self, project):
|
||||||
self.set_prj_pseudometa(project, {})
|
self.set_prj_pseudometa(project, {})
|
||||||
|
|
||||||
def _add_rq_to_prj_pseudometa(self, project, request_id, package):
|
def _add_rq_to_prj_pseudometa(self, project, request_id, package, act_type=None):
|
||||||
"""
|
"""
|
||||||
Records request as part of the project within metadata
|
Records request as part of the project within metadata
|
||||||
:param project: project to record into
|
:param project: project to record into
|
||||||
@ -761,13 +768,14 @@ class StagingAPI(object):
|
|||||||
for request in data['requests']:
|
for request in data['requests']:
|
||||||
if request['package'] == package:
|
if request['package'] == package:
|
||||||
# Only update if needed (to save calls to get_request)
|
# Only update if needed (to save calls to get_request)
|
||||||
if request['id'] != request_id or not request.get('author'):
|
if request['id'] != request_id or not request.get('author') or not request.get('type'):
|
||||||
request['id'] = request_id
|
request['id'] = request_id
|
||||||
|
request['type'] = act_type
|
||||||
request['author'] = get_request(self.apiurl, str(request_id)).get_creator()
|
request['author'] = get_request(self.apiurl, str(request_id)).get_creator()
|
||||||
append = False
|
append = False
|
||||||
if append:
|
if append:
|
||||||
author = get_request(self.apiurl, str(request_id)).get_creator()
|
author = get_request(self.apiurl, str(request_id)).get_creator()
|
||||||
data['requests'].append({'id': request_id, 'package': package, 'author': author})
|
data['requests'].append({'id': request_id, 'package': package, 'author': author, 'type': act_type})
|
||||||
self.set_prj_pseudometa(project, data)
|
self.set_prj_pseudometa(project, data)
|
||||||
|
|
||||||
def set_splitter_info_in_prj_pseudometa(self, project, group, strategy_info):
|
def set_splitter_info_in_prj_pseudometa(self, project, group, strategy_info):
|
||||||
@ -859,24 +867,27 @@ class StagingAPI(object):
|
|||||||
self._package_disabled['/'.join([project, package])] = disabled
|
self._package_disabled['/'.join([project, package])] = disabled
|
||||||
return disabled
|
return disabled
|
||||||
|
|
||||||
def create_package_container(self, project, package, disable_build=False):
|
def create_package_container(self, project, package, meta=None, disable_build=False):
|
||||||
"""
|
"""
|
||||||
Creates a package container without any fields in project/package
|
Creates a package container without any fields in project/package
|
||||||
:param project: project to create it
|
:param project: project to create it
|
||||||
:param package: package name
|
:param package: package name
|
||||||
|
:param meta: package metadata
|
||||||
:param disable_build: should the package be created with build
|
:param disable_build: should the package be created with build
|
||||||
flag disabled
|
flag disabled
|
||||||
"""
|
"""
|
||||||
dst_meta = '<package name="{}"><title/><description/></package>'
|
if not meta:
|
||||||
dst_meta = dst_meta.format(package)
|
meta = '<package name="{}"><title/><description/></package>'
|
||||||
|
meta = meta.format(package)
|
||||||
|
|
||||||
if disable_build:
|
if disable_build:
|
||||||
root = ET.fromstring(dst_meta)
|
root = ET.fromstring(meta)
|
||||||
elm = ET.SubElement(root, 'build')
|
elm = ET.SubElement(root, 'build')
|
||||||
ET.SubElement(elm, 'disable')
|
ET.SubElement(elm, 'disable')
|
||||||
dst_meta = ET.tostring(root)
|
meta = ET.tostring(root)
|
||||||
|
|
||||||
url = self.makeurl(['source', project, package, '_meta'])
|
url = self.makeurl(['source', project, package, '_meta'])
|
||||||
http_PUT(url, data=dst_meta)
|
http_PUT(url, data=meta)
|
||||||
|
|
||||||
def check_ring_packages(self, project, requests):
|
def check_ring_packages(self, project, requests):
|
||||||
"""
|
"""
|
||||||
@ -1057,6 +1068,7 @@ class StagingAPI(object):
|
|||||||
"""
|
"""
|
||||||
# read info from sr
|
# read info from sr
|
||||||
tar_pkg = None
|
tar_pkg = None
|
||||||
|
act_type = None
|
||||||
|
|
||||||
req = get_request(self.apiurl, str(request_id))
|
req = get_request(self.apiurl, str(request_id))
|
||||||
if not req:
|
if not req:
|
||||||
@ -1064,10 +1076,12 @@ class StagingAPI(object):
|
|||||||
|
|
||||||
act = req.get_actions('submit')
|
act = req.get_actions('submit')
|
||||||
if act:
|
if act:
|
||||||
|
act_type = 'submit'
|
||||||
tar_pkg = self.submit_to_prj(act[0], project)
|
tar_pkg = self.submit_to_prj(act[0], project)
|
||||||
|
|
||||||
act = req.get_actions('delete')
|
act = req.get_actions('delete')
|
||||||
if act:
|
if act:
|
||||||
|
act_type = 'delete'
|
||||||
tar_pkg = self.delete_to_prj(act[0], project)
|
tar_pkg = self.delete_to_prj(act[0], project)
|
||||||
|
|
||||||
if not tar_pkg:
|
if not tar_pkg:
|
||||||
@ -1076,7 +1090,7 @@ class StagingAPI(object):
|
|||||||
raise oscerr.WrongArgs(msg)
|
raise oscerr.WrongArgs(msg)
|
||||||
|
|
||||||
# register the package name
|
# register the package name
|
||||||
self._add_rq_to_prj_pseudometa(project, int(request_id), tar_pkg)
|
self._add_rq_to_prj_pseudometa(project, int(request_id), tar_pkg, act_type=act_type)
|
||||||
|
|
||||||
# add review
|
# add review
|
||||||
self.add_review(request_id, project)
|
self.add_review(request_id, project)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user