Skip to content

Commit 2133cd5

Browse files
chore: fix glob pattern and apply provider resources in batch
1 parent 9d54e8b commit 2133cd5

2 files changed

Lines changed: 140 additions & 22 deletions

File tree

cmd/ctrlc/root/apply/cmd.go

Lines changed: 31 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -61,31 +61,30 @@ func expandGlob(patterns []string) ([]string, error) {
6161
}
6262

6363
if len(matches) == 0 {
64-
// Check if it's a literal file path that exists
65-
if _, err := os.Stat(pattern); err == nil {
66-
if !seen[pattern] {
67-
seen[pattern] = true
68-
files = append(files, pattern)
69-
}
70-
} else {
71-
return nil, fmt.Errorf("no files matched pattern: %s", pattern)
72-
}
73-
continue
64+
return nil, fmt.Errorf("no files matched pattern: %s", pattern)
7465
}
7566

67+
added := 0
7668
for _, match := range matches {
69+
info, err := os.Stat(match)
70+
if err != nil || info.IsDir() {
71+
continue
72+
}
7773
if !seen[match] {
7874
seen[match] = true
7975
files = append(files, match)
76+
added++
8077
}
8178
}
79+
if added == 0 {
80+
return nil, fmt.Errorf("no files matched pattern: %s", pattern)
81+
}
8282
}
8383

8484
return files, nil
8585
}
8686

8787
func runApply(ctx context.Context, filePatterns []string) error {
88-
// Expand glob patterns to file paths
8988
files, err := expandGlob(filePatterns)
9089
if err != nil {
9190
return err
@@ -95,7 +94,6 @@ func runApply(ctx context.Context, filePatterns []string) error {
9594
return fmt.Errorf("no files to apply")
9695
}
9796

98-
// Create API client
9997
apiURL := viper.GetString("url")
10098
apiKey := viper.GetString("api-key")
10199
workspace := viper.GetString("workspace")
@@ -107,7 +105,6 @@ func runApply(ctx context.Context, filePatterns []string) error {
107105

108106
workspaceID := client.GetWorkspaceID(ctx, workspace)
109107

110-
// Parse all files and collect documents
111108
var documents []Document
112109
for _, filePath := range files {
113110
docs, err := ParseFile(filePath)
@@ -124,30 +121,42 @@ func runApply(ctx context.Context, filePatterns []string) error {
124121

125122
log.Info("Applying resources", "count", len(documents), "files", len(files))
126123

127-
// Create document context
128124
docCtx := NewDocContext(workspaceID.String(), client)
129125
docCtx.Context = ctx
130126

131-
// Sort documents by Order (lower number = processed first)
132-
// Sort documents by Order (higher number = higher priority = processed first)
133-
sort.Slice(documents, func(i, j int) bool {
134-
return documents[i].Order() > documents[j].Order()
127+
var resourceDocs []*ResourceDocument
128+
var otherDocs []Document
129+
for _, doc := range documents {
130+
if rd, ok := doc.(*ResourceDocument); ok {
131+
resourceDocs = append(resourceDocs, rd)
132+
} else {
133+
otherDocs = append(otherDocs, doc)
134+
}
135+
}
136+
137+
sort.Slice(otherDocs, func(i, j int) bool {
138+
return otherDocs[i].Order() > otherDocs[j].Order()
135139
})
136140

137-
// Apply all documents
138141
var results []ApplyResult
139-
for _, doc := range documents {
142+
for _, doc := range otherDocs {
140143
result, err := doc.Apply(docCtx)
141144
if err != nil {
142145
log.Error("Failed to apply document", "error", err)
143146
}
144147
results = append(results, result)
145148
}
146149

147-
// Print summary
150+
if len(resourceDocs) > 0 {
151+
resourceResults, err := applyResourcesBatch(docCtx, resourceDocs)
152+
if err != nil {
153+
log.Error("Failed to apply resources batch", "error", err)
154+
}
155+
results = append(results, resourceResults...)
156+
}
157+
148158
printResults(results)
149159

150-
// Check for errors
151160
for _, r := range results {
152161
if r.Error != nil {
153162
return fmt.Errorf("one or more resources failed to apply")

cmd/ctrlc/root/apply/doc_resource.go

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -174,3 +174,112 @@ func (d *ResourceDocument) Delete(ctx *DocContext) (DeleteResult, error) {
174174
Name: d.Name,
175175
}, fmt.Errorf("delete not implemented for resources")
176176
}
177+
178+
func applyResourcesBatch(ctx *DocContext, docs []*ResourceDocument) ([]ApplyResult, error) {
179+
providerGroups := make(map[string][]*ResourceDocument)
180+
for _, doc := range docs {
181+
providerName := doc.Provider
182+
if providerName == "" {
183+
providerName = "ctrlc-apply"
184+
}
185+
providerGroups[providerName] = append(providerGroups[providerName], doc)
186+
}
187+
188+
var results []ApplyResult
189+
190+
for providerName, groupDocs := range providerGroups {
191+
groupResults, err := applyProviderResources(ctx, providerName, groupDocs)
192+
if err != nil {
193+
for _, doc := range groupDocs {
194+
results = append(results, ApplyResult{
195+
Type: TypeResource,
196+
Name: doc.Name,
197+
Error: err,
198+
})
199+
}
200+
continue
201+
}
202+
results = append(results, groupResults...)
203+
}
204+
205+
return results, nil
206+
}
207+
208+
func applyProviderResources(ctx *DocContext, providerName string, docs []*ResourceDocument) ([]ApplyResult, error) {
209+
providerID, err := getProviderIDByName(ctx, providerName)
210+
if err != nil {
211+
return nil, fmt.Errorf("failed to get resource provider: %w", err)
212+
}
213+
214+
resources := make([]api.ResourceProviderResource, 0, len(docs))
215+
for _, doc := range docs {
216+
metadata := doc.Metadata
217+
if metadata == nil {
218+
metadata = make(map[string]string)
219+
}
220+
config := doc.Config
221+
if config == nil {
222+
config = make(map[string]any)
223+
}
224+
225+
resources = append(resources, api.ResourceProviderResource{
226+
Identifier: doc.Identifier,
227+
Name: doc.Name,
228+
Kind: doc.Kind,
229+
Version: doc.Version,
230+
Config: config,
231+
Metadata: metadata,
232+
})
233+
}
234+
235+
resp, err := ctx.Client.SetResourceProvidersResourcesPatchWithResponse(ctx.Context, ctx.WorkspaceID, providerID, api.SetResourceProvidersResourcesPatchJSONRequestBody{
236+
Resources: resources,
237+
})
238+
if err != nil {
239+
return nil, fmt.Errorf("failed to upsert resources: %w", err)
240+
}
241+
242+
if resp.JSON202 == nil {
243+
return nil, fmt.Errorf("failed to upsert resources: %s", string(resp.Body))
244+
}
245+
246+
var results []ApplyResult
247+
for _, doc := range docs {
248+
result := ApplyResult{
249+
Type: TypeResource,
250+
Name: doc.Name,
251+
ID: doc.Identifier,
252+
Action: "upserted",
253+
}
254+
255+
if err := doc.syncVariables(ctx); err != nil {
256+
result.Error = fmt.Errorf("failed to sync resource variables: %w", err)
257+
}
258+
259+
results = append(results, result)
260+
}
261+
262+
return results, nil
263+
}
264+
265+
func getProviderIDByName(ctx *DocContext, providerName string) (string, error) {
266+
providerResp, err := ctx.Client.GetResourceProviderByNameWithResponse(ctx.Context, ctx.WorkspaceID, providerName)
267+
if err != nil {
268+
return "", fmt.Errorf("failed to get resource provider: %w", err)
269+
}
270+
271+
if providerResp.JSON200 != nil {
272+
return providerResp.JSON200.Id, nil
273+
}
274+
275+
createResp, err := ctx.Client.UpsertResourceProviderWithResponse(ctx.Context, ctx.WorkspaceID, api.UpsertResourceProviderJSONRequestBody{
276+
Name: providerName,
277+
})
278+
if err != nil {
279+
return "", fmt.Errorf("failed to create resource provider: %w", err)
280+
}
281+
if createResp.JSON200 == nil {
282+
return "", fmt.Errorf("failed to create resource provider: %s", string(createResp.Body))
283+
}
284+
return createResp.JSON200.Id, nil
285+
}

0 commit comments

Comments
 (0)