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: 4 additions & 3 deletions cmd/agent/workspace/delete.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,10 @@ func NewDeleteCmd(flags *flags.GlobalFlags) *cobra.Command {
GlobalFlags: flags,
}
deleteCmd := &cobra.Command{
Use: "delete",
Short: "Cleans up a workspace on the remote server",
Args: cobra.NoArgs,
Use: "delete",
Aliases: []string{"rm"},
Short: "Cleans up a workspace on the remote server",
Args: cobra.NoArgs,
RunE: func(cobraCmd *cobra.Command, _ []string) error {
return cmd.Run(cobraCmd.Context())
},
Expand Down
5 changes: 3 additions & 2 deletions cmd/context/delete.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,9 @@ func NewDeleteCmd(flags *flags.GlobalFlags) *cobra.Command {
GlobalFlags: flags,
}
deleteCmd := &cobra.Command{
Use: "delete",
Short: "Delete a Devsy context",
Use: "delete",
Aliases: []string{"rm"},
Short: "Delete a Devsy context",
RunE: func(cobraCmd *cobra.Command, args []string) error {
if len(args) > 1 {
return fmt.Errorf("specify the context to delete")
Expand Down
5 changes: 3 additions & 2 deletions cmd/machine/delete.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,9 @@ func NewDeleteCmd(flags *flags.GlobalFlags) *cobra.Command {
GlobalFlags: flags,
}
deleteCmd := &cobra.Command{
Use: "delete [name]",
Short: "Deletes an existing machine",
Use: "delete [name]",
Aliases: []string{"rm"},
Short: "Deletes an existing machine",
RunE: func(cobraCmd *cobra.Command, args []string) error {
return cmd.Run(cobraCmd.Context(), args)
},
Expand Down
9 changes: 5 additions & 4 deletions cmd/pro/provider/delete.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,11 @@ func NewDeleteCmd(globalFlags *flags.GlobalFlags) *cobra.Command {
GlobalFlags: globalFlags,
}
c := &cobra.Command{
Hidden: true,
Use: "delete",
Short: "Runs delete on a workspace",
Args: cobra.NoArgs,
Hidden: true,
Use: "delete",
Aliases: []string{"rm"},
Short: "Runs delete on a workspace",
Args: cobra.NoArgs,
RunE: func(cobraCmd *cobra.Command, args []string) error {
return cmd.Run(cobraCmd.Context(), os.Stdin, os.Stdout, os.Stderr)
},
Expand Down
3 changes: 1 addition & 2 deletions cmd/provider/add.go
Original file line number Diff line number Diff line change
Expand Up @@ -146,8 +146,7 @@ func (cmd *AddCmd) Run(ctx context.Context, devsyConfig *config.Config, args []s
return writeDefaultProvider(cmd.Context, providerConfig.Name)
}

log.Infof("To configure the provider, run the following command:")
log.Infof("devsy provider configure %s", providerConfig.Name)
log.Infof("To initialize the provider, run: devsy provider init %s", providerConfig.Name)
return nil
}

Expand Down
7 changes: 4 additions & 3 deletions cmd/provider/delete.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,10 @@ func NewDeleteCmd(flags *flags.GlobalFlags) *cobra.Command {
GlobalFlags: flags,
}
deleteCmd := &cobra.Command{
Use: "delete [name]",
Short: "Deletes an existing provider",
Args: cobra.MaximumNArgs(1),
Use: "delete [name]",
Aliases: []string{"rm"},
Short: "Deletes an existing provider",
Args: cobra.MaximumNArgs(1),
RunE: func(cobraCmd *cobra.Command, args []string) error {
return cmd.Run(cobraCmd.Context(), args)
},
Expand Down
9 changes: 9 additions & 0 deletions cmd/provider/delete_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package provider

import (
"slices"
"testing"

"github.com/devsy-org/devsy/cmd/flags"
Expand All @@ -14,3 +15,11 @@ func TestDeleteCmd_RejectsMultipleArgs(t *testing.T) {
t.Fatal("expected error when passing multiple arguments to delete, got nil")
}
}

func TestDeleteCmdHasRmAlias(t *testing.T) {
cmd := NewDeleteCmd(&flags.GlobalFlags{})
found := slices.Contains(cmd.Aliases, "rm")
if !found {
t.Fatal("provider delete should expose 'rm' alias")
}
}
28 changes: 14 additions & 14 deletions cmd/provider/configure.go → cmd/provider/init.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,21 +8,21 @@ import (
"github.com/spf13/cobra"
)

// ConfigureCmd holds flags for the `provider configure` subcommand.
type ConfigureCmd struct {
// InitCmd holds flags for the `provider init` subcommand.
type InitCmd struct {
*flags.GlobalFlags
Reconfigure bool
SingleMachine bool
Options []string
SkipInit bool
}

// NewConfigureCmd creates the cobra command for `provider configure`.
func NewConfigureCmd(f *flags.GlobalFlags) *cobra.Command {
cmd := &ConfigureCmd{GlobalFlags: f}
configureCmd := &cobra.Command{
Use: "configure [name]",
Short: "Re-run init and option resolution for an existing provider",
// NewInitCmd creates the cobra command for `provider init`.
func NewInitCmd(f *flags.GlobalFlags) *cobra.Command {
cmd := &InitCmd{GlobalFlags: f}
initCmd := &cobra.Command{
Use: "init [name]",
Short: "Run or re-run init and option resolution for an existing provider",
Args: cobra.MaximumNArgs(1),
RunE: func(cobraCmd *cobra.Command, args []string) error {
devsyConfig, err := config.LoadConfig(cmd.Context, cmd.Provider)
Expand Down Expand Up @@ -63,14 +63,14 @@ func NewConfigureCmd(f *flags.GlobalFlags) *cobra.Command {
)
},
}
configureCmd.Flags().
initCmd.Flags().
BoolVar(&cmd.Reconfigure, "reconfigure", false, "Force re-resolution of all options")
configureCmd.Flags().
initCmd.Flags().
BoolVar(&cmd.SingleMachine, "single-machine", false, "Use a single machine for all workspaces")
configureCmd.Flags().
initCmd.Flags().
StringArrayVarP(&cmd.Options, "option", "o", []string{}, "Provider option in the form KEY=VALUE")
configureCmd.Flags().
initCmd.Flags().
BoolVar(&cmd.SkipInit, "skip-init", false, "Skip provider init (testing only)")
_ = configureCmd.Flags().MarkHidden("skip-init")
return configureCmd
_ = initCmd.Flags().MarkHidden("skip-init")
return initCmd
}
8 changes: 4 additions & 4 deletions cmd/provider/configure_test.go → cmd/provider/init_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,10 @@ import (
"github.com/devsy-org/devsy/cmd/flags"
)

func TestNewConfigureCmd(t *testing.T) {
cmd := NewConfigureCmd(&flags.GlobalFlags{})
if cmd.Use != "configure [name]" {
t.Errorf("Use: got %q want %q", cmd.Use, "configure [name]")
func TestNewInitCmd(t *testing.T) {
cmd := NewInitCmd(&flags.GlobalFlags{})
if cmd.Use != "init [name]" {
t.Errorf("Use: got %q want %q", cmd.Use, "init [name]")
}
if cmd.Short == "" {
t.Error("Short must be set")
Expand Down
4 changes: 2 additions & 2 deletions cmd/provider/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,13 @@ func NewProviderCmd(flags *flags.GlobalFlags) *cobra.Command {
}

providerCmd.AddCommand(NewAddCmd(flags))
providerCmd.AddCommand(NewConfigureCmd(flags))
providerCmd.AddCommand(NewDeleteCmd(flags))
providerCmd.AddCommand(NewGetCmd(flags))
providerCmd.AddCommand(NewInitCmd(flags))
providerCmd.AddCommand(NewListCmd(flags))
providerCmd.AddCommand(NewRenameCmd(flags))
providerCmd.AddCommand(NewSetCmd(flags))
providerCmd.AddCommand(NewUpdateCmd(flags))
providerCmd.AddCommand(NewSetSourceCmd(flags))
providerCmd.AddCommand(NewUseCmd(flags))
providerCmd.AddCommand(NewVersionsCmd(flags))
return providerCmd
Expand Down
7 changes: 4 additions & 3 deletions cmd/provider/rename.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,10 @@ func NewRenameCmd(globalFlags *flags.GlobalFlags) *cobra.Command {
}

return &cobra.Command{
Use: "rename <current-name> <new-name>",
Short: "Rename a provider",
Args: cobra.ExactArgs(2),
Use: "rename <current-name> <new-name>",
Aliases: []string{"mv"},
Short: "Rename a provider",
Args: cobra.ExactArgs(2),
RunE: func(cobraCmd *cobra.Command, args []string) error {
return cmd.Run(cobraCmd.Context(), args)
},
Expand Down
105 changes: 105 additions & 0 deletions cmd/provider/set_source.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
package provider

import (
"context"
"fmt"

"github.com/devsy-org/devsy/cmd/flags"
"github.com/devsy-org/devsy/pkg/config"
"github.com/devsy-org/devsy/pkg/log"
"github.com/devsy-org/devsy/pkg/workspace"
"github.com/spf13/cobra"
)

// SetSourceCmd holds the cmd flags.
type SetSourceCmd struct {
*flags.GlobalFlags

Use bool
Version string
Options []string
}

// NewSetSourceCmd creates a new command.
func NewSetSourceCmd(flags *flags.GlobalFlags) *cobra.Command {
cmd := &SetSourceCmd{
GlobalFlags: flags,
}
setSourceCmd := &cobra.Command{
Use: "set-source [name] [name, GitHub link, URL or path]",
Short: "Set or change a provider's source (replaces the registered name, repo, URL, or path)",
RunE: func(cobraCmd *cobra.Command, args []string) error {
ctx := cobraCmd.Context()
devsyConfig, err := config.LoadConfig(cmd.Context, cmd.Provider)
if err != nil {
return err
}

return cmd.Run(ctx, devsyConfig, args)
},
}

setSourceCmd.Flags().
BoolVar(&cmd.Use, "use", true, "If enabled will automatically activate the provider")
setSourceCmd.Flags().
StringVar(&cmd.Version, "version", "", "Pin the provider to a specific version tag")
setSourceCmd.Flags().
StringArrayVarP(&cmd.Options, "option", "o", []string{}, "Provider option in the form KEY=VALUE")
return setSourceCmd
}

func (cmd *SetSourceCmd) Run(ctx context.Context, devsyConfig *config.Config, args []string) error {
if cmd.Version != "" {
return cmd.runPinVersion(devsyConfig, args)
}

if len(args) != 1 && len(args) != 2 {
return fmt.Errorf("specify either a local file, URL or Git repository. " +
"E.g. devsy provider set-source my-provider " + config.ProviderPrefix + "gcloud")
}

providerSource := ""
if len(args) == 2 {
providerSource = args[1]
}

providerConfig, err := workspace.UpdateProvider(devsyConfig, args[0], providerSource)
if err != nil {
return err
}

log.Infof("updated provider: providerName=%s", providerConfig.Name)
if !cmd.Use {
log.Infof("To initialize the provider, run: devsy provider init %s", providerConfig.Name)
return nil
}

if err := ConfigureProvider(ctx, ProviderOptionsConfig{
Provider: providerConfig,
Context: devsyConfig.DefaultContext,
UserOptions: cmd.Options,
}); err != nil {
log.Errorf(
"Error initializing provider, retry with 'devsy provider init %s --reconfigure'",
providerConfig.Name,
)
return fmt.Errorf("configure provider: %w", err)
}
Comment on lines +77 to +87

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Recover the removed update.go from git history and inspect its ConfigureProvider call.
del=$(git rev-list -n1 HEAD -- cmd/provider/update.go)
if [ -n "$del" ]; then
  echo "Last commit touching update.go: $del"
  echo "===== content prior to deletion ====="
  git show "${del}^:cmd/provider/update.go" 2>/dev/null | sed -n '1,200p'
else
  echo "No git history found for cmd/provider/update.go"
fi

Repository: devsy-org/devsy

Length of output: 107


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== Check whether cmd/provider/update.go exists =="
ls -la cmd/provider | sed -n '1,200p' || true
test -f cmd/provider/update.go && echo "FOUND: cmd/provider/update.go" || echo "MISSING: cmd/provider/update.go"

echo
echo "== Find all ConfigureProvider calls in cmd/provider =="
rg -n "ConfigureProvider\\(" cmd/provider -S || true

echo
echo "== Search for Reconfigure: true / SkipRequired / SkipInit / SkipSubOptions / SingleMachine usage =="
rg -n "Reconfigure\\s*:\\s*true|SkipRequired|SkipInit|SkipSubOptions|SingleMachine" cmd/provider -S || true

echo
echo "== Search for 'provider update' command wiring =="
rg -n "provider\\s+update|update\\b" cmd/provider -S || true

echo
echo "== Inspect cmd/provider/set_source.go around ConfigureProvider call =="
sed -n '1,140p' cmd/provider/set_source.go || true

Repository: devsy-org/devsy

Length of output: 7111


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== Inspect cmd/provider/configure_shared.go =="
sed -n '1,220p' cmd/provider/configure_shared.go

echo
echo "== Inspect cmd/provider/add.go around ConfigureProvider call =="
sed -n '90,170p' cmd/provider/add.go

echo
echo "== Inspect cmd/provider/init.go around ConfigureProvider call =="
sed -n '1,130p' cmd/provider/init.go

echo
echo "== Inspect cmd/provider/set_source_test.go to see expected behavior =="
sed -n '1,220p' cmd/provider/set_source_test.go

Repository: devsy-org/devsy

Length of output: 10191


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== Search for workspace.UpdateProvider usage =="
rg -n "workspace\.UpdateProvider" -S . || true

echo
echo "== Search for ConfigureProvider calls with Reconfigure flags =="
rg -n "ConfigureProvider\\(ctx, ProviderOptionsConfig\\{" cmd/provider -S || true
rg -n "Reconfigure\\s*:\\s*(true|false)" cmd/provider -S || true

echo
echo "== Search for 'update' command wiring in cmd/provider =="
rg -n "\\bprovider\\s+update\\b|\\bUpdateCmd\\b|Use:\\s*\"update\"" cmd/provider -S || true

echo
echo "== Inspect cmd/provider/set.go for related reconfigure logic =="
sed -n '1,220p' cmd/provider/set.go

echo
echo "== Inspect cmd/provider/provider.go for command registration =="
sed -n '1,240p' cmd/provider/provider.go

Repository: devsy-org/devsy

Length of output: 5179


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== Inspect cmd/pro/update_provider.go =="
sed -n '1,220p' cmd/pro/update_provider.go

echo
echo "== Inspect workspace.UpdateProvider implementation =="
rg -n "func UpdateProvider\\(" -S ./pkg ./cmd || true
fd -e go UpdateProvider -a ./pkg ./cmd | head -n 20 || true

# Print the exact file that contains the function, if found
f=$(rg -l "func UpdateProvider\\(" -S ./pkg ./cmd | head -n 1 || true)
if [ -n "${f}" ]; then
  echo
  echo "== File: $f =="
  sed -n '1,260p' "$f"
fi

Repository: devsy-org/devsy

Length of output: 9187


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== Search for any provider command named update =="
rg -n 'Use:\s*"update' cmd/provider -S || true

echo
echo "== Search for ConfigureProvider calls in cmd/provider excluding set_source.go/add.go =="
rg -n "ConfigureProvider\\(ctx, ProviderOptionsConfig\\{" cmd/provider -S || true

echo
echo "== Search for 'Update' in cmd/provider file names =="
ls -ლა cmd/provider | sed -n '1,200p'

echo
echo "== Search for 'reconfigure' flag wiring in cmd/provider =="
rg -n 'reconfigure' cmd/provider -S || true

Repository: devsy-org/devsy

Length of output: 510


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== Locate ResolveOptions implementation =="
rg -n "func ResolveOptions\\(" -S pkg | head -n 20

f=$(rg -l "func ResolveOptions\\(" pkg | head -n 1 || true)
if [ -n "$f" ]; then
  echo
  echo "== File: $f =="
  sed -n '1,260p' "$f"
fi

echo
echo "== Search how resolve options handles unknown keys / required options =="
rg -n "unknown|not provided|required|SkipRequired|SkipSubOptions" -S "$f" || true

Repository: devsy-org/devsy

Length of output: 7492


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== Inspect cmd/provider/set_source_test.go =="
sed -n '1,260p' cmd/provider/set_source_test.go

echo
echo "== Search for set-source usage in tests =="
rg -n "set-source" -S . || true

echo
echo "== Search for provider init --reconfigure references =="
rg -n "init .*--reconfigure|--reconfigure.*provider init|provider init.*--reconfigure" -S . || true

Repository: devsy-org/devsy

Length of output: 2110


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== Inspect docs for provider set-source =="
sed -n '1,120p' docs/pages/managing-providers/set-source.mdx

echo
echo "== Inspect resolver behavior for unknown/extra options =="
rg -n "unknown option|not provided|not defined|extra option|unrecognized|skip.*unknown" pkg/options -S || true

echo
echo "== Locate resolver.New and its handling of input option keys =="
rg -n "func New\\(" pkg/options/resolver -S || true

f=$(rg -l "package resolver" pkg/options/resolver | head -n 1 || true)
echo "resolver dir sample file: $f"

# Print key resolver files (small-ish)
ls pkg/options/resolver 2>/dev/null | head -n 50 || true
for f in $(ls pkg/options/resolver 2>/dev/null | head -n 20); do
  echo "---- pkg/options/resolver/$f ----"
  sed -n '1,220p' "pkg/options/resolver/$f" | head -n 220
done

Repository: devsy-org/devsy

Length of output: 28043


set-source should likely pass Reconfigure: true after swapping provider source

cmd/provider/set_source.go calls ConfigureProvider without Reconfigure, so configure_shared.go will merge existing user-provided option values into the new option resolution (mergeExistingOptions when !cfg.Reconfigure). This differs from provider add (sets Reconfigure: true) and pro update-provider (also sets Reconfigure: true). Consider setting Reconfigure: true (and explicitly setting other defaults for clarity) to avoid carrying stale user-provided option values across source/schema changes.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@cmd/provider/set_source.go` around lines 77 - 87, The call to
ConfigureProvider in set-source.go is missing Reconfigure: true so
ConfigureProvider will merge prior user options (via mergeExistingOptions) into
the new source/schema; update the ProviderOptionsConfig passed to
ConfigureProvider to include Reconfigure: true (and explicitly set other default
fields as needed) so the provider option resolution behaves like provider
add/update-provider and does not carry stale values; locate the
ConfigureProvider invocation in set-source.go and modify the
ProviderOptionsConfig struct to include Reconfigure: true.


return writeDefaultProvider(cmd.Context, providerConfig.Name)
}

func (cmd *SetSourceCmd) runPinVersion(devsyConfig *config.Config, args []string) error {
if len(args) == 0 {
return fmt.Errorf("provider name must be provided when using --version")
}
if len(args) > 1 {
return fmt.Errorf("--version and a source argument are mutually exclusive")
}
providerName := args[0]
if err := workspace.SetProviderVersion(devsyConfig, providerName, cmd.Version); err != nil {
return err
}
log.Infof("pinned provider %s to version %s", providerName, cmd.Version)
return nil
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ import (
"github.com/devsy-org/devsy/cmd/flags"
)

func TestUpdateCmd_VersionFlag(t *testing.T) {
cmd := NewUpdateCmd(&flags.GlobalFlags{})
func TestSetSourceCmd_VersionFlag(t *testing.T) {
cmd := NewSetSourceCmd(&flags.GlobalFlags{})
if cmd.Flag("version") == nil {
t.Fatal("expected --version flag")
}
Expand Down
Loading
Loading