package cmd import ( "context" "errors" "fmt" "io" "os" "github.com/charmbracelet/huh" "github.com/charmbracelet/lipgloss" "github.com/google/go-github/v72/github" "github.com/spf13/cobra" ) const gitignoreFileName = ".gitignore" // newCmd represents the new command. var newCmd = &cobra.Command{ Use: "new", Short: "Create a new .gitignore file", Args: cobra.NoArgs, RunE: func(cmd *cobra.Command, args []string) error { return runNewCommand(cmd, args) }, } func init() { rootCmd.AddCommand(newCmd) } // runNewCommand is the handler for the 'new' command. // It retrieves available .gitignore templates from GitHub, prompts the user to select one, // and writes the selected template to a new .gitignore file. func runNewCommand(cmd *cobra.Command, _ []string) error { client, ok := getClientFromContext(cmd.Context()) if !ok { return errors.New("failed to get GitHub client from context") } templates, _, err := client.Gitignores.List(context.Background()) if err != nil { return fmt.Errorf("error listing gitignore templates: %w", err) } var selection string if err := runPrompt(templates, &selection); err != nil { return fmt.Errorf("error running selection prompt: %w", err) } content, _, err := client.Gitignores.Get(context.Background(), selection) if err != nil { return fmt.Errorf("error retrieving gitignore template '%s': %w", selection, err) } f, err := os.OpenFile(gitignoreFileName, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0o600) if err != nil { return fmt.Errorf("error opening file '%s': %w", gitignoreFileName, err) } defer f.Close() if err = commitGitignore(content, f); err != nil { return fmt.Errorf("error committing gitignore file: %w", err) } style := lipgloss.NewStyle(). Bold(true). Foreground(lipgloss.Color("#7D56F4")) // nolint: misspell fmt.Println(style.Render("Created"), selection, style.Render(".gitignore file ✓")) return nil } // runPrompt is a helper function to run the selection prompt for .gitignore templates. func runPrompt(templates []string, selection *string) error { var options []huh.Option[string] for _, template := range templates { options = append(options, huh.NewOption(template, template)) } selectionPrompt := huh.NewSelect[string](). Title("Select a .gitignore template"). Options(options...). Value(selection) if err := selectionPrompt.Run(); err != nil { return fmt.Errorf("error running selection prompt: %w", err) } return nil } // commitGitignore writes the content of the selected gitignore template to the .gitignore file. func commitGitignore(content *github.Gitignore, w io.Writer) error { if _, err := fmt.Fprintf(w, "# Generated by ignr-cli: github.com/onyx-and-iris/ignr-cli\n"); err != nil { return fmt.Errorf("error writing header to file '%s': %w", gitignoreFileName, err) } if _, err := fmt.Fprintf(w, "%s", *content.Source); err != nil { return fmt.Errorf("error writing to file '%s': %w", gitignoreFileName, err) } if _, err := fmt.Fprintf(w, "\n# End of ignr-cli\n"); err != nil { return fmt.Errorf("error writing footer to file '%s': %w", gitignoreFileName, err) } return nil }