|
14 | 14 | package project |
15 | 15 |
|
16 | 16 | import ( |
| 17 | + "fmt" |
| 18 | + "strconv" |
17 | 19 | "sync" |
18 | 20 |
|
19 | 21 | "github.com/goharbor/harbor-cli/pkg/api" |
20 | 22 | "github.com/goharbor/harbor-cli/pkg/prompt" |
| 23 | + "github.com/goharbor/harbor-cli/pkg/utils" |
21 | 24 | log "github.com/sirupsen/logrus" |
22 | 25 | "github.com/spf13/cobra" |
23 | 26 | ) |
24 | 27 |
|
25 | | -// DeleteProjectCommand creates a new `harbor project delete` command |
| 28 | +// DeleteProjectCommand creates a new `harbor delete project` command |
26 | 29 | func DeleteProjectCommand() *cobra.Command { |
27 | 30 | var forceDelete bool |
28 | 31 | var projectID string |
29 | 32 |
|
30 | 33 | cmd := &cobra.Command{ |
31 | 34 | Use: "delete", |
32 | 35 | 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 { |
37 | 40 | 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 | + } |
39 | 54 |
|
40 | 55 | if projectID != "" { |
| 56 | + log.Debugf("Deleting project with ID: %s", projectID) |
41 | 57 | wg.Add(1) |
42 | 58 | go func(id string) { |
43 | 59 | defer wg.Done() |
44 | 60 | 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() |
46 | 68 | } |
47 | 69 | }(projectID) |
48 | 70 | } else if len(args) > 0 { |
| 71 | + // Delete by project name from args |
| 72 | + log.Debugf("Deleting %d projects from args...", len(args)) |
49 | 73 | for _, projectName := range args { |
| 74 | + pn := projectName |
| 75 | + log.Debugf("Initiating delete for project: %s", pn) |
50 | 76 | wg.Add(1) |
51 | | - go func(name string) { |
| 77 | + go func(projectName string) { |
52 | 78 | 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() |
55 | 88 | } |
56 | | - }(projectName) |
| 89 | + }(pn) |
57 | 90 | } |
58 | 91 | } 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) |
60 | 100 | 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)) |
62 | 102 | } |
| 103 | + fmt.Printf("Project '%s' deleted successfully\n", projectName) |
| 104 | + return nil |
63 | 105 | } |
64 | 106 |
|
65 | | - go func() { |
66 | | - wg.Wait() |
67 | | - close(errChan) |
68 | | - }() |
| 107 | + wg.Wait() |
69 | 108 |
|
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) |
76 | 113 | } |
77 | 114 | } |
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)) |
80 | 122 | } |
| 123 | + |
| 124 | + log.Debug("All requested projects deleted successfully.") |
| 125 | + return nil |
81 | 126 | }, |
82 | 127 | } |
83 | 128 |
|
|
0 commit comments