mirror of
https://github.com/coder/coder.git
synced 2025-07-06 15:41:45 +00:00
feat: improve terraform template parsing errors (#2331)
This commit is contained in:
@ -2,9 +2,13 @@ package terraform
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/hashicorp/terraform-config-inspect/tfconfig"
|
||||
"github.com/mitchellh/go-wordwrap"
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
"github.com/coder/coder/provisionersdk/proto"
|
||||
@ -12,14 +16,12 @@ import (
|
||||
|
||||
// Parse extracts Terraform variables from source-code.
|
||||
func (*terraform) Parse(request *proto.Parse_Request, stream proto.DRPCProvisioner_ParseStream) error {
|
||||
defer func() {
|
||||
_ = stream.CloseSend()
|
||||
}()
|
||||
|
||||
// Load the module and print any parse errors.
|
||||
module, diags := tfconfig.LoadModule(request.Directory)
|
||||
if diags.HasErrors() {
|
||||
return xerrors.Errorf("load module: %w", diags.Err())
|
||||
return xerrors.Errorf("load module: %s", formatDiagnostics(request.Directory, diags))
|
||||
}
|
||||
|
||||
parameters := make([]*proto.ParameterSchema, 0, len(module.Variables))
|
||||
for _, v := range module.Variables {
|
||||
schema, err := convertVariableToParameter(v)
|
||||
@ -83,3 +85,47 @@ func convertVariableToParameter(variable *tfconfig.Variable) (*proto.ParameterSc
|
||||
|
||||
return schema, nil
|
||||
}
|
||||
|
||||
// formatDiagnostics returns a nicely formatted string containing all of the
|
||||
// error details within the tfconfig.Diagnostics. We need to use this because
|
||||
// the default format doesn't provide much useful information.
|
||||
func formatDiagnostics(baseDir string, diags tfconfig.Diagnostics) string {
|
||||
var msgs strings.Builder
|
||||
for _, d := range diags {
|
||||
// Convert severity.
|
||||
severity := "UNKNOWN SEVERITY"
|
||||
switch {
|
||||
case d.Severity == tfconfig.DiagError:
|
||||
severity = "ERROR"
|
||||
case d.Severity == tfconfig.DiagWarning:
|
||||
severity = "WARN"
|
||||
}
|
||||
|
||||
// Determine filepath and line
|
||||
location := "unknown location"
|
||||
if d.Pos != nil {
|
||||
filename, err := filepath.Rel(baseDir, d.Pos.Filename)
|
||||
if err != nil {
|
||||
filename = d.Pos.Filename
|
||||
}
|
||||
location = fmt.Sprintf("%s:%d", filename, d.Pos.Line)
|
||||
}
|
||||
|
||||
_, _ = msgs.WriteString(fmt.Sprintf("\n%s: %s (%s)\n", severity, d.Summary, location))
|
||||
|
||||
// Wrap the details to 80 characters and indent them.
|
||||
if d.Detail != "" {
|
||||
wrapped := wordwrap.WrapString(d.Detail, 78)
|
||||
for _, line := range strings.Split(wrapped, "\n") {
|
||||
_, _ = msgs.WriteString(fmt.Sprintf("> %s\n", line))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
spacer := " "
|
||||
if len(diags) > 1 {
|
||||
spacer = "\n\n"
|
||||
}
|
||||
|
||||
return spacer + strings.TrimSpace(msgs.String())
|
||||
}
|
||||
|
Reference in New Issue
Block a user