Skip to content

Commit 1782442

Browse files
feat: release targets preview cmd
1 parent aa8779f commit 1782442

File tree

4 files changed

+8951
-6788
lines changed

4 files changed

+8951
-6788
lines changed

cmd/ctrlc/root/api/get/get.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package get
22

33
import (
44
"github.com/ctrlplanedev/cli/cmd/ctrlc/root/api/get/release"
5+
"github.com/ctrlplanedev/cli/cmd/ctrlc/root/api/get/releasetargets"
56
"github.com/ctrlplanedev/cli/cmd/ctrlc/root/api/get/resources"
67
"github.com/spf13/cobra"
78
)
@@ -18,6 +19,7 @@ func NewGetCmd() *cobra.Command {
1819

1920
cmd.AddCommand(resources.NewResourcesCmd())
2021
cmd.AddCommand(release.NewReleaseCmd())
22+
cmd.AddCommand(releasetargets.NewReleaseTargetsCmd())
2123

2224
return cmd
2325
}
Lines changed: 177 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,177 @@
1+
package releasetargets
2+
3+
import (
4+
"fmt"
5+
"io"
6+
"os"
7+
8+
"github.com/ctrlplanedev/cli/internal/api"
9+
"github.com/ctrlplanedev/cli/internal/cliutil"
10+
"github.com/spf13/cobra"
11+
"github.com/spf13/viper"
12+
"gopkg.in/yaml.v3"
13+
)
14+
15+
type resourceInput struct {
16+
Name string `yaml:"name"`
17+
Kind string `yaml:"kind"`
18+
Version string `yaml:"version"`
19+
Identifier string `yaml:"identifier"`
20+
Config map[string]any `yaml:"config"`
21+
Metadata map[string]string `yaml:"metadata"`
22+
}
23+
24+
func NewReleaseTargetsCmd() *cobra.Command {
25+
var (
26+
filePath string
27+
name string
28+
kind string
29+
version string
30+
identifier string
31+
metadata map[string]string
32+
config map[string]string
33+
limit int
34+
offset int
35+
)
36+
37+
cmd := &cobra.Command{
38+
Use: "release-targets",
39+
Short: "Preview release targets for a resource",
40+
Long: `Simulates which release targets would be created if a given resource were added to the workspace. No resources are actually created.`,
41+
Example: ` # Preview from a YAML file
42+
ctrlc api get release-targets -f resource.yaml
43+
44+
# Preview from stdin
45+
cat resource.yaml | ctrlc api get release-targets -f -
46+
47+
# Preview with inline flags
48+
ctrlc api get release-targets --name my-pod --kind kubernetes/pod --version v1 --identifier my-pod-id`,
49+
RunE: func(cmd *cobra.Command, args []string) error {
50+
input, err := buildInput(filePath, name, kind, version, identifier, metadata, config)
51+
if err != nil {
52+
return err
53+
}
54+
55+
apiURL := viper.GetString("url")
56+
apiKey := viper.GetString("api-key")
57+
workspace := viper.GetString("workspace")
58+
59+
client, err := api.NewAPIKeyClientWithResponses(apiURL, apiKey)
60+
if err != nil {
61+
return fmt.Errorf("failed to create API client: %w", err)
62+
}
63+
64+
workspaceID := client.GetWorkspaceID(cmd.Context(), workspace)
65+
66+
params := &api.PreviewReleaseTargetsForResourceParams{}
67+
if limit > 0 {
68+
params.Limit = &limit
69+
}
70+
if offset > 0 {
71+
params.Offset = &offset
72+
}
73+
74+
body := api.PreviewReleaseTargetsForResourceJSONRequestBody{
75+
Name: input.Name,
76+
Kind: input.Kind,
77+
Version: input.Version,
78+
Identifier: input.Identifier,
79+
Config: input.Config,
80+
Metadata: input.Metadata,
81+
}
82+
83+
resp, err := client.PreviewReleaseTargetsForResource(cmd.Context(), workspaceID.String(), params, body)
84+
if err != nil {
85+
return fmt.Errorf("failed to preview release targets: %w", err)
86+
}
87+
88+
return cliutil.HandleResponseOutput(cmd, resp)
89+
},
90+
}
91+
92+
cmd.Flags().StringVarP(&filePath, "file", "f", "", "Path to a resource YAML file (use - for stdin)")
93+
cmd.Flags().StringVar(&name, "name", "", "Resource name")
94+
cmd.Flags().StringVar(&kind, "kind", "", "Resource kind")
95+
cmd.Flags().StringVar(&version, "version", "", "Resource version")
96+
cmd.Flags().StringVar(&identifier, "identifier", "", "Resource identifier")
97+
cmd.Flags().StringToStringVar(&metadata, "metadata", nil, "Resource metadata as key=value pairs")
98+
cmd.Flags().StringToStringVar(&config, "config", nil, "Resource config as key=value pairs")
99+
cmd.Flags().IntVarP(&limit, "limit", "l", 50, "Limit the number of results")
100+
cmd.Flags().IntVarP(&offset, "offset", "o", 0, "Offset the results")
101+
102+
return cmd
103+
}
104+
105+
func buildInput(
106+
filePath, name, kind, version, identifier string,
107+
metadata map[string]string,
108+
config map[string]string,
109+
) (*resourceInput, error) {
110+
if filePath != "" {
111+
return parseResourceFile(filePath)
112+
}
113+
114+
if name == "" || kind == "" || version == "" || identifier == "" {
115+
return nil, fmt.Errorf("when not using -f, --name, --kind, --version, and --identifier are all required")
116+
}
117+
118+
input := &resourceInput{
119+
Name: name,
120+
Kind: kind,
121+
Version: version,
122+
Identifier: identifier,
123+
Metadata: metadata,
124+
Config: make(map[string]any),
125+
}
126+
127+
for k, v := range config {
128+
input.Config[k] = v
129+
}
130+
131+
if input.Metadata == nil {
132+
input.Metadata = make(map[string]string)
133+
}
134+
135+
return input, nil
136+
}
137+
138+
func parseResourceFile(filePath string) (*resourceInput, error) {
139+
var data []byte
140+
var err error
141+
142+
if filePath == "-" {
143+
data, err = io.ReadAll(os.Stdin)
144+
} else {
145+
data, err = os.ReadFile(filePath)
146+
}
147+
if err != nil {
148+
return nil, fmt.Errorf("failed to read file: %w", err)
149+
}
150+
151+
var input resourceInput
152+
if err := yaml.Unmarshal(data, &input); err != nil {
153+
return nil, fmt.Errorf("failed to parse resource YAML: %w", err)
154+
}
155+
156+
if input.Name == "" {
157+
return nil, fmt.Errorf("resource YAML missing required 'name' field")
158+
}
159+
if input.Kind == "" {
160+
return nil, fmt.Errorf("resource YAML missing required 'kind' field")
161+
}
162+
if input.Version == "" {
163+
return nil, fmt.Errorf("resource YAML missing required 'version' field")
164+
}
165+
if input.Identifier == "" {
166+
return nil, fmt.Errorf("resource YAML missing required 'identifier' field")
167+
}
168+
169+
if input.Config == nil {
170+
input.Config = make(map[string]any)
171+
}
172+
if input.Metadata == nil {
173+
input.Metadata = make(map[string]string)
174+
}
175+
176+
return &input, nil
177+
}

0 commit comments

Comments
 (0)