-
Notifications
You must be signed in to change notification settings - Fork 131
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
4b7771b
commit 1e4f20a
Showing
7 changed files
with
271 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
# Commands | ||
|
||
The server exposes the following executable commands via LSP to clients. | ||
Typically these commands are not invokable by end-users automatically. | ||
Instead this serves as a documentation for client maintainers, | ||
and clients may expose these e.g. via command palette where appropriate. | ||
|
||
Every care is taken to avoid breaking changes, but these interfaces | ||
should not be considered stable yet and may change. | ||
|
||
Either way clients should always follow LSP spec in the sense | ||
that they check whether a command is actually supported or not | ||
(via `ServerCapabilities.executeCommandProvider.commands`). | ||
|
||
## `terraform.init` | ||
|
||
TODO - inputs, output, description | ||
|
||
## `terraform.validate` | ||
|
||
TODO - inputs, output, description | ||
|
||
## `module.callers` | ||
|
||
TODO - inputs, output, description | ||
|
||
## `rootmodules` (DEPRECATED, use `module.callers` instead) | ||
|
||
TODO - inputs, output, description |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
package command | ||
|
||
import ( | ||
"context" | ||
"fmt" | ||
"sort" | ||
|
||
"github.com/creachadair/jrpc2/code" | ||
lsctx "github.com/hashicorp/terraform-ls/internal/context" | ||
"github.com/hashicorp/terraform-ls/internal/langserver/cmd" | ||
"github.com/hashicorp/terraform-ls/internal/uri" | ||
) | ||
|
||
const moduleCallersVersion = 0 | ||
|
||
type moduleCallersResponse struct { | ||
FormatVersion int `json:"v"` | ||
Callers []moduleCaller `json:"callers"` | ||
} | ||
|
||
type moduleCaller struct { | ||
URI string `json:"uri"` | ||
Name string `json:"name"` | ||
} | ||
|
||
func ModuleCallersHandler(ctx context.Context, args cmd.CommandArgs) (interface{}, error) { | ||
modUri, ok := args.GetString("uri") | ||
if !ok || modUri == "" { | ||
return nil, fmt.Errorf("%w: expected uri argument to be set", code.InvalidParams.Err()) | ||
} | ||
|
||
modPath, err := uri.PathFromURI(modUri) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
mf, err := lsctx.ModuleFinder(ctx) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
modCallers, err := mf.CallersOfModule(modPath) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
callers := make([]moduleCaller, 0) | ||
for _, caller := range modCallers { | ||
callers = append(callers, moduleCaller{ | ||
URI: uri.FromPath(caller.Path), | ||
Name: humanReadablePath(modPath, caller.Path), | ||
}) | ||
} | ||
sort.SliceStable(callers, func(i, j int) bool { | ||
return callers[i].URI < callers[j].URI | ||
}) | ||
return moduleCallersResponse{ | ||
FormatVersion: moduleCallersVersion, | ||
Callers: callers, | ||
}, nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
164 changes: 164 additions & 0 deletions
164
internal/langserver/handlers/execute_command_module_callers_test.go
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,164 @@ | ||
package handlers | ||
|
||
import ( | ||
"fmt" | ||
"os" | ||
"path/filepath" | ||
"testing" | ||
|
||
"github.com/creachadair/jrpc2/code" | ||
"github.com/hashicorp/terraform-ls/internal/langserver" | ||
"github.com/hashicorp/terraform-ls/internal/langserver/cmd" | ||
"github.com/hashicorp/terraform-ls/internal/terraform/exec" | ||
"github.com/hashicorp/terraform-ls/internal/uri" | ||
"github.com/stretchr/testify/mock" | ||
) | ||
|
||
func TestLangServer_workspaceExecuteCommand_moduleCallers_argumentError(t *testing.T) { | ||
rootDir := t.TempDir() | ||
rootUri := uri.FromPath(rootDir) | ||
|
||
ls := langserver.NewLangServerMock(t, NewMockSession(&MockSessionInput{ | ||
TerraformCalls: &exec.TerraformMockCalls{ | ||
PerWorkDir: map[string][]*mock.Call{ | ||
rootDir: validTfMockCalls(), | ||
}, | ||
}, | ||
})) | ||
stop := ls.Start(t) | ||
defer stop() | ||
|
||
ls.Call(t, &langserver.CallRequest{ | ||
Method: "initialize", | ||
ReqParams: fmt.Sprintf(`{ | ||
"capabilities": {}, | ||
"rootUri": %q, | ||
"processId": 12345 | ||
}`, rootUri)}) | ||
ls.Notify(t, &langserver.CallRequest{ | ||
Method: "initialized", | ||
ReqParams: "{}", | ||
}) | ||
ls.Call(t, &langserver.CallRequest{ | ||
Method: "textDocument/didOpen", | ||
ReqParams: fmt.Sprintf(`{ | ||
"textDocument": { | ||
"version": 0, | ||
"languageId": "terraform", | ||
"text": "provider \"github\" {}", | ||
"uri": %q | ||
} | ||
}`, fmt.Sprintf("%s/main.tf", rootUri))}) | ||
|
||
ls.CallAndExpectError(t, &langserver.CallRequest{ | ||
Method: "workspace/executeCommand", | ||
ReqParams: fmt.Sprintf(`{ | ||
"command": %q | ||
}`, cmd.Name("module.callers"))}, code.InvalidParams.Err()) | ||
} | ||
|
||
func TestLangServer_workspaceExecuteCommand_moduleCallers_basic(t *testing.T) { | ||
rootDir := t.TempDir() | ||
rootUri := uri.FromPath(rootDir) | ||
baseDirUri := uri.FromPath(filepath.Join(rootDir, "base")) | ||
|
||
createModuleCalling(t, "../base", filepath.Join(rootDir, "dev")) | ||
createModuleCalling(t, "../base", filepath.Join(rootDir, "staging")) | ||
createModuleCalling(t, "../base", filepath.Join(rootDir, "prod")) | ||
|
||
ls := langserver.NewLangServerMock(t, NewMockSession(&MockSessionInput{ | ||
TerraformCalls: &exec.TerraformMockCalls{ | ||
PerWorkDir: map[string][]*mock.Call{ | ||
rootDir: validTfMockCalls(), | ||
}, | ||
}, | ||
})) | ||
stop := ls.Start(t) | ||
defer stop() | ||
|
||
ls.Call(t, &langserver.CallRequest{ | ||
Method: "initialize", | ||
ReqParams: fmt.Sprintf(`{ | ||
"capabilities": {}, | ||
"rootUri": %q, | ||
"processId": 12345 | ||
}`, rootUri)}) | ||
ls.Notify(t, &langserver.CallRequest{ | ||
Method: "initialized", | ||
ReqParams: "{}", | ||
}) | ||
ls.Call(t, &langserver.CallRequest{ | ||
Method: "textDocument/didOpen", | ||
ReqParams: fmt.Sprintf(`{ | ||
"textDocument": { | ||
"version": 0, | ||
"languageId": "terraform", | ||
"text": "provider \"github\" {}", | ||
"uri": %q | ||
} | ||
}`, fmt.Sprintf("%s/main.tf", baseDirUri))}) | ||
|
||
ls.CallAndExpectResponse(t, &langserver.CallRequest{ | ||
Method: "workspace/executeCommand", | ||
ReqParams: fmt.Sprintf(`{ | ||
"command": %q, | ||
"arguments": ["uri=%s"] | ||
}`, cmd.Name("module.callers"), baseDirUri)}, fmt.Sprintf(`{ | ||
"jsonrpc": "2.0", | ||
"id": 3, | ||
"result": { | ||
"v": 0, | ||
"callers": [ | ||
{ | ||
"uri": "%s/dev", | ||
"name": "../dev" | ||
}, | ||
{ | ||
"uri": "%s/prod", | ||
"name": "../prod" | ||
}, | ||
{ | ||
"uri": "%s/staging", | ||
"name": "../staging" | ||
} | ||
] | ||
} | ||
}`, rootUri, rootUri, rootUri)) | ||
} | ||
|
||
func createModuleCalling(t *testing.T, src, modPath string) { | ||
modulesDir := filepath.Join(modPath, ".terraform", "modules") | ||
err := os.MkdirAll(modulesDir, 0755) | ||
if err != nil { | ||
t.Fatal(err) | ||
} | ||
|
||
configBytes := []byte(fmt.Sprintf(` | ||
module "local" { | ||
source = %q | ||
} | ||
`, src)) | ||
err = os.WriteFile(filepath.Join(modPath, "module.tf"), configBytes, 0755) | ||
if err != nil { | ||
t.Fatal(err) | ||
} | ||
|
||
manifestBytes := []byte(fmt.Sprintf(`{ | ||
"Modules": [ | ||
{ | ||
"Key": "", | ||
"Source": "", | ||
"Dir": "." | ||
}, | ||
{ | ||
"Key": "local", | ||
"Source": %q, | ||
"Dir": %q | ||
} | ||
] | ||
}`, src, src)) | ||
err = os.WriteFile(filepath.Join(modulesDir, "modules.json"), manifestBytes, 0755) | ||
if err != nil { | ||
t.Fatal(err) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters