Skip to content

Conversation

@ldez
Copy link
Member

@ldez ldez commented Nov 11, 2025

The problem when running golangci-lint fmt inside a symlink is related to the filepath.Walk function.

Walk does not follow symbolic links.
https://pkg.go.dev/path/filepath#Walk

WalkDir does not follow symbolic links.
https://pkg.go.dev/path/filepath#WalkDir

Note: The filepath.Walk/filepath.WalkDir function is used by the golangci-lint fmt command but also by gofmt, gofumpt, etc.

The problem happens only with golangci-lint fmt because we use an absolute representation of paths.

But this absolute representation of paths is required by the exclusion paths system to evaluate the paths relatively to the base directory.

There are 2 ways to solve this problem:

  • When the absolute representation is created, we could also evaluate the symlinks. But the output of the diff option will be impacted and will display the real path instead of the symlink path.
  • Don't use an absolute representation of paths before the call to Walk function. But this will impact the exclusion paths system: the matching system needs the absolute representation.

I decided to go with the second option because it's closer to the gofmt and gofumpt behavior.

Note: this doesn't impact golangci-lint run because this is a different approach.

To reproduce
#!/bin/sh -e

GOLANGCI_LINT_BIN=golangci-lint

ROOT=$(mktemp -d)
mkdir -p $ROOT/project/

## Create module
cat > $ROOT/project/go.mod <<EOF
module github.com/golangci/sandbox

go1.24.0
EOF

# Create golangci-lint configuration file.
cat > $ROOT/project/.golangci.yaml <<EOF
version: "2"

formatters:
  enable:
    - gofmt
#  exclusions:
#    paths:
#      - ^[^/]+\\.go\$
EOF

## Create main.go file.
cat > $ROOT/project/main.go <<EOF
package main

import "fmt"

func main() {
fmt.Println("hello world") // Formatting problem.
}
EOF

## Create symlink to the project directory.
ln -s $ROOT/project/ $ROOT/workdir

## Run golangci-lint inside the real project directory.
cd $ROOT/project

echo
echo "--------------------------"
echo "Run on the real project directory ($(pwd)):"
echo

${GOLANGCI_LINT_BIN} fmt --diff || true

## Run golangci-lint inside the symlinked project directory.
cd $ROOT/workdir

echo
echo "--------------------------"
echo "Run on the symlinked project directory ($(pwd)):"
echo

${GOLANGCI_LINT_BIN} fmt --diff || true

rm -rf $ROOT
Before
$ ./setup.sh

--------------------------
Run on the real project directory (/tmp/tmp.aRmyw8ndll/project):

diff /tmp/tmp.aRmyw8ndll/project/main.go.orig /tmp/tmp.aRmyw8ndll/project/main.go
--- /tmp/tmp.aRmyw8ndll/project/main.go.orig
+++ /tmp/tmp.aRmyw8ndll/project/main.go
@@ -3,5 +3,5 @@
 import "fmt"
 
 func main() {
-fmt.Println("hello world") // Formatting problem.
+       fmt.Println("hello world") // Formatting problem.
 }

--------------------------
Run on the symlinked project directory (/tmp/tmp.aRmyw8ndll/workdir):

$
After
$ ./setup.sh

--------------------------
Run on the real project directory (/tmp/tmp.RhH8WxS3sf/project):

diff main.go.orig main.go
--- main.go.orig
+++ main.go
@@ -3,5 +3,5 @@
 import "fmt"
 
 func main() {
-fmt.Println("hello world") // Formatting problem.
+       fmt.Println("hello world") // Formatting problem.
 }

--------------------------
Run on the symlinked project directory (/tmp/tmp.RhH8WxS3sf/workdir):

diff main.go.orig main.go
--- main.go.orig
+++ main.go
@@ -3,5 +3,5 @@
 import "fmt"
 
 func main() {
-fmt.Println("hello world") // Formatting problem.
+       fmt.Println("hello world") // Formatting problem.
 }
$

</details>

@ldez ldez added this to the unreleased milestone Nov 11, 2025
@ldez ldez added bug Something isn't working area: formatters/fmt labels Nov 11, 2025
@ldez ldez requested a review from bombsimon November 11, 2025 15:15
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area: formatters/fmt bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant