Skip to content

Conversation

@ryo-matsuzaki-mdol
Copy link
Contributor

@ryo-matsuzaki-mdol ryo-matsuzaki-mdol commented Mar 30, 2022

Whats

Terraform Resources 変更レビューを助けるため、Terraform plan の JSON Output を人間がある程度読みやすい Markdown 形式に変換するためのシンプルなCLIツールを作成します。

How to confirm

ビルドの方法、使い方については README.md をご参照ください。

test_data ディレクトリ内に比較的シンプルなケースでの terraform plan 結果を同梱しており、
単体テストはこれらを使った table-driven-test を指向して実装してみました。

ここにある plan.txtterraform plan の標準出力(テキスト)であり、
expected.md と比べることでツールが出力する Markdown 自体の妥当性の検証が可能です。

実装できなかった(しなかった)こと

main.go Outdated
b := string(afterData)
diff := difflib.UnifiedDiff{
A: difflib.SplitLines(a),
B: difflib.SplitLines(b),
Copy link
Collaborator

Choose a reason for hiding this comment

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

[nits] 変数にせずに直接引数として渡してもいいかなと思います(aも同様)

Suggested change
B: difflib.SplitLines(b),
B: difflib.SplitLines(string(afterData)),

main.go Outdated
}
beforeData, err := json.MarshalIndent(report.Change.Before, "", " ")
if err != nil {
log.Fatal(err)
Copy link
Collaborator

Choose a reason for hiding this comment

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

エラーをそのまま出力するのではなく、 fmr.Errorf を使うなどしてMarshalIndentがreport.Change.Beforeを処理する時にエラーになった、ということが分かるようにエラーハンドリングをお願いします。
Goの標準パッケージではスタックトレースがないので、単純に受け取ったエラーを出力するだけだとどこで発生したエラーなのかを特定することが難しいからです。

Copy link
Collaborator

Choose a reason for hiding this comment

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

log.Fatal で都度エラー出力とプロセスを終了するよりかは関数の返値としてエラーを返すほうが関数から副作用を除去できてテストも書きやすくなります。明らかにreturnするよりもここでexitしたほうがよいのでなければreturnしてほしいです。

main_test.go Outdated
"github.com/pmezard/go-difflib/difflib"
)

func TestMain(t *testing.T) {
Copy link
Collaborator

Choose a reason for hiding this comment

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

TestMain 関数は testingパッケージに同名のものがあり、混合してややこしいので別名にしたほうがよさそうです。

Copy link
Contributor Author

Choose a reason for hiding this comment

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

こちらは gotests で自動生成された Test_render に改名しました!

main.go Outdated
"github.com/pmezard/go-difflib/difflib"
)

func listResourceNames(header string, report []*tfjson.ResourceChange) string {
Copy link
Collaborator

Choose a reason for hiding this comment

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

report よりは resourceChanges (ちょっと長いけど)や rcs のような引数名にした方が実態とマッチすると思います。

Copy link
Contributor Author

Choose a reason for hiding this comment

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

resourceChanges に改名しました!ただ、パッケージの組み替えなどを行った影響でこの関数自体は無くなっています。

main.go Outdated
}
return body
}
func createResourceDiffString(report *tfjson.ResourceChange) string {
Copy link
Collaborator

Choose a reason for hiding this comment

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

listResourceNamesと同様、引数名が実態とマッチしていないように感じました

Copy link
Contributor Author

Choose a reason for hiding this comment

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

こちらも同様に関数自体がなくなりました。

main.go Outdated
B: difflib.SplitLines(b),
Context: 3,
}
diffText, _ := difflib.GetUnifiedDiffString(diff)
Copy link
Collaborator

Choose a reason for hiding this comment

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

エラーハンドリングをお願いします

main_test.go Outdated
"Single Replace": "test_data/single_replace",
"All Change Types Mixed": "test_data/all_mixed",
"AWS Resource Changes": "test_data/aws_mixed",
}
Copy link
Collaborator

Choose a reason for hiding this comment

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

table driven testsですが、 https://github.com/cweill/gotests のフォーマットにあわせてもらってもよいでしょうか?いろんなエディタやIDEとの相性がよいので、明確な理由がなければgotestsに揃えたい気持ちがあります。

Copy link
Contributor Author

Choose a reason for hiding this comment

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

こちらは gotests で生成されたものに従ってみました。
gotests だと want をケース内に含んでいるのですが、このテストだと入力も出力も大きすぎるのでその辺は改変せざるを得ませんでした。
IDE的なメリットがどのくらい働いてくれるのか自分の環境だけだと自信が持てなかったで、改めて確認いただけますと幸いです!

main_test.go Outdated
os.Stdin = originStdin
os.Stdout = originStdout
}()
main()
Copy link
Collaborator

Choose a reason for hiding this comment

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

[IMO] 異常系のテストを書くことを考えると、mainを呼び出すよりはmainから呼ばれるexit codeを返す関数を用意してそれをテストでは呼ぶ方がいいかなと思います。

func main() {
  os.Exit(run())
}

func run() int {
    // 問題なく処理が終了した場合
    return 0

    // エラーの場合
    return 1
}

Copy link
Contributor Author

Choose a reason for hiding this comment

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

コメントいただいた main -> run という形はそのまま頂いてみました!
ただ、テスト対象としては標準入出力ではなく文字列を扱う Render という関数になりました。
その影響で、異常系のテストはケース内の wantErr で判断するようにしてみました!

@takaishi takaishi requested a review from okkez April 1, 2022 01:23
Copy link
Contributor

@okkez okkez left a comment

Choose a reason for hiding this comment

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

いくつかコメントしましたが、こういう小さいツールでも標準的な作法は守った方がよいと思います。

https://github.com/golang-standards/project-layout/blob/master/README_ja.md

README.md Outdated
Comment on lines 46 to 47
$ terraform show -json plan.tfplan > show.json
$ ./terraform-j2md < show.json
Copy link
Contributor

Choose a reason for hiding this comment

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

コマンドの実行例は terraform-j2md にパスが通っている前提で terraform show -json plan.tfplan | terraform-j2md でよいと思います。

@@ -0,0 +1,59 @@
### 2 to add, 1 to change, 2 to destroy.
Copy link
Contributor

Choose a reason for hiding this comment

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

Copy link
Contributor Author

Choose a reason for hiding this comment

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

頂いた標準的な作法にも従ってみて、 test/testdata にデータを配置するようにしてみました。
https://github.com/golang-standards/project-layout/blob/master/README_ja.md

main.go Outdated
}
func main() {
var plan tfjson.Plan
var body, diff string
Copy link
Contributor

Choose a reason for hiding this comment

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

body を文字列連結と Sprintf で組み立てていってますが、けっこうややこしいです。今後 terraform-json で resource drift のサポートが入ったときに修正が難しそうです。
https://pkg.go.dev/text/template などを使ってテンプレート化するといいのではないでしょうか。
💭 たぶん Ruby だったら ERB 使ってると思います。

Mustache 記法なので構造体を作ってはめ込むだけです。
テンプレートに渡す構造体を作る関数を切り出してテストすれば、もうちょっとテスト書きやすくなるのではと想像しています。

main_test.go Outdated
}
}

func RunCase(t *testing.T, inputFile string) string {
Copy link
Contributor

Choose a reason for hiding this comment

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

内部でしか使っていないので runCase だと思います。

Copy link
Contributor Author

Choose a reason for hiding this comment

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

標準入出力を無理くり置き換えてテストする必要がなくなったので、こちらの関数は無くなることになりました。

main_test.go Outdated
Comment on lines 61 to 62
originStdin := os.Stdin
originStdout := os.Stdout
Copy link
Contributor

Choose a reason for hiding this comment

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

[imo] テストで標準入出力を使うのは最終手段なので、標準入出力を使わない方法でテストできるように設計を見直した方がいいと思います。
💭 これもたぶん Ruby だったらやってないはず。

たとえば text/template を使うようにする前提だと以下のようになると思います。

  • できれば、テンプレートを差し替えできるようにしておく
  • テンプレートに与える構造体を作る関数
  • テンプレートをレンダリングして文字列を返す関数
  • main は ↑の関数を呼び出すだけ

みたいにすると、標準入出力を使ったテストをしなくて済むし、それぞれの関数をテストすれば main のテストも書かなくてよくなります。

Copy link
Contributor Author

Choose a reason for hiding this comment

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

具体的にコメントいただきありがとうございます!こちらは概ね適応してみたつもりです。
関数はそれぞれ分割した状態で、パッケージも分けてみました。
一部適応していないところがあるので、個別でコメントします。

できれば、テンプレートを差し替えできるようにしておく

テンプレートの差し替えを機能として作ると config 的な部分の実装も必要になりそうで、今回はベタ書きのままで進めてみたく思います!

それぞれの関数をテストすれば main のテストも書かなくてよくなります。

書きやすくなったのですが、時間がかかりそうで個別のテストを書いていないという状態です・・
最初にe2eめいたテストを書いてしまったのに引きずられすぎている気もちょっとしています。

ryo-matsuzaki-mdol and others added 3 commits April 4, 2022 13:52
- rename test_data directory
- fix testdata table to fit gotests format
- introduce `run`, `render` functions
- remove stdin/out mocking in test
- add tests for invalid inputs
yoshimura0725 and others added 6 commits April 5, 2022 11:13
    - introduce `constructor` functions
    - change error messages
    - rename some variables
Co-authored-by: ryo_matsuzaki <[email protected]>
- adjust line breaks
- introduces functions in template struct

Co-authored-by: Kaito Yoshimura <[email protected]>
- create cmd, internal packages
- split main.go to some packages

ref: https://github.com/golang-standards/project-layout/blob/master/README.md

Co-authored-by: Kaito Yoshimura <[email protected]>
@ryo-matsuzaki-mdol
Copy link
Contributor Author

レビューありがとうございます!少し時間がかかってしまいましたが、頂いたコメントに概ね適応しましたので改めてのレビューをお願いいたします! @okkez @takaishi

@ryo-matsuzaki-mdol
Copy link
Contributor Author

一つ出力の仕様について改変したところがあるので、書き置きします。
出力の先頭にあるサマリなのですが、沖本さんにもらったコメント (#3 (comment)) に影響を受けて Replace を個別にしてみました。

旧: 2 to add, 1 to change, 2 to destroy.
↓↓↓
新: 1 to add, 1 to change, 1 to destroy, 1 to replace.

元は terraform plan を実行した時のサマリと一致させるために add + destroy としていましただ、、差分出力の際には replace と記載されるので最初から replace として個別集計したほうがわかりやすいように考えたのでこうしてみました。

terraform plan と一致してる方が安心できるのでは?という印象もありますので、この改変については遠慮なくコメント頂けますと幸いです!

Copy link
Contributor

@okkez okkez left a comment

Choose a reason for hiding this comment

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

かなりよくなりましたが、パッケージ名や構造体の名前を実態に即した名前に変更して欲しいです。
テストコードは e2e テストっぽいものになっていて、これはこれでよいと思います。

"fmt"
"io"
"os"
"terraform-j2md/internal/template"
Copy link
Contributor

Choose a reason for hiding this comment

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

これたぶん template という名前で参照することになると思うのですが text/template と名前が似ていてややこしいので変えた方がよさそうです。

このパッケージはテンプレートではなくて定義したテンプレートを使って terrraform の plan の差分を markdown 形式に変換しているので、そういったことを表現した名前にするのがよさそうです。

Copy link
Contributor Author

Choose a reason for hiding this comment

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

抽象度が高いかもしれませんが、 converter という命名にしてみました。

"github.com/pmezard/go-difflib/difflib"
)

type PlanTemplate struct {
Copy link
Contributor

Choose a reason for hiding this comment

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

これはテンプレートじゃなくてテンプレートに使うデータを入れるものだと思うので名前を変えた方がよさそうです。

PlanDetails, PlanData, PlanInfo あたりでしょうか。

Copy link
Contributor Author

Choose a reason for hiding this comment

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

PlanData を頂いてみました!
究極的には Plan と命名できると良い気がしたのですが、 tfjson.Plan と一致してしまうとややこしそうですね・・

ReplacedNames []*tfjson.ResourceChange
ChangedResult []DiffTemplate
}
type DiffTemplate struct {
Copy link
Contributor

Choose a reason for hiding this comment

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

これもテンプレートじゃなくてテンプレートに使うデータを入れるものだと思うので名前を変えた方がよさそうです。

Copy link
Contributor Author

Choose a reason for hiding this comment

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

ResoucesChangeData と命名してみました!
Diffを出力する機能を持ってはいますが、データとしては tfjson.ResouceChange とほぼ同一という点からです。

func run() int {
input, err := io.ReadAll(os.Stdin)
if err != nil {
fmt.Printf("cannot read stdin: %v", err)
Copy link
Contributor

Choose a reason for hiding this comment

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

fmt.Errorf を使っているところもあるのでそろえた方がよさそうです。

Copy link
Contributor Author

Choose a reason for hiding this comment

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

すみません。この関数は main とほぼ同じ扱いで error を返さない作りとしたく、
それで fmt.Errorf の代わりに fmt.Printf を使ってエラーを出力させています。

ただ、このやり方が良いプラクティスなのかどうかはあまり分かっていないところはあります 🤔

Copy link
Collaborator

Choose a reason for hiding this comment

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

fmt.Fprintf を使ってstderrに出力するとよさそうです。

- rename 'template' module to 'converter'
- rename structs for template renderer
- store addresses instead of full resouce changes per change types

Co-authored-by: Kaito Yoshimura <[email protected]>
@ryo-matsuzaki-mdol
Copy link
Contributor Author

@okkez 迅速にレビューいただきありがとうございます!
頂いたコメントについてはほぼ対応してみましたので、またお手隙の際に見ていただけますと幸いです!

var plan tfjson.Plan
err := json.Unmarshal([]byte(input), &plan)
if err != nil {
return "", fmt.Errorf("invalid input: %w", err)
Copy link
Collaborator

Choose a reason for hiding this comment

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

引数で渡したデータがinvalidであるエラー以外が返ってくる可能性もあるので、別のメッセージにした方がよさそうです

return "", fmt.Errorf("invalid template text: %w", err)
}

var output bytes.Buffer
Copy link
Collaborator

Choose a reason for hiding this comment

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

Render関数内でoutput変数に書き出してからStringに変換して返し、run関数内で標準出力に書き出していますが、これはRender関数にio.Writerを渡すと綺麗に書けます。

func run() {
    err := Render(os.Stdout)
}

func Render(w io.Writer) error {
	if err := planTemplate.Execute(w, planData); err != nil {
		return "", fmt.Errorf("failed to render template: %w", err)
	}

        return nil
}

テストの時には bytes.Bufferの変数を渡して、関数実行後に変数に出力された内容をチェックすることができます。

got = bytes.Buffer{}
_, err = Render(string(input), &got)

if got.String() != string(expected) {

}

}
type ResourceChangeData struct {
ResourceChange *tfjson.ResourceChange
HeaderSuffix string
Copy link
Collaborator

Choose a reason for hiding this comment

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

HeaderSuffixはレンダリング時にActionの種類に応じて生成すると構造体に保持しなくてもよさそうです。
ResourceChangeDataにメソッドとして用意するか、
Funcsを使うことでtemplateにカスタムで関数を渡すことができるので、headerSuffixを返す関数を与えるかができます。

	funcMap := template.FuncMap{
		"headerSuffix": func(c *tfjson.ResourceChange) string {
			switch {
			case c.Change.Actions.Create():
				return "will be created"
			case c.Change.Actions.Update():
				return "will be updated in-place"
			case c.Change.Actions.Delete():
				return "will be destroyed"
			case c.Change.Actions.Replace():
				return "will be replaced"
			}
			return ""
		},
	}

	planTemplate, err := template.New("plan").Funcs(funcMap).Parse(planTemplateBody)

Copy link
Contributor

Choose a reason for hiding this comment

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

headerSuffixをResourceChangeDataにメソッドとして用意するように変更しました。
また、Backquoteを構造体に保持せずFuncMapでtemplateに渡すようにしました。

Change []string
Destroy []string
Replace []string
}
Copy link
Collaborator

Choose a reason for hiding this comment

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

Anonymous Structを作らず、PlanDataとなる変数をここで宣言して下の方のfor loopで直接PlanDataを更新すると構造体の数を一つ減らせてすっきりしそうです

}

func (d ResourceChangeData) GetUnifiedDiffString() (string, error) {
beforeData, err := json.MarshalIndent(d.ResourceChange.Change.Before, "", " ")
Copy link
Collaborator

Choose a reason for hiding this comment

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

[nits, imo] 変数名に Data はなくてもdiffで比較するbeforeだな、と分かるのでつけなくてもいいかなと思いました

func run() int {
input, err := io.ReadAll(os.Stdin)
if err != nil {
fmt.Printf("cannot read stdin: %v", err)
Copy link
Collaborator

Choose a reason for hiding this comment

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

fmt.Fprintf を使ってstderrに出力するとよさそうです。

</details>
{{end}}`

func Render(input string) (string, error) {
Copy link
Collaborator

Choose a reason for hiding this comment

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

converter パッケージにRenderがあるのは違和感を覚えました。

[IMO] converterからterraform にパッケージ名を変え、run()の中でPlanDataを作り、PlanDataに生やしたRenderメソッドを呼ぶと関数毎の責務がシンプルになるかなと思います。

	planData, err := terraform.NewPlanData(input)
	if err != nil {
		fmt.Printf("invalid plan data: %v", err)
		return 1
	}

	err = planData.Render(os.Stdout)
	if err != nil {
		fmt.Printf("cannot convert: %v", err)
		return 1
	}

Copy link
Contributor Author

Choose a reason for hiding this comment

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

converter パッケージはコメントいただいた通り terraform としました!
構造体の定義とレンダリングを行う go ファイルを別々にしていましたが、1つに統合させておりますー。

この影響で、テストに関しても NewPlanDataRender を別々に実施する形にしてみました。
NewPlanData のテストはパースできるか否かのみになっているのが少しわかりづらいかもしれません。

</details>
{{end}}`

func Render(input string) (string, error) {
Copy link
Collaborator

Choose a reason for hiding this comment

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

string型の引数を受け取ってバイト列にキャストしていますが、Renderの呼び出し側でバイト列をstringにキャストして渡しているので引数の型は[]byteでよいと思います。

"testing"
)

func Test_render(t *testing.T) {
Copy link
Collaborator

Choose a reason for hiding this comment

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

テスト、扱いやすくなって助かりました 👍

- rename package
- merge tmplate_renderer and plan_template
- use funcMap

Co-authored-by: ryo_matsuzaki <[email protected]>
@yoshimura0725
Copy link
Contributor

@takaishi レビューありがとうございます。
指摘された内容は全て修正しましたので、お手隙の際に見ていただけますと幸いです!


func (plan *PlanData) Render(w io.Writer) error {
funcMap := template.FuncMap{
"backquote": func() string {
Copy link
Contributor

Choose a reason for hiding this comment

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

バッククォート1つでも意味あるし、バッククォート3つ続けて書いてるので backquote という名前じゃないなぁ、と思って調べてみたら code fence と呼ぶのが common mark の仕様みたいです。
https://spec.commonmark.org/0.30/#code-fence

Copy link
Contributor

Choose a reason for hiding this comment

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

https://github.github.com/gfm/#fenced-code-blocks

GitHub flavored markdown でも同じでした。

}
tests := []struct {
name string
args args
Copy link
Contributor

Choose a reason for hiding this comment

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

[Q] args はどうして構造体になっているのでしょうか?いらないように見えます。

直接 testDataPath string にしても大丈夫そうに見えます。

Copy link
Contributor Author

Choose a reason for hiding this comment

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

個人的にも構造体が必須だとは考えていないのですが、このテストコードは gotests で半自動生成したものになっており、今回はそのガイドに従順に実装しています。
https://github.com/golang/go/wiki/TableDrivenTests

Copy link
Contributor Author

Choose a reason for hiding this comment

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

すみません、ガイドをよく見たら args が必須というわけではなさそうでした・・完全に勘違いしていました。
args、一度消してみようと思います。

Comment on lines 18 to 26
{name: "No Changes", args: args{testDataPath: "../../test/testdata/no_changes"}, wantErr: false},
{name: "Single Create", args: args{testDataPath: "../../test/testdata/single_add"}, wantErr: false},
{name: "Single Change", args: args{testDataPath: "../../test/testdata/single_change"}, wantErr: false},
{name: "Single Destroy", args: args{testDataPath: "../../test/testdata/single_destroy"}, wantErr: false},
{name: "Single Replace", args: args{testDataPath: "../../test/testdata/single_replace"}, wantErr: false},
{name: "All Change Types Mixed", args: args{testDataPath: "../../test/testdata/all_mixed"}, wantErr: false},
{name: "AWS Resource Changes", args: args{testDataPath: "../../test/testdata/aws_mixed"}, wantErr: false},
{name: "Invalid JSON input", args: args{testDataPath: "../../test/testdata/invalid_json"}, wantErr: true},
{name: "Invalid format input", args: args{testDataPath: "../../test/testdata/not_json"}, wantErr: true},
Copy link
Contributor

Choose a reason for hiding this comment

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

[imo] ../../test/testdata/ が固定なので共通化できそうです。
自分だったら以下のような関数を定義すると思います。

func testDataPath(name, suffix) string {
	return fmt.Sprintf("../../test/testdata/%s/&s", name, suffix)
}

そして tests のところも name だけ使うようにする気がします。
ディレクトリ名だとわかりづらいから name を付与したように見えるのでディレクトリ名も整理すると思います。

tests := []struct {
	name string
	wantErr bool
}{
	{name: "no_changes", wantErr: false},
....
}

Copy link
Contributor Author

Choose a reason for hiding this comment

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

頂いたコメント、とてもわかりやすかったのでほぼそのまま引用させていただきました!
テストケースのディレクトリ名は all_mixed aws_mixed が分かりにくい筆頭と思っていたので、これら2つだけ改名しています。

- rename backquote to codeFence
- remove args struct from test cases
- make utility function for test data path solving
- rename some test data directories

Co-authored-by: Kaito Yoshimura <[email protected]>
@ryo-matsuzaki-mdol
Copy link
Contributor Author

@okkez レビューいただきありがとうございます!
コメントいただいた分, [Q] でいただいた分も含めて残らず適応してみたつもりですので、改めて見ていただけますと幸いです!

Copy link
Contributor

@okkez okkez left a comment

Choose a reason for hiding this comment

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

よいと思います 👍

Copy link
Collaborator

@takaishi takaishi left a comment

Choose a reason for hiding this comment

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

1カ所だけ改善できそうな箇所に気づいたので、そこの修正だけ検討をお願いします!他はよさそうです〜!

"github.com/pmezard/go-difflib/difflib"
)

const planTemplateBody = `### {{.CreatedCount}} to add, {{.UpdatedCount}} to change, {{.DeletedCount}} to destroy, {{.ReplacedCount}} to replace.
Copy link
Collaborator

Choose a reason for hiding this comment

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

ここ、CreatedCountを使わずに {{ len .CreatedAddresses }} で同じ結果が得られるので、構造体の *Count フィールドはなくてもよさそうということに気がつきました。行の長さが長くなるので、lenの結果を変数にしてもよさそうです。

Copy link
Contributor

Choose a reason for hiding this comment

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

構造体の *Count フィールドをなくしてlenで出力するように変更しました。

@yoshimura0725
Copy link
Contributor

@takaishi レビューありがとうございます!
指摘された箇所を変更しましたので、お手隙の際にレビューをお願いします!

Copy link
Collaborator

@takaishi takaishi left a comment

Choose a reason for hiding this comment

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

LGTM!

@ryo-matsuzaki-mdol
Copy link
Contributor Author

レビューありがとうございます!マージいたします!

@ryo-matsuzaki-mdol ryo-matsuzaki-mdol merged commit ecf378a into master Apr 12, 2022
@takaishi takaishi deleted the feature/json2md branch April 12, 2022 05:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants