Skip to content

Comments

Revert "Remove RemoteProjectName"#1925

Merged
lionello merged 1 commit intomainfrom
revert-1919-jordan/remove-remote-project-name
Feb 12, 2026
Merged

Revert "Remove RemoteProjectName"#1925
lionello merged 1 commit intomainfrom
revert-1919-jordan/remove-remote-project-name

Conversation

@lionello
Copy link
Member

@lionello lionello commented Feb 12, 2026

Reverts #1919

  1. Deploy project to Playground (e.g. 1-click from portal)
  2. defang ps without add'l info should imply Playground
  3. defang ps -Pdefang should show deployed project

Step 2. was already broken in prev CLI release. Step 3. broke with #1919.

Summary by CodeRabbit

  • Refactor
    • Enhanced project name resolution logic with improved fallback mechanisms for CLI commands. Updates project name loading across multiple commands to use a more robust provider-aware resolution path, ensuring consistent behavior when project names are not explicitly provided.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 12, 2026

📝 Walkthrough

Walkthrough

This PR introduces a new LoadProjectNameWithFallback function that attempts to load a project name from a local loader first, then falls back to retrieving it from a remote provider if the local load fails. The new function is integrated across multiple CLI commands and agent tools, replacing direct LoadProjectName calls. A new RemoteProjectName method is added to the Provider interface to support the fallback mechanism.

Changes

Cohort / File(s) Summary
Core Client Library - Fallback Mechanism
src/pkg/cli/client/projectName.go, src/pkg/cli/client/projectName_test.go, src/pkg/cli/client/provider.go
New LoadProjectNameWithFallback function that tries local loader first, then falls back to provider's RemoteProjectName method. New RemoteProjectName method added to Provider interface.
BYOC Base Client
src/pkg/cli/client/byoc/baseclient.go
New RemoteProjectName method retrieves remote cloud project names via projectBackend.CdList, validates projects, and returns single project or error on multiple/none.
CLI Commands
src/cmd/cli/command/cd.go, src/cmd/cli/command/compose.go, src/cmd/cli/command/config.go
Updated to use LoadProjectNameWithFallback. In compose.go, handleTooManyProjectsError signature generalized to accept Provider interface instead of concrete PlaygroundProvider type; error handling flow adjusted to return originalErr when appropriate.
Agent Tools Interface & Core
src/pkg/agent/tools/interfaces.go, src/pkg/agent/tools/default_tool_cli.go
CLIInterface.LoadProjectName method signature renamed to LoadProjectNameWithFallback with added provider parameter. DefaultToolCLI implementation updated to delegate to new client function.
Agent Tools - Implementations
src/pkg/agent/tools/destroy.go, src/pkg/agent/tools/listConfig.go, src/pkg/agent/tools/logs.go, src/pkg/agent/tools/removeConfig.go, src/pkg/agent/tools/services.go, src/pkg/agent/tools/setConfig.go
All replaced LoadProjectName calls with LoadProjectNameWithFallback, adding provider parameter. Debug logs updated to reflect new function names.
Agent Tools - Tests
src/pkg/agent/tools/destroy_test.go, src/pkg/agent/tools/listConfig_test.go, src/pkg/agent/tools/removeConfig_test.go, src/pkg/agent/tools/services_test.go, src/pkg/agent/tools/setConfig_test.go
Mock implementations updated with new LoadProjectNameWithFallback method signature and provider parameter. Test expectations updated to match new function names.

Sequence Diagram

sequenceDiagram
    participant CLI as CLI Command
    participant LoadFB as LoadProjectNameWithFallback
    participant Loader as Local Loader
    participant Provider as Provider
    participant Remote as RemoteProjectName

    CLI->>LoadFB: LoadProjectNameWithFallback(ctx, loader, provider)
    LoadFB->>Loader: LoadProjectName(ctx)
    alt Local Load Succeeds
        Loader-->>LoadFB: projectName, nil
        LoadFB-->>CLI: projectName, nil
    else Local Load Fails
        Loader-->>LoadFB: "", error
        LoadFB->>Provider: RemoteProjectName(ctx)
        Provider->>Remote: Retrieve remote project
        alt Remote Succeeds
            Remote-->>Provider: projectName, nil
            Provider-->>LoadFB: projectName, nil
            LoadFB-->>CLI: projectName, nil
        else Remote Fails
            Remote-->>Provider: "", error
            Provider-->>LoadFB: "", error
            LoadFB-->>CLI: "", wrappedError
        end
    end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~30 minutes

Possibly related PRs

Suggested reviewers

  • jordanstephens

Poem

🐰 A loader learns to fall back gracefully,
When local paths don't work, the provider's key,
Remote lookups spring forth with a gentle flair,
Project names now found with layered care! ✨

🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 17.65% 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 accurately describes the main change: reverting a previous commit that removed RemoteProjectName functionality, which aligns with the changeset's restoration of RemoteProjectName across multiple files.

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

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch revert-1919-jordan/remove-remote-project-name

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 golangci-lint (2.5.0)

level=warning msg="[linters_context] running gomodguard failed: unable to read module file go.mod: current working directory must have a go.mod file: if you are not using go modules it is suggested to disable this linter"
level=error msg="[linters_context] typechecking error: pattern ./...: directory prefix . does not contain main module or its selected dependencies"


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

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/projectName.go`:
- Around line 11-26: LoadProjectNameWithFallback currently guards loader but not
provider, causing a possible nil dereference when loader fails and provider is
nil; after the loader block (after the term.Debug("Trying to get the remote
project name from the provider") line) add a nil check for provider and return a
wrapped error (including loadErr) if provider is nil, e.g. return "",
fmt.Errorf("%w and %w", loadErr, fmt.Errorf("provider is nil")), ensuring calls
to provider.RemoteProjectName(ctx) only occur when provider != nil.
🧹 Nitpick comments (3)
src/pkg/agent/tools/setConfig_test.go (1)

67-76: LGTM!

The mock method signature correctly implements the updated interface.

Note: The struct fields LoadProjectNameError (line 20) and LoadProjectNameCalled (line 25) weren't renamed to match the new method name (unlike MockDestroyCLI which uses LoadProjectNameWithFallbackError). This is a minor naming inconsistency that doesn't affect functionality.

Optional: Rename fields for consistency with other mocks
 type MockSetConfigCLI struct {
 	CLIInterface
 	ConnectError             error
-	LoadProjectNameError     error
+	LoadProjectNameWithFallbackError error
 	ConfigSetError           error
 	InteractiveLoginMCPError error
 	ConnectCalled            bool
 	NewProviderCalled        bool
-	LoadProjectNameCalled    bool
+	LoadProjectNameWithFallbackCalled bool

And update references in the test assertions accordingly.

src/pkg/cli/client/projectName.go (1)

23-25: Error message may include <nil> when loader is nil.

When loader is nil, loadErr remains nil, and the error message on line 24 will read "<nil> and <remote error>". Consider handling this case for cleaner error messages.

♻️ Proposed fix for cleaner error handling
 	projectName, err := provider.RemoteProjectName(ctx)
 	if err != nil {
+		if loadErr != nil {
+			return "", fmt.Errorf("%w and %w", loadErr, err)
+		}
-		return "", fmt.Errorf("%w and %w", loadErr, err)
+		return "", err
 	}
 	return projectName, nil
src/pkg/cli/client/projectName_test.go (1)

11-52: Good test coverage, consider adding edge case.

The tests cover the main scenarios well. Consider adding a test case where loader is nil to verify the function correctly falls back to the remote provider when no loader is provided.

💡 Suggested additional test case
t.Run("nil loader, with fallback", func(t *testing.T) {
	provider := mockRemoteProjectName{
		ProjectName: "remote-project",
	}
	projectName, err := LoadProjectNameWithFallback(ctx, nil, provider)
	if err != nil {
		t.Fatalf("expected no error, got %v", err)
	}
	if projectName != "remote-project" {
		t.Fatalf("expected project name 'remote-project', got %q", projectName)
	}
})

Comment on lines +11 to +26
func LoadProjectNameWithFallback(ctx context.Context, loader Loader, provider Provider) (string, error) {
var loadErr error
if loader != nil {
projectName, _, err := loader.LoadProjectName(ctx)
if err == nil {
return projectName, nil
}
term.Debug("Failed to load local project:", err)
loadErr = err
}
term.Debug("Trying to get the remote project name from the provider")
projectName, err := provider.RemoteProjectName(ctx)
if err != nil {
return "", fmt.Errorf("%w and %w", loadErr, err)
}
return projectName, nil
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 | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Search for calls to LoadProjectNameWithFallback
rg -n 'LoadProjectNameWithFallback' --type go

Repository: DefangLabs/defang

Length of output: 5526


🏁 Script executed:

#!/bin/bash
# Read the test file to see what's expected when provider is nil
cat -n src/pkg/cli/client/projectName_test.go

Repository: DefangLabs/defang

Length of output: 2258


🏁 Script executed:

#!/bin/bash
# Find the session type definition to check if Provider can be nil
rg -n 'type.*Session.*struct' --type go -A 10

Repository: DefangLabs/defang

Length of output: 1972


🏁 Script executed:

#!/bin/bash
# Read the full newCommandSessionWithOpts function to see how Session is created
sed -n '31,100p' src/cmd/cli/command/session.go

Repository: DefangLabs/defang

Length of output: 2585


🏁 Script executed:

#!/bin/bash
# Check the LoadSession method to see if Provider can be nil
rg -n 'func.*LoadSession' --type go -A 20 | head -40

Repository: DefangLabs/defang

Length of output: 2458


🏁 Script executed:

#!/bin/bash
# Double-check by looking at how Provider interface is defined
rg -n 'type Provider interface' --type go -A 10

Repository: DefangLabs/defang

Length of output: 1123


Add nil check for provider parameter to prevent panic.

The function checks if loader is nil (line 13) but doesn't check if provider is nil before calling provider.RemoteProjectName(ctx) on line 22. Although the test file explicitly passes a nil provider (when the loader succeeds and returns early), there's no test coverage for the case where both the loader fails and the provider is nil, which would cause a nil pointer dereference panic. Add a nil check after the loader block for consistency and defensive programming.

Proposed fix
 func LoadProjectNameWithFallback(ctx context.Context, loader Loader, provider Provider) (string, error) {
 	var loadErr error
 	if loader != nil {
 		projectName, _, err := loader.LoadProjectName(ctx)
 		if err == nil {
 			return projectName, nil
 		}
 		term.Debug("Failed to load local project:", err)
 		loadErr = err
 	}
+	if provider == nil {
+		return "", loadErr
+	}
 	term.Debug("Trying to get the remote project name from the provider")
 	projectName, err := provider.RemoteProjectName(ctx)
📝 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 LoadProjectNameWithFallback(ctx context.Context, loader Loader, provider Provider) (string, error) {
var loadErr error
if loader != nil {
projectName, _, err := loader.LoadProjectName(ctx)
if err == nil {
return projectName, nil
}
term.Debug("Failed to load local project:", err)
loadErr = err
}
term.Debug("Trying to get the remote project name from the provider")
projectName, err := provider.RemoteProjectName(ctx)
if err != nil {
return "", fmt.Errorf("%w and %w", loadErr, err)
}
return projectName, nil
func LoadProjectNameWithFallback(ctx context.Context, loader Loader, provider Provider) (string, error) {
var loadErr error
if loader != nil {
projectName, _, err := loader.LoadProjectName(ctx)
if err == nil {
return projectName, nil
}
term.Debug("Failed to load local project:", err)
loadErr = err
}
if provider == nil {
return "", loadErr
}
term.Debug("Trying to get the remote project name from the provider")
projectName, err := provider.RemoteProjectName(ctx)
if err != nil {
return "", fmt.Errorf("%w and %w", loadErr, err)
}
return projectName, nil
}
🤖 Prompt for AI Agents
In `@src/pkg/cli/client/projectName.go` around lines 11 - 26,
LoadProjectNameWithFallback currently guards loader but not provider, causing a
possible nil dereference when loader fails and provider is nil; after the loader
block (after the term.Debug("Trying to get the remote project name from the
provider") line) add a nil check for provider and return a wrapped error
(including loadErr) if provider is nil, e.g. return "", fmt.Errorf("%w and %w",
loadErr, fmt.Errorf("provider is nil")), ensuring calls to
provider.RemoteProjectName(ctx) only occur when provider != nil.

@lionello lionello merged commit b81eecd into main Feb 12, 2026
14 checks passed
@lionello lionello deleted the revert-1919-jordan/remove-remote-project-name branch February 12, 2026 01:12
lionello added a commit that referenced this pull request Feb 12, 2026
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.

1 participant