Skip to content

Commit 27253c7

Browse files
authored
feat: adds git deployment generator (#161)
1 parent 143fdec commit 27253c7

File tree

14 files changed

+362
-21
lines changed

14 files changed

+362
-21
lines changed

cli/cmd/cmds/module/template.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,8 @@ func (c *TemplateCmd) Run(ctx run.RunContext) error {
6565
mod.Path = path
6666
}
6767

68-
out, err := gen.Generate(mod, bundle.Bundle.Env)
68+
raw := bundle.Raw.LookupPath(cue.ParsePath(fmt.Sprintf("modules.%s", c.Module)))
69+
out, err := gen.Generate(mod, raw, bundle.Bundle.Env)
6970
if err != nil {
7071
return fmt.Errorf("failed to generate manifest: %w", err)
7172
}

lib/project/deployment/generator/generator.go

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,8 @@ func (d *Generator) GenerateBundle(b deployment.ModuleBundle, env cue.Value) (Ge
4242
results := make(map[string][]byte)
4343
for name, module := range nb.Bundle.Modules {
4444
d.logger.Debug("Generating module", "name", name)
45-
result, err := d.Generate(module, b.Bundle.Env)
45+
raw := nb.Raw.LookupPath(cue.ParsePath(fmt.Sprintf("modules.%s", name)))
46+
result, err := d.Generate(module, raw, b.Bundle.Env)
4647
if err != nil {
4748
return GeneratorResult{}, fmt.Errorf("failed to generate module %s: %w", name, err)
4849
}
@@ -57,7 +58,7 @@ func (d *Generator) GenerateBundle(b deployment.ModuleBundle, env cue.Value) (Ge
5758
}
5859

5960
// Generate generates manifests for a deployment module.
60-
func (d *Generator) Generate(m sp.Module, env string) ([]byte, error) {
61+
func (d *Generator) Generate(m sp.Module, raw cue.Value, env string) ([]byte, error) {
6162
if err := deployment.Validate(m); err != nil {
6263
return nil, fmt.Errorf("failed to validate module: %w", err)
6364
}
@@ -67,7 +68,7 @@ func (d *Generator) Generate(m sp.Module, env string) ([]byte, error) {
6768
return nil, fmt.Errorf("failed to get generator for module: %w", err)
6869
}
6970

70-
manifests, err := mg.Generate(m, env)
71+
manifests, err := mg.Generate(m, raw, env)
7172
if err != nil {
7273
return nil, fmt.Errorf("failed to generate manifest for module: %w", err)
7374
}

lib/project/deployment/generator/generator_test.go

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,7 @@ func TestGeneratorGenerateBundle(t *testing.T) {
9898
for _, tt := range tests {
9999
t.Run(tt.name, func(t *testing.T) {
100100
mg := &mocks.ManifestGeneratorMock{
101-
GenerateFunc: func(mod sp.Module, env string) ([]byte, error) {
101+
GenerateFunc: func(mod sp.Module, raw cue.Value, env string) ([]byte, error) {
102102
if tt.err {
103103
return nil, fmt.Errorf("error")
104104
}
@@ -120,7 +120,7 @@ func TestGeneratorGenerateBundle(t *testing.T) {
120120
store: store,
121121
}
122122

123-
tt.bundle.Raw = getRaw(tt.bundle.Bundle)
123+
tt.bundle.Raw = getRawBundle(tt.bundle.Bundle)
124124
result, err := gen.GenerateBundle(tt.bundle, tt.env)
125125
tt.validate(t, result, err)
126126
})
@@ -177,7 +177,7 @@ func TestGeneratorGenerate(t *testing.T) {
177177
for _, tt := range tests {
178178
t.Run(tt.name, func(t *testing.T) {
179179
mg := &mocks.ManifestGeneratorMock{
180-
GenerateFunc: func(mod sp.Module, env string) ([]byte, error) {
180+
GenerateFunc: func(mod sp.Module, raw cue.Value, env string) ([]byte, error) {
181181
if tt.err {
182182
return nil, fmt.Errorf("error")
183183
}
@@ -199,15 +199,22 @@ func TestGeneratorGenerate(t *testing.T) {
199199
store: store,
200200
}
201201

202-
result, err := gen.Generate(tt.module, tt.env)
202+
result, err := gen.Generate(tt.module, getRawModule(tt.module), tt.env)
203203
tt.validate(t, result, err)
204204
})
205205
}
206206
}
207207

208-
func getRaw(mod sp.ModuleBundle) cue.Value {
208+
func getRawBundle(b sp.ModuleBundle) cue.Value {
209209
ctx := cuecontext.New()
210-
v := ctx.Encode(mod)
210+
v := ctx.Encode(b)
211+
212+
return v
213+
}
214+
215+
func getRawModule(m sp.Module) cue.Value {
216+
ctx := cuecontext.New()
217+
v := ctx.Encode(m)
211218

212219
return v
213220
}
Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package deployment
22

33
import (
4+
"cuelang.org/go/cue"
45
sp "github.com/input-output-hk/catalyst-forge/lib/schema/blueprint/project"
56
)
67

@@ -9,5 +10,5 @@ import (
910
// ManifestGenerator generates deployment manifests.
1011
type ManifestGenerator interface {
1112
// Generate generates a deployment manifest for the given module.
12-
Generate(mod sp.Module, env string) ([]byte, error)
13+
Generate(mod sp.Module, raw cue.Value, env string) ([]byte, error)
1314
}

lib/project/deployment/mocks/manifest.go

Lines changed: 11 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
package git
2+
3+
import (
4+
"fmt"
5+
"log/slog"
6+
"strings"
7+
8+
"cuelang.org/go/cue"
9+
sp "github.com/input-output-hk/catalyst-forge/lib/schema/blueprint/project"
10+
"github.com/input-output-hk/catalyst-forge/lib/tools/fs"
11+
"github.com/input-output-hk/catalyst-forge/lib/tools/fs/billy"
12+
"github.com/input-output-hk/catalyst-forge/lib/tools/git/repo"
13+
"github.com/input-output-hk/catalyst-forge/lib/tools/git/repo/remote"
14+
)
15+
16+
// Options is the configuration for the GitManifestGenerator.
17+
type Options struct {
18+
Paths []string `json:"paths"`
19+
}
20+
21+
// GitManifestGenerator is a ManifestGenerator that uses Git.
22+
// It clones the git repository and checks out the specified ref.
23+
// It then reads the file at the specified path and returns its contents.
24+
type GitManifestGenerator struct {
25+
fs fs.Filesystem
26+
logger *slog.Logger
27+
remote remote.GitRemoteInteractor
28+
}
29+
30+
func (g *GitManifestGenerator) Generate(mod sp.Module, raw cue.Value, env string) ([]byte, error) {
31+
var opts Options
32+
v := raw.LookupPath(cue.ParsePath("values"))
33+
if err := v.Decode(&opts); err != nil {
34+
return nil, fmt.Errorf("failed to decode options: %w", err)
35+
} else if len(opts.Paths) == 0 {
36+
return nil, fmt.Errorf("no paths specified")
37+
}
38+
39+
r, err := repo.NewGitRepo("/repo", g.logger, repo.WithFS(g.fs), repo.WithGitRemoteInteractor(g.remote))
40+
if err != nil {
41+
return nil, fmt.Errorf("failed to create git repo: %w", err)
42+
}
43+
44+
g.logger.Debug("Cloning git repo", "url", mod.Registry)
45+
if err := r.Clone(mod.Registry); err != nil {
46+
return nil, fmt.Errorf("failed to clone git repo %s: %w", mod.Registry, err)
47+
}
48+
49+
g.logger.Debug("Checking out git ref", "ref", mod.Version)
50+
if err := r.CheckoutRef(mod.Version); err != nil {
51+
return nil, fmt.Errorf("failed to checkout ref %s: %w", mod.Version, err)
52+
}
53+
54+
var final string
55+
for _, path := range opts.Paths {
56+
g.logger.Debug("Reading file from git repo", "path", path)
57+
exists, err := r.Exists(path)
58+
if err != nil {
59+
return nil, fmt.Errorf("failed to check if path %s exists: %w", path, err)
60+
} else if !exists {
61+
return nil, fmt.Errorf("path %s does not exist in git repo", path)
62+
}
63+
64+
contents, err := r.ReadFile(path)
65+
if err != nil {
66+
return nil, fmt.Errorf("failed to read file %s: %w", path, err)
67+
}
68+
69+
if final == "" {
70+
final = strings.TrimPrefix(string(contents), "---\n")
71+
} else {
72+
final += "\n---\n" + strings.TrimPrefix(string(contents), "---\n")
73+
}
74+
}
75+
76+
return []byte(final), nil
77+
}
78+
79+
// NewGitManifestGenerator creates a new GitManifestGenerator instance.
80+
func NewGitManifestGenerator(logger *slog.Logger) *GitManifestGenerator {
81+
return &GitManifestGenerator{
82+
fs: billy.NewInMemoryFs(),
83+
logger: logger,
84+
remote: remote.GoGitRemoteInteractor{},
85+
}
86+
}

0 commit comments

Comments
 (0)