Skip to content

Commit

Permalink
Provide module output references
Browse files Browse the repository at this point in the history
  • Loading branch information
radeksimko committed Jul 29, 2021
1 parent 1d6a7db commit 9dbdaa6
Show file tree
Hide file tree
Showing 8 changed files with 322 additions and 12 deletions.
4 changes: 2 additions & 2 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,12 @@ require (
github.com/hashicorp/go-memdb v1.3.2
github.com/hashicorp/go-multierror v1.1.1
github.com/hashicorp/go-version v1.3.0
github.com/hashicorp/hcl-lang v0.0.0-20210727133229-454bfd2596ce
github.com/hashicorp/hcl-lang v0.0.0-20210728150846-565e9ca96f5a
github.com/hashicorp/hcl/v2 v2.10.1
github.com/hashicorp/terraform-exec v0.14.0
github.com/hashicorp/terraform-json v0.12.0
github.com/hashicorp/terraform-registry-address v0.0.0-20210412075316-9b2996cce896
github.com/hashicorp/terraform-schema v0.0.0-20210722111916-2c53a3129d11
github.com/hashicorp/terraform-schema v0.0.0-20210728151552-ade5695c845a
github.com/kylelemons/godebug v1.1.0 // indirect
github.com/mh-cbon/go-fmt-fail v0.0.0-20160815164508-67765b3fbcb5
github.com/mitchellh/cli v1.1.2
Expand Down
11 changes: 4 additions & 7 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -190,10 +190,8 @@ github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+l
github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4=
github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
github.com/hashicorp/hcl-lang v0.0.0-20210616121206-bd34ebcc883b/go.mod h1:uMsq6wV8ZXEH8qndov4tncXlHDYnZ8aHsGmS4T74e2o=
github.com/hashicorp/hcl-lang v0.0.0-20210727133229-454bfd2596ce h1:XekCZzsJL95UGIMEWHBdPjGSPpi8uxU91zRghDbRgTc=
github.com/hashicorp/hcl-lang v0.0.0-20210727133229-454bfd2596ce/go.mod h1:xzXU6Fn+TWVaZUFxV8CyAsObi2oMgSEFAmLvCx2ArzM=
github.com/hashicorp/hcl/v2 v2.10.0/go.mod h1:FwWsfWEjyV/CMj8s/gqAuiviY72rJ1/oayI9WftqcKg=
github.com/hashicorp/hcl-lang v0.0.0-20210728150846-565e9ca96f5a h1:/4iJtfKKXrHCi99FQgUeHvF6OBNUzJeVO7Tsmfj8F1s=
github.com/hashicorp/hcl-lang v0.0.0-20210728150846-565e9ca96f5a/go.mod h1:xzXU6Fn+TWVaZUFxV8CyAsObi2oMgSEFAmLvCx2ArzM=
github.com/hashicorp/hcl/v2 v2.10.1 h1:h4Xx4fsrRE26ohAk/1iGF/JBqRQbyUqu5Lvj60U54ys=
github.com/hashicorp/hcl/v2 v2.10.1/go.mod h1:FwWsfWEjyV/CMj8s/gqAuiviY72rJ1/oayI9WftqcKg=
github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64=
Expand All @@ -206,8 +204,8 @@ github.com/hashicorp/terraform-json v0.12.0 h1:8czPgEEWWPROStjkWPUnTQDXmpmZPlkQA
github.com/hashicorp/terraform-json v0.12.0/go.mod h1:pmbq9o4EuL43db5+0ogX10Yofv1nozM+wskr/bGFJpI=
github.com/hashicorp/terraform-registry-address v0.0.0-20210412075316-9b2996cce896 h1:1FGtlkJw87UsTMg5s8jrekrHmUPUJaMcu6ELiVhQrNw=
github.com/hashicorp/terraform-registry-address v0.0.0-20210412075316-9b2996cce896/go.mod h1:bzBPnUIkI0RxauU8Dqo+2KrZZ28Cf48s8V6IHt3p4co=
github.com/hashicorp/terraform-schema v0.0.0-20210722111916-2c53a3129d11 h1:AmgdvpxCaq1rb90drpXqOafdPSR4084bOBtDthYrd7Y=
github.com/hashicorp/terraform-schema v0.0.0-20210722111916-2c53a3129d11/go.mod h1:2rBfUJC+1kyVzt5R/6pRa+d9HbpZrf8sMjQZdh8rSCM=
github.com/hashicorp/terraform-schema v0.0.0-20210728151552-ade5695c845a h1:IZ1T0OvyLXM5+VYaMYhOrbCb8qS2ASoDlPfsbx8c64M=
github.com/hashicorp/terraform-schema v0.0.0-20210728151552-ade5695c845a/go.mod h1:laZKK46fUcgutOVcEOx7lY0POxOEFxLZCD+eaUvGIc8=
github.com/hashicorp/terraform-svchost v0.0.0-20200729002733-f050f53b9734 h1:HKLsbzeOsfXmKNpr3GiT18XAblV0BjCbzL8KQAMZGa0=
github.com/hashicorp/terraform-svchost v0.0.0-20200729002733-f050f53b9734/go.mod h1:kNDNcF7sN4DocDLBkQYz73HGKwN1ANB1blq4lIYLYvg=
github.com/huandu/xstrings v1.3.2 h1:L18LIDzqlW6xN2rEkpdV8+oL/IXWJ1APd+vsdYy4Wdw=
Expand Down Expand Up @@ -382,7 +380,6 @@ github.com/zclconf/go-cty v1.1.0/go.mod h1:xnAOWiHeOqg2nWS62VtQ7pbOu17FtxJNW8RLE
github.com/zclconf/go-cty v1.2.0/go.mod h1:hOPWgoHbaTUnI5k4D2ld+GRpFJSCe6bCM7m1q/N4PQ8=
github.com/zclconf/go-cty v1.2.1/go.mod h1:hOPWgoHbaTUnI5k4D2ld+GRpFJSCe6bCM7m1q/N4PQ8=
github.com/zclconf/go-cty v1.8.0/go.mod h1:vVKLxnk3puL4qRAv72AO+W99LUD4da90g3uUAzyuvAk=
github.com/zclconf/go-cty v1.8.3/go.mod h1:vVKLxnk3puL4qRAv72AO+W99LUD4da90g3uUAzyuvAk=
github.com/zclconf/go-cty v1.8.4/go.mod h1:vVKLxnk3puL4qRAv72AO+W99LUD4da90g3uUAzyuvAk=
github.com/zclconf/go-cty v1.9.0 h1:IgJxw5b4LPXCPeqFjjhLaNEA8NKXMyaEUdAd399acts=
github.com/zclconf/go-cty v1.9.0/go.mod h1:vVKLxnk3puL4qRAv72AO+W99LUD4da90g3uUAzyuvAk=
Expand Down
4 changes: 2 additions & 2 deletions internal/langserver/handlers/code_lens.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,12 @@ func (h *logHandler) TextDocumentCodeLens(ctx context.Context, params lsp.CodeLe
return list, err
}

list = append(list, referenceCountCodeLens(ctx, file)...)
list = append(list, h.referenceCountCodeLens(ctx, file)...)

return list, nil
}

func referenceCountCodeLens(ctx context.Context, doc filesystem.Document) []lsp.CodeLens {
func (h *logHandler) referenceCountCodeLens(ctx context.Context, doc filesystem.Document) []lsp.CodeLens {
list := make([]lsp.CodeLens, 0)

cc, err := lsctx.ClientCapabilities(ctx)
Expand Down
269 changes: 269 additions & 0 deletions internal/langserver/handlers/complete_test.go
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
package handlers

import (
"context"
"encoding/json"
"fmt"
"os"
"path/filepath"
"testing"

"github.com/hashicorp/go-version"
"github.com/hashicorp/terraform-exec/tfinstall"
tfjson "github.com/hashicorp/terraform-json"
"github.com/hashicorp/terraform-ls/internal/langserver"
"github.com/hashicorp/terraform-ls/internal/langserver/session"
Expand Down Expand Up @@ -595,3 +599,268 @@ func TestVarsCompletion_withValidData(t *testing.T) {
}
}`)
}

func TestCompletion_moduleWithValidData(t *testing.T) {
tmpDir := TempDir(t)

writeContentToFile(t, filepath.Join(tmpDir.Dir(), "submodule", "main.tf"), `variable "testvar" {
type = string
}
output "testout" {
value = 42
}
`)
mainCfg := `module "refname" {
source = "./submodule"
}
output "test" {
}
`
writeContentToFile(t, filepath.Join(tmpDir.Dir(), "main.tf"), mainCfg)
mainCfg = `module "refname" {
source = "./submodule"
}
output "test" {
value = module.refname.
}
`

tfExec := tfExecutor(t, tmpDir.Dir(), "1.0.2")
err := tfExec.Get(context.Background())
if err != nil {
t.Fatal(err)
}

var testSchema tfjson.ProviderSchemas
err = json.Unmarshal([]byte(testModuleSchemaOutput), &testSchema)
if err != nil {
t.Fatal(err)
}

ls := langserver.NewLangServerMock(t, NewMockSession(&MockSessionInput{
TerraformCalls: &exec.TerraformMockCalls{
PerWorkDir: map[string][]*mock.Call{
tmpDir.Dir(): {
{
Method: "Version",
Repeatability: 1,
Arguments: []interface{}{
mock.AnythingOfType(""),
},
ReturnArguments: []interface{}{
version.Must(version.NewVersion("0.12.0")),
nil,
nil,
},
},
{
Method: "GetExecPath",
Repeatability: 1,
ReturnArguments: []interface{}{
"",
},
},
{
Method: "ProviderSchemas",
Repeatability: 1,
Arguments: []interface{}{
mock.AnythingOfType(""),
},
ReturnArguments: []interface{}{
&testSchema,
nil,
},
},
},
},
}}))
stop := ls.Start(t)
defer stop()

ls.Call(t, &langserver.CallRequest{
Method: "initialize",
ReqParams: fmt.Sprintf(`{
"capabilities": {},
"rootUri": %q,
"processId": 12345
}`, tmpDir.URI())})
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": %q,
"uri": "%s/main.tf"
}
}`, mainCfg, tmpDir.URI())})

ls.CallAndExpectResponse(t, &langserver.CallRequest{
Method: "textDocument/completion",
ReqParams: fmt.Sprintf(`{
"textDocument": {
"uri": "%s/main.tf"
},
"position": {
"character": 0,
"line": 2
}
}`, tmpDir.URI())}, `{
"jsonrpc": "2.0",
"id": 3,
"result": {
"isIncomplete": false,
"items": [
{
"label": "providers",
"kind": 10,
"detail": "optional, map of provider references",
"documentation": "Explicit mapping of providers which the module uses",
"insertTextFormat": 1,
"textEdit": {
"range": {
"start": {
"line": 2,
"character": 0
},
"end": {
"line": 2,
"character": 0
}
},
"newText": "providers"
}
},
{
"label": "testvar",
"kind": 10,
"detail": "required, string",
"insertTextFormat": 1,
"textEdit": {
"range": {
"start": {
"line": 2,
"character": 0
},
"end": {
"line": 2,
"character": 0
}
},
"newText": "testvar"
}
},
{
"label": "version",
"kind": 10,
"detail": "optional, string",
"documentation": "Constraint to set the version of the module, e.g. ~\u003e 1.0. Only applicable to modules in a module registry.",
"insertTextFormat": 1,
"textEdit": {
"range": {
"start": {
"line": 2,
"character": 0
},
"end": {
"line": 2,
"character": 0
}
},
"newText": "version"
}
}
]
}
}`)

ls.CallAndExpectResponse(t, &langserver.CallRequest{
Method: "textDocument/completion",
ReqParams: fmt.Sprintf(`{
"textDocument": {
"uri": "%s/main.tf"
},
"position": {
"character": 25,
"line": 6
}
}`, tmpDir.URI())}, `{
"jsonrpc": "2.0",
"id": 4,
"result": {
"isIncomplete": false,
"items": [
{
"label": "module.refname.testout",
"kind": 6,
"detail": "number",
"insertTextFormat": 1,
"textEdit": {
"range": {
"start": {
"line": 6,
"character": 10
},
"end": {
"line": 6,
"character": 25
}
},
"newText": "module.refname.testout"
}
}
]
}
}`)
}

func tfExecutor(t *testing.T, workdir, version string) exec.TerraformExecutor {
ctx := context.Background()
installPath := filepath.Join(t.TempDir(), "tfinstall")
err := os.MkdirAll(installPath, 0o755)
if err != nil {
t.Fatal(err)
}
execPath, err := tfinstall.Find(ctx, tfinstall.ExactVersion(version, installPath))
if err != nil {
t.Fatal(err)
}

tfExec, err := exec.NewExecutor(workdir, execPath)
if err != nil {
t.Fatal(err)
}
return tfExec
}

func writeContentToFile(t *testing.T, path string, content string) {
err := os.MkdirAll(filepath.Dir(path), 0o755)
if err != nil {
t.Fatal(err)
}

f, err := os.Create(path)
if err != nil {
t.Fatal(err)
}

_, err = f.WriteString(content)
if err != nil {
t.Fatal(err)
}

err = f.Close()
if err != nil {
t.Fatal(err)
}
}
11 changes: 11 additions & 0 deletions internal/state/module.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ type ModuleMetadata struct {
ProviderReferences map[tfmod.ProviderRef]tfaddr.Provider
ProviderRequirements map[tfaddr.Provider]version.Constraints
Variables map[string]tfmod.Variable
Outputs map[string]tfmod.Output
}

func (mm ModuleMetadata) Copy() ModuleMetadata {
Expand Down Expand Up @@ -49,6 +50,13 @@ func (mm ModuleMetadata) Copy() ModuleMetadata {
}
}

if mm.Outputs != nil {
newMm.Outputs = make(map[string]tfmod.Output, len(mm.Outputs))
for name, output := range mm.Outputs {
newMm.Outputs[name] = output
}
}

return newMm
}

Expand Down Expand Up @@ -259,6 +267,7 @@ func (s *ModuleStore) ModuleCalls(modPath string) ([]tfmod.ModuleCall, error) {
continue
}
result = append(result, tfmod.ModuleCall{
LocalName: record.Key,
SourceAddr: record.SourceAddr,
Path: filepath.Join(modPath, record.Dir),
})
Expand All @@ -279,6 +288,7 @@ func (s *ModuleStore) ModuleMeta(modPath string) (*tfmod.Meta, error) {
ProviderRequirements: mod.Meta.ProviderRequirements,
CoreRequirements: mod.Meta.CoreRequirements,
Variables: mod.Meta.Variables,
Outputs: mod.Meta.Outputs,
}, nil
}

Expand Down Expand Up @@ -579,6 +589,7 @@ func (s *ModuleStore) UpdateMetadata(path string, meta *tfmod.Meta, mErr error)
ProviderReferences: meta.ProviderReferences,
ProviderRequirements: meta.ProviderRequirements,
Variables: meta.Variables,
Outputs: meta.Outputs,
}
mod.MetaErr = mErr

Expand Down
Loading

0 comments on commit 9dbdaa6

Please sign in to comment.