Hello, I have modified osc/commandline.py to add client support for this feature, below is the detail
osc help creq createrequest (creq): create multiple requests with a single command
usage:
osc creq [OPTIONS] [ -a submit SOURCEPRJ SOURCEPKG DESTPRJ [DESTPKG] -a delete PROJECT [PACKAGE] -a change_devel PROJECT PACKAGE DEVEL_PROJECT [DEVEL_PACKAGE] ]
Option -m works for all types of request, the rest work only for submit.
example:
osc creq -a submit -a delete home:brookhong:branches:openSUSE:Tools -a change_devel openSUSE:Tools osc home:brookhong:branches:openSUSE:Tools -m ok
This will submit all modified packages under current directory, delete project home:brookhong:branches:openSUSE:Tools and change the devel project to home:brookhong:branches:openSUSE:Tools for package osc in project openSUSE:Tools.
Options:
-h, --help show this help message and exit
--yes proceed without asking.
-d, --diff show diff only instead of creating the actual request
--no-update never touch source package on accept (will break
source links)
--no-cleanup never remove source package on accept, but update its
content
--cleanup remove package if submission gets accepted (default
for home:<id>:branch projects)
--nodevelproject do not follow a defined devel project (primary project
where a package is developed)
-s SUPERSEDE, --supersede=SUPERSEDE
Superseding another request by this one
-r REV, --revision=REV
for "create", specify a certain source revision ID
(the md5 sum)
-m TEXT, --message=TEXT
specify message TEXT
-a, --action specify action type of a request, can be :
submit/delete/change_devel
With command "osc creq -a submit -a delete home:brookhong:branches:hello_test -a change_devel hello_test hello_people home:brookhong:branches:hello_test -m ok", I can create a request successfully which consists of three actions as
<request id="39">
<action type="submit">
<source project="home:brookhong:branches:hello_test" package="hello_people" rev="2" />
<target project="hello_test" package="hello_people" />
<options>
<sourceupdate>noupdate</sourceupdate>
</options>
</action>
<action type="submit">
<source project="home:brookhong:branches:hello_test" package="hello_world" rev="3" />
<target project="hello_test" package="hello_world" />
<options>
<sourceupdate>noupdate</sourceupdate>
</options>
</action>
<action type="delete">
<target project="home:brookhong:branches:hello_test" />
</action>
<action type="change_devel">
<source project="home:brookhong:branches:hello_test" package="hello_people" />
<target project="hello_test" package="hello_people" />
</action>
<state name="new" who="brookhong" when="2010-05-19T11:05:02" />
<description>ok</description>
</request>
Here are the code patch, I tried to push into http://gitorious.org/opensuse/osc, seems I have no permission.
diff --git a/osc/commandline.py b/osc/commandline.py
old mode 100644
new mode 100755
index 98d5844..59a3ee5
--- a/osc/commandline.py
+++ b/osc/commandline.py
@@ -942,6 +942,322 @@ Please submit there instead, or use --nodevelproject to force direct submission.
print 'created request id', result
+ def actionparser(option, opt_str, value, parser):
+ value = []
+ if not hasattr(parser.values, 'actiondata'):
+ setattr(parser.values, 'actiondata', [])
+ if parser.values.actions == None:
+ parser.values.actions = []
+
+ rargs = parser.rargs
+ while rargs:
+ arg = rargs[0]
+ if ((arg[:2] == "--" and len(arg) > 2) or
+ (arg[:1] == "-" and len(arg) > 1 and arg[1] != "-")):
+ break
+ else:
+ value.append(arg)
+ del rargs[0]
+
+ parser.values.actions.append(value[0])
+ del value[0]
+ parser.values.actiondata.append(value)
+
+ def _submit_request(self, args, opts, options_block):
+ actionxml=""
+ apiurl = self.get_api_url()
+ if len(args) == 0 and is_project_dir(os.getcwd()):
+ import cgi
+ # submit requests for multiple packages are currently handled via multiple requests
+ # They could be also one request with multiple actions, but that avoids to accepts parts of it.
+ project = store_read_project(os.curdir)
+ apiurl = store_read_apiurl(os.curdir)
+
+ pi = []
+ pac = []
+ targetprojects = []
+ rdiffmsg = []
+ # loop via all packages for checking their state
+ for p in meta_get_packagelist(apiurl, project):
+ if p.startswith("_patchinfo:"):
+ pi.append(p)
+ else:
+ # get _link info from server, that knows about the local state ...
+ u = makeurl(apiurl, ['source', project, p])
+ f = http_GET(u)
+ root = ET.parse(f).getroot()
+ linkinfo = root.find('linkinfo')
+ if linkinfo == None:
+ print "Package ", p, " is not a source link."
+ sys.exit("This is currently not supported.")
+ if linkinfo.get('error'):
+ print "Package ", p, " is a broken source link."
+ sys.exit("Please fix this first")
+ t = linkinfo.get('project')
+ if t:
+ rdiff = ''
+ try:
+ rdiff = server_diff(apiurl, t, p, opts.revision, project, p, None, True)
+ except:
+ rdiff = ''
+
+ if rdiff != '':
+ targetprojects.append(t)
+ pac.append(p)
+ rdiffmsg.append("old: %s/%s\nnew: %s/%s\n%s" %(t, p, project, p,rdiff))
+ else:
+ print "Skipping package ", p, " since it has no difference with the target package."
+ else:
+ print "Skipping package ", p, " since it is a source link pointing inside the project."
+ if opts.diff:
+ print ''.join(rdiffmsg)
+ sys.exit(0)
+
+ if not opts.yes:
+ if pi:
+ print "Submitting patchinfo ", ', '.join(pi), " to ", ', '.join(targetprojects)
+ print "\nEverything fine? Can we create the requests ? [y/n]"
+ if sys.stdin.read(1) != "y":
+ sys.exit("Aborted...")
+
+ # loop via all packages to do the action
+ for p in pac:
+ s = """<action type="submit"> <source project="%s" package="%s" rev="%s"/> <target project="%s" package="%s"/> %s </action>""" % \
+ (project, p, opts.revision or show_upstream_rev(apiurl, project, p), t, p, options_block)
+ actionxml += s
+
+ # create submit requests for all found patchinfos
+ for p in pi:
+ for t in targetprojects:
+ s = """<action type="submit"> <source project="%s" package="%s" /> <target project="%s" package="%s" /> %s </action>""" % \
+ (project, p, t, p, options_block)
+ actionxml += s
+
+ return actionxml
+
+ elif len(args) <= 2:
+ # try using the working copy at hand
+ p = findpacs(os.curdir)[0]
+ src_project = p.prjname
+ src_package = p.name
+ apiurl = p.apiurl
+ if len(args) == 0 and p.islink():
+ dst_project = p.linkinfo.project
+ dst_package = p.linkinfo.package
+ 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'))
+
+ 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 """\
+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)
+ if not opts.diff:
+ sys.exit(1)
+
+ rdiff = None
+ if opts.diff:
+ try:
+ rdiff = 'old: %s/%s\nnew: %s/%s' %(dst_project, dst_package, src_project, src_package)
+ rdiff += server_diff(apiurl,
+ dst_project, dst_package, opts.revision,
+ src_project, src_package, None, True)
+ except:
+ rdiff = ''
+ if opts.diff:
+ print rdiff
+ else:
+ reqs = get_request_list(apiurl, dst_project, dst_package, req_type='submit')
+ 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('Supersede the old requests? (y/n/c) ')
+ if repl.lower() == 'c':
+ print >>sys.stderr, 'Aborting'
+ sys.exit(1)
+
+ actionxml = """<action type="submit"> <source project="%s" package="%s" rev="%s"/> <target project="%s" package="%s"/> %s </action>""" % \
+ (src_project, src_package, opts.revision or show_upstream_rev(apiurl, src_project, src_package), dst_project, dst_package, options_block+ if repl.lower() == 'y':
+ for req in myreqs:
+ change_request_state(apiurl, str(req.reqid), 'superseded',
+ 'superseded by %s' % result, result)
+
+ if opts.supersede:
+ r = change_request_state(conf.config['apiurl'],
+ opts.supersede, 'superseded', '', result)
+
+ #print 'created request id', result
+ return actionxml
+
+ def _delete_request(self, args, opts):
+ if len(args) < 1:
+ raise oscerr.WrongArgs('Please specify at least a project.')
+ if len(args) > 2:
+ raise oscerr.WrongArgs('Too many arguments.')
+
+ apiurl = self.get_api_url()
+
+ package = ""
+ if len(args) > 1:
+ package = """package="%s" """ % (args[1])
+ actionxml = """<action type="delete">