mirror of
https://github.com/jesseduffield/lazygit.git
synced 2026-09-12 08:36:25 -04:00
When a user switches into a repo whose .envrc hasn't been approved with `direnv allow`, the previous behavior was to drop a "blocked" error popup and leave the user to fix it externally. That meant opening a terminal, running `direnv allow`, and then either restarting lazygit or switching repos and back to refresh the env — easy to get wrong, easy to forget. When `direnv export json` exits non-zero, follow up with `direnv status --json` to ask direnv whether the current directory has a not-yet- allowed .envrc, and if so, get its path. Then show a confirmation popup with the .envrc contents inline so the user can read what they're approving. Confirming runs `direnv allow <path>` and re-runs the load so the new env reaches subprocesses immediately; cancelling leaves the env unloaded (the same state as before this commit when direnv refused to load the .envrc). Using `direnv status --json` instead of parsing the "is blocked" stderr line means we rely on direnv's structured output rather than its human-readable error format, which is more stable across versions and avoids assumptions about output formatting. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
91 lines
2.7 KiB
Go
91 lines
2.7 KiB
Go
package misc
|
|
|
|
import (
|
|
"os"
|
|
"path/filepath"
|
|
|
|
"github.com/jesseduffield/lazygit/pkg/config"
|
|
. "github.com/jesseduffield/lazygit/pkg/integration/components"
|
|
)
|
|
|
|
// When the new repo's .envrc is blocked, lazygit offers the user a popup to
|
|
// approve it without leaving the app. Confirming runs `direnv allow` and
|
|
// re-runs the load so the env reaches subprocesses immediately.
|
|
var DirenvApprovesEnvrc = NewIntegrationTest(NewIntegrationTestArgs{
|
|
Description: "Approving a blocked .envrc from the in-app popup loads its env",
|
|
ExtraCmdArgs: []string{},
|
|
ExtraEnvVars: map[string]string{
|
|
"PATH": "{{actualPath}}/bin:" + os.Getenv("PATH"),
|
|
},
|
|
SetupConfig: func(cfg *config.AppConfig) {
|
|
otherRepo, _ := filepath.Abs("../other")
|
|
cfg.GetAppState().RecentRepos = []string{otherRepo}
|
|
cfg.GetUserConfig().CustomCommands = []config.CustomCommand{
|
|
{
|
|
Key: config.Keybinding{"X"},
|
|
Context: "files",
|
|
Command: `echo "VAR=$LG_DIRENV_TEST" > output.txt`,
|
|
},
|
|
}
|
|
},
|
|
SetupRepo: func(shell *Shell) {
|
|
shell.EmptyCommit("initial")
|
|
shell.CloneNonBare("other")
|
|
|
|
shell.CreateFile("../other/.envrc", "export LG_DIRENV_TEST=approved_value\n")
|
|
|
|
// Fake direnv that flips behavior once `direnv allow` runs.
|
|
// Before allow: export errors with the "blocked" signal,
|
|
// status reports allowed=1 (NotAllowed).
|
|
// On allow: create a sentinel and exit 0.
|
|
// After allow: export emits the loaded delta normally.
|
|
shell.CreateFile("../bin/direnv", `#!/bin/sh
|
|
SENTINEL="$(dirname "$0")/.approved"
|
|
case "$1 $2" in
|
|
"allow "*)
|
|
touch "$SENTINEL"
|
|
exit 0
|
|
;;
|
|
"export json")
|
|
if [ -f "$SENTINEL" ]; then
|
|
echo '{"LG_DIRENV_TEST":"approved_value"}'
|
|
echo "direnv: loading $PWD/.envrc" >&2
|
|
else
|
|
echo '{"LG_DIRENV_TEST":null}'
|
|
echo "direnv: error $PWD/.envrc is blocked" >&2
|
|
exit 1
|
|
fi
|
|
;;
|
|
"status --json")
|
|
if [ -f "$SENTINEL" ]; then
|
|
printf '{"state":{"foundRC":{"allowed":0,"path":"%s/.envrc"}}}\n' "$PWD"
|
|
else
|
|
printf '{"state":{"foundRC":{"allowed":1,"path":"%s/.envrc"}}}\n' "$PWD"
|
|
fi
|
|
;;
|
|
esac
|
|
`)
|
|
shell.MakeExecutable("../bin/direnv")
|
|
},
|
|
Run: func(t *TestDriver, keys config.KeybindingConfig) {
|
|
t.GlobalPress(keys.Universal.OpenRecentRepos)
|
|
t.ExpectPopup().Menu().Title(Equals("Recent repositories")).
|
|
Lines(
|
|
Contains("other").IsSelected(),
|
|
Contains("Cancel"),
|
|
).
|
|
Confirm()
|
|
|
|
t.ExpectPopup().Confirmation().
|
|
Title(Equals("Approve .envrc?")).
|
|
Content(Contains("export LG_DIRENV_TEST=approved_value")).
|
|
Confirm()
|
|
|
|
t.Views().Files().
|
|
Focus().
|
|
Press(config.Keybinding{"X"}).
|
|
NavigateToLine(Contains("output.txt"))
|
|
t.Views().Main().Content(Contains("VAR=approved_value"))
|
|
},
|
|
})
|