Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package osc for openSUSE:Factory checked in 
at 2023-02-03 22:05:58
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/osc (Old)
 and      /work/SRC/openSUSE:Factory/.osc.new.4462 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "osc"

Fri Feb  3 22:05:58 2023 rev:170 rq:1063021 version:1.0.0~b4

Changes:
--------
--- /work/SRC/openSUSE:Factory/osc/osc.changes  2023-01-25 17:51:54.254858955 
+0100
+++ /work/SRC/openSUSE:Factory/.osc.new.4462/osc.changes        2023-02-03 
22:12:57.669979725 +0100
@@ -1,0 +2,28 @@
+Fri Feb  3 10:11:27 UTC 2023 - Daniel Mach <daniel.m...@suse.com>
+
+- 1.0.0b4
+  - Fix regressions to osc 0.x:
+    - mv: Fix traceback due to missing target file name
+    - rm: Fix creating a Package object by providing multiple files on the 
command line
+    - copypac: Fix downgrading a package to an old revision
+    - buildhist: Fix running from a package checkout
+    - rebuild: Fix running from a package checkout
+    - rdiff: Fix traceback when new project is not specified
+    - rq list: Fix passing values of the --type option
+    - build: Fix reading extra-pkgs from oscrc
+    - Support withfullhistory in osc.core.get_request_list again
+    - Fix osc.get_request_list ignoring the req_type parameter
+  - Revert "Do not list declined requests by default"
+  - connection: Mute the "Converted retries value" debug message
+  - connection: Fix traceback on loading an invalid cookiejar file
+  - connection: Save cookiejar only when there's a Set-Cookie header in the 
response
+  - Add oscerr.ProjectError class needed by core.delete_project()
+  - Fix all errors reported by pylint
+
+- spec file:
+  - drop upstreamed patches:
+    - 1217.patch
+    - 1228.patch
+  - Recommend python3-distro - needed for setting the default editor by distro
+
+-------------------------------------------------------------------

Old:
----
  1217.patch
  1228.patch
  osc-1.0.0~b3.tar.gz

New:
----
  osc-1.0.0~b4.tar.gz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ osc.spec ++++++
--- /var/tmp/diff_new_pack.p6fTAd/_old  2023-02-03 22:12:58.141982467 +0100
+++ /var/tmp/diff_new_pack.p6fTAd/_new  2023-02-03 22:12:58.149982513 +0100
@@ -49,7 +49,7 @@
 %endif
 
 Name:           osc
-Version:        1.0.0~b3
+Version:        1.0.0~b4
 Release:        0
 Summary:        Command-line client for the Open Build Service
 License:        GPL-2.0-or-later
@@ -62,8 +62,7 @@
 Source1:        debian.dirs
 Source2:        debian.docs
 %endif
-Patch1:         https://github.com/openSUSE/osc/pull/1228.patch
-Patch2:         https://github.com/openSUSE/osc/pull/1217.patch
+
 BuildArch:      noarch
 BuildRoot:      %{_tmppath}/%{name}-%{version}-build
 
@@ -84,6 +83,9 @@
 # needed for showing download progressbars
 Recommends:     %{use_python_pkg}-progressbar
 
+# needed for setting the default editor by distro
+Recommends:     %{use_python_pkg}-distro
+
 # needed for storing credentials in kwallet/gnome-keyring
 Recommends:     %{use_python_pkg}-keyring
 Recommends:     %{use_python_pkg}-keyring-keyutils

++++++ PKGBUILD ++++++
--- /var/tmp/diff_new_pack.p6fTAd/_old  2023-02-03 22:12:58.193982769 +0100
+++ /var/tmp/diff_new_pack.p6fTAd/_new  2023-02-03 22:12:58.197982792 +0100
@@ -1,5 +1,5 @@
 pkgname=osc
-pkgver=1.0.0~b3
+pkgver=1.0.0~b4
 pkgrel=0
 pkgdesc="Command-line client for the Open Build Service"
 arch=('x86_64')

++++++ _service ++++++
--- /var/tmp/diff_new_pack.p6fTAd/_old  2023-02-03 22:12:58.217982908 +0100
+++ /var/tmp/diff_new_pack.p6fTAd/_new  2023-02-03 22:12:58.225982955 +0100
@@ -1,7 +1,7 @@
 <services>
   <service name="tar_scm" mode="disabled">
-    <param name="version">1.0.0~b3</param>
-    <param name="revision">1.0.0b3</param>
+    <param name="version">1.0.0~b4</param>
+    <param name="revision">1.0.0b4</param>
     <param name="url">https://github.com/openSUSE/osc.git</param>
     <param name="scm">git</param>
   </service>

++++++ debian.changelog ++++++
--- /var/tmp/diff_new_pack.p6fTAd/_old  2023-02-03 22:12:58.269983211 +0100
+++ /var/tmp/diff_new_pack.p6fTAd/_new  2023-02-03 22:12:58.273983233 +0100
@@ -1,4 +1,4 @@
-osc (1.0.0~b3-0) unstable; urgency=low
+osc (1.0.0~b4-0) unstable; urgency=low
   - Update to 0.174.0:
     - fix password deletion via "osc config -d <apiurl> pass"
     - support changing the password store via "osc config <apiurl>

++++++ osc-1.0.0~b3.tar.gz -> osc-1.0.0~b4.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/osc-1.0.0~b3/.github/workflows/build-install.yaml 
new/osc-1.0.0~b4/.github/workflows/build-install.yaml
--- old/osc-1.0.0~b3/.github/workflows/build-install.yaml       2023-01-17 
09:35:55.000000000 +0100
+++ new/osc-1.0.0~b4/.github/workflows/build-install.yaml       2023-02-03 
11:01:51.000000000 +0100
@@ -10,6 +10,10 @@
       - 'README.md'
       - 'doc/**'
 
+concurrency:
+  group: ${{ github.workflow }}-${{ github.ref }}
+  cancel-in-progress: true
+
 jobs:
   rpmbuild:
     name: 'rpmbuild test'
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/osc-1.0.0~b3/.github/workflows/codeql.yml 
new/osc-1.0.0~b4/.github/workflows/codeql.yml
--- old/osc-1.0.0~b3/.github/workflows/codeql.yml       2023-01-17 
09:35:55.000000000 +0100
+++ new/osc-1.0.0~b4/.github/workflows/codeql.yml       2023-02-03 
11:01:51.000000000 +0100
@@ -8,6 +8,10 @@
   schedule:
     - cron: "13 12 * * 6"
 
+concurrency:
+  group: ${{ github.workflow }}-${{ github.ref }}
+  cancel-in-progress: true
+
 jobs:
   analyze:
     name: Analyze
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/osc-1.0.0~b3/.github/workflows/linters.yaml 
new/osc-1.0.0~b4/.github/workflows/linters.yaml
--- old/osc-1.0.0~b3/.github/workflows/linters.yaml     2023-01-17 
09:35:55.000000000 +0100
+++ new/osc-1.0.0~b4/.github/workflows/linters.yaml     2023-02-03 
11:01:51.000000000 +0100
@@ -7,6 +7,10 @@
       - '.github/**'
       - '**.py'
 
+concurrency:
+  group: ${{ github.workflow }}-${{ github.ref }}
+  cancel-in-progress: true
+
 jobs:
   mypy:
     runs-on: ubuntu-latest
@@ -25,11 +29,25 @@
         with:
           fetch-depth: 0
       - uses: actions/setup-python@v4
-      - uses: akaihola/darker@1.5.1
+      - uses: akaihola/darker@1.6.1
         with:
           options: "--check --diff --color --line-length=120"
           src: "."
-          version: "1.5.1"
+
+  pylint_errors:
+    name: 'Run pylint that reports only errors'
+    runs-on: 'ubuntu-latest'
+    steps:
+      - name: 'Install packages'
+        run: |
+            sudo apt-get -y update
+            sudo apt-get -y --no-install-recommends install pylint python3-rpm
+
+      - uses: actions/checkout@v3
+
+      - name: 'Run pylint --errors-only'
+        run: |
+            pylint --errors-only osc
 
   pylint_plugins:
     name: 'Diff pylint runs on osc plugin'
@@ -64,11 +82,28 @@
           repository: ${{ matrix.plugin_repository }}
           path: plugin
 
+      - name: 'Run pylint with osc from master'
+        run: |
+            cd plugin
+            find . -type f -name "*.py" | sort | PYTHONPATH="../osc-master" 
xargs pylint --errors-only >> pylint-osc-master.log || :
+
+            echo
+            echo ">>>>> pylint-osc-master.log <<<<<"
+            cat pylint-osc-master.log
+
+      - name: 'Run pylint with osc from pull-request'
+        run: |
+            cd plugin
+            find . -type f -name "*.py" | sort | PYTHONPATH="../osc-pr" xargs 
pylint --errors-only >> pylint-osc-pr.log || :
+
+            echo
+            echo ">>>>> pylint-osc-pr.log <<<<<"
+            cat pylint-osc-pr.log
+
       - name: 'Diff pylint runs'
         run: |
             cd plugin
-            find -maxdepth 2 -name __init__.py | while read i; do dirname $i; 
done | sort > .pylint-args
-            find -maxdepth 1 -name '*.py' | sort >> .pylint-args
-            PYTHONPATH="../osc-master" pylint --errors-only $(cat 
.pylint-args) | sort > pylint-osc-master.log || :
-            PYTHONPATH="../osc-pr" pylint --errors-only $(cat .pylint-args) | 
sort > pylint-osc-pr.log || :
+
+            echo
+            echo ">>>>> diff <<<<<"
             diff -u pylint-osc-master.log pylint-osc-pr.log
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/osc-1.0.0~b3/.github/workflows/tests.yaml 
new/osc-1.0.0~b4/.github/workflows/tests.yaml
--- old/osc-1.0.0~b3/.github/workflows/tests.yaml       2023-01-17 
09:35:55.000000000 +0100
+++ new/osc-1.0.0~b4/.github/workflows/tests.yaml       2023-02-03 
11:01:51.000000000 +0100
@@ -9,6 +9,10 @@
       - 'behave/**'
       - 'tests/**'
 
+concurrency:
+  group: ${{ github.workflow }}-${{ github.ref }}
+  cancel-in-progress: true
+
 jobs:
   unit:
     name: "unit"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/osc-1.0.0~b3/NEWS new/osc-1.0.0~b4/NEWS
--- old/osc-1.0.0~b3/NEWS       2023-01-17 09:35:55.000000000 +0100
+++ new/osc-1.0.0~b4/NEWS       2023-02-03 11:01:51.000000000 +0100
@@ -1,3 +1,22 @@
+1.0.0b4
+ - Fix regressions to osc 0.x:
+   - mv: Fix traceback due to missing target file name
+   - rm: Fix creating a Package object by providing multiple files on the 
command line
+   - copypac: Fix downgrading a package to an old revision
+   - buildhist: Fix running from a package checkout
+   - rebuild: Fix running from a package checkout
+   - rdiff: Fix traceback when new project is not specified
+   - rq list: Fix passing values of the --type option
+   - build: Fix reading extra-pkgs from oscrc
+   - Support withfullhistory in osc.core.get_request_list again
+   - Fix osc.get_request_list ignoring the req_type parameter
+ - Revert "Do not list declined requests by default"
+ - connection: Mute the "Converted retries value" debug message
+ - connection: Fix traceback on loading an invalid cookiejar file
+ - connection: Save cookiejar only when there's a Set-Cookie header in the 
response
+ - Add oscerr.ProjectError class needed by core.delete_project()
+ - Fix all errors reported by pylint
+
 1.0.0b3
   - add create-pbuild-config (cpc) command which allows to create a working
     config for pbuild tool based on OBS server side data
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/osc-1.0.0~b3/behave/features/buildhist.feature 
new/osc-1.0.0~b4/behave/features/buildhist.feature
--- old/osc-1.0.0~b3/behave/features/buildhist.feature  1970-01-01 
01:00:00.000000000 +0100
+++ new/osc-1.0.0~b4/behave/features/buildhist.feature  2023-02-03 
11:01:51.000000000 +0100
@@ -0,0 +1,30 @@
+Feature: `osc buildhist` command
+
+
+# common steps for all scenarios
+Background:
+   Given I set working directory to "{context.osc.temp}"
+
+
+Scenario: Run `osc buildist <project>/<package> <repository>/<arch>`
+    When I execute osc with args "buildhist test:factory/test-pkgA 
standard/x86_64"
+    Then the exit code is 0
+
+
+Scenario: Run `osc buildist <repository>/<arch>` from a package checkout
+   Given I execute osc with args "co test:factory/test-pkgA"
+     And I set working directory to "{context.osc.temp}/test:factory/test-pkgA"
+    When I execute osc with args "buildhist standard/x86_64"
+    Then the exit code is 0
+
+
+Scenario: Run `osc buildist <repository>/<arch>` from outside a package 
checkout
+    When I execute osc with args "buildhist standard/x86_64"
+    Then the exit code is 1
+
+
+Scenario: Run `osc buildist <repository>/<arch>` from a project checkout
+   Given I execute osc with args "co test:factory"
+     And I set working directory to "{context.osc.temp}/test:factory"
+    When I execute osc with args "buildhist standard/x86_64"
+    Then the exit code is 1
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/osc-1.0.0~b3/behave/features/copypac.feature 
new/osc-1.0.0~b4/behave/features/copypac.feature
--- old/osc-1.0.0~b3/behave/features/copypac.feature    2023-01-17 
09:35:55.000000000 +0100
+++ new/osc-1.0.0~b4/behave/features/copypac.feature    2023-02-03 
11:01:51.000000000 +0100
@@ -18,6 +18,12 @@
     Then the exit code is 0
 
 
+@destructive
+Scenario: Run `osc copypac <project>/<package> <project>/<package> --keep-link 
--revision`
+    When I execute osc with args "copypac test:factory/test-pkgA 
test:factory/test-pkgA --keep-link --revision=1"
+    Then the exit code is 0
+
+
 Scenario: Run `osc copypac` where the source and target are the same
     When I execute osc with args "copypac test:factory/test-pkgA test:factory"
     Then the exit code is 1
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/osc-1.0.0~b3/behave/features/mv.feature 
new/osc-1.0.0~b4/behave/features/mv.feature
--- old/osc-1.0.0~b3/behave/features/mv.feature 1970-01-01 01:00:00.000000000 
+0100
+++ new/osc-1.0.0~b4/behave/features/mv.feature 2023-02-03 11:01:51.000000000 
+0100
@@ -0,0 +1,21 @@
+Feature: `osc mv` command
+
+
+# common steps for all scenarios
+Background:
+   Given I set working directory to "{context.osc.temp}"
+     And I execute osc with args "checkout test:factory/test-pkgA"
+     And I set working directory to "{context.osc.temp}/test:factory/test-pkgA"
+
+
+Scenario: Run `osc mv <file> <new-name>` in a package checkout
+    When I execute osc with args "mv test-pkgA.changes new-name.changes"
+    Then the exit code is 0
+     And I execute osc with args "status"
+     And stdout is
+     """
+     A    new-name.changes
+     D    test-pkgA.changes
+     """
+     And file "{context.osc.temp}/test:factory/test-pkgA/test-pkgA.changes" 
does not exist
+     And file "{context.osc.temp}/test:factory/test-pkgA/new-name.changes" 
exists
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/osc-1.0.0~b3/behave/features/rdelete.feature 
new/osc-1.0.0~b4/behave/features/rdelete.feature
--- old/osc-1.0.0~b3/behave/features/rdelete.feature    1970-01-01 
01:00:00.000000000 +0100
+++ new/osc-1.0.0~b4/behave/features/rdelete.feature    2023-02-03 
11:01:51.000000000 +0100
@@ -0,0 +1,6 @@
+Feature: `osc rdelete` command
+
+@destructive
+Scenario: Run `osc rdelete` to delete a project and mark it with a 
desctructive tag
+   When I execute osc with args "rdelete -r -f test:factory -m 'cleanup'"
+   Then the exit code is 0 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/osc-1.0.0~b3/behave/features/rdiff.feature 
new/osc-1.0.0~b4/behave/features/rdiff.feature
--- old/osc-1.0.0~b3/behave/features/rdiff.feature      1970-01-01 
01:00:00.000000000 +0100
+++ new/osc-1.0.0~b4/behave/features/rdiff.feature      2023-02-03 
11:01:51.000000000 +0100
@@ -0,0 +1,26 @@
+Feature: `osc rdiff` command
+
+
+# common steps for all scenarios
+Background:
+   Given I set working directory to "{context.osc.temp}"
+
+
+Scenario: Run `osc rdiff <project>/<package> <target-project>/<target-package>`
+    When I execute osc with args "rdiff test:factory/test-pkgA 
test:factory/test-pkgA"
+    Then the exit code is 0
+
+
+Scenario: Run `osc rdiff <project>/<package> <target-project>`
+    When I execute osc with args "rdiff test:factory/test-pkgA test:factory"
+    Then the exit code is 0
+
+
+Scenario: Run `osc rdiff <project>/<package>`
+    When I execute osc with args "rdiff test:factory/test-pkgA"
+    Then the exit code is 0
+
+
+Scenario: Run `osc rdiff <project>/<package> --change`
+    When I execute osc with args "rdiff test:factory/test-pkgA --change=1"
+    Then the exit code is 0
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/osc-1.0.0~b3/behave/features/rm.feature 
new/osc-1.0.0~b4/behave/features/rm.feature
--- old/osc-1.0.0~b3/behave/features/rm.feature 1970-01-01 01:00:00.000000000 
+0100
+++ new/osc-1.0.0~b4/behave/features/rm.feature 2023-02-03 11:01:51.000000000 
+0100
@@ -0,0 +1,19 @@
+Feature: `osc rm` command
+
+
+# common steps for all scenarios
+Background:
+   Given I set working directory to "{context.osc.temp}"
+     And I execute osc with args "checkout test:factory/test-pkgA"
+     And I set working directory to "{context.osc.temp}/test:factory/test-pkgA"
+
+
+Scenario: Run `osc rm` on multiple files
+    When I execute osc with args "rm test-pkgA.spec test-pkgA.changes"
+    Then the exit code is 0
+     And I execute osc with args "status"
+     And stdout is
+        """
+        D    test-pkgA.changes
+        D    test-pkgA.spec
+        """
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/osc-1.0.0~b3/contrib/osc.spec 
new/osc-1.0.0~b4/contrib/osc.spec
--- old/osc-1.0.0~b3/contrib/osc.spec   2023-01-17 09:35:55.000000000 +0100
+++ new/osc-1.0.0~b4/contrib/osc.spec   2023-02-03 11:01:51.000000000 +0100
@@ -19,7 +19,7 @@
 %endif
 
 # generate manpages on distros where argparse-manpage >= 3 is available
-%if 0%{?suse_version} > 1500 || 0%{?fedora}
+%if 0%{?suse_version} > 1500 || 0%{?fedora} >= 37
 %bcond_without man
 %else
 %bcond_with man
@@ -31,7 +31,7 @@
 %endif
 
 Name:           osc
-Version:        1.0.0~b3
+Version:        1.0.0~b4
 Release:        0
 Summary:        Command-line client for the Open Build Service
 License:        GPL-2.0-or-later
@@ -65,6 +65,9 @@
 # needed for showing download progressbars
 Recommends:     %{use_python_pkg}-progressbar
 
+# needed for setting the default editor by distro
+Recommends:     %{use_python_pkg}-distro
+
 # needed for storing credentials in kwallet/gnome-keyring
 Recommends:     %{use_python_pkg}-keyring
 Recommends:     %{use_python_pkg}-keyring-keyutils
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/osc-1.0.0~b3/doc/README.md 
new/osc-1.0.0~b4/doc/README.md
--- old/osc-1.0.0~b3/doc/README.md      1970-01-01 01:00:00.000000000 +0100
+++ new/osc-1.0.0~b4/doc/README.md      2023-02-03 11:01:51.000000000 +0100
@@ -0,0 +1 @@
+This is the place where all osc documentation starts
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/osc-1.0.0~b3/osc/__init__.py 
new/osc-1.0.0~b4/osc/__init__.py
--- old/osc-1.0.0~b3/osc/__init__.py    2023-01-17 09:35:55.000000000 +0100
+++ new/osc-1.0.0~b4/osc/__init__.py    2023-02-03 11:01:51.000000000 +0100
@@ -13,7 +13,7 @@
 
 
 from .util import git_version
-__version__ = git_version.get_version('1.0.0~b3')
+__version__ = git_version.get_version('1.0.0~b4')
 
 
 # vim: sw=4 et
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/osc-1.0.0~b3/osc/_private/api_build.py 
new/osc-1.0.0~b4/osc/_private/api_build.py
--- old/osc-1.0.0~b3/osc/_private/api_build.py  2023-01-17 09:35:55.000000000 
+0100
+++ new/osc-1.0.0~b4/osc/_private/api_build.py  2023-02-03 11:01:51.000000000 
+0100
@@ -34,7 +34,7 @@
         ]
         url_query = {}
         if self._limit and self._limit > 0:
-            query["limit"] = self._limit
+            url_query["limit"] = self._limit
 
         root = api.get(self.apiurl, url_path, url_query)
 
@@ -47,8 +47,13 @@
                 "ver_rel": node.get("versrel"),
                 "build_count": int(node.get("bcnt")),
                 "time": time.strftime("%Y-%m-%d %H:%M:%S", 
time.gmtime(int(node.get("time")))),
-                "duration": int(node.get("duration")),
             }
+
+            # duration may not always be available
+            duration = node.get("duration")
+            if duration:
+                item["duration"] = int(duration)
+
             result.append(item)
         return result
 
@@ -72,7 +77,7 @@
                 i["srcmd5"],
                 f"{i['ver_rel']}.{i['build_count']}",
                 i["rev"],
-                i["duration"],
+                i.get("duration", ""),
             )
             data.extend(item)
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/osc-1.0.0~b3/osc/_private/common.py 
new/osc-1.0.0~b4/osc/_private/common.py
--- old/osc-1.0.0~b3/osc/_private/common.py     2023-01-17 09:35:55.000000000 
+0100
+++ new/osc-1.0.0~b4/osc/_private/common.py     2023-02-03 11:01:51.000000000 
+0100
@@ -12,7 +12,7 @@
     elif print_to == "stdout":
         print(msg)
     else:
-        raise ValueError(f"Invalid value of the 'output' option: {output}")
+        raise ValueError(f"Invalid value of the 'print_to' option: {print_to}")
 
 
 def format_msg_project_package_options(
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/osc-1.0.0~b3/osc/babysitter.py 
new/osc-1.0.0~b4/osc/babysitter.py
--- old/osc-1.0.0~b3/osc/babysitter.py  2023-01-17 09:35:55.000000000 +0100
+++ new/osc-1.0.0~b4/osc/babysitter.py  2023-02-03 11:01:51.000000000 +0100
@@ -26,6 +26,7 @@
 
 try:
     # import as RPMError because the class "error" is too generic
+    # pylint: disable=E0611
     from rpm import error as RPMError
 except:
     # if rpm-python isn't installed (we might be on a debian system):
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/osc-1.0.0~b3/osc/build.py 
new/osc-1.0.0~b4/osc/build.py
--- old/osc-1.0.0~b3/osc/build.py       2023-01-17 09:35:55.000000000 +0100
+++ new/osc-1.0.0~b4/osc/build.py       2023-02-03 11:01:51.000000000 +0100
@@ -221,6 +221,14 @@
 
     def __init__(self, node, buildarch, pacsuffix, apiurl, localpkgs=None):
         localpkgs = localpkgs or []
+
+        # set attributes to mute pylint error E1101: Instance of 'Pac' has no 
'<attr>' member (no-member)
+        self.project = None
+        self.name = None
+        self.canonname = None
+        self.repository = None
+        self.repoarch = None
+
         self.mp = {}
         for i in ['binary', 'package',
                   'epoch', 'version', 'release', 'hdrmd5',
@@ -292,7 +300,7 @@
         self.urllist = [url % self.mp for url in urllist]
 
     def __str__(self):
-        return self.name
+        return self.name or ""
 
     def __repr__(self):
         return "%s" % self.name
@@ -863,7 +871,7 @@
 
     extra_pkgs = []
     if not opts.extra_pkgs:
-        extra_pkgs = getattr(config, 'extra-pkgs', extra_pkgs)
+        extra_pkgs = config.get('extra-pkgs', [])
     elif opts.extra_pkgs != ['']:
         extra_pkgs = opts.extra_pkgs
 
@@ -1177,11 +1185,11 @@
                     def __del__(self):
                         self.cleanup()
 
-                    def __exit__(self):
+                    def __exit__(self, exc_type, exc_value, traceback):
                         self.cleanup()
 
                     def __str__(self):
-                        return self.name
+                        return self.name or ""
 
                 old_pkg_dir = mytmpdir(prefix='.build.oldpackages', 
dir=os.path.abspath(os.curdir))
                 if not os.path.exists(destdir):
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/osc-1.0.0~b3/osc/checker.py 
new/osc-1.0.0~b4/osc/checker.py
--- old/osc-1.0.0~b3/osc/checker.py     2023-01-17 09:35:55.000000000 +0100
+++ new/osc-1.0.0~b4/osc/checker.py     2023-02-03 11:01:51.000000000 +0100
@@ -19,6 +19,7 @@
         import rpm
         self.dbdir = mkdtemp(prefix='oscrpmdb')
         self.imported = {}
+        # pylint: disable=E1101
         rpm.addMacro('_dbpath', self.dbdir)
         self.ts = rpm.TransactionSet()
         self.ts.initDB()
@@ -29,6 +30,7 @@
     def readkeys(self, keys=None):
         import rpm
         keys = keys or []
+        # pylint: disable=E1101
         rpm.addMacro('_dbpath', self.dbdir)
         for key in keys:
             try:
@@ -40,6 +42,7 @@
             raise KeyError('', "no key imported")
 
         import rpm
+        # pylint: disable=E1101
         rpm.delMacro("_dbpath")
 
 # python is an idiot
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/osc-1.0.0~b3/osc/commandline.py 
new/osc-1.0.0~b4/osc/commandline.py
--- old/osc-1.0.0~b3/osc/commandline.py 2023-01-17 09:35:55.000000000 +0100
+++ new/osc-1.0.0~b4/osc/commandline.py 2023-02-03 11:01:51.000000000 +0100
@@ -1856,7 +1856,7 @@
 
         print('created request id', result)
         if conf.config['print_web_links']:
-            obs_url = _private.get_configuration_option(apiurl, "obs_url")
+            obs_url = _private.get_configuration_value(apiurl, "obs_url")
             print(f"{obs_url}/request/show/{result}")
 
         if supersede_existing:
@@ -2487,7 +2487,7 @@
     @cmdln.option('-f', '--force', action='store_true',
                         help='enforce state change, can be used to ignore open 
reviews')
     @cmdln.option('-s', '--state',
-                        help='only list requests in one of the comma separated 
given states (new/review/accepted/revoked/declined) or "all" 
[default="new,review"]')
+                        help='only list requests in one of the comma separated 
given states (new/review/accepted/revoked/declined) or "all" 
[default="new,review,declined"]')
     @cmdln.option('-D', '--days', metavar='DAYS',
                         help='only list requests in state "new" or changed in 
the last DAYS.')
     @cmdln.option('-U', '--user', metavar='USER',
@@ -2621,7 +2621,7 @@
             state_list = ["all"]
         else:
             if not opts.state:
-                opts.state = "new,review"
+                opts.state = "new,review,declined"
             state_list = opts.state.split(",")
             state_list = [i for i in state_list if i.strip()]
 
@@ -2773,7 +2773,7 @@
                         roles = ["creator"] if opts.mine else None
                         results = get_request_collection(
                             apiurl, project=project, package=package, user=who,
-                            states=state_list, types=opts.type, roles=roles)
+                            states=state_list, types=[opts.type], roles=roles)
 
             # Check if project actually exists if result list is empty
             if not results:
@@ -3349,9 +3349,8 @@
         if opts.message:
             comment = opts.message
         else:
-            if not rev:
-                rev = show_upstream_rev(src_apiurl, src_project, src_package)
-            comment = 'osc copypac from project:%s package:%s revision:%s' % 
(src_project, src_package, rev)
+            src_rev = rev or show_upstream_rev(src_apiurl, src_project, 
src_package)
+            comment = 'osc copypac from project:%s package:%s revision:%s' % 
(src_project, src_package, src_rev)
             if opts.keep_link:
                 comment += ", using keep-link"
             if opts.expand:
@@ -3650,7 +3649,7 @@
         r = create_maintenance_request(apiurl, source_project, 
source_packages, target_project, release_project, opt_sourceupdate, 
opts.message, opts.enforce_branching)
         print(r.reqid)
         if conf.config['print_web_links']:
-            obs_url = _private.get_configuration_option(apiurl, "obs_url")
+            obs_url = _private.get_configuration_value(apiurl, "obs_url")
             print(f"{obs_url}/request/show/{r.reqid}")
 
         if supersede_existing:
@@ -4201,6 +4200,9 @@
         )
         ensure_no_remaining_args(args)
 
+        if not new_project:
+            new_project = old_project
+
         if not new_package:
             new_package = old_package
 
@@ -4578,7 +4580,7 @@
         else:
             raise oscerr.WrongArgs('Wrong number of arguments')
 
-        download_url = _private.get_configuration_option(apiurl, 
"download_url")
+        download_url = _private.get_configuration_value(apiurl, "download_url")
 
         url_deb_tmpl = 'deb ' + download_url + '/%s/%s/ /'
         url_arch_tmpl = 'Server=' + download_url + '/%s/%s/$arch'
@@ -6907,8 +6909,16 @@
         apiurl = self.get_api_url()
 
         args = list(args)
-        project, package, repository, arch = 
pop_project_package_repository_arch_from_args(args)
-        ensure_no_remaining_args(args)
+        args_backup = args.copy()
+
+        try:
+            args = [".", "."] + args_backup.copy()
+            project, package, repository, arch = 
pop_project_package_repository_arch_from_args(args)
+            ensure_no_remaining_args(args)
+        except (oscerr.NoWorkingCopy, oscerr.WrongArgs):
+            args[:] = args_backup.copy()
+            project, package, repository, arch = 
pop_project_package_repository_arch_from_args(args)
+            ensure_no_remaining_args(args)
 
         if opts.multibuild_package:
             package = package + ":" + opts.multibuild_package
@@ -7144,6 +7154,8 @@
             package_is_optional=True,
             repository_is_optional=True,
             arch_is_optional=True,
+            default_project='.',
+            default_package='.',
         )
         ensure_no_remaining_args(args)
 
@@ -9159,11 +9171,11 @@
 
         os.rename(source, dest)
         try:
-            tgt_pkg[0].addfile(os.path.basename(dest))
+            tgt_pkg.addfile(os.path.basename(dest))
         except oscerr.PackageFileConflict:
             # file is already tracked
             pass
-        src_pkg[0].delete_file(os.path.basename(source), force=opts.force)
+        src_pkg.delete_file(os.path.basename(source), force=opts.force)
 
     @cmdln.option('-d', '--delete', action='store_true',
                         help='delete option from config or reset option to the 
default)')
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/osc-1.0.0~b3/osc/connection.py 
new/osc-1.0.0~b4/osc/connection.py
--- old/osc-1.0.0~b3/osc/connection.py  2023-01-17 09:35:55.000000000 +0100
+++ new/osc-1.0.0~b4/osc/connection.py  2023-02-03 11:01:51.000000000 +0100
@@ -217,7 +217,7 @@
     pool = CONNECTION_POOLS.get(apiurl, None)
     if not pool:
         pool_kwargs = {}
-        pool_kwargs["retries"] = int(conf.config["http_retries"])
+        pool_kwargs["retries"] = 
urllib3.Retry(total=int(conf.config["http_retries"]))
 
         if purl.scheme == "https":
             ssl_context = oscssl.create_ssl_context()
@@ -451,7 +451,10 @@
                 pass
             jar = http.cookiejar.LWPCookieJar(self.cookiejar_path)
             if os.path.isfile(self.cookiejar_path):
-                jar.load()
+                try:
+                    jar.load()
+                except http.cookiejar.LoadError:
+                    pass
             self.COOKIEJARS[self.cookiejar_path] = jar
         return jar
 
@@ -484,8 +487,9 @@
         return False
 
     def process_response(self, url, request_headers, response):
-        self._cookiejar.extract_cookies(response, MockRequest(url, 
response.headers))
-        self._cookiejar.save()
+        if response.headers.get_all("set-cookie", None):
+            self._cookiejar.extract_cookies(response, MockRequest(url, 
response.headers))
+            self._cookiejar.save()
         self._unlock()
 
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/osc-1.0.0~b3/osc/core.py new/osc-1.0.0~b4/osc/core.py
--- old/osc-1.0.0~b3/osc/core.py        2023-01-17 09:35:55.000000000 +0100
+++ new/osc-1.0.0~b4/osc/core.py        2023-02-03 11:01:51.000000000 +0100
@@ -1224,7 +1224,14 @@
     def __init__(self, workingdir, progress_obj=None, size_limit=None, 
wc_check=True):
         global store
 
-        self.dir = workingdir
+        self.todo = []
+        if os.path.isfile(workingdir) or not os.path.exists(workingdir):
+            # workingdir is a file
+            # workingdir doesn't exist -> it points to a non-existing file in 
a working dir (e.g. during mv)
+            workingdir, todo_entry = os.path.split(workingdir)
+            self.todo.append(todo_entry)
+
+        self.dir = workingdir or "."
         self.absdir = os.path.abspath(self.dir)
         self.store = Store(self.dir)
         self.storedir = os.path.join(self.absdir, store)
@@ -1251,8 +1258,6 @@
                 'of the working copy afterwards (via \'osc status %s\')' % 
(self.dir, self.dir, self.dir)
             raise oscerr.WorkingCopyInconsistent(self.prjname, self.name, 
dirty_files, msg)
 
-        self.todo = []
-
     def __repr__(self):
         return super().__repr__() + f"({self.prjname}/{self.name})"
 
@@ -1272,18 +1277,24 @@
         """
         packages = []
         for path in paths:
-            # TODO: match only dirs, remove the code for resolving files into 
Package objects
-            orig_path = path
-            path_is_file = os.path.isfile(path)
-            if path_is_file:
-                path = os.path.dirname(path) or "."
             package = cls(path, progress_obj)
-            if path_is_file:
-                # XXX: modifying 'todo' is an unexpected side-effect
-                package.todo = [os.path.basename(orig_path)]
-            if package in packages:
-                raise oscerr.PackageExists(package.prjname, package.name, 
"Duplicate package")
-            packages.append(package)
+            seen_package = None
+            try:
+                # re-use an existing package
+                seen_package_index = packages.index(package)
+                seen_package = packages[seen_package_index]
+            except ValueError:
+                pass
+
+            if seen_package:
+                # merge package into seen_package
+                if seen_package.absdir != package.absdir:
+                    raise oscerr.PackageExists(package.prjname, package.name, 
"Duplicate package")
+                seen_package.merge(package)
+            else:
+                # use the new package instance
+                packages.append(package)
+
         return packages
 
     @classmethod
@@ -1295,21 +1306,30 @@
         packages = []
         failed_to_load = []
         for path in paths:
-            # TODO: match only dirs, remove the code for resolving files into 
Package objects
-            orig_path = path
-            path_is_file = os.path.isfile(path)
-            if path_is_file:
-                path = os.path.dirname(path) or "."
             try:
                 package = cls(path, progress_obj)
-                if path_is_file:
-                    # XXX: modifying 'todo' is an unexpected side-effect
-                    package.todo = [os.path.basename(orig_path)]
-                if package in packages:
+            except oscerr.NoWorkingCopy:
+                failed_to_load.append(path)
+                continue
+
+            # the following code is identical to from_paths()
+            seen_package = None
+            try:
+                # re-use an existing package
+                seen_package_index = packages.index(package)
+                seen_package = packages[seen_package_index]
+            except ValueError:
+                pass
+
+            if seen_package:
+                # merge package into seen_package
+                if seen_package.absdir != package.absdir:
                     raise oscerr.PackageExists(package.prjname, package.name, 
"Duplicate package")
+                seen_package.merge(package)
+            else:
+                # use the new package instance
                 packages.append(package)
-            except oscerr.NoWorkingCopy:
-                failed_to_load.append(orig_path)
+
         return packages, failed_to_load
 
     def wc_check(self):
@@ -2134,7 +2154,6 @@
         def diff_add_delete(fname, add, revision):
             diff = []
             diff.append(diff_hdr % fname.encode())
-            tmpfile = None
             origname = fname
             if add:
                 diff.append(b'--- %s\t(revision 0)\n' % fname.encode())
@@ -2155,6 +2174,8 @@
                 diff.append(b'+++ %s\t(working copy)\n' % fname.encode())
                 fname = os.path.join(self.storedir, fname)
 
+            fd = None
+            tmpfile = None
             try:
                 if revision is not None and not add:
                     (fd, tmpfile) = tempfile.mkstemp(prefix='osc_diff')
@@ -2180,8 +2201,9 @@
                         lines.append(b'\n\\ No newline at end of file\n')
                 diff.extend(lines)
             finally:
-                if tmpfile is not None:
+                if fd is not None:
                     os.close(fd)
+                if tmpfile is not None and os.path.exists(tmpfile):
                     os.unlink(tmpfile)
             return diff
 
@@ -2226,6 +2248,7 @@
             if revision is None:
                 yield get_source_file_diff(self.absdir, f.name, self.rev)
             else:
+                fd = None
                 tmpfile = None
                 diff = []
                 try:
@@ -2234,8 +2257,9 @@
                     diff = get_source_file_diff(self.absdir, f.name, revision,
                                                 os.path.basename(tmpfile), 
os.path.dirname(tmpfile), f.name)
                 finally:
-                    if tmpfile is not None:
+                    if fd is not None:
                         os.close(fd)
+                    if tmpfile is not None and os.path.exists(tmpfile):
                         os.unlink(tmpfile)
                 yield diff
 
@@ -2245,7 +2269,9 @@
             yield diff_add_delete(f, False, revision)
 
     def merge(self, otherpac):
-        self.todo += otherpac.todo
+        for todo_entry in otherpac.todo:
+            if todo_entry not in self.todo:
+                self.todo.append(todo_entry)
 
     def __str__(self):
         r = """
@@ -2617,7 +2643,8 @@
         elif filename in self.skipped:
             raise oscerr.OscIOError(None, 'file \'%s\' is marked as skipped 
and cannot be reverted' % filename)
         if filename in self.filenamelist and not 
os.path.exists(os.path.join(self.storedir, filename)):
-            raise oscerr.PackageInternalError('file \'%s\' is listed in 
filenamelist but no storefile exists' % filename)
+            msg = f"file '{filename}' is listed in filenamelist but no 
storefile exists"
+            raise oscerr.PackageInternalError(self.prjname, self.name, msg)
         state = self.status(filename)
         if not (state == 'A' or state == '!' and filename in self.to_be_added):
             shutil.copyfile(os.path.join(self.storedir, filename), 
os.path.join(self.absdir, filename))
@@ -4203,10 +4230,7 @@
 def _get_linux_distro():
     if distro is not None:
         return distro.id()
-    elif sys.version_info >= (3, 8):
-        return None
-    # compatibility for Python 2.6 to 3.7
-    return platform.linux_distribution()[0]
+    return None
 
 
 def get_default_editor():
@@ -4604,8 +4628,9 @@
     package=None,
     states=None,
     review_states=None,
-    types=None,
+    types: List[str] = None,
     ids=None,
+    withfullhistory=False
 ):
 
     # We don't want to overload server by requesting everything.
@@ -4632,7 +4657,7 @@
             raise ValueError("Project must be set to query a package; see 
https://github.com/openSUSE/open-build-service/issues/13075";)
         query["package"] = package
 
-    states = states or ("new", "review")
+    states = states or ("new", "review", "declined")
     if states:
         if "all" not in states:
             query["states"] = ",".join(states)
@@ -4642,11 +4667,15 @@
             query["review_states"] = ",".join(review_states)
 
     if types:
+        assert not isinstance(types, str)
         query["types"] = ",".join(types)
 
     if ids:
         query["ids"] = ",".join(ids)
 
+    if withfullhistory:
+        query["withfullhistory"] = "1"
+
     u = makeurl(apiurl, ['request'], query)
     f = http_GET(u)
     res = ET.parse(f).getroot()
@@ -4726,10 +4755,13 @@
         "project": project,
         "package": package,
         "states": req_state,
+        "withfullhistory": withfullhistory,
     }
 
+    if req_type is not None:
+        kwargs["types"] = [req_type]
+
     assert not exclude_target_projects, "unsupported"
-    assert not withfullhistory, "unsupported"
 
     return get_request_collection(**kwargs)
 
@@ -4741,6 +4773,7 @@
     req_state=(
         "new",
         "review",
+        "declined",
     ),
     req_type=None,
     exclude_projects=None,
@@ -5932,8 +5965,10 @@
     or by the server, in a single api call.
     """
     if (src_apiurl, src_project, src_package) == (dst_apiurl, dst_project, 
dst_package):
-        # copypac is also used to expand sources, let's allow that
-        if not expand:
+        # special cases when source and target can be the same:
+        # * expanding sources
+        # * downgrading package to an old revision
+        if not any([expand, revision]):
             raise oscerr.OscValueError("Cannot copy package. Source and target 
are the same.")
 
     if not (src_apiurl == dst_apiurl and src_project == dst_project
@@ -6073,7 +6108,7 @@
 
 def delete_project(apiurl: str, prj: str, force=False, msg=None, 
recursive=False):
     if not recursive:
-        packages = meta_get_packagelist(apiurl, project)
+        packages = meta_get_packagelist(apiurl, prj)
         if packages:
             error_msg = \
                 "Project contains packages. It must be empty before deleting 
it. " \
@@ -8000,7 +8035,7 @@
     return msg
 
 
-def print_request_list(apiurl, project, package=None, states=('new', 
'review'), force=False):
+def print_request_list(apiurl, project, package=None, states=("new", 
"review"), force=False):
     """
     prints list of pending requests for the specified project/package if 
"check_for_request_on_action"
     is enabled in the config or if "force" is set to True
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/osc-1.0.0~b3/osc/fetch.py 
new/osc-1.0.0~b4/osc/fetch.py
--- old/osc-1.0.0~b3/osc/fetch.py       2023-01-17 09:35:55.000000000 +0100
+++ new/osc-1.0.0~b4/osc/fetch.py       2023-02-03 11:01:51.000000000 +0100
@@ -86,6 +86,8 @@
                         pac = pkgs[decode_it(hdr.filename)]
 
                     # Extract a single file from the cpio archive
+                    fd = None
+                    tmpfile = None
                     try:
                         fd, tmpfile = tempfile.mkstemp(prefix='osc_build_file')
                         archive.copyin_file(hdr.filename,
@@ -93,8 +95,9 @@
                                             
decode_it(os.path.basename(tmpfile)))
                         self.move_package(tmpfile, pac.localdir, pac)
                     finally:
-                        os.close(fd)
-                        if os.path.exists(tmpfile):
+                        if fd is not None:
+                            os.close(fd)
+                        if tmpfile is not None and os.path.exists(tmpfile):
                             os.unlink(tmpfile)
 
                 for pac in pkgs.values():
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/osc-1.0.0~b3/osc/oscerr.py 
new/osc-1.0.0~b4/osc/oscerr.py
--- old/osc-1.0.0~b3/osc/oscerr.py      2023-01-17 09:35:55.000000000 +0100
+++ new/osc-1.0.0~b4/osc/oscerr.py      2023-02-03 11:01:51.000000000 +0100
@@ -126,6 +126,21 @@
                 % (self.args[0], self.args[1], self.args[2]))
 
 
+class ProjectError(OscBaseError):
+    """Base class for all Project related exceptions"""
+
+    def __init__(self, prj, msg=None):
+        super().__init__()
+        self.prj = prj
+        self.msg = msg
+
+    def __str__(self):
+        result = f"{self.__class__.__name__}: {self.prj}"
+        if self.msg:
+            result += f": {self.msg}"
+        return result
+
+
 class PackageError(OscBaseError):
     """Base class for all Package related exceptions"""
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/osc-1.0.0~b3/tests/fixtures/packages/osctest/projectA/pkgA-symlink 
new/osc-1.0.0~b4/tests/fixtures/packages/osctest/projectA/pkgA-symlink
--- old/osc-1.0.0~b3/tests/fixtures/packages/osctest/projectA/pkgA-symlink      
1970-01-01 01:00:00.000000000 +0100
+++ new/osc-1.0.0~b4/tests/fixtures/packages/osctest/projectA/pkgA-symlink      
2023-02-03 22:12:58.545984814 +0100
@@ -0,0 +1 @@
+symbolic link to pkgA
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/osc-1.0.0~b3/tests/test_core_package.py 
new/osc-1.0.0~b4/tests/test_core_package.py
--- old/osc-1.0.0~b3/tests/test_core_package.py 2023-01-17 09:35:55.000000000 
+0100
+++ new/osc-1.0.0~b4/tests/test_core_package.py 2023-02-03 11:01:51.000000000 
+0100
@@ -69,6 +69,36 @@
     def _get_fixtures_dir(self):
         return FIXTURES_DIR
 
+    def test_package_object_dir(self):
+        path = "projectA/pkgA"
+        path = os.path.join(self.tmpdir, 'osctest', path)
+        pac = osc.core.Package(path)
+
+        self.assertEqual(pac.name, "pkgA")
+        self.assertEqual(pac.prjname, "projectA")
+        self.assertEqual(pac.apiurl, "http://localhost";)
+        self.assertEqual(pac.todo, [])
+
+    def test_package_object_file(self):
+        path = "projectA/pkgA/pkgA.spec"
+        path = os.path.join(self.tmpdir, 'osctest', path)
+        pac = osc.core.Package(path)
+
+        self.assertEqual(pac.name, "pkgA")
+        self.assertEqual(pac.prjname, "projectA")
+        self.assertEqual(pac.apiurl, "http://localhost";)
+        self.assertEqual(pac.todo, ["pkgA.spec"])
+
+    def test_package_object_file_missing(self):
+        path = "projectA/pkgA/missing-file"
+        path = os.path.join(self.tmpdir, 'osctest', path)
+        pac = osc.core.Package(path)
+
+        self.assertEqual(pac.name, "pkgA")
+        self.assertEqual(pac.prjname, "projectA")
+        self.assertEqual(pac.apiurl, "http://localhost";)
+        self.assertEqual(pac.todo, ["missing-file"])
+
     def test_single_package(self):
         paths = ["projectA/pkgA"]
         paths = [os.path.join(self.tmpdir, 'osctest', i) for i in paths]
@@ -81,10 +111,31 @@
         self.assertEqual(pac.apiurl, "http://localhost";)
 
     def test_duplicates(self):
+        # passing a path twice is ok
         paths = ["projectA/pkgA", "projectA/pkgA"]
         paths = [os.path.join(self.tmpdir, 'osctest', i) for i in paths]
+        pacs = osc.core.Package.from_paths(paths)
+        pac = pacs[0]
+        self.assertEqual(pac.name, "pkgA")
+        self.assertEqual(pac.prjname, "projectA")
+        self.assertEqual(pac.apiurl, "http://localhost";)
+
+        # the same package in 2 paths is an error
+        paths = ["projectA/pkgA", "projectA/pkgA-symlink"]
+        paths = [os.path.join(self.tmpdir, 'osctest', i) for i in paths]
         self.assertRaises(osc.oscerr.PackageExists, 
osc.core.Package.from_paths, paths)
 
+    def test_one_package_two_files(self):
+        paths = ["projectA/pkgA/pkgA.spec", "projectA/pkgA/pkgA.changes"]
+        paths = [os.path.join(self.tmpdir, 'osctest', i) for i in paths]
+        pacs = osc.core.Package.from_paths(paths)
+        self.assertEqual(len(pacs), 1)
+
+        pac = pacs[0]
+        self.assertEqual(pac.name, "pkgA")
+        self.assertEqual(pac.prjname, "projectA")
+        self.assertEqual(pac.apiurl, "http://localhost";)
+
     def test_two_packages(self):
         paths = ["projectA/pkgA", "projectA/pkgB"]
         paths = [os.path.join(self.tmpdir, 'osctest', i) for i in paths]

++++++ osc.dsc ++++++
--- /var/tmp/diff_new_pack.p6fTAd/_old  2023-02-03 22:12:58.693985673 +0100
+++ /var/tmp/diff_new_pack.p6fTAd/_new  2023-02-03 22:12:58.697985697 +0100
@@ -1,6 +1,6 @@
 Format: 1.0
 Source: osc
-Version: 1.0.0~b1-0
+Version: 1.0.0~b4-0
 Binary: osc
 Maintainer: Adrian Schroeter <adr...@suse.de>
 Architecture: any

Reply via email to