diff --git a/.travis.yml b/.travis.yml
index e8d8e4af..5de3ac99 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,4 +1,7 @@
language: python
python:
- "2.7"
+before_install:
+ - sudo apt-get update -qq
+ - sudo apt-get install -qq diffstat
script: cd tests; python suite.py
diff --git a/osc/commandline.py b/osc/commandline.py
index e896c515..51103e8f 100644
--- a/osc/commandline.py
+++ b/osc/commandline.py
@@ -3511,6 +3511,158 @@ Please submit there instead, or use --nodevelproject to force direct submission.
run_pager(rdiff)
+ def _get_branch_parent(self, prj):
+ m = re.match('^home:[^:]+:branches:(.+)', prj)
+ # OBS_Maintained is a special case
+ if m and prj.find(':branches:OBS_Maintained:') == -1:
+ return m.group(1)
+ return None
+
+ def _prdiff_skip_package(self, opts, pkg):
+ if opts.exclude and re.search(opts.exclude, pkg):
+ return True
+
+ if opts.include and not re.search(opts.include, pkg):
+ return True
+
+ return False
+
+ def _prdiff_output_diff(self, opts, rdiff):
+ if opts.diffstat:
+ print
+ p = subprocess.Popen("diffstat",
+ stdin=subprocess.PIPE,
+ stdout=subprocess.PIPE,
+ close_fds=True)
+ p.stdin.write(rdiff)
+ p.stdin.close()
+ diffstat = "".join(p.stdout.readlines())
+ print diffstat
+ elif opts.unified:
+ print
+ print rdiff
+ #run_pager(rdiff)
+
+ def _prdiff_output_matching_requests(self, opts, requests,
+ srcprj, pkg):
+ """
+ Search through the given list of requests and output any
+ submitrequests which target pkg and originate from srcprj.
+ """
+ for req in requests:
+ for action in req.get_actions('submit'):
+ if action.src_project != srcprj:
+ continue
+
+ if action.tgt_package != pkg:
+ continue
+
+ print
+ print req.list_view()
+ break
+
+ @cmdln.alias('projectdiff')
+ @cmdln.alias('projdiff')
+ @cmdln.option('-r', '--requests', action='store_true',
+ help='show open requests for any packages with differences')
+ @cmdln.option('-e', '--exclude', metavar='REGEXP', dest='exclude',
+ help='skip packages matching REGEXP')
+ @cmdln.option('-i', '--include', metavar='REGEXP', dest='include',
+ help='only consider packages matching REGEXP')
+ @cmdln.option('-n', '--show-not-in-old', action='store_true',
+ help='show packages only in the new project')
+ @cmdln.option('-o', '--show-not-in-new', action='store_true',
+ help='show packages only in the old project')
+ @cmdln.option('-u', '--unified', action='store_true',
+ help='show full unified diffs of differences')
+ @cmdln.option('-d', '--diffstat', action='store_true',
+ help='show diffstat of differences')
+
+ def do_prdiff(self, subcmd, opts, *args):
+ """${cmd_name}: Server-side diff of two projects
+
+ Compares two projects and either summarises or outputs the
+ differences in full. In the second form, a project is compared
+ with one of its branches inside a home:$USER project (the branch
+ is treated as NEWPRJ). The home branch is optional if the current
+ working directory is a checked out copy of it.
+
+ Usage:
+ osc prdiff [OPTIONS] OLDPRJ NEWPRJ
+ osc prdiff [OPTIONS] [home:$USER:branch:$PRJ]
+
+ ${cmd_option_list}
+ """
+
+ if len(args) > 2:
+ raise oscerr.WrongArgs('Too many arguments.')
+
+ if len(args) == 0:
+ if is_project_dir(os.curdir):
+ newprj = Project('.', getPackageList=False).name
+ oldprj = self._get_branch_parent(newprj)
+ if oldprj is None:
+ raise oscerr.WrongArgs('Current directory is not a valid home branch.')
+ else:
+ raise oscerr.WrongArgs('Current directory is not a project.')
+ elif len(args) == 1:
+ newprj = args[0]
+ oldprj = self._get_branch_parent(newprj)
+ if oldprj is None:
+ raise oscerr.WrongArgs('Single-argument form must be for a home branch.')
+ elif len(args) == 2:
+ oldprj, newprj = args
+ else:
+ raise RuntimeError('BUG in argument parsing, please report.\n'
+ 'args: ' + repr(args))
+
+ if opts.diffstat and opts.unified:
+ print >>sys.stderr, 'error - cannot specify both --diffstat and --unified'
+ sys.exit(1)
+
+ apiurl = self.get_api_url()
+
+ old_packages = meta_get_packagelist(apiurl, oldprj)
+ new_packages = meta_get_packagelist(apiurl, newprj)
+
+ if opts.requests:
+ requests = get_request_list(apiurl, project=oldprj,
+ req_state=('new', 'review'))
+
+ for pkg in old_packages:
+ if self._prdiff_skip_package(opts, pkg):
+ continue
+
+ if pkg not in new_packages:
+ if opts.show_not_in_new:
+ print "old only: %s" % pkg
+ continue
+
+ rdiff = server_diff_noex(
+ apiurl,
+ oldprj, pkg, None,
+ newprj, pkg, None,
+ unified=True, missingok=False, meta=False, expand=True
+ )
+
+ if rdiff:
+ print "differs: %s" % pkg
+ self._prdiff_output_diff(opts, rdiff)
+
+ if opts.requests:
+ self._prdiff_output_matching_requests(opts, requests,
+ newprj, pkg)
+ else:
+ print "identical: %s" % pkg
+
+ for pkg in new_packages:
+ if self._prdiff_skip_package(opts, pkg):
+ continue
+
+ if pkg not in old_packages:
+ if opts.show_not_in_old:
+ print "new only: %s" % pkg
+
@cmdln.hide(1)
@cmdln.alias('in')
def do_install(self, subcmd, opts, *args):
diff --git a/tests/common.py b/tests/common.py
index f56541bf..fd1d7dce 100644
--- a/tests/common.py
+++ b/tests/common.py
@@ -106,8 +106,11 @@ def addExpectedRequest(method, url, **kwargs):
class OscTestCase(unittest.TestCase):
def setUp(self, copytree=True):
- osc.core.conf.get_config(override_conffile=os.path.join(self._get_fixtures_dir(), 'oscrc'),
+ oscrc = os.path.join(self._get_fixtures_dir(), 'oscrc')
+ osc.core.conf.get_config(override_conffile=oscrc,
override_no_keyring=True, override_no_gnome_keyring=True)
+ os.environ['OSC_CONFIG'] = oscrc
+
self.tmpdir = tempfile.mkdtemp(prefix='osc_test')
if copytree:
shutil.copytree(os.path.join(self._get_fixtures_dir(), 'osctest'), os.path.join(self.tmpdir, 'osctest'))
diff --git a/tests/prdiff_fixtures/common-two-diff b/tests/prdiff_fixtures/common-two-diff
new file mode 100644
index 00000000..a06ddea3
--- /dev/null
+++ b/tests/prdiff_fixtures/common-two-diff
@@ -0,0 +1,10 @@
+Index: common-two
+===================================================================
+--- common-two 2013-01-18 19:18:38.225983117 +0000
++++ common-two 2013-01-18 19:19:27.882082325 +0000
+@@ -1,4 +1,5 @@
+ line one
+ line two
+ line three
++an extra line
+ last line
diff --git a/tests/prdiff_fixtures/home:user:branches:some:project/.osc/_apiurl b/tests/prdiff_fixtures/home:user:branches:some:project/.osc/_apiurl
new file mode 100644
index 00000000..0afeace7
--- /dev/null
+++ b/tests/prdiff_fixtures/home:user:branches:some:project/.osc/_apiurl
@@ -0,0 +1 @@
+http://localhost
diff --git a/tests/prdiff_fixtures/home:user:branches:some:project/.osc/_packages b/tests/prdiff_fixtures/home:user:branches:some:project/.osc/_packages
new file mode 100644
index 00000000..e1711ef4
--- /dev/null
+++ b/tests/prdiff_fixtures/home:user:branches:some:project/.osc/_packages
@@ -0,0 +1,4 @@
+
+
+
+
\ No newline at end of file
diff --git a/tests/prdiff_fixtures/home:user:branches:some:project/.osc/_project b/tests/prdiff_fixtures/home:user:branches:some:project/.osc/_project
new file mode 100644
index 00000000..b83a395a
--- /dev/null
+++ b/tests/prdiff_fixtures/home:user:branches:some:project/.osc/_project
@@ -0,0 +1 @@
+home:user:branches:some:project
diff --git a/tests/prdiff_fixtures/home:user:branches:some:project/common-two b/tests/prdiff_fixtures/home:user:branches:some:project/common-two
new file mode 100644
index 00000000..ade1e2d8
--- /dev/null
+++ b/tests/prdiff_fixtures/home:user:branches:some:project/common-two
@@ -0,0 +1,5 @@
+line one
+line two
+line three
+an extra line
+last line
\ No newline at end of file
diff --git a/tests/prdiff_fixtures/home:user:branches:some:project/directory b/tests/prdiff_fixtures/home:user:branches:some:project/directory
new file mode 100644
index 00000000..f29d4543
--- /dev/null
+++ b/tests/prdiff_fixtures/home:user:branches:some:project/directory
@@ -0,0 +1,6 @@
+
+
+
+
+
+
diff --git a/tests/prdiff_fixtures/new:prj/common-two b/tests/prdiff_fixtures/new:prj/common-two
new file mode 100644
index 00000000..ade1e2d8
--- /dev/null
+++ b/tests/prdiff_fixtures/new:prj/common-two
@@ -0,0 +1,5 @@
+line one
+line two
+line three
+an extra line
+last line
\ No newline at end of file
diff --git a/tests/prdiff_fixtures/new:prj/directory b/tests/prdiff_fixtures/new:prj/directory
new file mode 100644
index 00000000..f29d4543
--- /dev/null
+++ b/tests/prdiff_fixtures/new:prj/directory
@@ -0,0 +1,6 @@
+
+
+
+
+
+
diff --git a/tests/prdiff_fixtures/no-requests b/tests/prdiff_fixtures/no-requests
new file mode 100644
index 00000000..aef429f1
--- /dev/null
+++ b/tests/prdiff_fixtures/no-requests
@@ -0,0 +1,2 @@
+
+
diff --git a/tests/prdiff_fixtures/old:prj/common-two b/tests/prdiff_fixtures/old:prj/common-two
new file mode 100644
index 00000000..48365a30
--- /dev/null
+++ b/tests/prdiff_fixtures/old:prj/common-two
@@ -0,0 +1,4 @@
+line one
+line two
+line three
+last line
\ No newline at end of file
diff --git a/tests/prdiff_fixtures/old:prj/directory b/tests/prdiff_fixtures/old:prj/directory
new file mode 100644
index 00000000..a9db4b70
--- /dev/null
+++ b/tests/prdiff_fixtures/old:prj/directory
@@ -0,0 +1,6 @@
+
+
+
+
+
+
diff --git a/tests/prdiff_fixtures/oscrc b/tests/prdiff_fixtures/oscrc
new file mode 100644
index 00000000..a30e040c
--- /dev/null
+++ b/tests/prdiff_fixtures/oscrc
@@ -0,0 +1,103 @@
+[general]
+# URL to access API server, e.g. https://api.opensuse.org
+# you also need a section [https://api.opensuse.org] with the credentials
+apiurl = http://localhost
+# Downloaded packages are cached here. Must be writable by you.
+#packagecachedir = /var/tmp/osbuild-packagecache
+# Wrapper to call build as root (sudo, su -, ...)
+#su-wrapper = su -c
+# rootdir to setup the chroot environment
+# can contain %(repo)s, %(arch)s, %(project)s and %(package)s for replacement, e.g.
+# /srv/oscbuild/%(repo)s-%(arch)s or
+# /srv/oscbuild/%(repo)s-%(arch)s-%(project)s-%(package)s
+#build-root = /var/tmp/build-root
+# compile with N jobs (default: "getconf _NPROCESSORS_ONLN")
+#build-jobs = N
+# build-type to use - values can be (depending on the capabilities of the 'build' script)
+# empty - chroot build
+# kvm - kvm VM build (needs build-device, build-swap, build-memory)
+# xen - xen VM build (needs build-device, build-swap, build-memory)
+# experimental:
+# qemu - qemu VM build
+# lxc - lxc build
+#build-type =
+# build-device is the disk-image file to use as root for VM builds
+# e.g. /var/tmp/FILE.root
+#build-device = /var/tmp/FILE.root
+# build-swap is the disk-image to use as swap for VM builds
+# e.g. /var/tmp/FILE.swap
+#build-swap = /var/tmp/FILE.swap
+# build-memory is the amount of memory used in the VM
+# value in MB - e.g. 512
+#build-memory = 512
+# build-vmdisk-rootsize is the size of the disk-image used as root in a VM build
+# values in MB - e.g. 4096
+#build-vmdisk-rootsize = 4096
+# build-vmdisk-swapsize is the size of the disk-image used as swap in a VM build
+# values in MB - e.g. 1024
+#build-vmdisk-swapsize = 1024
+# Numeric uid:gid to assign to the "abuild" user in the build-root
+# or "caller" to use the current users uid:gid
+# This is convenient when sharing the buildroot with ordinary userids
+# on the host.
+# This should not be 0
+# build-uid =
+# extra packages to install when building packages locally (osc build)
+# this corresponds to osc build's -x option and can be overridden with that
+# -x '' can also be given on the command line to override this setting, or
+# you can have an empty setting here.
+#extra-pkgs = vim gdb strace
+# build platform is used if the platform argument is omitted to osc build
+#build_repository = openSUSE_Factory
+# default project for getpac or bco
+#getpac_default_project = openSUSE:Factory
+# alternate filesystem layout: have multiple subdirs, where colons were.
+#checkout_no_colon = 0
+# local files to ignore with status, addremove, ....
+#exclude_glob = .osc CVS .svn .* _linkerror *~ #*# *.orig *.bak *.changes.*
+# keep passwords in plaintext. If you see this comment, your osc
+# already uses the encrypted password, and only keeps them in plain text
+# for backwards compatibility. Default will change to 0 in future releases.
+# You can remove the plaintext password without harm, if you do not need
+# backwards compatibility.
+#plaintext_passwd = 1
+# limit the age of requests shown with 'osc req list'.
+# this is a default only, can be overridden by 'osc req list -D NNN'
+# Use 0 for unlimted.
+#request_list_days = 0
+# show info useful for debugging
+#debug = 1
+# show HTTP traffic useful for debugging
+#http_debug = 1
+# Skip signature verification of packages used for build.
+#no_verify = 1
+# jump into the debugger in case of errors
+#post_mortem = 1
+# print call traces in case of errors
+#traceback = 1
+# use KDE/Gnome/MacOS/Windows keyring for credentials if available
+#use_keyring = 1
+# check for unversioned/removed files before commit
+#check_filelist = 1
+# check for pending requests after executing an action (e.g. checkout, update, commit)
+#check_for_request_on_action = 0
+# what to do with the source package if the submitrequest has been accepted. If
+# nothing is specified the API default is used
+#submitrequest_on_accept_action = cleanup|update|noupdate
+#review requests interactively (default: off)
+#request_show_review = 1
+# Directory with executables to validate sources, esp before committing
+#source_validator_directory = /usr/lib/osc/source_validators
+
+[http://localhost]
+user=Admin
+pass=opensuse
+# set aliases for this apiurl
+# aliases = foo, bar
+# email used in .changes, unless the one from osc meta prj will be used
+# email =
+# additional headers to pass to a request, e.g. for special authentication
+#http_headers = Host: foofoobar,
+# User: mumblegack
+# Force using of keyring for this API
+#keyring = 1
diff --git a/tests/prdiff_fixtures/osctest/.osc/_apiurl b/tests/prdiff_fixtures/osctest/.osc/_apiurl
new file mode 100644
index 00000000..0afeace7
--- /dev/null
+++ b/tests/prdiff_fixtures/osctest/.osc/_apiurl
@@ -0,0 +1 @@
+http://localhost
diff --git a/tests/prdiff_fixtures/osctest/.osc/_packages b/tests/prdiff_fixtures/osctest/.osc/_packages
new file mode 100644
index 00000000..e1711ef4
--- /dev/null
+++ b/tests/prdiff_fixtures/osctest/.osc/_packages
@@ -0,0 +1,4 @@
+
+
+
+
\ No newline at end of file
diff --git a/tests/prdiff_fixtures/osctest/.osc/_project b/tests/prdiff_fixtures/osctest/.osc/_project
new file mode 100644
index 00000000..b83a395a
--- /dev/null
+++ b/tests/prdiff_fixtures/osctest/.osc/_project
@@ -0,0 +1 @@
+home:user:branches:some:project
diff --git a/tests/prdiff_fixtures/osctest/common-one/.osc/_apiurl b/tests/prdiff_fixtures/osctest/common-one/.osc/_apiurl
new file mode 100644
index 00000000..0afeace7
--- /dev/null
+++ b/tests/prdiff_fixtures/osctest/common-one/.osc/_apiurl
@@ -0,0 +1 @@
+http://localhost
diff --git a/tests/prdiff_fixtures/osctest/common-one/.osc/_files b/tests/prdiff_fixtures/osctest/common-one/.osc/_files
new file mode 100644
index 00000000..4b6dcca0
--- /dev/null
+++ b/tests/prdiff_fixtures/osctest/common-one/.osc/_files
@@ -0,0 +1,4 @@
+
+
+
+
diff --git a/tests/prdiff_fixtures/osctest/common-one/.osc/_meta b/tests/prdiff_fixtures/osctest/common-one/.osc/_meta
new file mode 100644
index 00000000..38045198
--- /dev/null
+++ b/tests/prdiff_fixtures/osctest/common-one/.osc/_meta
@@ -0,0 +1,10 @@
+
+ blah
+ foo
+
+
+
+
+
+
+
diff --git a/tests/prdiff_fixtures/osctest/common-one/.osc/_osclib_version b/tests/prdiff_fixtures/osctest/common-one/.osc/_osclib_version
new file mode 100644
index 00000000..d3827e75
--- /dev/null
+++ b/tests/prdiff_fixtures/osctest/common-one/.osc/_osclib_version
@@ -0,0 +1 @@
+1.0
diff --git a/tests/prdiff_fixtures/osctest/common-one/.osc/_package b/tests/prdiff_fixtures/osctest/common-one/.osc/_package
new file mode 100644
index 00000000..089880f8
--- /dev/null
+++ b/tests/prdiff_fixtures/osctest/common-one/.osc/_package
@@ -0,0 +1 @@
+common-one
\ No newline at end of file
diff --git a/tests/prdiff_fixtures/osctest/common-one/.osc/_project b/tests/prdiff_fixtures/osctest/common-one/.osc/_project
new file mode 100644
index 00000000..b83a395a
--- /dev/null
+++ b/tests/prdiff_fixtures/osctest/common-one/.osc/_project
@@ -0,0 +1 @@
+home:user:branches:some:project
diff --git a/tests/prdiff_fixtures/osctest/common-one/.osc/common-one.spec b/tests/prdiff_fixtures/osctest/common-one/.osc/common-one.spec
new file mode 100644
index 00000000..99bed787
--- /dev/null
+++ b/tests/prdiff_fixtures/osctest/common-one/.osc/common-one.spec
@@ -0,0 +1 @@
+contents are irrelevant
diff --git a/tests/prdiff_fixtures/osctest/common-one/common-one.spec b/tests/prdiff_fixtures/osctest/common-one/common-one.spec
new file mode 100644
index 00000000..99bed787
--- /dev/null
+++ b/tests/prdiff_fixtures/osctest/common-one/common-one.spec
@@ -0,0 +1 @@
+contents are irrelevant
diff --git a/tests/prdiff_fixtures/osctest/common-two/.osc/_apiurl b/tests/prdiff_fixtures/osctest/common-two/.osc/_apiurl
new file mode 100644
index 00000000..0afeace7
--- /dev/null
+++ b/tests/prdiff_fixtures/osctest/common-two/.osc/_apiurl
@@ -0,0 +1 @@
+http://localhost
diff --git a/tests/prdiff_fixtures/osctest/common-two/.osc/_files b/tests/prdiff_fixtures/osctest/common-two/.osc/_files
new file mode 100644
index 00000000..63b65f21
--- /dev/null
+++ b/tests/prdiff_fixtures/osctest/common-two/.osc/_files
@@ -0,0 +1,4 @@
+
+
+
+
diff --git a/tests/prdiff_fixtures/osctest/common-two/.osc/_meta b/tests/prdiff_fixtures/osctest/common-two/.osc/_meta
new file mode 100644
index 00000000..3d41ffd3
--- /dev/null
+++ b/tests/prdiff_fixtures/osctest/common-two/.osc/_meta
@@ -0,0 +1,10 @@
+
+ blah
+ foo
+
+
+
+
+
+
+
diff --git a/tests/prdiff_fixtures/osctest/common-two/.osc/_osclib_version b/tests/prdiff_fixtures/osctest/common-two/.osc/_osclib_version
new file mode 100644
index 00000000..d3827e75
--- /dev/null
+++ b/tests/prdiff_fixtures/osctest/common-two/.osc/_osclib_version
@@ -0,0 +1 @@
+1.0
diff --git a/tests/prdiff_fixtures/osctest/common-two/.osc/_package b/tests/prdiff_fixtures/osctest/common-two/.osc/_package
new file mode 100644
index 00000000..2ff38288
--- /dev/null
+++ b/tests/prdiff_fixtures/osctest/common-two/.osc/_package
@@ -0,0 +1 @@
+common-two
\ No newline at end of file
diff --git a/tests/prdiff_fixtures/osctest/common-two/.osc/_project b/tests/prdiff_fixtures/osctest/common-two/.osc/_project
new file mode 100644
index 00000000..b83a395a
--- /dev/null
+++ b/tests/prdiff_fixtures/osctest/common-two/.osc/_project
@@ -0,0 +1 @@
+home:user:branches:some:project
diff --git a/tests/prdiff_fixtures/osctest/common-two/.osc/common-two.spec b/tests/prdiff_fixtures/osctest/common-two/.osc/common-two.spec
new file mode 100644
index 00000000..99bed787
--- /dev/null
+++ b/tests/prdiff_fixtures/osctest/common-two/.osc/common-two.spec
@@ -0,0 +1 @@
+contents are irrelevant
diff --git a/tests/prdiff_fixtures/osctest/common-two/common-two.spec b/tests/prdiff_fixtures/osctest/common-two/common-two.spec
new file mode 100644
index 00000000..99bed787
--- /dev/null
+++ b/tests/prdiff_fixtures/osctest/common-two/common-two.spec
@@ -0,0 +1 @@
+contents are irrelevant
diff --git a/tests/prdiff_fixtures/request b/tests/prdiff_fixtures/request
new file mode 100644
index 00000000..2355cbbe
--- /dev/null
+++ b/tests/prdiff_fixtures/request
@@ -0,0 +1,16 @@
+
+
+
+
+
+
+ update
+
+
+
+
+
+ - Fix it to work
+- Improve support for something
+
+
diff --git a/tests/prdiff_fixtures/some:project/.osc/_apiurl b/tests/prdiff_fixtures/some:project/.osc/_apiurl
new file mode 100644
index 00000000..0afeace7
--- /dev/null
+++ b/tests/prdiff_fixtures/some:project/.osc/_apiurl
@@ -0,0 +1 @@
+http://localhost
diff --git a/tests/prdiff_fixtures/some:project/.osc/_packages b/tests/prdiff_fixtures/some:project/.osc/_packages
new file mode 100644
index 00000000..c4c8b110
--- /dev/null
+++ b/tests/prdiff_fixtures/some:project/.osc/_packages
@@ -0,0 +1,4 @@
+
+
+
+
\ No newline at end of file
diff --git a/tests/prdiff_fixtures/some:project/.osc/_project b/tests/prdiff_fixtures/some:project/.osc/_project
new file mode 100644
index 00000000..f9a316e5
--- /dev/null
+++ b/tests/prdiff_fixtures/some:project/.osc/_project
@@ -0,0 +1 @@
+some:project
diff --git a/tests/prdiff_fixtures/some:project/common-two b/tests/prdiff_fixtures/some:project/common-two
new file mode 100644
index 00000000..ade1e2d8
--- /dev/null
+++ b/tests/prdiff_fixtures/some:project/common-two
@@ -0,0 +1,5 @@
+line one
+line two
+line three
+an extra line
+last line
\ No newline at end of file
diff --git a/tests/prdiff_fixtures/some:project/directory b/tests/prdiff_fixtures/some:project/directory
new file mode 100644
index 00000000..f29d4543
--- /dev/null
+++ b/tests/prdiff_fixtures/some:project/directory
@@ -0,0 +1,6 @@
+
+
+
+
+
+
diff --git a/tests/suite.py b/tests/suite.py
index 8e5142cb..0987b37c 100644
--- a/tests/suite.py
+++ b/tests/suite.py
@@ -21,6 +21,7 @@ import test_package_status
import test_project_status
import test_request
import test_setlinkrev
+import test_prdiff
suite = unittest.TestSuite()
suite.addTests(test_addfiles.suite())
@@ -36,6 +37,7 @@ suite.addTests(test_package_status.suite())
suite.addTests(test_project_status.suite())
suite.addTests(test_request.suite())
suite.addTests(test_setlinkrev.suite())
+suite.addTests(test_prdiff.suite())
if have_xmlrunner:
result = xmlrunner.XMLTestRunner(output=os.path.join(os.getcwd(), 'junit-xml-results')).run(suite)
diff --git a/tests/test_prdiff.py b/tests/test_prdiff.py
new file mode 100644
index 00000000..b82fc5e6
--- /dev/null
+++ b/tests/test_prdiff.py
@@ -0,0 +1,272 @@
+import osc.commandline
+import osc.core
+import osc.oscerr
+import os
+import re
+import sys
+import urllib2
+from common import GET, POST, OscTestCase, addExpectedRequest, EXPECTED_REQUESTS
+
+
+FIXTURES_DIR = os.path.join(os.getcwd(), 'prdiff_fixtures')
+API_URL = 'http://localhost/'
+UPSTREAM = 'some:project'
+BRANCH = 'home:user:branches:' + UPSTREAM
+
+def rdiff_url(pkg, oldprj, newprj):
+ return API_URL + 'source/%s/%s?unified=1&opackage=%s&oproject=%s&cmd=diff&expand=1&filelimit=0' % \
+ (newprj, pkg, pkg, oldprj.replace(':', '%3A'))
+
+def request_url(prj):
+ return API_URL + 'search/request?match=%%28state%%2F%%40name%%3D%%27new%%27+or+state%%2F%%40name%%3D%%27review%%27%%29+and+%%28action%%2Ftarget%%2F%%40project%%3D%%27%s%%27+or+submit%%2Ftarget%%2F%%40project%%3D%%27%s%%27+or+action%%2Fsource%%2F%%40project%%3D%%27%s%%27+or+submit%%2Fsource%%2F%%40project%%3D%%27%s%%27%%29' % \
+ tuple([prj.replace(':', '%3A')] * 4)
+
+def GET_PROJECT_PACKAGES(*projects):
+ def decorator(test_method):
+ def wrapped_test_method(*args):
+ for project in projects:
+ addExpectedRequest('GET', API_URL + 'source/' + project,
+ file='%s/directory' % project)
+ test_method(*args)
+ # "rename" method otherwise we cannot specify a TestCaseClass.testName
+ # cmdline arg when using unittest.main()
+ wrapped_test_method.__name__ = test_method.__name__
+ return wrapped_test_method
+ return decorator
+
+def POST_RDIFF(oldprj, newprj):
+ def decorator(test_method):
+ def wrapped_test_method(*args):
+ addExpectedRequest('POST', rdiff_url('common-one', oldprj, newprj), exp='', text='')
+ addExpectedRequest('POST', rdiff_url('common-two', oldprj, newprj), exp='', file='common-two-diff')
+ addExpectedRequest('POST', rdiff_url('common-three', oldprj, newprj), exp='', text='')
+ test_method(*args)
+ # "rename" method otherwise we cannot specify a TestCaseClass.testName
+ # cmdline arg when using unittest.main()
+ wrapped_test_method.__name__ = test_method.__name__
+ return wrapped_test_method
+ return decorator
+
+def suite():
+ import unittest
+ return unittest.makeSuite(TestProjectDiff)
+
+class TestProjectDiff(OscTestCase):
+ diff_hdr = 'Index: %s\n==================================================================='
+ def _get_fixtures_dir(self):
+ return FIXTURES_DIR
+
+ def _change_to_tmpdir(self, *args):
+ os.chdir(os.path.join(self.tmpdir, *args))
+
+ def _run_prdiff(self, *args):
+ """Runs osc prdiff, returning captured STDOUT as a string."""
+ cli = osc.commandline.Osc()
+ argv = ['osc', 'prdiff']
+ argv.extend(args)
+ cli.main(argv=argv)
+ return sys.stdout.getvalue()
+
+
+ def testPrdiffTooManyArgs(self):
+ def runner():
+ self._run_prdiff('one', 'two', 'superfluous-arg')
+ self.assertRaises(osc.oscerr.WrongArgs, runner)
+
+
+ @GET_PROJECT_PACKAGES(UPSTREAM, BRANCH)
+ @POST_RDIFF(UPSTREAM, BRANCH)
+ @POST(rdiff_url('only-in-new', UPSTREAM, BRANCH), exp='', text='')
+ def testPrdiffZeroArgs(self):
+ exp = """identical: common-one
+differs: common-two
+identical: common-three
+identical: only-in-new
+"""
+ def runner():
+ self._run_prdiff()
+
+ os.chdir('/tmp')
+ self.assertRaises(osc.oscerr.WrongArgs, runner)
+
+ self._change_to_tmpdir(FIXTURES_DIR, UPSTREAM)
+ self.assertRaises(osc.oscerr.WrongArgs, runner)
+
+ self._change_to_tmpdir(FIXTURES_DIR, BRANCH)
+ out = self._run_prdiff()
+ self.assertEqualMultiline(out, exp)
+
+
+ @GET_PROJECT_PACKAGES(UPSTREAM, BRANCH)
+ @POST_RDIFF(UPSTREAM, BRANCH)
+ @POST(rdiff_url('only-in-new', UPSTREAM, BRANCH), exp='', text='')
+ def testPrdiffOneArg(self):
+ self._change_to_tmpdir()
+ exp = """identical: common-one
+differs: common-two
+identical: common-three
+identical: only-in-new
+"""
+ out = self._run_prdiff('home:user:branches:some:project')
+ self.assertEqualMultiline(out, exp)
+
+
+ @GET_PROJECT_PACKAGES('old:prj', 'new:prj')
+ @POST_RDIFF('old:prj', 'new:prj')
+ def testPrdiffTwoArgs(self):
+ self._change_to_tmpdir()
+ exp = """identical: common-one
+differs: common-two
+identical: common-three
+"""
+ out = self._run_prdiff('old:prj', 'new:prj')
+ self.assertEqualMultiline(out, exp)
+
+
+ @GET_PROJECT_PACKAGES('old:prj', 'new:prj')
+ @POST_RDIFF('old:prj', 'new:prj')
+ def testPrdiffOldOnly(self):
+ self._change_to_tmpdir()
+ exp = """identical: common-one
+differs: common-two
+identical: common-three
+old only: only-in-old
+"""
+ out = self._run_prdiff('--show-not-in-new', 'old:prj', 'new:prj')
+ self.assertEqualMultiline(out, exp)
+
+
+ @GET_PROJECT_PACKAGES('old:prj', 'new:prj')
+ @POST_RDIFF('old:prj', 'new:prj')
+ def testPrdiffNewOnly(self):
+ self._change_to_tmpdir()
+ exp = """identical: common-one
+differs: common-two
+identical: common-three
+new only: only-in-new
+"""
+ out = self._run_prdiff('--show-not-in-old', 'old:prj', 'new:prj')
+ self.assertEqualMultiline(out, exp)
+
+
+ @GET_PROJECT_PACKAGES('old:prj', 'new:prj')
+ @POST_RDIFF('old:prj', 'new:prj')
+ def testPrdiffDiffstat(self):
+ self._change_to_tmpdir()
+ exp = """identical: common-one
+differs: common-two
+
+ common-two | 1 +
+ 1 file changed, 1 insertion(+)
+
+identical: common-three
+"""
+ out = self._run_prdiff('--diffstat', 'old:prj', 'new:prj')
+ self.assertEqualMultiline(out, exp)
+
+
+ @GET_PROJECT_PACKAGES('old:prj', 'new:prj')
+ @POST_RDIFF('old:prj', 'new:prj')
+ def testPrdiffUnified(self):
+ self._change_to_tmpdir()
+ exp = """identical: common-one
+differs: common-two
+
+Index: common-two
+===================================================================
+--- common-two\t2013-01-18 19:18:38.225983117 +0000
++++ common-two\t2013-01-18 19:19:27.882082325 +0000
+@@ -1,4 +1,5 @@
+ line one
+ line two
+ line three
++an extra line
+ last line
+
+identical: common-three
+"""
+ out = self._run_prdiff('--unified', 'old:prj', 'new:prj')
+ self.assertEqualMultiline(out, exp)
+
+
+ @GET_PROJECT_PACKAGES('old:prj', 'new:prj')
+ @POST(rdiff_url('common-two', 'old:prj', 'new:prj'), exp='', file='common-two-diff')
+ @POST(rdiff_url('common-three', 'old:prj', 'new:prj'), exp='', text='')
+ def testPrdiffInclude(self):
+ self._change_to_tmpdir()
+ exp = """differs: common-two
+identical: common-three
+"""
+ out = self._run_prdiff('--include', 'common-t',
+ 'old:prj', 'new:prj')
+ self.assertEqualMultiline(out, exp)
+
+
+ @GET_PROJECT_PACKAGES('old:prj', 'new:prj')
+ @POST(rdiff_url('common-two', 'old:prj', 'new:prj'), exp='', file='common-two-diff')
+ @POST(rdiff_url('common-three', 'old:prj', 'new:prj'), exp='', text='')
+ def testPrdiffExclude(self):
+ self._change_to_tmpdir()
+ exp = """differs: common-two
+identical: common-three
+"""
+ out = self._run_prdiff('--exclude', 'one', 'old:prj', 'new:prj')
+ self.assertEqualMultiline(out, exp)
+
+
+ @GET_PROJECT_PACKAGES('old:prj', 'new:prj')
+ @POST(rdiff_url('common-two', 'old:prj', 'new:prj'), exp='', file='common-two-diff')
+ def testPrdiffIncludeExclude(self):
+ self._change_to_tmpdir()
+ exp = """differs: common-two
+"""
+ out = self._run_prdiff('--include', 'common-t',
+ '--exclude', 'three',
+ 'old:prj', 'new:prj')
+ self.assertEqualMultiline(out, exp)
+
+
+ @GET_PROJECT_PACKAGES(UPSTREAM, BRANCH)
+ @GET(request_url(UPSTREAM), exp='', file='request')
+ @POST(rdiff_url('common-one', UPSTREAM, BRANCH), exp='', text='')
+ @POST(rdiff_url('common-two', UPSTREAM, BRANCH), exp='', file='common-two-diff')
+ @POST(rdiff_url('common-three', UPSTREAM, BRANCH), exp='', file='common-two-diff')
+ @POST(rdiff_url('only-in-new', UPSTREAM, BRANCH), exp='', text='')
+ def testPrdiffRequestsMatching(self):
+ self._change_to_tmpdir()
+ exp = """identical: common-one
+differs: common-two
+
+148023 State:new By:user When:2013-01-11T11:04:14
+ submit: home:user:branches:some:project/common-two -> some:project
+ Descr: - Fix it to work - Improve support for something
+
+differs: common-three
+identical: only-in-new
+"""
+ out = self._run_prdiff('--requests', UPSTREAM, BRANCH)
+ self.assertEqualMultiline(out, exp)
+
+
+ # Reverse the direction of the diff.
+ @GET_PROJECT_PACKAGES(BRANCH, UPSTREAM)
+ @GET(request_url(BRANCH), exp='', file='no-requests')
+ @POST(rdiff_url('common-one', BRANCH, UPSTREAM), exp='', text='')
+ @POST(rdiff_url('common-two', BRANCH, UPSTREAM), exp='', file='common-two-diff')
+ @POST(rdiff_url('common-three', BRANCH, UPSTREAM), exp='', file='common-two-diff')
+ @POST(rdiff_url('only-in-new', BRANCH, UPSTREAM), exp='', text='')
+ def testPrdiffRequestsSwitched(self):
+ self._change_to_tmpdir()
+ exp = """identical: common-one
+differs: common-two
+differs: common-three
+identical: only-in-new
+"""
+ out = self._run_prdiff('--requests', BRANCH, UPSTREAM)
+ self.assertEqualMultiline(out, exp)
+
+
+
+if __name__ == '__main__':
+ import unittest
+ unittest.main()