mirror of
https://github.com/opentffoundation/opentf.git
synced 2025-12-19 17:59:05 -05:00
Experiment with -json-into command output option
Signed-off-by: Christian Mesh <christianmesh1@gmail.com>
This commit is contained in:
@@ -35,6 +35,8 @@ type Plan struct {
|
|||||||
// ViewType specifies which output format to use
|
// ViewType specifies which output format to use
|
||||||
ViewType ViewType
|
ViewType ViewType
|
||||||
|
|
||||||
|
JsonInto string
|
||||||
|
|
||||||
// ShowSensitive is used to display the value of variables marked as sensitive.
|
// ShowSensitive is used to display the value of variables marked as sensitive.
|
||||||
ShowSensitive bool
|
ShowSensitive bool
|
||||||
}
|
}
|
||||||
@@ -59,6 +61,7 @@ func ParsePlan(args []string) (*Plan, tfdiags.Diagnostics) {
|
|||||||
|
|
||||||
var json bool
|
var json bool
|
||||||
cmdFlags.BoolVar(&json, "json", false, "json")
|
cmdFlags.BoolVar(&json, "json", false, "json")
|
||||||
|
cmdFlags.StringVar(&plan.JsonInto, "json-into", "", "json-into")
|
||||||
|
|
||||||
if err := cmdFlags.Parse(args); err != nil {
|
if err := cmdFlags.Parse(args); err != nil {
|
||||||
diags = diags.Append(tfdiags.Sourceless(
|
diags = diags.Append(tfdiags.Sourceless(
|
||||||
@@ -86,7 +89,7 @@ func ParsePlan(args []string) (*Plan, tfdiags.Diagnostics) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
switch {
|
switch {
|
||||||
case json:
|
case json || plan.JsonInto != "":
|
||||||
plan.ViewType = ViewJSON
|
plan.ViewType = ViewJSON
|
||||||
default:
|
default:
|
||||||
plan.ViewType = ViewHuman
|
plan.ViewType = ViewHuman
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ package command
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/opentofu/opentofu/internal/command/views"
|
"github.com/opentofu/opentofu/internal/command/views"
|
||||||
@@ -30,6 +31,7 @@ func (c *GetCommand) Run(args []string) int {
|
|||||||
cmdFlags.BoolVar(&update, "update", false, "update")
|
cmdFlags.BoolVar(&update, "update", false, "update")
|
||||||
cmdFlags.StringVar(&testsDirectory, "test-directory", "tests", "test-directory")
|
cmdFlags.StringVar(&testsDirectory, "test-directory", "tests", "test-directory")
|
||||||
cmdFlags.BoolVar(&c.outputInJSON, "json", false, "json")
|
cmdFlags.BoolVar(&c.outputInJSON, "json", false, "json")
|
||||||
|
cmdFlags.StringVar(&c.outputJSONInto, "json-into", "", "json-into")
|
||||||
cmdFlags.Usage = func() { c.Ui.Error(c.Help()) }
|
cmdFlags.Usage = func() { c.Ui.Error(c.Help()) }
|
||||||
if err := cmdFlags.Parse(args); err != nil {
|
if err := cmdFlags.Parse(args); err != nil {
|
||||||
c.Ui.Error(fmt.Sprintf("Error parsing command-line flags: %s\n", err.Error()))
|
c.Ui.Error(fmt.Sprintf("Error parsing command-line flags: %s\n", err.Error()))
|
||||||
@@ -40,9 +42,22 @@ func (c *GetCommand) Run(args []string) int {
|
|||||||
c.Meta.Color = false
|
c.Meta.Color = false
|
||||||
c.oldUi = c.Ui
|
c.oldUi = c.Ui
|
||||||
c.Ui = &WrappedUi{
|
c.Ui = &WrappedUi{
|
||||||
cliUi: c.oldUi,
|
cliUi: c.oldUi,
|
||||||
jsonView: views.NewJSONView(c.View),
|
jsonView: views.NewJSONView(c.View, nil),
|
||||||
outputInJSON: true,
|
onlyOutputInJSON: true,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if c.outputJSONInto != "" {
|
||||||
|
out, err := os.OpenFile(c.outputJSONInto, os.O_RDWR|os.O_CREATE, 0600)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
c.oldUi = c.Ui
|
||||||
|
c.Ui = &WrappedUi{
|
||||||
|
cliUi: c.oldUi,
|
||||||
|
jsonView: views.NewJSONView(c.View, out),
|
||||||
|
onlyOutputInJSON: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
|
"os"
|
||||||
"reflect"
|
"reflect"
|
||||||
"sort"
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
@@ -73,6 +74,7 @@ func (c *InitCommand) Run(args []string) int {
|
|||||||
cmdFlags.BoolVar(&c.Meta.ignoreRemoteVersion, "ignore-remote-version", false, "continue even if remote and local OpenTofu versions are incompatible")
|
cmdFlags.BoolVar(&c.Meta.ignoreRemoteVersion, "ignore-remote-version", false, "continue even if remote and local OpenTofu versions are incompatible")
|
||||||
cmdFlags.StringVar(&testsDirectory, "test-directory", "tests", "test-directory")
|
cmdFlags.StringVar(&testsDirectory, "test-directory", "tests", "test-directory")
|
||||||
cmdFlags.BoolVar(&c.outputInJSON, "json", false, "json")
|
cmdFlags.BoolVar(&c.outputInJSON, "json", false, "json")
|
||||||
|
cmdFlags.StringVar(&c.outputJSONInto, "json-into", "", "json-into")
|
||||||
cmdFlags.Usage = func() { c.Ui.Error(c.Help()) }
|
cmdFlags.Usage = func() { c.Ui.Error(c.Help()) }
|
||||||
if err := cmdFlags.Parse(args); err != nil {
|
if err := cmdFlags.Parse(args); err != nil {
|
||||||
return 1
|
return 1
|
||||||
@@ -83,9 +85,22 @@ func (c *InitCommand) Run(args []string) int {
|
|||||||
c.Meta.Color = false
|
c.Meta.Color = false
|
||||||
c.oldUi = c.Ui
|
c.oldUi = c.Ui
|
||||||
c.Ui = &WrappedUi{
|
c.Ui = &WrappedUi{
|
||||||
cliUi: c.oldUi,
|
cliUi: c.oldUi,
|
||||||
jsonView: views.NewJSONView(c.View),
|
jsonView: views.NewJSONView(c.View, nil),
|
||||||
outputInJSON: true,
|
onlyOutputInJSON: true,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if c.outputJSONInto != "" {
|
||||||
|
out, err := os.OpenFile(c.outputJSONInto, os.O_RDWR|os.O_CREATE, 0600)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
c.oldUi = c.Ui
|
||||||
|
c.Ui = &WrappedUi{
|
||||||
|
cliUi: c.oldUi,
|
||||||
|
jsonView: views.NewJSONView(c.View, out),
|
||||||
|
onlyOutputInJSON: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -299,7 +299,8 @@ type Meta struct {
|
|||||||
// state even if the remote and local OpenTofu versions don't match.
|
// state even if the remote and local OpenTofu versions don't match.
|
||||||
ignoreRemoteVersion bool
|
ignoreRemoteVersion bool
|
||||||
|
|
||||||
outputInJSON bool
|
outputInJSON bool
|
||||||
|
outputJSONInto string
|
||||||
|
|
||||||
// Used to cache the root module rootModuleCallCache and known variables.
|
// Used to cache the root module rootModuleCallCache and known variables.
|
||||||
// This helps prevent duplicate errors/warnings.
|
// This helps prevent duplicate errors/warnings.
|
||||||
@@ -760,8 +761,17 @@ func (m *Meta) showDiagnostics(vals ...interface{}) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if m.outputJSONInto != "" {
|
||||||
|
out, err := os.OpenFile(m.outputJSONInto, os.O_RDWR|os.O_CREATE, 0600)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
jsonView := views.NewJSONView(m.View, out)
|
||||||
|
jsonView.Diagnostics(diags)
|
||||||
|
return
|
||||||
|
}
|
||||||
if m.outputInJSON {
|
if m.outputInJSON {
|
||||||
jsonView := views.NewJSONView(m.View)
|
jsonView := views.NewJSONView(m.View, nil)
|
||||||
jsonView.Diagnostics(diags)
|
jsonView.Diagnostics(diags)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,9 +19,9 @@ import (
|
|||||||
// implement cli.Ui interface, so that we can make all command support json
|
// implement cli.Ui interface, so that we can make all command support json
|
||||||
// output in a short time.
|
// output in a short time.
|
||||||
type WrappedUi struct {
|
type WrappedUi struct {
|
||||||
cliUi cli.Ui
|
cliUi cli.Ui
|
||||||
jsonView *views.JSONView
|
jsonView *views.JSONView
|
||||||
outputInJSON bool
|
onlyOutputInJSON bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *WrappedUi) Ask(s string) (string, error) {
|
func (m *WrappedUi) Ask(s string) (string, error) {
|
||||||
@@ -33,32 +33,32 @@ func (m *WrappedUi) AskSecret(s string) (string, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (m *WrappedUi) Output(s string) {
|
func (m *WrappedUi) Output(s string) {
|
||||||
if m.outputInJSON {
|
m.jsonView.Output(s)
|
||||||
m.jsonView.Output(s)
|
if m.onlyOutputInJSON {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
m.cliUi.Output(s)
|
m.cliUi.Output(s)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *WrappedUi) Info(s string) {
|
func (m *WrappedUi) Info(s string) {
|
||||||
if m.outputInJSON {
|
m.jsonView.Info(s)
|
||||||
m.jsonView.Info(s)
|
if m.onlyOutputInJSON {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
m.cliUi.Info(s)
|
m.cliUi.Info(s)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *WrappedUi) Error(s string) {
|
func (m *WrappedUi) Error(s string) {
|
||||||
if m.outputInJSON {
|
m.jsonView.Error(s)
|
||||||
m.jsonView.Error(s)
|
if m.onlyOutputInJSON {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
m.cliUi.Error(s)
|
m.cliUi.Error(s)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *WrappedUi) Warn(s string) {
|
func (m *WrappedUi) Warn(s string) {
|
||||||
if m.outputInJSON {
|
m.jsonView.Warn(s)
|
||||||
m.jsonView.Warn(s)
|
if m.onlyOutputInJSON {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
m.cliUi.Warn(s)
|
m.cliUi.Warn(s)
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ func (c *PlanCommand) Run(rawArgs []string) int {
|
|||||||
|
|
||||||
// Instantiate the view, even if there are flag errors, so that we render
|
// Instantiate the view, even if there are flag errors, so that we render
|
||||||
// diagnostics according to the desired view
|
// diagnostics according to the desired view
|
||||||
view := views.NewPlan(args.ViewType, c.View)
|
view := views.NewPlan(args, c.View)
|
||||||
|
|
||||||
if diags.HasErrors() {
|
if diags.HasErrors() {
|
||||||
view.Diagnostics(diags)
|
view.Diagnostics(diags)
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ func NewApply(vt arguments.ViewType, destroy bool, view *View) Apply {
|
|||||||
switch vt {
|
switch vt {
|
||||||
case arguments.ViewJSON:
|
case arguments.ViewJSON:
|
||||||
return &ApplyJSON{
|
return &ApplyJSON{
|
||||||
view: NewJSONView(view),
|
view: NewJSONView(view, nil),
|
||||||
destroy: destroy,
|
destroy: destroy,
|
||||||
countHook: &countHook{},
|
countHook: &countHook{},
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ import (
|
|||||||
// Test a sequence of hooks associated with creating a resource
|
// Test a sequence of hooks associated with creating a resource
|
||||||
func TestJSONHook_create(t *testing.T) {
|
func TestJSONHook_create(t *testing.T) {
|
||||||
streams, done := terminal.StreamsForTesting(t)
|
streams, done := terminal.StreamsForTesting(t)
|
||||||
hook := newJSONHook(NewJSONView(NewView(streams)))
|
hook := newJSONHook(NewJSONView(NewView(streams), nil))
|
||||||
|
|
||||||
var nowMu sync.Mutex
|
var nowMu sync.Mutex
|
||||||
now := time.Now()
|
now := time.Now()
|
||||||
@@ -195,7 +195,7 @@ func TestJSONHook_create(t *testing.T) {
|
|||||||
|
|
||||||
func TestJSONHook_errors(t *testing.T) {
|
func TestJSONHook_errors(t *testing.T) {
|
||||||
streams, done := terminal.StreamsForTesting(t)
|
streams, done := terminal.StreamsForTesting(t)
|
||||||
hook := newJSONHook(NewJSONView(NewView(streams)))
|
hook := newJSONHook(NewJSONView(NewView(streams), nil))
|
||||||
|
|
||||||
addr := addrs.Resource{
|
addr := addrs.Resource{
|
||||||
Mode: addrs.ManagedResourceMode,
|
Mode: addrs.ManagedResourceMode,
|
||||||
@@ -282,7 +282,7 @@ func TestJSONHook_errors(t *testing.T) {
|
|||||||
|
|
||||||
func TestJSONHook_refresh(t *testing.T) {
|
func TestJSONHook_refresh(t *testing.T) {
|
||||||
streams, done := terminal.StreamsForTesting(t)
|
streams, done := terminal.StreamsForTesting(t)
|
||||||
hook := newJSONHook(NewJSONView(NewView(streams)))
|
hook := newJSONHook(NewJSONView(NewView(streams), nil))
|
||||||
|
|
||||||
addr := addrs.Resource{
|
addr := addrs.Resource{
|
||||||
Mode: addrs.DataResourceMode,
|
Mode: addrs.DataResourceMode,
|
||||||
@@ -497,7 +497,7 @@ func TestJSONHook_ephemeral(t *testing.T) {
|
|||||||
for _, tt := range cases {
|
for _, tt := range cases {
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
streams, done := terminal.StreamsForTesting(t)
|
streams, done := terminal.StreamsForTesting(t)
|
||||||
h := newJSONHook(NewJSONView(NewView(streams)))
|
h := newJSONHook(NewJSONView(NewView(streams), nil))
|
||||||
|
|
||||||
action, err := tt.preF(h)
|
action, err := tt.preF(h)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ package views
|
|||||||
import (
|
import (
|
||||||
encJson "encoding/json"
|
encJson "encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"os"
|
||||||
|
|
||||||
"github.com/hashicorp/go-hclog"
|
"github.com/hashicorp/go-hclog"
|
||||||
|
|
||||||
@@ -22,10 +23,13 @@ import (
|
|||||||
// command/views/json package.
|
// command/views/json package.
|
||||||
const JSON_UI_VERSION = "1.2"
|
const JSON_UI_VERSION = "1.2"
|
||||||
|
|
||||||
func NewJSONView(view *View) *JSONView {
|
func NewJSONView(view *View, out *os.File) *JSONView {
|
||||||
|
if out == nil {
|
||||||
|
out = view.streams.Stdout.File
|
||||||
|
}
|
||||||
log := hclog.New(&hclog.LoggerOptions{
|
log := hclog.New(&hclog.LoggerOptions{
|
||||||
Name: "tofu.ui",
|
Name: "tofu.ui",
|
||||||
Output: view.streams.Stdout.File,
|
Output: out,
|
||||||
JSONFormat: true,
|
JSONFormat: true,
|
||||||
JSONEscapeDisabled: true,
|
JSONEscapeDisabled: true,
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ import (
|
|||||||
// convenient way to test that NewJSONView works.
|
// convenient way to test that NewJSONView works.
|
||||||
func TestNewJSONView(t *testing.T) {
|
func TestNewJSONView(t *testing.T) {
|
||||||
streams, done := terminal.StreamsForTesting(t)
|
streams, done := terminal.StreamsForTesting(t)
|
||||||
NewJSONView(NewView(streams))
|
NewJSONView(NewView(streams), nil)
|
||||||
|
|
||||||
version := tfversion.String()
|
version := tfversion.String()
|
||||||
want := []map[string]interface{}{
|
want := []map[string]interface{}{
|
||||||
@@ -78,7 +78,7 @@ func TestJSONView_Log(t *testing.T) {
|
|||||||
for _, tc := range testCases {
|
for _, tc := range testCases {
|
||||||
t.Run(tc.caseName, func(t *testing.T) {
|
t.Run(tc.caseName, func(t *testing.T) {
|
||||||
streams, done := terminal.StreamsForTesting(t)
|
streams, done := terminal.StreamsForTesting(t)
|
||||||
jv := NewJSONView(NewView(streams))
|
jv := NewJSONView(NewView(streams), nil)
|
||||||
jv.Log(tc.input)
|
jv.Log(tc.input)
|
||||||
testJSONViewOutputEquals(t, done(t).Stdout(), tc.want)
|
testJSONViewOutputEquals(t, done(t).Stdout(), tc.want)
|
||||||
})
|
})
|
||||||
@@ -89,7 +89,7 @@ func TestJSONView_Log(t *testing.T) {
|
|||||||
// complex diagnostics are tested elsewhere.
|
// complex diagnostics are tested elsewhere.
|
||||||
func TestJSONView_Diagnostics(t *testing.T) {
|
func TestJSONView_Diagnostics(t *testing.T) {
|
||||||
streams, done := terminal.StreamsForTesting(t)
|
streams, done := terminal.StreamsForTesting(t)
|
||||||
jv := NewJSONView(NewView(streams))
|
jv := NewJSONView(NewView(streams), nil)
|
||||||
|
|
||||||
var diags tfdiags.Diagnostics
|
var diags tfdiags.Diagnostics
|
||||||
diags = diags.Append(tfdiags.Sourceless(
|
diags = diags.Append(tfdiags.Sourceless(
|
||||||
@@ -134,7 +134,7 @@ func TestJSONView_Diagnostics(t *testing.T) {
|
|||||||
|
|
||||||
func TestJSONView_DiagnosticsWithMetadata(t *testing.T) {
|
func TestJSONView_DiagnosticsWithMetadata(t *testing.T) {
|
||||||
streams, done := terminal.StreamsForTesting(t)
|
streams, done := terminal.StreamsForTesting(t)
|
||||||
jv := NewJSONView(NewView(streams))
|
jv := NewJSONView(NewView(streams), nil)
|
||||||
|
|
||||||
var diags tfdiags.Diagnostics
|
var diags tfdiags.Diagnostics
|
||||||
diags = diags.Append(tfdiags.Sourceless(
|
diags = diags.Append(tfdiags.Sourceless(
|
||||||
@@ -181,7 +181,7 @@ func TestJSONView_DiagnosticsWithMetadata(t *testing.T) {
|
|||||||
|
|
||||||
func TestJSONView_PlannedChange(t *testing.T) {
|
func TestJSONView_PlannedChange(t *testing.T) {
|
||||||
streams, done := terminal.StreamsForTesting(t)
|
streams, done := terminal.StreamsForTesting(t)
|
||||||
jv := NewJSONView(NewView(streams))
|
jv := NewJSONView(NewView(streams), nil)
|
||||||
|
|
||||||
foo, diags := addrs.ParseModuleInstanceStr("module.foo")
|
foo, diags := addrs.ParseModuleInstanceStr("module.foo")
|
||||||
if len(diags) > 0 {
|
if len(diags) > 0 {
|
||||||
@@ -222,7 +222,7 @@ func TestJSONView_PlannedChange(t *testing.T) {
|
|||||||
|
|
||||||
func TestJSONView_ResourceDrift(t *testing.T) {
|
func TestJSONView_ResourceDrift(t *testing.T) {
|
||||||
streams, done := terminal.StreamsForTesting(t)
|
streams, done := terminal.StreamsForTesting(t)
|
||||||
jv := NewJSONView(NewView(streams))
|
jv := NewJSONView(NewView(streams), nil)
|
||||||
|
|
||||||
foo, diags := addrs.ParseModuleInstanceStr("module.foo")
|
foo, diags := addrs.ParseModuleInstanceStr("module.foo")
|
||||||
if len(diags) > 0 {
|
if len(diags) > 0 {
|
||||||
@@ -263,7 +263,7 @@ func TestJSONView_ResourceDrift(t *testing.T) {
|
|||||||
|
|
||||||
func TestJSONView_ChangeSummary(t *testing.T) {
|
func TestJSONView_ChangeSummary(t *testing.T) {
|
||||||
streams, done := terminal.StreamsForTesting(t)
|
streams, done := terminal.StreamsForTesting(t)
|
||||||
jv := NewJSONView(NewView(streams))
|
jv := NewJSONView(NewView(streams), nil)
|
||||||
|
|
||||||
jv.ChangeSummary(&viewsjson.ChangeSummary{
|
jv.ChangeSummary(&viewsjson.ChangeSummary{
|
||||||
Add: 1,
|
Add: 1,
|
||||||
@@ -293,7 +293,7 @@ func TestJSONView_ChangeSummary(t *testing.T) {
|
|||||||
|
|
||||||
func TestJSONView_ChangeSummaryWithImport(t *testing.T) {
|
func TestJSONView_ChangeSummaryWithImport(t *testing.T) {
|
||||||
streams, done := terminal.StreamsForTesting(t)
|
streams, done := terminal.StreamsForTesting(t)
|
||||||
jv := NewJSONView(NewView(streams))
|
jv := NewJSONView(NewView(streams), nil)
|
||||||
|
|
||||||
jv.ChangeSummary(&viewsjson.ChangeSummary{
|
jv.ChangeSummary(&viewsjson.ChangeSummary{
|
||||||
Add: 1,
|
Add: 1,
|
||||||
@@ -324,7 +324,7 @@ func TestJSONView_ChangeSummaryWithImport(t *testing.T) {
|
|||||||
|
|
||||||
func TestJSONView_ChangeSummaryWithForget(t *testing.T) {
|
func TestJSONView_ChangeSummaryWithForget(t *testing.T) {
|
||||||
streams, done := terminal.StreamsForTesting(t)
|
streams, done := terminal.StreamsForTesting(t)
|
||||||
jv := NewJSONView(NewView(streams))
|
jv := NewJSONView(NewView(streams), nil)
|
||||||
|
|
||||||
jv.ChangeSummary(&viewsjson.ChangeSummary{
|
jv.ChangeSummary(&viewsjson.ChangeSummary{
|
||||||
Add: 1,
|
Add: 1,
|
||||||
@@ -355,7 +355,7 @@ func TestJSONView_ChangeSummaryWithForget(t *testing.T) {
|
|||||||
|
|
||||||
func TestJSONView_Hook(t *testing.T) {
|
func TestJSONView_Hook(t *testing.T) {
|
||||||
streams, done := terminal.StreamsForTesting(t)
|
streams, done := terminal.StreamsForTesting(t)
|
||||||
jv := NewJSONView(NewView(streams))
|
jv := NewJSONView(NewView(streams), nil)
|
||||||
|
|
||||||
foo, diags := addrs.ParseModuleInstanceStr("module.foo")
|
foo, diags := addrs.ParseModuleInstanceStr("module.foo")
|
||||||
if len(diags) > 0 {
|
if len(diags) > 0 {
|
||||||
@@ -395,7 +395,7 @@ func TestJSONView_Hook(t *testing.T) {
|
|||||||
|
|
||||||
func TestJSONView_Outputs(t *testing.T) {
|
func TestJSONView_Outputs(t *testing.T) {
|
||||||
streams, done := terminal.StreamsForTesting(t)
|
streams, done := terminal.StreamsForTesting(t)
|
||||||
jv := NewJSONView(NewView(streams))
|
jv := NewJSONView(NewView(streams), nil)
|
||||||
|
|
||||||
jv.Outputs(jsonentities.Outputs{
|
jv.Outputs(jsonentities.Outputs{
|
||||||
"boop_count": {
|
"boop_count": {
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ package views
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
@@ -49,6 +50,66 @@ func NewOperation(vt arguments.ViewType, inAutomation bool, view *View) Operatio
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type OperationMulti []Operation
|
||||||
|
|
||||||
|
var _ Operation = (OperationMulti)(nil)
|
||||||
|
|
||||||
|
func (o OperationMulti) Interrupted() {
|
||||||
|
for _, operation := range o {
|
||||||
|
operation.Interrupted()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o OperationMulti) FatalInterrupt() {
|
||||||
|
for _, operation := range o {
|
||||||
|
operation.FatalInterrupt()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o OperationMulti) Stopping() {
|
||||||
|
for _, operation := range o {
|
||||||
|
operation.Stopping()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o OperationMulti) Cancelled(planMode plans.Mode) {
|
||||||
|
for _, operation := range o {
|
||||||
|
operation.Cancelled(planMode)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o OperationMulti) EmergencyDumpState(stateFile *statefile.File, enc encryption.StateEncryption) error {
|
||||||
|
var errs []error
|
||||||
|
for _, operation := range o {
|
||||||
|
errs = append(errs, operation.EmergencyDumpState(stateFile, enc))
|
||||||
|
}
|
||||||
|
return errors.Join(errs...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o OperationMulti) PlannedChange(change *plans.ResourceInstanceChangeSrc) {
|
||||||
|
for _, operation := range o {
|
||||||
|
operation.PlannedChange(change)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o OperationMulti) Plan(plan *plans.Plan, schemas *tofu.Schemas) {
|
||||||
|
for _, operation := range o {
|
||||||
|
operation.Plan(plan, schemas)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o OperationMulti) PlanNextStep(planPath string, genConfigPath string) {
|
||||||
|
for _, operation := range o {
|
||||||
|
operation.PlanNextStep(planPath, genConfigPath)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o OperationMulti) Diagnostics(diags tfdiags.Diagnostics) {
|
||||||
|
for _, operation := range o {
|
||||||
|
operation.Diagnostics(diags)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
type OperationHuman struct {
|
type OperationHuman struct {
|
||||||
view *View
|
view *View
|
||||||
|
|
||||||
|
|||||||
@@ -508,7 +508,7 @@ func TestOperation_planNextStepInAutomation(t *testing.T) {
|
|||||||
// This test is not a realistic stream of messages.
|
// This test is not a realistic stream of messages.
|
||||||
func TestOperationJSON_logs(t *testing.T) {
|
func TestOperationJSON_logs(t *testing.T) {
|
||||||
streams, done := terminal.StreamsForTesting(t)
|
streams, done := terminal.StreamsForTesting(t)
|
||||||
v := &OperationJSON{view: NewJSONView(NewView(streams))}
|
v := &OperationJSON{view: NewJSONView(NewView(streams), nil)}
|
||||||
|
|
||||||
// Added an ephemeral resource change to double-check that it's not
|
// Added an ephemeral resource change to double-check that it's not
|
||||||
// shown.
|
// shown.
|
||||||
@@ -567,7 +567,7 @@ func TestOperationJSON_logs(t *testing.T) {
|
|||||||
// we upgrade state format in the future.
|
// we upgrade state format in the future.
|
||||||
func TestOperationJSON_emergencyDumpState(t *testing.T) {
|
func TestOperationJSON_emergencyDumpState(t *testing.T) {
|
||||||
streams, done := terminal.StreamsForTesting(t)
|
streams, done := terminal.StreamsForTesting(t)
|
||||||
v := &OperationJSON{view: NewJSONView(NewView(streams))}
|
v := &OperationJSON{view: NewJSONView(NewView(streams), nil)}
|
||||||
|
|
||||||
stateFile := statefile.New(nil, "foo", 1)
|
stateFile := statefile.New(nil, "foo", 1)
|
||||||
stateBuf := new(bytes.Buffer)
|
stateBuf := new(bytes.Buffer)
|
||||||
@@ -601,7 +601,7 @@ func TestOperationJSON_emergencyDumpState(t *testing.T) {
|
|||||||
|
|
||||||
func TestOperationJSON_planNoChanges(t *testing.T) {
|
func TestOperationJSON_planNoChanges(t *testing.T) {
|
||||||
streams, done := terminal.StreamsForTesting(t)
|
streams, done := terminal.StreamsForTesting(t)
|
||||||
v := &OperationJSON{view: NewJSONView(NewView(streams))}
|
v := &OperationJSON{view: NewJSONView(NewView(streams), nil)}
|
||||||
|
|
||||||
plan := &plans.Plan{
|
plan := &plans.Plan{
|
||||||
Changes: plans.NewChanges(),
|
Changes: plans.NewChanges(),
|
||||||
@@ -630,7 +630,7 @@ func TestOperationJSON_planNoChanges(t *testing.T) {
|
|||||||
|
|
||||||
func TestOperationJSON_plan(t *testing.T) {
|
func TestOperationJSON_plan(t *testing.T) {
|
||||||
streams, done := terminal.StreamsForTesting(t)
|
streams, done := terminal.StreamsForTesting(t)
|
||||||
v := &OperationJSON{view: NewJSONView(NewView(streams))}
|
v := &OperationJSON{view: NewJSONView(NewView(streams), nil)}
|
||||||
|
|
||||||
root := addrs.RootModuleInstance
|
root := addrs.RootModuleInstance
|
||||||
vpc, diags := addrs.ParseModuleInstanceStr("module.vpc")
|
vpc, diags := addrs.ParseModuleInstanceStr("module.vpc")
|
||||||
@@ -799,7 +799,7 @@ func TestOperationJSON_plan(t *testing.T) {
|
|||||||
|
|
||||||
func TestOperationJSON_planWithImport(t *testing.T) {
|
func TestOperationJSON_planWithImport(t *testing.T) {
|
||||||
streams, done := terminal.StreamsForTesting(t)
|
streams, done := terminal.StreamsForTesting(t)
|
||||||
v := &OperationJSON{view: NewJSONView(NewView(streams))}
|
v := &OperationJSON{view: NewJSONView(NewView(streams), nil)}
|
||||||
|
|
||||||
root := addrs.RootModuleInstance
|
root := addrs.RootModuleInstance
|
||||||
vpc, diags := addrs.ParseModuleInstanceStr("module.vpc")
|
vpc, diags := addrs.ParseModuleInstanceStr("module.vpc")
|
||||||
@@ -947,7 +947,7 @@ func TestOperationJSON_planWithImport(t *testing.T) {
|
|||||||
|
|
||||||
func TestOperationJSON_planDriftWithMove(t *testing.T) {
|
func TestOperationJSON_planDriftWithMove(t *testing.T) {
|
||||||
streams, done := terminal.StreamsForTesting(t)
|
streams, done := terminal.StreamsForTesting(t)
|
||||||
v := &OperationJSON{view: NewJSONView(NewView(streams))}
|
v := &OperationJSON{view: NewJSONView(NewView(streams), nil)}
|
||||||
|
|
||||||
root := addrs.RootModuleInstance
|
root := addrs.RootModuleInstance
|
||||||
boop := addrs.Resource{Mode: addrs.ManagedResourceMode, Type: "test_resource", Name: "boop"}
|
boop := addrs.Resource{Mode: addrs.ManagedResourceMode, Type: "test_resource", Name: "boop"}
|
||||||
@@ -1085,7 +1085,7 @@ func TestOperationJSON_planDriftWithMove(t *testing.T) {
|
|||||||
|
|
||||||
func TestOperationJSON_planDriftWithMoveRefreshOnly(t *testing.T) {
|
func TestOperationJSON_planDriftWithMoveRefreshOnly(t *testing.T) {
|
||||||
streams, done := terminal.StreamsForTesting(t)
|
streams, done := terminal.StreamsForTesting(t)
|
||||||
v := &OperationJSON{view: NewJSONView(NewView(streams))}
|
v := &OperationJSON{view: NewJSONView(NewView(streams), nil)}
|
||||||
|
|
||||||
root := addrs.RootModuleInstance
|
root := addrs.RootModuleInstance
|
||||||
boop := addrs.Resource{Mode: addrs.ManagedResourceMode, Type: "test_resource", Name: "boop"}
|
boop := addrs.Resource{Mode: addrs.ManagedResourceMode, Type: "test_resource", Name: "boop"}
|
||||||
@@ -1217,7 +1217,7 @@ func TestOperationJSON_planDriftWithMoveRefreshOnly(t *testing.T) {
|
|||||||
|
|
||||||
func TestOperationJSON_planOutputChanges(t *testing.T) {
|
func TestOperationJSON_planOutputChanges(t *testing.T) {
|
||||||
streams, done := terminal.StreamsForTesting(t)
|
streams, done := terminal.StreamsForTesting(t)
|
||||||
v := &OperationJSON{view: NewJSONView(NewView(streams))}
|
v := &OperationJSON{view: NewJSONView(NewView(streams), nil)}
|
||||||
|
|
||||||
root := addrs.RootModuleInstance
|
root := addrs.RootModuleInstance
|
||||||
|
|
||||||
@@ -1303,7 +1303,7 @@ func TestOperationJSON_planOutputChanges(t *testing.T) {
|
|||||||
|
|
||||||
func TestOperationJSON_plannedChange(t *testing.T) {
|
func TestOperationJSON_plannedChange(t *testing.T) {
|
||||||
streams, done := terminal.StreamsForTesting(t)
|
streams, done := terminal.StreamsForTesting(t)
|
||||||
v := &OperationJSON{view: NewJSONView(NewView(streams))}
|
v := &OperationJSON{view: NewJSONView(NewView(streams), nil)}
|
||||||
|
|
||||||
root := addrs.RootModuleInstance
|
root := addrs.RootModuleInstance
|
||||||
boop := addrs.Resource{Mode: addrs.ManagedResourceMode, Type: "test_instance", Name: "boop"}
|
boop := addrs.Resource{Mode: addrs.ManagedResourceMode, Type: "test_instance", Name: "boop"}
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ package views
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"os"
|
||||||
|
|
||||||
"github.com/opentofu/opentofu/internal/command/arguments"
|
"github.com/opentofu/opentofu/internal/command/arguments"
|
||||||
"github.com/opentofu/opentofu/internal/tfdiags"
|
"github.com/opentofu/opentofu/internal/tfdiags"
|
||||||
@@ -23,19 +24,62 @@ type Plan interface {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// NewPlan returns an initialized Plan implementation for the given ViewType.
|
// NewPlan returns an initialized Plan implementation for the given ViewType.
|
||||||
func NewPlan(vt arguments.ViewType, view *View) Plan {
|
func NewPlan(args *arguments.Plan, view *View) Plan {
|
||||||
switch vt {
|
human := &PlanHuman{
|
||||||
|
view: view,
|
||||||
|
inAutomation: view.RunningInAutomation(),
|
||||||
|
}
|
||||||
|
|
||||||
|
switch args.ViewType {
|
||||||
case arguments.ViewJSON:
|
case arguments.ViewJSON:
|
||||||
|
if args.JsonInto != "" {
|
||||||
|
out, err := os.OpenFile(args.JsonInto, os.O_RDWR|os.O_CREATE, 0600)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
return PlanMulti{human, &PlanJSON{
|
||||||
|
view: NewJSONView(view, out),
|
||||||
|
}}
|
||||||
|
}
|
||||||
return &PlanJSON{
|
return &PlanJSON{
|
||||||
view: NewJSONView(view),
|
view: NewJSONView(view, nil),
|
||||||
}
|
}
|
||||||
case arguments.ViewHuman:
|
case arguments.ViewHuman:
|
||||||
return &PlanHuman{
|
return human
|
||||||
view: view,
|
|
||||||
inAutomation: view.RunningInAutomation(),
|
|
||||||
}
|
|
||||||
default:
|
default:
|
||||||
panic(fmt.Sprintf("unknown view type %v", vt))
|
panic(fmt.Sprintf("unknown view type %v", args.ViewType))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type PlanMulti []Plan
|
||||||
|
|
||||||
|
var _ Plan = (PlanMulti)(nil)
|
||||||
|
|
||||||
|
func (p PlanMulti) Operation() Operation {
|
||||||
|
var operation OperationMulti
|
||||||
|
for _, plan := range p {
|
||||||
|
operation = append(operation, plan.Operation())
|
||||||
|
}
|
||||||
|
return operation
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p PlanMulti) Hooks() []tofu.Hook {
|
||||||
|
var hooks []tofu.Hook
|
||||||
|
for _, plan := range p {
|
||||||
|
hooks = append(hooks, plan.Hooks()...)
|
||||||
|
}
|
||||||
|
return hooks
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p PlanMulti) Diagnostics(diags tfdiags.Diagnostics) {
|
||||||
|
for _, plan := range p {
|
||||||
|
plan.Diagnostics(diags)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p PlanMulti) HelpPrompt() {
|
||||||
|
for _, plan := range p {
|
||||||
|
plan.HelpPrompt()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ import (
|
|||||||
func TestPlanHuman_operation(t *testing.T) {
|
func TestPlanHuman_operation(t *testing.T) {
|
||||||
streams, done := terminal.StreamsForTesting(t)
|
streams, done := terminal.StreamsForTesting(t)
|
||||||
defer done(t)
|
defer done(t)
|
||||||
v := NewPlan(arguments.ViewHuman, NewView(streams).SetRunningInAutomation(true)).Operation()
|
v := NewPlan(&arguments.Plan{ViewType: arguments.ViewHuman}, NewView(streams).SetRunningInAutomation(true)).Operation()
|
||||||
if hv, ok := v.(*OperationHuman); !ok {
|
if hv, ok := v.(*OperationHuman); !ok {
|
||||||
t.Fatalf("unexpected return type %t", v)
|
t.Fatalf("unexpected return type %t", v)
|
||||||
} else if hv.inAutomation != true {
|
} else if hv.inAutomation != true {
|
||||||
@@ -36,7 +36,7 @@ func TestPlanHuman_operation(t *testing.T) {
|
|||||||
func TestPlanHuman_hooks(t *testing.T) {
|
func TestPlanHuman_hooks(t *testing.T) {
|
||||||
streams, done := terminal.StreamsForTesting(t)
|
streams, done := terminal.StreamsForTesting(t)
|
||||||
defer done(t)
|
defer done(t)
|
||||||
v := NewPlan(arguments.ViewHuman, NewView(streams).SetRunningInAutomation((true)))
|
v := NewPlan(&arguments.Plan{ViewType: arguments.ViewHuman}, NewView(streams).SetRunningInAutomation((true)))
|
||||||
hooks := v.Hooks()
|
hooks := v.Hooks()
|
||||||
|
|
||||||
var uiHook *UiHook
|
var uiHook *UiHook
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ func NewRefresh(vt arguments.ViewType, view *View) Refresh {
|
|||||||
switch vt {
|
switch vt {
|
||||||
case arguments.ViewJSON:
|
case arguments.ViewJSON:
|
||||||
return &RefreshJSON{
|
return &RefreshJSON{
|
||||||
view: NewJSONView(view),
|
view: NewJSONView(view, nil),
|
||||||
}
|
}
|
||||||
case arguments.ViewHuman:
|
case arguments.ViewHuman:
|
||||||
return &RefreshHuman{
|
return &RefreshHuman{
|
||||||
|
|||||||
@@ -78,7 +78,7 @@ func NewTest(vt arguments.ViewType, view *View) Test {
|
|||||||
switch vt {
|
switch vt {
|
||||||
case arguments.ViewJSON:
|
case arguments.ViewJSON:
|
||||||
return &TestJSON{
|
return &TestJSON{
|
||||||
view: NewJSONView(view),
|
view: NewJSONView(view, nil),
|
||||||
}
|
}
|
||||||
case arguments.ViewHuman:
|
case arguments.ViewHuman:
|
||||||
return &TestHuman{
|
return &TestHuman{
|
||||||
|
|||||||
Reference in New Issue
Block a user