Skip to content

Commit

Permalink
Enhance LocalModule when no go sources found in project root
Browse files Browse the repository at this point in the history
Signed-off-by: Petr Korobeinikov <pkorobeinikov@gmail.com>
  • Loading branch information
petr-korobeinikov committed Mar 12, 2024
1 parent e9e4f70 commit 0ae02bf
Show file tree
Hide file tree
Showing 27 changed files with 203 additions and 102 deletions.
4 changes: 2 additions & 2 deletions README.md
Expand Up @@ -50,8 +50,8 @@ Since v0.9.0, GCI always puts C import block as the first.

### LocalModule

Local module detection is done via listing packages from *the directory where
`gci` is invoked* and reading the modules off these. This means:
Local module detection is done via reading the module name from the `go.mod`
file in *the directory where `gci` is invoked*. This means:

- This mode works when `gci` is invoked from a module root (i.e. directory
containing `go.mod`)
Expand Down
2 changes: 1 addition & 1 deletion go.mod
Expand Up @@ -8,6 +8,7 @@ require (
github.com/spf13/cobra v1.6.1
github.com/stretchr/testify v1.8.1
go.uber.org/zap v1.24.0
golang.org/x/mod v0.8.0
golang.org/x/sync v0.1.0
golang.org/x/tools v0.6.0
gopkg.in/yaml.v3 v3.0.1
Expand All @@ -19,6 +20,5 @@ require (
github.com/spf13/pflag v1.0.5 // indirect
go.uber.org/atomic v1.7.0 // indirect
go.uber.org/multierr v1.6.0 // indirect
golang.org/x/mod v0.8.0 // indirect
golang.org/x/sys v0.5.0 // indirect
)
95 changes: 54 additions & 41 deletions pkg/gci/gci_test.go
Expand Up @@ -21,10 +21,6 @@ func init() {
}

func TestRun(t *testing.T) {
// if runtime.GOOS == "windows" {
// t.Skip("Skipping test on Windows")
// }

for i := range testCases {
t.Run(fmt.Sprintf("run case: %s", testCases[i].name), func(t *testing.T) {
config, err := config.ParseConfig(testCases[i].config)
Expand Down Expand Up @@ -56,35 +52,65 @@ func chdir(t *testing.T, dir string) {
func readConfig(t *testing.T, configPath string) *config.Config {
rawConfig, err := os.ReadFile(configPath)
require.NoError(t, err)
config, err := config.ParseConfig(string(rawConfig))
cfg, err := config.ParseConfig(string(rawConfig))
require.NoError(t, err)

return config
return cfg
}

func TestRunWithLocalModule(t *testing.T) {
moduleDir := filepath.Join("testdata", "module")
// files with a corresponding '*.out.go' file containing the expected
// result of formatting
testedFiles := []string{
"main.go",
filepath.Join("internal", "foo", "lib.go"),
tests := []struct {
name string
moduleDir string
// files with a corresponding '*.out.go' file containing the expected
// result of formatting
testedFiles []string
}{
{
name: `default module test case`,
moduleDir: filepath.Join("testdata", "module"),
testedFiles: []string{
"main.go",
filepath.Join("internal", "foo", "lib.go"),
},
},
{
name: `canonical module without go sources in root dir`,
moduleDir: filepath.Join("testdata", "module_canonical"),
testedFiles: []string{
filepath.Join("cmd", "client", "main.go"),
filepath.Join("cmd", "server", "main.go"),
filepath.Join("internal", "foo", "lib.go"),
},
},
{
name: `non-canonical module without go sources in root dir`,
moduleDir: filepath.Join("testdata", "module_noncanonical"),
testedFiles: []string{
filepath.Join("cmd", "client", "main.go"),
filepath.Join("cmd", "server", "main.go"),
filepath.Join("internal", "foo", "lib.go"),
},
},
}

// run subtests for expected module loading behaviour
chdir(t, moduleDir)
cfg := readConfig(t, "config.yaml")

for _, path := range testedFiles {
t.Run(path, func(t *testing.T) {
// *.go -> *.out.go
expected, err := os.ReadFile(strings.TrimSuffix(path, ".go") + ".out.go")
require.NoError(t, err)

_, got, err := LoadFormatGoFile(io.File{path}, *cfg)

require.NoError(t, err)
require.Equal(t, string(expected), string(got))
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
// run subtests for expected module loading behaviour
chdir(t, tt.moduleDir)
cfg := readConfig(t, "config.yaml")

for _, path := range tt.testedFiles {
t.Run(path, func(t *testing.T) {
// *.go -> *.out.go
expected, err := os.ReadFile(strings.TrimSuffix(path, ".go") + ".out.go")
require.NoError(t, err)

_, got, err := LoadFormatGoFile(io.File{path}, *cfg)

require.NoError(t, err)
require.Equal(t, string(expected), string(got))
})
}
})
}
}
Expand All @@ -96,18 +122,5 @@ func TestRunWithLocalModuleWithPackageLoadFailure(t *testing.T) {

chdir(t, dir)
_, err := config.ParseConfig(configContent)
require.ErrorContains(t, err, "failed to load local modules: ")
}

func TestRunWithLocalModuleWithModuleLookupError(t *testing.T) {
dir := t.TempDir()
// error from trying to list packages under module with no go files
configContent := "sections:\n - LocalModule\n"
goModContent := "module example.com/foo\n"
require.NoError(t, os.WriteFile(filepath.Join(dir, "go.mod"), []byte(goModContent), 0o644))

chdir(t, dir)
_, err := config.ParseConfig(configContent)
require.ErrorContains(t, err, "error reading local packages: ")
require.ErrorContains(t, err, dir)
require.ErrorContains(t, err, "go.mod: open go.mod:")
}
23 changes: 0 additions & 23 deletions pkg/gci/testdata.go
Expand Up @@ -1293,29 +1293,6 @@ import (
"fmt"
"net"
)
`,
},
{
"basic module",
// implicitly relies on the local module name being: github.com/daixiang0/gci
`sections:
- Standard
- LocalModule
`,
`package main
import (
"os"
"github.com/daixiang0/gci/cmd/gci"
)
`,
`package main
import (
"os"
"github.com/daixiang0/gci/cmd/gci"
)
`,
},
}
4 changes: 4 additions & 0 deletions pkg/gci/testdata/module_canonical/.gitattributes
@@ -0,0 +1,4 @@
# try and stop git running on Windows from converting line endings from
# in all Go files under this directory. This is to avoid inconsistent test
# results when `gci` strips "\r" characters
**/*.go eol=lf
9 changes: 9 additions & 0 deletions pkg/gci/testdata/module_canonical/cmd/client/main.go
@@ -0,0 +1,9 @@
package main

import (
"example.com/service/internal"
"example.com/service/internal/bar"
"example.com/service/internal/foo"
"golang.org/x/net"
"log"
)
11 changes: 11 additions & 0 deletions pkg/gci/testdata/module_canonical/cmd/client/main.out.go
@@ -0,0 +1,11 @@
package main

import (
"log"

"golang.org/x/net"

"example.com/service/internal"
"example.com/service/internal/bar"
"example.com/service/internal/foo"
)
9 changes: 9 additions & 0 deletions pkg/gci/testdata/module_canonical/cmd/server/main.go
@@ -0,0 +1,9 @@
package main

import (
"example.com/service/internal"
"example.com/service/internal/bar"
"example.com/service/internal/foo"
"golang.org/x/net"
"log"
)
11 changes: 11 additions & 0 deletions pkg/gci/testdata/module_canonical/cmd/server/main.out.go
@@ -0,0 +1,11 @@
package main

import (
"log"

"golang.org/x/net"

"example.com/service/internal"
"example.com/service/internal/bar"
"example.com/service/internal/foo"
)
4 changes: 4 additions & 0 deletions pkg/gci/testdata/module_canonical/config.yaml
@@ -0,0 +1,4 @@
sections:
- Standard
- Default
- LocalModule
3 changes: 3 additions & 0 deletions pkg/gci/testdata/module_canonical/go.mod
@@ -0,0 +1,3 @@
module example.com/service

go 1.20
1 change: 1 addition & 0 deletions pkg/gci/testdata/module_canonical/internal/bar/lib.go
@@ -0,0 +1 @@
package bar
6 changes: 6 additions & 0 deletions pkg/gci/testdata/module_canonical/internal/foo/lib.go
@@ -0,0 +1,6 @@
package foo

import (
"example.com/service/internal/bar"
"log"
)
7 changes: 7 additions & 0 deletions pkg/gci/testdata/module_canonical/internal/foo/lib.out.go
@@ -0,0 +1,7 @@
package foo

import (
"log"

"example.com/service/internal/bar"
)
1 change: 1 addition & 0 deletions pkg/gci/testdata/module_canonical/internal/lib.go
@@ -0,0 +1 @@
package internal
4 changes: 4 additions & 0 deletions pkg/gci/testdata/module_noncanonical/.gitattributes
@@ -0,0 +1,4 @@
# try and stop git running on Windows from converting line endings from
# in all Go files under this directory. This is to avoid inconsistent test
# results when `gci` strips "\r" characters
**/*.go eol=lf
9 changes: 9 additions & 0 deletions pkg/gci/testdata/module_noncanonical/cmd/client/main.go
@@ -0,0 +1,9 @@
package main

import (
"golang.org/x/net"
"log"
"service/internal"
"service/internal/bar"
"service/internal/foo"
)
11 changes: 11 additions & 0 deletions pkg/gci/testdata/module_noncanonical/cmd/client/main.out.go
@@ -0,0 +1,11 @@
package main

import (
"log"

"golang.org/x/net"

"service/internal"
"service/internal/bar"
"service/internal/foo"
)
9 changes: 9 additions & 0 deletions pkg/gci/testdata/module_noncanonical/cmd/server/main.go
@@ -0,0 +1,9 @@
package main

import (
"golang.org/x/net"
"log"
"service/internal"
"service/internal/bar"
"service/internal/foo"
)
11 changes: 11 additions & 0 deletions pkg/gci/testdata/module_noncanonical/cmd/server/main.out.go
@@ -0,0 +1,11 @@
package main

import (
"log"

"golang.org/x/net"

"service/internal"
"service/internal/bar"
"service/internal/foo"
)
4 changes: 4 additions & 0 deletions pkg/gci/testdata/module_noncanonical/config.yaml
@@ -0,0 +1,4 @@
sections:
- Standard
- Default
- LocalModule
3 changes: 3 additions & 0 deletions pkg/gci/testdata/module_noncanonical/go.mod
@@ -0,0 +1,3 @@
module service

go 1.20
1 change: 1 addition & 0 deletions pkg/gci/testdata/module_noncanonical/internal/bar/lib.go
@@ -0,0 +1 @@
package bar
6 changes: 6 additions & 0 deletions pkg/gci/testdata/module_noncanonical/internal/foo/lib.go
@@ -0,0 +1,6 @@
package foo

import (
"log"
"service/internal/bar"
)
7 changes: 7 additions & 0 deletions pkg/gci/testdata/module_noncanonical/internal/foo/lib.out.go
@@ -0,0 +1,7 @@
package foo

import (
"log"

"service/internal/bar"
)
1 change: 1 addition & 0 deletions pkg/gci/testdata/module_noncanonical/internal/lib.go
@@ -0,0 +1 @@
package internal

0 comments on commit 0ae02bf

Please sign in to comment.