Skip to content

Commit

Permalink
feat(values): reload values files on changes
Browse files Browse the repository at this point in the history
  • Loading branch information
qvalentin committed Feb 3, 2024
1 parent 46c5f65 commit 0a96b2b
Show file tree
Hide file tree
Showing 8 changed files with 155 additions and 15 deletions.
20 changes: 18 additions & 2 deletions internal/charts/chart_store.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package charts

import (
"path/filepath"

"github.com/mrjosh/helm-ls/internal/util"
"go.lsp.dev/uri"
)
Expand Down Expand Up @@ -29,8 +31,8 @@ func (s *ChartStore) SetValuesFilesConfig(valuesFilesConfig util.ValuesFilesConf
return
}
s.valuesFilesConfig = valuesFilesConfig
for _, chart := range s.Charts {
chart.ValuesFiles = NewValuesFiles(chart.RootURI, valuesFilesConfig.MainValuesFileName, valuesFilesConfig.LintOverlayValuesFileName, valuesFilesConfig.AdditionalValuesFilesGlobPattern)
for uri := range s.Charts {
s.Charts[uri] = s.newChart(uri, valuesFilesConfig)
}
}

Expand All @@ -54,3 +56,17 @@ func (s *ChartStore) GetChartForURI(fileURI uri.URI) (*Chart, error) {
URI: fileURI,
}
}

func (s *ChartStore) ReloadValuesFile(file uri.URI) {
logger.Println("Reloading values file", file)
chart, err := s.GetChartForURI(uri.URI(util.FileURIScheme + filepath.Dir(file.Filename())))
if err != nil {
logger.Error("Error reloading values file", file, err)
return
}
for _, valuesFile := range chart.ValuesFiles.AllValuesFiles() {
if valuesFile.URI == file {
valuesFile.Reload()
}
}
}
33 changes: 31 additions & 2 deletions internal/charts/chart_store_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"github.com/mrjosh/helm-ls/pkg/chartutil"
"github.com/stretchr/testify/assert"
"go.lsp.dev/uri"
"gopkg.in/yaml.v3"
)

func TestSetValuesFilesConfigOverwrites(t *testing.T) {
Expand All @@ -26,10 +27,13 @@ func TestSetValuesFilesConfigOverwrites(t *testing.T) {
_ = os.WriteFile(filepath.Join(tempDir, "values.other.yaml"), []byte(valuesContent), 0o644)
s := NewChartStore(uri.New(util.FileURIScheme+tempDir), NewChart)

chart, err := s.GetChartForURI(uri.New(util.FileURIScheme + tempDir))
assert.Equal(t, chartutil.Values{}, chart.ValuesFiles.MainValuesFile.Values)
chartOld, err := s.GetChartForURI(uri.New(util.FileURIScheme + tempDir))
assert.Equal(t, chartutil.Values{}, chartOld.ValuesFiles.MainValuesFile.Values)

s.SetValuesFilesConfig(valuesFilesConfig)
chart, err := s.GetChartForURI(uri.New(util.FileURIScheme + tempDir))
assert.NoError(t, err)
assert.NotSame(t, chartOld, chart)
assert.NoError(t, err)
assert.NotEqual(t, chartutil.Values{}, chart.ValuesFiles.MainValuesFile.Values)
assert.Equal(t, valuesFilesConfig.MainValuesFileName, filepath.Base(chart.ValuesFiles.MainValuesFile.URI.Filename()))
Expand Down Expand Up @@ -73,3 +77,28 @@ func TestGetChartForURIWhenChartYamlDoesNotExist(t *testing.T) {
assert.Error(t, err)
assert.Nil(t, chart)
}

func TestReloadValuesFiles(t *testing.T) {
tempDir := t.TempDir()
chart := &Chart{
ValuesFiles: &ValuesFiles{MainValuesFile: &ValuesFile{
Values: map[string]interface{}{"foo": "bar"},
ValueNode: yaml.Node{},
URI: uri.New(util.FileURIScheme + filepath.Join(tempDir, "values.yaml")),
}, OverlayValuesFile: &ValuesFile{}, AdditionalValuesFiles: []*ValuesFile{}},
ChartMetadata: &ChartMetadata{},
RootURI: uri.New("file://" + tempDir),
ParentChart: ParentChart{},
}
s := NewChartStore(uri.New(util.FileURIScheme+tempDir), NewChart)
s.Charts[chart.RootURI] = chart

assert.Equal(t, "bar", chart.ValuesFiles.MainValuesFile.Values["foo"])
os.WriteFile(filepath.Join(tempDir, "values.yaml"), []byte("foo: new"), 0o644)

s.ReloadValuesFile(uri.New(util.FileURIScheme + filepath.Join(tempDir, "values.yaml")))
assert.Equal(t, "new", chart.ValuesFiles.MainValuesFile.Values["foo"])

s.ReloadValuesFile(uri.New(util.FileURIScheme + filepath.Join(tempDir, "notfound.yaml")))
s.ReloadValuesFile(uri.New(util.FileURIScheme + "/notFound.yaml"))
}
24 changes: 18 additions & 6 deletions internal/charts/values_file.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,24 @@ type ValuesFile struct {
}

func NewValuesFile(filePath string) *ValuesFile {
vals, valueNodes := readInValuesFile(filePath)

return &ValuesFile{
ValueNode: valueNodes,
Values: vals,
URI: uri.New(util.FileURIScheme + filePath),
}
}

func (v *ValuesFile) Reload() {
vals, valueNodes := readInValuesFile(v.URI.Filename())

logger.Debug("Reloading values file", v.URI.Filename(), vals)
v.Values = vals
v.ValueNode = valueNodes
}

func readInValuesFile(filePath string) (chartutil.Values, yaml.Node) {
vals, err := chartutil.ReadValuesFile(filePath)
if err != nil {
logger.Error("Error loading values file ", filePath, err)
Expand All @@ -25,10 +42,5 @@ func NewValuesFile(filePath string) *ValuesFile {
if err != nil {
logger.Error("Error loading values file ", filePath, err)
}

return &ValuesFile{
ValueNode: valueNodes,
Values: vals,
URI: uri.New(util.FileURIScheme + filePath),
}
return vals, valueNodes
}
15 changes: 15 additions & 0 deletions internal/charts/values_file_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,3 +30,18 @@ func TestNewValuesFileFileNotFound(t *testing.T) {
assert.Equal(t, chartutil.Values{}, valuesFile.Values)
assert.Equal(t, yaml.Node{}, valuesFile.ValueNode)
}

func TestReload(t *testing.T) {
tempDir := t.TempDir()
valuesContent := `foo: bar`
_ = os.WriteFile(filepath.Join(tempDir, "values.yaml"), []byte(valuesContent), 0o644)
valuesFile := charts.NewValuesFile(filepath.Join(tempDir, "values.yaml"))

assert.Equal(t, "bar", valuesFile.Values["foo"])
assert.NotEqual(t, yaml.Node{}, valuesFile.ValueNode)

_ = os.WriteFile(filepath.Join(tempDir, "values.yaml"), []byte("foo: baz"), 0o644)
valuesFile.Reload()
assert.Equal(t, "baz", valuesFile.Values["foo"])
assert.NotEqual(t, yaml.Node{}, valuesFile.ValueNode)
}
5 changes: 2 additions & 3 deletions internal/charts/values_files.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,8 @@ type ValuesFiles struct {

func NewValuesFiles(rootURI uri.URI, mainValuesFileName string, lintOverlayValuesFile string, additionalValuesFilesGlob string) *ValuesFiles {
additionalValuesFiles := getAdditionalValuesFiles(additionalValuesFilesGlob, rootURI, mainValuesFileName)
var overlayValuesFile *ValuesFile

overlayValuesFile = getLintOverlayValuesFile(lintOverlayValuesFile, additionalValuesFiles, overlayValuesFile, rootURI)
overlayValuesFile := getLintOverlayValuesFile(lintOverlayValuesFile, additionalValuesFiles, rootURI)

return &ValuesFiles{
MainValuesFile: NewValuesFile(filepath.Join(rootURI.Filename(), mainValuesFileName)),
Expand All @@ -28,7 +27,7 @@ func NewValuesFiles(rootURI uri.URI, mainValuesFileName string, lintOverlayValue
}
}

func getLintOverlayValuesFile(lintOverlayValuesFile string, additionalValuesFiles []*ValuesFile, overlayValuesFile *ValuesFile, rootURI uri.URI) *ValuesFile {
func getLintOverlayValuesFile(lintOverlayValuesFile string, additionalValuesFiles []*ValuesFile, rootURI uri.URI) (overlayValuesFile *ValuesFile) {
if lintOverlayValuesFile == "" && len(additionalValuesFiles) == 1 {
overlayValuesFile = additionalValuesFiles[0]
}
Expand Down
3 changes: 2 additions & 1 deletion internal/handler/handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,8 @@ func (h *langHandler) handle(ctx context.Context, reply jsonrpc2.Replier, req js
return h.handleHover(ctx, reply, req)
case lsp.MethodWorkspaceDidChangeConfiguration:
return h.handleWorkspaceDidChangeConfiguration(ctx, reply, req)
case lsp.MethodWorkspaceDidChangeWatchedFiles:
return h.handleDidChangeWatchedFiles(ctx, reply, req)
default:
logger.Debug("Unsupported method", req.Method())
}
Expand All @@ -80,7 +82,6 @@ func (h *langHandler) handleShutdown(_ context.Context, _ jsonrpc2.Replier, _ js
}

func (h *langHandler) handleTextDocumentDidOpen(ctx context.Context, reply jsonrpc2.Replier, req jsonrpc2.Request) (err error) {

var params lsp.DidOpenTextDocumentParams
if err := json.Unmarshal(req.Params(), &params); err != nil {
return reply(ctx, nil, err)
Expand Down
2 changes: 1 addition & 1 deletion internal/handler/initialization.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ func (h *langHandler) handleInitialize(ctx context.Context, reply jsonrpc2.Repli
}
h.yamllsConnector.CallInitialize(workspaceURI)

h.chartStore = charts.NewChartStore(workspaceURI, charts.NewChart)
h.chartStore = charts.NewChartStore(workspaceURI, h.NewChartWithWatchedFiles)

return reply(ctx, lsp.InitializeResult{
Capabilities: lsp.ServerCapabilities{
Expand Down
68 changes: 68 additions & 0 deletions internal/handler/watched_files.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
package handler

import (
"context"
"encoding/json"

"github.com/mrjosh/helm-ls/internal/charts"
"github.com/mrjosh/helm-ls/internal/util"
lsp "go.lsp.dev/protocol"
"go.lsp.dev/uri"

"go.lsp.dev/jsonrpc2"
)

func (h *langHandler) NewChartWithWatchedFiles(rootURI uri.URI, valuesFilesConfig util.ValuesFilesConfig) *charts.Chart {
logger.Debug("NewChartWithWatchedFiles", rootURI, valuesFilesConfig)
chart := charts.NewChart(rootURI, valuesFilesConfig)

uris := make([]uri.URI, 0)
for _, valuesFile := range chart.ValuesFiles.AllValuesFiles() {
uris = append(uris, valuesFile.URI)
}

go h.RegisterWatchedFiles(context.Background(), h.connPool, uris)
return chart
}

func (h *langHandler) RegisterWatchedFiles(ctx context.Context, conn jsonrpc2.Conn, files []uri.URI) {
watchers := make([]lsp.FileSystemWatcher, 0)

for _, file := range files {
watchers = append(watchers, lsp.FileSystemWatcher{
GlobPattern: file.Filename(),
})
}

var result any
_, err := conn.Call(ctx, "client/registerCapability", lsp.RegistrationParams{
Registrations: []lsp.Registration{
{
Method: "workspace/didChangeWatchedFiles",
RegisterOptions: lsp.DidChangeWatchedFilesRegistrationOptions{
Watchers: watchers,
},
},
},
}, result)
if err != nil {
logger.Error("Error registering watched files", err)
}
}

func (h *langHandler) handleDidChangeWatchedFiles(ctx context.Context, reply jsonrpc2.Replier, req jsonrpc2.Request) (err error) {
if req.Params() == nil {
return &jsonrpc2.Error{Code: jsonrpc2.InvalidParams}
}

var params lsp.DidChangeWatchedFilesParams
if err := json.Unmarshal(req.Params(), &params); err != nil {
return err
}

for _, change := range params.Changes {
h.chartStore.ReloadValuesFile(change.URI)
}

return reply(ctx, nil, nil)
}

0 comments on commit 0a96b2b

Please sign in to comment.