Skip to content

feat: setup サブコマンドで認証 config を対話生成 (#30)#31

Merged
polidog merged 3 commits into
mainfrom
feat/30
Jun 27, 2026
Merged

feat: setup サブコマンドで認証 config を対話生成 (#30)#31
polidog merged 3 commits into
mainfrom
feat/30

Conversation

@polidog

@polidog polidog commented Jun 27, 2026

Copy link
Copy Markdown
Member

タスク

env-sync に新しいサブコマンド setup を追加し、認証 config ファイル(.env-sync.config.yaml / ~/.config/env-sync/config.yaml)を対話プロンプトで生成できるようにする。

完了条件

  • env-sync setup で対話プロンプトが起動し、Vercel / GitHub の設定有無・project_id・repo・token 入力方法を質問できる
  • 生成される YAML が AppConfig スキーマとして LoadAppConfig() で正しくパースできる
  • token はデフォルトで ${VERCEL_TOKEN} / ${GITHUB_TOKEN} 形式の環境変数参照で書き出される
  • デフォルトは .env-sync.config.yaml に出力し、--global で ~/.config/env-sync/config.yaml に出力される(XDG_CONFIG_HOME 尊重)
  • 既存ファイルがある場合 --force なしではエラーで停止し上書きしない
  • 生 token を平文で書く場合・--global 出力時はファイルが 0600 で作成される
  • 非対話環境(TTY なし)ではエラーで停止し案内を出す
  • printUsage() のサブコマンド一覧・オプション説明に setup が載っている
  • README に setup の説明が追記されている
  • 既存テストを含め go test ./... が通り、setup_test.go でテストが追加されている

動作確認

  • lint / build 通過 (go build ./...)
  • go test ./... がすべて green
  • go vet ./... でエラーなし

変更ファイル

  • internal/config/setup.go: RunSetup / ParseSetupFlags / BuildSetupYAML / WriteSetupFile / RunSetupWithReader を実装
  • internal/config/setup_test.go: YAML生成・出力先解決・上書き保護・token参照形式・パーミッションのテストを追加
  • cmd/env-sync/main.go: run() に setup 分岐を追加、printUsage() を更新
  • README.md: クイックスタートと setup 章を追加

🤖 Generated with Claude Code

https://claude.ai/code/session_01MUNfaHdh77j6ZEA2v8oieH

- internal/config/setup.go: RunSetup / ParseSetupFlags / BuildSetupYAML / WriteSetupFile を追加
  - 対話プロンプトで Vercel/GitHub の設定を収集し .env-sync.config.yaml を生成
  - token はデフォルトで \${VERCEL_TOKEN}/\${GITHUB_TOKEN} 環境変数参照形式
  - 生 token または --global 出力時はファイルを 0600 で作成
  - 非対話環境(TTY なし)ではエラーで停止し手書き方法を案内
- internal/config/setup_test.go: YAML 生成・出力先解決・上書き保護・token 参照形式のテストを追加
- cmd/env-sync/main.go: run() に setup 分岐を追加、printUsage() にサブコマンド一覧とオプション説明を追記
- README.md: setup サブコマンドの説明をクイックスタートと章として追記

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MUNfaHdh77j6ZEA2v8oieH

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

env-sync に新しい setup サブコマンドを追加し、対話プロンプトで認証 config(.env-sync.config.yaml / ~/.config/env-sync/config.yaml)を生成できるようにする PR です。既存の LoadAppConfig() スキーマに沿った YAML を生成し、README/usage 表示も更新しています。

Changes:

  • env-sync setup の対話フロー・YAML 生成・ファイル出力(上書き保護/出力先切替/パーミッション)を実装
  • setup の統合テスト(YAML生成、global 解決、上書き拒否、token 参照形式、パーミッション)を追加
  • CLI usage と README に setup の説明を追加

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 3 comments.

File Description
README.md クイックスタートに setup を追加し、対話生成の説明を追記
internal/config/setup.go setup サブコマンド本体(プロンプト、YAML生成、出力/権限/上書き制御)を追加
internal/config/setup_test.go setup のYAML/出力先/上書き保護/パーミッション等のテストを追加
cmd/env-sync/main.go setup サブコマンド分岐と usage 表示を追加

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread internal/config/setup.go
Comment on lines +69 to +84
if answers.UseVercel {
sb.WriteString("vercel:\n")
sb.WriteString(" token: ")
sb.WriteString(answers.VercelTokenRef)
sb.WriteString("\n")
if answers.VercelProjectID != "" {
sb.WriteString(" project_id: ")
sb.WriteString(answers.VercelProjectID)
sb.WriteString("\n")
}
if answers.VercelTeamID != "" {
sb.WriteString(" team_id: ")
sb.WriteString(answers.VercelTeamID)
sb.WriteString("\n")
}
}
Comment thread internal/config/setup.go
Comment on lines +86 to +96
if answers.UseGitHub {
sb.WriteString("github:\n")
sb.WriteString(" token: ")
sb.WriteString(answers.GitHubTokenRef)
sb.WriteString("\n")
if answers.GitHubRepo != "" {
sb.WriteString(" repo: ")
sb.WriteString(answers.GitHubRepo)
sb.WriteString("\n")
}
}
Comment thread internal/config/setup.go
Comment on lines +103 to +123
func WriteSetupFile(path, content string, perm os.FileMode, force bool) error {
flags := os.O_WRONLY | os.O_CREATE | os.O_TRUNC
if !force {
flags = os.O_WRONLY | os.O_CREATE | os.O_EXCL
}
f, err := os.OpenFile(path, flags, perm)
if err != nil {
if !force && os.IsExist(err) {
return fmt.Errorf("既に存在します: %s(上書きするには --force)", path)
}
return fmt.Errorf("config ファイルの書き込みに失敗: %s: %s", path, err)
}
if _, err := f.WriteString(content); err != nil {
f.Close()
return fmt.Errorf("config ファイルの書き込みに失敗: %s: %s", path, err)
}
if err := f.Close(); err != nil {
return fmt.Errorf("config ファイルの書き込みに失敗: %s: %s", path, err)
}
return nil
}
- BuildSetupYAML: ユーザー入力値を YAML シングルクォートスカラでエスケープ
  (:、#、$、改行などの特殊文字でも YAML が壊れない)
- WriteSetupFile: --force 上書き時も os.Chmod で perm を確実に適用
  (os.OpenFile の perm は新規作成時のみ有効なため既存ファイルに反映されなかった)
- TestWriteSetupFile_ForceOverwrite_Permissions を追加

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MUNfaHdh77j6ZEA2v8oieH

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 4 out of 4 changed files in this pull request and generated 5 comments.

Comment thread internal/config/setup.go
Comment on lines +61 to +63
// yamlSingleQuote は value を YAML シングルクォートスカラとしてエスケープして返す。
// シングルクォートスカラ内では ' のみ ” に置換すればよく、
// :、#、$、改行などの特殊文字を含む値でも安全に扱える。
Comment thread internal/config/setup.go Outdated
Comment on lines +288 to +292
line, err := reader.ReadString('\n')
if err != nil && err != io.EOF {
return "", fmt.Errorf("入力の読み込みに失敗: %w", err)
}
return strings.TrimRight(line, "\r\n"), nil
Comment thread internal/config/setup.go
return answers, err
}
if useEnvRef {
answers.VercelTokenRef = "${VERCEL_TOKEN}"
Comment thread internal/config/setup.go
return answers, err
}
if useEnvRef {
answers.GitHubTokenRef = "${GITHUB_TOKEN}"
Comment on lines +150 to +163
// AppConfig スキーマとして YAML パースできること
var cfg config.AppConfig
if err := yaml.Unmarshal([]byte(yamlText), &cfg); err != nil {
t.Fatalf("生成 YAML が AppConfig としてパースできない: %v\n%s", err, yamlText)
}
if cfg.Vercel.ProjectID != "prj_round" {
t.Errorf("Vercel.ProjectID = %q, want prj_round", cfg.Vercel.ProjectID)
}
if cfg.Vercel.TeamID != "team_round" {
t.Errorf("Vercel.TeamID = %q, want team_round", cfg.Vercel.TeamID)
}
if cfg.Vercel.Token != "${VERCEL_TOKEN}" {
t.Errorf("Vercel.Token = %q, want ${VERCEL_TOKEN}", cfg.Vercel.Token)
}
- yamlSingleQuote: コメントの誤記(" → '' シングルクォート2つ)を修正
- setupReadLine: TrimRight から TrimSpace に変更し、
  project_id/repo/token の前後空白混入を防止

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MUNfaHdh77j6ZEA2v8oieH

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@polidog polidog merged commit f89c05c into main Jun 27, 2026
1 of 2 checks passed
@polidog polidog deleted the feat/30 branch June 27, 2026 14:13
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.

2 participants