Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 24 additions & 5 deletions cmd/stackpack/stackpack_package.go
Original file line number Diff line number Diff line change
Expand Up @@ -65,10 +65,16 @@ func (y *YamlParser) Parse(filePath string) (*StackpackInfo, error) {

// Required files and directories for a valid stackpack
var requiredStackpackItems = []string{
"provisioning",
"stackpack.yaml",
"README.md",
"settings",
"resources",
"stackpack.yaml",
}

// Optional files and directories for a valid stackpack
var optionalStackpackItems = []string{
"icons",
"includes",
}

// StackpackPackageCommand creates the package subcommand
Expand All @@ -79,11 +85,13 @@ func StackpackPackageCommand(cli *di.Deps) *cobra.Command {
Short: "Package a stackpack into an .sts file",
Long: `Package a stackpack into an .sts file.

Creates an .sts file containing all required stackpack files and directories:
- provisioning/ (directory)
Creates an .sts file containing all stackpack files and directories:
- stackpack.yaml (file)
- README.md (file)
- settings/ (directory)
- resources/ (directory)
- stackpack.yaml (file)
- icons/ (directory, optional)
- includes/ (directory, optional)

The .sts file is named <stackpack_name>-<version>.sts where the name and
version are extracted from stackpack.yaml and created in the current directory.`,
Expand Down Expand Up @@ -222,6 +230,17 @@ func createStackpackZip(sourceDir, zipPath string) error {
}
}

// Add each optional item to the zip
for _, item := range optionalStackpackItems {
itemPath := filepath.Join(sourceDir, item)
if err := addToZip(zipWriter, itemPath, item); err != nil {
if os.IsNotExist(err) {
continue
}
return fmt.Errorf("failed to add %s to zip: %w", item, err)
}
}

return nil
}

Expand Down
24 changes: 12 additions & 12 deletions cmd/stackpack/stackpack_package_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ func setupStackPackPackageCmd(t *testing.T) (*di.MockDeps, *cobra.Command) {
// createTestStackpack creates a valid stackpack directory structure for testing
func createTestStackpack(t *testing.T, dir string, name string, version string) {
// Create required directories
require.NoError(t, os.MkdirAll(filepath.Join(dir, "provisioning"), 0755))
require.NoError(t, os.MkdirAll(filepath.Join(dir, "settings"), 0755))
require.NoError(t, os.MkdirAll(filepath.Join(dir, "resources"), 0755))

// Create stackpack.conf
Expand All @@ -42,7 +42,7 @@ version: "%s"
require.NoError(t, os.WriteFile(filepath.Join(dir, "README.md"), []byte(readme), 0644))

// Create test files in subdirectories
require.NoError(t, os.WriteFile(filepath.Join(dir, "provisioning", "test.sty"), []byte("test provisioning"), 0644))
require.NoError(t, os.WriteFile(filepath.Join(dir, "settings", "test.sty"), []byte("test settings"), 0644))
require.NoError(t, os.WriteFile(filepath.Join(dir, "resources", "overview.md"), []byte("test overview"), 0644))
}

Expand Down Expand Up @@ -192,18 +192,18 @@ func TestStackpackPackageCommand_MissingRequiredFiles(t *testing.T) {
expectedError string
}{
{
name: "missing provisioning directory",
name: "missing settings directory",
setupFunc: func(dir string) {
require.NoError(t, os.MkdirAll(filepath.Join(dir, "resources"), 0755))
require.NoError(t, os.WriteFile(filepath.Join(dir, "README.md"), []byte("readme"), 0644))
require.NoError(t, os.WriteFile(filepath.Join(dir, "stackpack.yaml"), []byte("name: \"test\"\nversion: \"1.0.0\""), 0644))
},
expectedError: "required stackpack item not found: provisioning",
expectedError: "required stackpack item not found: settings",
},
{
name: "missing README.md file",
setupFunc: func(dir string) {
require.NoError(t, os.MkdirAll(filepath.Join(dir, "provisioning"), 0755))
require.NoError(t, os.MkdirAll(filepath.Join(dir, "settings"), 0755))
require.NoError(t, os.MkdirAll(filepath.Join(dir, "resources"), 0755))
require.NoError(t, os.WriteFile(filepath.Join(dir, "stackpack.yaml"), []byte("name: \"test\"\nversion: \"1.0.0\""), 0644))
},
Expand All @@ -212,7 +212,7 @@ func TestStackpackPackageCommand_MissingRequiredFiles(t *testing.T) {
{
name: "missing resources directory",
setupFunc: func(dir string) {
require.NoError(t, os.MkdirAll(filepath.Join(dir, "provisioning"), 0755))
require.NoError(t, os.MkdirAll(filepath.Join(dir, "settings"), 0755))
require.NoError(t, os.WriteFile(filepath.Join(dir, "README.md"), []byte("readme"), 0644))
require.NoError(t, os.WriteFile(filepath.Join(dir, "stackpack.yaml"), []byte("name: \"test\"\nversion: \"1.0.0\""), 0644))
},
Expand All @@ -221,7 +221,7 @@ func TestStackpackPackageCommand_MissingRequiredFiles(t *testing.T) {
{
name: "missing stackpack.yaml file",
setupFunc: func(dir string) {
require.NoError(t, os.MkdirAll(filepath.Join(dir, "provisioning"), 0755))
require.NoError(t, os.MkdirAll(filepath.Join(dir, "settings"), 0755))
require.NoError(t, os.MkdirAll(filepath.Join(dir, "resources"), 0755))
require.NoError(t, os.WriteFile(filepath.Join(dir, "README.md"), []byte("readme"), 0644))
},
Expand Down Expand Up @@ -293,7 +293,7 @@ version: ""`,
require.NoError(t, os.MkdirAll(stackpackDir, 0755))

// Create required directories and files except stackpack.conf
require.NoError(t, os.MkdirAll(filepath.Join(stackpackDir, "provisioning"), 0755))
require.NoError(t, os.MkdirAll(filepath.Join(stackpackDir, "settings"), 0755))
require.NoError(t, os.MkdirAll(filepath.Join(stackpackDir, "resources"), 0755))
require.NoError(t, os.WriteFile(filepath.Join(stackpackDir, "README.md"), []byte("readme"), 0644))

Expand Down Expand Up @@ -447,30 +447,30 @@ func TestValidateStackpackDirectory(t *testing.T) {
{
name: "valid stackpack directory",
setupFunc: func(dir string) {
require.NoError(t, os.MkdirAll(filepath.Join(dir, "provisioning"), 0755))
require.NoError(t, os.MkdirAll(filepath.Join(dir, "settings"), 0755))
require.NoError(t, os.MkdirAll(filepath.Join(dir, "resources"), 0755))
require.NoError(t, os.WriteFile(filepath.Join(dir, "README.md"), []byte("readme"), 0644))
require.NoError(t, os.WriteFile(filepath.Join(dir, "stackpack.yaml"), []byte("yaml"), 0644))
},
expectError: false,
},
{
name: "missing provisioning directory",
name: "missing settings directory",
setupFunc: func(dir string) {
require.NoError(t, os.MkdirAll(filepath.Join(dir, "resources"), 0755))
require.NoError(t, os.WriteFile(filepath.Join(dir, "README.md"), []byte("readme"), 0644))
require.NoError(t, os.WriteFile(filepath.Join(dir, "stackpack.yaml"), []byte("yaml"), 0644))
},
expectError: true,
errorContains: "required stackpack item not found: provisioning",
errorContains: "required stackpack item not found: settings",
},
{
name: "missing all required items",
setupFunc: func(dir string) {
// Create empty directory
},
expectError: true,
errorContains: "required stackpack item not found: provisioning",
errorContains: "required stackpack item not found: stackpack.yaml",
},
}

Expand Down