Skip to content

Commit

Permalink
Rename Migration to File
Browse files Browse the repository at this point in the history
  • Loading branch information
minamijoyo committed Apr 20, 2022
1 parent d9e3410 commit 47b4aeb
Show file tree
Hide file tree
Showing 2 changed files with 54 additions and 49 deletions.
51 changes: 51 additions & 0 deletions migration/file.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
package migration

import (
"bytes"
"fmt"
"text/template"
)

// File is a type which is equivalent to tfmigrate.StateMigratorConfig of
// minamijoyo/tfmigrate.
// The current implementation doesn't encode migration actions to a file
// directly with gohcl, so we avoid to depend on tfmigrate's type and we define
// only what we need here.
type File struct {
// Dir is a working directory for executing terraform command.
Dir string
// Actions is a list of state action.
Actions []string
}

var migrationTemplate = `migration "state" "awsv4upgrade" {
actions = [
{{- range . }}
"{{ . }}",
{{- end }}
]
}
`

var compiledMigrationTemplate = template.Must(template.New("migration").Parse(migrationTemplate))

// AppendAction appends an action to migration.
func (f *File) AppendAction(action string) {
f.Actions = append(f.Actions, action)
}

// Render converts a state migration config to bytes
func (f *File) Render() ([]byte, error) {
// Encoding StateMigratorConfig directly with gohcl has some problems.
// An array contains multiple elements is output as one line. It's not readable
// for multiple actions. In additon, the default value is set explicitly, it's
// not only redundant but also increases cognitive load for user who isn't
// familiar with tfmigrate.
// So we use text/template to render a migration file.
var output bytes.Buffer
if err := compiledMigrationTemplate.Execute(&output, f.Actions); err != nil {
return nil, fmt.Errorf("failed to render migration file: %s", err)
}

return output.Bytes(), nil
}
52 changes: 3 additions & 49 deletions migration/migration.go
Original file line number Diff line number Diff line change
@@ -1,76 +1,30 @@
package migration

import (
"bytes"
"encoding/json"
"fmt"
"text/template"

tfjson "github.com/hashicorp/terraform-json"
"github.com/minamijoyo/tfedit/migration/schema"
_ "github.com/minamijoyo/tfedit/migration/schema/aws" // Register schema for aws
)

// Migration is a type which is equivalent to tfmigrate.StateMigratorConfig of
// minamijoyo/tfmigrate.
// The current implementation doesn't encode migration actions to a file
// directly with gohcl, so we avoid to depend on tfmigrate's type and we define
// only what we need here.
type Migration struct {
// Dir is a working directory for executing terraform command.
Dir string
// Actions is a list of state action.
Actions []string
}

var migrationTemplate = `migration "state" "awsv4upgrade" {
actions = [
{{- range . }}
"{{ . }}",
{{- end }}
]
}
`

var compiledMigrationTemplate = template.Must(template.New("migration").Parse(migrationTemplate))

// AppendAction appends an action to migration.
func (m *Migration) AppendAction(action string) {
m.Actions = append(m.Actions, action)
}

// Encode converts a state migration config to bytes
func (m *Migration) Encode() ([]byte, error) {
// Encoding StateMigratorConfig directly with gohcl has some problems.
// An array contains multiple elements is output as one line. It's not readable
// for multiple actions. In additon, the default value is set explicitly, it's
// not only redundant but also increases cognitive load for user who isn't
// familiar with tfmigrate.
// So we use text/template to render a migration file.
var output bytes.Buffer
if err := compiledMigrationTemplate.Execute(&output, m.Actions); err != nil {
return nil, fmt.Errorf("failed to render migration file: %s", err)
}

return output.Bytes(), nil
}

func Generate(planJSON []byte) ([]byte, error) {
var plan tfjson.Plan
if err := json.Unmarshal(planJSON, &plan); err != nil {
return nil, fmt.Errorf("failed to parse plan file: %s", err)
}

var migration Migration
var file File
for _, rc := range plan.ResourceChanges {
if rc.Change.Actions.Create() {
address := rc.Address
after := rc.Change.After.(map[string]interface{})
importID := schema.ImportID(rc.Type, after)
migrateAction := fmt.Sprintf("import %s %s", address, importID)
migration.AppendAction(migrateAction)
file.AppendAction(migrateAction)
}
}

return migration.Encode()
return file.Render()
}

0 comments on commit 47b4aeb

Please sign in to comment.