Skip to content

Commit 2a8fe98

Browse files
feat: support remove command to unregister hooks
1 parent f219063 commit 2a8fe98

File tree

2 files changed

+89
-0
lines changed

2 files changed

+89
-0
lines changed

internal/cmd/cmd.go

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ func Run() error {
1717
func newCliApp() *cli.App {
1818
cmds := []*cli.Command{
1919
newInitCmd(),
20+
newRemoveCmd(),
2021
newLintCmd(),
2122
newConfigCmd(),
2223
newHookCmd(),
@@ -207,6 +208,25 @@ func newHookCmd() *cli.Command {
207208
}
208209
}
209210

211+
func newRemoveCmd() *cli.Command {
212+
return &cli.Command{
213+
Name: "remove",
214+
Usage: "Remove commitlint from git config",
215+
Description: "Unset git's core.hooksPath so commits are no longer linted.\nHook files are left intact.\nUse --global to remove globally configured hooks.",
216+
Flags: []cli.Flag{
217+
&cli.BoolFlag{
218+
Name: "global",
219+
Aliases: []string{"g"},
220+
Usage: "Remove from global git config",
221+
},
222+
},
223+
Action: func(ctx *cli.Context) error {
224+
isGlobal := ctx.Bool("global")
225+
return removeLint(isGlobal)
226+
},
227+
}
228+
}
229+
210230
func newDebugCmd() *cli.Command {
211231
return &cli.Command{
212232
Name: "debug",

internal/cmd/remove.go

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
package cmd
2+
3+
import (
4+
"fmt"
5+
"os"
6+
"os/exec"
7+
"strings"
8+
)
9+
10+
// removeLint is the callback function for the uninstall command.
11+
func removeLint(isGlobal bool) error {
12+
return gitRemoveHook(isGlobal)
13+
}
14+
15+
// gitRemoveHook removes commitlint from git config by unsetting core.hooksPath.
16+
// It prompts for confirmation before making any changes.
17+
// Hook files are left intact - the user can remove them manually if needed.
18+
func gitRemoveHook(isGlobal bool) error {
19+
scope := "local"
20+
if isGlobal {
21+
scope = "global"
22+
}
23+
confirmed, err := promptConfirm(fmt.Sprintf("Unset core.hooksPath from %s git config?", scope))
24+
if err != nil {
25+
return err
26+
}
27+
if !confirmed {
28+
fmt.Println("aborted")
29+
return nil
30+
}
31+
32+
if err := unsetGitConf(isGlobal); err != nil {
33+
return fmt.Errorf("could not unset git core.hooksPath: %w", err)
34+
}
35+
36+
fmt.Println("commitlint hook removed successfully")
37+
fmt.Println("note: hook files were not removed - delete them manually if no longer needed")
38+
return nil
39+
}
40+
41+
// unsetGitConf removes the core.hooksPath entry from git config (local or global).
42+
func unsetGitConf(isGlobal bool) error {
43+
args := []string{"config"}
44+
if isGlobal {
45+
args = append(args, "--global")
46+
}
47+
args = append(args, "--unset", "core.hooksPath")
48+
49+
cmd := exec.Command("git", args...)
50+
cmd.Stderr = os.Stderr
51+
return cmd.Run()
52+
}
53+
54+
// promptConfirm prints prompt and waits for the user to type y/yes or anything else.
55+
// Returns true only when the user confirms with "y" or "yes" (case-insensitive).
56+
func promptConfirm(prompt string) (bool, error) {
57+
fmt.Printf("%s [y/N]: ", prompt)
58+
var response string
59+
_, err := fmt.Scanln(&response)
60+
if err != nil {
61+
// empty Enter is reported by fmt.Scanln as "unexpected newline"
62+
if err.Error() == "unexpected newline" {
63+
return false, nil
64+
}
65+
return false, err
66+
}
67+
response = strings.TrimSpace(strings.ToLower(response))
68+
return response == "y" || response == "yes", nil
69+
}

0 commit comments

Comments
 (0)