Skip to content

Commit ed2eaaf

Browse files
authored
feat: integrates ECR generation into docker release and adds deployment runtime (#121)
1 parent a0516ff commit ed2eaaf

File tree

21 files changed

+385
-161
lines changed

21 files changed

+385
-161
lines changed

blueprint.cue

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,10 @@ global: {
7171
]
7272
}
7373
deployment: {
74-
registry: ci.providers.aws.ecr.registry + "/catalyst-deployments"
74+
registries: {
75+
containers: "ghcr.io/input-output-hk/catalyst-forge"
76+
modules: ci.providers.aws.ecr.registry + "/catalyst-deployments"
77+
}
7578
repo: {
7679
url: "https://github.com/input-output-hk/catalyst-world"
7780
ref: "master"

cli/pkg/deployment/gitops_test.go

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@ import (
1414
"github.com/input-output-hk/catalyst-forge/lib/project/schema"
1515
"github.com/input-output-hk/catalyst-forge/lib/project/secrets"
1616
"github.com/input-output-hk/catalyst-forge/lib/project/secrets/mocks"
17-
"github.com/input-output-hk/catalyst-forge/lib/tools/pointers"
1817
"github.com/input-output-hk/catalyst-forge/lib/tools/testutils"
1918
"github.com/stretchr/testify/assert"
2019
"github.com/stretchr/testify/require"
@@ -50,7 +49,9 @@ func TestDeploy(t *testing.T) {
5049
defaultParams := projectParams{
5150
projectName: "test",
5251
globalDeploy: schema.GlobalDeployment{
53-
Registry: "registry.myserver.com",
52+
Registries: schema.GlobalDeploymentRegistries{
53+
Modules: "registry.myserver.com",
54+
},
5455
Repo: schema.GlobalDeploymentRepo{
5556
Ref: "main",
5657
Url: "https://github.com/foo/bar",
@@ -191,7 +192,9 @@ func TestLoad(t *testing.T) {
191192
defaultParams := projectParams{
192193
projectName: "test",
193194
globalDeploy: schema.GlobalDeployment{
194-
Registry: "registry.myserver.com",
195+
Registries: schema.GlobalDeploymentRegistries{
196+
Modules: "registry.myserver.com",
197+
},
195198
Repo: schema.GlobalDeploymentRepo{
196199
Ref: "main",
197200
Url: "https://github.com/foo/bar",
@@ -294,7 +297,7 @@ func newTestProject(p projectParams) *project.Project {
294297
Environment: p.enviroment,
295298
Modules: &schema.DeploymentModules{
296299
Main: schema.Module{
297-
Container: pointers.String(p.container),
300+
Name: p.container,
298301
Namespace: p.namespace,
299302
Values: ctx.CompileString(p.values),
300303
Version: p.version,

cli/pkg/deployment/kcl.go

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -60,8 +60,8 @@ type KCLRunner struct {
6060
func (k *KCLRunner) GetMainValues(p *project.Project) (string, error) {
6161
if p.Blueprint.Project.Deployment.Modules == nil {
6262
return "", fmt.Errorf("no deployment modules found in project blueprint")
63-
} else if p.Blueprint.Global.Deployment.Registry == "" {
64-
return "", fmt.Errorf("no deployment registry found in project blueprint")
63+
} else if p.Blueprint.Global.Deployment.Registries.Modules == "" {
64+
return "", fmt.Errorf("no module deployment registry found in project blueprint")
6565
}
6666

6767
ctx := cuecontext.New()
@@ -86,8 +86,8 @@ func (k *KCLRunner) RunDeployment(p *project.Project) (map[string]KCLRunResult,
8686
ctx := cuecontext.New()
8787
if p.Blueprint.Project.Deployment.Modules == nil {
8888
return nil, fmt.Errorf("no deployment modules found in project blueprint")
89-
} else if p.Blueprint.Global.Deployment.Registry == "" {
90-
return nil, fmt.Errorf("no deployment registry found in project blueprint")
89+
} else if p.Blueprint.Global.Deployment.Registries.Modules == "" {
90+
return nil, fmt.Errorf("no module deployment registry found in project blueprint")
9191
}
9292

9393
modules := map[string]schema.Module{"main": p.Blueprint.Project.Deployment.Modules.Main}
@@ -109,10 +109,10 @@ func (k *KCLRunner) RunDeployment(p *project.Project) (map[string]KCLRunResult,
109109
Version: module.Version,
110110
}
111111

112-
container := fmt.Sprintf("%s/%s", strings.TrimSuffix(p.Blueprint.Global.Deployment.Registry, "/"), module.Module)
112+
container := fmt.Sprintf("%s/%s", strings.TrimSuffix(p.Blueprint.Global.Deployment.Registries.Modules, "/"), module.Name)
113113
out, err := k.run(container, args)
114114
if err != nil {
115-
k.logger.Error("Failed to run KCL module", "module", module.Module, "error", err, "output", string(out))
115+
k.logger.Error("Failed to run KCL module", "module", module.Name, "error", err, "output", string(out))
116116
return nil, fmt.Errorf("failed to run KCL module: %w", err)
117117
}
118118

cli/pkg/deployment/kcl_test.go

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,9 @@ func TestKCLRunnerGetMainValues(t *testing.T) {
2525
},
2626
Global: schema.Global{
2727
Deployment: schema.GlobalDeployment{
28-
Registry: "test",
28+
Registries: schema.GlobalDeploymentRegistries{
29+
Modules: "test.com",
30+
},
2931
},
3032
},
3133
},
@@ -43,7 +45,7 @@ func TestKCLRunnerGetMainValues(t *testing.T) {
4345
"test",
4446
&schema.DeploymentModules{
4547
Main: schema.Module{
46-
Module: "module",
48+
Name: "module",
4749
Namespace: "default",
4850
Values: map[string]string{
4951
"key": "value",
@@ -91,7 +93,9 @@ func TestKCLRunnerRunDeployment(t *testing.T) {
9193
},
9294
Global: schema.Global{
9395
Deployment: schema.GlobalDeployment{
94-
Registry: registry,
96+
Registries: schema.GlobalDeploymentRegistries{
97+
Modules: registry,
98+
},
9599
},
96100
},
97101
},
@@ -113,7 +117,7 @@ func TestKCLRunnerRunDeployment(t *testing.T) {
113117
"test.com",
114118
&schema.DeploymentModules{
115119
Main: schema.Module{
116-
Module: "module",
120+
Name: "module",
117121
Namespace: "default",
118122
Values: map[string]string{
119123
"key": "value",
@@ -122,7 +126,7 @@ func TestKCLRunnerRunDeployment(t *testing.T) {
122126
},
123127
Support: map[string]schema.Module{
124128
"support": {
125-
Module: "module1",
129+
Name: "module1",
126130
Namespace: "default",
127131
Values: map[string]string{
128132
"key1": "value1",
@@ -152,7 +156,7 @@ func TestKCLRunnerRunDeployment(t *testing.T) {
152156
"test.com",
153157
&schema.DeploymentModules{
154158
Main: schema.Module{
155-
Module: "module",
159+
Name: "module",
156160
Namespace: "default",
157161
Values: map[string]string{
158162
"key": "value",

cli/pkg/release/providers/common.go

Lines changed: 0 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -34,40 +34,11 @@ func createECRRepoIfNotExists(client aws.ECRClient, p *project.Project, registry
3434
return nil
3535
}
3636

37-
// generateContainerName generates the container name for the project.
38-
// If the name is not provided, the project name is used.
39-
func generateContainerName(p *project.Project, name string, registry string) string {
40-
var n string
41-
if name == "" {
42-
n = p.Name
43-
} else {
44-
n = name
45-
}
46-
47-
if isGHCRRegistry(registry) {
48-
return fmt.Sprintf("%s/%s", strings.TrimSuffix(registry, "/"), n)
49-
} else {
50-
var repo string
51-
if strings.Contains(p.Blueprint.Global.Repo.Name, "/") {
52-
repo = strings.Split(p.Blueprint.Global.Repo.Name, "/")[1]
53-
} else {
54-
repo = p.Blueprint.Global.Repo.Name
55-
}
56-
57-
return fmt.Sprintf("%s/%s/%s", strings.TrimSuffix(registry, "/"), repo, n)
58-
}
59-
}
60-
6137
// isECRRegistry checks if the registry is an ECR registry.
6238
func isECRRegistry(registry string) bool {
6339
return regexp.MustCompile(`^\d{12}\.dkr\.ecr\.[a-z0-9-]+\.amazonaws\.com`).MatchString(registry)
6440
}
6541

66-
// isGHCRRegistry checks if the registry is a GHCR registry.
67-
func isGHCRRegistry(registry string) bool {
68-
return regexp.MustCompile(`^ghcr\.io/[a-zA-Z0-9](?:-?[a-zA-Z0-9])*$`).MatchString(registry)
69-
}
70-
7142
// parseConfig parses the configuration for the release.
7243
func parseConfig(p *project.Project, release string, config any) error {
7344
err := p.Raw().DecodePath(fmt.Sprintf("project.release.%s.config", release), &config)

cli/pkg/release/providers/docker.go

Lines changed: 26 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import (
88
"github.com/input-output-hk/catalyst-forge/cli/pkg/earthly"
99
"github.com/input-output-hk/catalyst-forge/cli/pkg/events"
1010
"github.com/input-output-hk/catalyst-forge/cli/pkg/executor"
11+
"github.com/input-output-hk/catalyst-forge/cli/pkg/providers/aws"
1112
"github.com/input-output-hk/catalyst-forge/cli/pkg/run"
1213
"github.com/input-output-hk/catalyst-forge/lib/project/project"
1314
"github.com/input-output-hk/catalyst-forge/lib/project/schema"
@@ -26,6 +27,7 @@ type DockerReleaserConfig struct {
2627
type DockerReleaser struct {
2728
config DockerReleaserConfig
2829
docker executor.WrappedExecuter
30+
ecr aws.ECRClient
2931
force bool
3032
handler events.EventHandler
3133
logger *slog.Logger
@@ -56,9 +58,7 @@ func (r *DockerReleaser) Release() error {
5658
return fmt.Errorf("no registries found")
5759
}
5860

59-
container := r.project.Blueprint.Project.Container
6061
registries := r.project.Blueprint.Global.CI.Registries
61-
6262
imageTag := r.config.Tag
6363
if imageTag == "" {
6464
return fmt.Errorf("no image tag specified")
@@ -69,10 +69,18 @@ func (r *DockerReleaser) Release() error {
6969
for _, registry := range registries {
7070
var pushed []string
7171

72+
container := project.GenerateContainerName(&r.project, r.project.Blueprint.Project.Container, registry)
73+
if isECRRegistry(registry) {
74+
r.logger.Info("Detected ECR registry, checking if repository exists", "repository", container)
75+
if err := createECRRepoIfNotExists(r.ecr, &r.project, container, r.logger); err != nil {
76+
return fmt.Errorf("failed to create ECR repository: %w", err)
77+
}
78+
}
79+
7280
for _, platform := range platforms {
7381
platformSuffix := strings.Replace(platform, "/", "_", -1)
7482
curImage := fmt.Sprintf("%s:%s_%s", CONTAINER_NAME, TAG_NAME, platformSuffix)
75-
newImage := fmt.Sprintf("%s/%s:%s_%s", registry, container, imageTag, platformSuffix)
83+
newImage := fmt.Sprintf("%s:%s_%s", container, imageTag, platformSuffix)
7684

7785
r.logger.Debug("Tagging image", "tag", newImage)
7886
if err := r.tagImage(curImage, newImage); err != nil {
@@ -95,8 +103,16 @@ func (r *DockerReleaser) Release() error {
95103
}
96104
} else {
97105
for _, registry := range registries {
106+
container := project.GenerateContainerName(&r.project, r.project.Blueprint.Project.Container, registry)
107+
if isECRRegistry(registry) {
108+
r.logger.Info("Detected ECR registry, checking if repository exists", "repository", container)
109+
if err := createECRRepoIfNotExists(r.ecr, &r.project, container, r.logger); err != nil {
110+
return fmt.Errorf("failed to create ECR repository: %w", err)
111+
}
112+
}
113+
98114
curImage := fmt.Sprintf("%s:%s", CONTAINER_NAME, TAG_NAME)
99-
newImage := fmt.Sprintf("%s/%s:%s", registry, container, imageTag)
115+
newImage := fmt.Sprintf("%s:%s", container, imageTag)
100116

101117
r.logger.Info("Tagging image", "old", curImage, "new", newImage)
102118
if err := r.tagImage(curImage, newImage); err != nil {
@@ -215,12 +231,18 @@ func NewDockerReleaser(
215231
return nil, fmt.Errorf("failed to parse release config: %w", err)
216232
}
217233

234+
ecr, err := aws.NewECRClient(ctx.Logger)
235+
if err != nil {
236+
return nil, fmt.Errorf("failed to create ECR client: %w", err)
237+
}
238+
218239
docker := executor.NewLocalWrappedExecutor(exec, "docker")
219240
handler := events.NewDefaultEventHandler(ctx.Logger)
220241
runner := run.NewDefaultProjectRunner(ctx, &project)
221242
return &DockerReleaser{
222243
config: config,
223244
docker: docker,
245+
ecr: ecr,
224246
force: force,
225247
handler: &handler,
226248
logger: ctx.Logger,

0 commit comments

Comments
 (0)