Skip to content

Commit 60ad0bd

Browse files
rizul2108Copilotbupd
authored
feat: Add label sub-cmd in artifact cmd (goharbor#483)
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Co-authored-by: Prasanth Baskar <bupdprasanth@gmail.com>
1 parent 6caf59e commit 60ad0bd

27 files changed

Lines changed: 851 additions & 87 deletions

cmd/harbor/root/artifact/cmd.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
package artifact
1515

1616
import (
17+
"github.com/goharbor/harbor-cli/cmd/harbor/root/artifact/label"
1718
"github.com/spf13/cobra"
1819
)
1920

@@ -31,6 +32,7 @@ func Artifact() *cobra.Command {
3132
DeleteArtifactCommand(),
3233
ScanArtifactCommand(),
3334
ArtifactTagsCmd(),
35+
label.LabelsArtifactCommmand(),
3436
)
3537

3638
return cmd

cmd/harbor/root/artifact/delete.go

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

1616
import (
17+
"fmt"
18+
1719
"github.com/goharbor/harbor-cli/pkg/api"
1820
"github.com/goharbor/harbor-cli/pkg/prompt"
1921
"github.com/goharbor/harbor-cli/pkg/utils"
@@ -26,17 +28,13 @@ func DeleteArtifactCommand() *cobra.Command {
2628
Use: "delete",
2729
Short: "delete an artifact",
2830
Args: cobra.MaximumNArgs(1),
29-
Run: func(cmd *cobra.Command, args []string) {
31+
RunE: func(cmd *cobra.Command, args []string) error {
3032
var err error
3133
var projectName, repoName, reference string
3234
if len(args) > 0 {
33-
projectName, repoName, reference, parseError := utils.ParseProjectRepoReference(args[0])
34-
if parseError != nil {
35-
log.Errorf("failed to parse project/repo/reference: %v", parseError)
36-
}
37-
err = api.DeleteArtifact(projectName, repoName, reference)
35+
projectName, repoName, reference, err = utils.ParseProjectRepoReference(args[0])
3836
if err != nil {
39-
log.Errorf("failed to delete an artifact: %v", err)
37+
return fmt.Errorf("failed to parse project/repo/reference: %v", err)
4038
}
4139
} else {
4240
projectName, err = prompt.GetProjectNameFromUser()
@@ -48,8 +46,9 @@ func DeleteArtifactCommand() *cobra.Command {
4846
}
4947
err = api.DeleteArtifact(projectName, repoName, reference)
5048
if err != nil {
51-
log.Errorf("failed to delete an artifact: %v", err)
49+
return fmt.Errorf("failed to delete an artifact: %v", utils.ParseHarborErrorMsg(err))
5250
}
51+
return nil
5352
},
5453
}
5554

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
// Copyright Project Harbor Authors
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
package label
15+
16+
import (
17+
"fmt"
18+
19+
"github.com/goharbor/harbor-cli/pkg/api"
20+
"github.com/goharbor/harbor-cli/pkg/prompt"
21+
"github.com/goharbor/harbor-cli/pkg/utils"
22+
"github.com/spf13/cobra"
23+
)
24+
25+
// AddLabelArtifactCommmand adds a label to an artifact
26+
func AddLabelArtifactCommmand() *cobra.Command {
27+
cmd := &cobra.Command{
28+
Use: "add",
29+
Short: "Attach a label to an artifact in a Harbor project repository",
30+
Long: `Attach an existing label to a specific artifact identified by <project>/<repository>:<reference>.
31+
You can specify the artifact and label directly as arguments, or interactively select them if arguments are omitted.
32+
33+
Examples:
34+
# Add a label to an artifact using project/repo:reference and label name
35+
harbor artifact label add myproject/myrepo@sha256:abcdef1234567890 dev
36+
37+
# Prompt-based label selection for an artifact
38+
harbor artifact label add library/nginx:1.21
39+
40+
# Fully interactive mode (prompt for everything)
41+
harbor artifact label add
42+
`,
43+
Args: cobra.MaximumNArgs(2),
44+
RunE: func(cmd *cobra.Command, args []string) error {
45+
var (
46+
projectName, repoName, reference string
47+
labelName string
48+
labelID int64
49+
err error
50+
)
51+
52+
if len(args) >= 1 {
53+
projectName, repoName, reference, err = utils.ParseProjectRepoReference(args[0])
54+
if err != nil {
55+
return fmt.Errorf("failed to parse project/repo/reference: %v", err)
56+
}
57+
} else {
58+
projectName, err = prompt.GetProjectNameFromUser()
59+
if err != nil {
60+
return fmt.Errorf("failed to get project name: %v", utils.ParseHarborErrorMsg(err))
61+
}
62+
repoName = prompt.GetRepoNameFromUser(projectName)
63+
reference = prompt.GetReferenceFromUser(repoName, projectName)
64+
}
65+
66+
if len(args) == 2 {
67+
labelName = args[1]
68+
labelID, err = api.GetLabelIdByName(labelName)
69+
if err != nil {
70+
return fmt.Errorf("failed to get label id: %v", utils.ParseHarborErrorMsg(err))
71+
}
72+
} else {
73+
labels, err := api.ListLabel()
74+
if err != nil {
75+
return fmt.Errorf("failed to list labels: %v", utils.ParseHarborErrorMsg(err))
76+
}
77+
labelID = prompt.GetLabelIdFromUser(labels.Payload)
78+
}
79+
80+
label := api.GetLabel(labelID)
81+
82+
if _, err := api.AddLabelArtifact(projectName, repoName, reference, label); err != nil {
83+
return fmt.Errorf("failed to add label to artifact: %v", utils.ParseHarborErrorMsg(err))
84+
}
85+
86+
fmt.Printf("Label '%s' added to artifact %s/%s@%s\n", label.Name, projectName, repoName, reference)
87+
return nil
88+
},
89+
}
90+
91+
return cmd
92+
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
// Copyright Project Harbor Authors
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
package label
15+
16+
import (
17+
"github.com/spf13/cobra"
18+
)
19+
20+
// LabelsArtifactCommmand compound command to label artifacts
21+
func LabelsArtifactCommmand() *cobra.Command {
22+
cmd := &cobra.Command{
23+
Use: "label",
24+
Short: "label command for artifacts",
25+
Long: `label command for artifact`,
26+
Example: `harbor artifact label add <project>/<repository>/<reference> <label name>
27+
harbor artifact label del <project>/<repository>/<reference> <label name>
28+
`,
29+
}
30+
cmd.AddCommand(AddLabelArtifactCommmand())
31+
cmd.AddCommand(DelLabelArtifactCommmand())
32+
cmd.AddCommand(ListLabelArtifactCommmand())
33+
return cmd
34+
}
Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
// Copyright Project Harbor Authors
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
package label
15+
16+
import (
17+
"fmt"
18+
19+
"github.com/goharbor/harbor-cli/pkg/api"
20+
"github.com/goharbor/harbor-cli/pkg/prompt"
21+
"github.com/goharbor/harbor-cli/pkg/utils"
22+
"github.com/spf13/cobra"
23+
)
24+
25+
// DelLabelArtifactCommmand deletes a label from an artifact
26+
func DelLabelArtifactCommmand() *cobra.Command {
27+
cmd := &cobra.Command{
28+
Use: "delete",
29+
Aliases: []string{"del"},
30+
Short: "Detach a label from an artifact in a Harbor project repository",
31+
Long: `Remove an existing label from a specific artifact identified by <project>/<repository>:<reference>.
32+
You can provide the artifact and label name as arguments, or choose them interactively if not specified.
33+
34+
Examples:
35+
# Remove a label by specifying artifact and label name
36+
harbor artifact label delete library/nginx:latest stable
37+
38+
# Prompt-based label selection for a specific artifact
39+
harbor artifact label del library/nginx:1.21
40+
41+
# Fully interactive mode (prompt for project, repo, reference, and label)
42+
harbor artifact label delete
43+
44+
# Remove a label from an artifact identified by digest
45+
harbor artifact label del myproject/myrepo@sha256:abcdef1234567890 qa-label`,
46+
RunE: func(cmd *cobra.Command, args []string) error {
47+
var (
48+
projectName, repoName, reference string
49+
labelID int64
50+
err error
51+
)
52+
53+
if len(args) >= 1 {
54+
projectName, repoName, reference, err = utils.ParseProjectRepoReference(args[0])
55+
if err != nil {
56+
return fmt.Errorf("failed to parse project/repo/reference: %v", err)
57+
}
58+
} else {
59+
projectName, err = prompt.GetProjectNameFromUser()
60+
if err != nil {
61+
return fmt.Errorf("failed to get project name: %v", utils.ParseHarborErrorMsg(err))
62+
}
63+
repoName = prompt.GetRepoNameFromUser(projectName)
64+
reference = prompt.GetReferenceFromUser(repoName, projectName)
65+
}
66+
67+
if len(args) == 2 {
68+
labelName := args[1]
69+
labelID, err = api.GetLabelIdByName(labelName)
70+
if err != nil {
71+
return fmt.Errorf("failed to get label id: %v", utils.ParseHarborErrorMsg(err))
72+
}
73+
} else {
74+
artifact, err := api.ViewArtifact(projectName, repoName, reference, true)
75+
if err != nil || artifact == nil {
76+
return fmt.Errorf("failed to get artifact info: %v", utils.ParseHarborErrorMsg(err))
77+
}
78+
79+
labels := artifact.Payload.Labels
80+
if len(labels) == 0 {
81+
fmt.Printf("No labels found for artifact %s/%s@%s\n", projectName, repoName, reference)
82+
return nil
83+
}
84+
labelID = prompt.GetLabelIdFromUser(labels)
85+
}
86+
87+
if _, err := api.RemoveLabelArtifact(projectName, repoName, reference, labelID); err != nil {
88+
return fmt.Errorf("failed to remove label from artifact: %v", utils.ParseHarborErrorMsg(err))
89+
}
90+
91+
fmt.Println("Label removed successfully")
92+
return nil
93+
},
94+
}
95+
96+
return cmd
97+
}
Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
// Copyright Project Harbor Authors
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
package label
15+
16+
import (
17+
"fmt"
18+
19+
"github.com/goharbor/go-client/pkg/sdk/v2.0/client/artifact"
20+
"github.com/goharbor/harbor-cli/pkg/api"
21+
"github.com/goharbor/harbor-cli/pkg/prompt"
22+
"github.com/goharbor/harbor-cli/pkg/utils"
23+
"github.com/goharbor/harbor-cli/pkg/views/label/list"
24+
"github.com/spf13/cobra"
25+
"github.com/spf13/viper"
26+
)
27+
28+
// DelLabelArtifactCommmand delete label command to artifact
29+
func ListLabelArtifactCommmand() *cobra.Command {
30+
cmd := &cobra.Command{
31+
Use: "list",
32+
Short: "Display labels attached to a specific artifact",
33+
Long: `This command lists all labels currently associated with a specific artifact in a Harbor project repository.
34+
You can provide the artifact reference in the format <project>/<repository>:<reference> (where reference is either a tag or a digest).
35+
If the reference is not provided as an argument, the command will prompt you to select the project, repository, and artifact.
36+
37+
Supports output formatting such as JSON or YAML using the --output (-o) flag.`,
38+
Example: ` # List labels for a tagged artifact
39+
harbor artifact label list library/nginx:latest
40+
41+
# List labels for an artifact by digest
42+
harbor artifact label list myproject/myrepo@sha256:abc123...
43+
44+
# Prompt-based interactive selection of artifact
45+
harbor artifact label list
46+
47+
# Output in JSON format
48+
harbor artifact label list library/nginx:1.21 -o json`,
49+
Args: cobra.MaximumNArgs(1),
50+
RunE: func(cmd *cobra.Command, args []string) error {
51+
var err error
52+
var projectName, repoName, reference string
53+
var artifact *artifact.GetArtifactOK
54+
getLabel := true
55+
if len(args) > 0 {
56+
projectName, repoName, reference, err = utils.ParseProjectRepoReference(args[0])
57+
if err != nil {
58+
return fmt.Errorf("failed to parse project/repo/reference: %v", err)
59+
}
60+
} else {
61+
projectName, err = prompt.GetProjectNameFromUser()
62+
if err != nil {
63+
return fmt.Errorf("failed to get project name: %v", utils.ParseHarborErrorMsg(err))
64+
}
65+
repoName = prompt.GetRepoNameFromUser(projectName)
66+
reference = prompt.GetReferenceFromUser(repoName, projectName)
67+
}
68+
69+
if reference == "" {
70+
if len(args) > 0 {
71+
return fmt.Errorf("Invalid artifact reference format: %s", args[0])
72+
} else {
73+
return fmt.Errorf("Invalid artifact reference format: no arguments provided")
74+
}
75+
}
76+
77+
artifact, err = api.ViewArtifact(projectName, repoName, reference, getLabel)
78+
79+
if err != nil || artifact == nil {
80+
return fmt.Errorf("failed to get info of an artifact: %v", utils.ParseHarborErrorMsg(err))
81+
}
82+
labelList := artifact.Payload.Labels
83+
if len(labelList) == 0 {
84+
fmt.Printf("No labels found for artifact %s/%s@%s", projectName, repoName, reference)
85+
return nil
86+
}
87+
formatFlag := viper.GetString("output-format")
88+
if formatFlag != "" {
89+
err = utils.PrintFormat(labelList, formatFlag)
90+
if err != nil {
91+
return err
92+
}
93+
} else {
94+
list.ListLabels(labelList)
95+
}
96+
return nil
97+
},
98+
}
99+
100+
return cmd
101+
}

0 commit comments

Comments
 (0)