Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
534 changes: 534 additions & 0 deletions cmd/rde.go

Large diffs are not rendered by default.

29 changes: 29 additions & 0 deletions cmd/rde_blueprint.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package cmd

import (
"github.com/qovery/qovery-cli/utils"
"github.com/spf13/cobra"
"os"
)

var rdeBlueprintCmd = &cobra.Command{
Use: "blueprint",
Short: "Manage RDE blueprints",
Long: `Manage RDE blueprint projects and environments.

A blueprint is a project with a template environment that serves as the source
for cloning new Remote Development Environments. Blueprints are identified by
a project-level environment variable BLUEPRINT_PROJECT_ID.`,
Run: func(cmd *cobra.Command, args []string) {
utils.Capture(cmd)

if len(args) == 0 {
_ = cmd.Help()
os.Exit(0)
}
},
}

func init() {
rdeCmd.AddCommand(rdeBlueprintCmd)
}
61 changes: 61 additions & 0 deletions cmd/rde_blueprint_deploy.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
package cmd

import (
"context"
"fmt"
"os"
"time"

"github.com/pterm/pterm"
"github.com/qovery/qovery-cli/utils"
"github.com/qovery/qovery-client-go"
"github.com/spf13/cobra"
)

var rdeBlueprintDeployCmd = &cobra.Command{
Use: "deploy",
Short: "Deploy a blueprint environment",
Run: func(cmd *cobra.Command, args []string) {
utils.Capture(cmd)

client := utils.GetQoveryClientPanicInCaseOfError()
orgId, err := rdeGetOrgId(client)
checkError(err)

bp, err := rdeFindBlueprintByProjectName(client, orgId, rdeBlueprintProjectName)
if err != nil {
utils.PrintlnError(err)
os.Exit(1)
panic("unreachable") // staticcheck false positive: https://staticcheck.io/docs/checks#SA5011
}

if bp.EnvId == "" {
utils.PrintlnError(fmt.Errorf("blueprint %s has no environment with %s set", bp.ProjectName, rdeBlueprintKeyVar))
os.Exit(1)
panic("unreachable") // staticcheck false positive: https://staticcheck.io/docs/checks#SA5011
}

_, _, err = client.EnvironmentActionsAPI.DeployEnvironment(context.Background(), bp.EnvId).Execute()
if err != nil {
utils.PrintlnError(fmt.Errorf("deploy failed: %w", err))
os.Exit(1)
panic("unreachable") // staticcheck false positive: https://staticcheck.io/docs/checks#SA5011
}

utils.Println(fmt.Sprintf("Request to deploy blueprint %s has been queued..", pterm.FgBlue.Sprintf("%s", bp.ProjectName)))

if watchFlag {
time.Sleep(3 * time.Second)
utils.WatchEnvironment(bp.EnvId, qovery.STATEENUM_DEPLOYED, client)
}
},
}

func init() {
rdeBlueprintCmd.AddCommand(rdeBlueprintDeployCmd)
rdeBlueprintDeployCmd.Flags().StringVarP(&rdeBlueprintProjectName, "project", "p", "", "Blueprint Project Name")
rdeBlueprintDeployCmd.Flags().StringVarP(&organizationName, "organization", "o", "", "Organization Name")
rdeBlueprintDeployCmd.Flags().BoolVarP(&watchFlag, "watch", "w", false, "Watch deployment status until it's ready or an error occurs")

_ = rdeBlueprintDeployCmd.MarkFlagRequired("project")
}
86 changes: 86 additions & 0 deletions cmd/rde_blueprint_list.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
package cmd

import (
"encoding/json"
"fmt"
"os"

"github.com/qovery/qovery-cli/utils"
"github.com/spf13/cobra"
)

var rdeBlueprintListCmd = &cobra.Command{
Use: "list",
Short: "List all RDE blueprints",
Run: func(cmd *cobra.Command, args []string) {
utils.Capture(cmd)

client := utils.GetQoveryClientPanicInCaseOfError()
orgId, err := rdeGetOrgId(client)
checkError(err)

blueprints, err := rdeListBlueprintProjects(client, orgId)
checkError(err)

if len(blueprints) == 0 {
utils.Println("No RDE blueprints found.")
return
}

if jsonFlag {
var results []interface{}
for _, bp := range blueprints {
status := ""
if bp.EnvId != "" {
s, err := rdeGetEnvStatus(client, bp.EnvId)
if err == nil {
status = string(s)
}
}
results = append(results, map[string]interface{}{
"project_id": bp.ProjectId,
"project_name": bp.ProjectName,
"env_id": bp.EnvId,
"env_name": bp.EnvName,
"status": status,
})
}
j, _ := json.Marshal(results)
utils.Println(string(j))
return
}

var data [][]string
for _, bp := range blueprints {
status := "NO_ENV"
if bp.EnvId != "" {
s, err := rdeGetEnvStatus(client, bp.EnvId)
if err == nil {
status = string(utils.GetStatusTextWithColor(s))
}
}

envName := "-"
if bp.EnvName != "" {
envName = bp.EnvName
}

data = append(data, []string{bp.ProjectName, envName, status, bp.ProjectId})
}

err = utils.PrintTable([]string{"Project Name", "Environment", "Status", "Project ID"}, data)
if err != nil {
utils.PrintlnError(err)
os.Exit(1)
panic("unreachable") // staticcheck false positive: https://staticcheck.io/docs/checks#SA5011
}

utils.Println(fmt.Sprintf("\nTotal: %d blueprint(s)", len(blueprints)))
},
}

func init() {
rdeBlueprintCmd.AddCommand(rdeBlueprintListCmd)
rdeBlueprintListCmd.Flags().StringVarP(&organizationName, "organization", "o", "", "Organization Name")
rdeBlueprintListCmd.Flags().BoolVarP(&jsonFlag, "json", "", false, "JSON output")
}
104 changes: 104 additions & 0 deletions cmd/rde_blueprint_register.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
package cmd

import (
"context"
"fmt"
"os"

"github.com/qovery/qovery-cli/utils"
"github.com/qovery/qovery-client-go"
"github.com/spf13/cobra"
)

var rdeBlueprintRegisterCmd = &cobra.Command{
Use: "register",
Short: "Register a project as an RDE blueprint",
Long: `Register an existing project as an RDE blueprint by setting the
BLUEPRINT_PROJECT_ID project-level variable and BLUEPRINT_KEY on the
first DEVELOPMENT environment.

The project must already exist and contain at least one environment.`,
Run: func(cmd *cobra.Command, args []string) {
utils.Capture(cmd)

client := utils.GetQoveryClientPanicInCaseOfError()
orgId, err := rdeGetOrgId(client)
checkError(err)

// Find the project by name
project, err := rdeFindProjectByName(client, orgId, rdeBlueprintProjectName)
if err != nil {
utils.PrintlnError(fmt.Errorf("project %s not found in organization", rdeBlueprintProjectName))
os.Exit(1)
panic("unreachable") // staticcheck false positive: https://staticcheck.io/docs/checks#SA5011
}

// Check if already registered as a blueprint
vars, err := utils.ListProjectVariables(client, project.Id)
if err == nil {
existing := utils.FindEnvironmentVariableByKey(rdeBlueprintProjectIdVar, vars)
if existing != nil {
utils.PrintlnInfo(fmt.Sprintf("Project %s is already registered as a blueprint", rdeBlueprintProjectName))
return
}
}

// Step 1: Create project-level env var BLUEPRINT_PROJECT_ID = projectId
utils.Println(fmt.Sprintf("Step 1/2: Setting %s on project %s...", rdeBlueprintProjectIdVar, rdeBlueprintProjectName))
err = utils.CreateProjectVariable(client, project.Id, rdeBlueprintProjectIdVar, project.Id, false)
if err != nil {
utils.PrintlnError(fmt.Errorf("failed to create project variable %s: %w", rdeBlueprintProjectIdVar, err))
os.Exit(1)
panic("unreachable") // staticcheck false positive: https://staticcheck.io/docs/checks#SA5011
}

// Step 2: Find first environment and set BLUEPRINT_KEY = projectId
utils.Println("Step 2/2: Setting BLUEPRINT_KEY on environment...")
environments, _, err := client.EnvironmentsAPI.ListEnvironment(context.Background(), project.Id).Execute()
if err != nil {
utils.PrintlnError(fmt.Errorf("failed to list environments: %w", err))
os.Exit(1)
panic("unreachable") // staticcheck false positive: https://staticcheck.io/docs/checks#SA5011
}

envResults := environments.GetResults()
if len(envResults) == 0 {
utils.PrintlnError(fmt.Errorf("project %s has no environments - create at least one environment first", rdeBlueprintProjectName))
os.Exit(1)
panic("unreachable") // staticcheck false positive: https://staticcheck.io/docs/checks#SA5011
}

// Prefer the first DEVELOPMENT environment, fallback to first env
var targetEnv *qovery.Environment
for _, env := range envResults {
if env.Mode == qovery.ENVIRONMENTMODEENUM_DEVELOPMENT {
targetEnv = &env
break
}
}
if targetEnv == nil {
targetEnv = &envResults[0]
}

err = utils.CreateEnvironmentVariable(client, project.Id, targetEnv.Id, rdeBlueprintKeyVar, project.Id, false)
if err != nil {
utils.PrintlnError(fmt.Errorf("failed to create environment variable %s: %w", rdeBlueprintKeyVar, err))
os.Exit(1)
panic("unreachable") // staticcheck false positive: https://staticcheck.io/docs/checks#SA5011
}

utils.Println("")
utils.Println("Blueprint registered successfully!")
utils.Println(fmt.Sprintf(" Project: %s (%s)", project.Name, project.Id))
utils.Println(fmt.Sprintf(" Environment: %s (%s)", targetEnv.Name, targetEnv.Id))
utils.Println(fmt.Sprintf(" Console: https://console.qovery.com/organization/%s/project/%s/environment/%s", orgId, project.Id, targetEnv.Id))
},
}

func init() {
rdeBlueprintCmd.AddCommand(rdeBlueprintRegisterCmd)
rdeBlueprintRegisterCmd.Flags().StringVarP(&rdeBlueprintProjectName, "project", "p", "", "Project Name to register as a blueprint")
rdeBlueprintRegisterCmd.Flags().StringVarP(&organizationName, "organization", "o", "", "Organization Name")

_ = rdeBlueprintRegisterCmd.MarkFlagRequired("project")
}
69 changes: 69 additions & 0 deletions cmd/rde_blueprint_status.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
package cmd

import (
"fmt"
"os"

"github.com/pterm/pterm"
"github.com/qovery/qovery-cli/utils"
"github.com/spf13/cobra"
)

var rdeBlueprintStatusCmd = &cobra.Command{
Use: "status",
Short: "Show detailed status of a blueprint",
Run: func(cmd *cobra.Command, args []string) {
utils.Capture(cmd)

client := utils.GetQoveryClientPanicInCaseOfError()
orgId, err := rdeGetOrgId(client)
checkError(err)

bp, err := rdeFindBlueprintByProjectName(client, orgId, rdeBlueprintProjectName)
if err != nil {
utils.PrintlnError(err)
os.Exit(1)
panic("unreachable") // staticcheck false positive: https://staticcheck.io/docs/checks#SA5011
}

rows := [][]string{
{"Blueprint", pterm.FgBlue.Sprintf("%s", bp.ProjectName)},
{"Project", bp.ProjectId},
}

if bp.EnvId == "" {
rows = append(rows, []string{"Environment", "(none)"})
rdePrintKeyValueTable(rows)
return
}

rows = append(rows, []string{"Environment", fmt.Sprintf("%s (%s)", bp.EnvName, bp.EnvId)})

status, err := rdeGetEnvStatus(client, bp.EnvId)
if err == nil {
rows = append(rows, []string{"Status", utils.GetStatusTextWithColor(status)})
}

rows = append(rows, []string{"Console", fmt.Sprintf("https://console.qovery.com/organization/%s/project/%s/environment/%s", orgId, bp.ProjectId, bp.EnvId)})

// Count children
children, err := rdeListChildren(client, orgId, bp.ProjectId)
if err == nil {
rows = append(rows, []string{"Children", fmt.Sprintf("%d RDE(s)", len(children))})
}

rdePrintKeyValueTable(rows)

// List services
utils.Println("")
rdePrintEnvServices(client, bp.EnvId)
},
}

func init() {
rdeBlueprintCmd.AddCommand(rdeBlueprintStatusCmd)
rdeBlueprintStatusCmd.Flags().StringVarP(&rdeBlueprintProjectName, "project", "p", "", "Blueprint Project Name")
rdeBlueprintStatusCmd.Flags().StringVarP(&organizationName, "organization", "o", "", "Organization Name")

_ = rdeBlueprintStatusCmd.MarkFlagRequired("project")
}
Loading
Loading