Skip to content

Commit bb173c1

Browse files
STAC-23385: Use Yaml version of the conf
1 parent e279981 commit bb173c1

5 files changed

Lines changed: 84 additions & 72 deletions

File tree

cmd/stackpack/stackpack_package.go

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

33
import (
44
"archive/zip"
5+
"bytes"
56
"fmt"
67
"io"
78
"os"
@@ -12,6 +13,7 @@ import (
1213
"github.com/spf13/cobra"
1314
"github.com/stackvista/stackstate-cli/internal/common"
1415
"github.com/stackvista/stackstate-cli/internal/di"
16+
"gopkg.in/yaml.v3"
1517
)
1618

1719
const (
@@ -73,16 +75,35 @@ func (h *HoconParser) Parse(filePath string) (*StackpackInfo, error) {
7375
type YamlParser struct{}
7476

7577
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")
78+
content, err := os.ReadFile(filePath)
79+
if err != nil {
80+
return nil, fmt.Errorf("failed to read file: %w", err)
81+
}
82+
83+
dec := yaml.NewDecoder(bytes.NewBuffer(content))
84+
cfg := &StackpackInfo{}
85+
86+
if err := dec.Decode(&cfg); err != nil {
87+
return nil, fmt.Errorf("failed to parse stackpack.yaml file: %w", err)
88+
}
89+
90+
if cfg.Name == "" {
91+
return nil, fmt.Errorf("name not found in stackpack.yaml")
92+
}
93+
94+
if cfg.Version == "" {
95+
return nil, fmt.Errorf("version not found in stackpack.yaml")
96+
}
97+
98+
return cfg, nil
7899
}
79100

80101
// Required files and directories for a valid stackpack
81102
var requiredStackpackItems = []string{
82103
"provisioning",
83104
"README.md",
84105
"resources",
85-
"stackpack.conf",
106+
"stackpack.yaml",
86107
}
87108

88109
// StackpackPackageCommand creates the package subcommand
@@ -97,10 +118,10 @@ Creates a zip file containing all required stackpack files and directories:
97118
- provisioning/ (directory)
98119
- README.md (file)
99120
- resources/ (directory)
100-
- stackpack.conf (file)
121+
- stackpack.yaml (file)
101122
102123
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.`,
124+
version are extracted from stackpack.yaml and created in the current directory.`,
104125
Example: `# Package stackpack in current directory
105126
sts stackpack package
106127
@@ -142,10 +163,10 @@ func RunStackpackPackageCommand(args *PackageArgs) func(cli *di.Deps, cmd *cobra
142163
args.StackpackDir = absStackpackDir
143164

144165
// 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"))
166+
parser := &YamlParser{}
167+
stackpackInfo, err := parser.Parse(filepath.Join(args.StackpackDir, "stackpack.yaml"))
147168
if err != nil {
148-
return common.NewRuntimeError(fmt.Errorf("failed to parse stackpack.conf: %w", err))
169+
return common.NewRuntimeError(fmt.Errorf("failed to parse stackpack.yaml: %w", err))
149170
}
150171

151172
// Set default archive file path if not specified

cmd/stackpack/stackpack_package_test.go

Lines changed: 31 additions & 40 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

@@ -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",

cmd/stackpack/stackpack_test_cmd.go

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ import (
1818
)
1919

2020
const (
21-
stackpackConfigFile = "stackpack.conf"
21+
stackpackConfigFile = "stackpack.yaml"
2222
)
2323

2424
// TestArgs contains arguments for stackpack test command
@@ -96,7 +96,7 @@ func RunStackpackTestCommand(args *TestArgs) di.CmdWithApiFn {
9696
}
9797

9898
// Parse stackpack configuration to get original version
99-
parser := &HoconParser{}
99+
parser := &YamlParser{}
100100
stackpackConf := filepath.Join(args.StackpackDir, stackpackConfigFile)
101101
originalInfo, err := parser.Parse(stackpackConf)
102102
if err != nil {
@@ -286,7 +286,7 @@ func bumpSnapshotVersionWithBase(configPath, baseVersion string) (string, error)
286286
} else {
287287
// Invalid format: reset to cli-test.10000
288288
newVersion = fmt.Sprintf("%d.%d.%d-cli-test.10000", version.Major, version.Minor, version.Patch)
289-
return newVersion, updateVersionInHocon(configPath, newVersion)
289+
return newVersion, updateVersionInYaml(configPath, newVersion)
290290
}
291291

292292
// Rebuild pre-release parts with incremented cli-test number
@@ -310,7 +310,7 @@ func bumpSnapshotVersionWithBase(configPath, baseVersion string) (string, error)
310310
newVersion = fmt.Sprintf("%d.%d.%d-cli-test.10000", version.Major, version.Minor, version.Patch)
311311
}
312312

313-
return newVersion, updateVersionInHocon(configPath, newVersion)
313+
return newVersion, updateVersionInYaml(configPath, newVersion)
314314
}
315315

316316
// confirmUpload prompts user for confirmation before upload
@@ -442,25 +442,25 @@ func copyFile(src, dst string, mode os.FileMode) error {
442442
return err
443443
}
444444

445-
// updateVersionInHocon updates the version field in a HOCON configuration using regex
446-
func updateVersionInHocon(configPath, newVersion string) error {
445+
// updateVersionInYaml updates the version field in a HOCON configuration using regex
446+
func updateVersionInYaml(configPath, newVersion string) error {
447447
// Read the current config
448448
content, err := os.ReadFile(configPath)
449449
if err != nil {
450450
return fmt.Errorf("failed to read config file: %w", err)
451451
}
452452

453453
// Parse as HOCON to validate structure
454-
parser := &HoconParser{}
454+
parser := &YamlParser{}
455455
_, err = parser.Parse(configPath)
456456
if err != nil {
457-
return fmt.Errorf("failed to parse HOCON config: %w", err)
457+
return fmt.Errorf("failed to parse Yaml config: %w", err)
458458
}
459459

460460
// Use regex to replace version while preserving HOCON structure
461461
// This is more reliable than string replacement as it targets the version field specifically
462462
oldContent := string(content)
463-
versionRegex := regexp.MustCompile(`(?m)^(\s*version\s*=\s*)"[^"]*"(.*)$`)
463+
versionRegex := regexp.MustCompile(`(?m)^(\s*version\s*: \s*)"[^"]*"(.*)$`)
464464
newContent := versionRegex.ReplaceAllString(oldContent, `${1}"`+newVersion+`"${2}`)
465465

466466
if oldContent == newContent {

cmd/stackpack/stackpack_test_cmd_test.go

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -85,10 +85,10 @@ func TestBumpSnapshotVersion(t *testing.T) {
8585
require.NoError(t, err)
8686
defer os.RemoveAll(tempDir)
8787

88-
configPath := filepath.Join(tempDir, "stackpack.conf")
89-
configContent := fmt.Sprintf(`name = "test-stackpack"
90-
version = "%s"
91-
displayName = "Test StackPack"`, tt.currentVersion)
88+
configPath := filepath.Join(tempDir, "stackpack.yaml")
89+
configContent := fmt.Sprintf(`name: "test-stackpack"
90+
version: "%s"
91+
displayName: "Test StackPack"`, tt.currentVersion)
9292
require.NoError(t, os.WriteFile(configPath, []byte(configContent), 0644))
9393

9494
// Test version bumping
@@ -105,24 +105,24 @@ displayName = "Test StackPack"`, tt.currentVersion)
105105
}
106106
}
107107

108-
func TestUpdateVersionInHocon(t *testing.T) {
108+
func TestUpdateVersionInYaml(t *testing.T) {
109109
// Create temporary config file
110-
tempDir, err := os.MkdirTemp("", "stackpack-hocon-test-*")
110+
tempDir, err := os.MkdirTemp("", "stackpack-yaml-test-*")
111111
require.NoError(t, err)
112112
defer os.RemoveAll(tempDir)
113113

114-
configPath := filepath.Join(tempDir, "stackpack.conf")
114+
configPath := filepath.Join(tempDir, "stackpack.yaml")
115115
originalVersion := "2.0.0"
116116
newVersion := "2.0.0-cli-test.1"
117117

118118
// Create config with original version
119-
configContent := fmt.Sprintf(`name = "test-stackpack"
120-
version = "%s"
121-
displayName = "Test StackPack"`, originalVersion)
119+
configContent := fmt.Sprintf(`name: "test-stackpack"
120+
version: "%s"
121+
displayName: "Test StackPack"`, originalVersion)
122122
require.NoError(t, os.WriteFile(configPath, []byte(configContent), 0644))
123123

124124
// Test version update using HOCON approach
125-
err = updateVersionInHocon(configPath, newVersion)
125+
err = updateVersionInYaml(configPath, newVersion)
126126
require.NoError(t, err)
127127

128128
// Verify config file was updated and is still valid HOCON
@@ -193,10 +193,10 @@ func TestStackpackTestCommand_RequiredFlags(t *testing.T) {
193193
assert.Contains(t, err.Error(), tt.errorMessage)
194194
}
195195
} else if err != nil {
196-
// Note: This will fail due to missing stackpack.conf, but that's expected
196+
// Note: This will fail due to missing stackpack.yaml, but that's expected
197197
// We're only testing flag parsing here
198198
// Should fail on stackpack.conf parsing, not flag validation
199-
assert.Contains(t, err.Error(), "stackpack.conf")
199+
assert.Contains(t, err.Error(), "stackpack.yaml")
200200
}
201201
})
202202
}
@@ -234,8 +234,8 @@ func TestStackpackTestCommand_DirectoryHandling(t *testing.T) {
234234

235235
// Should fail on API calls (upload/install), not on directory or config parsing
236236
if err != nil {
237-
// The error should not be about missing stackpack.conf or directory issues
238-
assert.NotContains(t, err.Error(), "stackpack.conf")
237+
// The error should not be about missing stackpack.yaml or directory issues
238+
assert.NotContains(t, err.Error(), "stackpack.yaml")
239239
assert.NotContains(t, err.Error(), "no such file or directory")
240240
}
241241
})
-1 Bytes
Binary file not shown.

0 commit comments

Comments
 (0)