Skip to content

Commit 4ef237e

Browse files
authored
Merge pull request #19 from Piwriw/feat/tpl-tags
feat:add tpl tags
2 parents ef10816 + 1713a41 commit 4ef237e

4 files changed

Lines changed: 173 additions & 3 deletions

File tree

‎cmd/template/tag.go‎

Lines changed: 169 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,169 @@
1+
package template
2+
3+
import (
4+
"encoding/json"
5+
"fmt"
6+
"os"
7+
"strings"
8+
"time"
9+
10+
"github.com/spf13/cobra"
11+
"github.com/ucloud/ucloud-sandbox-cli/internal/config"
12+
"github.com/ucloud/ucloud-sandbox-cli/internal/prompt"
13+
"github.com/ucloud/ucloud-sandbox-cli/internal/table"
14+
)
15+
16+
type listedTemplateTag struct {
17+
Tag string `table_field:"Tag"`
18+
BuildID string `table_field:"Build ID"`
19+
CreatedAt time.Time `table_field:"Created"`
20+
}
21+
22+
func newTagCmd() *cobra.Command {
23+
cmd := &cobra.Command{
24+
Use: "tag",
25+
Aliases: []string{"tags"},
26+
Short: "Manage template tags",
27+
}
28+
cmd.AddCommand(newTagAssignCmd())
29+
cmd.AddCommand(newTagRemoveCmd())
30+
cmd.AddCommand(newTagListCmd())
31+
return cmd
32+
}
33+
34+
func newTagAssignCmd() *cobra.Command {
35+
return &cobra.Command{
36+
Use: "assign <template:source-tag> <tag> [tag ...]",
37+
Aliases: []string{"add"},
38+
Short: "Assign tags to the referenced template build",
39+
Args: func(cmd *cobra.Command, args []string) error {
40+
if len(args) == 0 {
41+
return fmt.Errorf("template source is required (for example: my-template:default)")
42+
}
43+
if len(args) == 1 {
44+
return fmt.Errorf("at least one tag is required")
45+
}
46+
return nil
47+
},
48+
RunE: func(cmd *cobra.Command, args []string) error {
49+
cfg, err := config.Load()
50+
if err != nil {
51+
return err
52+
}
53+
client, err := config.NewClient(cfg)
54+
if err != nil {
55+
return err
56+
}
57+
58+
assigned, err := client.AssignTemplateTags(cmd.Context(), args[0], args[1:])
59+
if err != nil {
60+
return err
61+
}
62+
fmt.Printf("Assigned tags %s to build %s.\n", strings.Join(assigned.Tags, ", "), assigned.BuildID)
63+
return nil
64+
},
65+
}
66+
}
67+
68+
func newTagRemoveCmd() *cobra.Command {
69+
var yes bool
70+
71+
cmd := &cobra.Command{
72+
Use: "remove <template> <tag> [tag ...]",
73+
Aliases: []string{"rm", "delete"},
74+
Short: "Remove tags from a template",
75+
Args: func(cmd *cobra.Command, args []string) error {
76+
if len(args) == 0 {
77+
return fmt.Errorf("template is required")
78+
}
79+
if len(args) == 1 {
80+
return fmt.Errorf("at least one tag is required")
81+
}
82+
return nil
83+
},
84+
RunE: func(cmd *cobra.Command, args []string) error {
85+
if !yes {
86+
confirmed, err := prompt.Confirm(fmt.Sprintf("Remove tags %s from template %s?", strings.Join(args[1:], ", "), args[0]))
87+
if err != nil {
88+
return err
89+
}
90+
if !confirmed {
91+
fmt.Println("Canceled.")
92+
return nil
93+
}
94+
}
95+
96+
cfg, err := config.Load()
97+
if err != nil {
98+
return err
99+
}
100+
client, err := config.NewClient(cfg)
101+
if err != nil {
102+
return err
103+
}
104+
if err := client.DeleteTemplateTags(cmd.Context(), args[0], args[1:]); err != nil {
105+
return err
106+
}
107+
fmt.Printf("Removed tags %s from template %s.\n", strings.Join(args[1:], ", "), args[0])
108+
return nil
109+
},
110+
}
111+
112+
cmd.Flags().BoolVarP(&yes, "yes", "y", false, "Skip confirmation")
113+
return cmd
114+
}
115+
116+
func newTagListCmd() *cobra.Command {
117+
var format string
118+
119+
cmd := &cobra.Command{
120+
Use: "list <template>",
121+
Aliases: []string{"ls"},
122+
Short: "List template tags",
123+
Args: func(cmd *cobra.Command, args []string) error {
124+
if len(args) == 0 {
125+
return fmt.Errorf("template is required")
126+
}
127+
if len(args) > 1 {
128+
return fmt.Errorf("only one template can be specified")
129+
}
130+
return nil
131+
},
132+
RunE: func(cmd *cobra.Command, args []string) error {
133+
cfg, err := config.Load()
134+
if err != nil {
135+
return err
136+
}
137+
client, err := config.NewClient(cfg)
138+
if err != nil {
139+
return err
140+
}
141+
142+
tags, err := client.ListTemplateTags(cmd.Context(), args[0])
143+
if err != nil {
144+
return err
145+
}
146+
if format == "json" {
147+
return json.NewEncoder(os.Stdout).Encode(tags)
148+
}
149+
if len(tags) == 0 {
150+
fmt.Println("No tags found.")
151+
return nil
152+
}
153+
154+
rows := make([]listedTemplateTag, len(tags))
155+
for i, tag := range tags {
156+
rows[i] = listedTemplateTag(tag)
157+
}
158+
out, err := table.Render(rows, 1, 0, int64(len(rows)))
159+
if err != nil {
160+
return err
161+
}
162+
fmt.Print(out)
163+
return nil
164+
},
165+
}
166+
167+
cmd.Flags().StringVarP(&format, "format", "f", "pretty", "Output format (pretty, json)")
168+
return cmd
169+
}

‎cmd/template/template.go‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,5 +15,6 @@ func NewTemplateCmd() *cobra.Command {
1515
cmd.AddCommand(newDeleteCmd())
1616
cmd.AddCommand(newPublishCmd())
1717
cmd.AddCommand(newInitCmd())
18+
cmd.AddCommand(newTagCmd())
1819
return cmd
1920
}

‎go.mod‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ require (
88
github.com/manifoldco/promptui v0.9.0
99
github.com/spf13/cobra v1.10.2
1010
github.com/stretchr/testify v1.11.1
11-
github.com/ucloud/ucloud-sandbox-sdk-go v0.0.0-20260812025714-9a51285e73c9
11+
github.com/ucloud/ucloud-sandbox-sdk-go v0.0.0-20260818062953-e15ae148e737
1212
golang.org/x/term v0.44.0
1313
)
1414

‎go.sum‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,8 @@ github.com/spf13/pflag v1.0.9 h1:9exaQaMOCwffKiiiYk6/BndUBv+iRViNW+4lEMi0PvY=
2424
github.com/spf13/pflag v1.0.9/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
2525
github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
2626
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
27-
github.com/ucloud/ucloud-sandbox-sdk-go v0.0.0-20260812025714-9a51285e73c9 h1:B20Rbjyt5h5PZSziJbIhewzpcywOBYvh6Cx6bEewc0A=
28-
github.com/ucloud/ucloud-sandbox-sdk-go v0.0.0-20260812025714-9a51285e73c9/go.mod h1:097WABFNud50hH2KImyZ8WOJeb0lM2A4+gLvQ1kllsc=
27+
github.com/ucloud/ucloud-sandbox-sdk-go v0.0.0-20260818062953-e15ae148e737 h1:RC0VFN6anBxpFBj3X/mmbiXtm1V7FVwbGQyVqVZeu1c=
28+
github.com/ucloud/ucloud-sandbox-sdk-go v0.0.0-20260818062953-e15ae148e737/go.mod h1:097WABFNud50hH2KImyZ8WOJeb0lM2A4+gLvQ1kllsc=
2929
go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg=
3030
golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
3131
golang.org/x/sys v0.46.0 h1:noSf2Fq6F8DBgS+LysIkx7rIExoNHJsxOAtPp4rthXw=

0 commit comments

Comments
 (0)