1// SPDX-FileCopyrightText: Amolith <amolith@secluded.site>
2//
3// SPDX-License-Identifier: AGPL-3.0-or-later
4
5package main
6
7import (
8 "context"
9 "os"
10 "runtime/debug"
11
12 "github.com/charmbracelet/fang"
13 "github.com/spf13/cobra"
14)
15
16var (
17 commitType string
18 message string
19 trailers []string
20 body string
21 scope string
22 breakingChange bool
23)
24
25var rootCmd = &cobra.Command{
26 Use: "formatted-commit",
27 Short: "Create conventionally formatted Git commits",
28 Long: `formatted-commit helps you create well-formatted Git commits that follow
29the Conventional Commits specification with proper subject length validation,
30body wrapping, and trailer formatting.`,
31 Example: `
32# With co-author
33formatted-commit -t feat -m "do a thing" -T "Crush <crush@charm.land>"
34
35# Breaking change with longer body
36formatted-commit -t feat -m "do a thing that borks a thing" -B "$(cat <<'EOF'
37Multi-line
38- Body
39- Here
40
41This is what borked because of new shiny, this is how migrate
42EOF
43)"
44
45# Including scope for more precise changes
46formatted-commit -t refactor -s "web/git-bug" -m "fancy shmancy" \
47 -b "Had to do a weird thing because..."
48`,
49 RunE: func(cmd *cobra.Command, args []string) error {
50 // TODO: Implement commit formatting logic here
51 // 1. Validate subject length (type(scope): message <= 50 chars)
52 // 2. Format body as Markdown wrapped to 72 columns
53 // 3. Validate and format trailers
54 // 4. Pipe result to `git commit -F -`
55
56 return nil
57 },
58}
59
60func init() {
61 rootCmd.Flags().StringVarP(&commitType, "type", "t", "", "commit type (required)")
62 rootCmd.Flags().StringVarP(&message, "message", "m", "", "commit message (required)")
63 rootCmd.Flags().StringSliceVarP(&trailers, "trailer", "T", []string{}, "trailer in 'Sentence-case-key: value' format (optional, repeatable)")
64 rootCmd.Flags().StringVarP(&body, "body", "b", "", "commit body (optional)")
65 rootCmd.Flags().StringVarP(&scope, "scope", "s", "", "commit scope (optional)")
66 rootCmd.Flags().BoolVarP(&breakingChange, "breaking", "B", false, "mark as breaking change (optional)")
67
68 if err := rootCmd.MarkFlagRequired("type"); err != nil {
69 panic(err)
70 }
71 if err := rootCmd.MarkFlagRequired("message"); err != nil {
72 panic(err)
73 }
74}
75
76func main() {
77 ctx := context.Background()
78
79 var version string
80 if info, ok := debug.ReadBuildInfo(); ok {
81 version = info.Main.Version
82 }
83 if version == "" || version == "(devel)" {
84 version = "dev"
85 }
86
87 if err := fang.Execute(ctx, rootCmd,
88 fang.WithVersion(version),
89 fang.WithoutCompletions(),
90 ); err != nil {
91 os.Exit(1)
92 }
93}