Skip to content

Conversation

@lionello
Copy link
Member

@lionello lionello commented Jan 23, 2026

Description

Using our (existing) state file for tracking the current workspace.

Linked Issues

Checklist

  • I have performed a self-review of my code
  • I have added appropriate tests
  • I have updated the Defang CLI docs and/or README to reflect my changes, if necessary

Summary by CodeRabbit

  • New Features
    • Added workspace selection functionality to switch between workspaces with persistent storage of the selected workspace across sessions
    • CLI now remembers your current workspace selection

✏️ Tip: You can customize this high-level summary in your review settings.

@lionello lionello requested a review from raphaeltm January 23, 2026 02:57
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jan 23, 2026

📝 Walkthrough

Walkthrough

The changes implement persistent tenant state management by adding storage and retrieval APIs for the current workspace, updating the default tenant initialization to read from persistent state, and introducing a new workspace selection command that allows users to switch between workspaces with automatic state persistence.

Changes

Cohort / File(s) Summary
Persistent Tenant State Management
src/pkg/cli/client/state.go
Adds Tenant field to State struct and introduces SetCurrentTenant() and GetCurrentTenant() exported functions to manage persistent tenant state across CLI sessions.
Workspace Selection Workflow
src/cmd/cli/command/workspace.go
Renames public ListWorkspaces function to private listWorkspaces, adds types package import, and introduces new workspaceSelectCmd command that enables workspace selection by name/ID with automatic state update and tenant reconnection.
Global Tenant Initialization
src/cmd/cli/command/globals.go
Updates default tenant initialization to retrieve the current tenant via client.GetCurrentTenant() instead of using an empty TenantNameOrID, allowing environment variable overrides to remain in effect.

Sequence Diagram

sequenceDiagram
    actor User
    participant CLI as CLI Command
    participant Client as Client
    participant State as Persistent State

    User->>CLI: workspace select <workspace-id>
    CLI->>Client: GetTenant (lookup workspace)
    Client-->>CLI: TenantNameOrID
    CLI->>Client: SetCurrentTenant(tenant)
    Client->>State: Write Tenant to state
    State-->>Client: Success
    Client-->>CLI: Success
    CLI->>Client: Reconnect with new tenant
    Client-->>CLI: Connection established
    CLI-->>User: Workspace switched & persisted
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

  • Multi-user workspaces #1711 — Multi-user workspaces feature that directly depends on this PR's persistent tenant state management (Get/SetCurrentTenant) for storing and retrieving workspace context across sessions.

Suggested reviewers

  • jordanstephens
  • raphaeltm
  • edwardrf

Poem

🐰 A workspace switcher's delight!
Through persistent state we store the night,
Select your tenant, swift and true,
The CLI remembers—just for you! 🌙✨

🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'feat: add workspace select command' directly and accurately describes the main feature addition in the changeset—a new workspace select command.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings

Warning

Tools execution failed with the following error:

Failed to run tools: 13 INTERNAL: Received RST_STREAM with code 2 (Internal server error)


Comment @coderabbitai help to get the list of available commands and usage tips.

@lionello lionello marked this pull request as ready for review January 23, 2026 17:02
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@src/pkg/cli/client/state.go`:
- Around line 69-72: SetCurrentTenant currently assigns to the zero-valued
package-level state and writes it, which can erase existing fields; before
mutating, read/initialize the existing state from disk (e.g., call the state
reader like state.read(statePath) or use the package getter that ensures state
is loaded), handle any read error, then set state.Tenant and call
state.write(statePath) so existing AnonID and TermsAcceptedAt are preserved;
update SetCurrentTenant to perform this load-before-write flow and propagate
errors.
🧹 Nitpick comments (1)
src/cmd/cli/command/workspace.go (1)

80-94: Remove redundant newline from log output and clarify commented annotation.

The explicit \n in line 91 is unnecessary—standard Go logging functions like Infof automatically append a newline if missing, so term.Infof("Switched to workspace %q\n", ...) will produce a double newline. Remove the \n from the format string.

Additionally, the commented-out authNeededAnnotation on line 84 should either be uncommented (if auth is required) or removed entirely (if intentionally not needed). If authentication is delegated to ConnectWithTenant on line 88, the comment should be deleted to avoid confusion.

Suggested cleanup
 var workspaceSelectCmd = &cobra.Command{
 	Use:     "select WORKSPACE",
 	Aliases: []string{"use", "switch"},
 	Args:    cobra.ExactArgs(1),
-	// Annotations: authNeededAnnotation,
 	Short: "Select a workspace to use",
 	RunE: func(cmd *cobra.Command, args []string) error {
 		global.Tenant = types.TenantNameOrID(args[0])
 		if _, err := cli.ConnectWithTenant(cmd.Context(), global.Cluster, global.Tenant); err != nil {
 			return err
 		}
-		term.Infof("Switched to workspace %q\n", global.Tenant)
+		term.Infof("Switched to workspace %q", global.Tenant)
 		return client.SetCurrentTenant(global.Tenant)
 	},
 }

Comment on lines +69 to +72
func SetCurrentTenant(tenant types.TenantNameOrID) error {
state.Tenant = tenant
return state.write(statePath)
}
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Potential data loss: SetCurrentTenant may overwrite uninitialized state.

If SetCurrentTenant is called before any getter (like GetAnonID or GetCurrentTenant), the package-level state variable will still be zero-valued. Writing it will overwrite any existing AnonID and TermsAcceptedAt in the state file.

Consider initializing the state before modifying it:

Proposed fix
 func SetCurrentTenant(tenant types.TenantNameOrID) error {
+	state = initState(statePath)
 	state.Tenant = tenant
 	return state.write(statePath)
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
func SetCurrentTenant(tenant types.TenantNameOrID) error {
state.Tenant = tenant
return state.write(statePath)
}
func SetCurrentTenant(tenant types.TenantNameOrID) error {
state = initState(statePath)
state.Tenant = tenant
return state.write(statePath)
}
🤖 Prompt for AI Agents
In `@src/pkg/cli/client/state.go` around lines 69 - 72, SetCurrentTenant currently
assigns to the zero-valued package-level state and writes it, which can erase
existing fields; before mutating, read/initialize the existing state from disk
(e.g., call the state reader like state.read(statePath) or use the package
getter that ensures state is loaded), handle any read error, then set
state.Tenant and call state.write(statePath) so existing AnonID and
TermsAcceptedAt are preserved; update SetCurrentTenant to perform this
load-before-write flow and propagate errors.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants