1// SPDX-FileCopyrightText: Amolith <amolith@secluded.site>
2//
3// SPDX-License-Identifier: AGPL-3.0-or-later
4
5package main
6
7import (
8 "fmt"
9 "strings"
10
11 "github.com/spf13/cobra"
12)
13
14var (
15 tagMessage string
16 tagBody string
17 tagForce bool
18)
19
20var tagCmd = &cobra.Command{
21 Use: "git-formatted-tag NAME",
22 Short: "Create formatted annotated Git tags",
23 Long: `git-formatted-tag helps you create well-formatted annotated Git tags with
24proper subject length validation and body wrapping.`,
25 Example: `
26# Simple tag with just a message
27git formatted-tag v1.0.0 -m "Initial stable release"
28
29# Tag with body
30git formatted-tag v1.2.0 -m "Add user authentication" -b "$(cat <<'EOF'
31✨ Features
32- [auth]: implement JWT-based authentication
33- [api]: add login and logout endpoints
34
35🐛 Bug Fixes
36- [login]: correct password validation error
37EOF
38)"
39
40# Force overwrite an existing tag
41git formatted-tag v1.0.0 -m "Re-release with hotfix" -f
42`,
43 Args: cobra.ExactArgs(1),
44 RunE: func(cmd *cobra.Command, args []string) error {
45 tagName := args[0]
46
47 if tagMessage == "" {
48 return fmt.Errorf("formatted-tag requires at least a subject (-m)\nFor lightweight tags, use: git tag %s", tagName)
49 }
50
51 if err := validateSubjectLength(tagMessage); err != nil {
52 return err
53 }
54
55 var tagContent strings.Builder
56 tagContent.WriteString(tagMessage)
57
58 if tagBody != "" {
59 formattedBody, err := formatBody(tagBody)
60 if err != nil {
61 return fmt.Errorf("failed to format body: %w", err)
62 }
63 tagContent.WriteString("\n\n")
64 tagContent.WriteString(formattedBody)
65 }
66
67 gitArgs := []string{"tag", "-a", tagName}
68 if tagForce {
69 gitArgs = append(gitArgs, "-f")
70 }
71 gitArgs = append(gitArgs, "-F", "-")
72
73 return runGitWithStdin(gitArgs, tagContent.String())
74 },
75}
76
77func init() {
78 tagCmd.Flags().StringVarP(&tagMessage, "message", "m", "", "tag subject (required, max 50 characters)")
79 tagCmd.Flags().StringVarP(&tagBody, "body", "b", "", "tag body (optional)")
80 tagCmd.Flags().BoolVarP(&tagForce, "force", "f", false, "replace existing tag")
81}