Skip to content

Commit e0ac25c

Browse files
committed
Add self config commands
1 parent c095457 commit e0ac25c

6 files changed

Lines changed: 176 additions & 0 deletions

File tree

docs/docs/changelog.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ title: Changelog
55

66
## [Unreleased](https://github.com/lets-cli/lets/releases/tag/v0.0.X)
77

8+
* `[Added]` Add `lets self config path` and `lets self config edit` for user settings. Issue [#370](https://github.com/lets-cli/lets/issues/370)
89
* `[Added]` Show interactive download progress for remote configs and remote mixins. Issue [#360](https://github.com/lets-cli/lets/issues/360)
910
* `[Fixed]` Make `--no-cache` re-download remote mixins for local and remote configs. Issue [#365](https://github.com/lets-cli/lets/issues/365)
1011
* `[Added]` Remote config support: `lets -c https://url` downloads and caches config to `~/.config/lets/remote-configs/`. Use `--no-cache` to force re-download.

docs/docs/settings.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,18 @@ Use settings for things like colored output, theming, or update notifications. D
1717

1818
This file is per-user and applies to all projects on the machine.
1919

20+
Print the path:
21+
22+
```bash
23+
lets self config path
24+
```
25+
26+
Open the file in `$EDITOR`:
27+
28+
```bash
29+
lets self config edit
30+
```
31+
2032
## Precedence
2133

2234
Settings are resolved in this order:

internal/cmd/root_test.go

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import (
44
"bytes"
55
"context"
66
"errors"
7+
"path/filepath"
78
"strings"
89
"testing"
910

@@ -236,6 +237,59 @@ func TestSelfCmd(t *testing.T) {
236237
}
237238
})
238239

240+
t.Run("should print user config path", func(t *testing.T) {
241+
home := t.TempDir()
242+
t.Setenv("HOME", home)
243+
bufOut := new(bytes.Buffer)
244+
245+
rootCmd := CreateRootCommand("v0.0.0-test", "")
246+
rootCmd.SetArgs([]string{"self", "config", "path"})
247+
rootCmd.SetOut(bufOut)
248+
rootCmd.SetErr(bufOut)
249+
initSelfCmd(rootCmd, "v0.0.0-test", func(string) error { return nil })
250+
251+
if err := rootCmd.Execute(); err != nil {
252+
t.Fatalf("unexpected error: %v", err)
253+
}
254+
255+
expected := filepath.Join(home, ".config", "lets", "config.yaml") + "\n"
256+
if bufOut.String() != expected {
257+
t.Fatalf("expected %q, got %q", expected, bufOut.String())
258+
}
259+
})
260+
261+
t.Run("should open user config in editor", func(t *testing.T) {
262+
home := t.TempDir()
263+
t.Setenv("HOME", home)
264+
bufOut := new(bytes.Buffer)
265+
called := false
266+
gotPath := ""
267+
268+
rootCmd := CreateRootCommand("v0.0.0-test", "")
269+
rootCmd.SetArgs([]string{"self", "config", "edit"})
270+
rootCmd.SetOut(bufOut)
271+
rootCmd.SetErr(bufOut)
272+
initSelfCmdWithEditor(rootCmd, "v0.0.0-test", func(string) error { return nil }, func(path string) error {
273+
called = true
274+
gotPath = path
275+
276+
return nil
277+
})
278+
279+
if err := rootCmd.Execute(); err != nil {
280+
t.Fatalf("unexpected error: %v", err)
281+
}
282+
283+
expected := filepath.Join(home, ".config", "lets", "config.yaml")
284+
if !called {
285+
t.Fatal("expected editor to be called")
286+
}
287+
288+
if gotPath != expected {
289+
t.Fatalf("expected editor path %q, got %q", expected, gotPath)
290+
}
291+
})
292+
239293
t.Run("should open documentation in browser", func(t *testing.T) {
240294
bufOut := new(bytes.Buffer)
241295
called := false

internal/cmd/self.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,15 @@ func InitSelfCmd(rootCmd *cobra.Command, version string) {
1111
}
1212

1313
func initSelfCmd(rootCmd *cobra.Command, version string, openURL func(string) error) {
14+
initSelfCmdWithEditor(rootCmd, version, openURL, util.OpenEditor)
15+
}
16+
17+
func initSelfCmdWithEditor(
18+
rootCmd *cobra.Command,
19+
version string,
20+
openURL func(string) error,
21+
openEditor func(string) error,
22+
) {
1423
selfCmd := &cobra.Command{
1524
Use: "self",
1625
Hidden: false,
@@ -24,6 +33,7 @@ func initSelfCmd(rootCmd *cobra.Command, version string, openURL func(string) er
2433

2534
rootCmd.AddCommand(selfCmd)
2635

36+
selfCmd.AddCommand(initConfigCommand(openEditor))
2737
selfCmd.AddCommand(initDocCommand(openURL))
2838
selfCmd.AddCommand(initLspCommand(version))
2939
selfCmd.AddCommand(initSkillsCommand())

internal/cmd/self_config.go

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
package cmd
2+
3+
import (
4+
"fmt"
5+
"os"
6+
"path/filepath"
7+
"strings"
8+
9+
"github.com/lets-cli/lets/internal/util"
10+
"github.com/spf13/cobra"
11+
)
12+
13+
func initConfigCommand(openEditor func(string) error) *cobra.Command {
14+
configCmd := &cobra.Command{
15+
Use: "config <command>",
16+
Short: "Manage lets user config",
17+
Long: strings.TrimSpace(`Manage the per-user lets settings file.
18+
19+
The user config is stored at ~/.config/lets/config.yaml and applies to all
20+
projects on the machine.`),
21+
Args: validateCommandArgs,
22+
RunE: func(cmd *cobra.Command, args []string) error {
23+
return cmd.Help()
24+
},
25+
}
26+
27+
configCmd.AddCommand(initConfigPathCommand())
28+
configCmd.AddCommand(initConfigEditCommand(openEditor))
29+
30+
return configCmd
31+
}
32+
33+
func initConfigPathCommand() *cobra.Command {
34+
return &cobra.Command{
35+
Use: "path",
36+
Short: "Print lets user config path",
37+
Args: cobra.NoArgs,
38+
RunE: func(cmd *cobra.Command, args []string) error {
39+
path, err := util.LetsUserFile("config.yaml")
40+
if err != nil {
41+
return err
42+
}
43+
44+
_, err = fmt.Fprintln(cmd.OutOrStdout(), path)
45+
46+
return err
47+
},
48+
}
49+
}
50+
51+
func initConfigEditCommand(openEditor func(string) error) *cobra.Command {
52+
return &cobra.Command{
53+
Use: "edit",
54+
Short: "Open lets user config in EDITOR",
55+
Args: cobra.NoArgs,
56+
RunE: func(cmd *cobra.Command, args []string) error {
57+
path, err := util.LetsUserFile("config.yaml")
58+
if err != nil {
59+
return err
60+
}
61+
62+
if err := os.MkdirAll(filepath.Dir(path), 0o755); err != nil {
63+
return fmt.Errorf("creating config directory: %w", err)
64+
}
65+
66+
if err := openEditor(path); err != nil {
67+
return fmt.Errorf("can not open config: %w", err)
68+
}
69+
70+
return nil
71+
},
72+
}
73+
}

internal/util/editor.go

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
package util
2+
3+
import (
4+
"errors"
5+
"fmt"
6+
"os"
7+
"os/exec"
8+
)
9+
10+
func OpenEditor(path string) error {
11+
editor := os.Getenv("EDITOR")
12+
if editor == "" {
13+
return errors.New("EDITOR is not set")
14+
}
15+
16+
cmd := exec.Command(editor, path) //nolint:gosec
17+
cmd.Stdin = os.Stdin
18+
cmd.Stdout = os.Stdout
19+
cmd.Stderr = os.Stderr
20+
21+
if err := cmd.Run(); err != nil {
22+
return fmt.Errorf("run %s: %w", editor, err)
23+
}
24+
25+
return nil
26+
}

0 commit comments

Comments
 (0)