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
7 changes: 6 additions & 1 deletion cmd/application/env/create.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ func NewCreateEnvCommand() *cobra.Command {
isPreview, _ := cmd.Flags().GetBool("preview")
isLiteral, _ := cmd.Flags().GetBool("is-literal")
isMultiline, _ := cmd.Flags().GetBool("is-multiline")
isRuntime, _ := cmd.Flags().GetBool("runtime")

if key == "" {
return fmt.Errorf("--key is required")
Expand All @@ -56,6 +57,9 @@ func NewCreateEnvCommand() *cobra.Command {
if cmd.Flags().Changed("is-multiline") {
req.IsMultiline = &isMultiline
}
if cmd.Flags().Changed("runtime") {
req.IsRuntime = &isRuntime
}

appSvc := service.NewApplicationService(client)
env, err := appSvc.CreateEnv(ctx, appUUID, req)
Expand All @@ -71,9 +75,10 @@ func NewCreateEnvCommand() *cobra.Command {

cmd.Flags().String("key", "", "Environment variable key (required)")
cmd.Flags().String("value", "", "Environment variable value (required)")
cmd.Flags().Bool("build-time", false, "Available at build time")
cmd.Flags().Bool("build-time", true, "Available at build time (default: true)")
cmd.Flags().Bool("preview", false, "Available in preview deployments")
cmd.Flags().Bool("is-literal", false, "Treat value as literal (don't interpolate variables)")
cmd.Flags().Bool("is-multiline", false, "Value is multiline")
cmd.Flags().Bool("runtime", true, "Available at runtime (default: true)")
return cmd
}
6 changes: 5 additions & 1 deletion cmd/application/env/get.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import (
)

func NewGetEnvCommand() *cobra.Command {
return &cobra.Command{
cmd := &cobra.Command{
Use: "get <app_uuid> <env_uuid_or_key>",
Short: "Get environment variable details",
Long: `Get detailed information about a specific environment variable by UUID or key name.`,
Expand All @@ -27,6 +27,8 @@ func NewGetEnvCommand() *cobra.Command {
}

appSvc := service.NewApplicationService(client)

// First try to get by the identifier directly
env, err := appSvc.GetEnv(ctx, appUUID, envUUIDOrKey)
if err != nil {
return fmt.Errorf("failed to get environment variable: %w", err)
Expand All @@ -53,4 +55,6 @@ func NewGetEnvCommand() *cobra.Command {
return formatter.Format(env)
},
}

return cmd
}
34 changes: 32 additions & 2 deletions cmd/application/env/list.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,21 @@ package env

import (
"fmt"
"sort"

"github.com/spf13/cobra"

"github.com/coollabsio/coolify-cli/internal/cli"
"github.com/coollabsio/coolify-cli/internal/models"
"github.com/coollabsio/coolify-cli/internal/output"
"github.com/coollabsio/coolify-cli/internal/service"
)

func NewListEnvCommand() *cobra.Command {
return &cobra.Command{
cmd := &cobra.Command{
Use: "list <app_uuid>",
Short: "List all environment variables for an application",
Long: `List all environment variables for a specific application.`,
Long: `List all environment variables for a specific application. By default, only non-preview environment variables are shown. Use --preview to show preview environment variables instead, or --all to show all variables (non-preview first, then preview).`,
Args: cli.ExactArgs(1, "<uuid>"),
RunE: func(cmd *cobra.Command, args []string) error {
ctx := cmd.Context()
Expand All @@ -31,6 +33,29 @@ func NewListEnvCommand() *cobra.Command {
return fmt.Errorf("failed to list environment variables: %w", err)
}

// Filter by preview/all flags
showAll, _ := cmd.Flags().GetBool("all")
showPreview, _ := cmd.Flags().GetBool("preview")

if showAll {
// Sort: non-preview first, then preview
sort.SliceStable(envs, func(i, j int) bool {
if envs[i].IsPreview != envs[j].IsPreview {
return !envs[i].IsPreview // non-preview (false) comes before preview (true)
}
return false // maintain original order within groups
})
} else {
// Filter by preview flag
var filtered []models.EnvironmentVariable
for _, env := range envs {
if env.IsPreview == showPreview {
filtered = append(filtered, env)
}
}
envs = filtered
}

format, _ := cmd.Flags().GetString("format")
showSensitive, _ := cmd.Flags().GetBool("show-sensitive")

Expand All @@ -54,4 +79,9 @@ func NewListEnvCommand() *cobra.Command {
return formatter.Format(envs)
},
}

cmd.Flags().Bool("preview", false, "Show preview environment variables instead of regular ones")
cmd.Flags().Bool("all", false, "Show all environment variables (non-preview first, then preview)")

return cmd
}
7 changes: 6 additions & 1 deletion cmd/application/env/sync.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ Example: coolify app env sync abc123 --file .env.production`,
isBuildTime, _ := cmd.Flags().GetBool("build-time")
isPreview, _ := cmd.Flags().GetBool("preview")
isLiteral, _ := cmd.Flags().GetBool("is-literal")
isRuntime, _ := cmd.Flags().GetBool("runtime")

// Parse the .env file
envVars, err := parser.ParseEnvFile(filePath)
Expand Down Expand Up @@ -87,6 +88,9 @@ Example: coolify app env sync abc123 --file .env.production`,
if cmd.Flags().Changed("is-literal") {
req.IsLiteral = &isLiteral
}
if cmd.Flags().Changed("runtime") {
req.IsRuntime = &isRuntime
}

// Auto-detect multiline values
if strings.Contains(envVar.Value, "\n") {
Expand Down Expand Up @@ -147,8 +151,9 @@ Example: coolify app env sync abc123 --file .env.production`,
}

syncEnvCmd.Flags().StringP("file", "f", "", "Path to .env file (required)")
syncEnvCmd.Flags().Bool("build-time", false, "Make all variables available at build time")
syncEnvCmd.Flags().Bool("build-time", true, "Make all variables available at build time (default: true)")
syncEnvCmd.Flags().Bool("preview", false, "Make all variables available in preview deployments")
syncEnvCmd.Flags().Bool("is-literal", false, "Treat all values as literal (don't interpolate variables)")
syncEnvCmd.Flags().Bool("runtime", true, "Make all variables available at runtime (default: true)")
return syncEnvCmd
}
9 changes: 7 additions & 2 deletions cmd/application/env/update.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,8 +54,12 @@ func NewUpdateEnvCommand() *cobra.Command {
isMultiline, _ := cmd.Flags().GetBool("is-multiline")
req.IsMultiline = &isMultiline
}
if cmd.Flags().Changed("runtime") {
isRuntime, _ := cmd.Flags().GetBool("runtime")
req.IsRuntime = &isRuntime
}

if req.Key == nil && req.Value == nil && req.IsBuildTime == nil && req.IsPreview == nil && req.IsLiteral == nil && req.IsMultiline == nil {
if req.Key == nil && req.Value == nil && req.IsBuildTime == nil && req.IsPreview == nil && req.IsLiteral == nil && req.IsMultiline == nil && req.IsRuntime == nil {
return fmt.Errorf("at least one field must be provided to update")
}

Expand All @@ -72,9 +76,10 @@ func NewUpdateEnvCommand() *cobra.Command {

cmd.Flags().String("key", "", "New environment variable key")
cmd.Flags().String("value", "", "New environment variable value")
cmd.Flags().Bool("build-time", false, "Available at build time")
cmd.Flags().Bool("build-time", true, "Available at build time (default: true)")
cmd.Flags().Bool("preview", false, "Available in preview deployments")
cmd.Flags().Bool("is-literal", false, "Treat value as literal")
cmd.Flags().Bool("is-multiline", false, "Value is multiline")
cmd.Flags().Bool("runtime", true, "Available at runtime (default: true)")
return cmd
}
14 changes: 7 additions & 7 deletions cmd/service/env/create.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,9 @@ func NewCreateCommand() *cobra.Command {
key, _ := cmd.Flags().GetString("key")
value, _ := cmd.Flags().GetString("value")
isBuildTime, _ := cmd.Flags().GetBool("build-time")
isPreview, _ := cmd.Flags().GetBool("preview")
isLiteral, _ := cmd.Flags().GetBool("is-literal")
isMultiline, _ := cmd.Flags().GetBool("is-multiline")
isRuntime, _ := cmd.Flags().GetBool("runtime")

if key == "" {
return fmt.Errorf("--key is required")
Expand All @@ -39,7 +39,7 @@ func NewCreateCommand() *cobra.Command {
return fmt.Errorf("--value is required")
}

req := &models.EnvironmentVariableCreateRequest{
req := &models.ServiceEnvironmentVariableCreateRequest{
Key: key,
Value: value,
}
Expand All @@ -48,15 +48,15 @@ func NewCreateCommand() *cobra.Command {
if cmd.Flags().Changed("build-time") {
req.IsBuildTime = &isBuildTime
}
if cmd.Flags().Changed("preview") {
req.IsPreview = &isPreview
}
if cmd.Flags().Changed("is-literal") {
req.IsLiteral = &isLiteral
}
if cmd.Flags().Changed("is-multiline") {
req.IsMultiline = &isMultiline
}
if cmd.Flags().Changed("runtime") {
req.IsRuntime = &isRuntime
}

serviceSvc := service.NewService(client)
env, err := serviceSvc.CreateEnv(ctx, uuid, req)
Expand All @@ -71,10 +71,10 @@ func NewCreateCommand() *cobra.Command {

cmd.Flags().String("key", "", "Environment variable key (required)")
cmd.Flags().String("value", "", "Environment variable value (required)")
cmd.Flags().Bool("build-time", false, "Available at build time")
cmd.Flags().Bool("preview", false, "Available in preview deployments")
cmd.Flags().Bool("build-time", true, "Available at build time (default: true)")
cmd.Flags().Bool("is-literal", false, "Treat value as literal (don't interpolate variables)")
cmd.Flags().Bool("is-multiline", false, "Value is multiline")
cmd.Flags().Bool("runtime", true, "Available at runtime (default: true)")

return cmd
}
22 changes: 11 additions & 11 deletions cmd/service/env/sync.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,8 @@ Example: coolify service env sync abc123 --file .env.production`,
}

isBuildTime, _ := cmd.Flags().GetBool("build-time")
isPreview, _ := cmd.Flags().GetBool("preview")
isLiteral, _ := cmd.Flags().GetBool("is-literal")
isRuntime, _ := cmd.Flags().GetBool("runtime")

// Parse the .env file
envVars, err := parser.ParseEnvFile(filePath)
Expand All @@ -62,17 +62,17 @@ Example: coolify service env sync abc123 --file .env.production`,
}

// Build a map of existing env vars by key
existingMap := make(map[string]models.EnvironmentVariable)
existingMap := make(map[string]models.ServiceEnvironmentVariable)
for _, env := range existingEnvs {
existingMap[env.Key] = env
}

// Separate into updates and creates
var toUpdate []models.EnvironmentVariableCreateRequest
var toCreate []models.EnvironmentVariableCreateRequest
var toUpdate []models.ServiceEnvironmentVariableCreateRequest
var toCreate []models.ServiceEnvironmentVariableCreateRequest

for _, envVar := range envVars {
req := models.EnvironmentVariableCreateRequest{
req := models.ServiceEnvironmentVariableCreateRequest{
Key: envVar.Key,
Value: envVar.Value,
}
Expand All @@ -81,12 +81,12 @@ Example: coolify service env sync abc123 --file .env.production`,
if cmd.Flags().Changed("build-time") {
req.IsBuildTime = &isBuildTime
}
if cmd.Flags().Changed("preview") {
req.IsPreview = &isPreview
}
if cmd.Flags().Changed("is-literal") {
req.IsLiteral = &isLiteral
}
if cmd.Flags().Changed("runtime") {
req.IsRuntime = &isRuntime
}

// Auto-detect multiline values
if strings.Contains(envVar.Value, "\n") {
Expand All @@ -108,7 +108,7 @@ Example: coolify service env sync abc123 --file .env.production`,
// Perform bulk update if there are vars to update
if len(toUpdate) > 0 {
fmt.Printf("Updating %d existing variables...\n", len(toUpdate))
bulkReq := &service.BulkUpdateEnvsRequest{
bulkReq := &models.ServiceEnvBulkUpdateRequest{
Data: toUpdate,
}
_, err := serviceSvc.BulkUpdateEnvs(ctx, uuid, bulkReq)
Expand Down Expand Up @@ -147,9 +147,9 @@ Example: coolify service env sync abc123 --file .env.production`,
}

cmd.Flags().StringP("file", "f", "", "Path to .env file (required)")
cmd.Flags().Bool("build-time", false, "Make all variables available at build time")
cmd.Flags().Bool("preview", false, "Make all variables available in preview deployments")
cmd.Flags().Bool("build-time", true, "Make all variables available at build time (default: true)")
cmd.Flags().Bool("is-literal", false, "Treat all values as literal (don't interpolate variables)")
cmd.Flags().Bool("runtime", true, "Make all variables available at runtime (default: true)")

return cmd
}
18 changes: 9 additions & 9 deletions cmd/service/env/update.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ func NewUpdateCommand() *cobra.Command {
return fmt.Errorf("failed to get API client: %w", err)
}

req := &models.EnvironmentVariableUpdateRequest{
req := &models.ServiceEnvironmentVariableUpdateRequest{
UUID: envUUID,
}

Expand All @@ -43,10 +43,6 @@ func NewUpdateCommand() *cobra.Command {
isBuildTime, _ := cmd.Flags().GetBool("build-time")
req.IsBuildTime = &isBuildTime
}
if cmd.Flags().Changed("preview") {
isPreview, _ := cmd.Flags().GetBool("preview")
req.IsPreview = &isPreview
}
if cmd.Flags().Changed("is-literal") {
isLiteral, _ := cmd.Flags().GetBool("is-literal")
req.IsLiteral = &isLiteral
Expand All @@ -55,10 +51,14 @@ func NewUpdateCommand() *cobra.Command {
isMultiline, _ := cmd.Flags().GetBool("is-multiline")
req.IsMultiline = &isMultiline
}
if cmd.Flags().Changed("runtime") {
isRuntime, _ := cmd.Flags().GetBool("runtime")
req.IsRuntime = &isRuntime
}

// Check if at least one field is being updated
if req.Key == nil && req.Value == nil && req.IsBuildTime == nil && req.IsPreview == nil && req.IsLiteral == nil && req.IsMultiline == nil {
return fmt.Errorf("at least one field must be provided to update (--key, --value, --build-time, --preview, --is-literal, or --is-multiline)")
if req.Key == nil && req.Value == nil && req.IsBuildTime == nil && req.IsLiteral == nil && req.IsMultiline == nil && req.IsRuntime == nil {
return fmt.Errorf("at least one field must be provided to update (--key, --value, --build-time, --is-literal, --is-multiline, or --runtime)")
}

serviceSvc := service.NewService(client)
Expand All @@ -74,10 +74,10 @@ func NewUpdateCommand() *cobra.Command {

cmd.Flags().String("key", "", "New environment variable key")
cmd.Flags().String("value", "", "New environment variable value")
cmd.Flags().Bool("build-time", false, "Available at build time")
cmd.Flags().Bool("preview", false, "Available in preview deployments")
cmd.Flags().Bool("build-time", true, "Available at build time (default: true)")
cmd.Flags().Bool("is-literal", false, "Treat value as literal (don't interpolate variables)")
cmd.Flags().Bool("is-multiline", false, "Value is multiline")
cmd.Flags().Bool("runtime", true, "Available at runtime (default: true)")

return cmd
}
27 changes: 17 additions & 10 deletions cmd/service/service.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
package service

import "github.com/spf13/cobra"
import (
"github.com/spf13/cobra"

"github.com/coollabsio/coolify-cli/cmd/service/env"
)

// NewServiceCommand creates the service parent command with all subcommands
func NewServiceCommand() *cobra.Command {
Expand All @@ -19,15 +23,18 @@ func NewServiceCommand() *cobra.Command {
cmd.AddCommand(NewRestartCommand())
cmd.AddCommand(NewDeleteCommand())

// Add env subcommand (placeholder for now)
// TODO: Implement env commands
// envCmd := &cobra.Command{
// Use: "env",
// Short: "Manage service environment variables",
// }
// envCmd.AddCommand(env.NewListCommand())
// ... more env commands
// cmd.AddCommand(envCmd)
// Add env subcommand
envCmd := &cobra.Command{
Use: "env",
Short: "Manage service environment variables",
}
envCmd.AddCommand(env.NewListCommand())
envCmd.AddCommand(env.NewGetCommand())
envCmd.AddCommand(env.NewCreateCommand())
envCmd.AddCommand(env.NewUpdateCommand())
envCmd.AddCommand(env.NewDeleteCommand())
envCmd.AddCommand(env.NewSyncCommand())
cmd.AddCommand(envCmd)

return cmd
}
2 changes: 2 additions & 0 deletions internal/models/application.go
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,7 @@ type EnvironmentVariableCreateRequest struct {
IsPreview *bool `json:"is_preview,omitempty"`
IsLiteral *bool `json:"is_literal,omitempty"`
IsMultiline *bool `json:"is_multiline,omitempty"`
IsRuntime *bool `json:"is_runtime,omitempty"`
}

// EnvironmentVariableUpdateRequest represents the request to update an environment variable
Expand All @@ -131,4 +132,5 @@ type EnvironmentVariableUpdateRequest struct {
IsPreview *bool `json:"is_preview,omitempty"`
IsLiteral *bool `json:"is_literal,omitempty"`
IsMultiline *bool `json:"is_multiline,omitempty"`
IsRuntime *bool `json:"is_runtime,omitempty"`
}
Loading