mirror of
https://github.com/openSUSE/osc.git
synced 2025-01-27 15:06:15 +01:00
import new request handling from branch:
- New generic "request" command: - new "delete" request - new "change_devel" request - Multiple actions in one request is not yet supported by osc
This commit is contained in:
parent
0158d5e377
commit
46d726133c
5
NEWS
5
NEWS
@ -1,4 +1,9 @@
|
|||||||
0.118:
|
0.118:
|
||||||
|
- Obsolete "submitreq" command
|
||||||
|
- New generic "request" command:
|
||||||
|
- new "delete" request
|
||||||
|
- new "change_devel" request
|
||||||
|
- Multiple actions in one request is not yet supported by osc
|
||||||
- support of added .changes in commit message template
|
- support of added .changes in commit message template
|
||||||
- make submit request listing fast by server side filtering
|
- make submit request listing fast by server side filtering
|
||||||
- allow pulling of conflicting changes via "osc repairlink"
|
- allow pulling of conflicting changes via "osc repairlink"
|
||||||
|
74
TODO
74
TODO
@ -58,85 +58,11 @@ MINOR:
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
[1]
|
|
||||||
|
|
||||||
http://api.opensuse.org/result/Apache/SUSE_Linux_10.0/apache2/result
|
|
||||||
15:06 <darix> kurz zeit ueber 1-2 osc feature request zu reden die ich grade bekommen habe?
|
|
||||||
15:06 <DuDE_> ja
|
|
||||||
15:06 <darix> ok
|
|
||||||
15:06 <darix> das 1. ist
|
|
||||||
15:06 <darix> osc listpackages [<project>]
|
|
||||||
15:06 <DuDE_> als Alias?
|
|
||||||
15:07 <darix> osc listpackages [<project>] [<package>]
|
|
||||||
15:07 <darix> es soll die gebauten sachen listen
|
|
||||||
15:07 <DuDE_> ach so, rpms
|
|
||||||
15:07 <darix> quasi alle rpms/debs die da sind
|
|
||||||
15:07 <darix> und dann
|
|
||||||
15:07 <DuDE_> mit Pfad/URL?
|
|
||||||
15:07 <DuDE_> also praktisch den Link auf software.opesuse.org?
|
|
||||||
15:07 <darix> osc getpackage [<project>] [<package>] [<rpm>]+
|
|
||||||
15:07 <darix> nein
|
|
||||||
15:07 <darix> im zweifel ueber API saugen
|
|
||||||
15:08 <DuDE_> hm, waere noetig, falls ein Projekt noch nicht durchgebaut hat
|
|
||||||
15:08 <darix> jau
|
|
||||||
15:08 <darix> richi wuerde sich wirklich drueber freuen
|
|
||||||
15:08 <darix> ich weiss dass es ueber die api vom backend geht
|
|
||||||
15:09 <darix> ich weiss nur nicht ob api alles durchreicht
|
|
||||||
15:09 <darix> und leider hab ich schon ein paar sachen im api code gefunden
|
|
||||||
15:09 <darix> der falsch mit dem backend spricht :/
|
|
||||||
15:09 <DuDE_> ja, macht osc build auch so, eigentlich, allerdings weiss es dann die noetigen Datein aus dem buildinfo (version, release)
|
|
||||||
15:09 <darix> man kann auf dem backend alle rpms listen lassen
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
[3]
|
|
||||||
|
|
||||||
19:08 < Beineri> DuDE: can you add an option to "up" which moves instead overwriting a file if it has changed in the repository?
|
|
||||||
19:08 < darix> Beineri: moves?
|
|
||||||
19:08 < darix> oO
|
|
||||||
19:08 < darix> Beineri: use case?
|
|
||||||
19:09 < Beineri> darix: I want to see what changed when updating (we miss notification and history if you didn't notice). so I want to run "diff foo.myversion foo"
|
|
||||||
19:09 < darix> Beineri: we have a history?
|
|
||||||
19:09 < darix> Beineri: you should rtfm the api docs before claiming stuff!:p
|
|
||||||
19:10 < Beineri> darix: trying to turn around my words?
|
|
||||||
19:10 < darix> Beineri: no
|
|
||||||
19:10 < darix> just correcting wrong statements.
|
|
||||||
19:10 < DuDE> Beineri: doesn't sound too useful
|
|
||||||
19:10 < Beineri> darix: what's wrong with "we miss history"?
|
|
||||||
19:10 < DuDE> it's deviating too much from the normal usecase
|
|
||||||
19:10 < DuDE> which is, merging upstream changes in
|
|
||||||
19:10 < DuDE> Beineri: but I have a better idea, I think
|
|
||||||
19:11 < DuDE> Beineri: something that I miss in svn very much
|
|
||||||
19:11 < Beineri> DuDE: it still shall merge, but make a copy of my version before :-)
|
|
||||||
19:11 < darix> GET http://api.opensuse.org/source/<project>/<package>/<filename>
|
|
||||||
19:11 < DuDE> Beineri: you mean, keep a fool.mine file in any case?
|
|
||||||
19:11 < darix> GET http://api.opensuse.org/source/<project>/<package>/<filename>?rev=1234
|
|
||||||
19:11 < DuDE> Beineri: what I miss badly, is a command to see upstream changes
|
|
||||||
19:11 < DuDE> Beineri: such as the good old cvs status
|
|
||||||
19:12 < DuDE> Beineri: which showed the status of the files on the server
|
|
||||||
19:12 < Beineri> DuDE: status is not enough, I want to see what changed :-)
|
|
||||||
19:12 < DuDE> Beineri: I mostly want to know what I have to expect, before up'ping and merging
|
|
||||||
19:12 < DuDE> Beineri: yes, I also want to see that
|
|
||||||
19:12 < DuDE> Beineri: some kind of osc updiff
|
|
||||||
19:13 < DuDE> Beineri: would that help?
|
|
||||||
19:13 < darix> .oO( i smell nice race conditions^^ )o
|
|
||||||
19:13 < DuDE> Beineri: sorry, I just recognize that you asked for an option
|
|
||||||
19:13 < DuDE> Beineri: that's of course always an option
|
|
||||||
19:14 < DuDE> Beineri: surely
|
|
||||||
19:14 < Beineri> DuDE: that would help, yes. "my" stuff I could for now do with a wrapper :-)
|
|
||||||
19:15 < Beineri> darix: and that's how useful without osc/web-frontend support?
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
15:16 < DuDE> mt: Projekte anlegen geht nur, wenn es ein Subprojekt ist von einem Projekt wo Du Schreibrechte hast
|
15:16 < DuDE> mt: Projekte anlegen geht nur, wenn es ein Subprojekt ist von einem Projekt wo Du Schreibrechte hast
|
||||||
15:16 < mt> DuDE: wofür?
|
15:16 < mt> DuDE: wofür?
|
||||||
15:16 < DuDE> mt: dass jeder einfach so top-level-Projekte anlegen kann, war einmal. Chaos-Reduzierung
|
15:16 < DuDE> mt: dass jeder einfach so top-level-Projekte anlegen kann, war einmal. Chaos-Reduzierung
|
||||||
15:17 < DuDE> mt: ueblich ist heutzutage ein Request auf opensuse-buildservice@
|
15:17 < DuDE> mt: ueblich ist heutzutage ein Request auf opensuse-buildservice@
|
||||||
15:18 < DuDE> mt: kannst Du das gleiche mal eben mit osc -H probieren? Mich wuerde mal interessieren, ob da eine sinnvollere Meldung im Body mitkommt
|
15:18 < DuDE> mt: kannst Du das gleiche mal eben mit osc -H probieren? Mich wuerde mal interessieren, ob da eine sinnvollere Meldung im Body mitkommt
|
||||||
15:19 < DuDE> mt: mit -H muesste osc den Response-Body anzeigen. Meist ist der unerwuenscht, weil er typischerweise dank iChain hauptsaechlich Javascript-Schlonz enthaelt.
|
|
||||||
15:19 < mt> DuDE: reply: 'HTTP/1.1 403 Forbidden\r\n'
|
15:19 < mt> DuDE: reply: 'HTTP/1.1 403 Forbidden\r\n'
|
||||||
15:20 < DuDE> mt: das ist gut, dann sollte osc kein "try again" anbieten, sondern die Meldung rueberbringen
|
15:20 < DuDE> mt: das ist gut, dann sollte osc kein "try again" anbieten, sondern die Meldung rueberbringen
|
||||||
|
|
||||||
|
@ -486,58 +486,25 @@ class Osc(cmdln.Cmdln):
|
|||||||
help='only show requests created by yourself')
|
help='only show requests created by yourself')
|
||||||
@cmdln.alias("sr")
|
@cmdln.alias("sr")
|
||||||
@cmdln.alias("submitrequest")
|
@cmdln.alias("submitrequest")
|
||||||
|
@cmdln.hide(1)
|
||||||
def do_submitreq(self, subcmd, opts, *args):
|
def do_submitreq(self, subcmd, opts, *args):
|
||||||
"""${cmd_name}: Handle requests to submit a package into another project
|
"""${cmd_name}: Handle requests to submit a package into another project
|
||||||
|
|
||||||
[See http://en.opensuse.org/Build_Service/Collaboration for information
|
[See http://en.opensuse.org/Build_Service/Collaboration for information
|
||||||
on this topic.]
|
on this topic.]
|
||||||
|
|
||||||
For "create", there are two ways to use it. Either with a working copy
|
*************************************************************************
|
||||||
or without. If called with no arguments, osc will guess what to submit
|
WARNING: the "submitreq" command is about to become obsolete. Please use
|
||||||
where. If you don't have a working copy, you can give the respective
|
the "request" command instead !
|
||||||
arguments on the command line (see below for an example).
|
*************************************************************************
|
||||||
Then, the DESTPAC name is optional; the source packages' name will be
|
|
||||||
used if DESTPAC is omitted.
|
|
||||||
With --message, a message can be attached.
|
|
||||||
With --revision, a revision MD5 of a package can be specified which is
|
|
||||||
to be submitted. The default is to request submission of the currently
|
|
||||||
checked in revision.
|
|
||||||
|
|
||||||
"list" lists open requests attached to a project or package.
|
|
||||||
|
|
||||||
"log" will show the history of the given ID
|
|
||||||
|
|
||||||
"show" will show the request itself, and generate a diff for review, if
|
|
||||||
used with the --diff option.
|
|
||||||
|
|
||||||
"decline" will change the request state to "declined" and append a
|
|
||||||
message that you specify with the --message option.
|
|
||||||
|
|
||||||
"delete" will permanently delete a request and append a
|
|
||||||
message that you specify with the --message option.
|
|
||||||
|
|
||||||
"revoke" will set the request state to "revoked" and append a
|
|
||||||
message that you specify with the --message option.
|
|
||||||
|
|
||||||
"accept" will change the request state to "accepted" and will trigger
|
|
||||||
the actual submit process. That would normally be a server-side copy of
|
|
||||||
the source package to the target package.
|
|
||||||
|
|
||||||
|
|
||||||
usage:
|
|
||||||
osc submitreq create [-m TEXT]
|
|
||||||
osc submitreq create [-m TEXT] DESTPRJ [DESTPKG]
|
|
||||||
osc submitreq create [-m TEXT] SOURCEPRJ SOURCEPKG DESTPRJ [DESTPKG]
|
|
||||||
osc submitreq list [-M] [PRJ [PKG]]
|
|
||||||
osc submitreq log ID
|
|
||||||
osc submitreq show [-d] [-b] ID
|
|
||||||
osc submitreq accept [-m TEXT] ID
|
|
||||||
osc submitreq decline [-m TEXT] ID
|
|
||||||
osc submitreq delete [-m TEXT] ID
|
|
||||||
osc submitreq revoke [-m TEXT] ID
|
|
||||||
${cmd_option_list}
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
print """
|
||||||
|
*************************************************************************
|
||||||
|
WARNING: the "submitreq" command is about to become obsolete. Please use
|
||||||
|
the "request" command instead !
|
||||||
|
*************************************************************************
|
||||||
|
"""
|
||||||
args = slash_split(args)
|
args = slash_split(args)
|
||||||
|
|
||||||
cmds = ['create', 'list', 'log', 'show', 'decline', 'accept', 'delete', 'revoke']
|
cmds = ['create', 'list', 'log', 'show', 'decline', 'accept', 'delete', 'revoke']
|
||||||
@ -639,23 +606,25 @@ of the package %s primarily takes place.
|
|||||||
Please submit there instead, or use --nodevelproject to force direct submission.""" \
|
Please submit there instead, or use --nodevelproject to force direct submission.""" \
|
||||||
% (devloc, dst_package)
|
% (devloc, dst_package)
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
reqs = get_submit_request_list(apiurl, dst_project, dst_package)
|
reqs = get_request_list(apiurl, dst_project, dst_package)
|
||||||
user = conf.get_apiurl_usr(apiurl)
|
user = conf.get_apiurl_usr(apiurl)
|
||||||
myreqs = [ i for i in reqs if i.state.who == user ]
|
myreqs = [ i for i in reqs if i.state.who == user ]
|
||||||
repl = ''
|
repl = ''
|
||||||
if len(myreqs) > 0:
|
if len(myreqs) > 0:
|
||||||
print 'You already created the following submitrequests: %s.' % \
|
print 'You already created the following requests: %s.' % \
|
||||||
', '.join([str(i.reqid) for i in myreqs ])
|
', '.join([str(i.reqid) for i in myreqs ])
|
||||||
repl = raw_input('Revoke the old requests? (y/N) ')
|
repl = raw_input('Revoke the old requests? (y/N) ')
|
||||||
|
|
||||||
|
# since we have no support in the cli to specify different action types yet
|
||||||
|
# the default is a submit action
|
||||||
result = create_submit_request(apiurl,
|
result = create_submit_request(apiurl,
|
||||||
src_project, src_package,
|
src_project, src_package,
|
||||||
dst_project, dst_package,
|
dst_project, dst_package,
|
||||||
opts.message, orev=opts.revision)
|
opts.message, orev=opts.revision)
|
||||||
if repl == 'y':
|
if repl == 'y':
|
||||||
for req in myreqs:
|
for req in myreqs:
|
||||||
change_submit_request_state(apiurl, str(req.reqid), 'revoked',
|
change_request_state(apiurl, str(req.reqid), 'revoked',
|
||||||
'superseded by %s' % result)
|
'superseded by %s' % result)
|
||||||
|
|
||||||
print 'created request id', result
|
print 'created request id', result
|
||||||
|
|
||||||
@ -667,8 +636,8 @@ Please submit there instead, or use --nodevelproject to force direct submission.
|
|||||||
if opts.mine:
|
if opts.mine:
|
||||||
who = conf.get_apiurl_usr(apiurl)
|
who = conf.get_apiurl_usr(apiurl)
|
||||||
|
|
||||||
results = get_submit_request_list(apiurl,
|
results = get_request_list(apiurl,
|
||||||
project, package, who, state_list)
|
project, package, who, state_list)
|
||||||
|
|
||||||
results.sort(reverse=True)
|
results.sort(reverse=True)
|
||||||
|
|
||||||
@ -676,13 +645,13 @@ Please submit there instead, or use --nodevelproject to force direct submission.
|
|||||||
print result.list_view()
|
print result.list_view()
|
||||||
|
|
||||||
elif cmd == 'log':
|
elif cmd == 'log':
|
||||||
for l in get_submit_request_log(conf.config['apiurl'], reqid):
|
for l in get_request_log(conf.config['apiurl'], reqid):
|
||||||
print l
|
print l
|
||||||
|
|
||||||
|
|
||||||
# show
|
# show
|
||||||
elif cmd == 'show':
|
elif cmd == 'show':
|
||||||
r = get_submit_request(conf.config['apiurl'], reqid)
|
r = get_request(conf.config['apiurl'], reqid)
|
||||||
if opts.brief:
|
if opts.brief:
|
||||||
print r.list_view()
|
print r.list_view()
|
||||||
else:
|
else:
|
||||||
@ -691,8 +660,8 @@ Please submit there instead, or use --nodevelproject to force direct submission.
|
|||||||
if opts.diff:
|
if opts.diff:
|
||||||
try:
|
try:
|
||||||
print server_diff(conf.config['apiurl'],
|
print server_diff(conf.config['apiurl'],
|
||||||
r.dst_project, r.dst_package, None,
|
r.actions[0].dst_project, r.actions[0].dst_package, None,
|
||||||
r.src_project, r.src_package, r.src_rev, opts.unified)
|
r.actions[0].src_project, r.actions[0].src_package, r.actions[0].src_rev, opts.unified)
|
||||||
except urllib2.HTTPError, e:
|
except urllib2.HTTPError, e:
|
||||||
e.osc_msg = 'Diff not possible'
|
e.osc_msg = 'Diff not possible'
|
||||||
raise
|
raise
|
||||||
@ -700,23 +669,300 @@ Please submit there instead, or use --nodevelproject to force direct submission.
|
|||||||
|
|
||||||
# decline
|
# decline
|
||||||
elif cmd == 'decline':
|
elif cmd == 'decline':
|
||||||
r = change_submit_request_state(conf.config['apiurl'],
|
r = change_request_state(conf.config['apiurl'],
|
||||||
reqid, 'declined', opts.message or '')
|
reqid, 'declined', opts.message or '')
|
||||||
print r
|
print r
|
||||||
|
|
||||||
# accept
|
# accept
|
||||||
elif cmd == 'accept':
|
elif cmd == 'accept':
|
||||||
r = change_submit_request_state(conf.config['apiurl'],
|
r = change_request_state(conf.config['apiurl'],
|
||||||
reqid, 'accepted', opts.message or '')
|
reqid, 'accepted', opts.message or '')
|
||||||
print r
|
print r
|
||||||
# delete
|
# delete
|
||||||
elif cmd == 'delete':
|
elif cmd == 'delete':
|
||||||
r = change_submit_request_state(conf.config['apiurl'],
|
r = change_request_state(conf.config['apiurl'],
|
||||||
reqid, 'deleted', opts.message or '')
|
reqid, 'deleted', opts.message or '')
|
||||||
print r
|
print r
|
||||||
# revoke
|
# revoke
|
||||||
elif cmd == 'revoke':
|
elif cmd == 'revoke':
|
||||||
r = change_submit_request_state(conf.config['apiurl'],
|
r = change_request_state(conf.config['apiurl'],
|
||||||
|
reqid, 'revoked', opts.message or '')
|
||||||
|
print r
|
||||||
|
|
||||||
|
|
||||||
|
@cmdln.option('-d', '--diff', action='store_true',
|
||||||
|
help='generate a diff')
|
||||||
|
@cmdln.option('-u', '--unified', action='store_true',
|
||||||
|
help='output the diff in the unified diff format')
|
||||||
|
@cmdln.option('-m', '--message', metavar='TEXT',
|
||||||
|
help='specify message TEXT')
|
||||||
|
@cmdln.option('-r', '--revision', metavar='REV',
|
||||||
|
help='for "create", specify a certain source revision ID (the md5 sum)')
|
||||||
|
@cmdln.option('--nodevelproject', action='store_true',
|
||||||
|
help='do not follow a defined devel project ' \
|
||||||
|
'(primary project where a package is developed)')
|
||||||
|
@cmdln.option('-s', '--state', default='new',
|
||||||
|
help='only list requests in one of the comma separated given states [default=new]')
|
||||||
|
@cmdln.option('-b', '--brief', action='store_true', default=False,
|
||||||
|
help='print output in list view as list subcommand')
|
||||||
|
@cmdln.option('-M', '--mine', action='store_true',
|
||||||
|
help='only show requests created by yourself')
|
||||||
|
@cmdln.alias("rq")
|
||||||
|
def do_request(self, subcmd, opts, *args):
|
||||||
|
"""${cmd_name}: Handle requests to another project
|
||||||
|
|
||||||
|
[See http://en.opensuse.org/Build_Service/Collaboration for information
|
||||||
|
on this topic.]
|
||||||
|
|
||||||
|
For "submit", there are two ways to use it. Either with a working copy
|
||||||
|
or without. If called with no arguments, osc will guess what to submit
|
||||||
|
where. If you don't have a working copy, you can give the respective
|
||||||
|
arguments on the command line (see below for an example).
|
||||||
|
Then, the DESTPAC name is optional; the source packages' name will be
|
||||||
|
used if DESTPAC is omitted.
|
||||||
|
With --message, a message can be attached.
|
||||||
|
With --revision, a revision MD5 of a package can be specified which is
|
||||||
|
to be submitted. The default is to request submission of the currently
|
||||||
|
checked in revision.
|
||||||
|
|
||||||
|
"list" lists open requests attached to a project or package.
|
||||||
|
|
||||||
|
"log" will show the history of the given ID
|
||||||
|
|
||||||
|
"show" will show the request itself, and generate a diff for review, if
|
||||||
|
used with the --diff option.
|
||||||
|
|
||||||
|
"decline" will change the request state to "declined" and append a
|
||||||
|
message that you specify with the --message option.
|
||||||
|
|
||||||
|
"delete" will permanently delete a request and append a
|
||||||
|
message that you specify with the --message option.
|
||||||
|
|
||||||
|
"revoke" will set the request state to "revoked" and append a
|
||||||
|
message that you specify with the --message option.
|
||||||
|
|
||||||
|
"accept" will change the request state to "accepted" and will trigger
|
||||||
|
the actual submit process. That would normally be a server-side copy of
|
||||||
|
the source package to the target package.
|
||||||
|
|
||||||
|
|
||||||
|
usage:
|
||||||
|
osc request submit [-m TEXT]
|
||||||
|
osc request submit [-m TEXT] DESTPRJ [DESTPKG]
|
||||||
|
osc request submit [-m TEXT] SOURCEPRJ SOURCEPKG DESTPRJ [DESTPKG]
|
||||||
|
osc request list [-M] [PRJ [PKG]]
|
||||||
|
osc request log ID
|
||||||
|
osc request show [-d] [-b] ID
|
||||||
|
osc request accept [-m TEXT] ID
|
||||||
|
osc request decline [-m TEXT] ID
|
||||||
|
osc request revoke [-m TEXT] ID
|
||||||
|
osc request delete [-m TEXT] DESTPRJ [DESTPKG]
|
||||||
|
osc request change_devel [-m TEXT] PROJECT PACKAGE DEVEL_PROJECT [DEVEL_PACKAGE]
|
||||||
|
${cmd_option_list}
|
||||||
|
"""
|
||||||
|
|
||||||
|
args = slash_split(args)
|
||||||
|
|
||||||
|
cmds = ['submit', 'list', 'log', 'show', 'decline', 'accept', 'delete', 'revoke', 'change_devel']
|
||||||
|
if not args or args[0] not in cmds:
|
||||||
|
raise oscerr.WrongArgs('Unknown request action. Choose one of %s.' \
|
||||||
|
% ', '.join(cmds))
|
||||||
|
|
||||||
|
cmd = args[0]
|
||||||
|
del args[0]
|
||||||
|
|
||||||
|
if cmd in ['submit']:
|
||||||
|
min_args, max_args = 0, 4
|
||||||
|
elif cmd in ['delete']:
|
||||||
|
min_args, max_args = 1, 2
|
||||||
|
elif cmd in ['change_devel']:
|
||||||
|
min_args, max_args = 3, 4
|
||||||
|
elif cmd in ['list']:
|
||||||
|
min_args, max_args = 0, 2
|
||||||
|
else:
|
||||||
|
min_args, max_args = 1, 1
|
||||||
|
if len(args) < min_args:
|
||||||
|
raise oscerr.WrongArgs('Too few arguments.')
|
||||||
|
if len(args) > max_args:
|
||||||
|
raise oscerr.WrongArgs('Too many arguments.')
|
||||||
|
|
||||||
|
apiurl = conf.config['apiurl']
|
||||||
|
|
||||||
|
# collect specific arguments
|
||||||
|
if cmd == 'submit':
|
||||||
|
if len(args) <= 2:
|
||||||
|
# try using the working copy at hand
|
||||||
|
p = findpacs(os.curdir)[0]
|
||||||
|
src_project = p.prjname
|
||||||
|
src_package = p.name
|
||||||
|
if len(args) == 0 and p.islink():
|
||||||
|
dst_project = p.linkinfo.project
|
||||||
|
dst_package = p.linkinfo.package
|
||||||
|
apiurl = p.apiurl
|
||||||
|
elif len(args) > 0:
|
||||||
|
dst_project = args[0]
|
||||||
|
if len(args) == 2:
|
||||||
|
dst_package = args[1]
|
||||||
|
else:
|
||||||
|
dst_package = src_package
|
||||||
|
else:
|
||||||
|
sys.exit('Package \'%s\' is not a source link, so I cannot guess the submit target.\n'
|
||||||
|
'Please provide it the target via commandline arguments.' % p.name)
|
||||||
|
|
||||||
|
modified = [i for i in p.filenamelist if p.status(i) != ' ' and p.status(i) != '?']
|
||||||
|
if len(modified) > 0:
|
||||||
|
print 'Your working copy has local modifications.'
|
||||||
|
repl = raw_input('Proceed without committing the local changes? (y|N) ')
|
||||||
|
if repl != 'y':
|
||||||
|
sys.exit(1)
|
||||||
|
elif len(args) >= 3:
|
||||||
|
# get the arguments from the commandline
|
||||||
|
src_project, src_package, dst_project = args[0:3]
|
||||||
|
if len(args) == 4:
|
||||||
|
dst_package = args[3]
|
||||||
|
else:
|
||||||
|
dst_package = src_package
|
||||||
|
else:
|
||||||
|
raise oscerr.WrongArgs('Incorrect number of arguments.\n\n' \
|
||||||
|
+ self.get_cmd_help('request'))
|
||||||
|
|
||||||
|
elif cmd == 'list':
|
||||||
|
package = None
|
||||||
|
project = None
|
||||||
|
if len(args) > 0:
|
||||||
|
project = args[0]
|
||||||
|
elif not opts.mine:
|
||||||
|
project = store_read_project(os.curdir)
|
||||||
|
apiurl = store_read_apiurl(os.curdir)
|
||||||
|
try:
|
||||||
|
package = store_read_package(os.curdir)
|
||||||
|
except oscerr.NoWorkingCopy:
|
||||||
|
pass
|
||||||
|
|
||||||
|
if len(args) > 1:
|
||||||
|
package = args[1]
|
||||||
|
elif cmd in ['log', 'show', 'decline', 'accept', 'delete', 'revoke']:
|
||||||
|
reqid = args[0]
|
||||||
|
|
||||||
|
|
||||||
|
# create submit request
|
||||||
|
if cmd == 'submit':
|
||||||
|
if not opts.nodevelproject:
|
||||||
|
devloc = None
|
||||||
|
try:
|
||||||
|
devloc = show_develproject(apiurl, dst_project, dst_package)
|
||||||
|
except urllib2.HTTPError:
|
||||||
|
print >>sys.stderr, """\
|
||||||
|
Warning: failed to fetch meta data for '%s' package '%s' (new package?) """ \
|
||||||
|
% (dst_project, dst_package)
|
||||||
|
pass
|
||||||
|
|
||||||
|
if devloc \
|
||||||
|
and dst_project != devloc \
|
||||||
|
and src_project != devloc:
|
||||||
|
print """\
|
||||||
|
Sorry, but a different project, %s, is defined as the place where development
|
||||||
|
of the package %s primarily takes place.
|
||||||
|
Please submit there instead, or use --nodevelproject to force direct submission.""" \
|
||||||
|
% (devloc, dst_package)
|
||||||
|
sys.exit(1)
|
||||||
|
reqs = get_request_list(apiurl, dst_project, dst_package)
|
||||||
|
user = conf.get_apiurl_usr(apiurl)
|
||||||
|
myreqs = [ i for i in reqs if i.state.who == user ]
|
||||||
|
repl = ''
|
||||||
|
if len(myreqs) > 0:
|
||||||
|
print 'You already created the following submit request: %s.' % \
|
||||||
|
', '.join([str(i.reqid) for i in myreqs ])
|
||||||
|
repl = raw_input('Revoke the old requests? (y/N) ')
|
||||||
|
|
||||||
|
# since we have no support in the cli to specify different action types yet
|
||||||
|
# the default is a submit action
|
||||||
|
result = create_submit_request(apiurl,
|
||||||
|
src_project, src_package,
|
||||||
|
dst_project, dst_package,
|
||||||
|
opts.message, orev=opts.revision)
|
||||||
|
if repl == 'y':
|
||||||
|
for req in myreqs:
|
||||||
|
change_request_state(apiurl, str(req.reqid), 'revoked',
|
||||||
|
'superseded by %s' % result)
|
||||||
|
|
||||||
|
print 'created request id', result
|
||||||
|
|
||||||
|
# create delete request
|
||||||
|
elif cmd == 'delete':
|
||||||
|
project = args[0]
|
||||||
|
package = None
|
||||||
|
if len(args) > 1:
|
||||||
|
package = args[1]
|
||||||
|
result = create_delete_request(apiurl, project, package, opts.message)
|
||||||
|
print result
|
||||||
|
|
||||||
|
# request to change devel project
|
||||||
|
elif cmd == 'change_devel':
|
||||||
|
devel_project = args[2]
|
||||||
|
project = args[0]
|
||||||
|
package = args[1]
|
||||||
|
devel_package = package
|
||||||
|
if len(args) > 3:
|
||||||
|
devel_package = args[3]
|
||||||
|
result = create_change_devel_request(apiurl,
|
||||||
|
devel_project, devel_package,
|
||||||
|
project, package,
|
||||||
|
opts.message)
|
||||||
|
print result
|
||||||
|
|
||||||
|
# list
|
||||||
|
elif cmd == 'list':
|
||||||
|
state_list = opts.state.split(',')
|
||||||
|
who = ''
|
||||||
|
if opts.mine:
|
||||||
|
who = conf.get_apiurl_usr(apiurl)
|
||||||
|
|
||||||
|
results = get_request_list(apiurl,
|
||||||
|
project, package, who, state_list)
|
||||||
|
|
||||||
|
results.sort(reverse=True)
|
||||||
|
|
||||||
|
for result in results:
|
||||||
|
print result.list_view()
|
||||||
|
|
||||||
|
elif cmd == 'log':
|
||||||
|
for l in get_request_log(conf.config['apiurl'], reqid):
|
||||||
|
print l
|
||||||
|
|
||||||
|
|
||||||
|
# show
|
||||||
|
elif cmd == 'show':
|
||||||
|
r = get_request(conf.config['apiurl'], reqid)
|
||||||
|
if opts.brief:
|
||||||
|
print r.list_view()
|
||||||
|
else:
|
||||||
|
print r
|
||||||
|
# fixme: will inevitably fail if the given target doesn't exist
|
||||||
|
if opts.diff:
|
||||||
|
try:
|
||||||
|
print server_diff(conf.config['apiurl'],
|
||||||
|
r.actions[0].dst_project, r.actions[0].dst_package, None,
|
||||||
|
r.actions[0].src_project, r.actions[0].src_package, r.actions[0].src_rev, opts.unified)
|
||||||
|
except urllib2.HTTPError, e:
|
||||||
|
e.osc_msg = 'Diff not possible'
|
||||||
|
raise
|
||||||
|
|
||||||
|
|
||||||
|
# decline
|
||||||
|
elif cmd == 'decline':
|
||||||
|
r = change_request_state(conf.config['apiurl'],
|
||||||
|
reqid, 'declined', opts.message or '')
|
||||||
|
print r
|
||||||
|
|
||||||
|
# accept
|
||||||
|
elif cmd == 'accept':
|
||||||
|
r = change_request_state(conf.config['apiurl'],
|
||||||
|
reqid, 'accepted', opts.message or '')
|
||||||
|
print r
|
||||||
|
# revoke
|
||||||
|
elif cmd == 'revoke':
|
||||||
|
r = change_request_state(conf.config['apiurl'],
|
||||||
reqid, 'revoked', opts.message or '')
|
reqid, 'revoked', opts.message or '')
|
||||||
print r
|
print r
|
||||||
|
|
||||||
@ -727,6 +973,7 @@ Please submit there instead, or use --nodevelproject to force direct submission.
|
|||||||
@cmdln.alias("createpac")
|
@cmdln.alias("createpac")
|
||||||
@cmdln.alias("edituser")
|
@cmdln.alias("edituser")
|
||||||
@cmdln.alias("usermeta")
|
@cmdln.alias("usermeta")
|
||||||
|
@cmdln.hide(1)
|
||||||
def do_editmeta(self, subcmd, opts, *args):
|
def do_editmeta(self, subcmd, opts, *args):
|
||||||
"""${cmd_name}:
|
"""${cmd_name}:
|
||||||
|
|
||||||
|
213
osc/core.py
213
osc/core.py
@ -1231,9 +1231,18 @@ class RequestState:
|
|||||||
self.when = when
|
self.when = when
|
||||||
self.comment = comment
|
self.comment = comment
|
||||||
|
|
||||||
|
class Action:
|
||||||
|
"""represents an action"""
|
||||||
|
def __init__(self, type, src_project, src_package, src_rev, dst_project, dst_package):
|
||||||
|
self.type = type
|
||||||
|
self.src_project = src_project
|
||||||
|
self.src_package = src_package
|
||||||
|
self.src_rev = src_rev
|
||||||
|
self.dst_project = dst_project
|
||||||
|
self.dst_package = dst_package
|
||||||
|
|
||||||
class SubmitReq:
|
class Request:
|
||||||
"""represent a submit request and holds its metadata
|
"""represent a request and holds its metadata
|
||||||
it has methods to read in metadata from xml,
|
it has methods to read in metadata from xml,
|
||||||
different views, ..."""
|
different views, ..."""
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
@ -1242,26 +1251,30 @@ class SubmitReq:
|
|||||||
self.who = None
|
self.who = None
|
||||||
self.when = None
|
self.when = None
|
||||||
self.last_author = None
|
self.last_author = None
|
||||||
self.src_project = None
|
|
||||||
self.src_package = None
|
|
||||||
self.src_rev = None
|
|
||||||
self.dst_project = None
|
|
||||||
self.dst_package = None
|
|
||||||
self.descr = None
|
self.descr = None
|
||||||
|
self.actions = []
|
||||||
self.statehistory = []
|
self.statehistory = []
|
||||||
|
|
||||||
def read(self, root):
|
def read(self, root):
|
||||||
self.reqid = int(root.get('id'))
|
self.reqid = int(root.get('id'))
|
||||||
|
actions = root.findall('action')
|
||||||
|
if len(actions) == 0:
|
||||||
|
actions = [ root.find('submit') ] # for old style requests
|
||||||
|
|
||||||
n = root.find('submit').find('source')
|
for action in actions:
|
||||||
self.src_project = n.get('project')
|
type = action.get('type', 'submit')
|
||||||
self.src_package = n.get('package')
|
try:
|
||||||
try: self.src_rev = n.get('rev')
|
n = action.find('source')
|
||||||
except: pass
|
src_prj = n.get('project')
|
||||||
|
src_pkg = n.get('package')
|
||||||
n = root.find('submit').find('target')
|
src_rev = n.get('rev', None)
|
||||||
self.dst_project = n.get('project')
|
n = action.find('target')
|
||||||
self.dst_package = n.get('package')
|
dst_prj = n.get('project')
|
||||||
|
dst_pkg = n.get('package')
|
||||||
|
self.add_action(type, src_prj, src_pkg, src_rev, dst_prj, dst_pkg)
|
||||||
|
except:
|
||||||
|
msg = 'invalid request format:\n%s' % ET.tostring(root)
|
||||||
|
raise oscerr.APIError(msg)
|
||||||
|
|
||||||
# read the state
|
# read the state
|
||||||
n = root.find('state')
|
n = root.find('state')
|
||||||
@ -1292,11 +1305,15 @@ class SubmitReq:
|
|||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
def add_action(self, type, src_prj, src_pkg, src_rev, dst_prj, dst_pkg):
|
||||||
|
self.actions.append(Action(type, src_prj, src_pkg, src_rev,
|
||||||
|
dst_prj, dst_pkg)
|
||||||
|
)
|
||||||
|
|
||||||
def list_view(self):
|
def list_view(self):
|
||||||
dst = "%s/%s" % (self.dst_project, self.dst_package)
|
dst = "%s/%s" % (self.actions[0].dst_project, self.actions[0].dst_package)
|
||||||
if self.src_package == self.dst_package:
|
if self.actions[0].src_package == self.actions[0].dst_package:
|
||||||
dst = self.dst_project
|
dst = self.actions[0].dst_project
|
||||||
|
|
||||||
desc = ""
|
desc = ""
|
||||||
if self.descr:
|
if self.descr:
|
||||||
@ -1305,15 +1322,16 @@ class SubmitReq:
|
|||||||
return '%6d %-7s %-12s %-50s -> %-20s %s' % \
|
return '%6d %-7s %-12s %-50s -> %-20s %s' % \
|
||||||
(self.reqid,
|
(self.reqid,
|
||||||
self.state.name, "(%s)" % self.state.who,
|
self.state.name, "(%s)" % self.state.who,
|
||||||
"%s/%s" % (self.src_project, self.src_package),
|
"%s/%s" % (self.actions[0].src_project, self.actions[0].src_package),
|
||||||
dst, desc)
|
dst, desc)
|
||||||
|
|
||||||
def __cmp__(self, other):
|
def __cmp__(self, other):
|
||||||
return cmp(self.reqid, other.reqid)
|
return cmp(self.reqid, other.reqid)
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
|
# XXX: only prints out the first action element
|
||||||
s = """\
|
s = """\
|
||||||
Request to submit (sri%d):
|
Request to %s (sri%s):
|
||||||
|
|
||||||
%s/%s -> %s/%s
|
%s/%s -> %s/%s
|
||||||
|
|
||||||
@ -1325,12 +1343,13 @@ Message:
|
|||||||
|
|
||||||
State: %-10s %s %s
|
State: %-10s %s %s
|
||||||
Comment: %s
|
Comment: %s
|
||||||
""" % (self.reqid,
|
""" % (self.actions[0].type,
|
||||||
self.src_project,
|
self.reqid,
|
||||||
self.src_package,
|
self.actions[0].src_project,
|
||||||
self.dst_project,
|
self.actions[0].src_package,
|
||||||
self.dst_package,
|
self.actions[0].dst_project,
|
||||||
self.src_rev or 'not given',
|
self.actions[0].dst_package,
|
||||||
|
self.actions[0].src_rev or 'not given',
|
||||||
self.descr,
|
self.descr,
|
||||||
self.state.name,
|
self.state.name,
|
||||||
self.state.when, self.state.who, self.state.comment)
|
self.state.when, self.state.who, self.state.comment)
|
||||||
@ -2022,21 +2041,68 @@ def edit_message(footer='', template=''):
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
def create_delete_request(apiurl, project, package, message):
|
||||||
|
|
||||||
|
import cgi
|
||||||
|
|
||||||
|
if package:
|
||||||
|
package = """package="%s" """ % (package)
|
||||||
|
else:
|
||||||
|
package = ""
|
||||||
|
|
||||||
|
xml = """\
|
||||||
|
<request>
|
||||||
|
<action type="delete">
|
||||||
|
<target project="%s" %s/>
|
||||||
|
</action>
|
||||||
|
<state name="new"/>
|
||||||
|
<description>%s</description>
|
||||||
|
</request>
|
||||||
|
""" % (project, package,
|
||||||
|
cgi.escape(message or ''))
|
||||||
|
|
||||||
|
u = makeurl(apiurl, ['request'], query='cmd=create')
|
||||||
|
f = http_POST(u, data=xml)
|
||||||
|
|
||||||
|
root = ET.parse(f).getroot()
|
||||||
|
return root.get('id')
|
||||||
|
|
||||||
|
|
||||||
|
def create_change_devel_request(apiurl,
|
||||||
|
devel_project, devel_package,
|
||||||
|
project, package,
|
||||||
|
message):
|
||||||
|
|
||||||
|
import cgi
|
||||||
|
xml = """\
|
||||||
|
<request>
|
||||||
|
<action type="change_devel">
|
||||||
|
<source project="%s" package="%s" />
|
||||||
|
<target project="%s" package="%s" />
|
||||||
|
</action>
|
||||||
|
<state name="new"/>
|
||||||
|
<description>%s</description>
|
||||||
|
</request>
|
||||||
|
""" % (devel_project,
|
||||||
|
devel_package,
|
||||||
|
project,
|
||||||
|
package,
|
||||||
|
cgi.escape(message or ''))
|
||||||
|
|
||||||
|
u = makeurl(apiurl, ['request'], query='cmd=create')
|
||||||
|
f = http_POST(u, data=xml)
|
||||||
|
|
||||||
|
root = ET.parse(f).getroot()
|
||||||
|
return root.get('id')
|
||||||
|
|
||||||
|
|
||||||
def create_submit_request(apiurl,
|
def create_submit_request(apiurl,
|
||||||
src_project, src_package,
|
src_project, src_package,
|
||||||
dst_project, dst_package,
|
dst_project, dst_package,
|
||||||
message, orev=None):
|
message, orev=None):
|
||||||
|
|
||||||
import cgi
|
import cgi
|
||||||
|
# XXX: keep the old template for now in order to work with old obs instances
|
||||||
r = SubmitReq()
|
|
||||||
r.src_project = src_project
|
|
||||||
r.src_package = src_package
|
|
||||||
r.src_rev = orev or show_upstream_rev(apiurl, src_project, src_package)
|
|
||||||
r.dst_project = dst_project
|
|
||||||
r.dst_package = dst_package
|
|
||||||
r.descr = cgi.escape(message or '')
|
|
||||||
|
|
||||||
xml = """\
|
xml = """\
|
||||||
<request type="submit">
|
<request type="submit">
|
||||||
<submit>
|
<submit>
|
||||||
@ -2046,12 +2112,12 @@ def create_submit_request(apiurl,
|
|||||||
<state name="new"/>
|
<state name="new"/>
|
||||||
<description>%s</description>
|
<description>%s</description>
|
||||||
</request>
|
</request>
|
||||||
""" % (r.src_project,
|
""" % (src_project,
|
||||||
r.src_package,
|
src_package,
|
||||||
r.src_rev,
|
orev or show_upstream_rev(apiurl, src_project, src_package),
|
||||||
r.dst_project,
|
dst_project,
|
||||||
r.dst_package,
|
dst_package,
|
||||||
r.descr)
|
cgi.escape(message or ''))
|
||||||
|
|
||||||
u = makeurl(apiurl, ['request'], query='cmd=create')
|
u = makeurl(apiurl, ['request'], query='cmd=create')
|
||||||
f = http_POST(u, data=xml)
|
f = http_POST(u, data=xml)
|
||||||
@ -2060,17 +2126,17 @@ def create_submit_request(apiurl,
|
|||||||
return root.get('id')
|
return root.get('id')
|
||||||
|
|
||||||
|
|
||||||
def get_submit_request(apiurl, reqid):
|
def get_request(apiurl, reqid):
|
||||||
u = makeurl(apiurl, ['request', reqid])
|
u = makeurl(apiurl, ['request', reqid])
|
||||||
f = http_GET(u)
|
f = http_GET(u)
|
||||||
root = ET.parse(f).getroot()
|
root = ET.parse(f).getroot()
|
||||||
|
|
||||||
r = SubmitReq()
|
r = Request()
|
||||||
r.read(root)
|
r.read(root)
|
||||||
return r
|
return r
|
||||||
|
|
||||||
|
|
||||||
def change_submit_request_state(apiurl, reqid, newstate, message=''):
|
def change_request_state(apiurl, reqid, newstate, message=''):
|
||||||
u = makeurl(apiurl,
|
u = makeurl(apiurl,
|
||||||
['request', reqid],
|
['request', reqid],
|
||||||
query={'cmd': 'changestate', 'newstate': newstate})
|
query={'cmd': 'changestate', 'newstate': newstate})
|
||||||
@ -2078,40 +2144,43 @@ def change_submit_request_state(apiurl, reqid, newstate, message=''):
|
|||||||
return f.read()
|
return f.read()
|
||||||
|
|
||||||
|
|
||||||
def get_submit_request_list(apiurl, project, package, req_who='', req_state=('new',) ):
|
def get_request_list(apiurl, project, package, req_who='', req_state=('new',) ):
|
||||||
match = ''
|
|
||||||
if project:
|
|
||||||
if len(match): match += '%20and%20'
|
|
||||||
match += 'submit/target/@project=\'%s\'' % quote_plus(project)
|
|
||||||
if package:
|
|
||||||
if len(match): match += '%20and%20'
|
|
||||||
match += 'submit/target/@package=\'%s\'' % quote_plus(package)
|
|
||||||
for state in req_state:
|
|
||||||
if len(match): match += '%20and%20'
|
|
||||||
match += 'state/@name=\'%s\'' % quote_plus(state)
|
|
||||||
if req_who:
|
|
||||||
if len(match): match += '%20and%20'
|
|
||||||
match += 'state/@who=\'%s\'' % quote_plus(req_who)
|
|
||||||
|
|
||||||
u = makeurl(apiurl, ['search', 'request'], ['match=%s' % match])
|
|
||||||
f = http_GET(u)
|
|
||||||
collection = ET.parse(f).getroot()
|
|
||||||
|
|
||||||
requests = []
|
requests = []
|
||||||
for root in collection.findall('request'):
|
# XXX: we cannot use the '|' in the xpath expression because it is not supported
|
||||||
r = SubmitReq()
|
# in the backend
|
||||||
r.read(root)
|
for what in ['action', 'submit']:
|
||||||
if (r.state.name in req_state) or not len(req_state):
|
match = ''
|
||||||
requests.append(r)
|
if project:
|
||||||
|
if len(match): match += '%20and%20'
|
||||||
|
match += '%s/target/@project=\'%s\'' % (what, quote_plus(project))
|
||||||
|
if package:
|
||||||
|
if len(match): match += '%20and%20'
|
||||||
|
match += '%s/target/@package=\'%s\'' % (what, quote_plus(package))
|
||||||
|
for state in req_state:
|
||||||
|
if len(match): match += '%20and%20'
|
||||||
|
match += 'state/@name=\'%s\'' % quote_plus(state)
|
||||||
|
if req_who:
|
||||||
|
if len(match): match += '%20and%20'
|
||||||
|
match += 'state/@who=\'%s\'' % quote_plus(req_who)
|
||||||
|
|
||||||
|
u = makeurl(apiurl, ['search', 'request'], ['match=%s' % match])
|
||||||
|
f = http_GET(u)
|
||||||
|
collection = ET.parse(f).getroot()
|
||||||
|
|
||||||
|
for root in collection.findall('request'):
|
||||||
|
r = Request()
|
||||||
|
r.read(root)
|
||||||
|
if (r.state.name in req_state) or not len(req_state):
|
||||||
|
requests.append(r)
|
||||||
|
|
||||||
return requests
|
return requests
|
||||||
|
|
||||||
|
|
||||||
def get_submit_request_log(apiurl, reqid):
|
def get_request_log(apiurl, reqid):
|
||||||
r = get_submit_request(conf.config['apiurl'], reqid)
|
r = get_request(conf.config['apiurl'], reqid)
|
||||||
data = []
|
data = []
|
||||||
frmt = '-' * 76 + '\n%s | %s | %s\n\n%s'
|
frmt = '-' * 76 + '\n%s | %s | %s\n\n%s'
|
||||||
# the description of the submitrequest is used for the initial log entry
|
# the description of the request is used for the initial log entry
|
||||||
# otherwise its comment attribute would contain None
|
# otherwise its comment attribute would contain None
|
||||||
if len(r.statehistory) >= 1:
|
if len(r.statehistory) >= 1:
|
||||||
r.statehistory[-1].comment = r.descr
|
r.statehistory[-1].comment = r.descr
|
||||||
|
Loading…
Reference in New Issue
Block a user