Skip to content

Commit d8d1289

Browse files
rizul2108Copilotbupd
authored
Refactor: Make Error logging more user friendly for project commands (#424)
* fix error logging in project command Signed-off-by: Rizul Gupta <mail2rizul@gmail.com> * add logrus debug for verbose flag Signed-off-by: Rizul Gupta <mail2rizul@gmail.com> * lint fixes Signed-off-by: Rizul Gupta <mail2rizul@gmail.com> * code fixes Signed-off-by: Rizul Gupta <mail2rizul@gmail.com> * add verbose for list cmd Signed-off-by: Rizul Gupta <mail2rizul@gmail.com> * add verbose for llogs cmd Signed-off-by: Rizul Gupta <mail2rizul@gmail.com> * Update cmd/harbor/root/project/create.go Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Signed-off-by: Rizul Gupta <112455393+rizul2108@users.noreply.github.com> * fix project create Signed-off-by: Rizul Gupta <mail2rizul@gmail.com> * Update cmd/harbor/root/project/create.go Co-authored-by: Prasanth Baskar <bupdprasanth@gmail.com> Signed-off-by: Rizul Gupta <112455393+rizul2108@users.noreply.github.com> * implement change Signed-off-by: Rizul Gupta <mail2rizul@gmail.com> * disable logrus totally for non-verbose Signed-off-by: Rizul Gupta <mail2rizul@gmail.com> * handle prompt user aborting and deletion errors Signed-off-by: Rizul Gupta <mail2rizul@gmail.com> * fmt fix Signed-off-by: Rizul Gupta <mail2rizul@gmail.com> * Update cmd/harbor/root/tag/immutable/list.go Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Signed-off-by: Rizul Gupta <112455393+rizul2108@users.noreply.github.com> * lint fix Signed-off-by: Rizul Gupta <mail2rizul@gmail.com> * lint fix Signed-off-by: Rizul Gupta <mail2rizul@gmail.com> lint fix Signed-off-by: Rizul Gupta <mail2rizul@gmail.com> * Update cmd/harbor/root/artifact/view.go Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Signed-off-by: Rizul Gupta <112455393+rizul2108@users.noreply.github.com> * small fixes Signed-off-by: Rizul Gupta <mail2rizul@gmail.com> * lint fixes Signed-off-by: Rizul Gupta <mail2rizul@gmail.com> --------- Signed-off-by: Rizul Gupta <mail2rizul@gmail.com> Signed-off-by: Rizul Gupta <112455393+rizul2108@users.noreply.github.com> Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Co-authored-by: Prasanth Baskar <bupdprasanth@gmail.com>
1 parent 97c20c0 commit d8d1289

25 files changed

Lines changed: 429 additions & 143 deletions

File tree

cmd/harbor/root/artifact/delete.go

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -28,17 +28,18 @@ func DeleteArtifactCommand() *cobra.Command {
2828
Args: cobra.MaximumNArgs(1),
2929
Run: func(cmd *cobra.Command, args []string) {
3030
var err error
31-
31+
var projectName, repoName, reference string
3232
if len(args) > 0 {
33-
projectName, repoName, reference := utils.ParseProjectRepoReference(args[0])
34-
err = api.DeleteArtifact(projectName, repoName, reference)
33+
projectName, repoName, reference = utils.ParseProjectRepoReference(args[0])
3534
} else {
36-
projectName := prompt.GetProjectNameFromUser()
37-
repoName := prompt.GetRepoNameFromUser(projectName)
38-
reference := prompt.GetReferenceFromUser(repoName, projectName)
39-
err = api.DeleteArtifact(projectName, repoName, reference)
35+
projectName, err = prompt.GetProjectNameFromUser()
36+
if err != nil {
37+
log.Errorf("failed to get project name: %v", utils.ParseHarborErrorMsg(err))
38+
}
39+
repoName = prompt.GetRepoNameFromUser(projectName)
40+
reference = prompt.GetReferenceFromUser(repoName, projectName)
4041
}
41-
42+
err = api.DeleteArtifact(projectName, repoName, reference)
4243
if err != nil {
4344
log.Errorf("failed to delete an artifact: %v", err)
4445
}

cmd/harbor/root/artifact/list.go

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,10 @@ Supports pagination, search queries, and sorting using flags.`,
5353
if len(args) > 0 {
5454
projectName, repoName = utils.ParseProjectRepo(args[0])
5555
} else {
56-
projectName = prompt.GetProjectNameFromUser()
56+
projectName, err = prompt.GetProjectNameFromUser()
57+
if err != nil {
58+
return fmt.Errorf("failed to get project name: %v", utils.ParseHarborErrorMsg(err))
59+
}
5760
repoName = prompt.GetRepoNameFromUser(projectName)
5861
}
5962

cmd/harbor/root/artifact/scan.go

Lines changed: 20 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -46,16 +46,19 @@ func StartScanArtifactCommand() *cobra.Command {
4646
Example: `harbor artifact scan start <project>/<repository>/<reference>`,
4747
Run: func(cmd *cobra.Command, args []string) {
4848
var err error
49+
var projectName, repoName, reference string
4950

5051
if len(args) > 0 {
51-
projectName, repoName, reference := utils.ParseProjectRepoReference(args[0])
52-
err = api.StartScanArtifact(projectName, repoName, reference)
52+
projectName, repoName, reference = utils.ParseProjectRepoReference(args[0])
5353
} else {
54-
projectName := prompt.GetProjectNameFromUser()
55-
repoName := prompt.GetRepoNameFromUser(projectName)
56-
reference := prompt.GetReferenceFromUser(repoName, projectName)
57-
err = api.StartScanArtifact(projectName, repoName, reference)
54+
projectName, err = prompt.GetProjectNameFromUser()
55+
if err != nil {
56+
log.Errorf("failed to get project name: %v", utils.ParseHarborErrorMsg(err))
57+
}
58+
repoName = prompt.GetRepoNameFromUser(projectName)
59+
reference = prompt.GetReferenceFromUser(repoName, projectName)
5860
}
61+
err = api.StartScanArtifact(projectName, repoName, reference)
5962
if err != nil {
6063
log.Errorf("failed to start scan of artifact: %v", err)
6164
}
@@ -72,16 +75,21 @@ func StopScanArtifactCommand() *cobra.Command {
7275
Example: `harbor artifact scan stop <project>/<repository>/<reference>`,
7376
Run: func(cmd *cobra.Command, args []string) {
7477
var err error
78+
var projectName, repoName, reference string
7579

7680
if len(args) > 0 {
77-
projectName, repoName, reference := utils.ParseProjectRepoReference(args[0])
78-
err = api.StopScanArtifact(projectName, repoName, reference)
81+
projectName, repoName, reference = utils.ParseProjectRepoReference(args[0])
7982
} else {
80-
projectName := prompt.GetProjectNameFromUser()
81-
repoName := prompt.GetRepoNameFromUser(projectName)
82-
reference := prompt.GetReferenceFromUser(repoName, projectName)
83-
err = api.StopScanArtifact(projectName, repoName, reference)
83+
var projectName string
84+
projectName, err = prompt.GetProjectNameFromUser()
85+
if err != nil {
86+
log.Errorf("failed to get project name: %v", utils.ParseHarborErrorMsg(err))
87+
}
88+
repoName = prompt.GetRepoNameFromUser(projectName)
89+
reference = prompt.GetReferenceFromUser(repoName, projectName)
8490
}
91+
92+
err = api.StopScanArtifact(projectName, repoName, reference)
8593
if err != nil {
8694
log.Errorf("failed to stop scan of artifact: %v", err)
8795
}

cmd/harbor/root/artifact/tags.go

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,11 @@ func CreateTagsCmd() *cobra.Command {
5555
err = api.CreateTag(projectName, repoName, reference, tag)
5656
} else {
5757
var tagName string
58-
projectName := prompt.GetProjectNameFromUser()
58+
var projectName string
59+
projectName, err = prompt.GetProjectNameFromUser()
60+
if err != nil {
61+
log.Errorf("failed to get project name: %v", utils.ParseHarborErrorMsg(err))
62+
}
5963
repoName := prompt.GetRepoNameFromUser(projectName)
6064
reference := prompt.GetReferenceFromUser(repoName, projectName)
6165
create.CreateTagView(&tagName)
@@ -83,7 +87,10 @@ func ListTagsCmd() *cobra.Command {
8387
if len(args) > 0 {
8488
projectName, repoName, reference = utils.ParseProjectRepoReference(args[0])
8589
} else {
86-
projectName = prompt.GetProjectNameFromUser()
90+
projectName, err = prompt.GetProjectNameFromUser()
91+
if err != nil {
92+
log.Errorf("failed to get project name: %v", utils.ParseHarborErrorMsg(err))
93+
}
8794
repoName = prompt.GetRepoNameFromUser(projectName)
8895
reference = prompt.GetReferenceFromUser(repoName, projectName)
8996
}
@@ -124,7 +131,11 @@ func DeleteTagsCmd() *cobra.Command {
124131
tag := args[1]
125132
err = api.DeleteTag(projectName, repoName, reference, tag)
126133
} else {
127-
projectName := prompt.GetProjectNameFromUser()
134+
var projectName string
135+
projectName, err = prompt.GetProjectNameFromUser()
136+
if err != nil {
137+
log.Errorf("failed to get project name: %v", utils.ParseHarborErrorMsg(err))
138+
}
128139
repoName := prompt.GetRepoNameFromUser(projectName)
129140
reference := prompt.GetReferenceFromUser(repoName, projectName)
130141
tag := prompt.GetTagFromUser(repoName, projectName, reference)

cmd/harbor/root/artifact/view.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,11 @@ func ViewArtifactCommmand() *cobra.Command {
3838
if len(args) > 0 {
3939
projectName, repoName, reference = utils.ParseProjectRepoReference(args[0])
4040
} else {
41-
projectName = prompt.GetProjectNameFromUser()
41+
projectName, err = prompt.GetProjectNameFromUser()
42+
if err != nil {
43+
log.Errorf("failed to get project name: %v", utils.ParseHarborErrorMsg(err))
44+
return
45+
}
4246
repoName = prompt.GetRepoNameFromUser(projectName)
4347
reference = prompt.GetReferenceFromUser(repoName, projectName)
4448
}

cmd/harbor/root/cmd.go

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ package root
1515

1616
import (
1717
"fmt"
18+
"io"
1819
"time"
1920

2021
"github.com/goharbor/harbor-cli/cmd/harbor/root/artifact"
@@ -60,17 +61,16 @@ harbor help
6061
utils.InitConfig(cfgFile, userSpecifiedConfig)
6162

6263
// Conditionally set the timestamp format only in verbose mode
64+
formatter := &logrus.TextFormatter{}
65+
6366
if verbose {
64-
logrus.SetFormatter(&logrus.TextFormatter{
65-
FullTimestamp: true,
66-
TimestampFormat: time.RFC3339,
67-
})
67+
formatter.FullTimestamp = true
68+
formatter.TimestampFormat = time.RFC3339
69+
logrus.SetLevel(logrus.DebugLevel)
6870
} else {
69-
// No timestamp format for non-verbose
70-
logrus.SetFormatter(&logrus.TextFormatter{
71-
DisableTimestamp: true,
72-
})
71+
logrus.SetOutput(io.Discard)
7372
}
73+
logrus.SetFormatter(formatter)
7474

7575
return nil
7676
},

cmd/harbor/root/project/create.go

Lines changed: 33 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,10 @@
1414
package project
1515

1616
import (
17+
"fmt"
18+
1719
"github.com/goharbor/harbor-cli/pkg/api"
20+
"github.com/goharbor/harbor-cli/pkg/utils"
1821
"github.com/goharbor/harbor-cli/pkg/views/project/create"
1922
log "github.com/sirupsen/logrus"
2023
"github.com/spf13/cobra"
@@ -28,32 +31,42 @@ func CreateProjectCommand() *cobra.Command {
2831
Use: "create [project name]",
2932
Short: "create project",
3033
Args: cobra.MaximumNArgs(1),
31-
Run: func(cmd *cobra.Command, args []string) {
34+
RunE: func(cmd *cobra.Command, args []string) error {
3235
var err error
33-
createView := &create.CreateView{
34-
ProjectName: opts.ProjectName,
35-
Public: opts.Public,
36-
RegistryID: opts.RegistryID,
37-
StorageLimit: opts.StorageLimit,
38-
ProxyCache: false,
39-
}
36+
var ProjectName string
4037
if len(args) > 0 {
4138
opts.ProjectName = args[0]
39+
}
4240

43-
if opts.ProxyCache && opts.RegistryID == "" {
44-
log.Errorf("Use the --registry-id flag with a registry ID")
45-
} else {
46-
err = api.CreateProject(opts)
47-
}
41+
if opts.ProxyCache && opts.RegistryID == "" {
42+
return fmt.Errorf("Error: Proxy cache selected but no registry ID provided. Use --registry-id.")
43+
}
44+
45+
if opts.ProjectName != "" {
46+
log.Debug("Attempting to create project using flags...")
47+
err = api.CreateProject(opts)
48+
ProjectName = opts.ProjectName
4849
} else {
50+
log.Debug("No project name provided. Switching to interactive view...")
51+
createView := &create.CreateView{
52+
ProjectName: opts.ProjectName,
53+
Public: opts.Public,
54+
RegistryID: opts.RegistryID,
55+
StorageLimit: opts.StorageLimit,
56+
ProxyCache: opts.ProxyCache,
57+
}
58+
4959
err = createProjectView(createView)
60+
ProjectName = createView.ProjectName
5061
}
5162

5263
if err != nil {
53-
log.Errorf("failed to create project: %v", err)
64+
return fmt.Errorf("failed to create project: %v", utils.ParseHarborErrorMsg(err))
5465
}
55-
},
56-
}
66+
67+
fmt.Printf("Project '%s' created successfully\n", ProjectName)
68+
return nil
69+
}}
5770

5871
flags := cmd.Flags()
5972
flags.BoolVarP(&opts.Public, "public", "", false, "Project is public or private")
@@ -74,7 +87,9 @@ func createProjectView(createView *create.CreateView) error {
7487
}
7588
}
7689

77-
create.CreateProjectView(createView)
78-
90+
err := create.CreateProjectView(createView)
91+
if err != nil {
92+
return err
93+
}
7994
return api.CreateProject(*createView)
8095
}

cmd/harbor/root/project/delete.go

Lines changed: 70 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -14,70 +14,115 @@
1414
package project
1515

1616
import (
17+
"fmt"
18+
"strconv"
1719
"sync"
1820

1921
"github.com/goharbor/harbor-cli/pkg/api"
2022
"github.com/goharbor/harbor-cli/pkg/prompt"
23+
"github.com/goharbor/harbor-cli/pkg/utils"
2124
log "github.com/sirupsen/logrus"
2225
"github.com/spf13/cobra"
2326
)
2427

25-
// DeleteProjectCommand creates a new `harbor project delete` command
28+
// DeleteProjectCommand creates a new `harbor delete project` command
2629
func DeleteProjectCommand() *cobra.Command {
2730
var forceDelete bool
2831
var projectID string
2932

3033
cmd := &cobra.Command{
3134
Use: "delete",
3235
Short: "Delete project by name or ID",
33-
Example: "harbor project delete [projectname] or harbor project delete --project-id [projectid]",
34-
Long: "Delete project by name or ID. If no arguments are provided, it will prompt for the project name. Use --project-id to specify the project ID directly. The --force flag will delete all repositories and artifacts within the project.",
35-
Args: cobra.MaximumNArgs(1),
36-
Run: func(cmd *cobra.Command, args []string) {
36+
Example: "harbor project delete [projectname1] [projectname2] or harbor project delete --project-id [projectid]",
37+
Long: "Delete project by name or ID. Multiple projects can be deleted by providing their names as arguments. If no arguments are provided, it will prompt for the project name. Use --project-id to specify the project ID for single project directly. The --force flag will delete all repositories and artifacts within the project.",
38+
Args: cobra.MinimumNArgs(0),
39+
RunE: func(cmd *cobra.Command, args []string) error {
3740
var wg sync.WaitGroup
38-
errChan := make(chan error, len(args))
41+
var mu sync.Mutex
42+
43+
successfulDeletes := []string{}
44+
failedDeletes := map[string]string{}
45+
46+
if projectID != "" {
47+
if len(args) > 0 {
48+
return fmt.Errorf("--project-id cannot be used with additional arguments")
49+
}
50+
if _, err := strconv.Atoi(projectID); err != nil {
51+
return fmt.Errorf("--project-id must be a numeric value")
52+
}
53+
}
3954

4055
if projectID != "" {
56+
log.Debugf("Deleting project with ID: %s", projectID)
4157
wg.Add(1)
4258
go func(id string) {
4359
defer wg.Done()
4460
if err := api.DeleteProject(id, forceDelete, true); err != nil {
45-
errChan <- err
61+
mu.Lock()
62+
failedDeletes[id] = utils.ParseHarborErrorMsg(err)
63+
mu.Unlock()
64+
} else {
65+
mu.Lock()
66+
successfulDeletes = append(successfulDeletes, id)
67+
mu.Unlock()
4668
}
4769
}(projectID)
4870
} else if len(args) > 0 {
71+
// Delete by project name from args
72+
log.Debugf("Deleting %d projects from args...", len(args))
4973
for _, projectName := range args {
74+
pn := projectName
75+
log.Debugf("Initiating delete for project: %s", pn)
5076
wg.Add(1)
51-
go func(name string) {
77+
go func(projectName string) {
5278
defer wg.Done()
53-
if err := api.DeleteProject(name, forceDelete, false); err != nil {
54-
errChan <- err
79+
log.Debugf("Deleting project '%s' with force=%v", projectName, forceDelete)
80+
if err := api.DeleteProject(projectName, forceDelete, false); err != nil {
81+
mu.Lock()
82+
failedDeletes[projectName] = utils.ParseHarborErrorMsg(err)
83+
mu.Unlock()
84+
} else {
85+
mu.Lock()
86+
successfulDeletes = append(successfulDeletes, projectName)
87+
mu.Unlock()
5588
}
56-
}(projectName)
89+
}(pn)
5790
}
5891
} else {
59-
projectName := prompt.GetProjectNameFromUser()
92+
// If no arguments provided, prompt user for project name
93+
log.Debug("No arguments provided. Prompting user for project name.")
94+
projectName, err := prompt.GetProjectNameFromUser()
95+
if err != nil {
96+
return fmt.Errorf("failed to get project name: %v", utils.ParseHarborErrorMsg(err))
97+
}
98+
log.Debugf("User input project: %s", projectName)
99+
log.Debugf("Deleting project '%s' with force=%v", projectName, forceDelete)
60100
if err := api.DeleteProject(projectName, forceDelete, false); err != nil {
61-
log.Errorf("failed to delete project: %v", err)
101+
return fmt.Errorf("failed to delete project: %v", utils.ParseHarborErrorMsg(err))
62102
}
103+
fmt.Printf("Project '%s' deleted successfully\n", projectName)
104+
return nil
63105
}
64106

65-
go func() {
66-
wg.Wait()
67-
close(errChan)
68-
}()
107+
wg.Wait()
69108

70-
var finalErr error
71-
for err := range errChan {
72-
if finalErr == nil {
73-
finalErr = err
74-
} else {
75-
log.Errorf("Error: %v", err)
109+
if len(successfulDeletes) > 0 {
110+
fmt.Println("Successfully deleted projects:")
111+
for _, name := range successfulDeletes {
112+
fmt.Printf(" - %s\n", name)
76113
}
77114
}
78-
if finalErr != nil {
79-
log.Errorf("failed to delete some projects: %v", finalErr)
115+
116+
if len(failedDeletes) > 0 {
117+
fmt.Println("Failed to delete projects:")
118+
for name, reason := range failedDeletes {
119+
fmt.Printf(" - %s: %s\n", name, reason)
120+
}
121+
return fmt.Errorf("failed to delete %d project(s)", len(failedDeletes))
80122
}
123+
124+
log.Debug("All requested projects deleted successfully.")
125+
return nil
81126
},
82127
}
83128

0 commit comments

Comments
 (0)