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
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ All notable changes to the Docker Language Server will be documented in this fil
- Compose
- textDocument/documentLink
- support recursing into anchors when searching for document links ([#329](https://github.com/docker/docker-language-server/issues/329))
- return document links for the `file` attribute of a service object's `credential_spec` ([#338](https://github.com/docker/docker-language-server/issues/338))

### Fixed

Expand Down
13 changes: 9 additions & 4 deletions internal/compose/documentLink.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,11 +60,11 @@ func stringNode(value ast.Node) *ast.StringNode {
return nil
}

func createDockerfileLink(u *url.URL, serviceNode *ast.MappingValueNode) *protocol.DocumentLink {
if serviceNode.Key.GetToken().Value == "build" {
func createdNestedLink(u *url.URL, serviceNode *ast.MappingValueNode, parent, child string) *protocol.DocumentLink {
if serviceNode.Key.GetToken().Value == parent {
if mappingNode, ok := resolveAnchor(serviceNode.Value).(*ast.MappingNode); ok {
for _, buildAttribute := range mappingNode.Values {
if buildAttribute.Key.GetToken().Value == "dockerfile" {
if buildAttribute.Key.GetToken().Value == child {
return createFileLink(u, buildAttribute)
}
}
Expand Down Expand Up @@ -157,7 +157,12 @@ func scanForLinks(u *url.URL, n *ast.MappingValueNode) []protocol.DocumentLink {
links = append(links, *link)
}

link = createDockerfileLink(u, serviceAttribute)
link = createdNestedLink(u, serviceAttribute, "build", "dockerfile")
if link != nil {
links = append(links, *link)
}

link = createdNestedLink(u, serviceAttribute, "credential_spec", "file")
if link != nil {
links = append(links, *link)
}
Expand Down
99 changes: 98 additions & 1 deletion internal/compose/documentLink_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -612,7 +612,7 @@ services:
}
}

func TestDocumentLink_ServiceDockerfileLinks(t *testing.T) {
func TestDocumentLink_ServiceBuildDockerfileLinks(t *testing.T) {
testsFolder := filepath.Join(os.TempDir(), t.Name())
composeStringURI := fmt.Sprintf("file:///%v", strings.TrimPrefix(filepath.ToSlash(filepath.Join(testsFolder, "compose.yaml")), "/"))

Expand Down Expand Up @@ -710,6 +710,103 @@ services:
}
}

func TestDocumentLink_ServiceCredentialSpecFileLinks(t *testing.T) {
testsFolder := filepath.Join(os.TempDir(), t.Name())
composeStringURI := fmt.Sprintf("file:///%v", strings.TrimPrefix(filepath.ToSlash(filepath.Join(testsFolder, "compose.yaml")), "/"))

testCases := []struct {
name string
content string
path string
linkRange protocol.Range
}{
{
name: "./credential-spec.json",
content: `
services:
test:
credential_spec:
file: ./credential-spec.json`,
path: filepath.Join(testsFolder, "credential-spec.json"),
linkRange: protocol.Range{
Start: protocol.Position{Line: 4, Character: 12},
End: protocol.Position{Line: 4, Character: 34},
},
},
{
name: `"./credential-spec.json"`,
content: `
services:
test:
credential_spec:
file: "./credential-spec.json"`,
path: filepath.Join(testsFolder, "credential-spec.json"),
linkRange: protocol.Range{
Start: protocol.Position{Line: 4, Character: 13},
End: protocol.Position{Line: 4, Character: 35},
},
},
{
name: "anchors and aliases to nothing",
content: `
secrets:
test:
credential_spec:
file: &credentialSpecFile
test2:
credential_spec:
file: *credentialSpecFile`,
},
{
name: "anchor has string content",
content: `
services:
test:
credential_spec:
file: &credentialSpecFile ./credential-spec.json
test2:
credential_spec:
file: *credentialSpecFile`,
path: filepath.Join(testsFolder, "credential-spec.json"),
linkRange: protocol.Range{
Start: protocol.Position{Line: 4, Character: 32},
End: protocol.Position{Line: 4, Character: 54},
},
},
{
name: "anchor on the credential_spec object",
content: `
services:
test:
credential_spec: &anchor
file: ./credential-spec.json`,
path: filepath.Join(testsFolder, "credential-spec.json"),
linkRange: protocol.Range{
Start: protocol.Position{Line: 4, Character: 12},
End: protocol.Position{Line: 4, Character: 34},
},
},
}

for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
mgr := document.NewDocumentManager()
doc := document.NewComposeDocument(mgr, "compose.yaml", 1, []byte(tc.content))
links, err := DocumentLink(context.Background(), composeStringURI, doc)
require.NoError(t, err)
if tc.path == "" {
require.Equal(t, []protocol.DocumentLink{}, links)
} else {
link := protocol.DocumentLink{
Range: tc.linkRange,
Target: types.CreateStringPointer(fmt.Sprintf("file:///%v", strings.TrimPrefix(filepath.ToSlash(tc.path), "/"))),
Tooltip: types.CreateStringPointer(tc.path),
}
require.Equal(t, []protocol.DocumentLink{link}, links)
}
})
}
}
func TestDocumentLink_ConfigFileLinks(t *testing.T) {
testsFolder := filepath.Join(os.TempDir(), t.Name())
composeStringURI := fmt.Sprintf("file:///%v", strings.TrimPrefix(filepath.ToSlash(filepath.Join(testsFolder, "compose.yaml")), "/"))
Expand Down
Loading