feat: e opens a repo's SOPS or .env file, in nvim, sops edit or your editor
CI / Checks (pull_request) Successful in 26s
PR title / Conventional title (pull_request) Successful in 1s

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
kebandClaude Opus 5.5 committed 2026-10-11 00:09:45 +02:00
1 parent 6fab41703e
commit c29319b821
11 files changed
+395 -12

No files matched your search

+85
View File
@@ -3,6 +3,7 @@ package app
import (
tea "charm.land/bubbletea/v2"
"context"
"fmt"
"os"
"os/exec"
"path/filepath"
@@ -238,3 +239,87 @@ func TestSearchAllRepos(t *testing.T) {
t.Errorf("title:\n%s", d.screen())
}
}
func TestEditFile(t *testing.T) {
// Not parallel: git, run by the repo provider, is slow under load.
if _, err := exec.LookPath("git"); err != nil {
t.Skip("no git")
}
root := gitRepoWith(t, "https://git.example.com/team/x.git")
envPath := filepath.Join(root, "secrets", ".env")
os.WriteFile(envPath, []byte("# local\nTOKEN=x\n"), 0o600)
var opened []string
d := newDriverOpts(t, Options{OpenURL: func(u string) error { opened = append(opened, u); return nil }},
fake.Azure(0), repo.New(repo.Settings{Dir: root}))
env := map[string]string{"NVIM": "/tmp/nvim.sock"}
d.m.getenv = func(k string) string { return env[k] }
var nvim []string
d.m.nvimOpen = func(server, path string, line int) error {
nvim = append(nvim, fmt.Sprintf("%s %s:%d", server, path, line))
return nil
}
// Inside nvim: the file, then a secret at its line, and lazysecrets quits.
d.keys("2")
if _, c, _ := d.selected(); c != "secrets/.env" {
t.Fatalf("selected %q\n%s", c, d.screen())
}
d.keys("e")
d.keys("3", "e")
want := []string{"/tmp/nvim.sock " + envPath + ":0", "/tmp/nvim.sock " + envPath + ":2"}
if !slices.Equal(nvim, want) {
t.Errorf("nvim got %q\nwant %q", nvim, want)
}
if msg := d.m.edit()(); msg != (tea.QuitMsg{}) {
t.Errorf("after opening in nvim: %#v, want quit", msg)
}
// SOPS files go to sops edit, in the terminal, even inside nvim.
nvim = nil
d.keys("2", "j")
if _, c, _ := d.selected(); c != "secrets/app.yaml" {
t.Fatalf("selected %q", c)
}
if cmd := d.m.edit(); cmd == nil || len(nvim) > 0 {
t.Errorf("sops file: cmd %v, nvim %q", cmd, nvim)
}
// Neither nvim nor an editor: the system's default app.
delete(env, "NVIM")
d.keys("k", "e")
if !slices.Equal(opened, []string{envPath}) || !strings.Contains(d.screen(), "opened .env") {
t.Errorf("opened %q\n%s", opened, d.screen())
}
// Done editing: the file's secrets reload.
d.send(editDoneMsg{c: provider.Container{Source: provider.Source{Provider: "Repos"}, ID: envPath}, name: ".env"})
if !strings.Contains(d.screen(), "closed .env") {
t.Errorf("after editing:\n%s", d.screen())
}
// Other providers have no files.
az := newDriver(t, fake.Azure(0))
az.keys("2", "e")
if !strings.Contains(az.screen(), "only SOPS and .env files") {
t.Errorf("azure:\n%s", az.screen())
}
}
func TestEditorArgs(t *testing.T) {
t.Parallel()
f := provider.File{Path: "/r/.env", Line: 7}
for editor, want := range map[string][]string{
"nvim": {"+7", "/r/.env"},
"/usr/bin/vim -p": {"+7", "/r/.env"},
"hx": {"/r/.env:7"},
"code --wait": {"-g", "/r/.env:7"},
"open -a TextEdit": {"/r/.env"},
} {
if got := editorArgs(editor, f); !slices.Equal(got, want) {
t.Errorf("%s: %q, want %q", editor, got, want)
}
}
if got := editorArgs("nvim", provider.File{Path: "/r/.env"}); !slices.Equal(got, []string{"/r/.env"}) {
t.Errorf("no line: %q", got)
}
}