mirror of https://github.com/hashicorp/terraform
parent
c1f6360120
commit
ef4771bba4
@ -0,0 +1,49 @@
|
||||
// Copyright (c) HashiCorp, Inc.
|
||||
// SPDX-License-Identifier: BUSL-1.1
|
||||
|
||||
package arguments
|
||||
|
||||
import (
|
||||
"github.com/hashicorp/terraform/internal/tfdiags"
|
||||
)
|
||||
|
||||
// StateList represents the command-line arguments for the state list command.
|
||||
type StateList struct {
|
||||
// StatePath is an optional path to a state file, overriding the default.
|
||||
StatePath string
|
||||
|
||||
// ID filters the results to include only instances whose resource types
|
||||
// have an attribute named "id" whose value equals this string.
|
||||
ID string
|
||||
|
||||
// Addrs are optional resource or module addresses used to filter the
|
||||
// listed instances.
|
||||
Addrs []string
|
||||
}
|
||||
|
||||
// ParseStateList processes CLI arguments, returning a StateList value and
|
||||
// diagnostics. If errors are encountered, a StateList value is still returned
|
||||
// representing the best effort interpretation of the arguments.
|
||||
func ParseStateList(args []string) (*StateList, tfdiags.Diagnostics) {
|
||||
var diags tfdiags.Diagnostics
|
||||
list := &StateList{}
|
||||
|
||||
var statePath, id string
|
||||
cmdFlags := defaultFlagSet("state list")
|
||||
cmdFlags.StringVar(&statePath, "state", "", "path")
|
||||
cmdFlags.StringVar(&id, "id", "", "Restrict output to paths with a resource having the specified ID.")
|
||||
|
||||
if err := cmdFlags.Parse(args); err != nil {
|
||||
diags = diags.Append(tfdiags.Sourceless(
|
||||
tfdiags.Error,
|
||||
"Failed to parse command-line flags",
|
||||
err.Error(),
|
||||
))
|
||||
}
|
||||
|
||||
list.StatePath = statePath
|
||||
list.ID = id
|
||||
list.Addrs = cmdFlags.Args()
|
||||
|
||||
return list, diags
|
||||
}
|
||||
@ -0,0 +1,118 @@
|
||||
// Copyright (c) HashiCorp, Inc.
|
||||
// SPDX-License-Identifier: BUSL-1.1
|
||||
|
||||
package arguments
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/hashicorp/terraform/internal/tfdiags"
|
||||
)
|
||||
|
||||
func TestParseStateList_valid(t *testing.T) {
|
||||
testCases := map[string]struct {
|
||||
args []string
|
||||
want *StateList
|
||||
}{
|
||||
"defaults": {
|
||||
nil,
|
||||
&StateList{
|
||||
StatePath: "",
|
||||
ID: "",
|
||||
Addrs: nil,
|
||||
},
|
||||
},
|
||||
"state path": {
|
||||
[]string{"-state=foobar.tfstate"},
|
||||
&StateList{
|
||||
StatePath: "foobar.tfstate",
|
||||
ID: "",
|
||||
Addrs: nil,
|
||||
},
|
||||
},
|
||||
"id filter": {
|
||||
[]string{"-id=bar"},
|
||||
&StateList{
|
||||
StatePath: "",
|
||||
ID: "bar",
|
||||
Addrs: nil,
|
||||
},
|
||||
},
|
||||
"with addresses": {
|
||||
[]string{"module.example", "aws_instance.foo"},
|
||||
&StateList{
|
||||
StatePath: "",
|
||||
ID: "",
|
||||
Addrs: []string{"module.example", "aws_instance.foo"},
|
||||
},
|
||||
},
|
||||
"all options": {
|
||||
[]string{"-state=foobar.tfstate", "-id=bar", "module.example"},
|
||||
&StateList{
|
||||
StatePath: "foobar.tfstate",
|
||||
ID: "bar",
|
||||
Addrs: []string{"module.example"},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for name, tc := range testCases {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
got, diags := ParseStateList(tc.args)
|
||||
if len(diags) > 0 {
|
||||
t.Fatalf("unexpected diags: %v", diags)
|
||||
}
|
||||
if got.StatePath != tc.want.StatePath {
|
||||
t.Fatalf("unexpected StatePath\n got: %q\nwant: %q", got.StatePath, tc.want.StatePath)
|
||||
}
|
||||
if got.ID != tc.want.ID {
|
||||
t.Fatalf("unexpected ID\n got: %q\nwant: %q", got.ID, tc.want.ID)
|
||||
}
|
||||
if len(got.Addrs) != len(tc.want.Addrs) {
|
||||
t.Fatalf("unexpected Addrs length\n got: %d\nwant: %d", len(got.Addrs), len(tc.want.Addrs))
|
||||
}
|
||||
for i := range got.Addrs {
|
||||
if got.Addrs[i] != tc.want.Addrs[i] {
|
||||
t.Fatalf("unexpected Addrs[%d]\n got: %q\nwant: %q", i, got.Addrs[i], tc.want.Addrs[i])
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseStateList_invalid(t *testing.T) {
|
||||
testCases := map[string]struct {
|
||||
args []string
|
||||
want *StateList
|
||||
wantDiags tfdiags.Diagnostics
|
||||
}{
|
||||
"unknown flag": {
|
||||
[]string{"-boop"},
|
||||
&StateList{
|
||||
StatePath: "",
|
||||
ID: "",
|
||||
Addrs: nil,
|
||||
},
|
||||
tfdiags.Diagnostics{
|
||||
tfdiags.Sourceless(
|
||||
tfdiags.Error,
|
||||
"Failed to parse command-line flags",
|
||||
"flag provided but not defined: -boop",
|
||||
),
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for name, tc := range testCases {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
got, gotDiags := ParseStateList(tc.args)
|
||||
if got.StatePath != tc.want.StatePath {
|
||||
t.Fatalf("unexpected StatePath\n got: %q\nwant: %q", got.StatePath, tc.want.StatePath)
|
||||
}
|
||||
if got.ID != tc.want.ID {
|
||||
t.Fatalf("unexpected ID\n got: %q\nwant: %q", got.ID, tc.want.ID)
|
||||
}
|
||||
tfdiags.AssertDiagnosticsMatch(t, gotDiags, tc.wantDiags)
|
||||
})
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,93 @@
|
||||
// Copyright (c) HashiCorp, Inc.
|
||||
// SPDX-License-Identifier: BUSL-1.1
|
||||
|
||||
package arguments
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/hashicorp/terraform/internal/tfdiags"
|
||||
)
|
||||
|
||||
// StateMv represents the command-line arguments for the state mv command.
|
||||
type StateMv struct {
|
||||
// DryRun, if true, prints out what would be moved without actually
|
||||
// moving anything.
|
||||
DryRun bool
|
||||
|
||||
// BackupPath is the path where Terraform should write the backup state.
|
||||
BackupPath string
|
||||
|
||||
// BackupOutPath is the path where Terraform should write the backup of
|
||||
// the destination state.
|
||||
BackupOutPath string
|
||||
|
||||
// StateLock, if true, requests that the backend lock the state for this
|
||||
// operation.
|
||||
StateLock bool
|
||||
|
||||
// StateLockTimeout is the duration to retry a state lock.
|
||||
StateLockTimeout time.Duration
|
||||
|
||||
// StatePath is an optional path to a local state file.
|
||||
StatePath string
|
||||
|
||||
// StateOutPath is an optional path to write the destination state.
|
||||
StateOutPath string
|
||||
|
||||
// IgnoreRemoteVersion, if true, continues even if remote and local
|
||||
// Terraform versions are incompatible.
|
||||
IgnoreRemoteVersion bool
|
||||
|
||||
// SourceAddr is the source resource address.
|
||||
SourceAddr string
|
||||
|
||||
// DestAddr is the destination resource address.
|
||||
DestAddr string
|
||||
}
|
||||
|
||||
// ParseStateMv processes CLI arguments, returning a StateMv value and
|
||||
// diagnostics. If errors are encountered, a StateMv value is still returned
|
||||
// representing the best effort interpretation of the arguments.
|
||||
func ParseStateMv(args []string) (*StateMv, tfdiags.Diagnostics) {
|
||||
var diags tfdiags.Diagnostics
|
||||
mv := &StateMv{
|
||||
StateLock: true,
|
||||
}
|
||||
|
||||
cmdFlags := defaultFlagSet("state mv")
|
||||
cmdFlags.BoolVar(&mv.DryRun, "dry-run", false, "dry run")
|
||||
cmdFlags.StringVar(&mv.BackupPath, "backup", "-", "backup")
|
||||
cmdFlags.StringVar(&mv.BackupOutPath, "backup-out", "-", "backup")
|
||||
cmdFlags.BoolVar(&mv.StateLock, "lock", true, "lock states")
|
||||
cmdFlags.DurationVar(&mv.StateLockTimeout, "lock-timeout", 0, "lock timeout")
|
||||
cmdFlags.StringVar(&mv.StatePath, "state", "", "path")
|
||||
cmdFlags.StringVar(&mv.StateOutPath, "state-out", "", "path")
|
||||
cmdFlags.BoolVar(&mv.IgnoreRemoteVersion, "ignore-remote-version", false, "continue even if remote and local Terraform versions are incompatible")
|
||||
|
||||
if err := cmdFlags.Parse(args); err != nil {
|
||||
diags = diags.Append(tfdiags.Sourceless(
|
||||
tfdiags.Error,
|
||||
"Failed to parse command-line flags",
|
||||
err.Error(),
|
||||
))
|
||||
}
|
||||
|
||||
args = cmdFlags.Args()
|
||||
if len(args) != 2 {
|
||||
diags = diags.Append(tfdiags.Sourceless(
|
||||
tfdiags.Error,
|
||||
"Required argument missing",
|
||||
"Exactly two arguments expected: the source and destination addresses.",
|
||||
))
|
||||
}
|
||||
|
||||
if len(args) > 0 {
|
||||
mv.SourceAddr = args[0]
|
||||
}
|
||||
if len(args) > 1 {
|
||||
mv.DestAddr = args[1]
|
||||
}
|
||||
|
||||
return mv, diags
|
||||
}
|
||||
@ -0,0 +1,174 @@
|
||||
// Copyright (c) HashiCorp, Inc.
|
||||
// SPDX-License-Identifier: BUSL-1.1
|
||||
|
||||
package arguments
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/hashicorp/terraform/internal/tfdiags"
|
||||
)
|
||||
|
||||
func TestParseStateMv_valid(t *testing.T) {
|
||||
testCases := map[string]struct {
|
||||
args []string
|
||||
want *StateMv
|
||||
}{
|
||||
"addresses only": {
|
||||
[]string{"test_instance.foo", "test_instance.bar"},
|
||||
&StateMv{
|
||||
DryRun: false,
|
||||
BackupPath: "-",
|
||||
BackupOutPath: "-",
|
||||
StateLock: true,
|
||||
StateLockTimeout: 0,
|
||||
StatePath: "",
|
||||
StateOutPath: "",
|
||||
IgnoreRemoteVersion: false,
|
||||
SourceAddr: "test_instance.foo",
|
||||
DestAddr: "test_instance.bar",
|
||||
},
|
||||
},
|
||||
"dry run": {
|
||||
[]string{"-dry-run", "test_instance.foo", "test_instance.bar"},
|
||||
&StateMv{
|
||||
DryRun: true,
|
||||
BackupPath: "-",
|
||||
BackupOutPath: "-",
|
||||
StateLock: true,
|
||||
StateLockTimeout: 0,
|
||||
StatePath: "",
|
||||
StateOutPath: "",
|
||||
IgnoreRemoteVersion: false,
|
||||
SourceAddr: "test_instance.foo",
|
||||
DestAddr: "test_instance.bar",
|
||||
},
|
||||
},
|
||||
"all options": {
|
||||
[]string{
|
||||
"-dry-run",
|
||||
"-backup=backup.tfstate",
|
||||
"-backup-out=backup-out.tfstate",
|
||||
"-lock=false",
|
||||
"-lock-timeout=5s",
|
||||
"-state=state.tfstate",
|
||||
"-state-out=state-out.tfstate",
|
||||
"-ignore-remote-version",
|
||||
"test_instance.foo",
|
||||
"test_instance.bar",
|
||||
},
|
||||
&StateMv{
|
||||
DryRun: true,
|
||||
BackupPath: "backup.tfstate",
|
||||
BackupOutPath: "backup-out.tfstate",
|
||||
StateLock: false,
|
||||
StateLockTimeout: 5 * time.Second,
|
||||
StatePath: "state.tfstate",
|
||||
StateOutPath: "state-out.tfstate",
|
||||
IgnoreRemoteVersion: true,
|
||||
SourceAddr: "test_instance.foo",
|
||||
DestAddr: "test_instance.bar",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for name, tc := range testCases {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
got, diags := ParseStateMv(tc.args)
|
||||
if len(diags) > 0 {
|
||||
t.Fatalf("unexpected diags: %v", diags)
|
||||
}
|
||||
if *got != *tc.want {
|
||||
t.Fatalf("unexpected result\n got: %#v\nwant: %#v", got, tc.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseStateMv_invalid(t *testing.T) {
|
||||
testCases := map[string]struct {
|
||||
args []string
|
||||
want *StateMv
|
||||
wantDiags tfdiags.Diagnostics
|
||||
}{
|
||||
"no arguments": {
|
||||
nil,
|
||||
&StateMv{
|
||||
BackupPath: "-",
|
||||
BackupOutPath: "-",
|
||||
StateLock: true,
|
||||
},
|
||||
tfdiags.Diagnostics{
|
||||
tfdiags.Sourceless(
|
||||
tfdiags.Error,
|
||||
"Required argument missing",
|
||||
"Exactly two arguments expected: the source and destination addresses.",
|
||||
),
|
||||
},
|
||||
},
|
||||
"one argument": {
|
||||
[]string{"test_instance.foo"},
|
||||
&StateMv{
|
||||
BackupPath: "-",
|
||||
BackupOutPath: "-",
|
||||
StateLock: true,
|
||||
SourceAddr: "test_instance.foo",
|
||||
},
|
||||
tfdiags.Diagnostics{
|
||||
tfdiags.Sourceless(
|
||||
tfdiags.Error,
|
||||
"Required argument missing",
|
||||
"Exactly two arguments expected: the source and destination addresses.",
|
||||
),
|
||||
},
|
||||
},
|
||||
"too many arguments": {
|
||||
[]string{"a", "b", "c"},
|
||||
&StateMv{
|
||||
BackupPath: "-",
|
||||
BackupOutPath: "-",
|
||||
StateLock: true,
|
||||
SourceAddr: "a",
|
||||
DestAddr: "b",
|
||||
},
|
||||
tfdiags.Diagnostics{
|
||||
tfdiags.Sourceless(
|
||||
tfdiags.Error,
|
||||
"Required argument missing",
|
||||
"Exactly two arguments expected: the source and destination addresses.",
|
||||
),
|
||||
},
|
||||
},
|
||||
"unknown flag": {
|
||||
[]string{"-boop"},
|
||||
&StateMv{
|
||||
BackupPath: "-",
|
||||
BackupOutPath: "-",
|
||||
StateLock: true,
|
||||
},
|
||||
tfdiags.Diagnostics{
|
||||
tfdiags.Sourceless(
|
||||
tfdiags.Error,
|
||||
"Failed to parse command-line flags",
|
||||
"flag provided but not defined: -boop",
|
||||
),
|
||||
tfdiags.Sourceless(
|
||||
tfdiags.Error,
|
||||
"Required argument missing",
|
||||
"Exactly two arguments expected: the source and destination addresses.",
|
||||
),
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for name, tc := range testCases {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
got, gotDiags := ParseStateMv(tc.args)
|
||||
if *got != *tc.want {
|
||||
t.Fatalf("unexpected result\n got: %#v\nwant: %#v", got, tc.want)
|
||||
}
|
||||
tfdiags.AssertDiagnosticsMatch(t, gotDiags, tc.wantDiags)
|
||||
})
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,32 @@
|
||||
// Copyright (c) HashiCorp, Inc.
|
||||
// SPDX-License-Identifier: BUSL-1.1
|
||||
|
||||
package arguments
|
||||
|
||||
import (
|
||||
"github.com/hashicorp/terraform/internal/tfdiags"
|
||||
)
|
||||
|
||||
// StatePull represents the command-line arguments for the state pull command.
|
||||
type StatePull struct {
|
||||
}
|
||||
|
||||
// ParseStatePull processes CLI arguments, returning a StatePull value and
|
||||
// diagnostics. If errors are encountered, a StatePull value is still returned
|
||||
// representing the best effort interpretation of the arguments.
|
||||
func ParseStatePull(args []string) (*StatePull, tfdiags.Diagnostics) {
|
||||
var diags tfdiags.Diagnostics
|
||||
pull := &StatePull{}
|
||||
|
||||
cmdFlags := defaultFlagSet("state pull")
|
||||
|
||||
if err := cmdFlags.Parse(args); err != nil {
|
||||
diags = diags.Append(tfdiags.Sourceless(
|
||||
tfdiags.Error,
|
||||
"Failed to parse command-line flags",
|
||||
err.Error(),
|
||||
))
|
||||
}
|
||||
|
||||
return pull, diags
|
||||
}
|
||||
@ -0,0 +1,64 @@
|
||||
// Copyright (c) HashiCorp, Inc.
|
||||
// SPDX-License-Identifier: BUSL-1.1
|
||||
|
||||
package arguments
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/hashicorp/terraform/internal/tfdiags"
|
||||
)
|
||||
|
||||
func TestParseStatePull_valid(t *testing.T) {
|
||||
testCases := map[string]struct {
|
||||
args []string
|
||||
want *StatePull
|
||||
}{
|
||||
"defaults": {
|
||||
nil,
|
||||
&StatePull{},
|
||||
},
|
||||
}
|
||||
|
||||
for name, tc := range testCases {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
got, diags := ParseStatePull(tc.args)
|
||||
if len(diags) > 0 {
|
||||
t.Fatalf("unexpected diags: %v", diags)
|
||||
}
|
||||
if *got != *tc.want {
|
||||
t.Fatalf("unexpected result\n got: %#v\nwant: %#v", got, tc.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseStatePull_invalid(t *testing.T) {
|
||||
testCases := map[string]struct {
|
||||
args []string
|
||||
want *StatePull
|
||||
wantDiags tfdiags.Diagnostics
|
||||
}{
|
||||
"unknown flag": {
|
||||
[]string{"-boop"},
|
||||
&StatePull{},
|
||||
tfdiags.Diagnostics{
|
||||
tfdiags.Sourceless(
|
||||
tfdiags.Error,
|
||||
"Failed to parse command-line flags",
|
||||
"flag provided but not defined: -boop",
|
||||
),
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for name, tc := range testCases {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
got, gotDiags := ParseStatePull(tc.args)
|
||||
if *got != *tc.want {
|
||||
t.Fatalf("unexpected result\n got: %#v\nwant: %#v", got, tc.want)
|
||||
}
|
||||
tfdiags.AssertDiagnosticsMatch(t, gotDiags, tc.wantDiags)
|
||||
})
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,70 @@
|
||||
// Copyright (c) HashiCorp, Inc.
|
||||
// SPDX-License-Identifier: BUSL-1.1
|
||||
|
||||
package arguments
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/hashicorp/terraform/internal/tfdiags"
|
||||
)
|
||||
|
||||
// StatePush represents the command-line arguments for the state push command.
|
||||
type StatePush struct {
|
||||
// Force writes the state even if lineages don't match or the remote
|
||||
// serial is higher.
|
||||
Force bool
|
||||
|
||||
// StateLock, if true, requests that the backend lock the state for this
|
||||
// operation.
|
||||
StateLock bool
|
||||
|
||||
// StateLockTimeout is the duration to retry a state lock.
|
||||
StateLockTimeout time.Duration
|
||||
|
||||
// IgnoreRemoteVersion, if true, continues even if remote and local
|
||||
// Terraform versions are incompatible.
|
||||
IgnoreRemoteVersion bool
|
||||
|
||||
// Path is the path to the state file to push, or "-" for stdin.
|
||||
Path string
|
||||
}
|
||||
|
||||
// ParseStatePush processes CLI arguments, returning a StatePush value and
|
||||
// diagnostics. If errors are encountered, a StatePush value is still returned
|
||||
// representing the best effort interpretation of the arguments.
|
||||
func ParseStatePush(args []string) (*StatePush, tfdiags.Diagnostics) {
|
||||
var diags tfdiags.Diagnostics
|
||||
push := &StatePush{
|
||||
StateLock: true,
|
||||
}
|
||||
|
||||
cmdFlags := defaultFlagSet("state push")
|
||||
cmdFlags.BoolVar(&push.Force, "force", false, "")
|
||||
cmdFlags.BoolVar(&push.StateLock, "lock", true, "lock state")
|
||||
cmdFlags.DurationVar(&push.StateLockTimeout, "lock-timeout", 0, "lock timeout")
|
||||
cmdFlags.BoolVar(&push.IgnoreRemoteVersion, "ignore-remote-version", false, "continue even if remote and local Terraform versions are incompatible")
|
||||
|
||||
if err := cmdFlags.Parse(args); err != nil {
|
||||
diags = diags.Append(tfdiags.Sourceless(
|
||||
tfdiags.Error,
|
||||
"Failed to parse command-line flags",
|
||||
err.Error(),
|
||||
))
|
||||
}
|
||||
|
||||
args = cmdFlags.Args()
|
||||
if len(args) != 1 {
|
||||
diags = diags.Append(tfdiags.Sourceless(
|
||||
tfdiags.Error,
|
||||
"Required argument missing",
|
||||
"Exactly one argument expected: the path to a Terraform state file.",
|
||||
))
|
||||
}
|
||||
|
||||
if len(args) > 0 {
|
||||
push.Path = args[0]
|
||||
}
|
||||
|
||||
return push, diags
|
||||
}
|
||||
@ -0,0 +1,155 @@
|
||||
// Copyright (c) HashiCorp, Inc.
|
||||
// SPDX-License-Identifier: BUSL-1.1
|
||||
|
||||
package arguments
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/hashicorp/terraform/internal/tfdiags"
|
||||
)
|
||||
|
||||
func TestParseStatePush_valid(t *testing.T) {
|
||||
testCases := map[string]struct {
|
||||
args []string
|
||||
want *StatePush
|
||||
}{
|
||||
"path only": {
|
||||
[]string{"replace.tfstate"},
|
||||
&StatePush{
|
||||
Force: false,
|
||||
StateLock: true,
|
||||
StateLockTimeout: 0,
|
||||
IgnoreRemoteVersion: false,
|
||||
Path: "replace.tfstate",
|
||||
},
|
||||
},
|
||||
"stdin": {
|
||||
[]string{"-"},
|
||||
&StatePush{
|
||||
Force: false,
|
||||
StateLock: true,
|
||||
StateLockTimeout: 0,
|
||||
IgnoreRemoteVersion: false,
|
||||
Path: "-",
|
||||
},
|
||||
},
|
||||
"force": {
|
||||
[]string{"-force", "replace.tfstate"},
|
||||
&StatePush{
|
||||
Force: true,
|
||||
StateLock: true,
|
||||
StateLockTimeout: 0,
|
||||
IgnoreRemoteVersion: false,
|
||||
Path: "replace.tfstate",
|
||||
},
|
||||
},
|
||||
"lock disabled": {
|
||||
[]string{"-lock=false", "replace.tfstate"},
|
||||
&StatePush{
|
||||
Force: false,
|
||||
StateLock: false,
|
||||
StateLockTimeout: 0,
|
||||
IgnoreRemoteVersion: false,
|
||||
Path: "replace.tfstate",
|
||||
},
|
||||
},
|
||||
"lock timeout": {
|
||||
[]string{"-lock-timeout=5s", "replace.tfstate"},
|
||||
&StatePush{
|
||||
Force: false,
|
||||
StateLock: true,
|
||||
StateLockTimeout: 5 * time.Second,
|
||||
IgnoreRemoteVersion: false,
|
||||
Path: "replace.tfstate",
|
||||
},
|
||||
},
|
||||
"ignore remote version": {
|
||||
[]string{"-ignore-remote-version", "replace.tfstate"},
|
||||
&StatePush{
|
||||
Force: false,
|
||||
StateLock: true,
|
||||
StateLockTimeout: 0,
|
||||
IgnoreRemoteVersion: true,
|
||||
Path: "replace.tfstate",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for name, tc := range testCases {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
got, diags := ParseStatePush(tc.args)
|
||||
if len(diags) > 0 {
|
||||
t.Fatalf("unexpected diags: %v", diags)
|
||||
}
|
||||
if *got != *tc.want {
|
||||
t.Fatalf("unexpected result\n got: %#v\nwant: %#v", got, tc.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseStatePush_invalid(t *testing.T) {
|
||||
testCases := map[string]struct {
|
||||
args []string
|
||||
want *StatePush
|
||||
wantDiags tfdiags.Diagnostics
|
||||
}{
|
||||
"no arguments": {
|
||||
nil,
|
||||
&StatePush{
|
||||
StateLock: true,
|
||||
},
|
||||
tfdiags.Diagnostics{
|
||||
tfdiags.Sourceless(
|
||||
tfdiags.Error,
|
||||
"Required argument missing",
|
||||
"Exactly one argument expected: the path to a Terraform state file.",
|
||||
),
|
||||
},
|
||||
},
|
||||
"too many arguments": {
|
||||
[]string{"foo.tfstate", "bar.tfstate"},
|
||||
&StatePush{
|
||||
StateLock: true,
|
||||
Path: "foo.tfstate",
|
||||
},
|
||||
tfdiags.Diagnostics{
|
||||
tfdiags.Sourceless(
|
||||
tfdiags.Error,
|
||||
"Required argument missing",
|
||||
"Exactly one argument expected: the path to a Terraform state file.",
|
||||
),
|
||||
},
|
||||
},
|
||||
"unknown flag": {
|
||||
[]string{"-boop"},
|
||||
&StatePush{
|
||||
StateLock: true,
|
||||
},
|
||||
tfdiags.Diagnostics{
|
||||
tfdiags.Sourceless(
|
||||
tfdiags.Error,
|
||||
"Failed to parse command-line flags",
|
||||
"flag provided but not defined: -boop",
|
||||
),
|
||||
tfdiags.Sourceless(
|
||||
tfdiags.Error,
|
||||
"Required argument missing",
|
||||
"Exactly one argument expected: the path to a Terraform state file.",
|
||||
),
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for name, tc := range testCases {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
got, gotDiags := ParseStatePush(tc.args)
|
||||
if *got != *tc.want {
|
||||
t.Fatalf("unexpected result\n got: %#v\nwant: %#v", got, tc.want)
|
||||
}
|
||||
tfdiags.AssertDiagnosticsMatch(t, gotDiags, tc.wantDiags)
|
||||
})
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,85 @@
|
||||
// Copyright (c) HashiCorp, Inc.
|
||||
// SPDX-License-Identifier: BUSL-1.1
|
||||
|
||||
package arguments
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/hashicorp/terraform/internal/tfdiags"
|
||||
)
|
||||
|
||||
// StateReplaceProvider represents the command-line arguments for the state
|
||||
// replace-provider command.
|
||||
type StateReplaceProvider struct {
|
||||
// AutoApprove, if true, skips the interactive approval step.
|
||||
AutoApprove bool
|
||||
|
||||
// BackupPath is the path where Terraform should write the backup state.
|
||||
BackupPath string
|
||||
|
||||
// StateLock, if true, requests that the backend lock the state for this
|
||||
// operation.
|
||||
StateLock bool
|
||||
|
||||
// StateLockTimeout is the duration to retry a state lock.
|
||||
StateLockTimeout time.Duration
|
||||
|
||||
// StatePath is an optional path to a local state file.
|
||||
StatePath string
|
||||
|
||||
// IgnoreRemoteVersion, if true, continues even if remote and local
|
||||
// Terraform versions are incompatible.
|
||||
IgnoreRemoteVersion bool
|
||||
|
||||
// FromProviderAddr is the provider address to replace.
|
||||
FromProviderAddr string
|
||||
|
||||
// ToProviderAddr is the replacement provider address.
|
||||
ToProviderAddr string
|
||||
}
|
||||
|
||||
// ParseStateReplaceProvider processes CLI arguments, returning a
|
||||
// StateReplaceProvider value and diagnostics. If errors are encountered, a
|
||||
// StateReplaceProvider value is still returned representing the best effort
|
||||
// interpretation of the arguments.
|
||||
func ParseStateReplaceProvider(args []string) (*StateReplaceProvider, tfdiags.Diagnostics) {
|
||||
var diags tfdiags.Diagnostics
|
||||
rp := &StateReplaceProvider{
|
||||
StateLock: true,
|
||||
}
|
||||
|
||||
cmdFlags := defaultFlagSet("state replace-provider")
|
||||
cmdFlags.BoolVar(&rp.AutoApprove, "auto-approve", false, "skip interactive approval of replacements")
|
||||
cmdFlags.StringVar(&rp.BackupPath, "backup", "-", "backup")
|
||||
cmdFlags.BoolVar(&rp.StateLock, "lock", true, "lock states")
|
||||
cmdFlags.DurationVar(&rp.StateLockTimeout, "lock-timeout", 0, "lock timeout")
|
||||
cmdFlags.StringVar(&rp.StatePath, "state", "", "path")
|
||||
cmdFlags.BoolVar(&rp.IgnoreRemoteVersion, "ignore-remote-version", false, "continue even if remote and local Terraform versions are incompatible")
|
||||
|
||||
if err := cmdFlags.Parse(args); err != nil {
|
||||
diags = diags.Append(tfdiags.Sourceless(
|
||||
tfdiags.Error,
|
||||
"Failed to parse command-line flags",
|
||||
err.Error(),
|
||||
))
|
||||
}
|
||||
|
||||
args = cmdFlags.Args()
|
||||
if len(args) != 2 {
|
||||
diags = diags.Append(tfdiags.Sourceless(
|
||||
tfdiags.Error,
|
||||
"Required argument missing",
|
||||
"Exactly two arguments expected: the from and to provider addresses.",
|
||||
))
|
||||
}
|
||||
|
||||
if len(args) > 0 {
|
||||
rp.FromProviderAddr = args[0]
|
||||
}
|
||||
if len(args) > 1 {
|
||||
rp.ToProviderAddr = args[1]
|
||||
}
|
||||
|
||||
return rp, diags
|
||||
}
|
||||
@ -0,0 +1,144 @@
|
||||
// Copyright (c) HashiCorp, Inc.
|
||||
// SPDX-License-Identifier: BUSL-1.1
|
||||
|
||||
package arguments
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/hashicorp/terraform/internal/tfdiags"
|
||||
)
|
||||
|
||||
func TestParseStateReplaceProvider_valid(t *testing.T) {
|
||||
testCases := map[string]struct {
|
||||
args []string
|
||||
want *StateReplaceProvider
|
||||
}{
|
||||
"provider addresses only": {
|
||||
[]string{"hashicorp/aws", "acmecorp/aws"},
|
||||
&StateReplaceProvider{
|
||||
AutoApprove: false,
|
||||
BackupPath: "-",
|
||||
StateLock: true,
|
||||
StateLockTimeout: 0,
|
||||
StatePath: "",
|
||||
IgnoreRemoteVersion: false,
|
||||
FromProviderAddr: "hashicorp/aws",
|
||||
ToProviderAddr: "acmecorp/aws",
|
||||
},
|
||||
},
|
||||
"auto approve": {
|
||||
[]string{"-auto-approve", "hashicorp/aws", "acmecorp/aws"},
|
||||
&StateReplaceProvider{
|
||||
AutoApprove: true,
|
||||
BackupPath: "-",
|
||||
StateLock: true,
|
||||
StateLockTimeout: 0,
|
||||
StatePath: "",
|
||||
IgnoreRemoteVersion: false,
|
||||
FromProviderAddr: "hashicorp/aws",
|
||||
ToProviderAddr: "acmecorp/aws",
|
||||
},
|
||||
},
|
||||
"all options": {
|
||||
[]string{
|
||||
"-auto-approve",
|
||||
"-backup=backup.tfstate",
|
||||
"-lock=false",
|
||||
"-lock-timeout=5s",
|
||||
"-state=state.tfstate",
|
||||
"-ignore-remote-version",
|
||||
"hashicorp/aws",
|
||||
"acmecorp/aws",
|
||||
},
|
||||
&StateReplaceProvider{
|
||||
AutoApprove: true,
|
||||
BackupPath: "backup.tfstate",
|
||||
StateLock: false,
|
||||
StateLockTimeout: 5 * time.Second,
|
||||
StatePath: "state.tfstate",
|
||||
IgnoreRemoteVersion: true,
|
||||
FromProviderAddr: "hashicorp/aws",
|
||||
ToProviderAddr: "acmecorp/aws",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for name, tc := range testCases {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
got, diags := ParseStateReplaceProvider(tc.args)
|
||||
if len(diags) > 0 {
|
||||
t.Fatalf("unexpected diags: %v", diags)
|
||||
}
|
||||
if *got != *tc.want {
|
||||
t.Fatalf("unexpected result\n got: %#v\nwant: %#v", got, tc.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseStateReplaceProvider_invalid(t *testing.T) {
|
||||
testCases := map[string]struct {
|
||||
args []string
|
||||
want *StateReplaceProvider
|
||||
wantDiags tfdiags.Diagnostics
|
||||
}{
|
||||
"no arguments": {
|
||||
nil,
|
||||
&StateReplaceProvider{
|
||||
BackupPath: "-",
|
||||
StateLock: true,
|
||||
},
|
||||
tfdiags.Diagnostics{
|
||||
tfdiags.Sourceless(
|
||||
tfdiags.Error,
|
||||
"Required argument missing",
|
||||
"Exactly two arguments expected: the from and to provider addresses.",
|
||||
),
|
||||
},
|
||||
},
|
||||
"too many arguments": {
|
||||
[]string{"a", "b", "c", "d"},
|
||||
&StateReplaceProvider{
|
||||
BackupPath: "-",
|
||||
StateLock: true,
|
||||
FromProviderAddr: "a",
|
||||
ToProviderAddr: "b",
|
||||
},
|
||||
tfdiags.Diagnostics{
|
||||
tfdiags.Sourceless(
|
||||
tfdiags.Error,
|
||||
"Required argument missing",
|
||||
"Exactly two arguments expected: the from and to provider addresses.",
|
||||
),
|
||||
},
|
||||
},
|
||||
"unknown flag": {
|
||||
[]string{"-invalid", "hashicorp/google", "acmecorp/google"},
|
||||
&StateReplaceProvider{
|
||||
BackupPath: "-",
|
||||
StateLock: true,
|
||||
FromProviderAddr: "hashicorp/google",
|
||||
ToProviderAddr: "acmecorp/google",
|
||||
},
|
||||
tfdiags.Diagnostics{
|
||||
tfdiags.Sourceless(
|
||||
tfdiags.Error,
|
||||
"Failed to parse command-line flags",
|
||||
"flag provided but not defined: -invalid",
|
||||
),
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for name, tc := range testCases {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
got, gotDiags := ParseStateReplaceProvider(tc.args)
|
||||
if *got != *tc.want {
|
||||
t.Fatalf("unexpected result\n got: %#v\nwant: %#v", got, tc.want)
|
||||
}
|
||||
tfdiags.AssertDiagnosticsMatch(t, gotDiags, tc.wantDiags)
|
||||
})
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,76 @@
|
||||
// Copyright (c) HashiCorp, Inc.
|
||||
// SPDX-License-Identifier: BUSL-1.1
|
||||
|
||||
package arguments
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/hashicorp/terraform/internal/tfdiags"
|
||||
)
|
||||
|
||||
// StateRm represents the command-line arguments for the state rm command.
|
||||
type StateRm struct {
|
||||
// DryRun, if true, prints out what would be removed without actually
|
||||
// removing anything.
|
||||
DryRun bool
|
||||
|
||||
// BackupPath is the path where Terraform should write the backup state.
|
||||
BackupPath string
|
||||
|
||||
// StateLock, if true, requests that the backend lock the state for this
|
||||
// operation.
|
||||
StateLock bool
|
||||
|
||||
// StateLockTimeout is the duration to retry a state lock.
|
||||
StateLockTimeout time.Duration
|
||||
|
||||
// StatePath is an optional path to a local state file.
|
||||
StatePath string
|
||||
|
||||
// IgnoreRemoteVersion, if true, continues even if remote and local
|
||||
// Terraform versions are incompatible.
|
||||
IgnoreRemoteVersion bool
|
||||
|
||||
// Addrs are the resource instance addresses to remove.
|
||||
Addrs []string
|
||||
}
|
||||
|
||||
// ParseStateRm processes CLI arguments, returning a StateRm value and
|
||||
// diagnostics. If errors are encountered, a StateRm value is still returned
|
||||
// representing the best effort interpretation of the arguments.
|
||||
func ParseStateRm(args []string) (*StateRm, tfdiags.Diagnostics) {
|
||||
var diags tfdiags.Diagnostics
|
||||
rm := &StateRm{
|
||||
StateLock: true,
|
||||
}
|
||||
|
||||
cmdFlags := defaultFlagSet("state rm")
|
||||
cmdFlags.BoolVar(&rm.DryRun, "dry-run", false, "dry run")
|
||||
cmdFlags.StringVar(&rm.BackupPath, "backup", "-", "backup")
|
||||
cmdFlags.BoolVar(&rm.StateLock, "lock", true, "lock state")
|
||||
cmdFlags.DurationVar(&rm.StateLockTimeout, "lock-timeout", 0, "lock timeout")
|
||||
cmdFlags.StringVar(&rm.StatePath, "state", "", "path")
|
||||
cmdFlags.BoolVar(&rm.IgnoreRemoteVersion, "ignore-remote-version", false, "continue even if remote and local Terraform versions are incompatible")
|
||||
|
||||
if err := cmdFlags.Parse(args); err != nil {
|
||||
diags = diags.Append(tfdiags.Sourceless(
|
||||
tfdiags.Error,
|
||||
"Failed to parse command-line flags",
|
||||
err.Error(),
|
||||
))
|
||||
}
|
||||
|
||||
args = cmdFlags.Args()
|
||||
if len(args) < 1 {
|
||||
diags = diags.Append(tfdiags.Sourceless(
|
||||
tfdiags.Error,
|
||||
"Required argument missing",
|
||||
"At least one address is required.",
|
||||
))
|
||||
}
|
||||
|
||||
rm.Addrs = args
|
||||
|
||||
return rm, diags
|
||||
}
|
||||
@ -0,0 +1,126 @@
|
||||
// Copyright (c) HashiCorp, Inc.
|
||||
// SPDX-License-Identifier: BUSL-1.1
|
||||
|
||||
package arguments
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/hashicorp/terraform/internal/tfdiags"
|
||||
)
|
||||
|
||||
func TestParseStateRm_valid(t *testing.T) {
|
||||
testCases := map[string]struct {
|
||||
args []string
|
||||
want *StateRm
|
||||
}{
|
||||
"single address": {
|
||||
[]string{"test_instance.foo"},
|
||||
&StateRm{
|
||||
DryRun: false,
|
||||
BackupPath: "-",
|
||||
StateLock: true,
|
||||
StateLockTimeout: 0,
|
||||
StatePath: "",
|
||||
IgnoreRemoteVersion: false,
|
||||
Addrs: []string{"test_instance.foo"},
|
||||
},
|
||||
},
|
||||
"multiple addresses": {
|
||||
[]string{"test_instance.foo", "test_instance.bar"},
|
||||
&StateRm{
|
||||
DryRun: false,
|
||||
BackupPath: "-",
|
||||
StateLock: true,
|
||||
StateLockTimeout: 0,
|
||||
StatePath: "",
|
||||
IgnoreRemoteVersion: false,
|
||||
Addrs: []string{"test_instance.foo", "test_instance.bar"},
|
||||
},
|
||||
},
|
||||
"all options": {
|
||||
[]string{"-dry-run", "-backup=backup.tfstate", "-lock=false", "-lock-timeout=5s", "-state=state.tfstate", "-ignore-remote-version", "test_instance.foo"},
|
||||
&StateRm{
|
||||
DryRun: true,
|
||||
BackupPath: "backup.tfstate",
|
||||
StateLock: false,
|
||||
StateLockTimeout: 5 * time.Second,
|
||||
StatePath: "state.tfstate",
|
||||
IgnoreRemoteVersion: true,
|
||||
Addrs: []string{"test_instance.foo"},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for name, tc := range testCases {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
got, diags := ParseStateRm(tc.args)
|
||||
if len(diags) > 0 {
|
||||
t.Fatalf("unexpected diags: %v", diags)
|
||||
}
|
||||
if got.DryRun != tc.want.DryRun ||
|
||||
got.BackupPath != tc.want.BackupPath ||
|
||||
got.StateLock != tc.want.StateLock ||
|
||||
got.StateLockTimeout != tc.want.StateLockTimeout ||
|
||||
got.StatePath != tc.want.StatePath ||
|
||||
got.IgnoreRemoteVersion != tc.want.IgnoreRemoteVersion {
|
||||
t.Fatalf("unexpected result\n got: %#v\nwant: %#v", got, tc.want)
|
||||
}
|
||||
if len(got.Addrs) != len(tc.want.Addrs) {
|
||||
t.Fatalf("unexpected Addrs length\n got: %d\nwant: %d", len(got.Addrs), len(tc.want.Addrs))
|
||||
}
|
||||
for i := range got.Addrs {
|
||||
if got.Addrs[i] != tc.want.Addrs[i] {
|
||||
t.Fatalf("unexpected Addrs[%d]\n got: %q\nwant: %q", i, got.Addrs[i], tc.want.Addrs[i])
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseStateRm_invalid(t *testing.T) {
|
||||
testCases := map[string]struct {
|
||||
args []string
|
||||
wantAddrs int
|
||||
wantDiags tfdiags.Diagnostics
|
||||
}{
|
||||
"no arguments": {
|
||||
nil,
|
||||
0,
|
||||
tfdiags.Diagnostics{
|
||||
tfdiags.Sourceless(
|
||||
tfdiags.Error,
|
||||
"Required argument missing",
|
||||
"At least one address is required.",
|
||||
),
|
||||
},
|
||||
},
|
||||
"unknown flag": {
|
||||
[]string{"-boop"},
|
||||
0,
|
||||
tfdiags.Diagnostics{
|
||||
tfdiags.Sourceless(
|
||||
tfdiags.Error,
|
||||
"Failed to parse command-line flags",
|
||||
"flag provided but not defined: -boop",
|
||||
),
|
||||
tfdiags.Sourceless(
|
||||
tfdiags.Error,
|
||||
"Required argument missing",
|
||||
"At least one address is required.",
|
||||
),
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for name, tc := range testCases {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
got, gotDiags := ParseStateRm(tc.args)
|
||||
if len(got.Addrs) != tc.wantAddrs {
|
||||
t.Fatalf("unexpected Addrs length\n got: %d\nwant: %d", len(got.Addrs), tc.wantAddrs)
|
||||
}
|
||||
tfdiags.AssertDiagnosticsMatch(t, gotDiags, tc.wantDiags)
|
||||
})
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,54 @@
|
||||
// Copyright (c) HashiCorp, Inc.
|
||||
// SPDX-License-Identifier: BUSL-1.1
|
||||
|
||||
package arguments
|
||||
|
||||
import (
|
||||
"github.com/hashicorp/terraform/internal/tfdiags"
|
||||
)
|
||||
|
||||
// StateShow represents the command-line arguments for the state show command.
|
||||
type StateShow struct {
|
||||
// StatePath is an optional path to a state file, overriding the default.
|
||||
StatePath string
|
||||
|
||||
// Address is the resource instance address to show.
|
||||
Address string
|
||||
}
|
||||
|
||||
// ParseStateShow processes CLI arguments, returning a StateShow value and
|
||||
// diagnostics. If errors are encountered, a StateShow value is still returned
|
||||
// representing the best effort interpretation of the arguments.
|
||||
func ParseStateShow(args []string) (*StateShow, tfdiags.Diagnostics) {
|
||||
var diags tfdiags.Diagnostics
|
||||
show := &StateShow{}
|
||||
|
||||
var statePath string
|
||||
cmdFlags := defaultFlagSet("state show")
|
||||
cmdFlags.StringVar(&statePath, "state", "", "path")
|
||||
|
||||
if err := cmdFlags.Parse(args); err != nil {
|
||||
diags = diags.Append(tfdiags.Sourceless(
|
||||
tfdiags.Error,
|
||||
"Failed to parse command-line flags",
|
||||
err.Error(),
|
||||
))
|
||||
}
|
||||
|
||||
args = cmdFlags.Args()
|
||||
if len(args) != 1 {
|
||||
diags = diags.Append(tfdiags.Sourceless(
|
||||
tfdiags.Error,
|
||||
"Required argument missing",
|
||||
"Exactly one argument expected: the address of a resource instance to show.",
|
||||
))
|
||||
}
|
||||
|
||||
show.StatePath = statePath
|
||||
|
||||
if len(args) > 0 {
|
||||
show.Address = args[0]
|
||||
}
|
||||
|
||||
return show, diags
|
||||
}
|
||||
@ -0,0 +1,110 @@
|
||||
// Copyright (c) HashiCorp, Inc.
|
||||
// SPDX-License-Identifier: BUSL-1.1
|
||||
|
||||
package arguments
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/hashicorp/terraform/internal/tfdiags"
|
||||
)
|
||||
|
||||
func TestParseStateShow_valid(t *testing.T) {
|
||||
testCases := map[string]struct {
|
||||
args []string
|
||||
want *StateShow
|
||||
}{
|
||||
"address only": {
|
||||
[]string{"test_instance.foo"},
|
||||
&StateShow{
|
||||
StatePath: "",
|
||||
Address: "test_instance.foo",
|
||||
},
|
||||
},
|
||||
"with state path": {
|
||||
[]string{"-state=foobar.tfstate", "test_instance.foo"},
|
||||
&StateShow{
|
||||
StatePath: "foobar.tfstate",
|
||||
Address: "test_instance.foo",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for name, tc := range testCases {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
got, diags := ParseStateShow(tc.args)
|
||||
if len(diags) > 0 {
|
||||
t.Fatalf("unexpected diags: %v", diags)
|
||||
}
|
||||
if *got != *tc.want {
|
||||
t.Fatalf("unexpected result\n got: %#v\nwant: %#v", got, tc.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseStateShow_invalid(t *testing.T) {
|
||||
testCases := map[string]struct {
|
||||
args []string
|
||||
want *StateShow
|
||||
wantDiags tfdiags.Diagnostics
|
||||
}{
|
||||
"no arguments": {
|
||||
nil,
|
||||
&StateShow{
|
||||
StatePath: "",
|
||||
Address: "",
|
||||
},
|
||||
tfdiags.Diagnostics{
|
||||
tfdiags.Sourceless(
|
||||
tfdiags.Error,
|
||||
"Required argument missing",
|
||||
"Exactly one argument expected: the address of a resource instance to show.",
|
||||
),
|
||||
},
|
||||
},
|
||||
"too many arguments": {
|
||||
[]string{"test_instance.foo", "test_instance.bar"},
|
||||
&StateShow{
|
||||
StatePath: "",
|
||||
Address: "test_instance.foo",
|
||||
},
|
||||
tfdiags.Diagnostics{
|
||||
tfdiags.Sourceless(
|
||||
tfdiags.Error,
|
||||
"Required argument missing",
|
||||
"Exactly one argument expected: the address of a resource instance to show.",
|
||||
),
|
||||
},
|
||||
},
|
||||
"unknown flag": {
|
||||
[]string{"-boop"},
|
||||
&StateShow{
|
||||
StatePath: "",
|
||||
Address: "",
|
||||
},
|
||||
tfdiags.Diagnostics{
|
||||
tfdiags.Sourceless(
|
||||
tfdiags.Error,
|
||||
"Failed to parse command-line flags",
|
||||
"flag provided but not defined: -boop",
|
||||
),
|
||||
tfdiags.Sourceless(
|
||||
tfdiags.Error,
|
||||
"Required argument missing",
|
||||
"Exactly one argument expected: the address of a resource instance to show.",
|
||||
),
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for name, tc := range testCases {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
got, gotDiags := ParseStateShow(tc.args)
|
||||
if *got != *tc.want {
|
||||
t.Fatalf("unexpected result\n got: %#v\nwant: %#v", got, tc.want)
|
||||
}
|
||||
tfdiags.AssertDiagnosticsMatch(t, gotDiags, tc.wantDiags)
|
||||
})
|
||||
}
|
||||
}
|
||||
Loading…
Reference in new issue