Skip to content

Commit

Permalink
test(definition): definition for dependecy charts
Browse files Browse the repository at this point in the history
  • Loading branch information
qvalentin committed May 24, 2024
1 parent 6bb2fe3 commit 56b4765
Show file tree
Hide file tree
Showing 24 changed files with 207 additions and 44 deletions.
6 changes: 4 additions & 2 deletions internal/charts/chart.go
Original file line number Diff line number Diff line change
Expand Up @@ -100,10 +100,12 @@ func (c *Chart) GetValueLocation(templateContext []string) (lsp.Location, error)

func (c *Chart) GetDependeciesTemplates() []*DependencyTemplateFile {
result := []*DependencyTemplateFile{}
if c.HelmChart == nil {
return result
}
for _, dependency := range c.HelmChart.Dependencies() {
for _, file := range dependency.Templates {
dependencyTemplate := c.NewDeDependencyTemplateFile(dependency.Name(), file)
_ = dependencyTemplate.SyncToDisk()
dependencyTemplate := c.NewDependencyTemplateFile(dependency.Name(), file)
result = append(result, dependencyTemplate)
}
}
Expand Down
2 changes: 1 addition & 1 deletion internal/charts/chart_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ func TestResolvesValuesFileOfParentByName(t *testing.T) {
}

func TestLoadsHelmChartWithDependecies(t *testing.T) {
chart := charts.NewChart(uri.File("../../testdata/dependeciesExample/"), util.ValuesFilesConfig{})
chart := charts.NewChart(uri.File("../../testdata/dependenciesExample/"), util.ValuesFilesConfig{})

dependecyTemplates := chart.GetDependeciesTemplates()
assert.Len(t, dependecyTemplates, 21)
Expand Down
31 changes: 0 additions & 31 deletions internal/charts/dependecyTemplateFile.go

This file was deleted.

20 changes: 20 additions & 0 deletions internal/charts/dependency_template_file.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package charts

import (
"path/filepath"

"helm.sh/helm/v3/pkg/chart"
)

type DependencyTemplateFile struct {
Content []byte
Path string
}

var DependencyCacheFolder = ".helm_ls_cache"

func (c *Chart) NewDependencyTemplateFile(chartName string, file *chart.File) *DependencyTemplateFile {
path := filepath.Join(c.RootURI.Filename(), "charts", DependencyCacheFolder, chartName, file.Name)

return &DependencyTemplateFile{Content: file.Data, Path: path}
}
107 changes: 107 additions & 0 deletions internal/handler/definition_chart_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
package handler

import (
"context"
"os"
"path/filepath"
"strings"
"testing"

"github.com/mrjosh/helm-ls/internal/adapter/yamlls"
"github.com/mrjosh/helm-ls/internal/charts"
lsplocal "github.com/mrjosh/helm-ls/internal/lsp"
"github.com/mrjosh/helm-ls/internal/util"
"github.com/stretchr/testify/assert"
lsp "go.lsp.dev/protocol"
"go.lsp.dev/uri"
)

var (
rootUri = uri.File("../../testdata/dependenciesExample/")
fileURI = uri.File("../../testdata/dependenciesExample/templates/deployment.yaml")
)

type testCase struct {
templateLineWithMarker string
expectedFile string
expectedStartPosition lsp.Position
expectedError error
}

func TestDefinitionChart(t *testing.T) {
testCases := []testCase{
{
`{{ include "common.na^mes.name" . }}`,
"charts/.helm_ls_cache/common/templates/_names.tpl",
lsp.Position{Line: 9, Character: 0},
nil,
},
{
`{{- include "dependeciesEx^ample.labels" . | nindent 4 }}`,
"templates/_helpers.tpl",
lsp.Position{Line: 35, Character: 0},
nil,
},
}

fileContent, err := os.ReadFile(fileURI.Filename())
if err != nil {
t.Fatal(err)
}
lines := strings.Split(string(fileContent), "\n")
for _, tC := range testCases {
t.Run("Definition on "+tC.templateLineWithMarker, func(t *testing.T) {
pos := getPosition(tC, lines)

documents := lsplocal.NewDocumentStore()

chart := charts.NewChart(rootUri, util.ValuesFilesConfig{})

chartStore := charts.NewChartStore(rootUri, charts.NewChart)
chartStore.Charts = map[uri.URI]*charts.Chart{rootUri: chart}
h := &langHandler{
chartStore: chartStore,
documents: documents,
yamllsConnector: &yamlls.Connector{},
}

h.LoadDocsOnNewChart(chart)

locations, err := h.Definition(context.TODO(), &lsp.DefinitionParams{
TextDocumentPositionParams: lsp.TextDocumentPositionParams{
TextDocument: lsp.TextDocumentIdentifier{URI: fileURI},
Position: pos,
},
})

assert.Equal(t, tC.expectedError, err)
assert.Len(t, locations, 1)
if len(locations) > 0 {
assert.Equal(t, filepath.Join(rootUri.Filename(), tC.expectedFile), locations[0].URI.Filename())
assert.Equal(t, tC.expectedStartPosition, locations[0].Range.Start)
}

for _, location := range locations {
assert.FileExists(t, location.URI.Filename())
}

os.RemoveAll(filepath.Join(rootUri.Filename(), "charts", charts.DependencyCacheFolder))
})
}
}

func getPosition(tC testCase, lines []string) lsp.Position {
col := strings.Index(tC.templateLineWithMarker, "^")
buf := strings.Replace(tC.templateLineWithMarker, "^", "", 1)
line := uint32(0)

for i, v := range lines {
if strings.Contains(v, buf) {
line = uint32(i)
col = col + strings.Index(v, buf)
break
}
}
pos := lsp.Position{Line: line, Character: uint32(col)}
return pos
}
9 changes: 2 additions & 7 deletions internal/handler/text_document.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package handler
import (
"context"
"errors"
"path/filepath"

"github.com/mrjosh/helm-ls/internal/charts"
lsplocal "github.com/mrjosh/helm-ls/internal/lsp"
Expand Down Expand Up @@ -102,15 +103,9 @@ func (h *langHandler) DidRenameFiles(ctx context.Context, params *lsp.RenameFile

func (h *langHandler) LoadDocsOnNewChart(chart *charts.Chart) {
for _, file := range chart.HelmChart.Templates {
h.documents.Store(file.Name, file.Data, h.helmlsConfig)
h.documents.Store(filepath.Join(chart.RootURI.Filename(), file.Name), file.Data, h.helmlsConfig)

Check failure on line 106 in internal/handler/text_document.go

View workflow job for this annotation

GitHub Actions / lint (1.21.5, ubuntu-latest)

Error return value of `h.documents.Store` is not checked (errcheck)
}
for _, file := range chart.GetDependeciesTemplates() {
// TODO: for dependency files we must somehow dump the file content to /tmp (make sure they are readyonly) when
// the user wants to use go-to-definition or something like this
// gopls for example uses the files in ~/go/...
// but we cant do that because we don't have such files

// logger.Println("Loading chart", dependency.ChartPath())
h.documents.Store(file.Path, file.Content, h.helmlsConfig)

Check failure on line 109 in internal/handler/text_document.go

View workflow job for this annotation

GitHub Actions / lint (1.21.5, ubuntu-latest)

Error return value of `h.documents.Store` is not checked (errcheck)
}
}
6 changes: 6 additions & 0 deletions internal/language_features/includes.go
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,9 @@ func (f *IncludesFeature) getReferenceLocations(includeName string) []lsp.Locati
for _, referenceRange := range referenceRanges {
locations = append(locations, util.RangeToLocation(doc.URI, referenceRange))
}
if len(locations) > 0 {
doc.SyncToDisk()
}
}

return locations
Expand All @@ -104,6 +107,9 @@ func (f *IncludesFeature) getDefinitionLocations(includeName string) []lsp.Locat
for _, referenceRange := range referenceRanges {
locations = append(locations, util.RangeToLocation(doc.URI, referenceRange))
}
if len(locations) > 0 {
doc.SyncToDisk()
}
}

return locations
Expand Down
13 changes: 11 additions & 2 deletions internal/lsp/document.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"path/filepath"
"strings"

"github.com/mrjosh/helm-ls/internal/charts"
"github.com/mrjosh/helm-ls/internal/util"
sitter "github.com/smacker/go-tree-sitter"
lsp "go.lsp.dev/protocol"
Expand Down Expand Up @@ -80,14 +81,22 @@ func (d *Document) getLines() []string {
return d.lines
}

func (d *Document) SyncToDisk() error {
// SyncToDisk writes the content of the document to disk if it is a dependency file.
// If it is a dependency file, it was read from a archive, so we need to write it back,
// to be able to open it in a editor when using go-to-definition or go-to-reference.
func (d *Document) SyncToDisk() {
if !d.IsDependencyFile() {
return
}
err := os.MkdirAll(filepath.Dir(d.Path), 0o755)
if err == nil {
err = os.WriteFile(d.Path, []byte(d.Content), 0o444)
}
if err != nil {
logger.Error(err.Error())
}
}

return err
func (d *Document) IsDependencyFile() bool {
return strings.Contains(d.Path, charts.DependencyCacheFolder)
}
File renamed without changes.
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -28,3 +28,4 @@ dependencies:
tags:
- bitnami-common
version: 2.x.x
- name: subchartexample
23 changes: 23 additions & 0 deletions testdata/dependenciesExample/charts/subchartexample/.helmignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# Patterns to ignore when building packages.
# This supports shell glob matching, relative path matching, and
# negation (prefixed with !). Only one pattern per line.
.DS_Store
# Common VCS dirs
.git/
.gitignore
.bzr/
.bzrignore
.hg/
.hgignore
.svn/
# Common backup files
*.swp
*.bak
*.tmp
*.orig
*~
# Various IDEs
.project
.idea/
*.tmproj
.vscode/
24 changes: 24 additions & 0 deletions testdata/dependenciesExample/charts/subchartexample/Chart.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
apiVersion: v2
name: subchartexample
description: A Helm chart for Kubernetes

# A chart can be either an 'application' or a 'library' chart.
#
# Application charts are a collection of templates that can be packaged into versioned archives
# to be deployed.
#
# Library charts provide useful utilities or functions for the chart developer. They're included as
# a dependency of application charts to inject those utilities and functions into the rendering
# pipeline. Library charts do not define any templates and therefore cannot be deployed.
type: application

# This is the chart version. This version number should be incremented each time you make changes
# to the chart and its templates, including the app version.
# Versions are expected to follow Semantic Versioning (https://semver.org/)
version: 0.1.0

# This is the version number of the application being deployed. This version number should be
# incremented each time you make changes to the application. Versions are not expected to
# follow Semantic Versioning. They should reflect the version the application is using.
# It is recommended to use it with quotes.
appVersion: "1.16.0"
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
global:
subchart: works

subchartWithoutGlobal: works
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ include "dependeciesExample.fullname" . }}
name: {{ include "common.names.name" . }}
labels:
{{- include "dependeciesExample.labels" . | nindent 4 }}
spec:
Expand Down Expand Up @@ -66,3 +66,6 @@ spec:
tolerations:
{{- toYaml . | nindent 8 }}
{{- end }}
example: {{ .Values.common.exampleValue }}
example2: {{ .Values.global }} # todo fix this: missing hover, completion etc.
example3: {{ .Values.subchartexample.subchartWithoutGlobal }} # todo fix this: missing hover, completion etc.
File renamed without changes.

0 comments on commit 56b4765

Please sign in to comment.