mirror of
https://github.com/golang/go
synced 2024-11-18 16:54:43 -07:00
internal/lsp: add an upgrade all dependencies codelens
This change adds an upgrade all dependencies codelens on the go.mod file if there are available upgrades. Updates golang/go#36501 Change-Id: I86c1ae7e7a6dc01b7f5cd7eb18e5a11d96a3acc1 Reviewed-on: https://go-review.googlesource.com/c/tools/+/221108 Run-TryBot: Rohan Challa <rohan@golang.org> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Rebecca Stambler <rstambler@golang.org>
This commit is contained in:
parent
8d77031968
commit
c4f5635f10
@ -71,7 +71,7 @@ func NewRunner(exporter packagestest.Exporter, data *tests.Data, ctx context.Con
|
|||||||
return r
|
return r
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *runner) CodeLens(t *testing.T, spn span.Span, want []protocol.CodeLens) {
|
func (r *runner) CodeLens(t *testing.T, uri span.URI, want []protocol.CodeLens) {
|
||||||
//TODO: add command line completions tests when it works
|
//TODO: add command line completions tests when it works
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,6 +2,7 @@ package lsp
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"golang.org/x/tools/internal/gocommand"
|
"golang.org/x/tools/internal/gocommand"
|
||||||
"golang.org/x/tools/internal/lsp/protocol"
|
"golang.org/x/tools/internal/lsp/protocol"
|
||||||
@ -35,15 +36,15 @@ func (s *Server) executeCommand(ctx context.Context, params *protocol.ExecuteCom
|
|||||||
return nil, errors.Errorf("expected one file URI and one dependency for call to `go get`, got %v", params.Arguments)
|
return nil, errors.Errorf("expected one file URI and one dependency for call to `go get`, got %v", params.Arguments)
|
||||||
}
|
}
|
||||||
uri := protocol.DocumentURI(params.Arguments[0].(string))
|
uri := protocol.DocumentURI(params.Arguments[0].(string))
|
||||||
|
deps := params.Arguments[1].(string)
|
||||||
snapshot, _, ok, err := s.beginFileRequest(uri, source.UnknownKind)
|
snapshot, _, ok, err := s.beginFileRequest(uri, source.UnknownKind)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
dep := params.Arguments[1].(string)
|
|
||||||
// Run "go get" on the dependency to upgrade it to the latest version.
|
// Run "go get" on the dependency to upgrade it to the latest version.
|
||||||
inv := gocommand.Invocation{
|
inv := gocommand.Invocation{
|
||||||
Verb: "get",
|
Verb: "get",
|
||||||
Args: []string{dep},
|
Args: strings.Split(deps, " "),
|
||||||
Env: snapshot.Config(ctx).Env,
|
Env: snapshot.Config(ctx).Env,
|
||||||
WorkingDir: snapshot.View().Folder().Filename(),
|
WorkingDir: snapshot.View().Folder().Filename(),
|
||||||
}
|
}
|
||||||
|
@ -96,19 +96,19 @@ func testLSP(t *testing.T, exporter packagestest.Exporter) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *runner) CodeLens(t *testing.T, spn span.Span, want []protocol.CodeLens) {
|
func (r *runner) CodeLens(t *testing.T, uri span.URI, want []protocol.CodeLens) {
|
||||||
if source.DetectLanguage("", spn.URI().Filename()) != source.Mod {
|
if source.DetectLanguage("", uri.Filename()) != source.Mod {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
v, err := r.server.session.ViewOf(spn.URI())
|
v, err := r.server.session.ViewOf(uri)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
got, err := mod.CodeLens(r.ctx, v.Snapshot(), spn.URI())
|
got, err := mod.CodeLens(r.ctx, v.Snapshot(), uri)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
if diff := tests.DiffCodeLens(spn.URI(), want, got); diff != "" {
|
if diff := tests.DiffCodeLens(uri, want, got); diff != "" {
|
||||||
t.Error(diff)
|
t.Error(diff)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,9 @@ package mod
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"golang.org/x/mod/modfile"
|
||||||
"golang.org/x/tools/internal/lsp/protocol"
|
"golang.org/x/tools/internal/lsp/protocol"
|
||||||
"golang.org/x/tools/internal/lsp/source"
|
"golang.org/x/tools/internal/lsp/source"
|
||||||
"golang.org/x/tools/internal/lsp/telemetry"
|
"golang.org/x/tools/internal/lsp/telemetry"
|
||||||
@ -32,6 +34,7 @@ func CodeLens(ctx context.Context, snapshot source.Snapshot, uri span.URI) ([]pr
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
var codelens []protocol.CodeLens
|
var codelens []protocol.CodeLens
|
||||||
|
var allUpgrades []string
|
||||||
for _, req := range f.Require {
|
for _, req := range f.Require {
|
||||||
dep := req.Mod.Path
|
dep := req.Mod.Path
|
||||||
latest, ok := upgrades[dep]
|
latest, ok := upgrades[dep]
|
||||||
@ -39,18 +42,7 @@ func CodeLens(ctx context.Context, snapshot source.Snapshot, uri span.URI) ([]pr
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
// Get the range of the require directive.
|
// Get the range of the require directive.
|
||||||
s, e := req.Syntax.Start, req.Syntax.End
|
rng, err := positionsToRange(uri, m, req.Syntax.Start, req.Syntax.End)
|
||||||
line, col, err := m.Converter.ToPosition(s.Byte)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
start := span.NewPoint(line, col, s.Byte)
|
|
||||||
line, col, err = m.Converter.ToPosition(e.Byte)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
end := span.NewPoint(line, col, e.Byte)
|
|
||||||
rng, err := m.Range(span.New(uri, start, end))
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -62,6 +54,41 @@ func CodeLens(ctx context.Context, snapshot source.Snapshot, uri span.URI) ([]pr
|
|||||||
Arguments: []interface{}{uri, dep},
|
Arguments: []interface{}{uri, dep},
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
allUpgrades = append(allUpgrades, dep)
|
||||||
|
}
|
||||||
|
// If there is at least 1 upgrade, add an "Upgrade all dependencies" to the module statement.
|
||||||
|
if module := f.Module; len(allUpgrades) > 0 && module != nil && module.Syntax != nil {
|
||||||
|
// Get the range of the module directive.
|
||||||
|
rng, err := positionsToRange(uri, m, module.Syntax.Start, module.Syntax.End)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
codelens = append(codelens, protocol.CodeLens{
|
||||||
|
Range: rng,
|
||||||
|
Command: protocol.Command{
|
||||||
|
Title: "Upgrade all dependencies",
|
||||||
|
Command: "upgrade.dependency",
|
||||||
|
Arguments: []interface{}{uri, strings.Join(append([]string{"-u"}, allUpgrades...), " ")},
|
||||||
|
},
|
||||||
|
})
|
||||||
}
|
}
|
||||||
return codelens, err
|
return codelens, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func positionsToRange(uri span.URI, m *protocol.ColumnMapper, s, e modfile.Position) (protocol.Range, error) {
|
||||||
|
line, col, err := m.Converter.ToPosition(s.Byte)
|
||||||
|
if err != nil {
|
||||||
|
return protocol.Range{}, err
|
||||||
|
}
|
||||||
|
start := span.NewPoint(line, col, s.Byte)
|
||||||
|
line, col, err = m.Converter.ToPosition(e.Byte)
|
||||||
|
if err != nil {
|
||||||
|
return protocol.Range{}, err
|
||||||
|
}
|
||||||
|
end := span.NewPoint(line, col, e.Byte)
|
||||||
|
rng, err := m.Range(span.New(uri, start, end))
|
||||||
|
if err != nil {
|
||||||
|
return protocol.Range{}, err
|
||||||
|
}
|
||||||
|
return rng, err
|
||||||
|
}
|
||||||
|
@ -83,9 +83,6 @@ func (s *Server) codeLens(ctx context.Context, params *protocol.CodeLensParams)
|
|||||||
if !ok {
|
if !ok {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if !snapshot.IsSaved(fh.Identity().URI) {
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
return mod.CodeLens(ctx, snapshot, fh.Identity().URI)
|
return mod.CodeLens(ctx, snapshot, fh.Identity().URI)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -894,7 +894,7 @@ func (r *runner) Link(t *testing.T, uri span.URI, wantLinks []tests.Link) {
|
|||||||
// This is a pure LSP feature, no source level functionality to be tested.
|
// This is a pure LSP feature, no source level functionality to be tested.
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *runner) CodeLens(t *testing.T, spn span.Span, want []protocol.CodeLens) {
|
func (r *runner) CodeLens(t *testing.T, uri span.URI, want []protocol.CodeLens) {
|
||||||
// This is a pure LSP feature, no source level functionality to be tested.
|
// This is a pure LSP feature, no source level functionality to be tested.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
module upgradedep
|
module upgradedep //@codelens("module upgradedep", "Upgrade all dependencies", "upgrade.dependency")
|
||||||
|
|
||||||
// TODO(microsoft/vscode-go#12): Another issue. //@link(`microsoft/vscode-go#12`, `https://github.com/microsoft/vscode-go/issues/12`)
|
// TODO(microsoft/vscode-go#12): Another issue. //@link(`microsoft/vscode-go#12`, `https://github.com/microsoft/vscode-go/issues/12`)
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
-- summary --
|
-- summary --
|
||||||
CodeLensCount = 1
|
CodeLensCount = 2
|
||||||
CompletionsCount = 0
|
CompletionsCount = 0
|
||||||
CompletionSnippetCount = 0
|
CompletionSnippetCount = 0
|
||||||
UnimportedCompletionsCount = 0
|
UnimportedCompletionsCount = 0
|
||||||
|
@ -43,7 +43,7 @@ const (
|
|||||||
|
|
||||||
var UpdateGolden = flag.Bool("golden", false, "Update golden files")
|
var UpdateGolden = flag.Bool("golden", false, "Update golden files")
|
||||||
|
|
||||||
type CodeLens map[span.Span][]protocol.CodeLens
|
type CodeLens map[span.URI][]protocol.CodeLens
|
||||||
type Diagnostics map[span.URI][]source.Diagnostic
|
type Diagnostics map[span.URI][]source.Diagnostic
|
||||||
type CompletionItems map[token.Pos]*source.CompletionItem
|
type CompletionItems map[token.Pos]*source.CompletionItem
|
||||||
type Completions map[span.Span][]Completion
|
type Completions map[span.Span][]Completion
|
||||||
@ -115,7 +115,7 @@ type Data struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type Tests interface {
|
type Tests interface {
|
||||||
CodeLens(*testing.T, span.Span, []protocol.CodeLens)
|
CodeLens(*testing.T, span.URI, []protocol.CodeLens)
|
||||||
Diagnostics(*testing.T, span.URI, []source.Diagnostic)
|
Diagnostics(*testing.T, span.URI, []source.Diagnostic)
|
||||||
Completion(*testing.T, span.Span, Completion, CompletionItems)
|
Completion(*testing.T, span.Span, Completion, CompletionItems)
|
||||||
CompletionSnippet(*testing.T, span.Span, CompletionSnippet, bool, CompletionItems)
|
CompletionSnippet(*testing.T, span.Span, CompletionSnippet, bool, CompletionItems)
|
||||||
@ -530,14 +530,14 @@ func Run(t *testing.T, tests Tests, data *Data) {
|
|||||||
|
|
||||||
t.Run("CodeLens", func(t *testing.T) {
|
t.Run("CodeLens", func(t *testing.T) {
|
||||||
t.Helper()
|
t.Helper()
|
||||||
for spn, want := range data.CodeLens {
|
for uri, want := range data.CodeLens {
|
||||||
// Check if we should skip this URI if the -modfile flag is not available.
|
// Check if we should skip this URI if the -modfile flag is not available.
|
||||||
if shouldSkip(data, spn.URI()) {
|
if shouldSkip(data, uri) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
t.Run(SpanName(spn), func(t *testing.T) {
|
t.Run(uriName(uri), func(t *testing.T) {
|
||||||
t.Helper()
|
t.Helper()
|
||||||
tests.CodeLens(t, spn, want)
|
tests.CodeLens(t, uri, want)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@ -767,7 +767,7 @@ func checkData(t *testing.T, data *Data) {
|
|||||||
return count
|
return count
|
||||||
}
|
}
|
||||||
|
|
||||||
countCodeLens := func(c map[span.Span][]protocol.CodeLens) (count int) {
|
countCodeLens := func(c map[span.URI][]protocol.CodeLens) (count int) {
|
||||||
for _, want := range c {
|
for _, want := range c {
|
||||||
count += len(want)
|
count += len(want)
|
||||||
}
|
}
|
||||||
@ -883,8 +883,8 @@ func (data *Data) Golden(tag string, target string, update func() ([]byte, error
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (data *Data) collectCodeLens(spn span.Span, title, cmd string) {
|
func (data *Data) collectCodeLens(spn span.Span, title, cmd string) {
|
||||||
if _, ok := data.CodeLens[spn]; !ok {
|
if _, ok := data.CodeLens[spn.URI()]; !ok {
|
||||||
data.CodeLens[spn] = []protocol.CodeLens{}
|
data.CodeLens[spn.URI()] = []protocol.CodeLens{}
|
||||||
}
|
}
|
||||||
m, err := data.Mapper(spn.URI())
|
m, err := data.Mapper(spn.URI())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -894,7 +894,7 @@ func (data *Data) collectCodeLens(spn span.Span, title, cmd string) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
data.CodeLens[spn] = append(data.CodeLens[spn], protocol.CodeLens{
|
data.CodeLens[spn.URI()] = append(data.CodeLens[spn.URI()], protocol.CodeLens{
|
||||||
Range: rng,
|
Range: rng,
|
||||||
Command: protocol.Command{
|
Command: protocol.Command{
|
||||||
Title: title,
|
Title: title,
|
||||||
|
@ -197,7 +197,7 @@ func DiffDiagnostics(uri span.URI, want, got []source.Diagnostic) string {
|
|||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
func summarizeDiagnostics(i int, uri span.URI, want []source.Diagnostic, got []source.Diagnostic, reason string, args ...interface{}) string {
|
func summarizeDiagnostics(i int, uri span.URI, want, got []source.Diagnostic, reason string, args ...interface{}) string {
|
||||||
msg := &bytes.Buffer{}
|
msg := &bytes.Buffer{}
|
||||||
fmt.Fprint(msg, "diagnostics failed")
|
fmt.Fprint(msg, "diagnostics failed")
|
||||||
if i >= 0 {
|
if i >= 0 {
|
||||||
|
Loading…
Reference in New Issue
Block a user