Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package harbor-cli for openSUSE:Factory 
checked in at 2026-10-21 20:58:00
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/harbor-cli (Old)
 and      /work/SRC/openSUSE:Factory/.harbor-cli.new.2252680 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "harbor-cli"

Wed Oct 21 20:58:00 2026 rev:21 rq:1386680 version:0.0.27

Changes:
--------
--- /work/SRC/openSUSE:Factory/harbor-cli/harbor-cli.changes    2026-08-28 
19:50:27.244418604 +0200
+++ /work/SRC/openSUSE:Factory/.harbor-cli.new.2252680/harbor-cli.changes       
2026-10-21 20:59:44.962672737 +0200
@@ -1,0 +2,25 @@
+Wed Oct 21 05:05:10 UTC 2026 - Johannes Kastl 
<[email protected]>
+
+- Update to version 0.0.27:
+  * build(deps): bump github.com/stretchr/testify from 1.11.1 to
+    1.12.1 (#1093)
+  * build(deps): bump github.com/sirupsen/logrus from 1.9.4 to
+    1.10.2 (#1094)
+  * build(deps): bump github.com/charmbracelet/x/ansi from 0.11.7
+    to 0.11.8 (#1086)
+  * build(deps): bump golang.org/x/text from 0.40.0 to 0.41.0
+    (#1087)
+  * build(deps): bump go.yaml.in/yaml/v4 from 4.0.0-rc.4 to
+    4.0.0-rc.6 (#1088)
+  * fix(api): encode nested repository names in API paths (#1114)
+  * fix: TUI picker to set Aborted when user cancels (#1051)
+  * tests: Add unit test for API type structures (#616)
+  * fix(typos): Adherence to Go guidlines and typos (#983)
+  * fix: abort delete when project selection fails (#1104)
+  * build(deps): bump github.com/go-openapi/strfmt from 0.26.2 to
+    0.27.0 (#977)
+  * build(deps): bump dagger/dagger-for-github from 7.0.6 to 8.4.1
+    (#968)
+  * Update harbor-cli manifest
+
+-------------------------------------------------------------------

Old:
----
  harbor-cli-0.0.26.obscpio

New:
----
  harbor-cli-0.0.27.obscpio

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

Other differences:
------------------
++++++ harbor-cli.spec ++++++
--- /var/tmp/diff_new_pack.ozrnmU/_old  2026-10-21 20:59:46.078719530 +0200
+++ /var/tmp/diff_new_pack.ozrnmU/_new  2026-10-21 20:59:46.079719572 +0200
@@ -19,7 +19,7 @@
 %define executable_name harbor
 
 Name:           harbor-cli
-Version:        0.0.26
+Version:        0.0.27
 Release:        0
 Summary:        CLI for the Harbor cloud native registry
 License:        Apache-2.0

++++++ _service ++++++
--- /var/tmp/diff_new_pack.ozrnmU/_old  2026-10-21 20:59:46.120721291 +0200
+++ /var/tmp/diff_new_pack.ozrnmU/_new  2026-10-21 20:59:46.124721459 +0200
@@ -3,7 +3,7 @@
     <param name="url">https://github.com/goharbor/harbor-cli.git</param>
     <param name="scm">git</param>
     <param name="exclude">.git</param>
-    <param name="revision">refs/tags/v0.0.26</param>
+    <param name="revision">refs/tags/v0.0.27</param>
     <param name="versionformat">@PARENT_TAG@</param>
     <param name="versionrewrite-pattern">v(.*)</param>
     <param name="changesgenerate">enable</param>

++++++ _servicedata ++++++
--- /var/tmp/diff_new_pack.ozrnmU/_old  2026-10-21 20:59:46.148722465 +0200
+++ /var/tmp/diff_new_pack.ozrnmU/_new  2026-10-21 20:59:46.153722675 +0200
@@ -3,6 +3,6 @@
                 <param 
name="url">https://github.com/goharbor/harbor-cli</param>
               <param 
name="changesrevision">19e9a10c142ab3bb44e234f8862981a423cfc37c</param></service><service
 name="tar_scm">
                 <param 
name="url">https://github.com/goharbor/harbor-cli.git</param>
-              <param 
name="changesrevision">8c20d16b2f19adaa1c3b5fa7a6113c09938f65bd</param></service></servicedata>
+              <param 
name="changesrevision">1af93ace562d69b2293fa71733d4a4f5bb3c1503</param></service></servicedata>
 (No newline at EOF)
 

++++++ harbor-cli-0.0.26.obscpio -> harbor-cli-0.0.27.obscpio ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/harbor-cli-0.0.26/bucket/harbor-cli.json 
new/harbor-cli-0.0.27/bucket/harbor-cli.json
--- old/harbor-cli-0.0.26/bucket/harbor-cli.json        2026-08-18 
15:36:47.000000000 +0200
+++ new/harbor-cli-0.0.27/bucket/harbor-cli.json        2026-10-20 
15:28:52.000000000 +0200
@@ -1,5 +1,5 @@
 {
-    "version": "0.0.25",
+    "version": "0.0.26",
     "description": "A command-line interface for Harbor container registry.",
     "homepage": "https://github.com/goharbor/harbor-cli";,
     "license": "Apache-2.0",
@@ -8,13 +8,13 @@
     },
     "architecture": {
         "64bit": {
-            "url": 
"https://github.com/goharbor/harbor-cli/releases/download/v0.0.25/harbor-cli_0.0.25_windows_amd64.zip";,
-            "hash": 
"3ab1671a00a18bcd96da7c4e0e5cea577b54e1fb1a2de6036848c28d6f53d9e2",
+            "url": 
"https://github.com/goharbor/harbor-cli/releases/download/v0.0.26/harbor-cli_0.0.26_windows_amd64.zip";,
+            "hash": 
"3d50b8dd6eb6b59ccb617b4fe13136e805148c0d68eeefeab6639ad0d068b7c0",
             "bin": "harbor-cli.exe"
         },
         "arm64": {
-            "url": 
"https://github.com/goharbor/harbor-cli/releases/download/v0.0.25/harbor-cli_0.0.25_windows_arm64.zip";,
-            "hash": 
"ea1f911147e5b286c4d3b036c1d812b51c48bbe0436bee78de49ab75350700ec",
+            "url": 
"https://github.com/goharbor/harbor-cli/releases/download/v0.0.26/harbor-cli_0.0.26_windows_arm64.zip";,
+            "hash": 
"d1afb4b25c8efcd304c64e104171ec1bd2bbf806275bfa0bda58e03af20384f8",
             "bin": "harbor-cli.exe"
         }
     },
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/harbor-cli-0.0.26/cmd/harbor/root/artifact/delete.go 
new/harbor-cli-0.0.27/cmd/harbor/root/artifact/delete.go
--- old/harbor-cli-0.0.26/cmd/harbor/root/artifact/delete.go    2026-08-18 
15:36:47.000000000 +0200
+++ new/harbor-cli-0.0.27/cmd/harbor/root/artifact/delete.go    2026-10-20 
15:28:52.000000000 +0200
@@ -19,7 +19,6 @@
        "github.com/goharbor/harbor-cli/pkg/api"
        "github.com/goharbor/harbor-cli/pkg/prompt"
        "github.com/goharbor/harbor-cli/pkg/utils"
-       log "github.com/sirupsen/logrus"
        "github.com/spf13/cobra"
 )
 
@@ -39,7 +38,7 @@
                        } else {
                                projectName, err = 
prompt.GetProjectNameFromUser()
                                if err != nil {
-                                       log.Errorf("failed to get project name: 
%v", utils.ParseHarborErrorMsg(err))
+                                       return fmt.Errorf("failed to get 
project name: %v", utils.ParseHarborErrorMsg(err))
                                }
                                repoName = 
prompt.GetRepoNameFromUser(projectName)
                                reference = 
prompt.GetReferenceFromUser(repoName, projectName)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/harbor-cli-0.0.26/cmd/harbor/root/artifact/delete_test.go 
new/harbor-cli-0.0.27/cmd/harbor/root/artifact/delete_test.go
--- old/harbor-cli-0.0.26/cmd/harbor/root/artifact/delete_test.go       
1970-01-01 01:00:00.000000000 +0100
+++ new/harbor-cli-0.0.27/cmd/harbor/root/artifact/delete_test.go       
2026-10-20 15:28:52.000000000 +0200
@@ -0,0 +1,40 @@
+// Copyright Project Harbor Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+package artifact_test
+
+import (
+       "bytes"
+       "testing"
+
+       "github.com/goharbor/harbor-cli/cmd/harbor/root/artifact"
+       helpers "github.com/goharbor/harbor-cli/test/helper"
+       "github.com/stretchr/testify/assert"
+)
+
+func TestDeleteArtifactCommand_ProjectSelectionFailure(t *testing.T) {
+       helpers.SetMockKeyring(t)
+       data := helpers.Initialize(t, t.TempDir())
+       defer helpers.ConfigCleanup(t, data)
+
+       cmd := artifact.DeleteArtifactCommand()
+
+       var buf bytes.Buffer
+       cmd.SetOut(&buf)
+       cmd.SetErr(&buf)
+       cmd.SetArgs([]string{})
+
+       err := cmd.Execute()
+       assert.Error(t, err)
+       assert.Contains(t, err.Error(), "failed to get project name")
+}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/harbor-cli-0.0.26/cmd/harbor/root/artifact/label/list.go 
new/harbor-cli-0.0.27/cmd/harbor/root/artifact/label/list.go
--- old/harbor-cli-0.0.26/cmd/harbor/root/artifact/label/list.go        
2026-08-18 15:36:47.000000000 +0200
+++ new/harbor-cli-0.0.27/cmd/harbor/root/artifact/label/list.go        
2026-10-20 15:28:52.000000000 +0200
@@ -70,7 +70,7 @@
                                if len(args) > 0 {
                                        return fmt.Errorf("Invalid artifact 
reference format: %s", args[0])
                                } else {
-                                       return fmt.Errorf("Invalid artifact 
reference format: no arguments provided")
+                                       return fmt.Errorf("invalid artifact 
reference format: no arguments provided")
                                }
                        }
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/harbor-cli-0.0.26/cmd/harbor/root/project/list.go 
new/harbor-cli-0.0.27/cmd/harbor/root/project/list.go
--- old/harbor-cli-0.0.26/cmd/harbor/root/project/list.go       2026-08-18 
15:36:47.000000000 +0200
+++ new/harbor-cli-0.0.27/cmd/harbor/root/project/list.go       2026-10-20 
15:28:52.000000000 +0200
@@ -49,7 +49,7 @@
                        }
 
                        if private && public {
-                               return fmt.Errorf("Cannot specify both 
--private and --public flags")
+                               return fmt.Errorf("cannot specify both 
--private and --public flags")
                        }
 
                        var listFunc func(...api.ListFlags) 
(project.ListProjectsOK, error)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/harbor-cli-0.0.26/cmd/harbor/root/project/member/update.go 
new/harbor-cli-0.0.27/cmd/harbor/root/project/member/update.go
--- old/harbor-cli-0.0.26/cmd/harbor/root/project/member/update.go      
2026-08-18 15:36:47.000000000 +0200
+++ new/harbor-cli-0.0.27/cmd/harbor/root/project/member/update.go      
2026-10-20 15:28:52.000000000 +0200
@@ -57,7 +57,7 @@
                                opts.ID = 
prompt.GetMemberIDFromUser(opts.ProjectNameOrID, memberName)
 
                                if opts.ID == 0 {
-                                       return fmt.Errorf("No members found in 
project")
+                                       return fmt.Errorf("no members found in 
project")
                                }
                        } else {
                                opts.ID, err = api.GetUsersIdByName(memberName)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/harbor-cli-0.0.26/cmd/harbor/root/robot/create.go 
new/harbor-cli-0.0.27/cmd/harbor/root/robot/create.go
--- old/harbor-cli-0.0.26/cmd/harbor/root/robot/create.go       2026-08-18 
15:36:47.000000000 +0200
+++ new/harbor-cli-0.0.27/cmd/harbor/root/robot/create.go       2026-10-20 
15:28:52.000000000 +0200
@@ -347,7 +347,7 @@
        if err != nil {
                errorCode := utils.ParseHarborErrorCode(err)
                if errorCode == "403" {
-                       return fmt.Errorf("Permission denied: (Project) Admin 
privileges are required to execute this command.")
+                       return fmt.Errorf("permission denied: (Project) Admin 
privileges are required to execute this command.")
                } else {
                        return fmt.Errorf("failed to create robot: %v", 
utils.ParseHarborErrorMsg(err))
                }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/harbor-cli-0.0.26/cmd/harbor/root/robot/delete.go 
new/harbor-cli-0.0.27/cmd/harbor/root/robot/delete.go
--- old/harbor-cli-0.0.26/cmd/harbor/root/robot/delete.go       2026-08-18 
15:36:47.000000000 +0200
+++ new/harbor-cli-0.0.27/cmd/harbor/root/robot/delete.go       2026-10-20 
15:28:52.000000000 +0200
@@ -62,7 +62,7 @@
                                if err != nil {
                                        errorCode := 
utils.ParseHarborErrorCode(err)
                                        if errorCode == "403" {
-                                               return fmt.Errorf("Permission 
denied: (Project) Admin privileges are required to execute this command.")
+                                               return fmt.Errorf("permission 
denied: (Project) Admin privileges are required to execute this command.")
                                        } else {
                                                return fmt.Errorf("failed to 
get robot: %v", utils.ParseHarborErrorMsg(err))
                                        }
@@ -78,7 +78,7 @@
                        if err != nil {
                                errorCode := utils.ParseHarborErrorCode(err)
                                if errorCode == "403" {
-                                       return fmt.Errorf("Permission denied: 
(Project) Admin privileges are required to execute this command.")
+                                       return fmt.Errorf("permission denied: 
(Project) Admin privileges are required to execute this command.")
                                } else {
                                        return fmt.Errorf("failed to delete 
robot: %v", utils.ParseHarborErrorMsg(err))
                                }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/harbor-cli-0.0.26/cmd/harbor/root/robot/list.go 
new/harbor-cli-0.0.27/cmd/harbor/root/robot/list.go
--- old/harbor-cli-0.0.26/cmd/harbor/root/robot/list.go 2026-08-18 
15:36:47.000000000 +0200
+++ new/harbor-cli-0.0.27/cmd/harbor/root/robot/list.go 2026-10-20 
15:28:52.000000000 +0200
@@ -78,7 +78,7 @@
                        if err != nil {
                                errorCode := utils.ParseHarborErrorCode(err)
                                if errorCode == "403" {
-                                       return fmt.Errorf("Permission denied: 
(Project) Admin privileges are required to execute this command.")
+                                       return fmt.Errorf("permission denied: 
(Project) Admin privileges are required to execute this command.")
                                } else {
                                        return fmt.Errorf("failed to list 
robots: %v", utils.ParseHarborErrorMsg(err))
                                }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/harbor-cli-0.0.26/cmd/harbor/root/robot/view.go 
new/harbor-cli-0.0.27/cmd/harbor/root/robot/view.go
--- old/harbor-cli-0.0.26/cmd/harbor/root/robot/view.go 2026-08-18 
15:36:47.000000000 +0200
+++ new/harbor-cli-0.0.27/cmd/harbor/root/robot/view.go 2026-10-20 
15:28:52.000000000 +0200
@@ -80,7 +80,7 @@
                        if err != nil {
                                errorCode := utils.ParseHarborErrorCode(err)
                                if errorCode == "403" {
-                                       return fmt.Errorf("Permission denied: 
(Project) Admin privileges are required to execute this command.")
+                                       return fmt.Errorf("permission denied: 
(Project) Admin privileges are required to execute this command.")
                                } else {
                                        return fmt.Errorf("failed to get robot: 
%v", utils.ParseHarborErrorMsg(err))
                                }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/harbor-cli-0.0.26/cmd/harbor/root/tag/retention/delete.go 
new/harbor-cli-0.0.27/cmd/harbor/root/tag/retention/delete.go
--- old/harbor-cli-0.0.26/cmd/harbor/root/tag/retention/delete.go       
2026-08-18 15:36:47.000000000 +0200
+++ new/harbor-cli-0.0.27/cmd/harbor/root/tag/retention/delete.go       
2026-10-20 15:28:52.000000000 +0200
@@ -45,7 +45,7 @@
                Args: cobra.MaximumNArgs(1),
                RunE: func(cmd *cobra.Command, args []string) error {
                        if projectID != -1 && projectName != "" {
-                               return fmt.Errorf("Cannot specify both 
--project-id and --project-name flags")
+                               return fmt.Errorf("cannot specify both 
--project-id and --project-name flags")
                        }
 
                        if projectID == -1 && projectName == "" {
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/harbor-cli-0.0.26/cmd/harbor/root/tag/retention/list.go 
new/harbor-cli-0.0.27/cmd/harbor/root/tag/retention/list.go
--- old/harbor-cli-0.0.26/cmd/harbor/root/tag/retention/list.go 2026-08-18 
15:36:47.000000000 +0200
+++ new/harbor-cli-0.0.27/cmd/harbor/root/tag/retention/list.go 2026-10-20 
15:28:52.000000000 +0200
@@ -55,7 +55,7 @@
                Args: cobra.NoArgs,
                RunE: func(cmd *cobra.Command, args []string) error {
                        if projectID != -1 && projectName != "" {
-                               return fmt.Errorf("Cannot specify both 
--project-id and --project-name flags")
+                               return fmt.Errorf("cannot specify both 
--project-id and --project-name flags")
                        }
 
                        if projectID == -1 && projectName == "" {
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/harbor-cli-0.0.26/cmd/harbor/root/user/create.go 
new/harbor-cli-0.0.27/cmd/harbor/root/user/create.go
--- old/harbor-cli-0.0.26/cmd/harbor/root/user/create.go        2026-08-18 
15:36:47.000000000 +0200
+++ new/harbor-cli-0.0.27/cmd/harbor/root/user/create.go        2026-10-20 
15:28:52.000000000 +0200
@@ -58,7 +58,7 @@
 
                        if err != nil {
                                if isUnauthorizedError(err) {
-                                       return fmt.Errorf("Permission denied: 
Admin privileges are required to execute this command.")
+                                       return fmt.Errorf("permission denied: 
Admin privileges are required to execute this command.")
                                } else {
                                        return fmt.Errorf("failed to create 
user: %v", err)
                                }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/harbor-cli-0.0.26/cmd/harbor/root/user/delete.go 
new/harbor-cli-0.0.27/cmd/harbor/root/user/delete.go
--- old/harbor-cli-0.0.26/cmd/harbor/root/user/delete.go        2026-08-18 
15:36:47.000000000 +0200
+++ new/harbor-cli-0.0.27/cmd/harbor/root/user/delete.go        2026-10-20 
15:28:52.000000000 +0200
@@ -72,7 +72,7 @@
                                }
                                if err := api.DeleteUser(userID); err != nil {
                                        if isUnauthorizedError(err) {
-                                               return fmt.Errorf("Permission 
denied: Admin privileges are required to execute this command.")
+                                               return fmt.Errorf("permission 
denied: Admin privileges are required to execute this command.")
                                        } else {
                                                return fmt.Errorf("failed to 
delete user: %v", err)
                                        }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/harbor-cli-0.0.26/cmd/harbor/root/user/elevate.go 
new/harbor-cli-0.0.27/cmd/harbor/root/user/elevate.go
--- old/harbor-cli-0.0.26/cmd/harbor/root/user/elevate.go       2026-08-18 
15:36:47.000000000 +0200
+++ new/harbor-cli-0.0.27/cmd/harbor/root/user/elevate.go       2026-10-20 
15:28:52.000000000 +0200
@@ -60,7 +60,7 @@
                return err
        }
        if !confirm {
-               err = errors.New("User did not confirm elevation. Aborting 
command.")
+               err = errors.New("user did not confirm elevation. Aborting 
command.")
                log.Error(err.Error())
                return err
        }
@@ -68,7 +68,7 @@
        err = elevateUserAPI(userId)
        if err != nil {
                if isUnauthorizedError(err) {
-                       err = errors.New("Permission denied: Admin privileges 
are required to execute this command.")
+                       err = errors.New("permission denied: Admin privileges 
are required to execute this command.")
                } else {
                        err = fmt.Errorf("failed to elevate user: %v", err)
                }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/harbor-cli-0.0.26/cmd/harbor/root/user/list.go 
new/harbor-cli-0.0.27/cmd/harbor/root/user/list.go
--- old/harbor-cli-0.0.26/cmd/harbor/root/user/list.go  2026-08-18 
15:36:47.000000000 +0200
+++ new/harbor-cli-0.0.27/cmd/harbor/root/user/list.go  2026-10-20 
15:28:52.000000000 +0200
@@ -47,7 +47,7 @@
                                        response, err := api.ListUsers(opts)
                                        if err != nil {
                                                if isUnauthorizedError(err) {
-                                                       return 
fmt.Errorf("Permission denied: Admin privileges are required to execute this 
command.")
+                                                       return 
fmt.Errorf("permission denied: Admin privileges are required to execute this 
command.")
                                                }
                                                return fmt.Errorf("failed to 
list users: %v", err)
                                        }
@@ -63,7 +63,7 @@
                                response, err := api.ListUsers(opts)
                                if err != nil {
                                        if isUnauthorizedError(err) {
-                                               return fmt.Errorf("Permission 
denied: Admin privileges are required to execute this command.")
+                                               return fmt.Errorf("permission 
denied: Admin privileges are required to execute this command.")
                                        }
                                        return fmt.Errorf("failed to list 
users: %v", err)
                                }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/harbor-cli-0.0.26/go.mod new/harbor-cli-0.0.27/go.mod
--- old/harbor-cli-0.0.26/go.mod        2026-08-18 15:36:47.000000000 +0200
+++ new/harbor-cli-0.0.27/go.mod        2026-10-20 15:28:52.000000000 +0200
@@ -8,16 +8,16 @@
        github.com/charmbracelet/bubbletea v1.3.10
        github.com/charmbracelet/huh v1.0.0
        github.com/charmbracelet/lipgloss v1.1.0
-       github.com/charmbracelet/x/ansi v0.11.7
+       github.com/charmbracelet/x/ansi v0.11.8
        github.com/gocarina/gocsv v0.0.0-20240520201108-78e41c74b4b1
        github.com/sahilm/fuzzy v0.1.3
-       github.com/sirupsen/logrus v1.9.4
+       github.com/sirupsen/logrus v1.10.2
        github.com/spf13/cobra v1.10.2
        github.com/spf13/viper v1.21.0
-       github.com/stretchr/testify v1.11.1
+       github.com/stretchr/testify v1.12.1
        github.com/zalando/go-keyring v0.2.8
-       go.yaml.in/yaml/v4 v4.0.0-rc.4
-       golang.org/x/term v0.44.0
+       go.yaml.in/yaml/v4 v4.0.0-rc.6
+       golang.org/x/term v0.45.0
        gopkg.in/yaml.v2 v2.4.0
 )
 
@@ -41,14 +41,13 @@
        github.com/lucasb-eyer/go-colorful v1.4.0 // indirect
        github.com/mattn/go-isatty v0.0.20 // indirect
        github.com/mattn/go-localereader v0.0.1 // indirect
-       github.com/mattn/go-runewidth v0.0.23 // indirect
+       github.com/mattn/go-runewidth v0.0.24 // indirect
        github.com/mitchellh/hashstructure/v2 v2.0.2 // indirect
        github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 // indirect
        github.com/muesli/cancelreader v0.2.2 // indirect
        github.com/muesli/termenv v0.16.0 // indirect
        github.com/oklog/ulid/v2 v2.1.1 // indirect
        github.com/pelletier/go-toml/v2 v2.2.4 // indirect
-       github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // 
indirect
        github.com/rivo/uniseg v0.4.7 // indirect
        github.com/russross/blackfriday/v2 v2.1.0 // indirect
        github.com/sagikazarmark/locafero v0.11.0 // indirect
@@ -59,10 +58,10 @@
        github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect
        go.opentelemetry.io/auto/sdk v1.1.0 // indirect
        go.opentelemetry.io/otel/sdk v1.35.0 // indirect
-       go.yaml.in/yaml/v3 v3.0.4 // indirect
+       go.yaml.in/yaml/v3 v3.0.5 // indirect
        golang.org/x/exp v0.0.0-20241217172543-b2144cdd0a67 // indirect
-       golang.org/x/net v0.53.0 // indirect
-       golang.org/x/sync v0.20.0 // indirect
+       golang.org/x/net v0.57.0 // indirect
+       golang.org/x/sync v0.22.0 // indirect
        gopkg.in/yaml.v3 v3.0.1 // indirect
 )
 
@@ -70,13 +69,13 @@
        github.com/go-logr/logr v1.4.2 // indirect
        github.com/go-logr/stdr v1.2.2 // indirect
        github.com/go-openapi/analysis v0.23.0 // indirect
-       github.com/go-openapi/errors v0.22.7 // indirect
+       github.com/go-openapi/errors v0.22.8 // indirect
        github.com/go-openapi/jsonpointer v0.21.0 // indirect
        github.com/go-openapi/jsonreference v0.21.0 // indirect
        github.com/go-openapi/loads v0.22.0 // indirect
        github.com/go-openapi/runtime v0.28.0 // indirect
        github.com/go-openapi/spec v0.21.0 // indirect
-       github.com/go-openapi/strfmt v0.26.2
+       github.com/go-openapi/strfmt v0.27.0
        github.com/go-openapi/swag v0.23.0 // indirect
        github.com/go-openapi/validate v0.24.0 // indirect
        github.com/goharbor/go-client v0.213.1
@@ -89,8 +88,8 @@
        go.opentelemetry.io/otel v1.35.0 // indirect
        go.opentelemetry.io/otel/metric v1.35.0 // indirect
        go.opentelemetry.io/otel/trace v1.35.0 // indirect
-       golang.org/x/sys v0.46.0 // indirect
-       golang.org/x/text v0.37.0
+       golang.org/x/sys v0.47.0 // indirect
+       golang.org/x/text v0.41.0
 )
 
 replace go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc => 
go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc 
v0.0.0-20240518090000-14441aefdf88
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/harbor-cli-0.0.26/go.sum new/harbor-cli-0.0.27/go.sum
--- old/harbor-cli-0.0.26/go.sum        2026-08-18 15:36:47.000000000 +0200
+++ new/harbor-cli-0.0.27/go.sum        2026-10-20 15:28:52.000000000 +0200
@@ -18,8 +18,8 @@
 github.com/charmbracelet/huh v1.0.0/go.mod 
h1:5YVc+SlZ1IhQALxRPpkGwwEKftN/+OlJlnJYlDRFqN4=
 github.com/charmbracelet/lipgloss v1.1.0 
h1:vYXsiLHVkK7fp74RkV7b2kq9+zDLoEU4MZoFqR/noCY=
 github.com/charmbracelet/lipgloss v1.1.0/go.mod 
h1:/6Q8FR2o+kj8rz4Dq0zQc3vYf7X+B0binUUBwA0aL30=
-github.com/charmbracelet/x/ansi v0.11.7 
h1:kzv1kJvjg2S3r9KHo8hDdHFQLEqn4RBCb39dAYC84jI=
-github.com/charmbracelet/x/ansi v0.11.7/go.mod 
h1:9qGpnAVYz+8ACONkZBUWPtL7lulP9No6p1epAihUZwQ=
+github.com/charmbracelet/x/ansi v0.11.8 
h1:JMFwp0CgDC2+jcOB162HH5k7I3FVbgFSMMYg7dSPBQQ=
+github.com/charmbracelet/x/ansi v0.11.8/go.mod 
h1:ZNN+3mXny/516oTQPLMPIBeSINvNJJQ8uQXDgbeJxY0=
 github.com/charmbracelet/x/cellbuf v0.0.15 
h1:ur3pZy0o6z/R7EylET877CBxaiE1Sp1GMxoFPAIztPI=
 github.com/charmbracelet/x/cellbuf v0.0.15/go.mod 
h1:J1YVbR7MUuEGIFPCaaZ96KDl5NoS0DAWkskup+mOY+Q=
 github.com/charmbracelet/x/conpty v0.1.0 
h1:4zc8KaIcbiL4mghEON8D72agYtSeIgq8FSThSPQIb+U=
@@ -64,8 +64,8 @@
 github.com/go-logr/stdr v1.2.2/go.mod 
h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
 github.com/go-openapi/analysis v0.23.0 
h1:aGday7OWupfMs+LbmLZG4k0MYXIANxcuBTYUC03zFCU=
 github.com/go-openapi/analysis v0.23.0/go.mod 
h1:9mz9ZWaSlV8TvjQHLl2mUW2PbZtemkE8yA5v22ohupo=
-github.com/go-openapi/errors v0.22.7 
h1:JLFBGC0Apwdzw3484MmBqspjPbwa2SHvpDm0u5aGhUA=
-github.com/go-openapi/errors v0.22.7/go.mod 
h1://QW6SD9OsWtH6gHllUCddOXDL0tk0ZGNYHwsw4sW3w=
+github.com/go-openapi/errors v0.22.8 
h1:oP7sW7TWc3wFFjrzzj0nI83H2qMBkNjNfSd+XRejk/I=
+github.com/go-openapi/errors v0.22.8/go.mod 
h1:BuUoHcYrU6E7V9gfj1I5wLQqgtIHnup/alXZ8KdgQ0w=
 github.com/go-openapi/jsonpointer v0.21.0 
h1:YgdVicSA9vH5RiHs9TZW5oyafXZFc6+2Vc1rr/O9oNQ=
 github.com/go-openapi/jsonpointer v0.21.0/go.mod 
h1:IUyH9l/+uyhIYQ/PXVA41Rexl+kOkAPDdXEYns6fzUY=
 github.com/go-openapi/jsonreference v0.21.0 
h1:Rs+Y7hSXT83Jacb7kFyjn4ijOuVGSvOdF2+tg1TRrwQ=
@@ -76,12 +76,12 @@
 github.com/go-openapi/runtime v0.28.0/go.mod 
h1:QN7OzcS+XuYmkQLw05akXk0jRH/eZ3kb18+1KwW9gyc=
 github.com/go-openapi/spec v0.21.0 
h1:LTVzPc3p/RzRnkQqLRndbAzjY0d0BCL72A6j3CdL9ZY=
 github.com/go-openapi/spec v0.21.0/go.mod 
h1:78u6VdPw81XU44qEWGhtr982gJ5BWg2c0I5XwVMotYk=
-github.com/go-openapi/strfmt v0.26.2 
h1:ysjheCh4i1rmFEo2LanhELDNucNzfWTZhUDKgWWPaFM=
-github.com/go-openapi/strfmt v0.26.2/go.mod 
h1:fXh1e449cyUn2NYuz+wb3wARBUdMl7qPEZwX00nqivY=
+github.com/go-openapi/strfmt v0.27.0 
h1:kbcTeaD9TXuXD0hhMXzuYa1sdTo6+dWGvwjW93E80IM=
+github.com/go-openapi/strfmt v0.27.0/go.mod 
h1:s/qhDqfY72irigXUGJmtgid2Rm+3tnz3k8hZaRmvWYc=
 github.com/go-openapi/swag v0.23.0 
h1:vsEVJDUo2hPJ2tu0/Xc+4noaxyEffXNIs3cOULZ+GrE=
 github.com/go-openapi/swag v0.23.0/go.mod 
h1:esZ8ITTYEsH1V2trKHjAN8Ai7xHb8RV+YSZ577vPjgQ=
-github.com/go-openapi/testify/v2 v2.4.2 
h1:tiByHpvE9uHrrKjOszax7ZvKB7QOgizBWGBLuq0ePx4=
-github.com/go-openapi/testify/v2 v2.4.2/go.mod 
h1:SgsVHtfooshd0tublTtJ50FPKhujf47YRqauXXOUxfw=
+github.com/go-openapi/testify/v2 v2.6.0 
h1:5PKH2HE7YJ/LuRPQGvSxBRlFXNQhSetBLlGAgUEu3ug=
+github.com/go-openapi/testify/v2 v2.6.0/go.mod 
h1:SgsVHtfooshd0tublTtJ50FPKhujf47YRqauXXOUxfw=
 github.com/go-openapi/validate v0.24.0 
h1:LdfDKwNbpB6Vn40xhTdNZAnfLECL81w+VX3BumrGD58=
 github.com/go-openapi/validate v0.24.0/go.mod 
h1:iyeX1sEufmv3nPbBdX3ieNviWnOZaJ1+zquzJEf2BAQ=
 github.com/go-viper/mapstructure/v2 v2.5.0 
h1:vM5IJoUAy3d7zRSVtIwQgBj7BiWtMPfmPEgAXnvj1Ro=
@@ -114,8 +114,8 @@
 github.com/mattn/go-isatty v0.0.20/go.mod 
h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
 github.com/mattn/go-localereader v0.0.1 
h1:ygSAOl7ZXTx4RdPYinUpg6W99U8jWvWi9Ye2JC/oIi4=
 github.com/mattn/go-localereader v0.0.1/go.mod 
h1:8fBrzywKY7BI3czFoHkuzRoWE9C+EiG4R1k4Cjx5p88=
-github.com/mattn/go-runewidth v0.0.23 
h1:7ykA0T0jkPpzSvMS5i9uoNn2Xy3R383f9HDx3RybWcw=
-github.com/mattn/go-runewidth v0.0.23/go.mod 
h1:XBkDxAl56ILZc9knddidhrOlY5R/pDhgLpndooCuJAs=
+github.com/mattn/go-runewidth v0.0.24 
h1:cpokDiIn0MGnhdHwuWnJBITySJ20QyNGnY2kR/ay2DU=
+github.com/mattn/go-runewidth v0.0.24/go.mod 
h1:XBkDxAl56ILZc9knddidhrOlY5R/pDhgLpndooCuJAs=
 github.com/mitchellh/hashstructure/v2 v2.0.2 
h1:vGKWl0YJqUNxE8d+h8f6NJLcCJrgbhC4NcD46KavDd4=
 github.com/mitchellh/hashstructure/v2 v2.0.2/go.mod 
h1:MG3aRVU/N29oo/V/IhBX8GR/zz4kQkprJgF2EVszyDE=
 github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 
h1:ZK8zHtRHOkbHy6Mmr5D264iyp3TiX5OmNcI5cIARiQI=
@@ -132,8 +132,6 @@
 github.com/pelletier/go-toml/v2 v2.2.4 
h1:mye9XuhQ6gvn5h28+VilKrrPoQVanw5PMw/TB0t5Ec4=
 github.com/pelletier/go-toml/v2 v2.2.4/go.mod 
h1:2gIqNv+qfxSVS7cM2xJQKtLSTLUE9V8t9Stt+h56mCY=
 github.com/pmezard/go-difflib v1.0.0/go.mod 
h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
-github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 
h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
-github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod 
h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
 github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ=
 github.com/rivo/uniseg v0.4.7/go.mod 
h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
 github.com/rogpeppe/go-internal v1.13.1 
h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII=
@@ -144,8 +142,8 @@
 github.com/sagikazarmark/locafero v0.11.0/go.mod 
h1:nVIGvgyzw595SUSUE6tvCp3YYTeHs15MvlmU87WwIik=
 github.com/sahilm/fuzzy v0.1.3 h1:juByESSS32nVD81vr6tHmKmA/8zde7gE+x5CLxrzXPU=
 github.com/sahilm/fuzzy v0.1.3/go.mod 
h1:au6//VbVSqu6DFrkL2CfjlJ5iURpNCPeE+1GwY3XsT8=
-github.com/sirupsen/logrus v1.9.4 
h1:TsZE7l11zFCLZnZ+teH4Umoq5BhEIfIzfRDZ1Uzql2w=
-github.com/sirupsen/logrus v1.9.4/go.mod 
h1:ftWc9WdOfJ0a92nsE2jF5u5ZwH8Bv2zdeOC42RjbV2g=
+github.com/sirupsen/logrus v1.10.2 
h1:G2SED73/qrAu6YwbdxOD6peLkCBI3z7L+ykJFTXJBBo=
+github.com/sirupsen/logrus v1.10.2/go.mod 
h1:SLEg8TqYulVKKfIGHldVp2K2aYz2DKSVBq4g/H5bR7Q=
 github.com/sourcegraph/conc v0.3.1-0.20240121214520-5f936abd7ae8 
h1:+jumHNA0Wrelhe64i8F6HNlS8pkoyMv5sreGx2Ry5Rw=
 github.com/sourcegraph/conc v0.3.1-0.20240121214520-5f936abd7ae8/go.mod 
h1:3n1Cwaq1E1/1lhQhtRK2ts/ZwZEhjcQeJQ1RuC6Q/8U=
 github.com/spf13/afero v1.15.0 h1:b/YBCLWAJdFWJTN9cLhiXXcD7mzKn9Dm86dNnfyQw1I=
@@ -160,11 +158,11 @@
 github.com/spf13/viper v1.21.0 h1:x5S+0EU27Lbphp4UKm1C+1oQO+rKx36vfCoaVebLFSU=
 github.com/spf13/viper v1.21.0/go.mod 
h1:P0lhsswPGWD/1lZJ9ny3fYnVqxiegrlNrEmgLjbTCAY=
 github.com/stretchr/objx v0.1.0/go.mod 
h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
-github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY=
-github.com/stretchr/objx v0.5.2/go.mod 
h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
+github.com/stretchr/objx v0.5.3 h1:jmXUvGomnU1o3W/V5h2VEradbpJDwGrzugQQvL0POH4=
+github.com/stretchr/objx v0.5.3/go.mod 
h1:rDQraq+vQZU7Fde9LOZLr8Tax6zZvy4kuNKF+QYS+U0=
 github.com/stretchr/testify v1.3.0/go.mod 
h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
-github.com/stretchr/testify v1.11.1 
h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
-github.com/stretchr/testify v1.11.1/go.mod 
h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
+github.com/stretchr/testify v1.12.1 
h1:EuwCh5fleGS7H32xRwO3wRGT7DxrDhLAT6FF8MpWDWE=
+github.com/stretchr/testify v1.12.1/go.mod 
h1:MDEgiDPPsNp5cuIrHPPCyornHKgEVbtFUmoNlxoYthg=
 github.com/subosito/gotenv v1.6.0 
h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8=
 github.com/subosito/gotenv v1.6.0/go.mod 
h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU=
 github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e 
h1:JVG44RsyaB9T2KIHavMF/ppJZNG9ZpyihvCd0w101no=
@@ -181,24 +179,25 @@
 go.opentelemetry.io/otel/sdk v1.35.0/go.mod 
h1:+ga1bZliga3DxJ3CQGg3updiaAJoNECOgJREo9KHGQg=
 go.opentelemetry.io/otel/trace v1.35.0 
h1:dPpEfJu1sDIqruz7BHFG3c7528f6ddfSWfFDVt/xgMs=
 go.opentelemetry.io/otel/trace v1.35.0/go.mod 
h1:WUk7DtFp1Aw2MkvqGdwiXYDZZNvA/1J8o6xRXLrIkyc=
-go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc=
 go.yaml.in/yaml/v3 v3.0.4/go.mod 
h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg=
-go.yaml.in/yaml/v4 v4.0.0-rc.4 h1:UP4+v6fFrBIb1l934bDl//mmnoIZEDK0idg1+AIvX5U=
-go.yaml.in/yaml/v4 v4.0.0-rc.4/go.mod 
h1:aZqd9kCMsGL7AuUv/m/PvWLdg5sjJsZ4oHDEnfPPfY0=
+go.yaml.in/yaml/v3 v3.0.5 h1:N6y/pJk8buWs9NY5ERU2HSMfm+IuD/OtfdAnq6kESPw=
+go.yaml.in/yaml/v3 v3.0.5/go.mod 
h1:HVTZu1O7/Vkt2N+BFy8Zza+lnLsABggaTM2ZpNIGuKg=
+go.yaml.in/yaml/v4 v4.0.0-rc.6 h1:1h7H1ohdUh93/FyE4YaDa1Zh64K6VVbjF4K6WUxMtH4=
+go.yaml.in/yaml/v4 v4.0.0-rc.6/go.mod 
h1:aZqd9kCMsGL7AuUv/m/PvWLdg5sjJsZ4oHDEnfPPfY0=
 golang.org/x/exp v0.0.0-20241217172543-b2144cdd0a67 
h1:1UoZQm6f0P/ZO0w1Ri+f+ifG/gXhegadRdwBIXEFWDo=
 golang.org/x/exp v0.0.0-20241217172543-b2144cdd0a67/go.mod 
h1:qj5a5QZpwLU2NLQudwIN5koi3beDhSAlJwa67PuM98c=
-golang.org/x/net v0.53.0 h1:d+qAbo5L0orcWAr0a9JweQpjXF19LMXJE8Ey7hwOdUA=
-golang.org/x/net v0.53.0/go.mod h1:JvMuJH7rrdiCfbeHoo3fCQU24Lf5JJwT9W3sJFulfgs=
-golang.org/x/sync v0.20.0 h1:e0PTpb7pjO8GAtTs2dQ6jYa5BWYlMuX047Dco/pItO4=
-golang.org/x/sync v0.20.0/go.mod 
h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0=
+golang.org/x/net v0.57.0 h1:K5+3DljvIuDG9/Jv9rvyMywYNFCQ9RSUY6OOTTkT+tE=
+golang.org/x/net v0.57.0/go.mod h1:KpXc8iv+r3XplLAG/f7Jsf9RPszJzdR0f58q9vGOuEU=
+golang.org/x/sync v0.22.0 h1:SZjpbeLmrCk4xhRSZFNZW5gFUeCeFgjekvI/+gfScek=
+golang.org/x/sync v0.22.0/go.mod 
h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0=
 golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod 
h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.46.0 h1:noSf2Fq6F8DBgS+LysIkx7rIExoNHJsxOAtPp4rthXw=
-golang.org/x/sys v0.46.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
-golang.org/x/term v0.44.0 h1:0rLvDRCtNj0gZkyIXhCyOb2OAzEhLVqc4B+hrsBhrmc=
-golang.org/x/term v0.44.0/go.mod 
h1:7ze4MdzUzLXpSAoFP1H0bOI9aXDqveSvatT5vKcFh2Y=
-golang.org/x/text v0.37.0 h1:Cqjiwd9eSg8e0QAkyCaQTNHFIIzWtidPahFWR83rTrc=
-golang.org/x/text v0.37.0/go.mod 
h1:a5sjxXGs9hsn/AJVwuElvCAo9v8QYLzvavO5z2PiM38=
+golang.org/x/sys v0.47.0 h1:o7XGOvZQCADBQQ4Y7VNq2dRWQR7JmOUW8Kxx4ZsNgWs=
+golang.org/x/sys v0.47.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
+golang.org/x/term v0.45.0 h1:NwWyBmoJCbfTHpxrWoZ9C6/VxOf7ic219I8xZZFdrf0=
+golang.org/x/term v0.45.0/go.mod 
h1:9aqxs0blBcrm/n0L9QW0aRVD+ktan8ssZromtqJC43w=
+golang.org/x/text v0.41.0 h1:vz/seA0lnX87Othu2f/0L24RcgrXD9/YFTSuGjj3rH8=
+golang.org/x/text v0.41.0/go.mod 
h1:jvf1O8ajNzZqhSrQBPbutR/EB83Cc0CFrezNQIwbb5M=
 gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod 
h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
 gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c 
h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
 gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod 
h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/harbor-cli-0.0.26/pkg/api/artifact_handler.go 
new/harbor-cli-0.0.27/pkg/api/artifact_handler.go
--- old/harbor-cli-0.0.26/pkg/api/artifact_handler.go   2026-08-18 
15:36:47.000000000 +0200
+++ new/harbor-cli-0.0.27/pkg/api/artifact_handler.go   2026-10-20 
15:28:52.000000000 +0200
@@ -32,7 +32,7 @@
 
        _, err = client.Artifact.DeleteArtifact(ctx, 
&artifact.DeleteArtifactParams{
                ProjectName:    projectName,
-               RepositoryName: repoName,
+               RepositoryName: encodeRepoName(repoName),
                Reference:      reference,
        })
        if err != nil {
@@ -54,7 +54,7 @@
 
        response, err = client.Artifact.GetArtifact(ctx, 
&artifact.GetArtifactParams{
                ProjectName:    projectName,
-               RepositoryName: repoName,
+               RepositoryName: encodeRepoName(repoName),
                Reference:      reference,
                WithLabel:      &withLabels,
        })
@@ -79,7 +79,7 @@
        }
        response, err := client.Artifact.ListArtifacts(ctx, 
&artifact.ListArtifactsParams{
                ProjectName:    projectName,
-               RepositoryName: repoName,
+               RepositoryName: encodeRepoName(repoName),
                Page:           &listFlags.Page,
                PageSize:       &listFlags.PageSize,
                Q:              &listFlags.Q,
@@ -101,7 +101,7 @@
 
        _, err = client.Scan.ScanArtifact(ctx, &scan.ScanArtifactParams{
                ProjectName:    projectName,
-               RepositoryName: repoName,
+               RepositoryName: encodeRepoName(repoName),
                Reference:      reference,
        })
        if err != nil {
@@ -122,7 +122,7 @@
 
        _, err = client.Scan.StopScanArtifact(ctx, &scan.StopScanArtifactParams{
                ProjectName:    projectName,
-               RepositoryName: repoName,
+               RepositoryName: encodeRepoName(repoName),
                Reference:      reference,
        })
        if err != nil {
@@ -143,7 +143,7 @@
 
        _, err = client.Artifact.DeleteTag(ctx, &artifact.DeleteTagParams{
                ProjectName:    projectName,
-               RepositoryName: repoName,
+               RepositoryName: encodeRepoName(repoName),
                Reference:      reference,
                TagName:        tag,
        })
@@ -165,7 +165,7 @@
 
        resp, err := client.Artifact.ListTags(ctx, &artifact.ListTagsParams{
                ProjectName:    projectName,
-               RepositoryName: repoName,
+               RepositoryName: encodeRepoName(repoName),
                Reference:      reference,
        })
 
@@ -185,7 +185,7 @@
        }
        _, err = client.Artifact.CreateTag(ctx, &artifact.CreateTagParams{
                ProjectName:    projectName,
-               RepositoryName: repoName,
+               RepositoryName: encodeRepoName(repoName),
                Reference:      reference,
                Tag: &models.Tag{
                        Name: tagName,
@@ -209,7 +209,7 @@
 
        response, err = client.Artifact.AddLabel(ctx, &artifact.AddLabelParams{
                ProjectName:    projectName,
-               RepositoryName: repoName,
+               RepositoryName: encodeRepoName(repoName),
                Reference:      reference,
                Label:          label,
        })
@@ -232,7 +232,7 @@
 
        response, err = client.Artifact.RemoveLabel(ctx, 
&artifact.RemoveLabelParams{
                ProjectName:    projectName,
-               RepositoryName: repoName,
+               RepositoryName: encodeRepoName(repoName),
                Reference:      reference,
                LabelID:        labelID,
        })
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/harbor-cli-0.0.26/pkg/api/quota_handler.go 
new/harbor-cli-0.0.27/pkg/api/quota_handler.go
--- old/harbor-cli-0.0.26/pkg/api/quota_handler.go      2026-08-18 
15:36:47.000000000 +0200
+++ new/harbor-cli-0.0.27/pkg/api/quota_handler.go      2026-10-20 
15:28:52.000000000 +0200
@@ -133,5 +133,5 @@
                id, _ := refMap["id"]
                return fmt.Sprintf("%v", id), nil
        }
-       return "", fmt.Errorf("Error: Ref is not of expected type")
+       return "", fmt.Errorf("error: Ref is not of expected type")
 }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/harbor-cli-0.0.26/pkg/api/repository_handler.go 
new/harbor-cli-0.0.27/pkg/api/repository_handler.go
--- old/harbor-cli-0.0.26/pkg/api/repository_handler.go 2026-08-18 
15:36:47.000000000 +0200
+++ new/harbor-cli-0.0.27/pkg/api/repository_handler.go 2026-10-20 
15:28:52.000000000 +0200
@@ -15,6 +15,7 @@
 
 import (
        "fmt"
+       "net/url"
 
        "github.com/goharbor/go-client/pkg/sdk/v2.0/client/repository"
        "github.com/goharbor/go-client/pkg/sdk/v2.0/client/search"
@@ -22,6 +23,13 @@
        "github.com/goharbor/harbor-cli/pkg/utils"
 )
 
+// encodeRepoName prepares a repository name for the repository_name path
+// parameter. Harbor expects a slash in it to be encoded twice
+// (a/b -> a%2Fb -> a%252Fb) and the client only encodes path parameters once.
+func encodeRepoName(repoName string) string {
+       return url.PathEscape(repoName)
+}
+
 func RepoDelete(projectNameOrID, repoName string, useProjectID bool) error {
        ctx, client, err := utils.ContextWithClient()
        if err != nil {
@@ -36,7 +44,7 @@
                }
                projectName = project.Payload.Name
        }
-       _, err = client.Repository.DeleteRepository(ctx, 
&repository.DeleteRepositoryParams{ProjectName: projectName, RepositoryName: 
repoName})
+       _, err = client.Repository.DeleteRepository(ctx, 
&repository.DeleteRepositoryParams{ProjectName: projectName, RepositoryName: 
encodeRepoName(repoName)})
 
        if err != nil {
                return err
@@ -53,7 +61,7 @@
                return response, err
        }
 
-       response, err = client.Repository.GetRepository(ctx, 
&repository.GetRepositoryParams{ProjectName: projectName, RepositoryName: 
repoName})
+       response, err = client.Repository.GetRepository(ctx, 
&repository.GetRepositoryParams{ProjectName: projectName, RepositoryName: 
encodeRepoName(repoName)})
 
        if err != nil {
                return response, err
@@ -129,7 +137,7 @@
 
        _, err = client.Repository.UpdateRepository(ctx, 
&repository.UpdateRepositoryParams{
                ProjectName:    projectName,
-               RepositoryName: repoName,
+               RepositoryName: encodeRepoName(repoName),
                Repository:     repo,
        })
        if err != nil {
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/harbor-cli-0.0.26/pkg/api/repository_handler_test.go 
new/harbor-cli-0.0.27/pkg/api/repository_handler_test.go
--- old/harbor-cli-0.0.26/pkg/api/repository_handler_test.go    1970-01-01 
01:00:00.000000000 +0100
+++ new/harbor-cli-0.0.27/pkg/api/repository_handler_test.go    2026-10-20 
15:28:52.000000000 +0200
@@ -0,0 +1,127 @@
+// Copyright Project Harbor Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+package api
+
+import (
+       "net/http"
+       "net/http/httptest"
+       "sync"
+       "testing"
+
+       "github.com/goharbor/go-client/pkg/harbor"
+       "github.com/goharbor/harbor-cli/pkg/utils"
+       "github.com/stretchr/testify/assert"
+)
+
+// useTestServer points the shared Harbor client at a local server that
+// records the escaped request path and answers with the given body. The
+// returned function reads the last recorded path.
+func useTestServer(t *testing.T, body string) func() string {
+       t.Helper()
+
+       var mu sync.Mutex
+       var gotPath string
+       srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, 
r *http.Request) {
+               mu.Lock()
+               gotPath = r.URL.EscapedPath()
+               mu.Unlock()
+               w.Header().Set("Content-Type", "application/json")
+               _, _ = w.Write([]byte(body))
+       }))
+
+       utils.ClientOnce = sync.Once{}
+       utils.ClientOnce.Do(func() {})
+       utils.ClientInstance = 
utils.GetClientByConfig(&harbor.ClientSetConfig{URL: srv.URL})
+       utils.ClientErr = nil
+
+       t.Cleanup(func() {
+               srv.Close()
+               utils.ClientOnce = sync.Once{}
+               utils.ClientInstance = nil
+               utils.ClientErr = nil
+       })
+
+       return func() string {
+               mu.Lock()
+               defer mu.Unlock()
+               return gotPath
+       }
+}
+
+// Harbor expects a slash in repository_name to be encoded twice
+// (a/b -> a%2Fb -> a%252Fb), otherwise the request does not reach the
+// repository handler when Harbor runs behind its nginx proxy.
+func TestRepositoryNameIsEncodedInPath(t *testing.T) {
+       tests := []struct {
+               name     string
+               body     string
+               call     func() error
+               wantPath string
+       }{
+               {
+                       name: "list artifacts of nested repository",
+                       body: "[]",
+                       call: func() error {
+                               _, err := ListArtifact("library", "team/app")
+                               return err
+                       },
+                       wantPath: 
"/api/v2.0/projects/library/repositories/team%252Fapp/artifacts",
+               },
+               {
+                       name: "view artifact of nested repository",
+                       body: "{}",
+                       call: func() error {
+                               _, err := ViewArtifact("library", "team/app", 
"latest", false)
+                               return err
+                       },
+                       wantPath: 
"/api/v2.0/projects/library/repositories/team%252Fapp/artifacts/latest",
+               },
+               {
+                       name: "list tags of nested repository",
+                       body: "[]",
+                       call: func() error {
+                               _, err := ListTags("library", "team/app", 
"latest")
+                               return err
+                       },
+                       wantPath: 
"/api/v2.0/projects/library/repositories/team%252Fapp/artifacts/latest/tags",
+               },
+               {
+                       name: "view nested repository",
+                       body: "{}",
+                       call: func() error {
+                               _, err := RepoView("library", "team/app")
+                               return err
+                       },
+                       wantPath: 
"/api/v2.0/projects/library/repositories/team%252Fapp",
+               },
+               {
+                       name: "list artifacts of single-level repository",
+                       body: "[]",
+                       call: func() error {
+                               _, err := ListArtifact("library", "nginx")
+                               return err
+                       },
+                       wantPath: 
"/api/v2.0/projects/library/repositories/nginx/artifacts",
+               },
+       }
+
+       for _, tt := range tests {
+               t.Run(tt.name, func(t *testing.T) {
+                       gotPath := useTestServer(t, tt.body)
+
+                       assert.NoError(t, tt.call())
+                       assert.Equal(t, tt.wantPath, gotPath())
+               })
+       }
+}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/harbor-cli-0.0.26/pkg/api/retention_handler.go 
new/harbor-cli-0.0.27/pkg/api/retention_handler.go
--- old/harbor-cli-0.0.26/pkg/api/retention_handler.go  2026-08-18 
15:36:47.000000000 +0200
+++ new/harbor-cli-0.0.27/pkg/api/retention_handler.go  2026-10-20 
15:28:52.000000000 +0200
@@ -114,7 +114,7 @@
        }
 
        if response.Payload.Metadata == nil || 
response.Payload.Metadata.RetentionID == nil {
-               return "", errors.New("No retention policy exists for this 
project")
+               return "", errors.New("no retention policy exists for this 
project")
        }
        retentionid := *response.Payload.Metadata.RetentionID
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/harbor-cli-0.0.26/pkg/api/types_test.go 
new/harbor-cli-0.0.27/pkg/api/types_test.go
--- old/harbor-cli-0.0.26/pkg/api/types_test.go 1970-01-01 01:00:00.000000000 
+0100
+++ new/harbor-cli-0.0.27/pkg/api/types_test.go 2026-10-20 15:28:52.000000000 
+0200
@@ -0,0 +1,139 @@
+// Copyright Project Harbor Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+package api_test
+
+import (
+       "testing"
+
+       "github.com/goharbor/harbor-cli/pkg/api"
+       "github.com/stretchr/testify/assert"
+)
+
+// TestListFlags validates the ListFlags structure for proper pagination 
defaults
+func TestListFlags(t *testing.T) {
+       t.Run("default values", func(t *testing.T) {
+               var flags api.ListFlags
+
+               assert.Equal(t, int64(0), flags.ProjectID)
+               assert.Equal(t, int64(0), flags.Page)
+               assert.Equal(t, int64(0), flags.PageSize)
+               assert.Equal(t, "", flags.Scope)
+               assert.Equal(t, "", flags.Name)
+               assert.Equal(t, "", flags.Q)
+               assert.Equal(t, "", flags.Sort)
+               assert.False(t, flags.Public)
+       })
+
+       t.Run("custom pagination", func(t *testing.T) {
+               flags := api.ListFlags{
+                       ProjectID: 10,
+                       Page:      1,
+                       PageSize:  50,
+                       Scope:     "project",
+                       Name:      "test",
+                       Q:         "admin",
+                       Sort:      "name",
+                       Public:    true,
+               }
+
+               assert.Equal(t, int64(10), flags.ProjectID)
+               assert.Equal(t, int64(1), flags.Page)
+               assert.Equal(t, int64(50), flags.PageSize)
+               assert.Equal(t, "project", flags.Scope)
+               assert.Equal(t, "test", flags.Name)
+               assert.Equal(t, "admin", flags.Q)
+               assert.Equal(t, "name", flags.Sort)
+               assert.True(t, flags.Public)
+       })
+}
+
+// TestListMemberOptions validates member listing options structure
+func TestListMemberOptions(t *testing.T) {
+       t.Run("valid member options", func(t *testing.T) {
+               opts := api.ListMemberOptions{
+                       XIsResourceName: true,
+                       ProjectNameOrID: "library",
+                       EntityName:      "testuser",
+                       Page:            1,
+                       PageSize:        10,
+               }
+
+               assert.True(t, opts.XIsResourceName)
+               assert.Equal(t, "library", opts.ProjectNameOrID)
+               assert.Equal(t, "testuser", opts.EntityName)
+               assert.Equal(t, int64(1), opts.Page)
+               assert.Equal(t, int64(10), opts.PageSize)
+       })
+
+       t.Run("project by ID vs name", func(t *testing.T) {
+               byName := api.ListMemberOptions{
+                       XIsResourceName: true,
+                       ProjectNameOrID: "my-project",
+               }
+
+               byID := api.ListMemberOptions{
+                       XIsResourceName: false,
+                       ProjectNameOrID: "123",
+               }
+
+               assert.True(t, byName.XIsResourceName)
+               assert.Equal(t, "my-project", byName.ProjectNameOrID)
+               assert.False(t, byID.XIsResourceName)
+               assert.Equal(t, "123", byID.ProjectNameOrID)
+       })
+}
+
+// TestUpdateMemberOptions validates member update options structure
+func TestUpdateMemberOptions(t *testing.T) {
+       t.Run("valid update options", func(t *testing.T) {
+               opts := api.UpdateMemberOptions{
+                       XIsResourceName: true,
+                       ProjectNameOrID: "library",
+                       ID:              123,
+                       RoleID:          nil,
+               }
+
+               assert.True(t, opts.XIsResourceName)
+               assert.Equal(t, "library", opts.ProjectNameOrID)
+               assert.Equal(t, int64(123), opts.ID)
+               assert.Nil(t, opts.RoleID)
+       })
+}
+
+// TestGetMemberOptions validates member retrieval options structure
+func TestGetMemberOptions(t *testing.T) {
+       t.Run("get member by ID", func(t *testing.T) {
+               opts := api.GetMemberOptions{
+                       XIsResourceName: false,
+                       ProjectNameOrID: "42",
+                       ID:              100,
+               }
+
+               assert.False(t, opts.XIsResourceName)
+               assert.Equal(t, "42", opts.ProjectNameOrID)
+               assert.Equal(t, int64(100), opts.ID)
+       })
+
+       t.Run("get member by name", func(t *testing.T) {
+               opts := api.GetMemberOptions{
+                       XIsResourceName: true,
+                       ProjectNameOrID: "test-project",
+                       ID:              200,
+               }
+
+               assert.True(t, opts.XIsResourceName)
+               assert.Equal(t, "test-project", opts.ProjectNameOrID)
+               assert.Equal(t, int64(200), opts.ID)
+       })
+}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/harbor-cli-0.0.26/pkg/views/base/selection/model.go 
new/harbor-cli-0.0.27/pkg/views/base/selection/model.go
--- old/harbor-cli-0.0.26/pkg/views/base/selection/model.go     2026-08-18 
15:36:47.000000000 +0200
+++ new/harbor-cli-0.0.27/pkg/views/base/selection/model.go     2026-10-20 
15:28:52.000000000 +0200
@@ -83,6 +83,15 @@
 
        case tea.KeyMsg:
                switch keypress := msg.String(); keypress {
+               case "ctrl+c":
+                       m.Aborted = true
+                       return m, tea.Quit
+               case "q", "esc":
+                       if m.List.FilterState() == list.Filtering {
+                               break // let the list handle it (esc exits 
filter mode, q types "q")
+                       }
+                       m.Aborted = true
+                       return m, tea.Quit
                case "enter":
                        if m.List.FilterState() != list.Filtering {
                                i, ok := m.List.SelectedItem().(Item)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/harbor-cli-0.0.26/pkg/views/member/create/view.go 
new/harbor-cli-0.0.27/pkg/views/member/create/view.go
--- old/harbor-cli-0.0.26/pkg/views/member/create/view.go       2026-08-18 
15:36:47.000000000 +0200
+++ new/harbor-cli-0.0.27/pkg/views/member/create/view.go       2026-10-20 
15:28:52.000000000 +0200
@@ -88,7 +88,7 @@
                                Value(&createView.MemberUser.Username).
                                Validate(func(str string) error {
                                        if str == "" {
-                                               return errors.New("Username 
cannot be empty.")
+                                               return errors.New("username 
cannot be empty.")
                                        }
 
                                        if !utils.ValidateUserName(str) {
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/harbor-cli-0.0.26/pkg/views/quota/list/view.go 
new/harbor-cli-0.0.27/pkg/views/quota/list/view.go
--- old/harbor-cli-0.0.26/pkg/views/quota/list/view.go  2026-08-18 
15:36:47.000000000 +0200
+++ new/harbor-cli-0.0.27/pkg/views/quota/list/view.go  2026-10-20 
15:28:52.000000000 +0200
@@ -40,7 +40,7 @@
                ownerName, _ := refMap["owner_name"].(string)
                return projectName, ownerName, nil
        }
-       return "", "", fmt.Errorf("Error: Ref is not of expected type")
+       return "", "", fmt.Errorf("error: Ref is not of expected type")
 }
 
 // Function to convert bytes to human-readable storage format

++++++ harbor-cli.obsinfo ++++++
--- /var/tmp/diff_new_pack.ozrnmU/_old  2026-10-21 20:59:46.645743304 +0200
+++ /var/tmp/diff_new_pack.ozrnmU/_new  2026-10-21 20:59:46.651743556 +0200
@@ -1,5 +1,5 @@
 name: harbor-cli
-version: 0.0.26
-mtime: 1787060207
-commit: 8c20d16b2f19adaa1c3b5fa7a6113c09938f65bd
+version: 0.0.27
+mtime: 1792502932
+commit: 1af93ace562d69b2293fa71733d4a4f5bb3c1503
 

++++++ vendor.tar.gz ++++++
++++ 67931 lines of diff (skipped)

Reply via email to