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
11 changes: 10 additions & 1 deletion .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,16 @@ jobs:
working-directory: ./src

- name: Run unit tests
run: go test -v ./...
run: |
echo "Running unit tests for all packages..."
go test -v ./...
working-directory: ./src

- name: Generate test coverage report
run: |
echo "Generating test coverage report..."
go test ./... -coverprofile=coverage.out
go tool cover -func=coverage.out
working-directory: ./src

- name: Run integration tests
Expand Down
56 changes: 44 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,7 @@ cd src
go test -v ./...

# Run integration tests (requires built binary)
cd ..
./test/integration_test.sh
```

Expand Down Expand Up @@ -155,10 +156,28 @@ go vet ./...

### Unit Tests

Located in `src/*_test.go`, these test core functionality:
- Resource path resolution
- Default values generation
- Secrets integration logic
The project includes comprehensive unit tests located in `src/*_test.go` and `src/internal/*/` packages:

**Core Functionality Tests:**
- Resource path resolution and environment variable handling
- Default values generation for global and cluster group configurations
- Secrets integration logic and template handling

**Helm Chart Discovery Tests:**
- `FindTopLevelCharts()` correctly identifies top-level Helm charts
- Properly skips sub-charts, hidden directories, and invalid chart structures
- `IsHelmChart()` validates chart structure (Chart.yaml, values.yaml, templates/)

**Pattern Processing Tests:**
- URL parsing for SSH, HTTPS, and HTTP Git repository formats
- Error handling for invalid or unsupported URL formats
- Field preservation during YAML processing (custom user fields are never overwritten)
- Proper merging of defaults with existing configuration files

**Field Preservation Verification:**
- Tests ensure that custom fields in `values-global.yaml` are preserved
- Tests verify that custom fields in cluster group values files are maintained
- Tests confirm that nested custom fields and arrays are properly handled

### Integration Tests

Expand Down Expand Up @@ -193,16 +212,29 @@ All code must pass linting and tests before being merged or deployed.

## Architecture

The CLI is organized into focused modules:
The CLI is organized into focused packages following Go best practices:

**Main Package (`src/`):**
- `main.go` - Application entry point

**Command Package (`src/cmd/`):**
- `root.go` - Cobra CLI setup and root command
- `init.go` - Initialization command logic and orchestration

**Internal Packages (`src/internal/`):**
- `fileutils/` - File operations, resource management, and path resolution
- `helm/` - Helm chart discovery and validation
- `pattern/` - Core pattern processing, Git operations, and URL parsing
- `types/` - YAML structure definitions and default value constructors

- `main.go` - CLI setup and command definitions (Cobra)
- `commands.go` - Command logic and orchestration
- `fileutils.go` - File operations and resource management
- `pattern.go` - Core pattern processing and Git operations
- `helm.go` - Helm chart discovery
- `values_*.go` - YAML structure definitions
**Key Design Principles:**
- **Separation of Concerns**: Each package has a single, well-defined responsibility
- **Testability**: All packages are thoroughly unit tested with comprehensive coverage
- **Field Preservation**: YAML processing preserves all user-defined custom fields
- **Error Handling**: Comprehensive error handling with descriptive messages
- **Modularity**: Clean interfaces between packages for maintainability

This modular design makes the codebase maintainable and testable.
This modular design makes the codebase maintainable, testable, and extensible.

---

Expand Down
67 changes: 67 additions & 0 deletions src/cmd/init.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
package cmd

import (
"fmt"
"path/filepath"

"github.com/dminnear-rh/patternizer/internal/fileutils"
"github.com/dminnear-rh/patternizer/internal/helm"
"github.com/dminnear-rh/patternizer/internal/pattern"
)

// runInit handles the initialization logic for the init command.
func runInit(withSecrets bool) error {
// Get pattern name and repository root
patternName, repoRoot, err := pattern.GetPatternNameAndRepoRoot()
if err != nil {
return fmt.Errorf("error getting pattern information: %w", err)
}

// Find Helm charts in the repository
chartPaths, err := helm.FindTopLevelCharts(repoRoot)
if err != nil {
return fmt.Errorf("error finding Helm charts: %w", err)
}

// Process values-global.yaml
actualPatternName, clusterGroupName, err := pattern.ProcessGlobalValues(patternName, repoRoot)
if err != nil {
return fmt.Errorf("error processing global values: %w", err)
}

// Process cluster group values using the actual pattern name and cluster group name from the global values
if err := pattern.ProcessClusterGroupValues(actualPatternName, clusterGroupName, repoRoot, chartPaths, withSecrets); err != nil {
return fmt.Errorf("error processing cluster group values: %w", err)
}

// Copy pattern.sh from resources
resourcesDir, err := fileutils.GetResourcePath()
if err != nil {
return fmt.Errorf("error getting resource path: %w", err)
}

patternShSrc := filepath.Join(resourcesDir, "pattern.sh")
patternShDst := filepath.Join(repoRoot, "pattern.sh")
if err := fileutils.CopyFile(patternShSrc, patternShDst); err != nil {
return fmt.Errorf("error copying pattern.sh: %w", err)
}

// Set USE_SECRETS in pattern.sh based on the flag
if err := fileutils.ModifyPatternShScript(patternShDst, withSecrets); err != nil {
return fmt.Errorf("error modifying pattern.sh: %w", err)
}

// Handle secrets setup if requested
if withSecrets {
if err := fileutils.HandleSecretsSetup(resourcesDir, repoRoot); err != nil {
return fmt.Errorf("error setting up secrets: %w", err)
}
}

fmt.Printf("Successfully initialized pattern '%s' in %s\n", actualPatternName, repoRoot)
if withSecrets {
fmt.Println("Secrets configuration has been enabled.")
}

return nil
}
46 changes: 46 additions & 0 deletions src/cmd/root.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package cmd

import (
"os"

"github.com/spf13/cobra"
)

// Execute adds all child commands to the root command and sets flags appropriately.
// This is called by main.main(). It only needs to happen once to the rootCmd.
func Execute() {
var withSecrets bool

var rootCmd = &cobra.Command{
Use: "patternizer",
Short: "A CLI tool for initializing Validated Patterns",
Long: `patternizer is a CLI tool for creating and managing validated pattern configurations.
It helps generate the necessary YAML files and setup for Validated Patterns including
values-global.yaml, values-<clustergroup>.yaml, and optional secrets configuration.`,
}

var initCmd = &cobra.Command{
Use: "init",
Short: "Initialize pattern files",
Long: `Initialize pattern files creates or updates the necessary YAML configuration files
for a validated pattern, including values-global.yaml and values-<clustergroup>.yaml.

When --with-secrets is specified, it also copies the secrets template and
configures the pattern.sh script for secrets usage.`,
RunE: func(cmd *cobra.Command, args []string) error {
// Check if "help" is passed as an argument
if len(args) > 0 && args[0] == "help" {
return cmd.Help()
}
return runInit(withSecrets)
},
}

initCmd.Flags().BoolVar(&withSecrets, "with-secrets", false, "Include secrets template and configure pattern for secrets usage")

rootCmd.AddCommand(initCmd)

if err := rootCmd.Execute(); err != nil {
os.Exit(1)
}
}
42 changes: 0 additions & 42 deletions src/commands.go

This file was deleted.

107 changes: 0 additions & 107 deletions src/fileutils.go

This file was deleted.

10 changes: 8 additions & 2 deletions src/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,15 @@ module github.com/dminnear-rh/patternizer

go 1.24.4

require (
github.com/spf13/cobra v1.9.1
gopkg.in/yaml.v3 v3.0.1
)

require (
github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/spf13/cobra v1.9.1 // indirect
github.com/kr/pretty v0.3.1 // indirect
github.com/rogpeppe/go-internal v1.14.1 // indirect
github.com/spf13/pflag v1.0.6 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect
)
Loading