Skip to content
Open
Show file tree
Hide file tree
Changes from all 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
18 changes: 12 additions & 6 deletions array_attribute.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,21 +18,24 @@ var _ attributeChange = &ArrayAttributeChange{}

// IsArrayAttributeChangeLine returns true if the line is a valid attribute change
// This requires the line to start with "+", "-" or "~", not be followed with "resource" or "data", and ends with "[".
// Terraform may append ForcesReplacementComment after the opening bracket.
func IsArrayAttributeChangeLine(line string) bool {
line = strings.TrimSpace(line)
// validPrefix := strings.HasPrefix(line, "+") || strings.HasPrefix(line, "-") || strings.HasPrefix(line, "~")
validSuffix := strings.HasSuffix(line, "[") || IsOneLineEmptyArrayAttribute(line)
base := strings.TrimSpace(strings.TrimSuffix(line, ForcesReplacementComment))
validSuffix := strings.HasSuffix(base, "[") || IsOneLineEmptyArrayAttribute(line)
return validSuffix && !IsResourceChangeLine(line)
}

// IsArrayAttributeTerminator returns true if the line is "]" or "] -> null"
func IsArrayAttributeTerminator(line string) bool {
return strings.TrimSuffix(strings.TrimSpace(line), " -> null") == "]"
return strings.TrimSuffix(strings.TrimSpace(line), " -> null") == "]" || strings.TrimSuffix(strings.TrimSpace(line), " -> (known after apply)") == "]"
}

// IsOneLineEmptyArrayAttribute returns true if the line ends with a "[]"
func IsOneLineEmptyArrayAttribute(line string) bool {
return strings.HasSuffix(line, "[]")
line = strings.TrimSpace(line)
line = strings.TrimSuffix(line, ForcesReplacementComment)
return strings.HasSuffix(strings.TrimSpace(line), "[]")
}

// NewArrayAttributeChangeFromLine initializes an ArrayAttributeChange from a line containing an array attribute change
Expand All @@ -57,10 +60,13 @@ func NewArrayAttributeChangeFromLine(line string) (*ArrayAttributeChange, error)
UpdateType: DestroyResource,
}, nil
} else if strings.HasPrefix(line, "~") {
// replace
updateType := UpdateInPlaceResource
if strings.HasSuffix(strings.TrimSpace(line), ForcesReplacementComment) {
updateType = ForceReplaceResource
}
return &ArrayAttributeChange{
Name: attributeName,
UpdateType: UpdateInPlaceResource,
UpdateType: updateType,
}, nil
} else {
return &ArrayAttributeChange{
Expand Down
8 changes: 8 additions & 0 deletions array_attribute_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,14 @@ func TestNewArrayAttributeChangeFromLine(t *testing.T) {
UpdateType: UpdateInPlaceResource,
},
},
"attribute changed forces replacement": {
line: `~ array_test = [` + ForcesReplacementComment,
shouldError: false,
expected: &ArrayAttributeChange{
Name: "array_test",
UpdateType: ForceReplaceResource,
},
},
"attribute is unchanged": {
line: `attribute [`,
shouldError: false,
Expand Down
19 changes: 14 additions & 5 deletions attribute.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ const (
ATTRIBUTE_DEFINITON_DELIMITER = " = "
SENSITIVE_VALUE = "(sensitive value)"
COMPUTED_VALUE = "(known after apply)"
// ForcesReplacementComment is the suffix Terraform appends to attributes that trigger replace.
ForcesReplacementComment = " # forces replacement"
)

type attributeChange interface {
Expand Down Expand Up @@ -92,9 +94,9 @@ func NewAttributeChangeFromLine(line string) (*AttributeChange, error) {
// replace
updateType := UpdateInPlaceResource

if strings.HasSuffix(attribute[1], " # forces replacement") {
if strings.HasSuffix(attribute[1], ForcesReplacementComment) {
updateType = ForceReplaceResource
attribute[1] = strings.TrimSuffix(attribute[1], " # forces replacement")
attribute[1] = strings.TrimSuffix(attribute[1], ForcesReplacementComment)
}

values := strings.Split(attribute[1], ATTRIBUTE_CHANGE_DELIMITER)
Expand All @@ -112,11 +114,18 @@ func NewAttributeChangeFromLine(line string) (*AttributeChange, error) {
UpdateType: updateType,
}, nil
} else {
valStr := strings.TrimSpace(attribute[1])
updateType := NoOpResource
if strings.HasSuffix(valStr, ForcesReplacementComment) {
valStr = strings.TrimSpace(strings.TrimSuffix(valStr, ForcesReplacementComment))
updateType = ForceReplaceResource
}
conv := doTypeConversion(valStr)
return &AttributeChange{
Name: dequote(strings.TrimSpace(attribute[0])),
OldValue: doTypeConversion(attribute[1]),
NewValue: doTypeConversion(attribute[1]),
UpdateType: NoOpResource,
OldValue: conv,
NewValue: conv,
UpdateType: updateType,
}, nil
}
}
Expand Down
10 changes: 10 additions & 0 deletions attribute_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,16 @@ func TestNewAttributeChangeFromLine(t *testing.T) {
UpdateType: NoOpResource,
},
},
"unchanged attribute forces replacement": {
line: `id = "namespace-id"` + ForcesReplacementComment,
shouldError: false,
expected: &AttributeChange{
Name: "id",
OldValue: "namespace-id",
NewValue: "namespace-id",
UpdateType: ForceReplaceResource,
},
},
"resource line": {
line: `+ resource "type" "name" {`,
shouldError: true,
Expand Down
2 changes: 1 addition & 1 deletion heredoc_attribute.go
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ func NewHeredocAttributeChangeFromLine(line string) (*HeredocAttributeChange, er
} else if strings.HasPrefix(line, "~") {
// replace
updateType := UpdateInPlaceResource
if strings.HasSuffix(attribute[1], " # forces replacement") {
if strings.HasSuffix(attribute[1], ForcesReplacementComment) {
updateType = ForceReplaceResource
}

Expand Down
2 changes: 1 addition & 1 deletion jsonencode.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ func NewJSONEncodeAttributeChangeFromLine(line string) (*JSONEncodeAttributeChan
} else if strings.HasPrefix(line, "~") {
// replace
updateType := UpdateInPlaceResource
if strings.HasSuffix(attribute[1], " # forces replacement") {
if strings.HasSuffix(attribute[1], ForcesReplacementComment) {
updateType = ForceReplaceResource
}

Expand Down
18 changes: 12 additions & 6 deletions map_attribute.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,21 +15,24 @@ var _ attributeChange = &MapAttributeChange{}

// IsMapAttributeChangeLine returns true if the line is a valid attribute change
// This requires the line to start with "+", "-" or "~", not be followed with "resource" or "data", and ends with "{".
// Terraform may append ForcesReplacementComment after the opening brace.
func IsMapAttributeChangeLine(line string) bool {
line = strings.TrimSpace(line)
// validPrefix := strings.HasPrefix(line, "+") || strings.HasPrefix(line, "-") || strings.HasPrefix(line, "~")
validSuffix := strings.HasSuffix(line, "{") || IsOneLineEmptyMapAttribute(line)
base := strings.TrimSpace(strings.TrimSuffix(line, ForcesReplacementComment))
validSuffix := strings.HasSuffix(base, "{") || IsOneLineEmptyMapAttribute(line)
return validSuffix && !IsResourceChangeLine(line)
}

// IsMapAttributeTerminator returns true if the line is a "}" or "},"
func IsMapAttributeTerminator(line string) bool {
return strings.TrimSuffix(strings.TrimSuffix(strings.TrimSpace(line), ","), " -> null") == "}"
return strings.TrimSuffix(strings.TrimSuffix(strings.TrimSpace(line), ","), " -> null") == "}" || strings.TrimSuffix(strings.TrimSuffix(strings.TrimSpace(line), ","), " -> (known after apply)") == "}"
}

// IsOneLineEmptyMapAttribute returns true if the line ends with a "{}"
func IsOneLineEmptyMapAttribute(line string) bool {
return strings.HasSuffix(line, "{}")
line = strings.TrimSpace(line)
line = strings.TrimSuffix(line, ForcesReplacementComment)
return strings.HasSuffix(strings.TrimSpace(line), "{}")
}

// NewMapAttributeChangeFromLine initializes an AttributeChange from a line containing an attribute change
Expand All @@ -54,10 +57,13 @@ func NewMapAttributeChangeFromLine(line string) (*MapAttributeChange, error) {
UpdateType: DestroyResource,
}, nil
} else if strings.HasPrefix(line, "~") {
// replace
updateType := UpdateInPlaceResource
if strings.HasSuffix(strings.TrimSpace(line), ForcesReplacementComment) {
updateType = ForceReplaceResource
}
return &MapAttributeChange{
Name: attributeName,
UpdateType: UpdateInPlaceResource,
UpdateType: updateType,
}, nil
} else {
return &MapAttributeChange{
Expand Down
8 changes: 8 additions & 0 deletions map_attribute_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,14 @@ func TestNewMapAttributeChangeFromLine(t *testing.T) {
UpdateType: UpdateInPlaceResource,
},
},
"attribute changed forces replacement": {
line: `~ triggers = {` + ForcesReplacementComment,
shouldError: false,
expected: &MapAttributeChange{
Name: "triggers",
UpdateType: ForceReplaceResource,
},
},
"attribute is unchanged": {
line: `attribute {`,
shouldError: false,
Expand Down
Loading