Skip to content

Commit 58b1b1e

Browse files
committed
feat: component getter
1 parent 8b9af4a commit 58b1b1e

File tree

9 files changed

+179
-6
lines changed

9 files changed

+179
-6
lines changed
Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
package ocm_cli
2+
3+
import (
4+
"context"
5+
"fmt"
6+
"strings"
7+
)
8+
9+
type ComponentGetter struct {
10+
// Location of the root component in the format <repo>//<component>:<version>.
11+
rootComponentLocation string
12+
// Path to the deployment templates resource in the format <componentRef1>/.../<componentRefN>/<resourceName>.
13+
deploymentTemplates string
14+
ocmConfig string
15+
16+
// Fields derived during InitializeComponents
17+
rootComponentVersion *ComponentVersion
18+
templatesComponentVersion *ComponentVersion
19+
templatesComponentLocation string
20+
templatesResourceName string
21+
}
22+
23+
func NewComponentGetter(rootComponentLocation, deploymentTemplates, ocmConfig string) *ComponentGetter {
24+
return &ComponentGetter{
25+
rootComponentLocation: rootComponentLocation,
26+
deploymentTemplates: deploymentTemplates,
27+
ocmConfig: ocmConfig,
28+
}
29+
}
30+
31+
func (g *ComponentGetter) InitializeComponents(ctx context.Context) error {
32+
repo, err := extractRepoFromLocation(g.rootComponentLocation)
33+
if err != nil {
34+
return err
35+
}
36+
37+
rootComponentVersion, err := GetComponentVersion(ctx, g.rootComponentLocation, g.ocmConfig)
38+
if err != nil {
39+
return fmt.Errorf("error getting root component version %s: %w", g.rootComponentLocation, err)
40+
}
41+
g.rootComponentVersion = rootComponentVersion
42+
43+
g.deploymentTemplates = strings.TrimSpace(g.deploymentTemplates)
44+
segments := strings.Split(g.deploymentTemplates, "/")
45+
if len(segments) == 0 {
46+
return fmt.Errorf("deploymentTemplates path must contain a resource name or component references and a resource name separated by slashes (ref1/.../refN/resource): %s", g.deploymentTemplates)
47+
}
48+
referenceNames := segments[:len(segments)-1]
49+
g.templatesResourceName = segments[len(segments)-1]
50+
51+
cv := g.rootComponentVersion
52+
for _, refName := range referenceNames {
53+
cv, err = getReferencedComponentVersion(ctx, repo, cv, refName, g.ocmConfig)
54+
if err != nil {
55+
return fmt.Errorf("error getting referenced component version %s: %w", refName, err)
56+
}
57+
}
58+
59+
g.templatesComponentVersion = cv
60+
g.templatesComponentLocation = buildLocation(repo, cv.Component.Name, cv.Component.Version)
61+
return nil
62+
}
63+
64+
func (g *ComponentGetter) RootComponentVersion() *ComponentVersion {
65+
return g.rootComponentVersion
66+
}
67+
68+
func (g *ComponentGetter) TemplatesComponentVersion() *ComponentVersion {
69+
return g.templatesComponentVersion
70+
}
71+
72+
func getReferencedComponentVersion(ctx context.Context, repo string, parentCV *ComponentVersion, refName string, ocmConfig string) (*ComponentVersion, error) {
73+
ref, err := parentCV.GetComponentReference(refName)
74+
if err != nil {
75+
return nil, fmt.Errorf("error getting component reference %s: %w", refName, err)
76+
}
77+
78+
location := buildLocation(repo, ref.ComponentName, ref.Version)
79+
cv, err := GetComponentVersion(ctx, location, ocmConfig)
80+
if err != nil {
81+
return nil, fmt.Errorf("error getting component version %s: %w", location, err)
82+
}
83+
84+
return cv, nil
85+
}
86+
87+
func (g *ComponentGetter) DownloadTemplatesResource(ctx context.Context, downloadDir string) error {
88+
return downloadDirectoryResource(ctx, g.templatesComponentLocation, g.templatesResourceName, downloadDir, g.ocmConfig)
89+
}
90+
91+
func downloadDirectoryResource(ctx context.Context, componentLocation string, resourceName string, downloadDir string, ocmConfig string) error {
92+
return Execute(ctx,
93+
[]string{"download", "resources", componentLocation, resourceName},
94+
[]string{"--downloader", "ocm/dirtree", "--outfile", downloadDir},
95+
ocmConfig,
96+
)
97+
}
98+
99+
func extractRepoFromLocation(location string) (string, error) {
100+
parts := strings.SplitN(location, "//", 2)
101+
if len(parts) < 2 {
102+
return "", fmt.Errorf("invalid component location format, expected '<repo>//<component>:<version>': %s", location)
103+
}
104+
return parts[0], nil
105+
}
106+
107+
func buildLocation(repo, name, version string) string {
108+
return fmt.Sprintf("%s//%s:%s", repo, name, version)
109+
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
package ocm_cli_test
2+
3+
import (
4+
"testing"
5+
6+
"github.com/stretchr/testify/assert"
7+
8+
ocmcli "github.com/openmcp-project/bootstrapper/internal/ocm-cli"
9+
testutil "github.com/openmcp-project/bootstrapper/test/utils"
10+
)
11+
12+
func TestComponentGetter(t *testing.T) {
13+
const (
14+
rootComponentName = "github.com/openmcp-project/openmcp"
15+
templatesComponentName = "github.com/openmcp-project/gitops-templates"
16+
)
17+
18+
testutil.DownloadOCMAndAddToPath(t)
19+
ctf := testutil.BuildComponent("./testdata/02/component-constructor.yaml", t)
20+
rootLocation := ctf + "//github.com/openmcp-project/openmcp:v0.0.11"
21+
g := ocmcli.NewComponentGetter(rootLocation, "gitops-templates/test-resource", ocmcli.NoOcmConfig)
22+
23+
err := g.InitializeComponents(t.Context())
24+
assert.NoError(t, err, "Error initializing components")
25+
26+
rootComponentVersion := g.RootComponentVersion()
27+
assert.NotNil(t, rootComponentVersion, "Root component version should not be nil")
28+
assert.Equal(t, rootComponentName, rootComponentVersion.Component.Name, "Root component name should match")
29+
30+
templatesComponentVersion := g.TemplatesComponentVersion()
31+
assert.NotNil(t, templatesComponentVersion, "Templates component version should not be nil")
32+
assert.Equal(t, templatesComponentName, templatesComponentVersion.Component.Name, "Templates component name should match")
33+
}

internal/ocm-cli/ocm_test.go

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ func TestExecute(t *testing.T) {
1616

1717
testutil.DownloadOCMAndAddToPath(t)
1818

19-
ctfIn := testutil.BuildComponent("./testdata/component-constructor.yaml", t)
19+
ctfIn := testutil.BuildComponent("./testdata/01/component-constructor.yaml", t)
2020

2121
testCases := []struct {
2222
desc string
@@ -43,15 +43,15 @@ func TestExecute(t *testing.T) {
4343
desc: "get componentversion with ocm config",
4444
commands: []string{"get", "componentversion"},
4545
arguments: []string{"--output", "yaml", ctfIn},
46-
ocmConfig: "./testdata/ocm-config.yaml",
46+
ocmConfig: "./testdata/01/ocm-config.yaml",
4747
expectedError: nil,
4848
},
4949

5050
{
5151
desc: "get componentversion with unsupported ocm config",
5252
commands: []string{"get", "componentversion"},
5353
arguments: []string{"--output", "yaml", ctfIn},
54-
ocmConfig: "./testdata/unsupported-ocm-config.yaml",
54+
ocmConfig: "./testdata/01/unsupported-ocm-config.yaml",
5555
expectedError: expectError,
5656
},
5757
}
@@ -73,7 +73,7 @@ func TestGetComponentVersion(t *testing.T) {
7373
expectError := errors.New("expected error")
7474
testutil.DownloadOCMAndAddToPath(t)
7575

76-
ctfIn := testutil.BuildComponent("./testdata/component-constructor.yaml", t)
76+
ctfIn := testutil.BuildComponent("./testdata/01/component-constructor.yaml", t)
7777

7878
testCases := []struct {
7979
desc string
@@ -119,13 +119,13 @@ func TestGetComponentVersion(t *testing.T) {
119119
{
120120
desc: "get component version with ocm config",
121121
componentRef: ctfIn,
122-
ocmConfig: "./testdata/ocm-config.yaml",
122+
ocmConfig: "./testdata/01/ocm-config.yaml",
123123
expectedError: nil,
124124
},
125125
{
126126
desc: "get component version with unsupported ocm config",
127127
componentRef: ctfIn,
128-
ocmConfig: "./testdata/unsupported-ocm-config.yaml",
128+
ocmConfig: "./testdata/01/unsupported-ocm-config.yaml",
129129
expectedError: expectError,
130130
},
131131
{
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
components:
2+
3+
- name: github.com/openmcp-project/openmcp
4+
version: v0.0.11
5+
provider:
6+
name: openmcp-project
7+
componentReferences:
8+
- componentName: github.com/openmcp-project/gitops-templates
9+
name: gitops-templates
10+
version: v0.0.1
11+
resources:
12+
- name: test-resource
13+
type: blob
14+
input:
15+
type: file
16+
path: ./test-resource.yaml
17+
18+
- name: github.com/openmcp-project/gitops-templates
19+
version: v0.0.1
20+
provider:
21+
name: openmcp-project
22+
resources:
23+
- name: test-resource
24+
type: blob
25+
input:
26+
type: file
27+
path: ./test-resource.yaml
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
config:
2+
vars:
3+
- a: "a"
4+
- b: "b"

0 commit comments

Comments
 (0)