feat: example env files are listed hidden, not skipped
CI / Checks (pull_request) Successful in 37s
PR title / Conventional title (pull_request) Successful in 0s

.env.example, .sample, .template and the like show with H: someone may
have put a real value in one. They're left out of sharing a repo's env
files.
This commit is contained in:
keb committed 2026-10-15 14:06:16 +02:00
1 parent 4bac06ae5b
commit 96d9f24082
4 files changed
+34 -16

No files matched your search

+24 -10
View File
@@ -333,8 +333,9 @@ func (p *Provider) Containers(ctx context.Context, src provider.Source) ([]provi
c.Detail = "sops · " + strings.Join(meta.methods, ", ")
case isSops:
return // a SOPS file where .sops.yaml says SOPS files don't go
case IsEnv(f):
case isEnvNamed(f):
c.Detail = provider.DetailPlainEnv
c.Hidden = isExample(f)
case IsSpring(f):
c.Detail = "spring · " + springFormat(f)
c.Hidden = p.springHidden(r.root, path)
@@ -717,7 +718,7 @@ func envFiles(root string, tracked []string) []string {
dirs := map[string]bool{".": true}
for _, f := range tracked {
isTracked[f] = true
if IsEnv(f) {
if isEnvNamed(f) {
out = append(out, f)
}
if d := path.Dir(f); !dirs[d] && !inPackages(f) {
@@ -731,7 +732,7 @@ func envFiles(root string, tracked []string) []string {
}
for _, e := range entries {
f := path.Join(d, e.Name())
if e.Type().IsRegular() && !isTracked[f] && IsEnv(f) {
if e.Type().IsRegular() && !isTracked[f] && isEnvNamed(f) {
out = append(out, f)
}
}
@@ -766,16 +767,29 @@ func inPackages(f string) bool {
// .env, .env.local, prod.env; not .env.example and the like, nor one in
// dependencies.
func IsEnv(f string) bool {
if inPackages(f) {
return false
}
return isEnvNamed(f) && !isExample(f)
}
// isEnvNamed reports whether a file outside dependencies is named like an
// env file, examples too.
func isEnvNamed(f string) bool {
base := strings.ToLower(path.Base(f))
for _, ext := range []string{".example", ".sample", ".template", ".dist", ".tmpl"} {
if strings.HasSuffix(base, ext) {
return false
return !inPackages(f) && (base == ".env" || strings.HasPrefix(base, ".env.") || strings.HasSuffix(base, ".env"))
}
var exampleWords = []string{"example", "sample", "template", "dist", "tmpl"}
// isExample reports whether a file is an example or template of another:
// .env.example, docker-compose.example.yml. They're listed hidden: someone
// may have put a real value in one.
func isExample(f string) bool {
base := strings.ToLower(path.Base(f))
for _, w := range exampleWords {
if strings.HasSuffix(base, "."+w) || strings.Contains(base, "."+w+".") {
return true
}
}
return base == ".env" || strings.HasPrefix(base, ".env.") || strings.HasSuffix(base, ".env")
return false
}
// plainValue reads a key from a plain env file.
+6 -3
View File
@@ -292,9 +292,12 @@ func TestPlainEnvFiles(t *testing.T) {
got := map[string]string{}
for _, c := range files {
got[c.Name] = c.Detail
if c.Hidden != (c.Name == ".env.example") {
t.Errorf("%s: hidden %t", c.Name, c.Hidden)
}
}
if len(got) != 2 || got[".env"] != "env · plain text" || got["secrets/app.yaml"] != "sops · age" {
t.Fatalf("files %v (want .env and the sops file; not the example or node_modules)", got)
if len(got) != 3 || got[".env"] != "env · plain text" || got[".env.example"] != "env · plain text" || got["secrets/app.yaml"] != "sops · age" {
t.Fatalf("files %v (want .env, the example, hidden, and the sops file; not node_modules)", got)
}
var env provider.Container
@@ -319,7 +322,7 @@ func TestPlainEnvFiles(t *testing.T) {
os.WriteFile(filepath.Join(root, ".sops.yaml"), []byte("creation_rules:\n - path_regex: nowhere/.*\n"), 0o644)
exec.Command("git", "-C", root, "add", ".sops.yaml").Run()
files, _ = New(Settings{Dir: root}).Containers(ctx, srcs[0])
if names := names(files, func(c provider.Container) string { return c.Name }); !slices.Equal(names, []string{".env"}) {
if names := names(files, func(c provider.Container) string { return c.Name }); !slices.Equal(names, []string{".env", ".env.example"}) {
t.Errorf("with rules elsewhere: %v", names)
}
}
+1 -1
View File
@@ -71,7 +71,7 @@ func (m *Model) shareFiles(src provider.Source, cs []provider.Container) tea.Cmd
return msg
}
for _, c := range all {
if c.Detail == provider.DetailPlainEnv {
if c.Detail == provider.DetailPlainEnv && !c.Hidden { // not .env.example
cs = append(cs, c)
}
}