Skip to content

Commit 9180baf

Browse files
authored
Small updates (#19)
* add latest fixes from common to pattern.sh * fix new patterns always defaulting to repo pattern name * write yaml with two spaces instead of 4 * remove projects from default values
1 parent 8951097 commit 9180baf

13 files changed

Lines changed: 124 additions & 184 deletions

‎Containerfile‎

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,6 @@ WORKDIR ${PATTERNIZER_RESOURCES_DIR}
2424

2525
COPY resources/* .
2626

27-
ARG PATTERN_REPO_ROOT=/repo
28-
WORKDIR ${PATTERN_REPO_ROOT}
29-
3027
ENV PATTERNIZER_RESOURCES_DIR=${PATTERNIZER_RESOURCES_DIR}
3128

3229
ENTRYPOINT ["patternizer"]

‎README.md‎

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# Patternizer
22

3-
![Version: 0.2.0](https://img.shields.io/badge/Version-0.2.0-informational?style=flat-square)
3+
![Version: 0.2.1](https://img.shields.io/badge/Version-0.2.0-informational?style=flat-square)
44
[![Quay Repository](https://img.shields.io/badge/Quay.io-patternizer-blue?logo=quay)](https://quay.io/repository/validatedpatterns/patternizer)
55
[![CI Pipeline](https://github.com/validatedpatterns/patternizer/actions/workflows/build-push.yaml/badge.svg?branch=main)](https://github.com/validatedpatterns/patternizer/actions/workflows/build-push.yaml)
66

@@ -50,7 +50,7 @@ Navigate to your repository's root directory and run the initialization command:
5050

5151
```bash
5252
# In the root of your pattern-repo
53-
podman run -v "$PWD:/repo:z" quay.io/validatedpatterns/patternizer init
53+
podman run -v "$PWD:$PWD:z" -w "$PWD" quay.io/validatedpatterns/patternizer init
5454
```
5555

5656
This single command will generate all the necessary files to turn your repository into a Validated Pattern.
@@ -68,7 +68,7 @@ This single command will generate all the necessary files to turn your repositor
6868
2. **Initialize the pattern using Patternizer:**
6969

7070
```bash
71-
podman run -v "$PWD:/repo:z" quay.io/validatedpatterns/patternizer init
71+
podman run -v "$PWD:$PWD:z" -w "$PWD" quay.io/validatedpatterns/patternizer init
7272
```
7373

7474
3. **Review, commit, and push the generated files:**
@@ -90,18 +90,18 @@ This single command will generate all the necessary files to turn your repositor
9090

9191
### Container Usage (Recommended)
9292

93-
Using the prebuilt container is the easiest way to run Patternizer, as it requires no local installation. The `-v "$PWD:/repo:z"` flag mounts your current directory into the container's `/repo` workspace.
93+
Using the prebuilt container is the easiest way to run Patternizer, as it requires no local installation. The `-v "$PWD:$PWD:z" -w "$PWD"` flag mounts your current directory into the container's `/repo` workspace.
9494
9595
#### **Initialize without secrets:**
9696
9797
```bash
98-
podman run -v "$PWD:/repo:z" quay.io/validatedpatterns/patternizer init
98+
podman run -v "$PWD:$PWD:z" -w "$PWD" quay.io/validatedpatterns/patternizer init
9999
```
100100
101101
#### **Initialize with secrets support:**
102102
103103
```bash
104-
podman run -v "$PWD:/repo:z" quay.io/validatedpatterns/patternizer init --with-secrets
104+
podman run -v "$PWD:$PWD:z" -w "$PWD" quay.io/validatedpatterns/patternizer init --with-secrets
105105
```
106106
107107
#### **Upgrade an existing pattern repository:**
@@ -110,10 +110,10 @@ Use this to migrate or refresh an existing pattern repo to the latest common str
110110
111111
```bash
112112
# Refresh common assets, keep your Makefile unless it lacks the include
113-
podman run -v "$PWD:/repo:z" quay.io/validatedpatterns/patternizer upgrade
113+
podman run -v "$PWD:$PWD:z" -w "$PWD" quay.io/validatedpatterns/patternizer upgrade
114114
115115
# Replace your Makefile with the default from Patternizer
116-
podman run -v "$PWD:/repo:z" quay.io/validatedpatterns/patternizer upgrade --replace-makefile
116+
podman run -v "$PWD:$PWD:z" -w "$PWD" quay.io/validatedpatterns/patternizer upgrade --replace-makefile
117117
```
118118
119119
What upgrade does:

‎resources/pattern.sh‎

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ fi
6262

6363
# Detect if we use podman machine. If we do not then we bind mount local host ssl folders
6464
# if we are using podman machine then we do not bind mount anything (for now!)
65-
REMOTE_PODMAN=$(podman system connection list -q | wc -l)
65+
REMOTE_PODMAN=$(podman system connection list | tail -n +2 | wc -l)
6666
if [ $REMOTE_PODMAN -eq 0 ]; then # If we are not using podman machine we check the hosts folders
6767
# We check /etc/pki/tls because on ubuntu /etc/pki/fwupd sometimes
6868
# exists but not /etc/pki/tls and we do not want to bind mount in such a case
@@ -107,10 +107,11 @@ podman run -it --rm --pull=newer \
107107
-e UUID_FILE \
108108
-e VALUES_SECRET \
109109
${PKI_HOST_MOUNT_ARGS} \
110+
-v "$(pwd -P)":"$(pwd -P)" \
110111
-v "${HOME}":"${HOME}" \
111112
-v "${HOME}":/pattern-home \
112113
${PODMAN_ARGS} \
113114
${EXTRA_ARGS} \
114-
-w "$(pwd)" \
115+
-w "$(pwd -P)" \
115116
"$PATTERN_UTILITY_CONTAINER" \
116117
$@

‎src/internal/fileutils/fileutils.go‎

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ import (
66
"os"
77
"path/filepath"
88
"strings"
9+
10+
"gopkg.in/yaml.v3"
911
)
1012

1113
// CopyFile copies a file from src to dst. If dst already exists, it will be overwritten.
@@ -130,3 +132,30 @@ func PrependLineToFile(filePath, line string) error {
130132
newContents := []byte(line + "\n" + string(data))
131133
return os.WriteFile(filePath, newContents, mode)
132134
}
135+
136+
// WriteYAMLWithIndent marshals the given data structure to YAML and writes it to a file
137+
// with 2-space indentation. This ensures consistency with prettier formatting.
138+
func WriteYAMLWithIndent(data interface{}, filePath string) error {
139+
file, err := os.Create(filePath)
140+
if err != nil {
141+
return fmt.Errorf("failed to create file %s: %w", filePath, err)
142+
}
143+
defer file.Close()
144+
145+
encoder := yaml.NewEncoder(file)
146+
defer encoder.Close()
147+
148+
// Set indentation to 2 spaces instead of the default 4
149+
encoder.SetIndent(2)
150+
151+
if err := encoder.Encode(data); err != nil {
152+
return fmt.Errorf("failed to encode YAML to %s: %w", filePath, err)
153+
}
154+
155+
// Set file permissions to 0644
156+
if err := os.Chmod(filePath, 0o644); err != nil {
157+
return fmt.Errorf("failed to set permissions on %s: %w", filePath, err)
158+
}
159+
160+
return nil
161+
}

‎src/internal/fileutils/fileutils_test.go‎

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ import (
66
"runtime"
77
"strings"
88
"testing"
9+
10+
"gopkg.in/yaml.v3"
911
)
1012

1113
func writeFileWithMode(t *testing.T, path, content string, mode os.FileMode) {
@@ -221,3 +223,78 @@ func TestPrependLineToFile_PrependsAndPreservesMode(t *testing.T) {
221223
t.Fatalf("mode not preserved: got %v want %v", info.Mode().Perm(), mode.Perm())
222224
}
223225
}
226+
227+
func TestWriteYAMLWithIndent_Uses2SpaceIndentation(t *testing.T) {
228+
dir := t.TempDir()
229+
p := filepath.Join(dir, "test.yaml")
230+
231+
// Create a nested structure to verify indentation
232+
type NestedStruct struct {
233+
Field1 string `yaml:"field1"`
234+
Field2 int `yaml:"field2"`
235+
}
236+
type TestStruct struct {
237+
Name string `yaml:"name"`
238+
Nested NestedStruct `yaml:"nested"`
239+
Items []string `yaml:"items"`
240+
}
241+
242+
data := TestStruct{
243+
Name: "test",
244+
Nested: NestedStruct{
245+
Field1: "value1",
246+
Field2: 42,
247+
},
248+
Items: []string{"item1", "item2", "item3"},
249+
}
250+
251+
// Write the YAML with our function
252+
if err := WriteYAMLWithIndent(data, p); err != nil {
253+
t.Fatalf("WriteYAMLWithIndent failed: %v", err)
254+
}
255+
256+
// Read the file and verify indentation
257+
content, err := os.ReadFile(p)
258+
if err != nil {
259+
t.Fatalf("read failed: %v", err)
260+
}
261+
262+
// Verify 2-space indentation by checking the content
263+
// The nested fields should be indented with 2 spaces, not 4
264+
contentStr := string(content)
265+
if !strings.Contains(contentStr, " field1: value1") {
266+
t.Fatalf("expected 2-space indentation for nested.field1, got:\n%s", contentStr)
267+
}
268+
if !strings.Contains(contentStr, " field2: 42") {
269+
t.Fatalf("expected 2-space indentation for nested.field2, got:\n%s", contentStr)
270+
}
271+
// Verify it's not 4-space indentation
272+
if strings.Contains(contentStr, " field1") || strings.Contains(contentStr, " field2") {
273+
t.Fatalf("unexpected 4-space indentation found:\n%s", contentStr)
274+
}
275+
276+
// Verify the file can be unmarshaled back correctly
277+
var decoded TestStruct
278+
if err := yaml.Unmarshal(content, &decoded); err != nil {
279+
t.Fatalf("failed to unmarshal written YAML: %v", err)
280+
}
281+
if decoded.Name != data.Name {
282+
t.Fatalf("name mismatch: got %q want %q", decoded.Name, data.Name)
283+
}
284+
if decoded.Nested.Field1 != data.Nested.Field1 {
285+
t.Fatalf("nested.field1 mismatch: got %q want %q", decoded.Nested.Field1, data.Nested.Field1)
286+
}
287+
if decoded.Nested.Field2 != data.Nested.Field2 {
288+
t.Fatalf("nested.field2 mismatch: got %d want %d", decoded.Nested.Field2, data.Nested.Field2)
289+
}
290+
291+
// Verify file permissions
292+
info, err := os.Stat(p)
293+
if err != nil {
294+
t.Fatalf("stat failed: %v", err)
295+
}
296+
expectedMode := os.FileMode(0o644)
297+
if info.Mode().Perm() != expectedMode.Perm() {
298+
t.Fatalf("mode mismatch: got %v want %v", info.Mode().Perm(), expectedMode.Perm())
299+
}
300+
}

‎src/internal/pattern/pattern.go‎

Lines changed: 5 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,10 @@ import (
44
"fmt"
55
"os"
66
"path/filepath"
7-
"strings"
87

98
"gopkg.in/yaml.v3"
109

10+
"github.com/dminnear-rh/patternizer/internal/fileutils"
1111
"github.com/dminnear-rh/patternizer/internal/types"
1212
)
1313

@@ -26,35 +26,6 @@ func GetPatternNameAndRepoRoot() (patternName, repoRoot string, err error) {
2626
return patternName, repoRoot, nil
2727
}
2828

29-
// extractPatternNameFromURL extracts the pattern name from a Git repository URL.
30-
// Returns an error if the URL format is not recognized.
31-
func extractPatternNameFromURL(url string) (string, error) {
32-
// Handle SSH URLs: git@github.com:user/repo.git
33-
if strings.HasPrefix(url, "git@") {
34-
parts := strings.Split(url, ":")
35-
if len(parts) >= 2 {
36-
repoPath := parts[1]
37-
repoName := filepath.Base(repoPath)
38-
return strings.TrimSuffix(repoName, ".git"), nil
39-
}
40-
return "", fmt.Errorf("invalid SSH URL format")
41-
}
42-
43-
// Handle HTTPS URLs: https://github.com/user/repo.git
44-
if strings.HasPrefix(url, "https://") {
45-
repoName := filepath.Base(url)
46-
return strings.TrimSuffix(repoName, ".git"), nil
47-
}
48-
49-
// Handle HTTP URLs: http://github.com/user/repo.git
50-
if strings.HasPrefix(url, "http://") {
51-
repoName := filepath.Base(url)
52-
return strings.TrimSuffix(repoName, ".git"), nil
53-
}
54-
55-
return "", fmt.Errorf("unsupported URL format: expected git@host:user/repo.git, https://host/user/repo.git, or http://host/user/repo.git")
56-
}
57-
5829
// ProcessGlobalValues processes the global values YAML file.
5930
// It returns the pattern name and cluster group name that should be used (from the file if they exist, or the detected/default names).
6031
func ProcessGlobalValues(patternName, repoRoot string, withSecrets bool) (actualPatternName, clusterGroupName string, err error) {
@@ -84,12 +55,8 @@ func ProcessGlobalValues(patternName, repoRoot string, withSecrets bool) (actual
8455
// If withSecrets is false, we want secretLoader to be disabled (disabled = true)
8556
values.Global.SecretLoader.Disabled = !withSecrets
8657

87-
// Write back the merged values
88-
finalYamlBytes, err := yaml.Marshal(values)
89-
if err != nil {
90-
return "", "", fmt.Errorf("failed to marshal global values: %w", err)
91-
}
92-
if err = os.WriteFile(globalValuesPath, finalYamlBytes, 0o644); err != nil {
58+
// Write back the merged values with 2-space indentation
59+
if err = fileutils.WriteYAMLWithIndent(values, globalValuesPath); err != nil {
9360
return "", "", fmt.Errorf("failed to write to %s: %w", globalValuesPath, err)
9461
}
9562

@@ -118,12 +85,8 @@ func ProcessClusterGroupValues(patternName, clusterGroupName, repoRoot string, c
11885
mergeClusterGroupValues(values, &existingValues)
11986
}
12087

121-
// Write back the merged values
122-
finalYamlBytes, err := yaml.Marshal(values)
123-
if err != nil {
124-
return fmt.Errorf("failed to marshal cluster group values: %w", err)
125-
}
126-
if err = os.WriteFile(clusterGroupValuesPath, finalYamlBytes, 0o644); err != nil {
88+
// Write back the merged values with 2-space indentation
89+
if err = fileutils.WriteYAMLWithIndent(values, clusterGroupValuesPath); err != nil {
12790
return fmt.Errorf("failed to write to %s: %w", clusterGroupValuesPath, err)
12891
}
12992

‎src/internal/pattern/pattern_test.go‎

Lines changed: 0 additions & 88 deletions
Original file line numberDiff line numberDiff line change
@@ -10,94 +10,6 @@ import (
1010
"github.com/dminnear-rh/patternizer/internal/types"
1111
)
1212

13-
// TestExtractPatternNameFromURL tests URL parsing for different Git URL formats.
14-
func TestExtractPatternNameFromURL(t *testing.T) {
15-
tests := []struct {
16-
name string
17-
url string
18-
expected string
19-
expectError bool
20-
}{
21-
{
22-
name: "SSH URL with .git suffix",
23-
url: "git@github.com:user/my-pattern.git",
24-
expected: "my-pattern",
25-
},
26-
{
27-
name: "SSH URL without .git suffix",
28-
url: "git@github.com:user/my-pattern",
29-
expected: "my-pattern",
30-
},
31-
{
32-
name: "HTTPS URL with .git suffix",
33-
url: "https://github.com/user/my-pattern.git",
34-
expected: "my-pattern",
35-
},
36-
{
37-
name: "HTTPS URL without .git suffix",
38-
url: "https://github.com/user/my-pattern",
39-
expected: "my-pattern",
40-
},
41-
{
42-
name: "HTTP URL with .git suffix",
43-
url: "http://github.com/user/my-pattern.git",
44-
expected: "my-pattern",
45-
},
46-
{
47-
name: "HTTP URL without .git suffix",
48-
url: "http://github.com/user/my-pattern",
49-
expected: "my-pattern",
50-
},
51-
{
52-
name: "GitLab SSH URL",
53-
url: "git@gitlab.com:group/subgroup/my-pattern.git",
54-
expected: "my-pattern",
55-
},
56-
{
57-
name: "GitLab HTTPS URL",
58-
url: "https://gitlab.com/group/subgroup/my-pattern.git",
59-
expected: "my-pattern",
60-
},
61-
{
62-
name: "Invalid SSH URL format",
63-
url: "git@github.com",
64-
expectError: true,
65-
},
66-
{
67-
name: "Unsupported protocol",
68-
url: "ftp://github.com/user/repo.git",
69-
expectError: true,
70-
},
71-
{
72-
name: "Empty URL",
73-
url: "",
74-
expectError: true,
75-
},
76-
}
77-
78-
for _, tt := range tests {
79-
t.Run(tt.name, func(t *testing.T) {
80-
result, err := extractPatternNameFromURL(tt.url)
81-
82-
if tt.expectError {
83-
if err == nil {
84-
t.Errorf("Expected error for URL '%s', but got none", tt.url)
85-
}
86-
return
87-
}
88-
89-
if err != nil {
90-
t.Errorf("Unexpected error for URL '%s': %v", tt.url, err)
91-
return
92-
}
93-
94-
if result != tt.expected {
95-
t.Errorf("extractPatternNameFromURL('%s') = '%s', expected '%s'", tt.url, result, tt.expected)
96-
}
97-
})
98-
}
99-
}
100-
10113
// TestProcessGlobalValuesPreservesFields tests that ProcessGlobalValues preserves existing user fields.
10214
func TestProcessGlobalValuesPreservesFields(t *testing.T) {
10315
tempDir, err := os.MkdirTemp("", "pattern-test-*")

0 commit comments

Comments
 (0)