feat: init and get command support json format output (#1453)

Signed-off-by: Syasusu <syasusu@163.com>
This commit is contained in:
Syasusu
2024-04-02 18:32:37 +02:00
committed by GitHub
parent 046beee664
commit bdab86962f
10 changed files with 325 additions and 72 deletions

View File

@@ -62,33 +62,67 @@ func TestInitProvidersInternal(t *testing.T) {
// This test should _not_ reach out anywhere because the "terraform"
// provider is internal to the core tofu binary.
fixturePath := filepath.Join("testdata", "tf-provider")
tf := e2e.NewBinary(t, tofuBin, fixturePath)
t.Run("output in human readable format", func(t *testing.T) {
fixturePath := filepath.Join("testdata", "tf-provider")
tf := e2e.NewBinary(t, tofuBin, fixturePath)
stdout, stderr, err := tf.Run("init")
if err != nil {
t.Errorf("unexpected error: %s", err)
}
stdout, stderr, err := tf.Run("init")
if err != nil {
t.Errorf("unexpected error: %s", err)
}
if stderr != "" {
t.Errorf("unexpected stderr output:\n%s", stderr)
}
if stderr != "" {
t.Errorf("unexpected stderr output:\n%s", stderr)
}
if !strings.Contains(stdout, "OpenTofu has been successfully initialized!") {
t.Errorf("success message is missing from output:\n%s", stdout)
}
if !strings.Contains(stdout, "OpenTofu has been successfully initialized!") {
t.Errorf("success message is missing from output:\n%s", stdout)
}
if strings.Contains(stdout, "Installing hashicorp/terraform") {
// Shouldn't have downloaded anything with this config, because the
// provider is built in.
t.Errorf("provider download message appeared in output:\n%s", stdout)
}
if strings.Contains(stdout, "Installing hashicorp/terraform") {
// Shouldn't have downloaded anything with this config, because the
// provider is built in.
t.Errorf("provider download message appeared in output:\n%s", stdout)
}
if strings.Contains(stdout, "Installing terraform.io/builtin/terraform") {
// Shouldn't have downloaded anything with this config, because the
// provider is built in.
t.Errorf("provider download message appeared in output:\n%s", stdout)
}
})
t.Run("output in machine readable format", func(t *testing.T) {
fixturePath := filepath.Join("testdata", "tf-provider")
tf := e2e.NewBinary(t, tofuBin, fixturePath)
stdout, stderr, err := tf.Run("init", "-json")
if err != nil {
t.Errorf("unexpected error: %s", err)
}
if stderr != "" {
t.Errorf("unexpected stderr output:\n%s", stderr)
}
// we can not check timestamp, so the sub string is not a valid json object
if !strings.Contains(stdout, `{"@level":"info","@message":"OpenTofu has been successfully initialized!","@module":"tofu.ui"`) {
t.Errorf("success message is missing from output:\n%s", stdout)
}
if strings.Contains(stdout, "Installing hashicorp/terraform") {
// Shouldn't have downloaded anything with this config, because the
// provider is built in.
t.Errorf("provider download message appeared in output:\n%s", stdout)
}
if strings.Contains(stdout, "Installing terraform.io/builtin/terraform") {
// Shouldn't have downloaded anything with this config, because the
// provider is built in.
t.Errorf("provider download message appeared in output:\n%s", stdout)
}
})
if strings.Contains(stdout, "Installing terraform.io/builtin/terraform") {
// Shouldn't have downloaded anything with this config, because the
// provider is built in.
t.Errorf("provider download message appeared in output:\n%s", stdout)
}
}
func TestInitProvidersVendored(t *testing.T) {
@@ -144,42 +178,85 @@ func TestInitProvidersLocalOnly(t *testing.T) {
// to the host "example.com", which is the placeholder domain we use in
// the test fixture.)
fixturePath := filepath.Join("testdata", "local-only-provider")
tf := e2e.NewBinary(t, tofuBin, fixturePath)
// If you run this test on a workstation with a plugin-cache directory
// configured, it will leave a bad directory behind and tofu init will
// not work until you remove it.
//
// To avoid this, we will "zero out" any existing cli config file.
tf.AddEnv("TF_CLI_CONFIG_FILE=")
t.Run("output in human readable format", func(t *testing.T) {
fixturePath := filepath.Join("testdata", "local-only-provider")
tf := e2e.NewBinary(t, tofuBin, fixturePath)
// If you run this test on a workstation with a plugin-cache directory
// configured, it will leave a bad directory behind and tofu init will
// not work until you remove it.
//
// To avoid this, we will "zero out" any existing cli config file.
tf.AddEnv("TF_CLI_CONFIG_FILE=")
// Our fixture dir has a generic os_arch dir, which we need to customize
// to the actual OS/arch where this test is running in order to get the
// desired result.
fixtMachineDir := tf.Path("terraform.d/plugins/example.com/awesomecorp/happycloud/1.2.0/os_arch")
wantMachineDir := tf.Path("terraform.d/plugins/example.com/awesomecorp/happycloud/1.2.0/", fmt.Sprintf("%s_%s", runtime.GOOS, runtime.GOARCH))
err := os.Rename(fixtMachineDir, wantMachineDir)
if err != nil {
t.Fatalf("unexpected error: %s", err)
}
// Our fixture dir has a generic os_arch dir, which we need to customize
// to the actual OS/arch where this test is running in order to get the
// desired result.
fixtMachineDir := tf.Path("terraform.d/plugins/example.com/awesomecorp/happycloud/1.2.0/os_arch")
wantMachineDir := tf.Path("terraform.d/plugins/example.com/awesomecorp/happycloud/1.2.0/", fmt.Sprintf("%s_%s", runtime.GOOS, runtime.GOARCH))
err := os.Rename(fixtMachineDir, wantMachineDir)
if err != nil {
t.Fatalf("unexpected error: %s", err)
}
stdout, stderr, err := tf.Run("init")
if err != nil {
t.Errorf("unexpected error: %s", err)
}
stdout, stderr, err := tf.Run("init")
if err != nil {
t.Errorf("unexpected error: %s", err)
}
if stderr != "" {
t.Errorf("unexpected stderr output:\n%s", stderr)
}
if stderr != "" {
t.Errorf("unexpected stderr output:\n%s", stderr)
}
if !strings.Contains(stdout, "OpenTofu has been successfully initialized!") {
t.Errorf("success message is missing from output:\n%s", stdout)
}
if !strings.Contains(stdout, "OpenTofu has been successfully initialized!") {
t.Errorf("success message is missing from output:\n%s", stdout)
}
if !strings.Contains(stdout, "- Installing example.com/awesomecorp/happycloud v1.2.0") {
t.Errorf("provider download message is missing from output:\n%s", stdout)
t.Logf("(this can happen if you have a conflicting copy of the plugin in one of the global plugin search dirs)")
}
})
t.Run("output in machine readable format", func(t *testing.T) {
fixturePath := filepath.Join("testdata", "local-only-provider")
tf := e2e.NewBinary(t, tofuBin, fixturePath)
// If you run this test on a workstation with a plugin-cache directory
// configured, it will leave a bad directory behind and tofu init will
// not work until you remove it.
//
// To avoid this, we will "zero out" any existing cli config file.
tf.AddEnv("TF_CLI_CONFIG_FILE=")
// Our fixture dir has a generic os_arch dir, which we need to customize
// to the actual OS/arch where this test is running in order to get the
// desired result.
fixtMachineDir := tf.Path("terraform.d/plugins/example.com/awesomecorp/happycloud/1.2.0/os_arch")
wantMachineDir := tf.Path("terraform.d/plugins/example.com/awesomecorp/happycloud/1.2.0/", fmt.Sprintf("%s_%s", runtime.GOOS, runtime.GOARCH))
err := os.Rename(fixtMachineDir, wantMachineDir)
if err != nil {
t.Fatalf("unexpected error: %s", err)
}
stdout, stderr, err := tf.Run("init", "-json")
if err != nil {
t.Errorf("unexpected error: %s", err)
}
if stderr != "" {
t.Errorf("unexpected stderr output:\n%s", stderr)
}
// we can not check timestamp, so the sub string is not a valid json object
if !strings.Contains(stdout, `{"@level":"info","@message":"OpenTofu has been successfully initialized!","@module":"tofu.ui"`) {
t.Errorf("success message is missing from output:\n%s", stdout)
}
if !strings.Contains(stdout, `{"@level":"info","@message":"- Installing example.com/awesomecorp/happycloud v1.2.0...","@module":"tofu.ui"`) {
t.Errorf("provider download message is missing from output:\n%s", stdout)
t.Logf("(this can happen if you have a conflicting copy of the plugin in one of the global plugin search dirs)")
}
})
if !strings.Contains(stdout, "- Installing example.com/awesomecorp/happycloud v1.2.0") {
t.Errorf("provider download message is missing from output:\n%s", stdout)
t.Logf("(this can happen if you have a conflicting copy of the plugin in one of the global plugin search dirs)")
}
}
func TestInitProvidersCustomMethod(t *testing.T) {
@@ -347,9 +424,21 @@ func TestInitProviderNotFound(t *testing.T) {
}
})
t.Run("registry provider not found output in json format", func(t *testing.T) {
stdout, _, err := tf.Run("init", "-no-color", "-json")
if err == nil {
t.Fatal("expected error, got success")
}
oneLineStdout := strings.ReplaceAll(stdout, "\n", " ")
if !strings.Contains(oneLineStdout, `"diagnostic":{"severity":"error","summary":"Failed to query available provider packages","detail":"Could not retrieve the list of available versions for provider hashicorp/nonexist: provider registry registry.opentofu.org does not have a provider named registry.opentofu.org/hashicorp/nonexist\n\nAll modules should specify their required_providers so that external consumers will get the correct providers when using a module. To see which modules are currently depending on hashicorp/nonexist, run the following command:\n tofu providers\n\nIf you believe this provider is missing from the registry, please submit a issue on the OpenTofu Registry https://github.com/opentofu/registry/issues/"},"type":"diagnostic"}`) {
t.Errorf("expected error message is missing from output:\n%s", stdout)
}
})
t.Run("local provider not found", func(t *testing.T) {
// The -plugin-dir directory must exist for the provider installer to search it.
pluginDir := tf.Path("empty")
pluginDir := tf.Path("empty-for-json")
if err := os.Mkdir(pluginDir, os.ModePerm); err != nil {
t.Fatal(err)
}
@@ -364,6 +453,23 @@ func TestInitProviderNotFound(t *testing.T) {
}
})
t.Run("local provider not found output in json format", func(t *testing.T) {
// The -plugin-dir directory must exist for the provider installer to search it.
pluginDir := tf.Path("empty")
if err := os.Mkdir(pluginDir, os.ModePerm); err != nil {
t.Fatal(err)
}
stdout, _, err := tf.Run("init", "-no-color", "-plugin-dir="+pluginDir, "-json")
if err == nil {
t.Fatal("expected error, got success")
}
if !strings.Contains(stdout, `"diagnostic":{"severity":"error","summary":"Failed to query available provider packages","detail":"Could not retrieve the list of available versions for provider hashicorp/nonexist: provider registry.opentofu.org/hashicorp/nonexist was not found in any of the search locations\n\n - `+pluginDir+`"},"type":"diagnostic"}`) {
t.Errorf("expected error message is missing from output:\n%s", stdout)
}
})
t.Run("special characters enabled", func(t *testing.T) {
_, stderr, err := tf.Run("init")
if err == nil {