| | | 1 | | package prompt |
| | | 2 | | |
| | | 3 | | import ( |
| | | 4 | | "bufio" |
| | | 5 | | "fmt" |
| | | 6 | | "io" |
| | | 7 | | "os" |
| | | 8 | | "strings" |
| | | 9 | | |
| | | 10 | | "github.com/jedi-knights/go-semantic-release/internal/ports" |
| | | 11 | | ) |
| | | 12 | | |
| | | 13 | | // Compile-time interface compliance check. |
| | | 14 | | var _ ports.Prompter = (*TerminalPrompter)(nil) |
| | | 15 | | |
| | | 16 | | // TerminalPrompter prompts the user via stdin/stdout. |
| | | 17 | | type TerminalPrompter struct { |
| | | 18 | | reader io.Reader |
| | | 19 | | writer io.Writer |
| | | 20 | | } |
| | | 21 | | |
| | | 22 | | // NewTerminalPrompter creates a prompter that reads from stdin and writes to stdout. |
| | | 23 | | func NewTerminalPrompter() *TerminalPrompter { |
| | | 24 | | return &TerminalPrompter{reader: os.Stdin, writer: os.Stdout} |
| | | 25 | | } |
| | | 26 | | |
| | | 27 | | // NewTerminalPrompterWithIO creates a prompter with custom reader/writer (for testing). |
| | | 28 | | func NewTerminalPrompterWithIO(r io.Reader, w io.Writer) *TerminalPrompter { |
| | | 29 | | return &TerminalPrompter{reader: r, writer: w} |
| | | 30 | | } |
| | | 31 | | |
| | | 32 | | // Confirm asks the user a yes/no question and returns their answer. |
| | 7 | 33 | | func (p *TerminalPrompter) Confirm(message string) (bool, error) { |
| | 0 | 34 | | if _, err := fmt.Fprintf(p.writer, "%s [y/N] ", message); err != nil { |
| | 0 | 35 | | return false, err |
| | 0 | 36 | | } |
| | | 37 | | |
| | 7 | 38 | | scanner := bufio.NewScanner(p.reader) |
| | 1 | 39 | | if !scanner.Scan() { |
| | 0 | 40 | | if err := scanner.Err(); err != nil { |
| | 0 | 41 | | return false, err |
| | 0 | 42 | | } |
| | 1 | 43 | | return false, nil // EOF |
| | | 44 | | } |
| | | 45 | | |
| | 6 | 46 | | answer := strings.TrimSpace(strings.ToLower(scanner.Text())) |
| | 6 | 47 | | return answer == "y" || answer == "yes", nil |
| | | 48 | | } |
| | | 49 | | |
| | | 50 | | // IsTerminal returns true if stdin appears to be a terminal. |
| | | 51 | | func IsTerminal() bool { |
| | | 52 | | fi, err := os.Stdin.Stat() |
| | | 53 | | if err != nil { |
| | | 54 | | return false |
| | | 55 | | } |
| | | 56 | | return fi.Mode()&os.ModeCharDevice != 0 |
| | | 57 | | } |