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 .dagger/build/sdk.go
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,7 @@ func (build *Builder) goSDKContent(ctx context.Context) (*sdkContent, error) {
sdkCtrTarball := dag.Container(dagger.ContainerOpts{Platform: build.platform}).
From(consts.GolangImage).
With(build.goPlatformEnv).
WithExec([]string{"apk", "add", "git"}).
WithExec([]string{"apk", "add", "git", "openssh"}).
WithEnvVariable("GOTOOLCHAIN", "auto").
WithFile("/usr/local/bin/codegen", build.CodegenBinary()).
// these cache directories should match the cache volume locations in the engine's goSDK.base
Expand Down
4 changes: 2 additions & 2 deletions cmd/init/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -210,8 +210,8 @@ func mainSession() {
client.SocketProvider{EnableHostNetworkAccess: true},
// host=>container networking
session.NewTunnelListenerAttachable(ctx),
// Git credentials
session.NewGitCredentialAttachable(ctx),
// Git attachable
session.NewGitAttachable(ctx),
}
// filesync
filesyncer, err := client.NewFilesyncer()
Expand Down
295 changes: 295 additions & 0 deletions core/integration/module_config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -524,6 +524,301 @@ func (ConfigSuite) TestDaggerConfig(ctx context.Context, t *testctx.T) {
}
}

func (ConfigSuite) TestSDKConfig(ctx context.Context, t *testctx.T) {
t.Run("go sdk", func(ctx context.Context, t *testctx.T) {
testcases := []struct {
name string
daggerjson string
expectedValue string
expectedError string
}{
{
name: "go sdk supports goprivate",
daggerjson: `{
"name": "foo",
"engineVersion": "v0.16.2",
"sdk": {
"source": "go",
"config": {
"goprivate": "github.com/foobar"
}
}
}`,
expectedValue: "github.com/foobar",
},
{
name: "go sdk errors if invalid value for goprivate is configured",
daggerjson: `{
"name": "foo",
"engineVersion": "v0.16.2",
"sdk": {
"source": "go",
"config": {
"goprivate": 1234
}
}
}`,
expectedError: "'GoPrivate' expected type 'string', got unconvertible type 'float64', value: '1234'",
},
{
name: "unknown sdk config keys returns error",
daggerjson: `{
"name": "foo",
"engineVersion": "v0.16.2",
"sdk": {
"source": "go",
"config": {
"foobar": 1234
}
}
}`,
expectedError: `unknown sdk config keys found [foobar]`,
},
}

for _, tc := range testcases {
t.Run(tc.name, func(ctx context.Context, t *testctx.T) {
c := connect(ctx, t)
ctr := c.Container().From(golangImage).
WithMountedFile(testCLIBinPath, daggerCliFile(t, c)).
WithWorkdir("/work").
With(daggerExec("init", "--sdk=go", "--name=foo", "--source=.")).
WithNewFile("dagger.json", tc.daggerjson).
WithNewFile("main.go", `package main

import (
"os"
)

type Foo struct{}

func (m *Foo) CheckEnv() string {
return os.Getenv("GOPRIVATE")
}
`)

output, err := ctr.With(daggerCall("check-env")).Stdout(ctx)
if tc.expectedError != "" {
require.NotNil(t, err)
execerror := err.(*dagger.ExecError)
require.Contains(t, execerror.Stderr, tc.expectedError)
} else {
require.Nil(t, err)
require.Equal(t, tc.expectedValue, output)
}
})
}
})

t.Run("module sdk", func(ctx context.Context, t *testctx.T) {
// This json is used when calling moduleRuntime and Codegen functions of the custom sdk.
// This is required because we are using golang sdk as underlying sdk for this test fixture
// and without this, we will endup loading the dagger.json, that user provided, when loading coolsdk
// and fail because coolsdk depends-on go-sdk, which does not support the sdk config meant for coolsdk
daggerjsonGoSDK := `{
"name": "foo",
"engineVersion": "v0.16.2",
"sdk": {
"source": "go"
},
"source": ".dagger"
}
`

daggerjson := `{
"name": "foo",
"engineVersion": "v0.16.2",
"sdk": {
"source": "coolsdk"
}
}
`

daggerjsonWithValidSDKConfig := `{
"name": "foo",
"engineVersion": "v0.16.2",
"sdk": {
"source": "coolsdk",
"config": {
"barConfig": "override-value"
}
}
}`

daggerjsonWithInvalidValueForSDKConfig := `{
"name": "foo",
"engineVersion": "v0.16.2",
"sdk": {
"source": "coolsdk",
"config": {
"barConfig": 1234
}
}
}`

daggerjsonWithUnknownConfigKey := `{
"name": "foo",
"engineVersion": "v0.16.2",
"sdk": {
"source": "coolsdk",
"config": {
"foobar": 1234
}
}
}`

var withoutSDKConfigSupport = `package main

import (
"dagger/coolsdk/internal/dagger"
)

type Coolsdk struct {
BarConfig string
}

func New(
// +default="class-default"
barConfig string,
) *Coolsdk {
return &Coolsdk{
BarConfig: barConfig,
}
}

func (m *Coolsdk) WithDaggerJson(modSource *dagger.ModuleSource) *dagger.ModuleSource {
return modSource.ContextDirectory().WithNewFile("dagger.json", ` + fmt.Sprintf("`%s`", daggerjsonGoSDK) + `).
AsModuleSource()
}

func (m *Coolsdk) ModuleRuntime(modSource *dagger.ModuleSource, introspectionJson *dagger.File) *dagger.Container {
return m.WithDaggerJson(modSource).WithSDK("go").AsModule().Runtime().WithEnvVariable("COOL", m.BarConfig)
}

func (m *Coolsdk) Codegen(modSource *dagger.ModuleSource, introspectionJson *dagger.File) *dagger.GeneratedCode {
modSource = m.WithDaggerJson(modSource).WithSDK("go")
return dag.GeneratedCode(
// apply generated diff over context directory
modSource.ContextDirectory().WithDirectory("/", modSource.GeneratedContextDirectory()),
)
}
`

var withSDKConfigSupport = withoutSDKConfigSupport + `

func (m *Coolsdk) WithConfig(
// +default="func-default"
barConfig string,
) *Coolsdk {
m.BarConfig = barConfig
return m
}
`

for _, tc := range []struct {
name string
customSDKUnderlyingSDK string
customSDKSource string
sdk string
expectedCoolName string
daggerjson string
expectedError string
}{
{
name: "withConfig function is optional if no sdk config specified in dagger.json",
sdk: "coolsdk",
customSDKUnderlyingSDK: "go",
customSDKSource: withoutSDKConfigSupport,
expectedCoolName: "class-default",
daggerjson: daggerjson,
},
{
name: "withConfig function is required if dagger.json has sdk config specified",
sdk: "coolsdk",
customSDKUnderlyingSDK: "go",
customSDKSource: withoutSDKConfigSupport,
expectedCoolName: "class-default",
daggerjson: daggerjsonWithValidSDKConfig,
expectedError: "sdk does not currently support specifying config",
},
{
name: "withConfig function is called if it exists with sdk config from dagger json",
sdk: "coolsdk",
customSDKUnderlyingSDK: "go",
customSDKSource: withSDKConfigSupport,
expectedCoolName: "override-value",
daggerjson: daggerjsonWithValidSDKConfig,
},
{
name: "if sdk config not provided, use the default arg value in withConfig function",
sdk: "coolsdk",
customSDKUnderlyingSDK: "go",
customSDKSource: withSDKConfigSupport,
expectedCoolName: "func-default",
daggerjson: daggerjson,
},
{
name: "invalid format for sdk config in dagger json",
sdk: "coolsdk",
customSDKUnderlyingSDK: "go",
customSDKSource: withSDKConfigSupport,
daggerjson: daggerjsonWithInvalidValueForSDKConfig,
expectedError: `parsing value for arg "barConfig": cannot create String from float64`,
},
{
name: "unknown config key returns error",
sdk: "coolsdk",
customSDKUnderlyingSDK: "go",
customSDKSource: withSDKConfigSupport,
daggerjson: daggerjsonWithUnknownConfigKey,
expectedError: `unknown sdk config keys found [foobar]`,
},
} {
t.Run(tc.name, func(ctx context.Context, t *testctx.T) {
c := connect(ctx, t)
ctr := c.Container().From(golangImage).
WithMountedFile(testCLIBinPath, daggerCliFile(t, c)).
WithWorkdir("/work")

// special case custom sdk
if tc.customSDKSource != "" {
ctr = ctr.
WithWorkdir("/work/"+tc.sdk).
With(daggerExec("init", "--name="+tc.sdk, "--sdk="+tc.customSDKUnderlyingSDK)).
WithNewFile("main.go", tc.customSDKSource)
}

// create a module that use the custom sdk
ctr = ctr.
WithWorkdir("/work").
With(daggerExec("init", "--source=.", "--name=foo", "--sdk="+tc.sdk)).
WithNewFile("dagger.json", tc.daggerjson).
WithNewFile(".dagger/main.go", `package main

import "os"

type Foo struct{}

// Returns a container that echoes whatever string argument is provided
func (m *Foo) GetCoolName() string {
return os.Getenv("COOL")
}
`)

output, err := ctr.With(daggerCall("get-cool-name")).Stdout(ctx)
if tc.expectedError != "" {
require.NotNil(t, err)
execerror := err.(*dagger.ExecError)
require.Contains(t, execerror.Stderr, tc.expectedError)
} else {
require.Nil(t, err)
require.Equal(t, tc.expectedCoolName, output)
}
})
}
})
}

func (ConfigSuite) TestIncludeExclude(ctx context.Context, t *testctx.T) {
for _, tc := range []struct {
sdk string
Expand Down
59 changes: 59 additions & 0 deletions core/integration/module_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5841,3 +5841,62 @@ func (ModuleSuite) TestSSHAuthSockPathHandling(ctx context.Context, t *testctx.T
require.Contains(t, lines, "fn -")
})
}

func (ModuleSuite) TestPrivateDeps(ctx context.Context, t *testctx.T) {
t.Run("golang", func(ctx context.Context, t *testctx.T) {
privateDepCode := `package main

import (
"github.com/dagger/dagger-test-modules/privatedeps/pkg/cooldep"
)

type Foo struct{}

// Returns a container that echoes whatever string argument is provided
func (m *Foo) HowCoolIsDagger() string {
return cooldep.HowCoolIsThat
}
`

daggerjson := `{
"name": "foo",
"engineVersion": "v0.16.2",
"sdk": {
"source": "go",
"config": {
"goprivate": "github.com/dagger/dagger-test-modules"
}
}
}`

c := connect(ctx, t)
sockPath, cleanup := setupPrivateRepoSSHAgent(t)
defer cleanup()

socket := c.Host().UnixSocket(sockPath)

// This is simulating a user's setup where they have
// 1. ssh auth sock setup
// 2. gitconfig file with insteadOf directive
// 3. a dagger module that requires a dependency (NOT a dagger dependency) from a remote private repo.
modGen := c.Container().From(golangImage).
WithMountedFile(testCLIBinPath, daggerCliFile(t, c)).
WithExec([]string{"apk", "add", "git", "openssh"}).
WithUnixSocket("/sock/unix-socket", socket).
WithEnvVariable("SSH_AUTH_SOCK", "/sock/unix-socket").
WithWorkdir("/work").
WithNewFile("/root/.gitconfig", `
[url "ssh://git@github.com/"]
insteadOf = https://github.com/
`).
With(daggerExec("init", "--name=foo", "--sdk=go", "--source=.")).
WithNewFile("main.go", privateDepCode).
WithNewFile("dagger.json", daggerjson)

howCoolIsDagger, err := modGen.
With(daggerExec("call", "how-cool-is-dagger")).
Stdout(ctx)
require.NoError(t, err)
require.Equal(t, "ubercool", howCoolIsDagger)
})
}
3 changes: 2 additions & 1 deletion core/modules/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,8 @@ type ModuleConfigUserFields struct {
// The source can be reference to a built-in sdk e.g. go, php, elixir or
// can be a reference to a git path e.g. github.com/username/reponame/sdk-name
type SDK struct {
Source string `json:"source"`
Source string `json:"source"`
Config map[string]interface{} `json:"config,omitempty"`
}

func (sdk *SDK) UnmarshalJSON(data []byte) error {
Expand Down
Loading