Skip to content

Commit

Permalink
feat: add support for workspaces and external modules in the same repo (
Browse files Browse the repository at this point in the history
#199)

* feat: fix bug

Signed-off-by: Kasper J. Hermansen <[email protected]>

* fix: set all output to stderr from ui

Signed-off-by: Kasper J. Hermansen <[email protected]>

* feat: with stderr instead

Signed-off-by: Kasper J. Hermansen <[email protected]>

* feat: with local dir

Signed-off-by: Kasper J. Hermansen <[email protected]>

* feat: with go mod

Signed-off-by: Kasper J. Hermansen <[email protected]>

* feat: with root module

Signed-off-by: Kasper J. Hermansen <[email protected]>

* feat: add workspace

Signed-off-by: Kasper J. Hermansen <[email protected]>

* feat: add more logs (#200)

Signed-off-by: Kasper J. Hermansen <[email protected]>

* refactor: into different files

Signed-off-by: Kasper J. Hermansen <[email protected]>

* refactor: into package finder

Signed-off-by: Kasper J. Hermansen <[email protected]>

* feat: add shuttle

Signed-off-by: Kasper J. Hermansen <[email protected]>

* feat: refactor go mod

Signed-off-by: Kasper J. Hermansen <[email protected]>

* refactor: patch gomodule

Signed-off-by: Kasper J. Hermansen <[email protected]>

* feat: with split workspace patcher

Signed-off-by: Kasper J. Hermansen <[email protected]>

* refactor: into modfile and module

Signed-off-by: Kasper J. Hermansen <[email protected]>

* feat: add mod file test

Signed-off-by: Kasper J. Hermansen <[email protected]>

* chore: fix typo

Signed-off-by: Kasper J. Hermansen <[email protected]>

---------

Signed-off-by: Kasper J. Hermansen <[email protected]>
  • Loading branch information
kjuulh authored Dec 11, 2023
1 parent b3817e6 commit bc03e8b
Show file tree
Hide file tree
Showing 24 changed files with 838 additions and 4 deletions.
68 changes: 68 additions & 0 deletions pkg/executors/golang/codegen/mod_file.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
package codegen

import (
"fmt"
"io/fs"
"path"
"strings"

"golang.org/x/exp/slices"
)

type actionsModFile struct {
info fs.FileInfo
content []string
path string

writeFileFunc writeFileFunc
}

func (a *actionsModFile) containsModule(moduleName string) bool {
return slices.ContainsFunc(a.content, func(s string) bool {
return strings.Contains(s, moduleName)
})
}

func (a *actionsModFile) replaceModulePath(rootDir string, module module) {
relativeToActionsModulePath := path.Join(strings.Repeat("../", a.segmentsTo(rootDir)), module.path)

foundReplace := false
for i, line := range a.content {
lineTrim := strings.TrimSpace(line)

if strings.Contains(lineTrim, fmt.Sprintf("replace %s", module.name)) {
a.content[i] = fmt.Sprintf("replace %s => %s", module.name, relativeToActionsModulePath)
foundReplace = true
break
}

}

if !foundReplace {
a.content = append(
a.content,
fmt.Sprintf("\nreplace %s => %s", module.name, relativeToActionsModulePath),
)

}
}

func (a *actionsModFile) segmentsTo(dirPath string) int {
relativeActionsModFilePath := strings.TrimPrefix(
strings.TrimPrefix(
a.path,
dirPath,
),
"/",
)

return strings.Count(relativeActionsModFilePath, "/")
}

func (a *actionsModFile) commit() error {
return a.writeFileFunc(
a.path,
[]byte(strings.Join(a.content, "\n")),
a.info.Mode(),
)
}
247 changes: 247 additions & 0 deletions pkg/executors/golang/codegen/mod_file_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,247 @@
package codegen

import (
"strings"
"testing"

"github.com/stretchr/testify/assert"
)

func TestContainsModule(t *testing.T) {
t.Parallel()

sut := actionsModFile{
content: []string{
"someModuleName",
"someOtherModuleName",
" someSpacedModule",
"package somePackaged",
"module someModModule",
"require someRequireModule",
},
}

t.Run("contains a module name", func(t *testing.T) {
actual := sut.containsModule("someModuleName")

assert.True(t, actual)
})

t.Run("does not contain module", func(t *testing.T) {
actual := sut.containsModule("someNonExistingModule")

assert.False(t, actual)
})

t.Run("spaced matches", func(t *testing.T) {
actual := sut.containsModule("someSpacedModule")

assert.True(t, actual)
})

t.Run("packaged matches", func(t *testing.T) {
actual := sut.containsModule("somePackaged")

assert.True(t, actual)
})

t.Run("modded module matches", func(t *testing.T) {
actual := sut.containsModule("someModModule")

assert.True(t, actual)
})

t.Run("required module matches", func(t *testing.T) {
actual := sut.containsModule("someRequireModule")

assert.True(t, actual)
})

t.Run("case sensitive doesn't match", func(t *testing.T) {
actual := sut.containsModule("SOMEMODULENAME")

assert.False(t, actual)
})
}

func TestReplaceModulePath(t *testing.T) {
t.Parallel()

createSut := func() actionsModFile {

modFileContent := `module actions
require (
root_workspace v0.0.0
subpackage v0.0.0
othersubpackage v0.0.0
)
go 1.21.4
replace othersubpackage => ../../../../othersubpackage`

return actionsModFile{
path: "/some-path/some-other-path",
content: strings.Split(modFileContent, "\n"),
}

}

t.Run("module matches, not replaced already", func(t *testing.T) {
sut := createSut()

expected := `module actions
require (
root_workspace v0.0.0
subpackage v0.0.0
othersubpackage v0.0.0
)
go 1.21.4
replace othersubpackage => ../../../../othersubpackage
replace subpackage => ../subpackage`

sut.replaceModulePath("some-other-path/newpath", module{
name: "subpackage",
path: "subpackage",
})

assert.Equal(t, expected, strings.Join(sut.content, "\n"))
})

t.Run("module matches, not replaced already, deeper nesting", func(t *testing.T) {
sut := createSut()

expected := `module actions
require (
root_workspace v0.0.0
subpackage v0.0.0
othersubpackage v0.0.0
)
go 1.21.4
replace othersubpackage => ../../../../othersubpackage
replace subpackage => subpackage`

sut.replaceModulePath("/some-path", module{
name: "subpackage",
path: "subpackage",
})

assert.Equal(t, expected, strings.Join(sut.content, "\n"))
})

t.Run("module matches, already replaced already", func(t *testing.T) {
sut := createSut()

expected := `module actions
require (
root_workspace v0.0.0
subpackage v0.0.0
othersubpackage v0.0.0
)
go 1.21.4
replace othersubpackage => ../othersubpackage`

sut.replaceModulePath("some-other-path/newpath", module{
name: "othersubpackage",
path: "othersubpackage",
})

assert.Equal(t, expected, strings.Join(sut.content, "\n"))
})

t.Run("module matches, already replaced already deeper nesting", func(t *testing.T) {
sut := createSut()

expected := `module actions
require (
root_workspace v0.0.0
subpackage v0.0.0
othersubpackage v0.0.0
)
go 1.21.4
replace othersubpackage => othersubpackage`

sut.replaceModulePath("/some-path", module{
name: "othersubpackage",
path: "othersubpackage",
})

assert.Equal(t, expected, strings.Join(sut.content, "\n"))
})
}

func TestSegmentsTo(t *testing.T) {
t.Parallel()

testCases := []struct {
name string
path string
rootDir string
expected int
}{
{
name: "empty",
path: "",
rootDir: "",
expected: 0,
},
{
name: "current dir",
path: "/some-dir/",
rootDir: "/some-dir/",
expected: 0,
},
{
name: "one level",
path: "/some-dir/some-other-dir/",
rootDir: "/some-dir",
expected: 1,
},
{
name: "2 level",
path: "/some-dir/some-other-dir/some-third-dir/",
rootDir: "/some-dir",
expected: 2,
},
{
name: "1 level",
path: "/some-dir/some-other-dir/some-third-dir/",
rootDir: "/some-dir/some-other-dir",
expected: 1,
},
{
name: "without trailing",
path: "/some-dir/some-third-dir",
rootDir: "/some-dir",
expected: 0,
},
}

for _, testCase := range testCases {
t.Run(testCase.name, func(t *testing.T) {
sut := actionsModFile{
path: testCase.path,
}

actual := sut.segmentsTo(testCase.rootDir)

assert.Equal(t, testCase.expected, actual)
})
}

}
27 changes: 27 additions & 0 deletions pkg/executors/golang/codegen/module.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package codegen

import (
"strings"

"golang.org/x/exp/slices"
)

type module struct {
name string
path string
}

func modulesFromMap(packages map[string]string) []module {
modules := make([]module, 0, len(packages))
for moduleName, modulePath := range packages {
modules = append(modules, module{
name: moduleName,
path: modulePath,
})
}
slices.SortFunc(modules, func(a, b module) int {
return strings.Compare(a.name, b.name)
})

return modules
}
38 changes: 38 additions & 0 deletions pkg/executors/golang/codegen/patch.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package codegen

import (
"context"
"io/fs"
"os"
)

type writeFileFunc = func(name string, contents []byte, permissions fs.FileMode) error

type Patcher struct {
patchFinder *chainedPackageFinder
patcher *goModPatcher
}

func NewPatcher() *Patcher {
return &Patcher{
patchFinder: newChainedPatchFinder(
newWorkspaceFinder(),
newGoModuleFinder(),
newDefaultFinder(),
),
patcher: newGoModPatcher(os.WriteFile),
}
}

func (p *Patcher) Patch(ctx context.Context, rootDir string, shuttleLocalDir string) error {
packages, err := p.patchFinder.findPackages(ctx, rootDir)
if err != nil {
return err
}

if err := p.patcher.patch(rootDir, shuttleLocalDir, packages); err != nil {
return err
}

return nil
}
14 changes: 14 additions & 0 deletions pkg/executors/golang/codegen/patch_default.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package codegen

import "context"

type defaultFinder struct{}

func newDefaultFinder() *defaultFinder {
return &defaultFinder{}
}

func (s *defaultFinder) Find(ctx context.Context, _ string) (packages map[string]string, ok bool, err error) {
// We return true, as this should be placed last in the chain
return make(map[string]string, 0), true, nil
}
Loading

0 comments on commit bc03e8b

Please sign in to comment.