Skip to content
Merged
Show file tree
Hide file tree
Changes from 10 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
2 changes: 2 additions & 0 deletions cmd/plugin/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"fmt"
"os"

"github.com/mongodb-labs/atlas-cli-plugin-terraform/internal/cli/adv2new"
"github.com/mongodb-labs/atlas-cli-plugin-terraform/internal/cli/clu2adv"
"github.com/spf13/cobra"
)
Expand All @@ -15,6 +16,7 @@ func main() {
Aliases: []string{"tf"},
}
terraformCmd.AddCommand(clu2adv.Builder())
terraformCmd.AddCommand(adv2new.Builder())

completionOption := &cobra.CompletionOptions{
DisableDefaultCmd: true,
Expand Down
25 changes: 25 additions & 0 deletions internal/cli/adv2new/adv2new.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package adv2new

import (
"github.com/mongodb-labs/atlas-cli-plugin-terraform/internal/cli"
"github.com/mongodb-labs/atlas-cli-plugin-terraform/internal/convert"
"github.com/spf13/afero"
"github.com/spf13/cobra"
)

func Builder() *cobra.Command {
o := &cli.BaseOpts{
Fs: afero.NewOsFs(),
Convert: convert.AdvancedClusterToNew,
}
cmd := &cobra.Command{
Use: "advancedClusterToNew",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
Use: "advancedClusterToNew",
Use: "advancedClusterV2",

just for sanity, how would the full command look like?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

some equivalent examples to use it with names or aliases are:

atlas tf adv2new -f example.in.tf -o example.out.tf
atlas terraform advancedClusterToNew --file example.in.tf --output example.out.tf

# current cluster to adv_cluster command
atlas tf clu2adv -f example.in.tf -o example.out.tf
atlas terraform clusterToAdvancedCluster --file example.in.tf --output example.out.tf

you can also mix names and aliases in the same command

I like the convert command pattern name of xxxToyyy and alias x2y, maybe advancedClusterToV2 and adv2v2 ? (not convinced with so many 2, that's why i tried to avoid 2 in the command name).

Having this context, what command and alias do you think it's better?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@marcosuma let me know if it's ok that I keep the current name and alias at the moment and I merge the PR as it is, or you prefer to use a different alias and name

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not blocking this PR, but I think New and Latest quickly become obsolete or ambiguous, that's why ...ToV2 I like it more. 2v2 is not ideal, but that's also an alias so I am less concerned

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

that's fair, changed here: 32398ac

Short: "Convert advanced_cluster from provider version 1 to 2",
Long: "Convert a Terraform configuration from mongodbatlas_advanced_cluster in provider version 1.X.X (SDKv2)" +
" to version 2.X.X (TPF - Terraform Plugin Framework)",
Aliases: []string{"adv2new"},
RunE: o.RunE,
}
cli.SetupCommonFlags(cmd, o)
return cmd
}
30 changes: 15 additions & 15 deletions internal/cli/clu2adv/clu2adv.go
Original file line number Diff line number Diff line change
@@ -1,34 +1,34 @@
package clu2adv

import (
"github.com/mongodb-labs/atlas-cli-plugin-terraform/internal/cli"
"github.com/mongodb-labs/atlas-cli-plugin-terraform/internal/convert"
"github.com/mongodb-labs/atlas-cli-plugin-terraform/internal/flag"
"github.com/spf13/afero"
"github.com/spf13/cobra"
)

func Builder() *cobra.Command {
o := &opts{fs: afero.NewOsFs()}
o := &struct {
*cli.BaseOpts
includeMoved bool
}{
BaseOpts: &cli.BaseOpts{
Fs: afero.NewOsFs(),
},
}
o.Convert = func(config []byte) ([]byte, error) {
return convert.ClusterToAdvancedCluster(config, o.includeMoved)
}
cmd := &cobra.Command{
Use: "clusterToAdvancedCluster",
Short: "Convert cluster to advanced_cluster preview provider 2.0.0",
Long: "Convert a Terraform configuration from mongodbatlas_cluster to " +
"mongodbatlas_advanced_cluster preview provider 2.0.0",
Aliases: []string{"clu2adv"},
RunE: func(_ *cobra.Command, _ []string) error {
if err := o.PreRun(); err != nil {
return err
}
return o.Run()
},
RunE: o.RunE,
}
cmd.Flags().StringVarP(&o.file, flag.File, flag.FileShort, "", "input file")
_ = cmd.MarkFlagRequired(flag.File)
cmd.Flags().StringVarP(&o.output, flag.Output, flag.OutputShort, "", "output file")
_ = cmd.MarkFlagRequired(flag.Output)
cmd.Flags().BoolVarP(&o.replaceOutput, flag.ReplaceOutput, flag.ReplaceOutputShort, false,
"replace output file if exists")
cmd.Flags().BoolVarP(&o.watch, flag.Watch, flag.WatchShort, false,
"keeps the plugin running and watches the input file for changes")
cli.SetupCommonFlags(cmd, o.BaseOpts)
cmd.Flags().BoolVarP(&o.includeMoved, flag.IncludeMoved, flag.IncludeMovedShort, false,
"include moved blocks in the output file")
return cmd
Expand Down
97 changes: 0 additions & 97 deletions internal/cli/clu2adv/opts.go

This file was deleted.

130 changes: 130 additions & 0 deletions internal/cli/common.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
package cli
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nice re-use!


import (
"errors"
"fmt"

"github.com/fsnotify/fsnotify"
"github.com/mongodb-labs/atlas-cli-plugin-terraform/internal/file"
"github.com/mongodb-labs/atlas-cli-plugin-terraform/internal/flag"
"github.com/spf13/afero"
"github.com/spf13/cobra"
)

type ConvertFn func(config []byte) ([]byte, error)

// BaseOpts contains common functionality for CLI commands that convert files.
type BaseOpts struct {
Fs afero.Fs
Convert ConvertFn
File string
Output string
ReplaceOutput bool
Watch bool
}

// RunE is the entry point for the command.
func (o *BaseOpts) RunE(cmd *cobra.Command, args []string) error {
if err := o.preRun(); err != nil {
return err
}
return o.run()
}

// preRun validates the input and output files before running the command.
func (o *BaseOpts) preRun() error {
if err := file.MustExist(o.Fs, o.File); err != nil {
return err
}
if !o.ReplaceOutput {
return file.MustNotExist(o.Fs, o.Output)
}
return nil
}

// run executes the conversion and optionally watches for file changes.
func (o *BaseOpts) run() error {
if err := o.generateFile(false); err != nil {
return err
}
if o.Watch {
return o.watchFile()
}
return nil
}

// generateFile reads the input file, converts it, and writes the output.
func (o *BaseOpts) generateFile(allowParseErrors bool) error {
inConfig, err := afero.ReadFile(o.Fs, o.File)
if err != nil {
return fmt.Errorf("failed to read file %s: %w", o.File, err)
}

outConfig, err := o.Convert(inConfig)
if err != nil {
if allowParseErrors {
outConfig = []byte("# CONVERT ERROR: " + err.Error() + "\n\n")
outConfig = append(outConfig, inConfig...)
} else {
return err
}
}

if err := afero.WriteFile(o.Fs, o.Output, outConfig, 0o600); err != nil {
return fmt.Errorf("failed to write file %s: %w", o.Output, err)
}
return nil
}

// watchFile watches the input file for changes and regenerates the output.
func (o *BaseOpts) watchFile() error {
watcher, err := fsnotify.NewWatcher()
if err != nil {
return err
}
defer watcher.Close()

if err := watcher.Add(o.File); err != nil {
return err
}

for {
if err := o.waitForFileEvent(watcher); err != nil {
return err
}
}
}

// waitForFileEvent waits for file system events and regenerates the output file.
func (o *BaseOpts) waitForFileEvent(watcher *fsnotify.Watcher) error {
watcherError := errors.New("watcher has been closed")
select {
case event, ok := <-watcher.Events:
if !ok {
return watcherError
}
if event.Has(fsnotify.Write) {
if err := o.generateFile(true); err != nil {
return err
}
}
case err, ok := <-watcher.Errors:
if !ok {
return watcherError
}
return err
}
return nil
}

// SetupCommonFlags sets up the common flags used by all commands.
func SetupCommonFlags(cmd *cobra.Command, opts *BaseOpts) {
cmd.Flags().StringVarP(&opts.File, flag.File, flag.FileShort, "", "input file")
_ = cmd.MarkFlagRequired(flag.File)
cmd.Flags().StringVarP(&opts.Output, flag.Output, flag.OutputShort, "", "output file")
_ = cmd.MarkFlagRequired(flag.Output)
cmd.Flags().BoolVarP(&opts.ReplaceOutput, flag.ReplaceOutput, flag.ReplaceOutputShort, false,
"replace output file if exists")
cmd.Flags().BoolVarP(&opts.Watch, flag.Watch, flag.WatchShort, false,
"keeps the plugin running and watches the input file for changes")
}
14 changes: 14 additions & 0 deletions internal/convert/adv2new.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package convert

import "github.com/mongodb-labs/atlas-cli-plugin-terraform/internal/hcl"

// AdvancedClusterToNew transforms all mongodbatlas_advanced_cluster resource definitions in a
// Terraform configuration file from SDKv2 schema to TPF (Terraform Plugin Framework) schema.
// All other resources and data sources are left untouched.
func AdvancedClusterToNew(config []byte) ([]byte, error) {
parser, err := hcl.GetParser(config)
if err != nil {
return nil, err
}
return parser.Bytes(), nil
}
13 changes: 13 additions & 0 deletions internal/convert/adv2new_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package convert_test

import (
"testing"

"github.com/mongodb-labs/atlas-cli-plugin-terraform/internal/convert"
)

func TestAdvancedClusterToNew(t *testing.T) {
runConvertTests(t, "adv2new", func(testName string, inConfig []byte) ([]byte, error) {
return convert.AdvancedClusterToNew(inConfig)
})
}
File renamed without changes.
15 changes: 15 additions & 0 deletions internal/convert/clu2adv_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package convert_test

import (
"strings"
"testing"

"github.com/mongodb-labs/atlas-cli-plugin-terraform/internal/convert"
)

func TestClusterToAdvancedCluster(t *testing.T) {
runConvertTests(t, "clu2adv", func(testName string, inConfig []byte) ([]byte, error) {
includeMoved := strings.Contains(testName, "includeMoved")
return convert.ClusterToAdvancedCluster(inConfig, includeMoved)
})
}
Loading