Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ jobs:
run: go mod verify

- name: Run golangci-lint
uses: golangci/golangci-lint-action@v4
uses: golangci/golangci-lint-action@v9
with:
version: latest

Expand Down
29 changes: 15 additions & 14 deletions .golangci.yml
Original file line number Diff line number Diff line change
@@ -1,25 +1,26 @@
version: "2"

run:
timeout: 5m
go: '1.23'

linters:
default: none
enable:
- gofmt
- govet
- errcheck
- staticcheck
- unused
- gosimple
- ineffassign
- typecheck

linters-settings:
errcheck:
check-blank: false
check-type-assertions: false
settings:
errcheck:
check-blank: false
check-type-assertions: false
exclusions:
rules:
- path: _test\.go
linters:
- errcheck

issues:
exclude-rules:
- path: _test\.go
linters:
- errcheck
formatters:
enable:
- gofmt
96 changes: 48 additions & 48 deletions e2e/run.go
Original file line number Diff line number Diff line change
Expand Up @@ -348,7 +348,7 @@ func generatePosixScript(wtBinary, shell string, scenario Scenario, verbose, sho

// Header
sb.WriteString("set -e\n")
sb.WriteString(fmt.Sprintf("export WT_BIN='%s'\n", wtBinary))
fmt.Fprintf(&sb, "export WT_BIN='%s'\n", wtBinary)
sb.WriteString("TEST_DIR=$(mktemp -d)\n")
sb.WriteString("REPO_DIR=\"$TEST_DIR/test-repo\"\n")
sb.WriteString("REPO_NAME=\"test-repo\"\n")
Expand All @@ -362,26 +362,26 @@ func generatePosixScript(wtBinary, shell string, scenario Scenario, verbose, sho
sb.WriteString("git add README.md\n")
sb.WriteString("git commit -m 'initial' --quiet\n")
sb.WriteString("git branch -M main\n")
sb.WriteString(fmt.Sprintf("export PATH=\"%s:$PATH\"\n", filepath.Dir(wtBinary)))
fmt.Fprintf(&sb, "export PATH=\"%s:$PATH\"\n", filepath.Dir(wtBinary))

// Setup steps
for _, setup := range scenario.Setup {
if setup.CreateBranch != "" {
sb.WriteString(fmt.Sprintf("git checkout -b '%s' --quiet\n", setup.CreateBranch))
sb.WriteString(fmt.Sprintf("git commit --allow-empty -m 'commit on %s' --quiet\n", setup.CreateBranch))
fmt.Fprintf(&sb, "git checkout -b '%s' --quiet\n", setup.CreateBranch)
fmt.Fprintf(&sb, "git commit --allow-empty -m 'commit on %s' --quiet\n", setup.CreateBranch)
sb.WriteString("git checkout main --quiet\n")
}
if setup.CreateFile != nil {
sb.WriteString(fmt.Sprintf("echo '%s' > '%s'\n", setup.CreateFile.Content, setup.CreateFile.Path))
fmt.Fprintf(&sb, "echo '%s' > '%s'\n", setup.CreateFile.Content, setup.CreateFile.Path)
}
if setup.GitAdd != "" {
sb.WriteString(fmt.Sprintf("git add '%s'\n", setup.GitAdd))
fmt.Fprintf(&sb, "git add '%s'\n", setup.GitAdd)
}
if setup.GitCommit != "" {
sb.WriteString(fmt.Sprintf("git commit -m '%s' --quiet\n", setup.GitCommit))
fmt.Fprintf(&sb, "git commit -m '%s' --quiet\n", setup.GitCommit)
}
if setup.GitCheckout != "" {
sb.WriteString(fmt.Sprintf("git checkout '%s' --quiet\n", setup.GitCheckout))
fmt.Fprintf(&sb, "git checkout '%s' --quiet\n", setup.GitCheckout)
}
}

Expand All @@ -395,7 +395,7 @@ func generatePosixScript(wtBinary, shell string, scenario Scenario, verbose, sho
if step.Cd != "" {
cd := step.Cd
cd = strings.ReplaceAll(cd, "$REPO_DIR", "\"$REPO_DIR\"")
sb.WriteString(fmt.Sprintf("cd %s\n", cd))
fmt.Fprintf(&sb, "cd %s\n", cd)
}
if step.Run != "" {
// Set step-level environment variables
Expand All @@ -406,7 +406,7 @@ func generatePosixScript(wtBinary, shell string, scenario Scenario, verbose, sho
}
sort.Strings(keys)
for _, k := range keys {
sb.WriteString(fmt.Sprintf("export %s='%s'\n", k, step.Env[k]))
fmt.Fprintf(&sb, "export %s='%s'\n", k, step.Env[k])
}
}

Expand All @@ -418,45 +418,45 @@ func generatePosixScript(wtBinary, shell string, scenario Scenario, verbose, sho
// Disable set -e for commands that expect non-zero exit
sb.WriteString("set +e\n")
if needsOutput {
sb.WriteString(fmt.Sprintf("__output=$(%s 2>&1)\n", runCmd))
fmt.Fprintf(&sb, "__output=$(%s 2>&1)\n", runCmd)
} else {
sb.WriteString(fmt.Sprintf("%s\n", runCmd))
fmt.Fprintf(&sb, "%s\n", runCmd)
}
sb.WriteString("__exit_code=$?\n")
sb.WriteString("set -e\n")
} else {
// Normal execution with set -e active
if needsOutput {
sb.WriteString(fmt.Sprintf("__output=$(%s 2>&1) || __exit_code=$?\n", runCmd))
fmt.Fprintf(&sb, "__output=$(%s 2>&1) || __exit_code=$?\n", runCmd)
sb.WriteString("__exit_code=${__exit_code:-0}\n")
} else {
sb.WriteString(fmt.Sprintf("%s || __exit_code=$?\n", runCmd))
fmt.Fprintf(&sb, "%s || __exit_code=$?\n", runCmd)
sb.WriteString("__exit_code=${__exit_code:-0}\n")
}
}

if step.Expect != nil {
if step.Expect.ExitCode != nil {
sb.WriteString(fmt.Sprintf("[ \"$__exit_code\" -eq %d ] || { echo \"Expected exit code %d, got $__exit_code\"; exit 1; }\n",
*step.Expect.ExitCode, *step.Expect.ExitCode))
fmt.Fprintf(&sb, "[ \"$__exit_code\" -eq %d ] || { echo \"Expected exit code %d, got $__exit_code\"; exit 1; }\n",
*step.Expect.ExitCode, *step.Expect.ExitCode)
}
if step.Expect.CwdEndsWith != "" {
sb.WriteString(fmt.Sprintf("case \"$(pwd)\" in *%s) ;; *) echo \"CWD $(pwd) doesn't end with %s\"; exit 1;; esac\n",
step.Expect.CwdEndsWith, step.Expect.CwdEndsWith))
fmt.Fprintf(&sb, "case \"$(pwd)\" in *%s) ;; *) echo \"CWD $(pwd) doesn't end with %s\"; exit 1;; esac\n",
step.Expect.CwdEndsWith, step.Expect.CwdEndsWith)
}
if step.Expect.Branch != "" {
sb.WriteString(fmt.Sprintf("[ \"$(git branch --show-current)\" = '%s' ] || { echo \"Expected branch %s\"; exit 1; }\n",
step.Expect.Branch, step.Expect.Branch))
fmt.Fprintf(&sb, "[ \"$(git branch --show-current)\" = '%s' ] || { echo \"Expected branch %s\"; exit 1; }\n",
step.Expect.Branch, step.Expect.Branch)
}
if step.Expect.OutputContains != "" {
contains := strings.ReplaceAll(step.Expect.OutputContains, "'", "'\\''")
sb.WriteString(fmt.Sprintf("echo \"$__output\" | grep -F -q -- '%s' || { echo \"Output missing expected substring\"; exit 1; }\n",
contains))
fmt.Fprintf(&sb, "echo \"$__output\" | grep -F -q -- '%s' || { echo \"Output missing expected substring\"; exit 1; }\n",
contains)
}
if step.Expect.OutputNotContains != "" {
notContains := strings.ReplaceAll(step.Expect.OutputNotContains, "'", "'\\''")
sb.WriteString(fmt.Sprintf("echo \"$__output\" | grep -F -q -- '%s' && { echo \"Output should not contain expected substring\"; exit 1; } || true\n",
notContains))
fmt.Fprintf(&sb, "echo \"$__output\" | grep -F -q -- '%s' && { echo \"Output should not contain expected substring\"; exit 1; } || true\n",
notContains)
}
}
}
Expand Down Expand Up @@ -489,7 +489,7 @@ func generatePowerShellScript(wtBinary string, scenario Scenario, verbose, showO

// Header
sb.WriteString("$ErrorActionPreference = 'Stop'\n")
sb.WriteString(fmt.Sprintf("$env:WT_BIN = '%s'\n", wtBinary))
fmt.Fprintf(&sb, "$env:WT_BIN = '%s'\n", wtBinary)
sb.WriteString("$__tmpBase = [System.IO.Path]::GetTempPath()\n")
sb.WriteString("if (-not $__tmpBase) { $__tmpBase = $env:TEMP }\n")
sb.WriteString("if (-not $__tmpBase) { $__tmpBase = $env:TMP }\n")
Expand All @@ -506,26 +506,26 @@ func generatePowerShellScript(wtBinary string, scenario Scenario, verbose, showO
sb.WriteString("git add 'README.md'\n")
sb.WriteString("git commit -m 'initial' --quiet\n")
sb.WriteString("git branch -M main\n")
sb.WriteString(fmt.Sprintf("$env:PATH = '%s;' + $env:PATH\n", filepath.Dir(wtBinary)))
fmt.Fprintf(&sb, "$env:PATH = '%s;' + $env:PATH\n", filepath.Dir(wtBinary))

// Setup steps
for _, setup := range scenario.Setup {
if setup.CreateBranch != "" {
sb.WriteString(fmt.Sprintf("git checkout -b '%s' --quiet\n", setup.CreateBranch))
sb.WriteString(fmt.Sprintf("git commit --allow-empty -m 'commit on %s' --quiet\n", setup.CreateBranch))
fmt.Fprintf(&sb, "git checkout -b '%s' --quiet\n", setup.CreateBranch)
fmt.Fprintf(&sb, "git commit --allow-empty -m 'commit on %s' --quiet\n", setup.CreateBranch)
sb.WriteString("git checkout main --quiet\n")
}
if setup.CreateFile != nil {
sb.WriteString(fmt.Sprintf("Set-Content -Path '%s' -Value '%s'\n", setup.CreateFile.Path, setup.CreateFile.Content))
fmt.Fprintf(&sb, "Set-Content -Path '%s' -Value '%s'\n", setup.CreateFile.Path, setup.CreateFile.Content)
}
if setup.GitAdd != "" {
sb.WriteString(fmt.Sprintf("git add '%s'\n", setup.GitAdd))
fmt.Fprintf(&sb, "git add '%s'\n", setup.GitAdd)
}
if setup.GitCommit != "" {
sb.WriteString(fmt.Sprintf("git commit -m '%s' --quiet\n", setup.GitCommit))
fmt.Fprintf(&sb, "git commit -m '%s' --quiet\n", setup.GitCommit)
}
if setup.GitCheckout != "" {
sb.WriteString(fmt.Sprintf("git checkout '%s' --quiet\n", setup.GitCheckout))
fmt.Fprintf(&sb, "git checkout '%s' --quiet\n", setup.GitCheckout)
}
}

Expand All @@ -540,7 +540,7 @@ func generatePowerShellScript(wtBinary string, scenario Scenario, verbose, showO
if step.Cd != "" {
cd := step.Cd
cd = strings.ReplaceAll(cd, "$REPO_DIR", "$RepoDir")
sb.WriteString(fmt.Sprintf("Set-Location %s\n", cd))
fmt.Fprintf(&sb, "Set-Location %s\n", cd)
}
if step.Run != "" {
// Set step-level environment variables
Expand All @@ -551,7 +551,7 @@ func generatePowerShellScript(wtBinary string, scenario Scenario, verbose, showO
}
sort.Strings(keys)
for _, k := range keys {
sb.WriteString(fmt.Sprintf("$env:%s = '%s'\n", k, step.Env[k]))
fmt.Fprintf(&sb, "$env:%s = '%s'\n", k, step.Env[k])
}
}

Expand All @@ -578,9 +578,9 @@ func generatePowerShellScript(wtBinary string, scenario Scenario, verbose, showO
sb.WriteString("$__exit_code = 0\n")
sb.WriteString("try {\n")
if needsOutput {
sb.WriteString(fmt.Sprintf(" $__output = %s 2>&1 | Out-String\n", runCmd))
fmt.Fprintf(&sb, " $__output = %s 2>&1 | Out-String\n", runCmd)
} else {
sb.WriteString(fmt.Sprintf(" %s\n", runCmd))
fmt.Fprintf(&sb, " %s\n", runCmd)
}
sb.WriteString(" $__exit_code = $LASTEXITCODE\n")
sb.WriteString("} catch {\n")
Expand All @@ -591,42 +591,42 @@ func generatePowerShellScript(wtBinary string, scenario Scenario, verbose, showO
sb.WriteString("}\n")
} else if needsOutput {
// Capture output (runs in pipeline context)
sb.WriteString(fmt.Sprintf("$__output = %s 2>&1 | Out-String\n", runCmd))
fmt.Fprintf(&sb, "$__output = %s 2>&1 | Out-String\n", runCmd)
sb.WriteString("$__exit_code = $LASTEXITCODE\n")
} else {
// Run directly to allow auto-cd to work
sb.WriteString(fmt.Sprintf("%s\n", runCmd))
fmt.Fprintf(&sb, "%s\n", runCmd)
sb.WriteString("$__exit_code = $LASTEXITCODE\n")
}

if step.Expect != nil {
if step.Expect.ExitCode != nil {
sb.WriteString(fmt.Sprintf("if ($__exit_code -ne %d) { throw \"Expected exit code %d, got $__exit_code\" }\n",
*step.Expect.ExitCode, *step.Expect.ExitCode))
fmt.Fprintf(&sb, "if ($__exit_code -ne %d) { throw \"Expected exit code %d, got $__exit_code\" }\n",
*step.Expect.ExitCode, *step.Expect.ExitCode)
}
if step.Expect.CwdEndsWith != "" {
// Handle both forward and back slashes for cross-platform compatibility
suffix := step.Expect.CwdEndsWith
sb.WriteString("$__cwd = (Get-Location).Path.Replace('\\', '/')\n")
sb.WriteString(fmt.Sprintf("if (-not $__cwd.EndsWith('%s')) { throw \"CWD $__cwd doesn't end with %s\" }\n",
suffix, suffix))
fmt.Fprintf(&sb, "if (-not $__cwd.EndsWith('%s')) { throw \"CWD $__cwd doesn't end with %s\" }\n",
suffix, suffix)
}
if step.Expect.Branch != "" {
sb.WriteString("$__branch = git branch --show-current\n")
sb.WriteString(fmt.Sprintf("if ($__branch -ne '%s') { throw \"Expected branch %s, got $__branch\" }\n",
step.Expect.Branch, step.Expect.Branch))
fmt.Fprintf(&sb, "if ($__branch -ne '%s') { throw \"Expected branch %s, got $__branch\" }\n",
step.Expect.Branch, step.Expect.Branch)
}
if step.Expect.OutputContains != "" {
contains := strings.ReplaceAll(step.Expect.OutputContains, "'", "''")
sb.WriteString("if ($null -eq $__output) { $__output = '' }\n")
sb.WriteString(fmt.Sprintf("if (-not $__output.Contains('%s')) { throw \"Output missing expected substring\" }\n",
contains))
fmt.Fprintf(&sb, "if (-not $__output.Contains('%s')) { throw \"Output missing expected substring\" }\n",
contains)
}
if step.Expect.OutputNotContains != "" {
notContains := strings.ReplaceAll(step.Expect.OutputNotContains, "'", "''")
sb.WriteString("if ($null -eq $__output) { $__output = '' }\n")
sb.WriteString(fmt.Sprintf("if ($__output.Contains('%s')) { throw \"Output should not contain expected substring\" }\n",
notContains))
fmt.Fprintf(&sb, "if ($__output.Contains('%s')) { throw \"Output should not contain expected substring\" }\n",
notContains)
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion init.go
Original file line number Diff line number Diff line change
Expand Up @@ -280,7 +280,7 @@ func installShellConfig(configPath, shell string, dryRun, noPrompt bool) error {
if err != nil {
return fmt.Errorf("failed to open %s: %v", configPath, err)
}
defer f.Close()
defer func() { _ = f.Close() }()

// Add newline before if file doesn't end with one
if len(existing) > 0 && existing[len(existing)-1] != '\n' {
Expand Down
2 changes: 1 addition & 1 deletion main.go
Original file line number Diff line number Diff line change
Expand Up @@ -535,7 +535,7 @@ func isDirEmpty(path string) (bool, error) {
case err != nil:
return false, err
}
defer dir.Close()
defer func() { _ = dir.Close() }()

_, err = dir.Readdirnames(1)
if err == io.EOF {
Expand Down