#go

1 messages · Page 2 of 1

ruby reef
#

Hmm, yeah, not sure how to accomplish this w/o nuking things.

granite valve
#

thanks

ruby reef
#

Or am I misreading the wipe docs
If false (the default), the contents of the directory will be merged with any existing contents of the host directory, leaving any existing files on the host that aren't in the exported directory alone.

#

will be merged with any existing contents of the host directory implies to me that changes being exported would overwrite existing files (merge).

tawny carbon
ruby reef
#

so I can't use Diff(<original src>)

#

to export only changes overwritting local contents

tawny carbon
#

If you diff, and only one file changed, then wipe will delete all other files because you're basically exporting a directory with a single file.

ruby reef
#

exactly

tawny carbon
#

So you shouldn't use diff with wipe.

#

Just export wipe without the diff.

ruby reef
#

AFAICT I can't do what I was trying to do then.

#

@tawny carbon that wipes everything excluded though at least.

tawny carbon
#

True, if you have a filtered directory.

ruby reef
#

I have to ... .git is ~1GB

#

and there are also other previous build stuff often in random locations not worth uploading.

tawny carbon
#

Yeah, we'd need something more in the API to wipe using the same filters or base set of files to compare.

ruby reef
#

--overwrite as an option to export would suffice for me

#

Wait ... now it seems to be overwritting. WTh?

#

export --path=. vs export --path=./

#

I apparently have no idea what I'm doing

#

Interestingly export --path=. without the Diff(<original directory>) works and does overwrite local files the way I would expect. With Diff(<original directory>) it doesn't.

ruby reef
#

How do I construct a *dagger.Secret in go code?

rocky karma
ruby reef
#

Can I pass a default for a []string ? If so, how?

#

I guess I could take a csv string and split it

violet cosmos
ruby reef
#

doesn't seem to work

#

or at least I'm pretty sure I tried that

violet cosmos
#

normally a good old printf should work. It will show up in your trace.

  • dagger --no-exit to navigate the trace interactively even after the call completes

  • dagger -w to open the trace interactively even after a web view

ruby reef
rocky karma
# ruby reef doesn't seem to work

I had to go through this same exercise when defaulting a slice of strings. It's not super intuitive because other defaults require it to be within quotes (valid json). Even a boolean has to be quoted. But the slice should not be. If you quote the slice you get a weird error. This is where I went to look or an example https://docs.dagger.io/api/arguments/#default-values but couldn't find one. I think there should be examples of each type of default there. I'll open an issue

Dagger Functions, just like regular functions, can accept arguments. In addition to basic types (string, boolean, integer, arrays...), Dagger also defines powerful core types which Dagger Functions can use for their arguments, such as Directory, Container, Service, Secret, and many more.

violet cosmos
#

@rocky karma the point was precisely to require valid json, to make it easier to remember:

  • string: json-encoded string eg. "foo"
  • array: json-encoded array eg. ["foo", "bar"]
warm nacelle
#

Learning Go (with Dagger)... How do I print output to stdout from Go when the module doesn't error? Tried a few fmt. and nothing actually prints to stdout?

#

Seems to only show in cloud, not in terminal

violet cosmos
#

You can also dagger --progress=plain for a more traditional flat log

warm nacelle
granite valve
#

I'm getting this error unless I add the source arg to Build directly: ! required flag(s) "source" not set. Am I getting this wrong?

type App struct {Source *dagger.Directory}
func New(source *dagger.Directory) *App {return &App{Source: source}}
func (m *App) Build() *dagger.Container {
    return dag.Container().
        From("golang:1.23").
        WithMountedDirectory("/src", m.Source)
}
tawny carbon
#

I'm getting this error unless I add the

ruby reef
#

I guess maps aren't supported?
error calling ModuleMainSrc: failed to parse field type: unsupported type for named type reference *types.Map

agile mural
signal mantle
# agile mural No idea if it's gonna make sense, but I started something here: https://github.c...

Makes sense to me! For the pipeline one you've built so far, we have an issue for a similar proposal that I'm still hoping becomes a reality but it hasn't happened yet https://github.com/dagger/dagger/issues/5083

GitHub

Summary This proposal suggests adding an SDK helper for efficiently synchronizing multiple pipelines, in an easy to use way. Background This is based on one aspect of: #4205 Motivation Often times,...

slim radish
agile mural
limpid mango
placid girder
#

So, last night (EMEA) my Dagger pipelines started failing again.

Error: bootstrap package: existing go.mod has unsupported version 1.22.5 (highest supported version is 1.22.3)
I pinned my CI image version to golang:1.22.2-alpine and dagger to DAGGER_VERSION=0.11.6.

I'm building with [attached screenshot] and getting the error (see screenshot)

What's changed? In the evening (8:00pm UTC) pipelines were OK. During the night (1:15am UTC) AMER folks started complaining. Nothing changed on my side (I'm vacation)

What happened and how do I recover?

placid girder
#

So, last night (EMEA) my Dagger

topaz cliff
#

Im using dagger in conjunction with mage.
Running the following command is returning an error:

dagger run -d go run -mod=mod mage.go -v release:all
invalid argument "mod" for "-d, --debug" flag: strconv.ParseBool: parsing "mod": invalid syntax

It seems dagger does not like the "-mod=mod" go run option.
Hopefully someone else has run into this before. Any help/insight would be great.

violet cosmos
topaz cliff
stray halo
#

hi i got my gitlab pipeline #gitlab message

  • using own dagger engine very simple setting ENV proxy

  • im behind corporate proxy with no access to internet

  • my problem was described on image1.png and later in that log was error with connect to proxy.golang.org image2.png

  • i thought if im using typescript SDK module then ill be not using GO but it seems yes

  • okay so i googled a bit and i needed GOPROXY to download deps because i have no access to proxy.golang.org

  • so i created my nexus proxy repo for golang

  • i set _DAGGER_ENGINE_SYSTEMENV_GOPROXY=nexus.proxy.dev/repo/golang-something

  • it started using proxy and downloaded some packages which are present in nexus proxy repo

  • which moved my error a bit further image3.png

  • in nexus documentation i found i can do 2 things either set GOSUMDB param to go environment https://help.sonatype.com/en/go-repositories.html#sumdb

  • or use GOPRIVATE env variable https://go.dev/ref/mod#environment-variables

my problem is i need to set it for go like :

go env -w GOPROXY=https://nexus.example.com/repository/golang-proxy
go env -w 'GOSUMDB=sum.golang.org https://nexus.example.com/repository/golang-sum-proxy'
go env -w 'GOPRIVATE=golang.org/*'

but all my attempts to set it to go inside dagger engine are not working because as i see it right dagger engine handles only env variable _DAGGER_ENGINE_SYSTEMENV_GOPROXY

Am i missing something ?

#

my Dockerfile which is building dagger engine

FROM harbor.company/proxy-dagger/engine:v0.14.0

# Set Go environment variables
ENV GOPROXY=https://nexus.company/repository/go-proxy
ENV _DAGGER_ENGINE_SYSTEMENV_GOPROXY=https://nexus.company/repository/go-proxy
ENV GOSUMDB='sum.golang.org https://nexus.company/repository/golang-sum-proxy'
#ENV GOPRIVATE=golang.org/*

ENV http_proxy=http://proxy.company:8080
ENV https_proxy=http://proxy.company:8080
ENV no_proxy=company.dev
dawn yacht
#

hey guys! I'm new to Dagger, and as a part of a college class, I'm defining a pipeline to test, format and run code coverage for a Rust application (I'm re-writing the GitHub pipeline from the 'Zero to Production in Rust' book). I started with just the test stage, as you can see on the images below, and when I try to run the installation of the sqlx-cli, the pipeline cannot grab the environment variables previously defined. How can I use them properly on the pipeline?

fallen root
fallen root
modest nacelle
dawn yacht
fallen root
exotic sail
#

Hi eveyone should we push the daggers auto generate bindings present inside the internal/ folder to the VCS?

fallen root
violet cosmos
exotic sail
#

Thanks 😊

agile flame
#

i have a pattern question related to long streams of args and chaining command.

I'm guessing i don't really have a better option than having multiple functions sharing the same stream of args: ?


// Build returns a go binary that can fetch private deps
func (m Module) Build (src *dagger.Directory, username, pwd *dagger.Secret, goprivate []string) *dagger.File

// DockerBuild returns a configured fresh alpine docker container with the binary
func (m Module) DockerBuild(binary *dagger.File) *dagger.Container

// Here i have to call all the parameters from the build command to effectively chain the build and the docker build command
func (m Module) DockerBuildButIHaveToChainEverything(src *dagger.Directory, username, pwd *dagger.Secret, goprivate []string) *dagger.Container{
    b := m.Build(src,username,pwd,goprivate)
    db := m.DockerBuild(b)
}

Actual usage:

username=riri password=fifi dagger call docker-build-but-i-have-to-chain-everything src=. username=env:username password=env:password goprivate=loulou

I could use a bespoke OptBuildOption struct but then i would loose the ability to call the function from the cli if i ever want to extract the binary on the host and i would then probably stop exporting the build command all together...:

username=riri password=fifi dagger call build src=. username=env:username password=env:password goprivate=loulou export path=./my_bin
violet cosmos
agile flame
#

oh that's super neat

#

i was kinda scratching my head a little bit thinking of how i would implement default values like

  • source should by default be the root of the git repo
  • output of a build should go in $PWD/bin

i would end up with a makefile for dagger which sounds like an antipattern when you think about the tool

violet cosmos
#

Also note that you can make arguments optional, when it makes sense. So you don't have to specify src=. every time. You can reference a default path for src, it can be any path within the same git repo as your module

agile flame
#

awesome thanks

violet cosmos
#
func New(
  // +optional
  // +defaultPath="."
  // +ignore=["node_modules", "bin/*"]
  src *dagger.Directory,
) Module {
  return Module{
    Src: Src,
  }
}

This will default src to the root directory of the module (the directory containing dagger.json). You can also ignore certain paths with +ignore

agile flame
#

that's really really good

#

been away from dagger for a couple months, the doc made leaps forward

violet cosmos
agile flame
#

thanks a lot :D

#

yeah i was browsing the daggerverse for ideas but this also fits nicely

rocky karma
#

You can also maintain a separate struct/s to pass around data instead of passing each argument. The nice thing about that is you can actually attach dagger functions to that secondary struct. That way you can enforce certain patterns within your code by chaining dagger objects. Here's an example https://github.com/dagger/dagger/blob/main/modules/golangci/lint.go#L43.

orchid yoke
#

HI, i have an issue with building typescript project

package main

import (
)

type MyProject struct{}


func (m *MyProject) BuildEnv(source *Directory) *Container {
    return dag.Container().
        From("node:14.15.5").
        WithDirectory("/src", source).
        WithWorkdir("/src").
        WithExec([]string{"npm", "install"})
}


func (m *MyProject) BuildDist(source *Directory, env string) *Directory {
    return m.BuildEnv(source).
        WithExec([]string{"npm", "run", "build-" + env})
        WithExec([]string{"mkdir", "./zip"}).
        WithExec([]string{"tar", "-czvf", "./zip/front_artifact.tar.gz", "-C", "dist", "."}).
        Directory("./zip")
}

Without dagger there is no problem
But with dagger :

 DeprecationWarning: 'createExpressionStatement' has been deprecated since v4.0.0. Use                   
    ┃ (node:64) UnhandledPromiseRejectionWarning: Error: write EPIPE                                          
    ┃     at process.target._send (internal/child_process.js:832:20)                                          
    ┃     at process.target.send (internal/child_process.js:703:19)                                           
    ┃     at file:///src/node_modules/@angular/compiler-cli/bundles/chunk-D5CHHDFQ.js:4995:1                  
    ┃     at new Promise (<anonymous>)                                                                        
    ┃     at sendMessageToMaster (file:///src/node_modules/@angular/compiler-cli/bundles/chu                  
    ┃     at Worker.<anonymous> (file:///src/node_modules/@angular/compiler-cli/bundles/ngcc                  
    ┃     at Worker.emit (events.js:315:20)                                                                   
    ┃     at process.<anonymous> (internal/cluster/worker.js:33:12)                                           
    ┃     at process.emit (events.js:315:20)                                                                  
    ┃     at emit (internal/child_process.js:903:12)                                                          
    ┃ (Use `node --trace-warnings ...` to show where the warning was created)                                 
    ┃ (node:64) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error or                  
    ┃ handled with .catch(). To terminate the node process on unhandled promise rejection, u                  
    ┃ ejection id: 1)                                                                                         
    ┃ (node:64) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. I                  
    ┃ (node:75) UnhandledPromiseRejectionWarning: Error: write EPIPE                                          
    ┃     at process.target._send (internal/child_process.js:832:20)                                          
    ┃     at process.target.send (internal/child_process.js:703:19)                                           
    ┃     at file:///src/node_modules/@angular/compiler-cli/bundles/chunk-D5CHHDFQ.js:4995:1                  
    ┃     at new Promise (<anonymous>)                                                                        
    ┃     at sendMessageToMaster (file:///src/node_modules/@angular/compiler-cli/bundles/chu                  
    ┃     at Worker.<anonymous> (file:///src/node_modules/@angular/compiler-cli/bundles/ngcc                  
    ┃     at Worker.emit (events.js:315:20)                                                                   
    ┃     at process.<anonymous> (internal/cluster/worker.js:33:12)                                           
    ┃     at process.emit (events.js:315:20)                                                                  
    ┃     at emit (internal/child_process.js:903:12)                          

Could you help me to fix this issue ?

orchid yoke
#

After some search its not coming from dagger !

shadow fjord
#

Hello, just read the article about migrating to go-app. Can someone explain me that part please?

We tried to perform Brotli compression on-the-fly in our CDN but the file was too large, so eventually we just included the compression step into our build process.

Who compresses and decompresses the wasm file and where it is happening?

Source:
https://dagger.io/blog/replaced-react-with-go

Powerful, programmable CI/CD engine that runs your pipelines in
containers — pre-push on your local machine and/or post-push in CI

#

Is it the browser who decompresses brotil by itself? And your cdn is who returns compressed wasm file?

slim radish
patent ermine
patent ermine
kind badge
#

Hello !
I am trying to walk a Directory hierarchy with

entries, err := dir.Entries(ctx)

But I cannot know whether an entry refers to a directory or a regular file 😐
Is there a way to achieve a file hierarchy walk? thanks.

regal seal
#

i'm still a bit on the fence as to whether the idea is good - wdyt?

tawny carbon
#

I'd still love to have it 🙂

regal seal
#

yeah 😦 i think my motivation for it died in a hole of fixing all the tests that rely on it

#

probably just need to power through

kind badge
# regal seal i'm still a bit on the fence as to whether the idea is good - wdyt?

Thanks a lot Jed! Sorry for the late reply.
I am glad to see I am not the only one asking for this.

Regarding your PR, it is fine by me, but the question is "would this API change break things for some existing pipelines, and if yes, are we ok with it?"

TBH I did not find the time to ponder this yet, but would it be a good idea to have an .Entries() alternative that returns an array of "info" structs instead of an array of strings?

🤔

regal seal
#

returning an info array would be cool - the problem is, under our current model, it'll be horribly inefficient 😦

#

so probably needs a bit more thought

#

🤔 🤔 @tawny carbon @pure flare wdyt about the idea of marking certain fields in the graphql schema as "pre-fetchable" (using a graphql directive) - an sdk codegen could then add those to the query out of the box, and just attach them as fields (instead of as functions that need await/context).
then, we could have this little info struct that could be efficiently returned

pearl tundra
#

unrelated, but typescript compiler is now written in go instead of typescript for performance. I wonder if that has any performance improvements on the typescript sdk?

regal seal
pearl tundra
#

I'm guessing the runtime is more of a bottleneck than the compiler but thought of sharing anyway

molten fractal
#

Hello

I’m wondering what is the best way to handle go mod cache in a project with go sdk.

I have currently 3 dagger function

  1. Buildenv: which create the container with mounted cache.etc

  2. Lint: which do the go vet

  3. Build: which go build the app

All chained

My issue is that any modification of the src code is relaunching go vet (expected) but it re pull every dependendies every time.

violet cosmos
molten fractal
hidden mango
#

Hey there! Is it possible to compose a dagger modules from another one using go struct embedding?
I've tried:

type Gateway struct {
    //+private
    *dagger.Go
}

But in order to have functions available at the Gateway level, I need to redefine them. It's not a blocker, it's just a bit repetitive, and I'm pretty sure I'm missing something obvious to achieve this pattern.

regal seal
hidden mango
regal seal
#

nah, no worries, i just have a good memory for what issues "exist" in the github somewhere 😛

muted zenith
#

Is support for go 1.24 planned? I couldnt find it anywhere and want to upgrade as soon as possible since snyk gives us quite some critical vulns on 1.23.8

regal seal
#

so we're blocked on a 1.24.3 release

#

actually. 🤔 looks like alpine has backported the fix

#

doesn't seem like wolfi currently does though, which is what we're using for our build (though maybe we might be able to switch)

muted zenith
#

you mean 1.23.3?

#

i tought 1.24.2 is the latest

regal seal
#

no, 1.24.0-1.24.2 are broken with this bug - it's fixed on trunk, and marked for cherry-pick into 1.24.3, but 1.24.3 has not been released yet

muted zenith
#

aha ok

#

That means ill have to wait for 1.24.3 to be released before fixing my vulnerabilities

regal seal
heady surge
#

I'm facing an issue where all the values I provide on module level via arguments end up as empty.

type Platform struct {
    terraformVersion   string
    awsAccessKeyID     *dagger.Secret
    awsSecretAccessKey *dagger.Secret
    awsSessionToken    *dagger.Secret
}

func New(
    // the version of the Terraform image to use
    // +default="1.5.7"
    terraformVersion string,
    // the AWS access key ID
    awsAccessKeyID *dagger.Secret,
    // the AWS secret access key
    awsSecretAccessKey *dagger.Secret,
    // the AWS session token
    awsSessionToken *dagger.Secret,
) (*Platform, error) {
    p := &Platform{
        terraformVersion:   terraformVersion,
        awsAccessKeyID:     awsAccessKeyID,
        awsSecretAccessKey: awsSecretAccessKey,
        awsSessionToken:    awsSessionToken,
    }

    return p, nil
}

// AwsContainer returns a container with the AWS CLI installed.
func (m *Platform) AwsContainer(
    ctx context.Context,
    // +default="latest"
    awsCliVersion string,
    env *dagger.Directory,
) (*dagger.Container, error) {
    slog.Info("AWS CLI version", slog.String("version", awsCliVersion))

    return dag.Container().
        From(fmt.Sprintf("amazon/aws-cli:%s", awsCliVersion)).
        WithEnvVariable("AWS_DEFAULT_REGION", "us-east-1").
        WithEnvVariable("TERRAFORM_VERSION", m.terraformVersion).
        // WithSecretVariable("AWS_ACCESS_KEY_ID", m.awsAccessKeyID).
        // WithSecretVariable("AWS_SECRET_ACCESS_KEY", m.awsSecretAccessKey).
        // WithSecretVariable("AWS_SESSION_TOKEN", m.awsSessionToken).
        WithMountedDirectory("/env", env).
        WithWorkdir("/env"), nil
}

Now when I call the module like this it just fails as all the arguments and the defaults are not set on my module

dagger call --aws-access-key-id=env://AWS_ACCESS_KEY_ID --aws-secret-access-key=env://AWS_SECRET_ACCESS_KEY --aws-session-token=env://AWS_SESSION_TOKEN aws-container --env environments terminal
#

I'm running using the latest dagger cli dagger v0.18.6 (docker-image://registry.dagger.io/engine:v0.18.6) darwin/arm64

#

What am I doing wrong? I want to have those settings globally because I want to have multiple functions that depend on the same secrets. All the secrets are nil and the terraformVersion is an empty string"".

dagger call --help
✔ connect 0.1s
✔ load module 0.7s
✔ parsing command line arguments 0.0s

Call one or more functions, interconnected into a pipeline

USAGE
  dagger call [options] [arguments] <function>

FUNCTIONS
  aws-container           AwsContainer returns a container with the AWS CLI installed.
  terraform-container     -
  terraform-environment   -

ARGUMENTS
      --aws-access-key-id Secret       the AWS access key ID
                                        [required]
      --aws-secret-access-key Secret   the AWS secret access key
                                        [required]
      --aws-session-token Secret       the AWS session token
                                        [required]
      --terraform-version string       
                                       the version of the Terraform image to use
                                        (default "1.5.7")
heady surge
quick snow
arctic niche
astral lotus
#

Hi everybody, long time no see! 👋

Is there a pattern for module development where you augment a container through a method.

Let's say : I have a *dagger.Container but I'd like to add some more things to it (files, exec some commands, etc) and return the augmented *dagger.Container.

Right now, I'm doing

func (m *Module) WithAndroidSDK(ctr *dagger.Container) *dagger.Container {}

func main() {
  ctr := dag.Container().From("golang:1.24)
  
  ctrWithAndroid := dag.Module().WithAndroidSDK(ctr)

I'd love to be able to chain this like

dag.Container().From("golang:1.24").WithAndroidSDK(ctr)

But that would mean it would extend the Container API, not just the *dagger.Client

I'm experimenting with it, but I'm not completely satisfied with my current API.

#

Forget about me. It's Container.With that would suit it best 🙂. Asking the question triggered a memory.
I guess rubber duck FTW.

violet cosmos
#

@astral lotus good to see you!

Quick reminder that Container.With is SDK-specific so only for internal use inside your module. You can't eg. return an extended container to another module. The with also won't show up in traces as an operation.

astral lotus
#

Thanks, good to know!

#

I got surprised trying to modularize a dagger script. And for that, I was chaining operation that would return a new struct

type Ubuntu struct{}
func (u *Ubuntu) WithGo() *Go { /* ... */ }

type Go struct{}
func (g *Go) WithAndroid() *Android { /* ... */ }

type Android struct{}
func (a *Android) BuildAPK() *dagger.File { /* ... */ }

But this didn't work because the subsequent calls were from a nil pointer. So

dagger call with-go with-android build-apk

failed because WithAndroid was called with (g *Go) being nil

#

As I wanted to create a module for Go, and a module for Android, how would you make them composable in that idea?

signal mantle
#

Hey 👋 That structure looks right, so maybe there's another detail missing?

rocky karma
#

I've done this type of chaining and it works. in your case @astral lotus , if your module is named Ubuntu you won't be able to chain call Android without first using Ubuntu as entrypoint. Intermediate structs can only be called if they were returned first from the main module. If that makes sense. But looks like that's what you are doing so, it should work.

astral lotus
#

Ok, there clearly must have been a mistake somewhere then 🙂
Anyway, I'm using With and it seems to work between modules ( is that was not supported @violet cosmos ?)

rocky karma
astral lotus
#

Oh, I see!
Well I guess I didn't use it the wrong way then 🙂

warm nacelle
#

How do you pass a directory arg in Go? In Python it's just a string that automagically becomes a dir, but doing the same in Go results in cannot use "./fixtures" (untyped string constant) as *dagger.Directory value

astral lotus
astral lotus
#

is it an optional parameter? Or is it positional?
Can you do a

dagger call my-function --help

?

warm nacelle
regal seal
#

do you have a code snippet?

warm nacelle
# regal seal do you have a code snippet?
func (m *DockerBuilder) BuildImage(
    // Dockerfile path
    Dir *dagger.Directory,
    // Dockerfile name
    // +default="Dockerfile"
    File string,
) (*dagger.Container, error) {
    ctr := Dir.DockerBuild(dagger.DirectoryDockerBuildOpts{
        Dockerfile: File,
    })

    return ctr, nil
}
_, err := dag.DockerBuilder().BuildImage("./fixtures")

-> cannot use "./fixtures" (untyped string constant) as *dagger.Directory value in argument to dag.DockerBuilder().BuildImage compiler (IncompatibleAssign) [22, 43]

#

(I'm quite new to the Go SDK having moved over from Python, I may be making rookie mistakes)

#

(Possibly related issue: assignment mismatch: 2 variables but dag.DockerBuilder().BuildImage returns 1 value compiler (WrongAssignCount) [22, 12] -> BuildImage returns two values, not sure why this isn't working, see #general message. The second snippet dag.DockerBuilder... is in a test submodule)

regal seal
#

you need +defaultPath

#

instead of +default

warm nacelle
#

Even for a string type?

#

It works in a Dagger shell with build-image ./tests/fixtures Dockerfile.other | stdout with

func (m *DockerBuilder) BuildImage(
    // Dockerfile path
    Dir *dagger.Directory,
    // Dockerfile name
    File string,
) (*dagger.Container, error) {
    ctr := Dir.DockerBuild(dagger.DirectoryDockerBuildOpts{
        Dockerfile: File,
    })

    return ctr, nil
}

It just doesn't work when calling the function in code?

regal seal
#

// +defaultPath is required for a default dir arg

#

It is possible to assign a default path for a Directory or File argument in a Dagger Function. Dagger will automatically use this default path when no value is specified for the argument. The Directory or File loaded in this manner is not merely a string, but the actual filesystem state of the directory or file.

warm nacelle
regal seal
#

oh i see yeah

#

um

#

how are you calling your BuildImage function?

warm nacelle
#
_, err := dag.DockerBuilder().BuildImage(
        "./fixtures",
        "Dockerfile.other",
    )
#

That doesn't work, I've not progressed with it since

regal seal
#

right okay, that's because "./fixtures" is a string

#

it needs to be a *dagger.Directory

#

i'd recommend using your IDE, with the output from dagger develop - it's a compile time error

warm nacelle
#

dagger develop runs fine as-is

#
✔ connect 0.2s

✔ moduleSource(refString: ".", requireKind: LOCAL_SOURCE): ModuleSource! 0.1s
✔ .localContextDirectoryPath: String! 0.0s

✔ develop 3.4s

✔ ModuleSource.sourceRootSubpath: String! 0.0s
regal seal
#

yeah, but if you load up the file in your IDE, it should be showing you errors?

warm nacelle
#

It is - cannot use "./fixtures" (untyped string constant as *dagger.Directory...

regal seal
#

right, so you need to use a dagger.Directory?

warm nacelle
#

I'm either misremembering or getting this wrong entirely, in Python you can just pass strings to become dagger.Directory automatically?

regal seal
#

🤔

#

maybe? i'm fairly not, cc @tawny carbon

warm nacelle
#

I think I've been confusing this with CLI inputs somewhere.

#

Calling this module from the CLI is simple, just pass a path and it loads that path as a dagger.Directory. How do I do that in code?

tawny carbon
warm nacelle
#

I'm thinking about the test

#

How do I pass that directory to the test in code

#

I'm happy with the function itself, it's using *dagger.Directory, no need for +defaultPath, but how do I test that function in a submodule

#

dag.CurrentModule().Source().Directory("./fixtures") perhaps?

tawny carbon
#

Just call it without passing a value for it. Otherwise +defaultPath is ignored. It's only set when you don't pass a value yourself.

warm nacelle
#

I don't have/need +defaultPath

tawny carbon
#

Ok, if it's within your module then you can use dag.CurrentModule(), yes.

warm nacelle
#

To extend the question, if the file wasn't part of the current module is that possible, and if so how?

tawny carbon
#

You need to make sure it's included in dagger.json if it's outside the module.

warm nacelle
#

Ok, that's new to me, got a link documenting that I can read/search for?

tawny carbon
#

But + defaultPath is a simpler solution imo.

warm nacelle
#

I'm not sure about putting a default path for test fixtures in a module for broad use, but I do see the point: provide a path or it'll just run the test path

tawny carbon
warm nacelle
#

Ahhh

#

Like this?

func (m *Tests) OtherDockerfileBuild(
    ctx context.Context,
    // +defaultPath="./fixtures"
    Path *dagger.Directory,
) error {
    _, err := dag.DockerBuilder().BuildImage(Path, "Dockerfile.other")
    return err
}
tawny carbon
#

Yes 🙂

warm nacelle
#

How should a default value for a []string be formatted? // +default="linux/amd64,linux/arm64" errors

warm nacelle
#

Seems like ["linux/amd64","linux/arm64"] works

vestal hatch
#

Hey all, just getting started with dagger and wondering if there is something I need to do to have neovim correctly run auto complete for dagger modules in projects?

warm nacelle
vestal hatch
#

Do I need to run that in a project that already has dagger setup but I've just freshly cloned?

warm nacelle
#

You just need a dagger.json file

vestal hatch
#

I have that 👍

#

The issue I have is files in .dagger don't auto complete the dag variable or the dagger module

#

I've setup the go work files as the docs suggest, it doesn't seem to have made a difference

warm nacelle
#

How is your neovim gopls plugin set up? Autocomplete was automatic for me once I'd run dagger develop

vestal hatch
#

Good question, I have just got vim-go installed via Lazy with no configuration options set

#

It is installed though and just running an update now

#

There was an update but it hasn't fixed this

vestal hatch
#

@warm nacelle if you don't mind sharing, how is your gopls setup?

regal seal
warm nacelle
#

Use Mason to install the Go extra and it all just worked

vestal hatch
#

Think maybe I'll build my config up again and see what happens

vestal hatch
#

So dagger develop needs to be run in order to put the .dagger/internal pkg in place, as this dir is in the .gitignore this fixes the issue I had

vestal hatch
#

I'm trying to export a file from the Container into the project directory with .File("/tst.md").Export(ctx, "./tst.md") bit the output of running dagger call shows the path as being /scratch/tst.md, what's the right way to do this?

Essentially I'm trying to get a cover report to attached to gitlab merge requests.

rocky karma
violet cosmos
vestal hatch
#

Got that working but have hit another issue, trying to use gocover-cobertura < cover.out > coverage.xml it seems that the > is ignored and the file coverage.xml is not created, anyone seen this before?

vestal hatch
#

Running as sh -c "gocover-cobertura < cover.out > coverage.xml" did the trick

violet cosmos
vestal hatch
#

Thanks, I did see those and tried it but found I preferred adding the file and using it in the command like that than getting the contents of the file and putting into the exec option input string.

I am quite liking the dagger system so far though

violet cosmos
vestal hatch
#

Yeah, that would be a nice improvement 👍

#

I see devine has already tried 😅

violet cosmos
#

Then you could have done:

ctr.
 WithExec([]string{"gocover-cobertura", dagger.ContainerWithExecOpts{StdinFile: "cover.out", RedirectStdout: "coverage.xml"})
violet cosmos
#

We should try again, with a Dagger-powered agent 🙂

vestal hatch
#

Yeah, much nicer than grabbing the content to push in

#

How good is the dagger ai stuff?

violet cosmos
#

The most underrated feature IMO is the interactive CLI. There's basically a codex-style interactive chat baked in the dagger CLI.

vestal hatch
#

think that's interesting, will take a look when I can

violet cosmos
sick fiber
#

quite new to dagger
maybe someone could help me 🙂

trying to build from dockerfile
then i want to get the sha of the build to use it for further flows
maybe someone can refer me to where and how : )

`func (m *EcsProject) BuildImageFromDockerfile(
ctx context.Context,
// location of directory containing Dockerfile
src *dagger.Directory,
) (string, error) {

ref, err := src.
    DockerBuild().
    Publish(ctx, "ttl.sh/image-name:latest")

if err != nil {
    return "", err
}

return ref, nil

}
`

regal seal
#

yeah, the ref you get at the end should actually have a digest in it

#

so it'll look like ttl.sh/image-name:latest@sha256:... - you just need to parse that to extract the sha

sick fiber
#

what i want is to, for example print the sha between the build and the publish lines

vestal hatch
#

Do all the properties and methods on a struct in a dagger pipeline need to be public?

regal seal
#

you could export it using AsTarball, then somehow extract the digest from the oci tarball? then publish it from that, but that's definitely a tricky flow

regal seal
vestal hatch
#

So dagger is doing some serialization of the struct in order to have it work with dagger call?

So I have func (t *Test) Lint(ctx context.Context) (string, error) {...} and within that I'm calling a private method and using a private property, this isn't possible with dagger?

regal seal
#

but for properties, those don't get persisted between calls - you can definitely use them, but they're gonna get set to zero values between calls

vestal hatch
#

Between call, meaning you can't use the dagger cli to do GenCoverOut | PrintCoverOut where cover out is stored in a private property? But I should expect that property to persist within the one dagger call lint?

#

Sorry the issue I have is that I have tried cleaning up my dagger call -h output and it is panicing with an invalid memory address

#

Is there a way to hide properties from the help output if making them private isn't the way?

#

Made one of the properties public again and it's working as expected, thanks for the help @regal seal

#

Looks like adding // +private is what I need

sick fiber
brave vine
#

I have some folks on my team that like to regularly run individual tests by clicking on the function name in vscode using its test integration. Since moving some of our tests to run inside dagger they can't do this. I don't use vscode personally, is there a way to configure the vscode test integration so that it'll run dagger call ... when running these tests? Or is there another way folks have made it easier to do this while still using dagger?

I think https://github.com/dagger/dagger/issues/5993 could potentially help here. I noticed its closed as completed?

GitHub

Right now if you want to call functions available in a module, the only reasonable ways are from another module or from the CLI. Otherwise you are on your own to load the module and construct graph...

vestal hatch
#

Hey all, just looking at the files generated via dagger develop --sdk go, I see there is a .gitignore and .gitattributes, is there a reason for having both?

regal seal
#

yes - lots of tooling follows .gitattributes to know if a file is generated
e.g. vscode will warn you if you try and edit a file that has the linguist-generated property (which we set)

#

.gitignore is because we don't want the file to be committed

vestal hatch
#

Ah okay, didn't think it was used outside of git, good to know 👍

brave vine
prisma arrow
rocky karma
#

Engine wide GOPRIVATE and GOSUMDB

warm nacelle
#

Want to double check this because it's either working or silently failing. Function parameter with a default and an enum type. I'm assuming as long as the default parameter value is a valid enum value then it works as you'd expect?

const (
  Plan               TerraformCommand = "plan"
  Apply              TerraformCommand = "apply"
)

with

// Terraform command
// +default="plan"
command TerraformCommand,
tawny carbon
#

Enum default

brave vine
#

So I have a function that returns a service, the important part is

func (m *NatsAuthCallout) NatsAuthCalloutSvc(ctx context.Context) (*dagger.Service, error) {
        <snip>

    natsSvc := dag.Nats().NatsSvc(userPublic, accountPublic)
    authCalloutCtr.
                <snip>
        WithServiceBinding("nats", natsSvc).
        AsService(
            dagger.ContainerAsServiceOpts{
                Args: []string{
                    "/nats-auth-callout",
                    "--config-file", "/tmp/auth-callout-config.yaml",
                },
            }).Start(ctx)

    return natsSvc, nil

My issue is that I end up with 2 instances of natsSvc running, one that does not have my authCalloutCtr hooked up to it. So every other request from my host hits the "bad" service.

I'm running it with dagger call -m dagger/auth-callout nats-auth-callout-svc up .

I know that WithServiceBinding will start the service. I'm not sure what to do differently here so that there's only one instance of natsSvc running?

rocky karma
#

You have Start(ctx) and also up in the CLI. I think both of those do the same thing. If you are using it with the CLI, you can remove the .Start(ctx). Then it won't run it twice.

brave vine
#

If I do that then the authCalloutCtr never gets started. I've tried to do natsSvc := dag.Nats().NatsSvc(userPublic, accountPublic).Start(ctx) as well but I still end up with two instances of natsSvc.

rocky karma
#

oh, why not return authCalloutCtr?

brave vine
#

because I need the actual nats container exposed, the auth callout container does expose an API or anything, it just needs to run in the background

rocky karma
#

ah.. yes I think you'd need that proxy for exposing multiple services

brave vine
#

Yeah I would prefer not to have to expose both but I don't know how else to get around doing that due to how WithServiceBinding works

rocky karma
#

oh you don't want to expose both? Hm, I don't think you need the proxy then. @signal mantle probably knows a better way to approach this.

brave vine
#

Oh yeah... proxy isn't gonna help. Really I want something like WithBoundService("nats") which would give me the "right" nats container

rocky karma
#

That's what supports the cookbook entry

signal mantle
#

yeah that sounds like the way to go. Somehow I haven't run into that kind of service dependency yet!

vestal hatch
#

Can I use dagger to run my e2e tests and debug them with delve? I assume this should be possible, are there any examples?

sonic island
#

Hi friends, I am making some changes in one of my modules that has a function that returns a custom type like this

type AttestationResult struct {
    OutputTerminal string
    // Attestation state
    OutputStatement string
    // Attestation bundle
    OutputBundle string
}

this means that after calling this method I need to chain with the property i.e dagger call my-function output-terminal. My question is, is there any way to tell the engine to by default return one of the properties while still have the flexibility provided by the custom type?

The background of this requirement is because currently our function returns a string and if we move to returning a custom-object we break backwards compatibility, so I am wondering if I could have the best of the two worlds, chaining enabled function + default returned value.

Thanks!

violet cosmos
rocky karma
violet cosmos
# rocky karma Hey Solomon, do you have a simple example of this? I am not sure I understand wh...

Well if you initially had:

func (m *MyModule) Result() string {
  // ...
}

And now you want to 1) return an object instead of a string, while 2) not breaking backwards compat. You can do:

func (m *MyModule) FullResult() AttestationResult {
  // ...
}

type AttestationResult {
  // ...
}

func (r AttestationResult) Description() string {
  // ...
}

// This is the alias
func (m *MyModule) Result string {
  return m.FullResult().Description()
}
#

It'a not a Dagger-specific pattern, you could do the same thing in eg. a Go package

rocky karma
#

Ah! Right.. I got confused with the word "alias" and thought it's some dagger thing I missed. Thank you for the example, this makes sense

sick fiber
livid quiver
#

I let my instance profile do most of the work in AWS, locally I'll just copy a short lived session in from my identity service

regal seal
#

oooh a new go release 😄

#

🎉 i shall celebrate now

dim arrow
#

HI there ! where could I find the list of all struct tags applicable to dagger functions / properties ?

violet cosmos
dim arrow
violet cosmos
#

I think +internal-use-only was perhaps a fake pragma to scare LLMs into not using a function

dim arrow
restive hollow
restive hollow
dim arrow
dim arrow
#

@restive hollow i actually do remember now what i was looking for. Is there a way to override the name of the CLI argument so it differs from the property name in the module function ? my use case is the following
If i have an array as an argument, it make sense that in the code it's pluralized ( e.g args) . But when i call the CLI i want have the arg as singular dagger call build --arg foo --arg bar

func (m *MyModule) Build(
  // i want to rename this cli argment
  args []string,
) {
...
}

violet cosmos
dim arrow
half vessel
#

Go module names for Dagger modules

I'm starting to look at some of the Dagger modules my team has developed, with the intent to apply our standard Go linting rules and styleguide across them. One of the things that has come up here is the module naming that Dagger creates; module dagger/{name} leads to the packages not meeting the expectations for Go module names (https://go.dev/ref/mod#module-path), where the repository name, and path to the module root apply. This also leads to inconsistencies in import ordering, where because the modules don't use a repository root path, they are treated as if they are part of the Go standard library, and ordered alongside the stdlib imports, while other linters expect them to be split from stdlib imports. These linters are all part of GolangCI Lint, not custom tooling for the organisation.

I've been able to successfully refactor (seemingly - more testing required) the existing Dagger modules to add in the repository root and paths to the module name and imports, however, this doesn't apply to new module creation, which continues to use dagger/{name}. My first question then is whether anything relies on the dagger/{name} module naming that prevents using fully qualified modules names? And secondly, whether it is possible to configure Dagger to create modules with fully qualified module names?

green terrace
restive hollow
violet cosmos
#

@half vessel for example, the dagger module at the root of our own repo is named github.com/dagger/dagger/.dagger (which is the actual path of the go module)

https://github.com/dagger/dagger/blob/main/.dagger/go.mod#L1

That name is not load-bearing either - it was just a subjective preference of one of the dagger maintainers at some point (I don't know the exact history)

agile mural
agile mural
# half vessel Go module names for Dagger modules I'm starting to look at some of the Dagger m...

I had that same dilemma when the naming convention was introduced.

There are cases where it doesn't really matter (for example: when maintaining a daggerverse repo: https://github.com/sagikazarmark/daggerverse/). It did bother me for a while, but there are no practical implications and the maintenance cost outweighs the benefits.

For actual application, though, I usually just rename the module to match the repository path.

whether it is possible to configure Dagger to create modules with fully qualified module names?

It probably is, but it isn't necessarily worth the cost. Dagger would have to take vanity imports and all kinds of stuff into account for this to work.

half vessel
# agile mural I had that same dilemma when the naming convention was introduced. There are ca...

if you had a module called go, it would collide with the stdlib go package? Or the go keyword?

This applies based on the last element of the module name regardless, given the current module naming is dagger/{name} ? I assume previously the dagger/ part wasn't included in the name here, so these were just module {name} like module go, which I can see being a problem. If this was github.com/{org}/{repo}/parent/path/{name} conflicts on the last element would be unchanged, but would represent a fully qualified module name. With this being a fully qualified URL path, it would not be misclassified as a package from the SDK (which applies for dagger/{name} due to the root dagger/ part of the path not being a domain).

It's interesting that https://github.com/dagger/dagger/blob/main/.dagger/go.mod#L1 is using a module name with a . in the path. I know I hit an issue with applying this approach to some of our other modules which are written in python, and use a dot prefixed folder in their path. I'll have to check what that issue was; I suspect it was in a parent path rather than the final element.

Given the advice here is that the module paths aren't load bearing, I'll continue to rename our modules to use fully qualified names. In our internal tooling, we'll need to have an extra step after the dagger init command for the new module to rename the Go module (to match the fully qualified url path).

agile mural
half vessel
# agile mural > This applies based on the last element of the module name regardless I don't ...

Right, yes. I can see how that prevents a collision with the SDK package paths 👍 This matches the advise from the official docs: https://go.dev/ref/mod#module-path

A module that will never be fetched as a dependency of any other module may use any valid package path for its module path, but must take care not to collide with paths that may be used by the module’s dependencies or the Go standard library

This also suggests that it should be ok to use such package names starting with dagger/ for locally resolved modules.

The very next sentence covers where the dagger/ module path prefix is getting confused with SDK packages:

The Go standard library uses package paths that do not contain a dot in the first path element, and the go command does not attempt to resolve such paths from network servers

This is then tripping up linters/formatters, which treat dagger/{name} as an SDK package, not a 3rd party or local one, and order it with the SDK group. Other linters know the valid SDK packages, and want it not in the SDK group.

agile mural
# half vessel Right, yes. I can see how that prevents a collision with the SDK package paths �...

Yeah, in those cases, manually rewritting the import path is the right thing to do. Fortunately, it works, and it's an easy thing to do (may not even need text replacing, you can use go mod edit).

Frankly, I never had an issue with linters, but I probably just ignore dagger code in my linter config.

In any case, in most of my projects (not my daggerverse repo), I also rewrite the import path. Never had any issue with that.

unborn bough
#

Its possibly to use go modules as both "module" and golang "library" at same time?
My idea was to create a golan module, for building/testing/pushing etc.. whole pipeline..
And then for some repos use it as remote modules..
And for some use it as library while allowing to modify some steps..
Is that feasible in golang?

Seems not easy.. right now I have bumped into

go get github.com/org/dagger-modules/{module}

error: package dagger/{module}/internal/dagger is not in std
foggy lava
#

Its possibly to use go modules as both "

spring fox
#

Is there a guide on any of the "gotchas" with Go and Dagger? I just ran into having an unexported member on a module struct that wasn't surviving between chain calls causing a panic: I think this happens since JSON unmarshal won't perserve those unexported fields in structs between chains.

old pier
spring fox
#

you should export the field (make it public) but add the +private pragma.

Right, that's basically what I did. It's just goofy since my "Go instinct" is to keep it unexported (i.e., lowercase) and not have to provide any metadata.

Seems that dagger's interpreter should "just work ™ " by setting the +private on unexported fields. Why wouldn't you want that?

#

It's almost like a double negative to have it exported in the Go code (so other API users of the module could in theory access it) while there's a +private that is a special dagger thing for just it's internal serialization.

sharp pike
#

Hey everyone! 👋 Before I file an official bug, I want to sanity-check a potential regression regarding private Go modules and SSH authentication.

The Issue:
Since v0.20.4 (tested up to v0.20.6), my Dagger module fails during code generation when building. It works in v0.20.3.

It appears the codegen container is no longer respecting the host’s Git configuration or SSH agent, causing go get to fail when it hits a private repository.

Symptoms:

dagger call fails during the "needs another pass..." stage of codegen.

Error: fatal: could not read Username for 'https://github.com': terminal prompts disabled.

I’ve detailed my configuration and suspected PRs in the thread below. Am I missing a new config requirement for v0.20.4+, or is this a genuine regression?