Skip to content

feat: add safer CLI cleanup modes#479

Open
Goryudyuma wants to merge 3 commits into
mainfrom
codex/cli-safety-and-docs
Open

feat: add safer CLI cleanup modes#479
Goryudyuma wants to merge 3 commits into
mainfrom
codex/cli-safety-and-docs

Conversation

@Goryudyuma
Copy link
Copy Markdown
Member

codexに「いい感じにして」って投げたらこうなったんだが、あってるんだろうか・・・

@dev-hato-app dev-hato-app Bot added this to task list May 15, 2026
@github-project-automation github-project-automation Bot moved this to In Progress in task list May 15, 2026
@github-actions
Copy link
Copy Markdown
Contributor

Super-linter summary

Language Validation result
BASH Pass ✅
BASH_EXEC Pass ✅
BIOME_LINT Pass ✅
CHECKOV Pass ✅
GITHUB_ACTIONS Pass ✅
GITHUB_ACTIONS_ZIZMOR Pass ✅
GITLEAKS Pass ✅
GIT_MERGE_CONFLICT_MARKERS Pass ✅
GO_MODULES Fail ❌
GO_RELEASER Pass ✅
JSCPD Fail ❌
JSON Pass ✅
JSON_PRETTIER Pass ✅
MARKDOWN Pass ✅
MARKDOWN_PRETTIER Pass ✅
NATURAL_LANGUAGE Pass ✅
PRE_COMMIT Pass ✅
RENOVATE Pass ✅
SHELL_SHFMT Pass ✅
SPELL_CODESPELL Pass ✅
TRIVY Pass ✅
YAML Pass ✅
YAML_PRETTIER Pass ✅

Super-linter detected linting errors

For more information, see the GitHub Actions workflow run

Powered by Super-linter

GO_MODULES
../../../github/workspace/main.go:192:12: shadow: declaration of "err" shadows declaration at line 165 (govet)
		pathKey, err := uniquePathKey(filePath)
		         ^
1 issues:
* govet: 1
JSCPD
Clone found (go):
 - /github/workspace/main_test.go [270:4 - 278:12] (8 lines, 72 tokens)
   /github/workspace/main_test.go [239:40 - 247:16]

Clone found (go):
 - /github/workspace/main_test.go [270:4 - 278:12] (8 lines, 72 tokens)
   /github/workspace/main_test.go [239:40 - 247:16]

 270 │ 239 │ )
 271 │ 240 │ 	require.Contains(t, stdout.String(), filePath)
 272 │ 241 │
 273 │ 242 │ 	got, readErr := os.ReadFile(filePath)
 274 │ 243 │ 	require.NoError(t, readErr)
 275 │ 244 │ 	require.Equal(t, string(input), string(got))
 276 │ 245 │ }
 277 │ 246 │
 278 │ 247 │ func Test_tfrbac

Found 1 clones.
Error: ERROR: jscpd found too many duplicates (0.59%) over threshold (0%)
    at ThresholdReporter.report (/node_modules/@jscpd/finder/dist/index.js:615:13)
    at /node_modules/@jscpd/finder/dist/index.js:109:18
    at Array.forEach (<anonymous>)
    at /node_modules/@jscpd/finder/dist/index.js:108:22
    at async /node_modules/jscpd/dist/bin/jscpd.js:9:5ERROR: jscpd found too many duplicates (0.59%) over threshold (0%)

@github-actions
Copy link
Copy Markdown
Contributor

Super-linter summary

Language Validation result
BASH Pass ✅
BASH_EXEC Pass ✅
BIOME_LINT Pass ✅
CHECKOV Pass ✅
GITHUB_ACTIONS Pass ✅
GITHUB_ACTIONS_ZIZMOR Pass ✅
GITLEAKS Pass ✅
GIT_MERGE_CONFLICT_MARKERS Pass ✅
GO_MODULES Fail ❌
GO_RELEASER Pass ✅
JSCPD Fail ❌
JSON Pass ✅
JSON_PRETTIER Pass ✅
MARKDOWN Pass ✅
MARKDOWN_PRETTIER Pass ✅
NATURAL_LANGUAGE Pass ✅
PRE_COMMIT Pass ✅
RENOVATE Pass ✅
SHELL_SHFMT Pass ✅
SPELL_CODESPELL Pass ✅
TRIVY Pass ✅
YAML Pass ✅
YAML_PRETTIER Pass ✅

Super-linter detected linting errors

For more information, see the GitHub Actions workflow run

Powered by Super-linter

GO_MODULES
../../../github/workspace/main.go:192:12: shadow: declaration of "err" shadows declaration at line 165 (govet)
		pathKey, err := uniquePathKey(filePath)
		         ^
1 issues:
* govet: 1
JSCPD
Clone found (go):
 - /github/workspace/main_test.go [270:4 - 278:12] (8 lines, 72 tokens)
   /github/workspace/main_test.go [239:40 - 247:16]

Clone found (go):
 - /github/workspace/main_test.go [270:4 - 278:12] (8 lines, 72 tokens)
   /github/workspace/main_test.go [239:40 - 247:16]

 270 │ 239 │ )
 271 │ 240 │ 	require.Contains(t, stdout.String(), filePath)
 272 │ 241 │
 273 │ 242 │ 	got, readErr := os.ReadFile(filePath)
 274 │ 243 │ 	require.NoError(t, readErr)
 275 │ 244 │ 	require.Equal(t, string(input), string(got))
 276 │ 245 │ }
 277 │ 246 │
 278 │ 247 │ func Test_tfrbac

Found 1 clones.
Error: ERROR: jscpd found too many duplicates (0.59%) over threshold (0%)
    at ThresholdReporter.report (/node_modules/@jscpd/finder/dist/index.js:615:13)
    at /node_modules/@jscpd/finder/dist/index.js:109:18
    at Array.forEach (<anonymous>)
    at /node_modules/@jscpd/finder/dist/index.js:108:22
    at async /node_modules/jscpd/dist/bin/jscpd.js:9:5ERROR: jscpd found too many duplicates (0.59%) over threshold (0%)

@github-actions
Copy link
Copy Markdown
Contributor

Super-linter summary

Language Validation result
BASH Pass ✅
BASH_EXEC Pass ✅
BIOME_LINT Pass ✅
CHECKOV Pass ✅
GITHUB_ACTIONS Pass ✅
GITHUB_ACTIONS_ZIZMOR Pass ✅
GITLEAKS Pass ✅
GIT_MERGE_CONFLICT_MARKERS Pass ✅
GO_MODULES Pass ✅
GO_RELEASER Pass ✅
JSCPD Pass ✅
JSON Pass ✅
JSON_PRETTIER Pass ✅
MARKDOWN Pass ✅
MARKDOWN_PRETTIER Pass ✅
NATURAL_LANGUAGE Pass ✅
PRE_COMMIT Pass ✅
RENOVATE Pass ✅
SHELL_SHFMT Pass ✅
SPELL_CODESPELL Pass ✅
TRIVY Pass ✅
YAML Pass ✅
YAML_PRETTIER Pass ✅

All files and directories linted successfully

For more information, see the GitHub Actions workflow run

Powered by Super-linter

Comment thread main.go
return strings.Join(*f, ",")
}

func (f *stringSliceFlag) Set(value string) error {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

📝 flags.Var の引数の型に合わせている。

Comment thread main.go
Comment on lines +72 to +74
fmt.Fprintln(os.Stderr, err)
fmt.Fprintln(os.Stderr)
fmt.Fprint(os.Stderr, usage())
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

errorを処理していないようです。

Comment thread main.go
}

if err := run(cfg); err != nil {
fmt.Fprintln(os.Stderr, err)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

errorを処理していないようです。

Comment thread main.go
return false, errors.Wrap(diags, "parse terraform file")
}

ret := tfrbac(file.Body()).Bytes()
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

これより前に file のnilチェックを入れた方が良さそうです。

Comment thread main.go
}

if showVersion {
fmt.Fprintln(os.Stdout, version)
Copy link
Copy Markdown
Member

@massongit massongit May 16, 2026

Choose a reason for hiding this comment

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

Suggested change
fmt.Fprintln(os.Stdout, version)
println(version)

println で良さそう。

Comment thread main.go
const terraformDir = "./" //TODO: あとで引数で弄れるようにしたい
func parseConfig(args []string, stdout io.Writer) (cfg config, showVersion bool, parseErr error) {
cfg = config{
excludeDirs: append([]string(nil), defaultExcludedDirs...),
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
excludeDirs: append([]string(nil), defaultExcludedDirs...),
excludeDirs: append([]string{}, defaultExcludedDirs...),

個人的にはこの方が好みかも。

Comment thread main.go
cfg.stdout = io.Discard
}
if len(cfg.excludeDirs) == 0 {
cfg.excludeDirs = append([]string(nil), defaultExcludedDirs...)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
cfg.excludeDirs = append([]string(nil), defaultExcludedDirs...)
cfg.excludeDirs = append([]string{}, defaultExcludedDirs...)

個人的にはこの方が好みかも。

Comment thread main.go
Comment on lines +117 to +125
if cfg.stdout == nil {
cfg.stdout = io.Discard
}
if len(cfg.excludeDirs) == 0 {
cfg.excludeDirs = append([]string(nil), defaultExcludedDirs...)
}
if len(cfg.targets) == 0 {
cfg.targets = []string{"."}
}
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

この辺は parseConfig と処理が被っている感じがあるので、この辺は削除するか、初期化のメソッドを用意して、それをここと parseConfig から呼び出す形にすると良さそう。

Comment thread main.go
Comment on lines -140 to -144
i++ // 後ろに改行がある場合はそれを削除
i++
} else if endTokenPos-2 > startTokenPos &&
tokens[endTokenPos-1].Type == hclsyntax.TokenNewline &&
tokens[endTokenPos-2].Type == hclsyntax.TokenNewline {
endTokenPos-- // 後ろに改行はないけど、上に二つ以上改行がある場合、一つ削除
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

このコメントはあっても良いかなぁ、と。

Comment thread main.go
Comment on lines +337 to +351
wf, err := root.OpenFile(relPath, os.O_WRONLY|os.O_TRUNC, perm)
if err != nil {
return errors.Wrap(err, "open file for write")
}
defer func() {
if closeErr := wf.Close(); closeErr != nil {
err = errors.Join(err, errors.Wrap(closeErr, "close file"))
}
}()

if _, err := wf.Write(src); err != nil {
return errors.Wrap(err, "write file")
}

return nil
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

📝 以下相当。

tfrbac/main.go

Lines 68 to 82 in 77cf704

wf, err := root.OpenFile(relPath, os.O_WRONLY|os.O_TRUNC, info.Mode().Perm())
if err != nil {
return errors.Wrap(err, "Error on OpenFile")
}
defer func(wf *os.File) {
if closeErr := wf.Close(); closeErr != nil {
err = errors.Join(err, errors.Wrap(closeErr, "Error on Close"))
}
}(wf)
if _, err = wf.Write(ret.Bytes()); err != nil {
return errors.Wrap(err, "Error on Write")
}
return nil

Comment thread main.go
Comment on lines +288 to +298
src, err := readTFFile(root, relPath)
if err != nil {
return false, errors.Wrap(err, "read terraform file")
}

file, diags := hclwrite.ParseConfig(src, displayPath, hcl.InitialPos)
if diags.HasErrors() {
return false, errors.Wrap(diags, "parse terraform file")
}

ret := tfrbac(file.Body()).Bytes()
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

📝 以下相当。

tfrbac/main.go

Lines 55 to 66 in 77cf704

src, err := readTFFile(root, relPath)
if err != nil {
return errors.Wrap(err, "Error on readTFFile")
}
file, diags := hclwrite.ParseConfig(src, filePath, hcl.InitialPos)
if diags.HasErrors() {
return errors.Wrap(diags, "Error on hclwrite.ParseConfig")
}
body := file.Body()
ret := tfrbac(body)

Comment thread main.go
Comment on lines +201 to +204
relPath, relErr := filepath.Rel(target, filePath)
if relErr != nil {
return errors.Wrap(relErr, "build relative path")
}
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

📝 以下相当。

tfrbac/main.go

Lines 50 to 53 in 77cf704

relPath, err := filepath.Rel(terraformDir, filePath)
if err != nil {
return errors.Wrap(err, "Error on filepath.Rel")
}

Comment thread main.go
Comment on lines +188 to 190
if !strings.HasSuffix(entry.Name(), ".tf") {
return nil
}
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

📝 以下相当。

tfrbac/main.go

Lines 45 to 48 in 77cf704

// '.tf' 拡張子でなければスキップ
if !strings.HasSuffix(info.Name(), ".tf") {
return nil
}

Comment thread main.go
Comment on lines 177 to 179
if walkErr != nil {
return errors.Wrap(walkErr, "Error on filepath.Walk")
return errors.Wrap(walkErr, "walk directory")
}
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

📝 以下相当。

tfrbac/main.go

Lines 41 to 43 in 77cf704

if walkErr != nil {
return errors.Wrap(walkErr, "Error on filepath.Walk")
}

Comment thread main.go
Comment on lines +166 to +174
root, err := os.OpenRoot(target)
if err != nil {
return errors.Wrap(err, "Error on os.OpenRoot")
return 0, errors.Wrap(err, "open root")
}
defer func(root *os.Root) {
defer func() {
if closeErr := root.Close(); closeErr != nil {
err = errors.Join(err, errors.Wrap(closeErr, "Error on Close"))
resultErr = errors.Join(resultErr, errors.Wrap(closeErr, "close root"))
}
}(root)
}()
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

📝 以下相当。

tfrbac/main.go

Lines 30 to 38 in 77cf704

root, err := os.OpenRoot(terraformDir)
if err != nil {
return errors.Wrap(err, "Error on os.OpenRoot")
}
defer func(root *os.Root) {
if closeErr := root.Close(); closeErr != nil {
err = errors.Join(err, errors.Wrap(closeErr, "Error on Close"))
}
}(root)

Comment thread main.go
Comment on lines +89 to +90
func parseConfig(args []string, stdout io.Writer) (cfg config, showVersion bool, parseErr error) {
cfg = config{
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
func parseConfig(args []string, stdout io.Writer) (cfg config, showVersion bool, parseErr error) {
cfg = config{
func parseConfig(args []string, stdout io.Writer) (config, bool, error) {
cfg := config{

戻り値の名前は定義しなくて良い気がする。

Comment thread main.go
Comment on lines +239 to +247
root, err := os.OpenRoot(filepath.Dir(target))
if err != nil {
return 0, errors.Wrap(err, "open file root")
}
defer func() {
if closeErr := root.Close(); closeErr != nil {
err = errors.Join(err, errors.Wrap(closeErr, "close file root"))
}
}()
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

📝 以下相当。

tfrbac/main.go

Lines 30 to 38 in 77cf704

root, err := os.OpenRoot(terraformDir)
if err != nil {
return errors.Wrap(err, "Error on os.OpenRoot")
}
defer func(root *os.Root) {
if closeErr := root.Close(); closeErr != nil {
err = errors.Join(err, errors.Wrap(closeErr, "Error on Close"))
}
}(root)

Comment thread main.go
}()

err = filepath.Walk(terraformDir, func(filePath string, info os.FileInfo, walkErr error) (err error) {
err = filepath.WalkDir(target, func(filePath string, entry fs.DirEntry, walkErr error) error {
Copy link
Copy Markdown
Member

@massongit massongit May 16, 2026

Choose a reason for hiding this comment

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

filepathfilePath は紛らわしいので、 filePath を変えても良いかも。
参考: dev-hato/hato-bot-go#363

Comment thread main.go
return errors.Wrap(err, "Error on readTFFile")
pathKey, pathErr := uniquePathKey(filePath)
if pathErr != nil {
return pathErr
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
return pathErr
return errors.Wrap(pathErr, "uniquePathKey")

pathErr をWrapしても良さそう。

Comment thread main.go
return errors.Wrap(err, "Error on Write")
changed, processErr := processTFFile(root, relPath, filePath, info.Mode().Perm(), cfg)
if processErr != nil {
return processErr
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
return processErr
return errors.Wrap(processErr, "processTFFile")

processErr をWrapしても良さそう。

Comment thread main.go
pathKey, err := uniquePathKey(target)
if err != nil {
return errors.Wrap(err, "Error walking through Terraform directory")
return 0, err
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
return 0, err
return 0, errors.Wrap(err, "uniquePathKey")

uniquePathKey をWrapしても良さそう。

Comment thread main.go

changed, err := processTFFile(root, filepath.Base(target), target, perm, cfg)
if err != nil {
return 0, err
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
return 0, err
return 0, errors.Wrap(err, "processTFFile")

processTFFile をWrapしても良さそう。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: In Progress

Development

Successfully merging this pull request may close these issues.

2 participants