Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Stevenmasley/tfparse to preview#18650

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to ourterms of service andprivacy statement. We’ll occasionally send you account related emails.

Already on GitHub?Sign in to your account

Draft
Emyrk wants to merge2 commits intomain
base:main
Choose a base branch
Loading
fromstevenmasley/tfparse_to_preview
Draft
Show file tree
Hide file tree
Changes fromall 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
19 changes: 19 additions & 0 deletionsarchive/fs/zip.go
View file
Open in desktop
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
package archivefs

import (
"archive/zip"
"io"
"io/fs"

"github.com/spf13/afero"
"github.com/spf13/afero/zipfs"
)

// FromZipReader creates a read-only in-memory FS
func FromZipReader(r io.ReaderAt, size int64) (fs.FS, error) {
zr, err := zip.NewReader(r, size)
if err != nil {
return nil, err
}
return afero.NewIOFS(zipfs.New(zr)), nil
}
46 changes: 33 additions & 13 deletionscoderd/templateversions.go
View file
Open in desktop
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,18 @@
package coderd

import (
"bytes"
"context"
"crypto/sha256"
"database/sql"
"encoding/hex"
"encoding/json"
"errors"
"fmt"
"io/fs"
"net/http"
"os"
"strings"

"github.com/go-chi/chi/v5"
"github.com/google/uuid"
Expand All@@ -18,6 +21,8 @@ import (
"golang.org/x/xerrors"

"cdr.dev/slog"
archivefs "github.com/coder/coder/v2/archive/fs"
"github.com/coder/preview"

"github.com/coder/coder/v2/coderd/audit"
"github.com/coder/coder/v2/coderd/database"
Expand DownExpand Up@@ -1589,36 +1594,51 @@ func (api *API) postTemplateVersionsByOrganization(rw http.ResponseWriter, r *ht
}
}()

if err := tfparse.WriteArchive(file.Data, file.Mimetype, tempDir); err != nil {
httpapi.Write(ctx, rw, http.StatusInternalServerError, codersdk.Response{
Message: "Internal error checking workspace tags",
Detail: "extract archive to tempdir: " + err.Error(),
})
return
var files fs.FS
switch file.Mimetype {
case "application/x-tar":
files = archivefs.FromTarReader(bytes.NewBuffer(file.Data))
case "application/zip":
files, err = archivefs.FromZipReader(bytes.NewReader(file.Data), int64(len(file.Data)))
if err != nil {
httpapi.Write(ctx, rw, http.StatusInternalServerError, codersdk.Response{
Message: "Internal error checking workspace tags",
Detail: "extract archive to tempdir: " + err.Error(),
})
return
}
}

parser, diags :=tfparse.New(tempDir, tfparse.WithLogger(api.Logger.Named("tfparse")))
output, diags :=preview.Preview(ctx, preview.Input{}, files)
if diags.HasErrors() {
httpapi.Write(ctx, rw, http.StatusInternalServerError, codersdk.Response{
Message: "Internal errorchecking workspace tags",
Message: "Internal errorparsing workspace tags",
Detail: "parse module: " + diags.Error(),
})
return
}
parsedTags := output.WorkspaceTags

failedTags := parsedTags.UnusableTags()
if len(failedTags) > 0 {
validations := make([]codersdk.ValidationError, 0, len(failedTags))
names := make([]string, 0, len(failedTags))
for _, tag := range failedTags {
validations = append(validations, tfparse.TagValidationResponse(tag))
}

parsedTags, err := parser.WorkspaceTagDefaults(ctx)
if err != nil {
httpapi.Write(ctx, rw, http.StatusInternalServerError, codersdk.Response{
Message: "Internal error checking workspace tags",
Detail: "evaluate default values of workspace tags: " + err.Error(),
Message: "Internal error checking workspace tags",
Detail: fmt.Sprintf("evaluate default values of workspace tags [%s]", strings.Join(names, ", ")),
Validations: validations,
})
return
}

// Ensure the "owner" tag is properly applied in addition to request tags and coder_workspace_tags.
// User-specified tags in the request will take precedence over tags parsed from `coder_workspace_tags`
// data sources defined in the template file.
tags := provisionersdk.MutateTags(apiKey.UserID, parsedTags, req.ProvisionerTags)
tags := provisionersdk.MutateTags(apiKey.UserID, parsedTags.Tags(), req.ProvisionerTags)

var templateVersion database.TemplateVersion
var provisionerJob database.ProvisionerJob
Expand Down
4 changes: 3 additions & 1 deletiongo.mod
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -483,7 +483,7 @@ require (
require (
github.com/coder/agentapi-sdk-go v0.0.0-20250505131810-560d1d88d225
github.com/coder/aisdk-go v0.0.9
github.com/coder/preview v1.0.1
github.com/coder/preview v1.0.3-0.20250627161416-e1ccd88ba6c0
github.com/fsnotify/fsnotify v1.9.0
github.com/mark3labs/mcp-go v0.32.0
)
Expand DownExpand Up@@ -538,3 +538,5 @@ require (
google.golang.org/genai v1.12.0 // indirect
k8s.io/utils v0.0.0-20241210054802-24370beab758 // indirect
)

replace github.com/coder/preview => /home/steven/go/src/github.com/coder/preview/
4 changes: 2 additions & 2 deletionsgo.sum
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -916,8 +916,8 @@ github.com/coder/pq v1.10.5-0.20240813183442-0c420cb5a048 h1:3jzYUlGH7ZELIH4XggX
github.com/coder/pq v1.10.5-0.20240813183442-0c420cb5a048/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
github.com/coder/pretty v0.0.0-20230908205945-e89ba86370e0 h1:3A0ES21Ke+FxEM8CXx9n47SZOKOpgSE1bbJzlE4qPVs=
github.com/coder/pretty v0.0.0-20230908205945-e89ba86370e0/go.mod h1:5UuS2Ts+nTToAMeOjNlnHFkPahrtDkmpydBen/3wgZc=
github.com/coder/preview v1.0.1 h1:f6q+RjNelwnkyXfGbmVlb4dcUOQ0z4mPsb2kuQpFHuU=
github.com/coder/preview v1.0.1/go.mod h1:efDWGlO/PZPrvdt5QiDhMtTUTkPxejXo9c0wmYYLLjM=
github.com/coder/preview v1.0.3-0.20250627161416-e1ccd88ba6c0 h1:6fbDlBk0MjSqkantXyLO1tN4fl40lnh90Q8ZTk9vXVA=
github.com/coder/preview v1.0.3-0.20250627161416-e1ccd88ba6c0/go.mod h1:efDWGlO/PZPrvdt5QiDhMtTUTkPxejXo9c0wmYYLLjM=
github.com/coder/quartz v0.2.1 h1:QgQ2Vc1+mvzewg2uD/nj8MJ9p9gE+QhGJm+Z+NGnrSE=
github.com/coder/quartz v0.2.1/go.mod h1:vsiCc+AHViMKH2CQpGIpFgdHIEQsxwm8yCscqKmzbRA=
github.com/coder/retry v1.5.1 h1:iWu8YnD8YqHs3XwqrqsjoBTAVqT9ml6z9ViJ2wlMiqc=
Expand Down
41 changes: 22 additions & 19 deletionsprovisioner/terraform/parse.go
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -2,16 +2,17 @@ package terraform

import (
"fmt"
"os"
"path/filepath"
"strings"

"github.com/hashicorp/terraform-config-inspect/tfconfig"
"github.com/hashicorp/hcl/v2"
"github.com/mitchellh/go-wordwrap"

"github.com/coder/coder/v2/coderd/tracing"
"github.com/coder/coder/v2/provisioner/terraform/tfparse"
"github.com/coder/coder/v2/provisionersdk"
"github.com/coder/coder/v2/provisionersdk/proto"
"github.com/coder/preview"
)

// Parse extracts Terraform variables from source-code.
Expand All@@ -21,50 +22,52 @@ func (s *server) Parse(sess *provisionersdk.Session, _ *proto.ParseRequest, _ <-
defer span.End()

// Load the module and print any parse errors.
parser, diags :=tfparse.New(sess.WorkDirectory, tfparse.WithLogger(s.logger.Named("tfparse")))
output, diags :=preview.Preview(ctx, preview.Input{}, os.DirFS(sess.WorkDirectory))
if diags.HasErrors() {
return provisionersdk.ParseErrorf("load module: %s", formatDiagnostics(sess.WorkDirectory, diags))
}

workspaceTags, _, err := parser.WorkspaceTags(ctx)
if err != nil {
return provisionersdk.ParseErrorf("can't load workspace tags: %v", err)
tags := output.WorkspaceTags
failedTags := tags.UnusableTags()
if len(failedTags) > 0 {
return provisionersdk.ParseErrorf("can't load workspace tags: %v", failedTags.SafeNames())
}

templateVariables, err := parser.TemplateVariables()
if err != nil {
return provisionersdk.ParseErrorf("can't load template variables: %v", err)
}
// TODO: THIS
//templateVariables, err := parser.TemplateVariables()
//if err != nil {
//return provisionersdk.ParseErrorf("can't load template variables: %v", err)
//}

return &proto.ParseComplete{
TemplateVariables:templateVariables,
WorkspaceTags:workspaceTags,
TemplateVariables:nil, // TODO: Handle template variables.
WorkspaceTags:tags.Tags(),
}
}

// 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, diagstfconfig.Diagnostics) string {
func formatDiagnostics(baseDir string, diagshcl.Diagnostics) string {
var msgs strings.Builder
for _, d := range diags {
// Convert severity.
severity := "UNKNOWN SEVERITY"
switch {
case d.Severity ==tfconfig.DiagError:
case d.Severity ==hcl.DiagError:
severity = "ERROR"
case d.Severity ==tfconfig.DiagWarning:
case d.Severity ==hcl.DiagWarning:
severity = "WARN"
}

// Determine filepath and line
location := "unknown location"
if d.Pos != nil {
filename, err := filepath.Rel(baseDir, d.Pos.Filename)
if d.Subject != nil {
filename, err := filepath.Rel(baseDir, d.Subject.Filename)
if err != nil {
filename = d.Pos.Filename
filename = d.Subject.Filename
}
location = fmt.Sprintf("%s:%d", filename, d.Pos.Line)
location = fmt.Sprintf("%s:%d", filename, d.Subject.Start.Line)
}

_, _ = msgs.WriteString(fmt.Sprintf("\n%s: %s (%s)\n", severity, d.Summary, location))
Expand Down
99 changes: 99 additions & 0 deletionsprovisioner/terraform/tfparse/previewtags.go
View file
Open in desktop
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
package tfparse

import (
"context"
"fmt"
"io/fs"

"github.com/hashicorp/hcl/v2"

"github.com/coder/coder/v2/codersdk"
"github.com/coder/preview"
previewtypes "github.com/coder/preview/types"
)

type Parsed struct {
output *preview.Output
}

//
//// TODO: Maybe swap workdir with an fs.FS interface?
//func New(files fs.FS, opt ...Option) (*Parser, hcl.Diagnostics) {
//return &Parser{
//logger: slog.Logger{},
//workdir: files,
//}, nil
//}

func New(ctx context.Context, workdir fs.FS, input preview.Input) (*preview.Output, hcl.Diagnostics) {
output, diags := preview.Preview(ctx, input, workdir)

if diags.HasErrors() {
return nil, diags
}
return output, nil
}

func TagValidationResponse(tag previewtypes.Tag) codersdk.ValidationError {
name := tag.KeyString()
if name == previewtypes.UnknownStringValue {
name = "unknown"
}

const (
key = "key"
value = "value"
)

diagErr := "Invalid tag %s: %s"
if tag.Key.ValueDiags.HasErrors() {
return codersdk.ValidationError{
Field: name,
Detail: fmt.Sprintf(diagErr, key, tag.Key.ValueDiags.Error()),
}
}

if tag.Value.ValueDiags.HasErrors() {
return codersdk.ValidationError{
Field: name,
Detail: fmt.Sprintf(diagErr, value, tag.Value.ValueDiags.Error()),
}
}

// TODO: It would be really nice to pull out the variable references to help identify the source of
// the unknown or invalid tag.
unknownErr := "Tag %s is not known, it likely refers to a variable that is not set or has no default."
if !tag.Key.IsKnown() {
return codersdk.ValidationError{
Field: name,
Detail: fmt.Sprintf(unknownErr, key),
}
}

if !tag.Value.IsKnown() {
return codersdk.ValidationError{
Field: name,
Detail: fmt.Sprintf(unknownErr, value),
}
}

invalidErr := "Tag %s is not valid, it must be a non-null string value."
if !tag.Key.Valid() {
return codersdk.ValidationError{
Field: name,
Detail: fmt.Sprintf(invalidErr, key),
}
}

if !tag.Value.Valid() {
return codersdk.ValidationError{
Field: name,
Detail: fmt.Sprintf(invalidErr, value),
}
}

return codersdk.ValidationError{
Field: name,
Detail: fmt.Sprintf("Tag is invalid for some unknown reason. Please check the tag's value and key."),
}
}
Loading
Loading

[8]ページ先頭

©2009-2025 Movatter.jp