Skip to content

Commit b2125ca

Browse files
Merge pull request #121 from StackVista/stac-23385
STAC-23385: Use Yaml version of the conf
2 parents e279981 + e06b552 commit b2125ca

7 files changed

Lines changed: 109 additions & 139 deletions

cmd/stackpack/stackpack_package.go

Lines changed: 21 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -2,16 +2,16 @@ package stackpack
22

33
import (
44
"archive/zip"
5+
"bytes"
56
"fmt"
67
"io"
78
"os"
89
"path/filepath"
9-
"strings"
1010

11-
"github.com/gurkankaymak/hocon"
1211
"github.com/spf13/cobra"
1312
"github.com/stackvista/stackstate-cli/internal/common"
1413
"github.com/stackvista/stackstate-cli/internal/di"
14+
"gopkg.in/yaml.v3"
1515
)
1616

1717
const (
@@ -36,53 +36,39 @@ type StackpackConfigParser interface {
3636
Parse(filePath string) (*StackpackInfo, error)
3737
}
3838

39-
// HoconParser implements StackpackConfigParser for HOCON format
40-
type HoconParser struct{}
39+
// YamlParser implements StackpackConfigParser for YAML format (future)
40+
type YamlParser struct{}
4141

42-
func (h *HoconParser) Parse(filePath string) (*StackpackInfo, error) {
43-
// Read the file content
42+
func (y *YamlParser) Parse(filePath string) (*StackpackInfo, error) {
4443
content, err := os.ReadFile(filePath)
4544
if err != nil {
4645
return nil, fmt.Errorf("failed to read file: %w", err)
4746
}
4847

49-
// Parse stackpack.conf content
50-
conf, err := hocon.ParseString(string(content))
51-
if err != nil {
52-
return nil, fmt.Errorf("failed to parse stackpack.conf file: %w", err)
53-
}
54-
55-
name := strings.Trim(conf.GetString("name"), `"`)
56-
version := strings.Trim(conf.GetString("version"), `"`)
48+
dec := yaml.NewDecoder(bytes.NewBuffer(content))
49+
cfg := &StackpackInfo{}
5750

58-
if name == "" {
59-
return nil, fmt.Errorf("name not found in stackpack.conf")
51+
if err := dec.Decode(&cfg); err != nil {
52+
return nil, fmt.Errorf("failed to parse stackpack.yaml file: %w", err)
6053
}
6154

62-
if version == "" {
63-
return nil, fmt.Errorf("version not found in stackpack.conf")
55+
if cfg.Name == "" {
56+
return nil, fmt.Errorf("name not found in stackpack.yaml")
6457
}
6558

66-
return &StackpackInfo{
67-
Name: name,
68-
Version: version,
69-
}, nil
70-
}
71-
72-
// YamlParser implements StackpackConfigParser for YAML format (future)
73-
type YamlParser struct{}
59+
if cfg.Version == "" {
60+
return nil, fmt.Errorf("version not found in stackpack.yaml")
61+
}
7462

75-
func (y *YamlParser) Parse(filePath string) (*StackpackInfo, error) {
76-
// TODO: Implement YAML parsing when format changes
77-
return nil, fmt.Errorf("YAML format not yet implemented")
63+
return cfg, nil
7864
}
7965

8066
// Required files and directories for a valid stackpack
8167
var requiredStackpackItems = []string{
8268
"provisioning",
8369
"README.md",
8470
"resources",
85-
"stackpack.conf",
71+
"stackpack.yaml",
8672
}
8773

8874
// StackpackPackageCommand creates the package subcommand
@@ -97,10 +83,10 @@ Creates a zip file containing all required stackpack files and directories:
9783
- provisioning/ (directory)
9884
- README.md (file)
9985
- resources/ (directory)
100-
- stackpack.conf (file)
86+
- stackpack.yaml (file)
10187
10288
The zip file is named <stackpack_name>-<version>.zip where the name and
103-
version are extracted from stackpack.conf and created in the current directory.`,
89+
version are extracted from stackpack.yaml and created in the current directory.`,
10490
Example: `# Package stackpack in current directory
10591
sts stackpack package
10692
@@ -142,10 +128,10 @@ func RunStackpackPackageCommand(args *PackageArgs) func(cli *di.Deps, cmd *cobra
142128
args.StackpackDir = absStackpackDir
143129

144130
// Parse stackpack.conf using HOCON parser to get name and version
145-
parser := &HoconParser{}
146-
stackpackInfo, err := parser.Parse(filepath.Join(args.StackpackDir, "stackpack.conf"))
131+
parser := &YamlParser{}
132+
stackpackInfo, err := parser.Parse(filepath.Join(args.StackpackDir, "stackpack.yaml"))
147133
if err != nil {
148-
return common.NewRuntimeError(fmt.Errorf("failed to parse stackpack.conf: %w", err))
134+
return common.NewRuntimeError(fmt.Errorf("failed to parse stackpack.yaml: %w", err))
149135
}
150136

151137
// Set default archive file path if not specified

cmd/stackpack/stackpack_package_test.go

Lines changed: 50 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -27,15 +27,15 @@ func createTestStackpack(t *testing.T, dir string, name string, version string)
2727

2828
// Create stackpack.conf
2929
stackpackConf := fmt.Sprintf(`# schemaVersion -- Stackpack specification version.
30-
schemaVersion = "2.0"
30+
schemaVersion: "2.0"
3131
# name -- Name of the StackPack.
32-
name = "%s"
32+
name: "%s"
3333
# displayName -- Display name of the StackPack.
34-
displayName = "Test %s"
34+
displayName: "Test %s"
3535
# version -- Semantic version of the StackPack.
36-
version = "%s"
36+
version: "%s"
3737
`, name, name, version)
38-
require.NoError(t, os.WriteFile(filepath.Join(dir, "stackpack.conf"), []byte(stackpackConf), 0644))
38+
require.NoError(t, os.WriteFile(filepath.Join(dir, "stackpack.yaml"), []byte(stackpackConf), 0644))
3939

4040
// Create README.md
4141
readme := fmt.Sprintf("# %s\n\nThis is a test stackpack.", name)
@@ -196,7 +196,7 @@ func TestStackpackPackageCommand_MissingRequiredFiles(t *testing.T) {
196196
setupFunc: func(dir string) {
197197
require.NoError(t, os.MkdirAll(filepath.Join(dir, "resources"), 0755))
198198
require.NoError(t, os.WriteFile(filepath.Join(dir, "README.md"), []byte("readme"), 0644))
199-
require.NoError(t, os.WriteFile(filepath.Join(dir, "stackpack.conf"), []byte("name = \"test\"\nversion = \"1.0.0\""), 0644))
199+
require.NoError(t, os.WriteFile(filepath.Join(dir, "stackpack.yaml"), []byte("name: \"test\"\nversion: \"1.0.0\""), 0644))
200200
},
201201
expectedError: "required stackpack item not found: provisioning",
202202
},
@@ -205,7 +205,7 @@ func TestStackpackPackageCommand_MissingRequiredFiles(t *testing.T) {
205205
setupFunc: func(dir string) {
206206
require.NoError(t, os.MkdirAll(filepath.Join(dir, "provisioning"), 0755))
207207
require.NoError(t, os.MkdirAll(filepath.Join(dir, "resources"), 0755))
208-
require.NoError(t, os.WriteFile(filepath.Join(dir, "stackpack.conf"), []byte("name = \"test\"\nversion = \"1.0.0\""), 0644))
208+
require.NoError(t, os.WriteFile(filepath.Join(dir, "stackpack.yaml"), []byte("name: \"test\"\nversion: \"1.0.0\""), 0644))
209209
},
210210
expectedError: "required stackpack item not found: README.md",
211211
},
@@ -214,18 +214,18 @@ func TestStackpackPackageCommand_MissingRequiredFiles(t *testing.T) {
214214
setupFunc: func(dir string) {
215215
require.NoError(t, os.MkdirAll(filepath.Join(dir, "provisioning"), 0755))
216216
require.NoError(t, os.WriteFile(filepath.Join(dir, "README.md"), []byte("readme"), 0644))
217-
require.NoError(t, os.WriteFile(filepath.Join(dir, "stackpack.conf"), []byte("name = \"test\"\nversion = \"1.0.0\""), 0644))
217+
require.NoError(t, os.WriteFile(filepath.Join(dir, "stackpack.yaml"), []byte("name: \"test\"\nversion: \"1.0.0\""), 0644))
218218
},
219219
expectedError: "required stackpack item not found: resources",
220220
},
221221
{
222-
name: "missing stackpack.conf file",
222+
name: "missing stackpack.yaml file",
223223
setupFunc: func(dir string) {
224224
require.NoError(t, os.MkdirAll(filepath.Join(dir, "provisioning"), 0755))
225225
require.NoError(t, os.MkdirAll(filepath.Join(dir, "resources"), 0755))
226226
require.NoError(t, os.WriteFile(filepath.Join(dir, "README.md"), []byte("readme"), 0644))
227227
},
228-
expectedError: "failed to parse stackpack.conf",
228+
expectedError: "failed to parse stackpack.yaml",
229229
},
230230
}
231231

@@ -255,37 +255,37 @@ func TestStackpackPackageCommand_InvalidStackpackConf(t *testing.T) {
255255
expectedError string
256256
}{
257257
{
258-
name: "invalid HOCON syntax",
258+
name: "invalid YAML syntax",
259259
confContent: `name = "test" invalid syntax {`,
260-
expectedError: "failed to parse stackpack.conf file",
260+
expectedError: "failed to parse stackpack.yaml file",
261261
},
262262
{
263263
name: "missing name field",
264-
confContent: `version = "1.0.0"`,
265-
expectedError: "name not found in stackpack.conf",
264+
confContent: `version: "1.0.0"`,
265+
expectedError: "name not found in stackpack.yaml",
266266
},
267267
{
268268
name: "missing version field",
269-
confContent: `name = "test"`,
270-
expectedError: "version not found in stackpack.conf",
269+
confContent: `name: "test"`,
270+
expectedError: "version not found in stackpack.yaml",
271271
},
272272
{
273273
name: "empty name field",
274-
confContent: `name = ""
275-
version = "1.0.0"`,
276-
expectedError: "name not found in stackpack.conf",
274+
confContent: `name: ""
275+
version: "1.0.0"`,
276+
expectedError: "name not found in stackpack.yaml",
277277
},
278278
{
279279
name: "empty version field",
280-
confContent: `name = "test"
281-
version = ""`,
282-
expectedError: "version not found in stackpack.conf",
280+
confContent: `name: "test"
281+
version: ""`,
282+
expectedError: "version not found in stackpack.yaml",
283283
},
284284
}
285285

286286
for _, tt := range tests {
287287
t.Run(tt.name, func(t *testing.T) {
288-
tempDir, err := os.MkdirTemp("", "stackpack-package-hocon-test-*")
288+
tempDir, err := os.MkdirTemp("", "stackpack-package-yaml-test-*")
289289
require.NoError(t, err)
290290
defer os.RemoveAll(tempDir)
291291

@@ -297,8 +297,8 @@ version = ""`,
297297
require.NoError(t, os.MkdirAll(filepath.Join(stackpackDir, "resources"), 0755))
298298
require.NoError(t, os.WriteFile(filepath.Join(stackpackDir, "README.md"), []byte("readme"), 0644))
299299

300-
// Create invalid stackpack.conf
301-
require.NoError(t, os.WriteFile(filepath.Join(stackpackDir, "stackpack.conf"), []byte(tt.confContent), 0644))
300+
// Create invalid stackpack.yaml
301+
require.NoError(t, os.WriteFile(filepath.Join(stackpackDir, "stackpack.yaml"), []byte(tt.confContent), 0644))
302302

303303
cli, cmd := setupStackPackPackageCmd(t)
304304

@@ -314,7 +314,7 @@ func TestStackpackPackageCommand_NonExistentDirectory(t *testing.T) {
314314

315315
_, err := di.ExecuteCommandWithContext(&cli.Deps, cmd, "-d", "/non/existent/directory")
316316
require.Error(t, err)
317-
assert.Contains(t, err.Error(), "failed to parse stackpack.conf")
317+
assert.Contains(t, err.Error(), "failed to parse stackpack.yaml")
318318
assert.Contains(t, err.Error(), "no such file or directory")
319319
}
320320

@@ -345,7 +345,7 @@ func TestStackpackPackageCommand_CreateOutputDirectory(t *testing.T) {
345345
assert.NoError(t, err, "Zip file should be created in nested directory")
346346
}
347347

348-
func TestHoconParser_Parse(t *testing.T) {
348+
func TestYamlParser_Parse(t *testing.T) {
349349
tests := []struct {
350350
name string
351351
content string
@@ -355,48 +355,48 @@ func TestHoconParser_Parse(t *testing.T) {
355355
errorContains string
356356
}{
357357
{
358-
name: "valid HOCON with quotes",
359-
content: `name = "my-stackpack"
360-
version = "1.2.3"`,
358+
name: "valid YAML with quotes",
359+
content: `name: "my-stackpack"
360+
version: "1.2.3"`,
361361
expectedName: "my-stackpack",
362362
expectedVer: "1.2.3",
363363
expectError: false,
364364
},
365365
{
366-
name: "valid HOCON without quotes",
367-
content: `name = my-stackpack
368-
version = "1.2.3"`,
366+
name: "valid YAML without quotes",
367+
content: `name: my-stackpack
368+
version: "1.2.3"`,
369369
expectedName: "my-stackpack",
370370
expectedVer: "1.2.3",
371371
expectError: false,
372372
},
373373
{
374-
name: "HOCON with comments",
374+
name: "YAML with comments",
375375
content: `# This is a comment
376-
name = "test-app"
376+
name: "test-app"
377377
# Another comment
378-
version = "2.0.0"`,
378+
version: "2.0.0"`,
379379
expectedName: "test-app",
380380
expectedVer: "2.0.0",
381381
expectError: false,
382382
},
383383
{
384384
name: "missing name",
385-
content: `version = "1.0.0"`,
385+
content: `version: "1.0.0"`,
386386
expectError: true,
387-
errorContains: "name not found in stackpack.conf",
387+
errorContains: "name not found in stackpack.yaml",
388388
},
389389
{
390390
name: "missing version",
391-
content: `name = "test"`,
391+
content: `name: "test"`,
392392
expectError: true,
393-
errorContains: "version not found in stackpack.conf",
393+
errorContains: "version not found in stackpack.yaml",
394394
},
395395
{
396-
name: "invalid HOCON syntax",
397-
content: `name = "test" { invalid`,
396+
name: "invalid YAML syntax",
397+
content: `name: "test" { invalid`,
398398
expectError: true,
399-
errorContains: "failed to parse stackpack.conf file",
399+
errorContains: "failed to parse stackpack.yaml file",
400400
},
401401
}
402402

@@ -406,10 +406,10 @@ version = "2.0.0"`,
406406
require.NoError(t, err)
407407
defer os.RemoveAll(tempDir)
408408

409-
confPath := filepath.Join(tempDir, "test.conf")
409+
confPath := filepath.Join(tempDir, "test.yaml")
410410
require.NoError(t, os.WriteFile(confPath, []byte(tt.content), 0644))
411411

412-
parser := &HoconParser{}
412+
parser := &YamlParser{}
413413
result, err := parser.Parse(confPath)
414414

415415
if tt.expectError {
@@ -428,21 +428,12 @@ version = "2.0.0"`,
428428
}
429429
}
430430

431-
func TestHoconParser_ParseNonExistentFile(t *testing.T) {
432-
parser := &HoconParser{}
433-
result, err := parser.Parse("/non/existent/file.conf")
434-
435-
require.Error(t, err)
436-
assert.Contains(t, err.Error(), "failed to read file")
437-
assert.Nil(t, result)
438-
}
439-
440-
func TestYamlParser_Parse(t *testing.T) {
431+
func TestYamlParser_ParseNonExistentFile(t *testing.T) {
441432
parser := &YamlParser{}
442-
result, err := parser.Parse("any-path")
433+
result, err := parser.Parse("/non/existent/file.yaml")
443434

444435
require.Error(t, err)
445-
assert.Contains(t, err.Error(), "YAML format not yet implemented")
436+
assert.Contains(t, err.Error(), "failed to read file")
446437
assert.Nil(t, result)
447438
}
448439

@@ -459,7 +450,7 @@ func TestValidateStackpackDirectory(t *testing.T) {
459450
require.NoError(t, os.MkdirAll(filepath.Join(dir, "provisioning"), 0755))
460451
require.NoError(t, os.MkdirAll(filepath.Join(dir, "resources"), 0755))
461452
require.NoError(t, os.WriteFile(filepath.Join(dir, "README.md"), []byte("readme"), 0644))
462-
require.NoError(t, os.WriteFile(filepath.Join(dir, "stackpack.conf"), []byte("conf"), 0644))
453+
require.NoError(t, os.WriteFile(filepath.Join(dir, "stackpack.yaml"), []byte("yaml"), 0644))
463454
},
464455
expectError: false,
465456
},
@@ -468,7 +459,7 @@ func TestValidateStackpackDirectory(t *testing.T) {
468459
setupFunc: func(dir string) {
469460
require.NoError(t, os.MkdirAll(filepath.Join(dir, "resources"), 0755))
470461
require.NoError(t, os.WriteFile(filepath.Join(dir, "README.md"), []byte("readme"), 0644))
471-
require.NoError(t, os.WriteFile(filepath.Join(dir, "stackpack.conf"), []byte("conf"), 0644))
462+
require.NoError(t, os.WriteFile(filepath.Join(dir, "stackpack.yaml"), []byte("yaml"), 0644))
472463
},
473464
expectError: true,
474465
errorContains: "required stackpack item not found: provisioning",

0 commit comments

Comments
 (0)