Skip to content
Merged
Show file tree
Hide file tree
Changes from 14 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
54 changes: 54 additions & 0 deletions internal/command/arguments/get.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
// Copyright IBM Corp. 2014, 2026
// SPDX-License-Identifier: BUSL-1.1

package arguments

import (
"github.com/hashicorp/terraform/internal/tfdiags"
)

// Get represents the command-line arguments for the get command.
type Get struct {
// Vars are the variable-related flags (-var, -var-file).
Vars *Vars

// Update, if true, checks already-downloaded modules for available
// updates and installs the newest versions available.
Update bool

// TestDirectory is the Terraform test directory.
TestDirectory string
}

// ParseGet processes CLI arguments, returning a Get value and diagnostics.
// If errors are encountered, a Get value is still returned representing
// the best effort interpretation of the arguments.
func ParseGet(args []string) (*Get, tfdiags.Diagnostics) {
var diags tfdiags.Diagnostics
get := &Get{
Vars: &Vars{},
}

cmdFlags := extendedFlagSet("get", nil, nil, get.Vars)
cmdFlags.BoolVar(&get.Update, "update", false, "update")
cmdFlags.StringVar(&get.TestDirectory, "test-directory", "tests", "test-directory")

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) > 0 {
diags = diags.Append(tfdiags.Sourceless(
tfdiags.Error,
"Too many command line arguments",
"Expected no positional arguments. Did you mean to use -chdir?",
))
}

return get, diags
}
161 changes: 161 additions & 0 deletions internal/command/arguments/get_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,161 @@
// Copyright IBM Corp. 2014, 2026
// SPDX-License-Identifier: BUSL-1.1

package arguments

import (
"testing"

"github.com/google/go-cmp/cmp"
"github.com/google/go-cmp/cmp/cmpopts"

"github.com/hashicorp/terraform/internal/tfdiags"
)

func TestParseGet_valid(t *testing.T) {
testCases := map[string]struct {
args []string
want *Get
}{
"defaults": {
nil,
&Get{
Vars: &Vars{},
TestDirectory: "tests",
},
},
"update": {
[]string{"-update"},
&Get{
Vars: &Vars{},
Update: true,
TestDirectory: "tests",
},
},
"test-directory": {
[]string{"-test-directory", "custom-tests"},
&Get{
Vars: &Vars{},
TestDirectory: "custom-tests",
},
},
"all options": {
[]string{
"-update",
"-test-directory", "custom-tests",
},
&Get{
Vars: &Vars{},
Update: true,
TestDirectory: "custom-tests",
},
},
}

cmpOpts := cmp.Options{cmpopts.IgnoreUnexported(Vars{})}

for name, tc := range testCases {
t.Run(name, func(t *testing.T) {
got, diags := ParseGet(tc.args)
if len(diags) > 0 {
t.Fatalf("unexpected diags: %v", diags)
}
if diff := cmp.Diff(tc.want, got, cmpOpts); diff != "" {
t.Fatalf("unexpected result\n got: %#v\nwant: %#v", got, tc.want)
}
})
}
}

func TestParseGet_vars(t *testing.T) {
testCases := map[string]struct {
args []string
want []FlagNameValue
}{
"var": {
args: []string{"-var", "foo=bar"},
want: []FlagNameValue{
{Name: "-var", Value: "foo=bar"},
},
},
"var-file": {
args: []string{"-var-file", "cool.tfvars"},
want: []FlagNameValue{
{Name: "-var-file", Value: "cool.tfvars"},
},
},
"both": {
args: []string{
"-var", "foo=bar",
"-var-file", "cool.tfvars",
"-var", "boop=beep",
},
want: []FlagNameValue{
{Name: "-var", Value: "foo=bar"},
{Name: "-var-file", Value: "cool.tfvars"},
{Name: "-var", Value: "boop=beep"},
},
},
}

for name, tc := range testCases {
t.Run(name, func(t *testing.T) {
got, diags := ParseGet(tc.args)
if len(diags) > 0 {
t.Fatalf("unexpected diags: %v", diags)
}
if vars := got.Vars.All(); !cmp.Equal(vars, tc.want) {
t.Fatalf("unexpected vars: %#v", vars)
}
})
}
}

func TestParseGet_invalid(t *testing.T) {
testCases := map[string]struct {
args []string
want *Get
wantDiags tfdiags.Diagnostics
}{
"unknown flag": {
[]string{"-boop"},
&Get{
Vars: &Vars{},
TestDirectory: "tests",
},
tfdiags.Diagnostics{
tfdiags.Sourceless(
tfdiags.Error,
"Failed to parse command-line flags",
"flag provided but not defined: -boop",
),
},
},
"too many arguments": {
[]string{"foo", "bar"},
&Get{
Vars: &Vars{},
TestDirectory: "tests",
},
tfdiags.Diagnostics{
tfdiags.Sourceless(
tfdiags.Error,
"Too many command line arguments",
"Expected no positional arguments. Did you mean to use -chdir?",
),
},
},
}

cmpOpts := cmp.Options{cmpopts.IgnoreUnexported(Vars{})}

for name, tc := range testCases {
t.Run(name, func(t *testing.T) {
got, gotDiags := ParseGet(tc.args)
if diff := cmp.Diff(tc.want, got, cmpOpts); diff != "" {
t.Fatalf("unexpected result\n got: %#v\nwant: %#v", got, tc.want)
}
tfdiags.AssertDiagnosticsMatch(t, gotDiags, tc.wantDiags)
})
}
}
6 changes: 5 additions & 1 deletion internal/command/arguments/graph.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@ type Graph struct {

// Plan is the path to a saved plan file to render as a graph.
Plan string

// Vars are the variable-related flags (-var, -var-file).
Vars *Vars
}

// ParseGraph processes CLI arguments, returning a Graph value and errors.
Expand All @@ -33,9 +36,10 @@ func ParseGraph(args []string) (*Graph, tfdiags.Diagnostics) {
var diags tfdiags.Diagnostics
graph := &Graph{
ModuleDepth: -1,
Vars: &Vars{},
}

cmdFlags := defaultFlagSet("graph")
cmdFlags := extendedFlagSet("graph", nil, nil, graph.Vars)
cmdFlags.BoolVar(&graph.DrawCycles, "draw-cycles", false, "draw-cycles")
cmdFlags.StringVar(&graph.GraphType, "type", "", "type")
cmdFlags.IntVar(&graph.ModuleDepth, "module-depth", -1, "module-depth")
Expand Down
Loading