From cdcd13d18e26446ca2a36c25b7c8e718a63b6430 Mon Sep 17 00:00:00 2001 From: Tim Holm Date: Mon, 7 Jul 2025 12:16:12 +1000 Subject: [PATCH 1/7] connect platform repository api. --- cli/cmd/build.go | 66 ++++++++++++++++++++++++++++ cli/internal/api/platform.go | 33 ++++++++++++++ cli/internal/platforms/repository.go | 50 +++++++++++++++++++++ cli/internal/plugins/repository.go | 4 +- engines/terraform/repository.go | 2 +- 5 files changed, 152 insertions(+), 3 deletions(-) create mode 100644 cli/cmd/build.go create mode 100644 cli/internal/api/platform.go create mode 100644 cli/internal/platforms/repository.go diff --git a/cli/cmd/build.go b/cli/cmd/build.go new file mode 100644 index 000000000..c94e41580 --- /dev/null +++ b/cli/cmd/build.go @@ -0,0 +1,66 @@ +package cmd + +import ( + "fmt" + + "github.com/nitrictech/nitric/cli/internal/api" + "github.com/nitrictech/nitric/cli/internal/auth" + "github.com/nitrictech/nitric/cli/internal/config" + "github.com/nitrictech/nitric/cli/internal/platforms" + "github.com/nitrictech/nitric/cli/internal/plugins" + "github.com/nitrictech/nitric/cli/pkg/schema" + "github.com/nitrictech/nitric/engines/terraform" + "github.com/spf13/afero" + "github.com/spf13/cobra" +) + +type MockTerraformPluginRepository struct { + plugins map[string]*terraform.PluginManifest +} + +func (r *MockTerraformPluginRepository) GetPlugin(name string) (*terraform.PluginManifest, error) { + return r.plugins[name], nil +} + +var buildCmd = &cobra.Command{ + Use: "build", + Short: "Builds the nitric application", + Long: `Builds an application using the nitric.yaml application spec and referenced platform.`, + Run: func(cmd *cobra.Command, args []string) { + + // Read the nitric.yaml file + fs := afero.NewOsFs() + + appSpec, err := schema.LoadFromFile(fs, "nitric.yaml", true) + cobra.CheckErr(err) + + client := api.NewNitricApiClient(config.GetNitricServerUrl(), auth.WithAuthHeader) + + platformRepository := platforms.NewPlatformRepository(client) + + // TODO:prompt for platform selection if multiple targets are specified + targetPlatform := appSpec.Targets[0] + + platform, err := terraform.PlatformFromId(fs, targetPlatform, platformRepository) + cobra.CheckErr(err) + + engine := terraform.New(platform, terraform.WithRepository(plugins.NewPluginRepository(client))) + // Parse the application spec + // Validate the application spec + // Build the application using the specified platform + // Handle any errors that occur during the build process + + err = engine.Apply(appSpec) + if err != nil { + fmt.Print("Error applying platform: ", err) + return + } + + fmt.Println("Build completed successfully.") + + }, +} + +func init() { + rootCmd.AddCommand(buildCmd) +} diff --git a/cli/internal/api/platform.go b/cli/internal/api/platform.go new file mode 100644 index 000000000..a7e94a1fc --- /dev/null +++ b/cli/internal/api/platform.go @@ -0,0 +1,33 @@ +package api + +import ( + "encoding/json" + "fmt" + "io" + + "github.com/nitrictech/nitric/engines/terraform" +) + +// FIXME: Because of the difference in fields between identity and resource plugins we need to return an interface +func (c *NitricApiClient) GetPlatform(team, name string, revision int) (*terraform.PlatformSpec, error) { + response, err := c.get(fmt.Sprintf("/api/platforms/%s/%s/revisions/%d", team, name, revision)) + if err != nil { + return nil, fmt.Errorf("failed to connect to nitric auth details endpoint: %v", err) + } + + if response.StatusCode != 200 { + return nil, fmt.Errorf("received non 200 response from nitric plugin details endpoint: %d", response.StatusCode) + } + + body, err := io.ReadAll(response.Body) + if err != nil { + return nil, fmt.Errorf("failed to read response from nitric auth details endpoint: %v", err) + } + + var platformSpec terraform.PlatformSpec + err = json.Unmarshal(body, &platformSpec) + if err != nil { + return nil, fmt.Errorf("unexpected response from nitric plugin details endpoint: %v", err) + } + return &platformSpec, nil +} diff --git a/cli/internal/platforms/repository.go b/cli/internal/platforms/repository.go new file mode 100644 index 000000000..59d23e26f --- /dev/null +++ b/cli/internal/platforms/repository.go @@ -0,0 +1,50 @@ +package platforms + +import ( + "fmt" + "regexp" + "strconv" + + "github.com/nitrictech/nitric/cli/internal/api" + "github.com/nitrictech/nitric/engines/terraform" +) + +type PlatformRepository struct { + apiClient *api.NitricApiClient +} + +var _ terraform.PlatformRepository = (*PlatformRepository)(nil) + +func (r *PlatformRepository) GetPlatform(name string) (*terraform.PlatformSpec, error) { + // Split the name into team, lib, and revision using a regex /@ + re := regexp.MustCompile(`^(?P[^/]+)/(?P[^@]+)@(?P\d+)$`) + matches := re.FindStringSubmatch(name) + + if matches == nil { + return nil, fmt.Errorf("invalid platform name format: %s. Expected format: /@ e.g. nitric/aws@1", name) + } + + // Extract named groups + team := matches[re.SubexpIndex("team")] + platform := matches[re.SubexpIndex("platform")] + revisionStr := matches[re.SubexpIndex("revision")] + + // Convert revision string to integer + revision, err := strconv.Atoi(revisionStr) + if err != nil { + return nil, fmt.Errorf("invalid revision format: %s. Expected integer", revisionStr) + } + + platformSpec, err := r.apiClient.GetPlatform(team, platform, revision) + if err != nil { + return nil, err + } + + return platformSpec, nil +} + +func NewPlatformRepository(apiClient *api.NitricApiClient) *PlatformRepository { + return &PlatformRepository{ + apiClient: apiClient, + } +} diff --git a/cli/internal/plugins/repository.go b/cli/internal/plugins/repository.go index 24fd3ff6a..421163be5 100644 --- a/cli/internal/plugins/repository.go +++ b/cli/internal/plugins/repository.go @@ -39,8 +39,8 @@ func (r *PluginRepository) GetIdentityPlugin(team, libname, version, name string return identityPluginManifest, nil } -func NewPluginRepository(client *api.NitricApiClient) *PluginRepository { +func NewPluginRepository(apiClient *api.NitricApiClient) *PluginRepository { return &PluginRepository{ - apiClient: client, + apiClient: apiClient, } } diff --git a/engines/terraform/repository.go b/engines/terraform/repository.go index 4848acd95..6a6e3c320 100644 --- a/engines/terraform/repository.go +++ b/engines/terraform/repository.go @@ -3,7 +3,7 @@ package terraform import "fmt" type PlatformRepository interface { - // terraform/nitric-aws + // // GetPlatform(string) (*PlatformSpec, error) } From 0ba2a7357b4771c64fdc992f0793d4b4eb77a128 Mon Sep 17 00:00:00 2001 From: Tim Holm Date: Mon, 7 Jul 2025 13:11:08 +1000 Subject: [PATCH 2/7] reduce platform revision creation down to single query. --- cli/internal/api/platform.go | 10 ++++++++-- cli/internal/platforms/repository.go | 2 ++ 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/cli/internal/api/platform.go b/cli/internal/api/platform.go index a7e94a1fc..6f5f96c2b 100644 --- a/cli/internal/api/platform.go +++ b/cli/internal/api/platform.go @@ -8,6 +8,10 @@ import ( "github.com/nitrictech/nitric/engines/terraform" ) +type PlatformRevisionResponse struct { + Content terraform.PlatformSpec `json:"content"` +} + // FIXME: Because of the difference in fields between identity and resource plugins we need to return an interface func (c *NitricApiClient) GetPlatform(team, name string, revision int) (*terraform.PlatformSpec, error) { response, err := c.get(fmt.Sprintf("/api/platforms/%s/%s/revisions/%d", team, name, revision)) @@ -24,10 +28,12 @@ func (c *NitricApiClient) GetPlatform(team, name string, revision int) (*terrafo return nil, fmt.Errorf("failed to read response from nitric auth details endpoint: %v", err) } - var platformSpec terraform.PlatformSpec + fmt.Println("body", string(body)) + + var platformSpec PlatformRevisionResponse err = json.Unmarshal(body, &platformSpec) if err != nil { return nil, fmt.Errorf("unexpected response from nitric plugin details endpoint: %v", err) } - return &platformSpec, nil + return &platformSpec.Content, nil } diff --git a/cli/internal/platforms/repository.go b/cli/internal/platforms/repository.go index 59d23e26f..ff68b7d66 100644 --- a/cli/internal/platforms/repository.go +++ b/cli/internal/platforms/repository.go @@ -40,6 +40,8 @@ func (r *PlatformRepository) GetPlatform(name string) (*terraform.PlatformSpec, return nil, err } + fmt.Println("platformSpec", platformSpec) + return platformSpec, nil } From 1bafe32fbdb8a4cc839ec62a0054e655c2aaf83d Mon Sep 17 00:00:00 2001 From: Tim Holm Date: Mon, 7 Jul 2025 13:27:04 +1000 Subject: [PATCH 3/7] clear debug logs --- cli/internal/platforms/repository.go | 2 -- 1 file changed, 2 deletions(-) diff --git a/cli/internal/platforms/repository.go b/cli/internal/platforms/repository.go index ff68b7d66..59d23e26f 100644 --- a/cli/internal/platforms/repository.go +++ b/cli/internal/platforms/repository.go @@ -40,8 +40,6 @@ func (r *PlatformRepository) GetPlatform(name string) (*terraform.PlatformSpec, return nil, err } - fmt.Println("platformSpec", platformSpec) - return platformSpec, nil } From 1df53cbb5793c729174026f8f1a3bec9d852298c Mon Sep 17 00:00:00 2001 From: Tim Holm Date: Mon, 7 Jul 2025 13:31:31 +1000 Subject: [PATCH 4/7] remove plugin debug line. --- cli/internal/api/plugin.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/cli/internal/api/plugin.go b/cli/internal/api/plugin.go index 09b48de3b..048b83c48 100644 --- a/cli/internal/api/plugin.go +++ b/cli/internal/api/plugin.go @@ -10,8 +10,7 @@ import ( // FIXME: Because of the difference in fields between identity and resource plugins we need to return an interface func (c *NitricApiClient) GetPluginManifest(team, lib, version, name string) (interface{}, error) { - fmt.Println("Getting plugin manifest for", team, lib, version, name) - response, err := c.get(fmt.Sprintf("/api/plugin_libraries/%s/%s/versions/%s/plugins/%s", team, lib, version, name), true) + response, err := c.get(fmt.Sprintf("/api/plugin_libraries/%s/%s/versions/%s/plugins/%s", team, lib, version, name)) if err != nil { return nil, fmt.Errorf("failed to connect to nitric auth details endpoint: %v", err) } From 4d57f98fe003fd87b24b1520594642aaf4d50ff5 Mon Sep 17 00:00:00 2001 From: Tim Holm Date: Mon, 7 Jul 2025 14:08:32 +1000 Subject: [PATCH 5/7] remove debug statement. --- cli/internal/api/platform.go | 2 -- 1 file changed, 2 deletions(-) diff --git a/cli/internal/api/platform.go b/cli/internal/api/platform.go index 6f5f96c2b..5cb0ce587 100644 --- a/cli/internal/api/platform.go +++ b/cli/internal/api/platform.go @@ -28,8 +28,6 @@ func (c *NitricApiClient) GetPlatform(team, name string, revision int) (*terrafo return nil, fmt.Errorf("failed to read response from nitric auth details endpoint: %v", err) } - fmt.Println("body", string(body)) - var platformSpec PlatformRevisionResponse err = json.Unmarshal(body, &platformSpec) if err != nil { From 365d708a429e3c88f931fe36967d5e4872e2c938 Mon Sep 17 00:00:00 2001 From: Jye Cusch Date: Thu, 10 Jul 2025 18:35:37 +1000 Subject: [PATCH 6/7] rebase build changes --- cli/cmd/build.go | 66 ------------------------------------------- cli/pkg/app/nitric.go | 5 ++-- 2 files changed, 3 insertions(+), 68 deletions(-) delete mode 100644 cli/cmd/build.go diff --git a/cli/cmd/build.go b/cli/cmd/build.go deleted file mode 100644 index c94e41580..000000000 --- a/cli/cmd/build.go +++ /dev/null @@ -1,66 +0,0 @@ -package cmd - -import ( - "fmt" - - "github.com/nitrictech/nitric/cli/internal/api" - "github.com/nitrictech/nitric/cli/internal/auth" - "github.com/nitrictech/nitric/cli/internal/config" - "github.com/nitrictech/nitric/cli/internal/platforms" - "github.com/nitrictech/nitric/cli/internal/plugins" - "github.com/nitrictech/nitric/cli/pkg/schema" - "github.com/nitrictech/nitric/engines/terraform" - "github.com/spf13/afero" - "github.com/spf13/cobra" -) - -type MockTerraformPluginRepository struct { - plugins map[string]*terraform.PluginManifest -} - -func (r *MockTerraformPluginRepository) GetPlugin(name string) (*terraform.PluginManifest, error) { - return r.plugins[name], nil -} - -var buildCmd = &cobra.Command{ - Use: "build", - Short: "Builds the nitric application", - Long: `Builds an application using the nitric.yaml application spec and referenced platform.`, - Run: func(cmd *cobra.Command, args []string) { - - // Read the nitric.yaml file - fs := afero.NewOsFs() - - appSpec, err := schema.LoadFromFile(fs, "nitric.yaml", true) - cobra.CheckErr(err) - - client := api.NewNitricApiClient(config.GetNitricServerUrl(), auth.WithAuthHeader) - - platformRepository := platforms.NewPlatformRepository(client) - - // TODO:prompt for platform selection if multiple targets are specified - targetPlatform := appSpec.Targets[0] - - platform, err := terraform.PlatformFromId(fs, targetPlatform, platformRepository) - cobra.CheckErr(err) - - engine := terraform.New(platform, terraform.WithRepository(plugins.NewPluginRepository(client))) - // Parse the application spec - // Validate the application spec - // Build the application using the specified platform - // Handle any errors that occur during the build process - - err = engine.Apply(appSpec) - if err != nil { - fmt.Print("Error applying platform: ", err) - return - } - - fmt.Println("Build completed successfully.") - - }, -} - -func init() { - rootCmd.AddCommand(buildCmd) -} diff --git a/cli/pkg/app/nitric.go b/cli/pkg/app/nitric.go index eaeeb67e1..a5bb9918a 100644 --- a/cli/pkg/app/nitric.go +++ b/cli/pkg/app/nitric.go @@ -18,6 +18,7 @@ import ( "github.com/nitrictech/nitric/cli/internal/browser" "github.com/nitrictech/nitric/cli/internal/config" "github.com/nitrictech/nitric/cli/internal/devserver" + "github.com/nitrictech/nitric/cli/internal/platforms" "github.com/nitrictech/nitric/cli/internal/plugins" "github.com/nitrictech/nitric/cli/internal/simulation" "github.com/nitrictech/nitric/cli/internal/style/colors" @@ -226,12 +227,12 @@ func (c *NitricApp) Build() error { return err } - mockPlatformRepository := terraform.NewMockPlatformRepository() + platformRepository := platforms.NewPlatformRepository(c.apiClient) // TODO:prompt for platform selection if multiple targets are specified targetPlatform := appSpec.Targets[0] - platform, err := terraform.PlatformFromId(fs, targetPlatform, mockPlatformRepository) + platform, err := terraform.PlatformFromId(fs, targetPlatform, platformRepository) if err != nil { return err } From 482120ba0195141ebdaad0a97581d6eecaf6de2e Mon Sep 17 00:00:00 2001 From: Jye Cusch Date: Thu, 10 Jul 2025 18:38:40 +1000 Subject: [PATCH 7/7] add auth to platform and plugin requests --- cli/internal/api/platform.go | 2 +- cli/internal/api/plugin.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/cli/internal/api/platform.go b/cli/internal/api/platform.go index 5cb0ce587..3b8fda51c 100644 --- a/cli/internal/api/platform.go +++ b/cli/internal/api/platform.go @@ -14,7 +14,7 @@ type PlatformRevisionResponse struct { // FIXME: Because of the difference in fields between identity and resource plugins we need to return an interface func (c *NitricApiClient) GetPlatform(team, name string, revision int) (*terraform.PlatformSpec, error) { - response, err := c.get(fmt.Sprintf("/api/platforms/%s/%s/revisions/%d", team, name, revision)) + response, err := c.get(fmt.Sprintf("/api/platforms/%s/%s/revisions/%d", team, name, revision), true) if err != nil { return nil, fmt.Errorf("failed to connect to nitric auth details endpoint: %v", err) } diff --git a/cli/internal/api/plugin.go b/cli/internal/api/plugin.go index 048b83c48..09ea38596 100644 --- a/cli/internal/api/plugin.go +++ b/cli/internal/api/plugin.go @@ -10,7 +10,7 @@ import ( // FIXME: Because of the difference in fields between identity and resource plugins we need to return an interface func (c *NitricApiClient) GetPluginManifest(team, lib, version, name string) (interface{}, error) { - response, err := c.get(fmt.Sprintf("/api/plugin_libraries/%s/%s/versions/%s/plugins/%s", team, lib, version, name)) + response, err := c.get(fmt.Sprintf("/api/plugin_libraries/%s/%s/versions/%s/plugins/%s", team, lib, version, name), true) if err != nil { return nil, fmt.Errorf("failed to connect to nitric auth details endpoint: %v", err) }