Over several months of testing these features with the community, we noticed something interesting: Dagger Functions are great for CI, but they can be applied to other problems as well. From test data management, to local AI development, to dev environments, to just-in-time artidfacts, to SaaS integration, to OpenAI development… The world is full of pipelines, just waiting to be Daggerized. We look forward to seeing what you build next!
#daggernauts
1 messages · Page 6 of 1
It's so weird it's called Functions and not Zenith. That name kinda grew on me. 😄
From someone who didn't look in the guts yet, excited about announcement but curious:
Do I need to install all the runtimes/compilers of all the tools my dagger functions use?
The promise of Functions is to have smooth cross-language functions, but if my python function calls a golang one, do I now need golang compiler on my machine?
That feels wrong, like eww now I'd have to care about every one of my function dependencies' language? So I'd think maybe dagger itself runs each of those runtimes in containers?
I initially thought that each module's call chain is turned into the language-independent GraphQL query, hence no compiler/interpreter needed, but then realized that if I use any native function (say in python concatenating an image name + a tag, as string operations), then GraphQL doesn't understand that, so you still need to run the real code.
zero dependency on your machine. Only the dagger CLI
fantastic =)
Can't wait to start making "CI Libraries but not Jenkins"
Hello, my main module sources are in the
same!!
We'll make a special edition sweat shirt 😁
Count me in for one of those 🙂
👋 just noticed that dagger init for Go doesn't add the internal or the dagger.gen.go files to .gitignore anymore?
didn't dagger stop adding any of the codegen to .gitignore? That's been the case in the last few releases afaik
I recall seeing some discussions about the .gitignore thing. It's tricky since users don't know if they should commit that to their VCS for dagger to work and I don't think we have that documented anywhere 😬
@kind carbon commented on whether we should commit all of that.
That's Go SDK specific. The motivation was that linting module snippets for docs failed in CI without dagger develop first. There's lots of them. @rocky harbor reasoned that there's precedent for committing generated files, like with protobuff, for example. I'm in favor of not committing them though.
well.. not all our examples are doing it: https://github.com/shykes/daggerverse/blob/3d608cb5e6b4b18036a471400bc4e6c753f229d7/hello/.gitignore
ah, ok maybe Erik 🙂
GitHub
Move dagger and querybuilder packages into internal package. See multiple points of confusion in discord:
#daggernauts message (c...
was there a takeaway on above? Can I safely .gitignore the internal directory in my new go modules?
yes you can. it's only a matter of convenience whether to commit them or not. They're regenerated at runtime no matter what
You would want to .gitignore the internal directory as well as dagger.gen.go in your module directory to have no generated code. They are both generated by dagger.
Getting Service.up(ports: [{front-end: null, backend: 8080, protocol: TCP}] during dagger call execution despite the frontend port being set (to 8080) in the module. Is this something to do with ports being equal, or unexpected behaviour? The service isn't available at localhost:8080 when the logs say it is, so seems like something isn't right?
so @warped canyon and @wintry prism, seems like @sharp zealot will ultimately propose adding a flag for this 😄
👋 is there a way to define a default value for a Dagger type? i.e I find myself typing dagger call $my_func --dir . every time to send the current dir to the function. I was wondering if there was a way to tell dagger to use the default CLI working directory as the default dir.
So, now that Project Zenith is complete, we need to decide what to do with this channel. Options are:
- Archive this channel
- Rename it to #modules-dev : a place to discuss the development of modules
- Other?
What do you think?
That's not possible yet, because functions are not allowed to have ambient access to the system. But we're working on adding a layer on convenience on top, to solve your problem.
I think mounting a directory is
Porting @chrome pilot demo to my modules repo: https://github.com/samalba/dagger-modules/pull/5 - I am going to try this to implement the CI part + bot, something we can likely reuse on dagger/dagger as well!
Chatting in dev-audio about Zenith for the next hour for anyone who wants to join!
@kind carbon do you have any WIP on your rye/pip stuff pushed up? Was curious to look at it for some inspration
Is there anything special we need to do with zenith in order use a custom image or mount certificates as shown here?
https://github.com/dagger/dagger/blob/main/core/docs/d7yxc-operator_manual.md#custom-ca-certs
How does Dagger establish if a pipeline is cached or needs to run? Does it check this on the host or tar up and send to BuildKit first?
this is going to be fun 🙂
@rocky harbor I just remembered why ID being a reserved word was actually a problem for my core wrapper: I need to expose loadFooFromID(id: String!) and that id: String! is forbidden
I'm getting this error initializing a new module, using dev dagger:
$ dagger init --sdk go
✔ ModuleSource.resolveFromCaller: ModuleSource! 0.7s
✘ ModuleSource.asModule: Module! 0.8s
✘ Module.withSource(
source: ✔ ModuleSource.resolveFromCaller: ModuleSource! 0.0s
): Module! 0.8s
✘ Container.directory(path: "/src"): Directory! 0.8s
✘ exec /usr/local/bin/codegen --module-context /src --module-name core --propagate-logs=true --introspection-json-path /schema.json 0.7s
┃ Error: exit status 1
✘ generating go module: core 0.3s
┃ creating directory internal
┃ creating directory internal/dagger
┃ writing internal/dagger/dagger.gen.go
┃ creating directory internal/querybuilder
┃ writing internal/querybuilder/marshal.go
┃ writing internal/querybuilder/querybuilder.go
┃ writing main.go
┃ go: open ../go.mod: no such file or directory
Error: failed to generate code: input: moduleSource.withContextDirectory.withName.withSDK.withSourceSubpath.asModule failed to create module: failed to update codegen and runtime: failed to generate code: failed to get modified source directory for go module sdk codegen: process "/usr/local/bin/codegen --module-context /src --module-name core --propagate-logs=true --introspection-json-path /schema.json" did not complete successfully: exit code: 1
Also reproduced with 0.10.0
Update: it works outside of my daggerverse repo 😭
It seems related to having a go.work. Removing it made the problem go away. Impossible to init any Go module in the repo otherwise
Somehow my developing one module interferes with developing others in the same daggerverse repo
The go.work seemed fine. No idea what was wrong with it
👋 not sure if this is considered an issue and/or it has been reported but is it expected for a constructor argument with a default value to resolve into a required argument for the Go SDK?
i.e:
func New(
// +default="foobar"
image string,
) *MyType {
return &MyType{}
}
resovles to dag.MyType(image) where image is a required argument even though it has a default value.
edit: testing in v0.10.0
if I add the +optional pragma it works as expected, but I was expecting that not to be necessary given that it has a default value
Oh, I know. I had just renamed a module
just double checked with the typescript SDK and seems to be working as intended as the generated Go code seems accurate even though I didn't have to specify stringArg as an optional parameter for containerEcho
@func()
containerEcho(stringArg: string = "foo"): Container {
return dag.container().from("alpine:latest").withExec(["echo", stringArg]);
}
resolves to:
func (*dagger.Testmodule).ContainerEcho(opts ...dagger.TestmoduleContainerEchoOpts)
@Erik Sipsma I just remembered why ID
Yeah there's some subtleties around optional/default still, @kind carbon wrote an issue describing them all recently https://github.com/dagger/dagger/issues/6749
How does Dagger establish if a pipeline
dagger/core/docs/d7yxc-operator_manual.m...
It occurs the same to me. By removing the go.work file, it was able to create the module. Isn't expected though. For a set of modules/functions inside a mono repository (I guess it's going to be the most common use case for shared modules) isn't ideal to remove the go.work and put it back after the module was created. 😛
Error: load package ".": err: exit status 1: stderr: go: module main appears multiple times i
┃ ace

It seems related to having a go.work.
Is there a way to handle when a library you might call in your function container needs an arbitrary binary dependency?
The example I ran into was trying to use psycopg2 as a function which has a dependency on the psql client binary (usually brew install postgres or similar puts it on).
I guess one somewhat non-ergonomic approach is to point the binary at the module and stage it in to the container manually via a function argument.... not really a super great UX though
You can use.file("") on an image that has the binary and WithFile in your container that needs it
yeah this one catches me all the time, there's an open linear issue for it: https://linear.app/dagger/issue/DEV-3459/default=foo-should-be-respected-without-optional - I suspect it's a quick fix
I think I am hitting a namespace conflict between 2 different dependencies...
github.com/shykes/daggerverse/docker-compose(): DockerComposegithub.com/shykes/daggerverse/docker().Compose(): DockerCompose
When I load both in my module, one DockerCompose type seems to overwrite the other.
Could fix this by adding a _ separator between module name + type name, which is safe since both sides get camel-cased. You'd have uglier generated type names but it seems like you rarely see those anyway
That's at least what we've said in the past, think we just never got around to it
Has anyone experimented with SLSA and Dagger?
Not properly yet, but I have an idea for potentially a rich integration here: https://github.com/dagger/dagger/issues/5621#issuecomment-1852318694
(for context, i worked on the attestations support in buildkit for quite a while)
I can't get this to work:
.withMountedCache(
`${workingDirectory}/node_modules`,
dag.cacheVolume(packageName)
)
Keep getting GraphQLRequestError: /code/node_modules: cannot retrieve path from cache
Also, why aren't "used modules" available via dagger call or dagger functions ?
Are Services supported with functions? I noticed all the services docs kind of disappeared with the latest release. I'm trying to get h2c working right now where I get a host service and expose it to my Function and it's not quite clear how to achieve that
services are definitely supported yup 🙂
It has to be passed as an argument. For example if you have an arg svc *Service, --svc tcp://localhost:8080
It has to be passed as an argument. For
That makes sense
I am stuck on either the same problem, or a very related one... This time there is no namespace conflict, and I have no clue what is causing it 😭
I'm going to hang out in #911305510882513037 for a while, in case someone is feeling generous and wants to help me troubleshoot. I'm blocked from shipping the solution for #1213207059974197308 (fyi @dense canyon )
Could anyone try to reproduce this please?
dagger functions -m github.com/shykes/daggerverse/scratch/bitgantter
I see this error:
Stderr:
# bitgantter/internal/dagger
internal/dagger/dagger.gen.go:2549:4: cannot assign to val.Client (neither addressable nor a map index expression)
internal/dagger/dagger.gen.go:2731:23: field and method with the same name Client
internal/dagger/dagger.gen.go:2721:2: other declaration of Client
internal/dagger/dagger.gen.go:2736:11: cannot use r.Client (value of type func() *DockerCli) as "github.com/Khan/genqlient/graphql".Client value in struct literal: func() *DockerCli does not implement "github.com/Khan/genqlient/graphql".Client (missing method MakeRequest)
internal/dagger/dagger.gen.go:2746:11: cannot use r.Client (value of type func() *DockerCli) as "github.com/Khan/genqlient/graphql".Client value in struct literal: func() *DockerCli does not implement "github.com/Khan/genqlient/graphql".Client (missing method MakeRequest)
internal/dagger/dagger.gen.go:2760:34: cannot use r.Client (value of type func() *DockerCli) as "github.com/Khan/genqlient/graphql".Client value in argument to q.Execute: func() *DockerCli does not implement "github.com/Khan/genqlient/graphql".Client (missing method MakeRequest)
internal/dagger/dagger.gen.go:2809:34: cannot use r.Client (value of type func() *DockerCli) as "github.com/Khan/genqlient/graphql".Client value in argument to q.Execute: func() *DockerCli does not implement "github.com/Khan/genqlient/graphql".Client (missing method MakeRequest)
internal/dagger/dagger.gen.go:2822:34: cannot use r.Client (value of type func() *DockerCli) as "github.com/Khan/genqlient/graphql".Client value in argument to q.Execute: func() *DockerCli does not implement "github.com/Khan/genqlient/graphql".Client (missing method MakeRequest)
internal/dagger/dagger.gen.go:2835:34: cannot use r.Client (value of type func() *DockerCli) as "github.com/Khan/genqlient/graphql".Client value in argument to q.Execute: func() *DockerCli does not implement "github.com/Khan/genqlient/graphql".Client (missing method MakeRequest)
internal/dagger/dagger.gen.go:2847:34: cannot use r.Client (value of type func() *DockerCli) as "github.com/Khan/genqlient/graphql".Client value in argument to q.Execute: func() *DockerCli does not implement "github.com/Khan/genqlient/graphql".Client (missing method MakeRequest)
internal/dagger/dagger.gen.go:2859:34: cannot use r.Client (value of type func() *DockerCli) as "github.com/Khan/genqlient/graphql".Client value in argument to q.Execute: func() *DockerCli does not implement "github.com/Khan/genqlient/graphql".Client (missing method MakeRequest)
internal/dagger/dagger.gen.go:2859:34: too many errors
@deft rain I was told by @mossy hazel that this error looks suspiciously like the name mangling issue he encountered with his SSH module. In my case, note that there is DockerCli, which looks like it could suffer from a similar problem.
I get Error: load package ".": err: exit status 1: stderr: go: module main appears multiple times in workspace
https://github.com/dagger/dagger/pull/6774 🙏 reviews needed and then maybe this issue can die 🎉
That was an unrelated go.work problem... I fixed it, could you try again?
now I get the same error as above
I tried with a python downstream module, and there is no error
Currently filing an issue
ah
this is because of Client as a method
I screwed up, and accidentally made it a reserved name
the fix for this is in https://github.com/dagger/dagger/pull/6716 (part of v0.10.1 milestone)
@deft rain thank you! So if I remove the field Client from my type Image, the module should work with 0.10.0?
Ah maybe I can even just make it private
Nice! Just making that one field private fixed the problem.
Note, I would never had guessed which field was causing the issue... Another one for the "confusing error messages" epic
@thorn moat when I persist a Service in an object's field, then chain several calls to that object, is it possible that the service gets re-instanciated instead of persisted?
I'm investigating a bug in my module, and it seems to point to a situation where the state of my service gets wiped in between calls to it
yep, known issue: https://github.com/dagger/dagger/issues/6493#issuecomment-1973928889
the issue talks about getting networking-related error messages, but I don't get that - just a seemingly well-running service that happens to have a wiped state.
the issue does, the relevant context is in the comments
Oh I see, the solution to that problem is the cause of my problem
yep yep
Got it
Could somebody help me with these two questions, please?
- Is there a known problem with cacheVolume and should my
dagger use'd functions be available fromdagger functionsanddagger call?
- not 100% sure, what are you seeing?
- no, not directly, but you can refer to them aliased as they appear in your
dagger.json- e.g.dagger -m <alias> ...
any suggestions for how we could get round the inevitable name conflicts? what if different modules define the same names?
dagger use ../rust --alias rust or omit alias to have none
dagger call rust:build ?
Moonrepo does a really good job of providing composable builds/tasks for monorepos, definitely some inspiration could come from there
I started to see No space left on device errors on GHA. Could be anything, I just wonder if it's something new that others started to experience as well?
dagger use ../rust --alias rust or
I started to see `No space left on
Calling for suggestions! We're going to announce Daggerverse soon. As part of that, we want to highlight specific modules with specific examples of using them. The goal is to get people excited about the possibilities.
I would love to see your suggestions for the most exciting snippets 🙂
Also: what medium should we use in the blog post to communicate the examples? CLI snippet only? Code snippets also? An animated gif? Something else?
Thanks, and I look forward to sharing the joys of the Daggerverse with the world!
I got hit by the arbitrary laziness rules while developing a module.
-
One function returns a custom type and an error (I force synchronous resolution, things can fail). But Go SDK exposes it as lazy. I cannot get the error right away. Unclear how to control that (add a
Sync()method to my custom type? But how do I implement it?) -
Another function returns a scalar, with no error. It's just an accessor. But Go SDK forces clients to pass a client and check for error.
TLDR: I got the perfect combo of too much laziness, and not enough
Dumping a few requests, I will file issues (or maybe they already exist).
-
I really would love
dagger installto always work. This means defaulting to installing in the user directory if not currently inside a dagger module. This would help simplify docs and daggerverse, becausedagger installcould always be step 1, then all thedagger callexamples could reference the shortname. -
Some commands, like
dagger develop, don't work in subdirectories of the module. But they should. Same as git commands. I think someone mentioned that one already. -
Query multiple fields from the CLI. GraphQL is super powerful for querying structured data, but
dagger callis not good a querying modules that take advantage of this. A simple improvement that would go a long way let me query multiple scalar fields at once, comma-separated. Eg.dagger call lint checks filename,error,rule-name,rule-description. -
Allow querying objects. When
dagger callreturns an object, don't fail with "requires a sub-command". Instead, query all the scalar types, and render them. For core types (container etc) query a safe and useful subset (which is almost all of it). Is it perfect? No. But it's better than the current situation. -
Error messages... Lots of low hanging fruits there. But that's already on the radar.
@sharp zealot would 6. be ability to call core API from the CLI?
Yes that would be cool too. I have a workaround, so not as urgent. But yes.
I remember you mentioning that and found myself wanting it the other day.
Big fan of all of these!
When I was working on a typescript module yesterday the runtime was taking about 30 seconds to build every time I ran anything. Afaik that's expected right now since the runtimes aren't cached between sessions, right?
I was going to show off a cool module, but I just hit a major performance edge case, so instead I'm going to show off that 🙂
The less-cool but less-slow example:
Run the official Dagger markdown linter against @warped canyon 's modules repo, and show the raw json report 😛
dagger call -m github.com/shykes/dagger/functions/linters/markdown@daggerize \
lint --source https://github.com/kpenfound/dagger-modules \
json
You can also query the individual fields of each check:
dagger call -m github.com/shykes/dagger/linters/markdown@daggerize \
lint --source https://github.com/kpenfound/dagger-modules \
checks error-detail
--> Unfortunately you can't query more than one scalar field from the CLI... yet 🙂 See checks --help for a list of fields
Now here's the part that gets slow: since I can't query multiple scalar fields in the checks, I thought - hey, what if I added a format function?
dagger call -m github.com/shykes/dagger/linters/markdown@daggerize \
lint --source https://github.com/kpenfound/dagger-modules \
checks \
format --text 'Dude! You messed up {{.FileName}} at line {{.LineNumber}}, by violating this rule: "{{.RuleDescription}}".'
--> This works, but on large results it's VERY slow. It looks like it runs the function sequentially against each check in the array. With the current overhead of function calls, it appears that adds up a lot.
Ah, actually it's pretty fast on that repo. I tried running it against dagger/dagger, and gave up before it completed...
For you @warped canyon 😛
Dude! You messed up dockerd/README.md at line 9, by violating this rule: "Multiple consecutive blank lines".
Dude! You messed up fly/README.md at line 4, by violating this rule: "Fenced code blocks should be surrounded by blank lines".
Dude! You messed up golang/README.md at line 5, by violating this rule: "Hard tabs".
Dude! You messed up golang/README.md at line 6, by violating this rule: "Hard tabs".
Dude! You messed up golang/README.md at line 7, by violating this rule: "Hard tabs".
Dude! You messed up netlify/README.md at line 4, by violating this rule: "Fenced code blocks should be surrounded by blank lines".
Dude! You messed up proxy/README.md at line 1, by violating this rule: "Trailing punctuation in heading".
Dude! You messed up proxy/README.md at line 5, by violating this rule: "Hard tabs".
Dude! You messed up proxy/README.md at line 6, by violating this rule: "Hard tabs".
Dude! You messed up proxy/README.md at line 7, by violating this rule: "Hard tabs".
Dude! You messed up proxy/README.md at line 10, by violating this rule: "Multiple consecutive blank lines".
And finally... You can also fix the simple errors (in theory)
dagger call -m github.com/shykes/dagger/linters/markdown@daggerize \
fix --source https://github.com/kpenfound/dagger-modules \
export --path ./fixed-it-for-you/
If you like what you see, consider a +1 on my PR 🙂 https://github.com/dagger/dagger/pull/6816
GitHub
Implement Dagger Functions for our official markdown linter. Example usage:
dagger call -m github.com/dagger/dagger/functions/linters/markdown
fix --source ./docs
export --path ./docs
This i...
I really need to demo more things like this. So cool
Lately we've been talking a lot about the downsides of having functions be completely separated from the git context of their module (no ambient access to the monorepo etc).
But there are advantages too... This is a good example.
Is that embedded markdown linter a "main" function or a "utility" function? I say: yes 🙂
Hi, I begin to play with dagger functions since some days but I'm facing a bug.
I have somewhere in my module an optional input with a list of lists when I'm calling the code directly from my golang code everything work without using this input
When I try to do the equivalent with the cli with same args I have the following error: Error: unsupported list of lists for flag: system-setup-cmds
(So it's not blocking me but I was finalizing my module documentation)
Should I avoid to have list of lists and doing chaining functions ?
what is strange is dagger installing the module or calling my test code for testing this function is working well
@rose hinge it's perfectly valid to take list of lists as argument in your function. There's just a limitation in the CLI, which prevents passing that particular argument. It's strictly a limitation of the CLI, as a client to your module's API. Your module is perfectly fine.
(sorry about that limitation 🙂
ok no problem so it means when I have this type of args the function is no more callable from the cli even if this one is optional
Ah I see what you mean! Apparently yes, but that seems like a separate bug, that we should be able to fix quickly
Since it's optional, it should still be possible to call the function without passing that particular argument
Wait!! It gets better 🙂
ok just to give a little example I was doing a call like that: dagger --debug call with-auto-setup --pipeline-id="testdata-myapi" --src=../testdata/node/myapi/ pipeline --dry-run=true --ttl=5m --is-oci=true without the --system-setup-cmds
@sharp zealot do you want I open an issue or there is yet one ?
@warped canyon export only the linted files:
dagger call -m github.com/shykes/dagger/functions/linters/markdown@daggerize \
lint --source https://github.com/kpenfound/dagger-modules \
files \
export --path ./linted/
That would be very useful! Thank you!
Query the contents of the file for an individual check (limited to one check here, to avoid too much output)
dagger call -m github.com/shykes/dagger/linters/markdown@daggerize \
lint --source https://github.com/kpenfound/dagger-modules \
checks --limit=1 \
file
Query the fixed file for an individual check (if fixable):
dagger call -m github.com/shykes/dagger/linters/markdown@daggerize \
lint --source https://github.com/kpenfound/dagger-modules \
checks --limit=1 \
fix
And finally... 🙂
Show the diff for each (fixable) check:
lint --source https://github.com/kpenfound/dagger-modules \
checks \
diff
I kind of want to shorten that path, and make it github.com/dagger/dagger/linters
-
call core functions from the CLI
-
-m FOOshould load the latest tagged version of FOO, if it exists. Not from dev branch by default
A quick and sort of a more broad question rather than a specific Zenith question (can I still use Zenith? it has a special space in my heart I'd say 😅 ) — what's the most recommended approach to pass content into our modules? I usually apply WithMountedDirectory but sometimes when the directory that's being mounted has a lot of files (e.g.: a .terraform folder, or a .git directory) makes things slow — and, as far as I can tell there isn't a way to exclude files or directories as we have when we're using WithDirectory where we're copying into the container's FS.
🤔
dagger init doesn't generate a .gitignore file anymore?
Also, the module name in go.mod is weird.
dagger init --name slsa-verifier --sdk go --source .
Results in: module dagger/slsa-verifier
Is that intentional?
yes, it's been changed from main now
we need something unique per module, otherwise the daggerverse structure doesn't work (since go.work is a thing, blehh)
and we can't just have the dagger module name, since some go module names are reserved (like go)
there's no .gitignore anymore for go, we are looking at having this be configurable in dagger.json
there's a prior conversation somewhere
Understood, thanks
How do I achieve something like this using WithMountedFile?
c.Directory("/work/artifacts").WithFile("", artifact)
Basically I want to mount the file using it's original name, without having to resolve it first. Is that possible?
This is what I'm trying right now:
artifactsDir := dag.Directory().With(func(d *Directory) *Directory {
for _, artifact := range artifacts {
d = d.WithFile("", artifact)
}
return d
})
ctr = ctr.WithMountedDirectory("/work/artifacts", artifactsDir).
But I don't know if this is the best option from a performance perspective.
👋🏼
I am not sure if something has changed but I am getting 403 errors while pulling a public container image from GitHub
func (m *TroubleshootDagger) TestPull() *Container {
return dag.Container().From("ghcr.io/chainloop-dev/chainloop/cli:v0.75.2")
}
and this is the error
dagger call test-pull
✔ initialize 0.5s
✔ ModuleSource.asModule: Module! 0.1s
✘ TroubleshootDagger.testPull: Container! 0.6s
✘ exec /runtime 0.6s
┃ json: error calling MarshalJSON for type *dagger.Container: input: container.from failed to authorize: failed to fetch oauth token: unexpected status from GET request to https://ghcr.io/token?scope=repository%3Achainloop-dev%2Fchainloop%2Fcli%3Apull&service=ghcr.io: 403 Forbidd
┃
✘ Container.from(address: "ghcr.io/chainloop-dev/chainloop/cli:v0.75.2"): Container! 0.2s
👋 question about service binding and the ability for the DAG to start resolving things ahead of time which don't require the service to be ready. i.e I have the following code
ctr, err := m.goBase(ctx, c)
if err != nil {
return "", err
}
return ctr.
WithServiceBinding("postgres", postgres.AsService()).
WithExec([]string{"go", "run", "main.go")
Stdout(ctx)
}
thing is that goBase has some WithExecs like go mod download before the postgress service gets bounded but given how the DAG gets resolved today, the go container won't execute any anything until the postgress service is healthy. I'm aware I can improve this by manually calling sync before binding the postgres service, but it still doesn't quite solve the problem as the postgres service won't initialize until the sync is done 😬 .
I'd assume it's not a trivial thing to do. cc @thorn moat ?
WithMountedDirectory is cheaper because there is no copy required. WithDirectory always copies, so even though it has include/exclude, that will only optimize that last copy. If you mount, there is no copy.
Either way, your choice will not affect performance of how the input directory is produced upstream from you. In particular, if it's loaded from a local filesystem (dag.Host.Directory, dag.CurrentModule.Workdir...) and that directory is very large, any includes/excludes need to be applied upstream at that point. At the moment the CLI cannot specify include/exclude, that's the issue @latent trellis is encountering.
🎉 https://github.com/dagger/dagger/pull/6843 opened a draft of our own ci modularization 😄
still got a lot of work to do, but happy with the skeleton 
yessssssssssss! the day approaches where I don't have to look at our console output from hack/dev 🎉
Nice 🙂 Wasn't sure if that branch was still active 😁
Should I expect a merge conflict for my little markdown linter PR?
thankfully not ❤️ i'm still working out exactly how to integrate this in, i'd like to aim to get it in asap, even if it results in a slightly worse experience - at least that motivates us to iron out the issues
get it in asap
you're talking about pr 6843 right? I agree.
really nice seeing all that dogfooding feedback
new tui is so nice
it does such a good job of "what's happening right this second" - which is actually really helpful to indicate where there may be performance issues
agreed!
if i could have a strange feature request @thorn moat 😆
so i made this little helper dev function to drop you into a terminal with a connected dagger instance, and i really like it, and it's neat.
but. i kind of lose visibility of the engine logs while that's happening, and there's not really a way to grab them, but it almost feels like now i'm asking for a full on terminal emulator
(i might also not always want service logs... like it's almost like i want a tmux integration or something like that)
lol, that's literally what it's doing (it's actually running in a virtual terminal emulator and painstakingly making sure to write things that go out-of-view into the outer terminal's scrollback), but I never got around to implementing side-by-side visualization in one TUI. implementing a whole terminal emulator is a lot of work so now I'm playing with @sharp zealot 's idea of running a separate dagger watch/wiretap/trace/logs command to view activity from your dev shell instead
for context - today i tend to develop dagger with 3 terminals:
- run builds, run tests, dev commands, etc
- view logs of the running
dagger-engine.dev - one client terminal with
_EXPERIMENTAL_DAGGER_RUNNER_HOSTset, so i can run round my local filesystem and play with examples
collapsing everything together with one module command is nice, but it feels like i lose a little bit of visibility into what's going on
dagger watch would be pretty close! something that could let me attach to a specific running session and view different things that are going on 😄
yup yup. I actually had to implement all the necessary infra already as part of the otel work. there's a little otel pub/sub stack, but it's not exposed yet. we could probably expose it as a GraphQL subscription
could possibly even let you interactively select which session you want to watch, based on the trace's root span name (which is the full command + args, so should be easy to identify)
this also plays a bit into another weird ask, which is that sometimes with lots of services, the screen can get a bit full - it would be really nice if i could cycle between the combined view and each service / the main pipeline as i want to
but then the tui becomes interactive, so maybe that's a no-go
keyboard interactivity is fine, mouse interactivity is fine too as long as we don't grab the scroll wheel. I've been meaning to add arrow keys so you can move back to things that go out of view at least
@deft rain what I want with watch is a continuous TUI feed of everything I'm running on a particular machine, or perhaps terminal. Just leave it there running all day, like an activity monitor
this would be easy too, the pub/sub supports subscribing to all traces 👍
hehe i don't even need to make requests now, you've just forseen everything
is there an internal/external writeup of the context of the otel work? sorry, i'm a bit out of the loop so far on it
not really, tl;dr we're at a point where we can break compatibility with the old Cloud event stream, and we figured it'd be better to take that opportunity to adopt a standard telemetry pipeline rather than double-down on Progrock for another iteration. the extra context is otel now has support for logging (kind of... we've had to write our own Go SDK boilerplate), which was the main value-add Progrock had over it
I started writing down a few ideas about writing modules: https://gist.github.com/sagikazarmark/53a77bf72ad494154f691c0ccd968e35
Question: which one do you think makes more sense?
type Python struct {
// +private
Ctr *Container
}
func (m *Python) Container() *Container {
return m.Ctr
}
vs
type Python struct {
Container *Container
}
Or to put it differently: does it make sense to hide struct members? They aren't "writable", are they?
I remember I started using this pattern for some reason, but I can't really justify it anymore.
I hide them to keep my api clean
in what i've been doing today, i've been quite aggresively hiding struct members
i like the idea of the dagger cli providing the "canonical" experience, without needing wrappers, and private helps keep the api clean and interacting with things that might not make sense to the consumer
unless I specifically want to expose a getter function
Yeah, that's my default strategy as well. But it proved useful on more than one occasion to gain access to the underlying container as sort of an "unsafe" API.
maybe // +hidden could be a thing? hide it, but still allow some sort of access?
The question here is whether hiding struct members and exposing them through functions make any difference. Again, I can't recall why I started doing this.
eh, not convinced on that actually.
the cache volume point is interesting, I know in the past we've considered scoping caches to modules by default somehow (cc @sharp zealot @rocky harbor @dense canyon, don't remember who else)
and yeah, the version/image/container flexibility gradient makes a lot of sense to me too
There is also cache sharing mode, but afaik the default is to share across pipelines and that still only means only one pipeline can use it at a time, doesn't make it exclusive for a project
ah yeah that's more around concurrency, 'shared' means allow concurrent read/write access
a configurable scope(?) could make sense
yeah cache volumes should definitely be scoped to module unilaterally (not configurable). No downside to that IMO.
yea I think at the time we just didn't have bandwidth to shake out the implementation details
I have a question about cache volumes should definitely be scopes to module, does it mean if we are using the distributed cache from dagger cloud we won' t be able to have a common cache volume between several pipelines ?
I ask that because actually we have a pipeline which consist to update and store in a cache volume a maxmind db then we are different services which pull this cache volume for testing / build purpose
like that we don' t have to maintain the maxmind db in several repository
@rose hinge you could still do that as long as all the functions using that cache volume are all in the same module
But, if they are not in the same module, then you should avoid using cache volumes as an "implicit API" between your modules
Here is another question: most of my modules are "low-level", meaning they are centered around a single tool (eg. Go or Helm). In some cases, there are tools around the same ecosystem that rely on each other.
For example:
- Golangci-Lint depends on Go
- Helm docs depends on Helm
Currently these (golangci-lint, helm-docs) are separate modules. Although it isn't visible in the API, cross module dependencies actually make these modules more complex.
I'm working on a python module now and I'm trying an alternative approach: instead of making a separate poetry module, it's gonna be a "submodule" of Python.
For example:
dag.Python().WithPipCache(...).Poetry()
// here comes the poetry specific API
A part of me is against it, because it's hard to define a fine line what should be part of a python module and what shouldn't. At the same time, maintenance is definitely easier (for example: due to that WithPipCache call, part of the module initialization would have to be delayed in case of a separate poetry module)
Any thoughts about that?
Here is another question: most of my
- Let me reference submodules of my dependencies 🙂 That way I could do:
# Install my daggerverse
dagger install github.com/shykes/daggerverse --as=shykes
# Call supergit from my daggerverse
dagger -m shykes/supergit call --help
# Call docker from my daggerverse
dagger -m shykes/docker call --help
etc. Right now this fails because it interprets it strictly as a local directory. 🙏 🙏
@kind carbon would you consider running a "How to write a Dagger SDK" mini-workshop? 🙂 🙏 I would attend eagerly
Trying to play with your codegen module at the moment
Is there a way to introspect my dependencies?
Yeah, I think if you run the codegen module from inside yours, it should introspect the whole API at that point, including your dependencies.
Planning on working on docs for that, haven't had time to circle back to the codegen module yet, but it'll make it much easier to implement.
Are you sure? That would be useful for my use case, but seems like a pretty serious scope leak no?
How does a dependency (in this case the module codegen) have access to its siblings in the dependency tree?
The codegen module simply makes a introspection query to the API. It's what any SDK needs to do and is native to GraphQL. The difference is just marshaling the resulting JSON into a data structure and attaching functions to it. But the data is available to anyone with any access to the API.
Right, in that case that introspection query will probably not include the siblings, but rather the current module's own dependencies. In other words, the codegen module will only ever see its own dependencies (plus core API of course)
I would need a way to pass a target module as argument to codegen, so that it can somehow introspect that
No, the main introspection feature has no knowledge of modules and functions. It's just accessing the whole GraphQL schema. Try putting this in the playground or a dagger -m <mod> listen session:
dagger -m github.com/helderco/daggerverse/codegen@v0.1.0 call introspection-query | pbcopy
Yeah, I understand
If you want module specific introspection, and navigating through the intermediary TypeDef representations, you can see how the following's implemented:
dagger -m github.com/helderco/daggerverse/codegen@v0.1.0 call experimental --help
But whether I use raw graphql introspection, or typedef introspection, I'm still only introspecting the current API available to the codegen module, which happens to not include any of the caller's own dependencies, right? That's the problem I'm trying to solve: I want to write a tool that can interact with the caller's current dependencies. It seems there isn't a way to do that from within a 3d-party module, so I might have to hardcode it into a custom client instead (or fork the dagger CLI itself )
ie. I want to be able to do:
$ dagger install foo
$ dagger instal bar
$ <magic-command> list
foo
bar
I guess I could pass the dagger.json as an argument
Is it limited? I'd expect it would be able to see the whole API, but haven't actually tried it like that.
To my knowledge dependencies are scoped: each module only sees its own dependencies. This is a valuable feature, for example it eliminates a whole class of "dependency hell" problems. Different modules in the dependency tree can import different versions of the same module, without conflicts
Ah, that's right. The codegen module also works from an introspection result if you can get one by other means. That's what I planned on using in the runtime module since an introspectionJson argument is provided by the server. But where can you get access to the API with dependencies included?
Right, you can loop the dependencies in dagger.json and load them individually from your module.
There's an API for that, not sure atm if it's public or not.
This would make my life complete
@kind carbon yeah exactly, I was wondering if codegen did any of that, or if not - maybe I can contribute it? 🙂
Also I was wondering if the CLI had the ability to pass a Module type as argument, maybe that can be a contribution down the line also
@rocky harbor just added that recently
wat
he's also doing that ID flattening thing i've been bringing up. truly a real-life 🎅
I don't know what that is, but I love it already
Oh I forgot about that: https://github.com/dagger/dagger/pull/6761
- Let me pass subdirectories to a git repo in the command-line. eg.
--source https://github.com/dagger/dagger/docs--> that last/docswon't work
Oh look at that:
$ dagger call experiment --mod-source=.
codegen
docker
dagger.json:
{
"name": "python-codegen",
"sdk": "python",
"dependencies": [
{
"name": "codegen",
"source": "../codegen"
},
{
"name": "docker",
"source": "github.com/shykes/daggerverse/docker@c9a80c9eac0675a53a7e052da3594207f4235988"
}
],
"source": ".",
"engineVersion": "v0.10.0"
}
Function:
@function
async def experiment(self, modSource: dagger.ModuleSource) -> list[str]:
deps = await modSource.dependencies()
return [await mod.name() for mod in deps]
Ha ha amazing 🙂
I thought I'd share a few neat tricks I discovered today:
-
You can run a function directly from a pull request 🙂 For example:
dagger call -m github.com/dagger/dagger/linters/markdown@pr/6816/head --help -
Sometimes your function runs a command in a container, and you also want to expose the container for interactive debugging. But then you don't have anywhere to store the same command. The trick: you can write that command to the container's shell history, so from the terminal you can just type ⬆️ and it's there 🙂
Oh 2) is genius!
how cool would it be if a future version of daggerverse included auto-generated gifs of the coolest way to use a module 😁
🐞 I'm hitting another codegen error triggered by installing a dependency... 😦
dagger init --sdk=go --source=.
dagger functions # success
dagger install github.com/quartz-technology/daggerverse/dagger@7c59dc94edaf73d9324abe2c36f946ace0d832e6
dagger functions # error
My output:
✘ initialize 0.6s
✔ ModuleSource.asModule: Module! 0.3s
✘ Module.initialize: Module! 0.2s
✘ exec go build -o /runtime . 0.2s
┃ internal/dagger/dagger.gen.go:1949:15: r.Query.Select undefined (type func(ctx context.Context, query string) (string, error) has no field or method Select)
┃ internal/dagger/dagger.gen.go:2008:15: r.Query.Select undefined (type func(ctx context.Context, query string) (string, error) has no field or method Select)
┃ internal/dagger/dagger.gen.go:2023:21: field and method with the same name Query
┃ internal/dagger/dagger.gen.go:1903:2: other declaration of Query
┃ internal/dagger/dagger.gen.go:2027:15: r.Query.Select undefined (type func(ctx context.Context, query string) (string, error) has no field or method Select)
┃ internal/dagger/dagger.gen.go:2041:15: r.Query.Select undefined (type func(ctx context.Context, query string) (string, error) has no field or method Select)
Error: input: module.withSource.initialize failed to initialize module: failed to call module "dsh" to get functions: call constructor: process "go build -o /runtime ." did not complete successfully: exit code: 1
Stderr:
# main/internal/dagger
internal/dagger/dagger.gen.go:1917:15: r.Query.Select undefined (type func(ctx context.Context, query string) (string, error) has no field or method Select)
internal/dagger/dagger.gen.go:1929:15: r.Query.Select undefined (type func(ctx context.Context, query string) (string, error) has no field or method Select)
internal/dagger/dagger.gen.go:1937:15: r.Query.Select undefined (type func(ctx context.Context, query string) (string, error) has no field or method Select)
internal/dagger/dagger.gen.go:1949:15: r.Query.Select undefined (type func(ctx context.Context, query string) (string, error) has no field or method Select)
internal/dagger/dagger.gen.go:2008:15: r.Query.Select undefined (type func(ctx context.Context, query string) (string, error) has no field or method Select)
internal/dagger/dagger.gen.go:2023:21: field and method with the same name Query
internal/dagger/dagger.gen.go:1903:2: other declaration of Query
internal/dagger/dagger.gen.go:2027:15: r.Query.Select undefined (type func(ctx context.Context, query string) (string, error) has no field or method Select)
internal/dagger/dagger.gen.go:2041:15: r.Query.Select undefined (type func(ctx context.Context, query string) (string, error) has no field or method Select)
$
Calling the dependency itself works fine:
$ dagger functions -m github.com/quartz-technology/daggerverse/dagger@7c59dc94edaf73d9324abe2c36f946ace0d832e6
Name Description
cli CLI returns a ready to use Dagger container with CLI installed.
install Install returns the same Container with the Dagger CLI installed in it.
Looks like maybe a name conflict on Query? https://github.com/quartz-technology/daggerverse/blob/7c59dc94edaf73d9324abe2c36f946ace0d832e6/dagger/commands.go#L66
Assuming the problem is indeed a name conflict: I don't know if there are new name conflicts popping up over time, or if I'm just gradually discovering them, but it's been quite disruptive, at least to me.
sorry @upbeat herald I had to uninstall your module
I think I might just need to update my module and change the naming if that’s the issue.
I could not have known haha
However that’s strange, I used the module in other modules and it worked just fine
dumb question, how do I run a command that creates a file inside a container and then fetch that file?
ctr.WithExec(args).Stdout(ctx)
for some command that writes to the filesystem, and then
ctr.File("/path-to-file-written-by-command-above").Contents(ctx)
shows the file not found
┃ 2024/03/07 10:31:17 error reading key for sa: input: resolve: container: from: withEnvVariable: withEnvVariable: withFile: file: lstat /root/sa-key.json: no such file or directory
I'm guessing File() operates on the container image rather than the container filesystem that results from the first command?
hm, that's really odd, File() should be operating on the filesystem in ctr
what i'd do, is re-assign ctr = ctr.WithExec(args)
then get Stdout and File on it, and there should be no issue hopefully!
oh cool, yeah maybe I'm expecting ctr to be mutated, but I actually need the reference to the new one. I'll test this - thanks @deft rain!
generally, i don't think any dagger value ends up getting mutated - it's a bit of a more functional approach to an api (which means you can easily get to any point in history of a build, which is quite cool)
opened a fix: https://github.com/dagger/dagger/pull/6849
potential idea for daggerverse here: could we run codegen for submitted modules for go/ts/python and check that the codegen succeeds? i'm guessing this isn't something we're currently doing? @thorn moat
Should happen already, daggerverse has to load each module to generate its docs
I guess it works in daggervese (https://daggerverse.dev/mod/github.com/quartz-technology/daggerverse/dagger@7c59dc94edaf73d9324abe2c36f946ace0d832e6) because in this case the codegen conflicts with the local module code generation? As solomon highlighted running dagger functions -m on that module actually works.
Use dagger as a Dagger module.
yeah the engine loading works fine, it's when the module gets codegen-ed for go that it has the issue
oh i see what you mean now
Is there a way to do a higher order function? Eg a module with a parameter which is a function that takes a container and produces another container?
Use case: implement codemod s using dagger, and provide a higher order function that produces a diff a before/after and runs the tests after running the codemod
You can't pass functions as arguments (yet).
I take yet to mean there’s at least some interest in this. Is there an issue tracking this request?
I don't think so. We discussed it as a downstream application of stable IDs aka "IDv2". cc @thorn moat
Sounds like a use case for interfaces to me? https://docs.dagger.io/developer-guide/go/637319/interfaces/
Is there an equivalent for this in the python SDK, and can one use dagger call with this?
No Python support yet afaik (cc @kind carbon) - it's somewhat experimental. And there's no way to pass an interface/object through dagger call, curious what you'd expect to type there
I’d like to create an implementation of the interface in another module (eg run clang-tidy, or comby replace class A with class B). Then call a function in the module that defined the interface to run a diff and test it
So the thing to pass would be either a factory function name or a constructor to specify the implementation of the codemod to use and probably a container as the argument to the codemod
Oh sorry, maybe I misunderstood. Was focusing on the idea of passing functions by value in an argument. But it looks like maybe that's not what you were asking for.
Ideally I can write these in different languages, but what I care about is Python on both sides because that is what I can expect colleagues to write
Ideally yes, but if what I have is interfaces then I can settle for an implementation of an interface. These aren’t that different. In fact an interface is probably a bit more powerful because it models a type class and not just a type
I've wanted the same thing, so you can define a module for your "Home" (i.e. personal dev environment, editor config etc.) that can install itself into per-project dev entrypoints (assuming a common OS, in my case Wolfi)
That would be another use case Ive considered @thorn moat
I just figured tooling around portable code mods was an easier sell 😅
Yeah I think the thing in common is taking an interface arg, which is tricky because the problem to "solve" in the CLI then is how to pass an arbitrary object in. Theoretically it's possible by passing any object's id string fetched from the GraphQL API, but that's not the best DX, and isn't exposed atm. If you have a module that can be constructed without params, maybe we could support something like <module ref>#<function> (strawman), so something like github.com/vito/daggerverse/home#installer for my case, or github.com/foo/codemod#modder for yours (not sure, just spitballing)
Yeah, I’m fine with default constructable being a requirement
Or we go full IDs + pipes, dagger call -m usermod use-iface --fooer $(dagger call -m foo fooer id) - a bit verbose, just putting it out there
For non default constructable things, pipe syntax is an acceptable compromise, but default constructors give me 90% of my use cases
I needed that exact pattern for my daggy module (LLM does the stitching via CLI, so need the IDs). I got it to work, but needed a wrapper module (github.com/shykes/daggerverse/supercore).
I needed the wrapper because:
- You can't call
IDfrom core types (special case in the CLI to block it) - You can't call core functions from the CLI
- Even if you could, the CLI interprets ID arguments in a custom way, you can't pass the litteral ID
Note: I'm talking about the calling pattern, not the part where you pass functions or interfaces around. I'm doing it for regular objects.
@sharp zealot while we're on the subject of IDs, there's an open bikeshedding window, if you have time: https://github.com/dagger/dagger/pull/6836#discussion_r1515489023
(this is the "ID flattening" thing I mentioned yesterday, requires a protocol change, so good time to bikeshed)
DAGGER_MODULE=github.com/shykes/daggerverse/supercore \
dagger call \
fs \
load \
directory --snapshot=$(dagger call \
git \
repository --url=https://github.com/dagger/dagger \
ref --name=main \
tree \
save \
) \
entries
Notes:
- I had to create custom wrapper types in order to get the ID. Since
IDis reserved by the SDKs, I had to call it something else:save - Since I had to write custom wrapper tools anyway, I took the liberty of experimenting with improvements to the core API 🙂 Hence the name
supercore. I'm also going to pushcorewhich is a straight 1-1 pass-through: it basically only exposes the top-level funtions as is, with strings instead of IDs. You have to callsyncfrom the CLI until we remove the "hidden ID" issue
Unrelated is there a way in a module to look for a device file on the HOST, and then mount it on a container passed as an argument
I’m thinking about generalizing GPU device support to incorporate the weird accelerators that I use at work.
Another use case would include a module that mounts /dev/kvm to allow VMs to run on Linux for other operating systems
Both of these would need to be “privileged” modules
mount custom devices
A little sneak preview of something I'm working on for dogfooding 🙂
Interesting! What is the use case for that?
A solution to the "ambient system access" problem, with builtin scripting support 🙂
#daggernauts message
The above 👆 is a full bash-compatible interface to the dagger engine. I'm experimenting with the syntax for it. Can be used to pass all those repetitive flags , cc @latent trellis 🙂
Imaginary scenario:
$ jq -r .scripts.build.lang dagger.json
bash
$ jq -r .scripts.build.source dagger.json
kpenfound/golang --proj=. \
build --args=./cmd/foo --arch $DAGGER_ARCH --os $DAGGER_OS \
export --path=./bin/foo
$ dagger run build
$ ./bin/foo
I sort of get it. Would love to see more. It's like a package.json basically.
It's a combination of:
- A builtin bash-compatible shell that executes dagger functions instead of local commands
- A simple way to save scripts in dagger.json and run them with a short commands - a-la package.json. Unlike regular npm scripts, those would be interpreted (and sandboxed) by the builtin shell. So more reproduceable, safer, etc. We can allow environment variable access, but do static analysis of which variables are accessed, so that the user can decide whether to allow it or not; we can virtualize the variables; we can scope local filesystem access to the boundaries of the current module; etc
Nice!
Sounds good for local development but I am curious how that extends to running dagger functions in a CI orchestrator like Jenkins. IIUC, the shell won't work in that instance.
Is it possible to dynamically add/call a dependency at runtime to a zenith module?
If I export a directory using export, have we considered having a way to replace the contents that were previously there? (instead of overlaying everything that was there, so old files wouldn't get cleaned up)
I'm trying to come up with a way to push to a git repo from Dagger and open a PR on GitHub.
I'm looking at supergit as a potential solution.
Shouldn't these be mounted directories? https://github.com/shykes/daggerverse/blob/main/supergit/repository.go#L54
cc @sharp zealot
Is it possible to dynamically add/call a
If I export a directory using export,
Chatting about Zenith for the next hour in dev-audio for anyone who wants to join!
I can't make it, but humbly submit my list of requests as possible topics for discussion 🙂
You can unroll the list from here 👆
I haven't had time to make the issues, but will get to it
@rocky harbor I tried what you suggested earlier for calling the dagger cli from a module:
func (m *Ci) DaggerCall(ctx context.Context) (string, error) {
ctr := m.getBaseImage(m.WorkDir.Directory("ci")).WithExec([]string{"sh", "-c", "apk add --no-cache docker"})
ctr = ctr.WithExec([]string{"sh", "-c", "curl -L https://dl.dagger.io/dagger/install.sh | BIN_DIR=/bin sh"})
ctr = ctr.WithExec([]string{"sh", "-c", "dagger functions"})
out, err := ctr.Stdout(ctx)
if err != nil {
return "", err
}
return out, nil
}
I get 1: [0.59s] Cannot connect to the Docker daemon at unix:///var/run/docker.sock. Is the docker daemon running? - Given the CLI still depends on the docker cli, I guess I'll have to wait for supporting mounting sockets in module to make that use case work
the tl;dr on how this related to v2 refs: I wanted to turn module refs into just a way to refer to a Directory, so dagger -m github.com/vito/daggerverse/apko would just be how you referred to a Directory that came from a git repo. (or git://git.sr.ht/foo/bar//baz to show an example of not special-casing github.com). So all module flags would actually just be Directory flags, and you could use those same refs anywhere that took a Directory
RFB (Request For Bikeshedding) on this PR for supporting directory arg filtering: https://github.com/dagger/dagger/pull/6857
Specifically, it expands dagger config with subcommands (currently just dagger config include and dagger config views) that each have their own set of "standard" CRUD subcommands, which has all sorts of naming and CLI design things to decide on
Any chance we could relax the rule of "no ID arguments or functions"?
At least argument name, seems excssive
Quick DX feedback on the topic of .gitignore. I contributed to someone's module, and got this review on the PR:
Look into potential, unnecessary autogenerated code added (internal/dagger) checked in.
@rocky harbor confirmed that module find-up doesn't work for me in any command:
dagger init --sdk=go repro
cd repro
dagger functions # this works
cd dagger
dagger functions # this fails
Ahh okay right we do have findup logic but it's for finding the context root (i.e. .git), but we also want it for finding dagger.json in these cases.
It should be a super simple fix, but one question: if you there was a module in ../some/dir and you ran dagger functions -m ../some/dir/some/subdir would you expect to see the functions for ../some/dir? Basically, should the find-up always kick in, or should only be if you don't specify an -m?
I think it should just always kick in, but just ambiguous enough to double check
If it always kicks in, wouldn't it make -m useless anytime you're inside a module?
My first instinct is that explicit -m means "override whatever you were going to do to find the module: this is the one I want"
Well the logic could be "if -m is specified, find-up from what it points to. Otherwise find-up from current dir". Basically, -m defaults to . and logic is that you always find-up from -m (whether explicitly set or just set from the default)
Oh, in your scenario, ../some/dir/some/subdir does not have its own dagger.json then?
right
In that case, then yes that makes sense to me. -m is always applied. And findup is always applied.
I think Container.terminal() hides the error message on error
In that case, then yes that makes sense
Does Dagger have a native time type?
nope
How does one create a file and pass it to a container inside a dagger function?
Container.WithNewFile
@kind carbon Any chance you could update https://github.com/helderco/daggerverse/tree/main/poetry to 0.10.x? Getting The "main" module could not be found. Did you create a "src/main.py" file in the root of your project? for a project structured as follows:
.
└── dagger
├── pyproject.toml
├── poetry.lock
├── sdk
│ └── src
│ └── dagger
│ ├── client
│ ├── _codegen
│ ├── _engine
│ └── mod
└── src
├── constants.py
└── main.py
and the following in pyproject.toml:
name = "lambda"
packages = [{ include = "main.py", from = "src" }]
Questions on dependency management.
-
Does
daggerever write git tags to thedependenciessource entry indagger.json? Or only ever raw git commit? -
If I manually write a dependency to
dagger.jsonwhich is pinned by tag rather than commit, what happens? Error?
- no, currently it always pins to commit digest
- it should resolve the tag to a commit internally and use that for
dagger calland if you randagger developthendagger.jsonwill be updated with the commit rather than the tag
Ok good to know. So is it fair to say the following?
- The spec says:
dagger.jsonMUST always reference dependencies by commit. - A
dagger.jsonwith a dependency not pinned by commit is considered invalid - We enforce this in a best effort way, by correcting the file on the fly
Yeah more or less, in practice its trivial for the engine to resolve any git ref to a commit, so our "best effort" is gonna work every time (as far as I can think), which makes "invalid" sound a bit too strong maybe, but I suppose if we were to write a formal spec that might be the technically correct language still
Yeah you're right that enforcement is airtight at execution. I only called it "best effort" because you can still write an invalid dagger.json, and publish it over git, we won't (can't) prevent you from doing that since we don't control source distribution.
It's good to have clarity on what is invalid, though, because then we can add little checks and warnings over time, to guide users. Like an error on publish, warning on load, stuff like that
FYI @dense canyon @wintry prism 👆
Do you know how to add function arg descriptions on the SDKs ? I can't seem to make it work
Sorry I didn't understand the question. You want to know how to add descriptions to your function arguments? In which language?
Yes sorry, wasn't clear. Euh, Go for example
Yes
In python, I'm guessing it's docstrings, that's the standard way
Thanks, there was a bug on Daggerverse, helped isolating the issue 🙏
$ dagger call -m ../supergit remote --url https://github.com/asciinema/asciinema branch --name main commit tree docker-build
✘ initialize 1.2s
✔ ModuleSource.asModule: Module! 0.3s
Error: unsupported list of input type "BuildArg" for flag: build-args
Translation: can't call Directory.DockerBuild from the CLI 😭 😭 😭
I'm tempted to try 1-repo-per-module for my next few modules... Instead of picking weird repo names like shykes/the-dagger-module-for-X, I kind of want to call it.... shykes/X.
As in:
shykes/git: git as a dagger module.shykes/docker: docker as a dagger module.shykes/tailscale: tailscale as a dagger module
Since it appears Dagger Functions can encapsulate pretty much any software that I'll build, download, deploy, run from the terminal, or integrate with: why bother with intermediary namespaces? My Github is my Daggerverse. Increasingly I will have no other purpose for GIthub, than hold my Dagger Functions, conveniently grouped into modules.
The other practical benefit is that, hopefully, it will make cold load times just slightly shorter - less git material to clone the first time 🤞
I am running dagger in dagger to test a module and running into a strange error that I have not seen before.
Connected to engine 25de772207a8 (version v0.10.2)
1: starting session
1: [1.01s] OK!
1: starting session [0.22s]
1: connect DONE
2: initialize
2: initialize ERROR: failed to get configured module: failed to get module ref kind: input: moduleSource resolve: get git tags: failed to run git: exit status 128
4: dagger call
4: [0.00s] Error: failed to get configured module: failed to get module ref kind: input: moduleSource resolve: get git tags: failed to run git: exit status 128
4: [0.00s]
4: dagger call ERROR: failed to get configured module: failed to get module ref kind: input: moduleSource resolve: get git tags: failed to run git: exit status 128
Error: failed to get configured module: failed to get module ref kind: input: moduleSource resolve: get git tags: failed to run git: exit status 128
Does anyone have any ideas?
I am running dagger in dagger to test a
Question about the Zenith Doc.
https://docs.dagger.io/quickstart/292472/arguments#pass-a-directory-as-argument
In this section we call the tree command from a local dir.
It's gonna sound stupid but I did it in my home dir and I was wondering why it took minutes to run. I quickly figured out that dagger was copying/caching my whole $HOME.
I completely forgot about it, but last week I introduced dagger to a colleague and he ran through the exact same issue and it took me a couple min to remember about the issue.
I don't think it is particularly obvious for a newcomer that calling tree on ./ Will cache my entire local dir especially when we are not focused on the command itself but rather on understanding what dagger does.
I would highly encourage a slight update encouraging the reader to create a dumb dir with 3 random files. It makes for a much nicer experience 🙂
Or mentioning that passing the --dir Implies that you copy out the local content and that you should avoid running it on any folder structure close to /
OK so... Is there any way to force the allocation of a tty in Container.withExec?
Basically an equivalent of ssh -t
no not currently, mainly because we don't want Container to be actually interactive with the user (that would be bad for caching, interaction is okay with Service since those aren't cached). But I'm guessing you have a use case where you need a tty even though it won't actually be interactive?
mmm actually I'm executing asciinema, and allocating a tty is exactly what it does. But somehow it's trying to allocate the tty, and failing. So there must be something wrong in the container that prevents it
I don't want to hijack the thread above but I had a similar use case, I am working on some smoke tests for our doc examples inspired by the panic from terminal in 0.10.1 -- I got most of the examples to run but ironically cant get the terminal one to work since it says "terminal not supported in TUI", ironic because it does not panic, but fails in its own way 😄
Trying to publish a module (again, but with a different org), but getting crawl error: ["error" "get module for ref: no rows in result set"]. First time I see it
FYI @thorn moat 👆 we are on the same page
@Helder Correia would you consider
ATTENTION: I am going to rename this channel:
- Name:
#developers - Category: USING DAGGER
- Description: A place to talk about developing for Dagger
Last call for feedback... We can change it if doesn't work.
Is there some nice pattern to make things feel clean that folks have found when you have a function that takes a lot of parameters (like 5+)
I wrote a module that uses another third party go library and basically 0 dagger code and everything "just works™" is this because its go and dagger knows how to execute it?
Done!
I just experimented with livestreaming software, to livestream myself daggerizing things 🙂
I tried it on my own, but I think it would be more fun as a duo. Also, I got stuck and didn't understand the software I was daggerizing well enough to get unstuck on my own 😛
Who wants to join me and daggerize something together live on air? 🙂
I’m in!
Im cooking up a dagger module that knows how to send toots on Mastodon. 
Im cooking up a dagger module that knows
Where do I go to follow the work on function/module caching? Cold start time is still a bit spicy these days.
Great idea
one thing that is a bit curious is why *Secret has what seems to be an empty default value in when you call dagger --help
Here is the definition
// mastodon access token
accessToken *Secret,
But when I run dagger --help for my function I see this
--access-token Secret mastodon access token (default :)
Does anyone happen to have a more advanced example of using Dagger constructors or interfaces with the go sdk?
I think its really awesome how daggerverse.dev shows you usage examples in shell automatically, have we considered adding this same behavior to --help so that you don't have to explicitly document the examples?
I think that would fit perfectly in dagger doc, which basically aims to be the CLI version of a daggerverse module docs page
How does everyone feel about allowing file:... for string arguments?
I've encountered a few times the situation where an argument could reasonably be an inline string or a file (eg. the contents of a script); but I don't want to have to split my function into fooString and fooFile. I would rather have an easy way for the CLI load a string argument from a file
Yeah, I recently used --arg="$(cat ./file.json)" but got issues anyway, so I thought the same thing.
Sounds reasonable.
Problem is if your string value needs to start with file: for some reason 🙂
I think we need dagger call --raw
Of course your module entrypoint could have a raw argument...
Chatting about modules for the next hour in dev-audio for anyone who wants to join!
Oh, you’re 1h early 😦
oh daylight savings kicked in for the US... lol
Yeah 😅
okay, be back in an hour! 😄
I think we could cover all corner cases if we did:
--string-arg string:foo- value isfoo--string-arg file:foo- value is contents of filefoo--string-arg foo- no prefix defaults tostring:so value is justfoo
Then the corner cases would be handled by:
--string-arg string:file:foo- value is the literal stringfile:foo--string-arg string:string:foo- value is the literal stringstring:foo
I don't love that but it would allow you to cover every case on a per-arg basis I think
what if my argument is string:string:foo 😛
then it would be string:string:string:foo 😂 which is absurd looking but at least logically consistent
The logic would be "strip any string: or file: prefix and interpret the rest of the value as indicated by that prefix, otherwise if those prefixes aren't present just interpret it all as a string"
okay, NOW chatting about modules for the next hour in dev-audio for anyone who wants to join! 😄
@kind carbon OK the real topic for our first episode together: HELDER SHOWS SOLOMON HOW TO MAKE A DAGGER SDK 🙂
oh man! was hoping to join today 😦
Hi, I'm playing with dagger function since some weeks, at the beginning I was a little disturbed with the transition from sdk style to function, but now I very like it.
I would like to have a feedback on my node module (https://github.com/Dudesons/daggerverse/tree/main/node).
This module allow to call a lot of functions to do test build ... Also I tried to add "lazy" functions, one for an automatic setup based on the package.json and another one which will try to build a basic pipeline, I would like to know if you think it's a good idea or not
automatic setup: https://github.com/Dudesons/daggerverse/blob/main/node/dagger/auto.go#L9
basic pipeline: https://github.com/Dudesons/daggerverse/blob/main/node/dagger/pipeline.go#L9
On the Pipeline function I was hesitating if it's a good idea to return (string, error) or if I should return my Node struct or a container for more flexibility
Also I have the feeling I didn't see modules around a language which purpose to build and push images, is there any reasons ?
Another thing I'm developing a terragrunt module and another one for drift detection but executing this call: dagger call terragrunt with-source --path=/terraform --src=../testdata/terragrunt/ plan --work-dir=/terraform/stacks/dev/europe-west1/staging/bar --detailed-exit-code do
I had in the following output:
...
Stderr:
2024/03/15 08:55:44 traces export: Post "http:///dev/otel-grpc.sock": http: no Host in request URL
2024/03/15 08:55:44 traces export: Post "http:///dev/otel-grpc.sock": http: no Host in request URL
...
Terragrunt add recently an opentelemetry integration: https://github.com/gruntwork-io/terragrunt/issues/2919
https://terragrunt.gruntwork.io/docs/features/debugging/#opentelemetry-integration
In the case a tool have an opentelemetry integration what do you recommend to do ?
If I need to use this kind of feature for debugging, there is a risk to break something in dagger ?
Environment of my container:
dagger call terragrunt with-source --path=/terraform --src=../testdata/terragrunt/ shell
/terraform # env
OTEL_EXPORTER_OTLP_TRACES_PROTOCOL=grpc
SHLVL=1
HOME=/root
TERM=xterm
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
_DAGGER_PARENT_CLIENT_IDS=zxcr8rjez0dw0n2ujeg2ntph0
/terraform # env
OTEL_EXPORTER_OTLP_TRACES_PROTOCOL=grpc
SHLVL=1
HOME=/root
TERM=xterm
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
(I didn't set any environment variables)
Node module
watch out world, i'm writing SDKs for my esoteric languages: https://github.com/vito/daggerverse/blob/main/apko/apko.bass
watch out world, i'm writing SDKs for my
I'm still a bit lost on how tagging is supposed to work for a monoerpo of modules, I have this tag for my mastodon module https://github.com/levlaz/daggerverse/tags and for a moment daggerverse did show this version as latest, but now it says my latest version is "main"
Tags · levlaz/daggerverse
Does anyone happen to have a more
I'm trying to build a module for publishing my modules.
This module is taking a git repo + a module name
Then this one is checking if the module has git tag or not
According to the function call it will increment major/minor/patch
After that it will git push the tag and run the dagger publish.
Actually I'm blocked on the git push part, my key have a passphrase and for the moment I didn't find a way to mount the ssh agent socket.
Is there a way to do that or for the moment it's a limitation ?
Sockets aren't supported yet. See https://github.com/dagger/dagger/issues/6726 and https://github.com/dagger/dagger/issues/6747.
GitHub
We missed adding support for host sockets to CurrentModule when removing Host from module codegen. We should re-add the equivalent support, it should be pretty straightforward.
ok so waiting that you recommend me to disable to git push part and doing it outside of dagger or maybe there is a workaround ?
Not that I know of \cc @rocky harbor
Yeah unfortunately at this exact moment there's no way to get a host ssh agent hooked up with pipelines running in a module. Supporting sockets as arguments should make that possible; https://github.com/dagger/dagger/issues/6747 Helder linked to is the one to follow for that. It will require explicitly passing the socket as an argument when using dagger call, but that's probably the best way since it will ensure that only the functions you've explicitly passed it to have access (relative to any module always having access to your ssh agent)
Just in case it's useful: I published a module that lets you call core functions directly from the CLI:
https://daggerverse.dev/mod/github.com/shykes/core
(
export DAGGER_MODULE=github.com/shykes/core
DIR=$(
dagger call \
git --url github.com/dagger/dagger \
branch --name=main \
tree \
sync
)
dagger call \
load-directory-from-id --identifier="$DIR" \
directory --path=cmd \
entries
)
Limitations (both are bug reports on dagger)
-
dagger callwon't let you callid()which is frustrating. You can callsync()on some types, but on others, likeGitRepository, there is no workaround -
idis a forbidden argument (I don't understand why). So I useidentifierinstead for load functions
id is a forbidden argument (I don't understand why). So I use identifier instead for load functions
Yeah I don't think this restriction was necessary, it just got caught up in adding protections against naming fields/functionsid. Was an extremely quick fix so sent out a PR here: https://github.com/dagger/dagger/pull/6912
dagger call won't let you call id() which is frustrating. You can call sync() on some types, but on others, like GitRepository, there is no workaround
This one is a lot more nuanced, left thoughts on it in the issue https://github.com/dagger/dagger/issues/6710#issuecomment-2012902063
Erring on the side of caution is ok with me! easier to relax the constraints afterwards
Hi All,
I have really noob questions.. As a Service Platform, we would like to have a centralized repository to develop our functions.
In Github Actions, how each engineering teams can access to functions that we created via dagger? Should they checkout the centralized repository in their repo or is there any there suggested way?
I also would be really happy to get some suggestion how the folder structure looks like.
When I'm running a service with up is there any way for me to enter the container that is running with terminal?
Hello, I’m playing with interfaces in the Go SDK and I expected something like this to work:
package main
type Test struct {
}
type TestOption interface {
DaggerObject
Do(m *Test) *Test
}
func New(
opts ...TestOption,
) *Test {
m := &Test{}
for _, opt := range opts {
m = opt.Do(m)
}
return m
}
But it doesn’t seem to be the case:
❯ dagger call help
✘ initialize 1.6s
✔ ModuleSource.asModule: Module! 1.1s
✘ Module.initialize: Module! 0.3s
✘ exec go build -o /runtime . 0.3s
┃ # dagger/test
┃ ./dagger.gen.go:598:19: (&Test{}).WithGraphQLQuery undefined (type *Test has no field or method WithGraphQLQuery)
Error: input: module.withSource.initialize resolve: failed to initialize module: failed to call module "test" to get functions: call constructor: process "go build -o /runtime ." did not complete successfully: exit code: 1
Stderr:
# dagger/test
./dagger.gen.go:598:19: (&Test{}).WithGraphQLQuery undefined (type *Test has no field or method WithGraphQLQuery)
Is it planned to make this kind of thing work in the future (would be awesome!)?
More on the use case: the idea would be to have something like this
container := dag.RedhatUbi(dag.Nodejs().RedhatUbiConfiguration(), dag.Golang().RedhatUbiConfiguration()).Container()
to get a container based on RedHat UBI with Node.js and Go installed and configured (with mounted cache volumes for example), all of this in the more efficient way. That is, installing all the packages at once to limit the number of layers in the image for example.
Dagger Module for Elixir is works now https://github.com/wingyplus/daggerverse/tree/main/elixir-sdk 😄
When I'm running a service with up is
Hello, I’m playing with interfaces in
Hi All,
Ahoy! Someone I know heavily suggested me to come by 🤣
Welcome 🙂
@thorn moat @rocky harbor @deft rain @kind carbon a not-urgent but pretty fundamental topic we've discussed in the past: whether to allow "upstream modules" as a first-class citizen.
An "upstream module" being a module embedded with upstream software, which it can implicitly access.
In other words, should we consider cautiously re-opening the door we closed when disabling "root": and host().Directory() ?
default OTEL env vars
I am running into something strange. I can't figure out a workaround. I have a container that has a service attached (basically docker-in-docker). Everything from that container runs fine.
When I try to pull a file out of that container and use it in another container, that other container also tries to look up the service of the first container and fails with a 125
host alias: lookup t6sjv1ru3serq on 10.87.0.1:53: no such host
┃ lookup t6sjv1ru3serq.c1mh4mk35essm.dagger.local on 10.87.0.1:53: no such host
This may be related to - https://discord.com/channels/707636530424053791/1220265352030584834. I am doing all of this within a function. Is there a workaround?
Basically run (container A + service).
file = get file from (container A + service)
Try to run (container B + file) fails
Basically run (container A + service).
ISSUE CLOSED! https://github.com/dagger/dagger/issues/4414 🙂
@rocky harbor is there an issue for the "can't compose multiple calls from the CLI" problem? ie. can't pass an ID as argument etc
This one is the closest, but the title is technically slightly more specific than that https://github.com/dagger/dagger/issues/6710
Thanks. Context for this is my writeup of https://github.com/dagger/dagger/issues/5774
It took me way too long to figure this out. When you are creating a daggerverse within an existing go project, and you create a new module and move things out of the "dagger" subfolder (not a fan of that default btw), it modifies the root directories go.work to add the module to be under mymodule/dagger. But init and develop both broke for me until I realized and fixed my go.work. This is probably worth documenting.
Yeah I got bitten by that too. I don't think it's dagger-specific: just how go tooling works I believe
Also: agree that the ./dagger default subfolder is not working out.
i consistently find myself typing --source=. since i pretty much always want it at the top-level for daggerverse-like projects.
maybe it makes more sense to default to the current directory, but still allow a source arg for monorepos?
I'll add a +1 to the bit about the /dagger subdir for what it's worth, I've kept it as-is in my modules but I've questioned why it exists every time I've seen it
I think the main reason is for doing dagger init in the root of an existing repo.
we have a working repro of a Service regression from 0.10.2 if anyone else wants to help figure it out 🙏 https://github.com/dagger/dagger/issues/6951#issuecomment-2022729135
GitHub
This appears to be a regression introduced in 0.10.2, things work as expected in 0.10.1 From @nipuna-perera on Discord: Basically run (container A + service). file = get file from (container A + se...
just glancing through the changes between v0.10.1 and v0.10.2, the only that i can see maybe impacting services is this one: https://github.com/dagger/dagger/pull/6806
(of course, it could be much more subtle)
One more small feature request 🙂 https://github.com/dagger/dagger/issues/6957
cool new function alert https://daggerverse.dev/mod/github.com/kpenfound/dagger-modules/postgres@57352e06a1cfbcb5307c009d37c0201b2719b935#Postgres.client
Nice 🙂 We should start a "cool database modules" collection, I have my clickhouse one too
Is there a sqlite module yet? I feel like that could be particularly awesome since you get "database forking" for free
I'll make that one next if nobody else does by the time I get to it!
I wonder if some real-world data management pipelines could be made 10x easier with the combination of a postgres +slqite module. Basically you'd handle export/import to/from the postgres DB; then instead of carrying a raw SQL text file, you'd carry it as a sqlite DB, and make arbitrary changes along the way - then re-export to postgres on the other end
(this assumes there is excellent sqlite/postgres bridges out there, but I'm pretty sure there are)
@warped canyon while we're showing off, I'm in the process of spinning out parts of my daggerverse repo into standalone repos (getting fed up with the go.work issues)
So I figured I'd make a reusable Function for spinning out a subdirectory of a repo into its own repo 🙂
Let me know how it feels 😄 There's obviously trade-offs each way
How do I cleanly check if a directory exists again?
Hey! For those who use Dagger to manage CI or local dev of applications that have environment stored in .env or .envrc and struggle exporting all variable, I made a super simple module that can help you:
https://daggerverse.dev/mod/github.com/quartz-technology/daggerverse/magicenv@627fc4df7de8ce3bd8710fa08ea2db6cf16712b3
The idea is simple -> load the environment from your file
Example in Typescript:
this.ctr = dag.magicenv().loadEnv(this.ctr, { path: ".envrc" });
It checks on .env by default and this supports env expansion (e.g Foo:$BAR:HA)
For a more complete use case of this module + how to deploy local infrastructure with dagger, you can check a demo I published there: https://github.com/quartz-technology/daggerverse/tree/main/demos/bun-server
I hope this helps some of you 😉
I'm also super open to comments for improvement, feel free to ping me or open an issue on my repo
Glob?
Ah, that will work! We should rename Glob to find() IMO
I'm actually used to glob 😄 https://docs.python.org/3/library/pathlib.html#pathlib.Path.glob
Yeah I get it. It's not a bad choice given the pre-existing use. It's just that the pre-existing choice of words is not good.
Potential bug?
If I return a *Container from a function that has a WithExec that runs a long running/blocking process (like a server) and I do a terminal in the CLI, I have no way to exit out of it. q or esc does not work. I have to kill the terminal.
I would have thought stat or isdir would have been functions.
It’s also worth noting that glob and find use different regex syntax. If your glob just respects “*” and “**” then that the better name for it. If it instead respects posix regex then it’s closer to find.
Also depending on the use (eg creating in private a container filesystem namespace is safe b/c of copy write semantics), but on the host or in shared cache volume, you actually want to check if the directory exists and atomically create it a the same time with mkdir or tmpdir because it avoids a time of check vs time of use bugs. In both cases these functions set errno to E_EXISTS to show the directory exits
When I do a dagger up. The TUI doesn't show the full log even with --debug. I have an entrypoint script that does a lot of work. That script outputs stuff to stdout but I can't see any of that in dagger up. How do I get to that data? It's pretty important when troubleshooting the script.
What version of dagger are you running? dagger up is deprecated in favor if dagger call ... up. Maybe your output issue is related to that deprecation?
oh no I said dagger up because it's succint 🙂 I am using dagger call ... up. Same behavior
Ah!
And I am on 0.10.3
The entrypoint script is what the service itself executes?
yeah.. It does a bunch of bootstrapping and then runs a java app (service)
Might be worth filing an issue- maybe service start maybe doesn't stream standard output the way it should?
might be worth splitting out the bootstrapoing into separate withExecs in the meantime?
hmm... You mean instead of running the script, do the work in the script via withExec? Right now I am running the script with withExec (as I don't know if there's an automatic way to run the entrypoint)
It's quite a big script. I don't really want to translate all that into dagger code yet
Even if we put the entrypiont aside, I can't see the running app's log. I only see a continuous "tail" of it.
When I exit out of the service, it truncates the historical stdout
Showing off my new git module 🙂
This used to be the most annoying git task for me: spinning out a subdirectory of a repo, as its own repo, with history properly translated. It is now a simple dagger call 🙂
# Let's spin out the dagger docs as their own repo
dagger call -m github.com/shykes/git \
clone --url https://github.com/dagger/dagger \
subdirectory --path docs \
inspect
And that's it!
To spin out any module from your daggerverse repo into its own repo:
REPO=https://github.com/shykes/daggerverse
MOD=tailscale
dagger call -m github.com/shykes/git \
clone --url=$REPO \
subdirectory --path=$MOD \
checkout \
export --path=./$MOD
This is probably a really silly question. I want process something in a file. But I want to do it using Go modules (like process env vars with dotenv). How do I load that file into my function? Or access it with Go? If I load it as a *File, do I mount it into a container and then export it? Feels very cumbersome. I'm probably missing something basic. Is there a location in CurrentModule where I have access to that file?
This is probably a really silly question
I was just randomly trying a module from daggerverse, and got a weird error:
$ dagger call github.com/purpleclay/daggerverse/ponysay@v0.1.0
✘ initialize 0.0s
Error: failed to get configured module: no dagger.json found in directory . or any parents up to git root
There is a dagger.json, and daggerverse crawled it
This is with Dagger 0.10.3. Anyone else able to repro?
Did you miss the -m?
Should we have another copy option for call? I do this a lot too
Well this is why I want dagger install to work all the time
So we can all build the muscle memory to install first, always
(or almost always)
I see we can get function description via dagger functions but how to get description of the module from the cli? It maybe a stupid question, but I can't find it. T_T
it's missing... @void widget is working on it 🙂
Thank you! Do we have workaround on this? publishing it to Daggerverse?
When publishing to the daggerverse, you'll have these infos yes 😇
Thank you @void widget. Will try on that way. 😀
Big difference in Gitlab CI in terminal output from 0.10.3 -> 0.11.0, much prefer the new, cleaner output 👍
Nice! Will try it out!
With 0.11.0 I am not seeing any of the docker pulls. Starting with the new engine pull. I see some references to http GET but that's it.
remotes.docker.resolver.HTTPRequest is what I'm seeing
In Dagger Cloud?
or TUI?
TUI
cc @thorn moat 👆
yeah, so now we're stuck with whatever Buildkit's OpenTelemetry gives us, which is not a lot. I really want to bring back those fancy 2-dimensional progress bars, but for now this is in a somewhat long list of tiny things that changed when we swapped out the entire telemetry stack. (Including no more "CACHED!" indicators)
we'll probably send PRs upstream to bring back all that goodness
Ah ok makes sense. Not a huge deal but I will miss those till they are back. They also made it nice to demo dagger to others 🙂
Hey just kind of curious on like overall guidance on using Dagger.. it feels like the dagger functions was a pretty big shift. I felt like before dagger functions you'd have a simple dagger program, likely in the language of your project, that would pipeline together the necessary steps to build your app. Now post dagger functions, it feels like the docs are pushing you more for either using one or more dagger call to run some module functions. Is that the future direction or is the older style programs that the docs had pre-functions still a good pattern?
Hi Ian 👋 today I'd use functions, but you can use them in basically the same way.
Write a simple Dagger function for CI in the language of your project that pipelines steps together.
You kick off your CI function with dagger call like you used to with dagger run go run or dagger run node or dagger run python (don't need those runtime tools on your machine anymore).
You can call other functions in code from your CI function from the Daggerverse or that you write yourself to get the best combo of composition, abstraction, DRY, re-use (you can call functions written in any Dagger SDK language, btw. That's new!).
This workshop (from today) shows how to do that really well:
https://www.linkedin.com/events/7170662442614636544/
https://github.com/kpenfound/kubesimplify-dagger-workshop
https://www.youtube.com/watch?v=1vHrf7-D3oI
What @wintry prism . Calling functions with dagger call is the recommended way. You can still embed a dagger client library in your own custom tool, and execute that on the host machine, but we consider that to be a niche use case. Most software teams don't actually want to develop a custom CLI tool just to run their pipeline: they would prefer to develop the individual building blocks, and use the dagger CLI to call them. Less boilerplate to maintain, less work for the user.
Thanks. @sharp zealot you'd still hope that people wouldn't glue dagger calls with bash right?
On 0.11.0, every time I run the TUI I see this 7:23 WRN failed to get commit object err="object not found" . It's persistent at the bottom of the TUI console. Didn't see that before.
I think of it as a gradual process. In the beginning, there is only glue scripts, as far as the eye can see. Then you drop a Dagger Function, creating an island of clean repeatable code - surrounded by glue. Then you add another island, connected to the first. Then another, etc. The whole time, there is still glue, but you're gradually pushing it back, one step at a time.
Sometimes you have the luxury of Daggerizing almost everything all at once. Sometimes, it might be a gradual process stretching years.
The point is: every step of the way, you decide how much glue script is involved. The important part is that the trend is reversed: instead of more glue accumulating over time, now things get simpler over time.
Concretely, the lifecycle of your dagger call glue will be:
- Ha ha, I can replace 100 lines of awful glue with just 1 line:
dagger call. Dagger rules! - OK, my
dagger callpipeline is getting a little longer, I'm chaining a few calls together. 10 lines. - This is stupid, I'm writing a whole shell script just to wrap
dagger call. Time to write a new function with the new logic!
-> You just expanded the boundary of your DAG. Repeat the cycle with the next function.
@warped canyon your demo this morning gave me an idea for a new blockbuster module 🙂
Oh??
Will keep it a surprise for now 😛
Don't suppose anyone is aware of, or has made a, kics module (https://www.kics.io/index.html) but hasn't published to daggerverse yet?
KICS
KICS is an open source solution for static code analysis of Infrastructure as Code.
@quick wind - There are few Trivy modules.
I just threw together the simplest kics module + test file, it's only for demonstration purposes
Having modules office hours for the next hour in the dev-audio channel for anyone who wants to join!
Im sad I missed it, next week!
same! I need to put a recurring meeting on my calendar. Keep missing it.
In case you were gonna ask about CA certs+proxies, that's been my main focus and I'm fairly hopeful the next release will have enough baseline fixes that should unblock you 🙂 It's been taking way longer than expected due to the fact that CA certs are a never ending hellhole of different cases to handle, but I think we'll be able to support enough common cases to start to cover the majority 🤞
Thank you for the update! That's very encouraging news ☺️.
I would like to develop some modules via TS but folder structure a bit confused to me. Should I really need dagger folder? For instance i'd like to develop a module for docker with scan and sign so should folder structure looks like below?
./docker/dagger/src/index.ts or is it also ok to have ./docker/src/.index.ts?
You definitely can develop modules without the dagger/ subfolder.
You can do so with
dagger init
dagger develop --sdk typescript --source .
Btw, what might be the reason of dagger call takes too long? Am I doing something wrong? :/
It could be that your docker directory has many MBs of files being copied into the runtime container. Can you share a du -h and a tree output?
is --progress=plain supported with dagger call ... up? It's stuck for me in Connected to engine .... Dagger v0.11.0
there's no streaming support yet, so it just pauses and prints everything all at once - not great, but had to cut some corners for now. 🙏 some folks internally are already motivated to fix it, so hopefully soon 😛
ah.. for me it doesn't look like it's even running. For the service up use case that is. It's just stuck. I gave it plenty of time.
Any info on the roadmap for Daggerverse publicly available? With the update from 0.10.3 -> 0.11 it's even more important that a module's engine version is displayed/filterable. Other things off the top of my head: filter criteria: partner/community/dagger-created modules, sort on publish/update date
Anyone have some good examples of unit testing their dagger functions?
Any info on the roadmap for Daggerverse
Are we not able to pass in dir as a constructor?
I tried this but the CLI yells at me
@object_type
class MyClass:
dir: Annotated[dagger.Directory, Doc("Directory containing source code")]
@function
def ci(self) -> str:
"""Run entire CI pipeline"""
# run tests
return self.test(self.dir).stdout()
then
dagger call ci --dir=.
((.venv) ) levlaz@Levs-MacBook-Pro fedidevs % dagger call ci --dir=.
✘ initialize 3.2s
! required flag(s) "dir" not set
✔ Module.initialize: Module! 1.0s
✔ exec /runtime 1.0s
Error: required flag(s) "dir" not set
https://github.com/dagger/dagger/issues/7047#issuecomment-2042403507
how about this fix for streaming output?
hey that's pretty cool! if you want to PR it I'll give it a review. 🙂 cc @deft rain who was also interested in reviving this - maybe this could be a kick-start (edit: oops sorry forgot @silent)
Any idea about to fix the color lost issue in CI?
I feel lost light when upgraded to dagger v0.11.0 =。=
your CI isn't setting $NO_COLOR right?
Yes. same CI env,
with old dagger (github.com/vito/progrock v0.10.2-0.20240221152222-63c8df30db8d) works well.
but with the idtui, the color lost.
it's possible that env var was ignored by the old UI, so just want to confirm it's not set; that should be the only way to disable colors, unless there's a bug (also likely)
I printed termenv.EnvNoColor(), it false.
so when is not tty, here to force drop color?
"CI=true" it may the issue
func (o *Output) isTTY() bool {
if o.assumeTTY || o.unsafe {
return true
}
if len(o.environ.Getenv("CI")) > 0 {
return false
}
if o.TTY() == nil {
return false
}
return isatty.IsTerminal(o.TTY().Fd())
}
Need to NewOutput with termenv.WithUnsafe()
color is back
@wintry prism is this what you need?
8.0K ./docker/sdk/context
28K ./docker/sdk/provisioning
52K ./docker/sdk/common/errors
56K ./docker/sdk/common
4.0K ./docker/sdk/introspector/decorators
4.0K ./docker/sdk/introspector/utils
8.0K ./docker/sdk/introspector/registry
28K ./docker/sdk/introspector/scanner/abtractions
44K ./docker/sdk/introspector/scanner
60K ./docker/sdk/introspector
4.0K ./docker/sdk/graphql
24K ./docker/sdk/entrypoint
200K ./docker/sdk/api
412K ./docker/sdk
4.0K ./docker/src
436K ./docker
40K ./docs
76K ./.github/workflows
12K ./.github/ISSUE_TEMPLATE
100K ./.github
4.0K ./.git/objects/3b
4.0K ./.git/objects/04
152K ./.git/objects/pack
4.0K ./.git/objects/7e
0B ./.git/objects/info
8.0K ./.git/objects/13
172K ./.git/objects
4.0K ./.git/info
4.0K ./.git/logs/refs/heads/feat
8.0K ./.git/logs/refs/heads
4.0K ./.git/logs/refs/remotes/origin
4.0K ./.git/logs/refs/remotes
12K ./.git/logs/refs
16K ./.git/logs
64K ./.git/hooks
4.0K ./.git/refs/heads/feat
8.0K ./.git/refs/heads
0B ./.git/refs/tags
4.0K ./.git/refs/remotes/origin
4.0K ./.git/refs/remotes
12K ./.git/refs
292K ./.git
908K .
Hey guys, is there a way to capture the stdout but avoid exposing it as part of the logs shown when a given command (WithExec()) is being evaluated?
Taking this snippet as an example
out, err := dag.Container().
From(image).
WithMountedCache("/go/pkg/mod", mod).
WithMountedCache("/root/.cache/go-build", build).
WithMountedCache("/root/.terraform", dotTerraform).
WithExec(t.getTFInstallCMD(tfVersion)).Stdout(context.Background())
If I run it, it's going to show the standard output, but what I'd like to do is to capture it, and show this one and others later on, in a sort of summarised view.
One option is to redirect the output of your specific withexec(s) to a file and read the contents of that later on https://pkg.go.dev/dagger.io/dagger#ContainerWithExecOpts.RedirectStdout
Sounds like it's what I need. I haven't tried it yet. The idea is to avoid completely showing the output through the terminal, and instead wrap it in an internal UI that wraps the dagger execution of certain commands and containers. I'll try it, thanks @warped canyon !
How to remove those resolver logs? (when plain mode)
cc @thorn moat
this explains why - #daggernauts message
Imagine a I have a function called cli that is a "proxy" for a CLI that sends string commands to some CLI that I am wrapping and returns a *Container.
Is it possible to chain things like with-directory before executing the cli function? I basically want to pre-pend a few steps before the function executes but I don't see any way to do that.
Can you put those steps in another function?
Hey guys, what's your experience debugging Dagger functions in something like Goland? (let's assume we're using mostly the Go SDK, and we prefer to code in Goland — my case).
I'm curious since there's a lot of code-generation, and the actual code that performs the magic is mostly generated, hence placing a breaking point in any part of the 'wrapper' code doesn't work. Going into the generated code and creating a breaking point there isn't a good Developer Experience. I'm looking for experiences and perhaps a better approach that works while developing and debugging functions. The same question applies for modules.
debugging a Go function
Hello, is there a way to simplify the following code by directly returning the Installed function as an anonymous function from the Packages function?
type RedhatMinimalPackages struct {
Names []string
}
func (*RedhatMinimal) Packages(names []string) *RedhatMinimalPackages {
packages := &RedhatMinimalPackages{
Names: names,
}
return packages
}
func (packages *RedhatMinimalPackages) Installed(container *Container) *Container {
return container.WithExec([]string{"microdnf install --nodocs --setopt install_weak_deps=0 --assumeyes " + strings.Join(packages.Names, " ") + " && microdnf clean all"})
}
You can't return anonymous functions, but you can do better in this case 🙂 You can define your own custom type that wraps Container, and has its own methods
How do you wrap? If I do something like type RedHatContainer struct { *Container }, I cannot use this type as a Container, maybe I do not do the correct thing?
Simplify code with custom type
Hey there, with the big push with Dagger Modules and Functions is the "legacy" (< v0.10.0) way of defining Dagger Pipelines/DAGs (e.g. any examples here) still be supported in the long term? Is the goal to deprecate it?
The goal is to support it as an advanced or niche use case. There's one major issue to resolve though, which is to be able to call module functions from this code, via an auto-generated client (dag). You can already call module functions, but you have to resort to a lower level graphql request, rather than through dag.
example: #1230428619755753553 message
Does this mean the recommended default pattern should be dagger call over dagger run? If so, will call be deprecated? Apologies for any ignorance, still digging in.
Using dagger call has many advantages over dagger run, so that's the default preferred way. But as for the deprecation, you're replying to my response to that exact same question 😄
Thanks for the clarification!
On one hand, code in dagger run can't run modules using dag from the larger modules ecosystem. On the other, dagger call has a more stricter access to host resources. Having good support in dagger run scripts to call module functions in order to bridge that gap is high on the list of things to fix, but I hope people try out modules and give it a chance.
Yeah it's fair to say: in doubt, use dagger call. But no plans to deprecate run.
And as @kind carbon said, we want to add a built-in scripting feature. If we do a good job, that may end up being everyone's favorite way to run dagger 🙂
When coming back to Dagger, I did get thrown for a loop by everything being Function-centric. I jumped straight to the docs to refresh myself on how to build a full CI pipeline with dagger, but felt a bit confused. Maybe because I was used to the old way dagger worked the last time I played with it. I thought it was replacing the CI provider's whole bespoke engine, but this time around it seemed more like it was replacing just individual bash scripts or commands within the engine(?). I no longer just invoke dagger once and let it drive the whole process, but call many individual modules/functions from the CLI serially? So if I want to parallelize the work and perform frontend build, backend build, and test coverage tasks all at once (what would normally be scripts all in the same gitlab CI stage), I should define a single CLI-callable function for this? And rather than dagger run, for some other less savvy user to execute it, I should provide a wrapper script to abstract away the individual function calls? What's the recommended practice here?
I'm rubber ducking more just by typing a lot of stuff out, and I can't quite put my finger on what I didn't like about the quickstart docs just yet. Something about not starting at the big picture with a whole non-trivial pipeline demonstration from which I could anchor my understanding of the use of functions, maybe. Or maybe that some of the examples were just toys (like cowsay) that I have to translate to actually useful alternatives in my head to understand the benefit. I may come back and say more if I figure that out. In the meantime, I'll be trying to put together at least part of a pipeline I use at work 👀
It's a layer on top of what you already knew. You can still write a function that implements the entire CI workflow like you could before. Or you can just implement one piece (which you could also do before). Either way, you can do it with containerized functions now, which has many benefits: call from the CLI, cross-language composition, reusable modules etc
the key is that you can easily write functions that call other functions. So you are free to abstract away as little or as much logic as you want
I'm sure I'll grok it better once I've dug into it sufficiently. I definitely see the use for the individual cross-language functions in this format -- it's like FOSS CircleCI orbs (or whatever other platforms call their reusable bits) everywhere, including local. Rad.
Yeah exactly 🙂 The transition hasn't been perfectly smooth, especially in the docs which we basically rebooted. Sorry about that. But I think it's worth it, the possibilities are truly endless now.
Also note that the "old" way still works: you can still write a custom Dagger client, and run it directly on your host machine. We think that will become more of a niche use case, as most people don't actually want to write a custom tool from scratch just to have good CI. But on the other hand, if you already are developing a custom tool, we want to make it very easy for you to embed dagger functions into it.
Having an issue with services if anyone wants to help me track it down. I have a repro using dockerd here: https://gist.github.com/kpenfound/696e49fca0bcf88e3a706a9ae1554657#file-main-go-L15-L26
The issue is that it doesn't appear the same service is being used across different calls in the same function
Dockerd services issue
Yeah exactly 🙂 The transition hasn't
In the docs here: https://docs.dagger.io/manuals/developer/go/882081/module-structure#file-layout
It says that dagger init should create a dagger.json and all the regular go files in the same directory. However, when I use that command, I get a directory by the name I expected, and inside that there is dagger.json and dagger/. Inside that dagger/ subdirectory I then find my regular go files. Should these all be one level up with the dagger.json presumably generated for the module? Or should every dagger module generated with init just contain dagger/ dagger.json at root level?
That dagger/ source directory is controversial, see https://github.com/dagger/dagger/issues/6963
The important thing to know is that you can change that source directory to anything you want with --source. The issue is about what the default should be.
I just see that the telemetry folder in internal didn't get ignore. Is that intention?
Oh, just see that it fixed on main. 👍
Do we have a primitive for unpacking a tarball, or generally interacting with tarballs in any way?
Use case: I have a tarball url, and want a directory. Trying to figure out how much I need to do myself vs. using core API
Also: I would love a core function that gives me an interactive terminal on a directory...
very common that I want to quickly inspect the result of a function that returns a directory, and have to manually orchestrate setting up a debug container with that directory mounted, so I can call terminal... I would prefer for the engine to just have a call to do that
I just looked for the first time at the source code of https://daggerverse.dev/mod/github.com/vito/daggerverse/apko, one of my most common dependencies... And LOL @vito you've snuck Bass into so many unsuspecting CI pipelines 😂
Feature request: https://github.com/dagger/dagger/issues/7171
there's no primitive for this today, definitely no reason we couldn't have this in the core api - but ideally, we'd be able to implement this as a function? but today, the caching doesn't quite work for that i guess.
I did something that felt really dirty today to work around the lack of host environment knowledge.
This works for Alpine, but Im sure there is a version for all distros.
alpine can load stuff from /etc/profile.d/script.sh whenever you have a sh --login shell, so if I pass in my entire local .zprofile file into the function I have access to all my local environment variables
func (m *MyModule) Run(env *Secret) *Container {
return dag.Container().
From("alpine:latest").
WithMountedSecret("/etc/profile.d/env.sh", env).
WithExec([]string{"sh", "-c", "--login", "echo $SECRET_FROM_PROFILE"})
}
dagger call run --env file:/Users/levlaz/.zprofile stdout
Note that this would not work, because os still refers to the engine and not the container runtime. So its still only half way to being as nice as the previous way things worked.
WithExec([]string{"sh", "-c", "--login", "echo", os.Getenv("SECRET_FROM_PROFILE")}
At the end of all this, I am more convinced than ever that I really should use Infisical for this locally and in CI 🙃
There is also https://daggerverse.dev/mod/github.com/sagikazarmark/daggerverse/archivist@769385f3c107cd70b31e64473eb5f40c6397ef8e
This is supposed to be a higher level module (also implementing a specific interface) whereas arc is just a wrapper around the arc binary.
I'm experimenting with a new way to write tests for my daggerverse repo: https://github.com/sagikazarmark/daggerverse/pull/68
What do you think?
Seems like a good way to organize tests. Maybe eventually dagger develop can generate a sample test like this
Maybe, although I would only expect tests to be generated for reusable modules, not for actual pipelines.
It's a good idea. I'd love to have a way to emulate the dagger.Connect with some sort of internal engine —in the old classic way— so we the tests can run emulating Dagger API(s), and assert against functions that use things such as WithDirectory or assert on WithExec or Sync functions for certain commands, etc.
Hm....I guess you mean for unit testing?
I don't know...most of the tests I wrote are more like e2e tests and I kinda like that. I'm mostly interested in the outcome, not the chain of function calls.
But that doesn't mean there isn't a good use case for unit style tests.
I think that falls into the grey area of functions/modules. For instance, I have modules that are very small and few of them are just exposing one or two functions. Those functions on itself are small enough to be considered as a single unit, hence a test for that specific function makes sense in that context. A more integrated API as part of the SDK(s) will be great to facilitate the unit/other sort of tests. It's kinda related to this discussion here: #daggernauts message
muahaha 
there's a bug though (I opened an issue)
ah, this is probably the same issue as with the Go SDK manifesting here too, where // +default= doesn't imply // +optional (linking for continuity - https://github.com/vito/daggerverse/issues/2)
not sure what the current status is for that, i.e. whether it can/should be fixed in the engine; @kind carbon opened an issue tracking the state of things there: https://github.com/dagger/dagger/issues/6749
actually - how did you repro this? calling from the CLI seems to respect the default, wonder if that's masking an issue
- did you only run into it in code?
Auto-complete in Go IDE
Actually @thorn moat - more broadly, the generated Go bindings were the problem for me. They make those arguments mandatory.
yep
it's because from a codegen POV the presence of a default has no bearing on that, which is wrong imo. instead it relies on the type being marked optional, which isn't necessary for an arg to actually be optional in GraphQL, and isn't really what you want, because you don't want to have to deal with a null value
I'll comment on 6749 to check what the resolution is, i'm not completely sure based on the convo
New testing strategy for daggerverse rep...
How can it be that an argument that is not marked as +optional is still optional? That makes it seem like we screwed up the design somewhere
If I understand the issue you linked, the problem is that +optional is actually implemented to mean "nullable"
leaving everyone unhappy: both people who care about nullable, and people who don't
well, what would you suggest // +default should mean without // +optional? I don't think this is screwed up, it's just a notoriously nuanced topic; we're reflecting how GraphQL works, and even that's under-documented, but it's important to distinguish these cases
I don't have a better suggestion. Just observing that people are getting consistently confused, which is a design problem
I think we're only partially reflecting how GraphQL works. To more fully reflect it, we would use the term "nullable" instead of optional. +optional would become +nullable. And "optional" is just what happens when you either have a default value, or a nullable value.
I'm not saying we should do that necessarily
But at the moment we define the word "optional" differently from the GraphQL spec
yeah, nullable vs optional conflation has come up before. it also kind of ties in to type inference; you could imagine in Go something is implicitly optional if it's a pointer. but we can't do that because all objects are pointers regardless
I think we do do that for pointers to primitive types like string but not sure
seems like this topic is still up in the air in graphql itself (to whatever extent graphql is still actively updated, anyway) - https://github.com/graphql/graphql-spec/issues/872
it seems like what has happened in practice is individual GraphQL server implementations have taken it upon themselves to allow non-null-type args with default values
There's another distinction at the GraphQL level, which is that "nullable" applies to any type, including return values, whereas "optional" (in its graphql definition of "either nullable, has a default value, or both") only applies to arguments.
yup yup
although - where is that actually defined in graphql? or is it just terminology?
afaik it's not part of the schema, fields just have a type and default
which is where the nullable confusion comes from
Which part?
the term "optional" regarding arguments specifically
here for example - they say "optional" but it's expressed as a nullable type with a default: https://graphql.org/learn/schema/#arguments
Ah. It's defined in the "learn" section, which is not the spec, but is the official learning material based on the spec. https://graphql.org/learn/schema/#arguments
But as you say, they don't specify the case non-nullable+default-value
There's a section called "input coercion" in the spec that seems relevant
If the value null was provided for an input object field, and the field’s type is not a non-null type, an entry in the coerced unordered map is given the value null. In other words, there is a semantic difference between the explicitly provided value null versus having not provided a value.
that's interesting, since if you extend that to args, from the first example we referenced that implies you can pass anullvalue forunit:- what would that even do?
oh wait, it doesn't mention a default there
Another clue in the introspection schema https://spec.graphql.org/October2021/#sec-The-__InputValue-Type:
The __InputValue type represents field and directive arguments as well as the inputFields of an input object.
defaultValue may return a String encoding (using the GraphQL language) of the default value used by this input value in the condition a value is not provided at runtime. If this input value has no default value, returns null.
Ah!
Arguments can be required. An argument is required if the argument type is non-null and does not have a default value. Otherwise, the argument is optional.
Link: https://spec.graphql.org/October2021/#sec-Required-Arguments.Explanatory-Text
nice
ok yeah that's basically how I want it to work, and how DagQL already works, it's just the codegen that's out of sync with it i suppose
glad it's actually defined in the spec
side note - these deep-links are pretty magical, you can select arbitrary text and link to it?! https://spec.graphql.org/October2021/#sel-HALTFFTBC3CDD5CAA4xG
Didn't even notice that, pretty cool
But it doesn't tell us how it should be exposed by each SDK though
isn't it just something like argIsRequired = !argType.Optional && !arg.Default? (to determine whether e.g. Go makes it a required arg or puts it in the Opts struct)
plus maybe renaming Optional to Nullable (or flipping it to NonNull to match GraphQL more closely)
since codegen is driven by an introspection schema JSON, I think each SDK would have to do that, unless we switch them to be based on our own typedefs, at which point we could expose a higher level check for that (like FunctionArg.isOptional)
The spec defines "required" and "optional" as opposites though. So yeah that argType.Optional is a problem
right, the semantics are unclean in that case, just because we're using that word
so we want something like argIsRequired = argType.NonNull && arg.Default == null then?
Does it even make sense to have an explicit non-null marker though? Either it can be infered by the native type already (eg. a Go function that returns a string is for sure String!), or it can't.
gets back to this issue - object types are always pointers in Go, so you can't always tell
that part is probably SDK-specific
that argIsRequired bit would be in codegen running against a generated schema though, so that decision is already made by the time we're generating code for it
for Go code => schema, I think you'd still need a comment to explicitly mark an object arg as optional (or nullable)
...unless we do some sort of cursed double pointer thing
OK better late than never: I'm starrting a thread 🙂
Random ?: Is there a general recommendation or leaning on building and publishing containers - via feeding a Dockerfile in or going all-in on Dagger native to build a publish containers?
Random ?: Is there a general
I'm writing up a proposal that I think will make you happy @wintry prism
Here it is: https://github.com/dagger/dagger/issues/7199
this with dagger will be unbelievable https://www.pulumi.com/blog/docker-build/
seems like a really cool addition to pulumi, but how do you see it integrating with Dagger? At first glance that plugin is redundant with the core Dagger API.
Anything in combination with Dagger becomes friggin cool. But, yeah. Some tools solve similar problems as Dagger does. Dagger is just doing it better IMHO. 😄
Opened this issue to start a conversation about pushing to Git repos from Dagger: https://github.com/dagger/dagger/issues/7202
For more complex functions and/or modules, with the principle in mind that they should be composable and self-contained, I've been thinking in cases that require complex logic beyond simple commands in WithExec — currently, my workaround involves writing the logic in —let's assume I'm writing it in Go— a Golang program, creating a container image, and initializing the Dagger function with dag.Container().From(mycustomimage:latest). This process is cumbersome as it involves multiple steps.
I'd love to have an API similar to WithExec, perhaps something like WithCodeEntryPoint("main.go"), that allows running code directly in a pre-existing base image as it's currently possible nowadays (e.g., golang:alpine), without the need to create and push a new container image 🤔
Have you considered this scenario, and what are your thoughts on its feasibility given the current capabilities of Dagger functions?
Contextual modules
my initial use case was to use dagger for the CI on the dockerfile build and use pulumi to push the image to a registry.
I admit tho I did not think about a dagger module for docker and I have not used it, if anyone has a reference example for building containers and shipping to a registry I would be happy to see it
This is in the core API. https://archive.docs.dagger.io/0.9/quickstart/730264/publish. These core API docs needs to bubble up to the current module docs. You could create a wrapper module to publish something and I am doing that currently at my work (dagger -m module call publish). The module is just using the core API to build and publish. Unfortunately I can't share that code here but you get the gist.
You can call publish on any Container object that gets returned in a module.
awesome thanks for sharing!
the core API reference is available in the current docs. See https://docs.dagger.io/manuals/developer
If I search the new site for "Publish" I only see a "Dagger module publish" doc. The previous "cookbooks" and "quickstart" guides for using the core api were very helpful. I still refer to them.
is there a recommended solution for the CD portion of application delivery with dagger? I realize that is application dependent and the answer might be "whatever you want, Argo, Flux, etc"
@willow carbon @restive shore https://docs.dagger.io/manuals/user/577201/publish/ has an example of building and publishing a container with publish. I hope that helps? Thanks also for the feedback on the search...I checked quickly just now searching for "publish" as you did and the page linked above appears in the drop-down list of search results (4th in the list)
that is unbelievably cool. I love wolfi too.
@chrome pilot I'm still digesting your idea that all modules could be contextual - ie. always look in .dagger 🤔
Curoius, why a map isn't supported for the type inference when writing functions?
For example
type MyModule struct {
Src *Directory
CfgFile string
// EnvVars map[string]string
EnvVars map[string]string
}```
The `EnvVars` breaks the code-generation.
Error: generate code: template: alias.go.tmpl:74:3: executing "_dagger.gen.go/alias
┃ " at <ModuleMainSrc>: error calling ModuleMainSrc: failed to parse field type: unsu
┃ type for named type reference *types.Map```
The Dagger API uses GraphQL schemas for cross-language interop. The GraphQL type system does not support maps.
Here's how we expose env variables in the core API: https://pkg.go.dev/dagger.io/dagger#Container.EnvVariables which returns an array of structs, and https://pkg.go.dev/dagger.io/dagger#Container.EnvVariable which looks up one variable by name
Another experiment I'm running: Unsafe API for modules to access certain features of the underlying container: https://github.com/sagikazarmark/daggerverse/pull/73
is this code generation intentional? using pointer and non-pointer refs causing warnings by IDE.
func (r Gh) MarshalJSON() ([]byte, error) {
var concrete struct{}
return json.Marshal(&concrete)
}
func (r *Gh) UnmarshalJSON(bs []byte) error {
var concrete struct{}
err := json.Unmarshal(bs, &concrete)
if err != nil {
return err
}
return nil
}
IMO it doesn’t matter. Unmarshal has to be a pointer, but Marshal doesn’t.
Yea i know it's not blocker but warning is annoying. I guess I need to disable this warning for dagger files
I’d say it makes sense for any generated code. 🙂
but this is not only for generated codes. it includes module code since Gh is extended from my module code. Anyway, no impact on code itself, just on me 🙂
yeah, this is weird 😄 super easy fix though, so https://github.com/dagger/dagger/pull/7216
👋 Dagger devs! Just created a new proposal issue here https://github.com/dagger/dagger/issues/7217 with the intent to improve our Daggerverse modules quality by allowing module creators to write examples for their modules that will be surfaced in Daggerverse. Any feedback or ideas are always welcome. Please don't heistate to ask if you have any questions 🙌
GitHub
Problem In many cases it's not clear for module consumers how to use them once they find them in the Daggerverse. Even though https://daggerverse.dev has detailed docs about the module function...
I didn't really understand the difference between "solution 1" and "solution 2"
I'll clarify the difference
the most important difference is that solution 1 will only translate the GraphQL queries made by the example code. So if the user writes something like:
func (e *JavaExample) ExampleJava() *Container {
c:= dag.Java().WithJdk("17").
WithMaven("3.9.5").
Container().
WithExec([]string{"mvn", "--version"})
if "foo" == "bar" { fmt.Println("test") }
return c
}
then the if statement won't be part of the generated example code since that is not part of the GraphQL pipeline query
as we're capturing the underlying graphql query from the returned *Container.ID(ctx) dagger.ID type
yeah that doesn't seem worth it to me
Is the idea that it might be a shortcut for generating multi-language snippets?
Exactly
I may be wrong, but doesn't seem worth it
Non-trivial engineering, and limiting experience for the user.
Better to invest the engineering in gradually improving a LLM-based snippet translation IMO
ie. assume LLMs will do it perfectly. Then plan gradual steps from there. Don't invest any engineering in something that you'll need to rip out later when LLMs do it perfectly
Also support for CLI example is key (not sure how your current plan addresses that, but I'd be curious to learn more)
Funny that you bring this up because solution #2 is basically this without the LLM part given that it's something that it won't probably happen in the short term
Funny that you bring this up because solution #2 is basically this without the LLM part
Yes I had the same thought, agreed.
given that it's something that it won't probably happen in the short term
Why not? Can't we invest a few cycles in exploring that, the way you proposed doing for graphql-based codegen?
Yes, we sure can. I'll ping you tomorrow since I have some things I'd like your opinion about.
I'll also add to the proposal the UX for writing and consuming those examples (i.e: if they should be a field of the Module core API type)
I liked the idea I saw floating around, of an examples/ directory with random files, which you can reference at will
But curious to hear other ideas as well
Yes, that's around my idea as well.. with some caveats
First naive attempt at translating with GPT4 🙂
Python:
from dagger import dag
class JavaExample:
def example_java(self) -> dagger.Container:
c = (dag.java()
.with_jdk("17")
.with_maven("3.9.5")
.container()
.with_exec(["mvn", "--version"]))
if "foo" == "bar":
print("test")
return c
Typescript:
import { dag, Java, Container } from '@dagger.io/dagger';
class JavaExample {
exampleJava(): Container {
const c = dag.java()
.withJdk("17")
.withMaven("3.9.5")
.container()
.withExec(["mvn", "--version"]);
if ("foo" === "bar") {
console.log("test");
}
return c;
}
}
Hello everyone 👋
For the past few months, several discussions have occurred around the best way to allow other SCM than GitHub for modules and Daggerverse. This is now a top-priority on the backlog 👼.
As no perfect solution exists, your opinion is extremely valuable to assess what behavior you would expect as a user, especially as it might touch the developer experience
Feel free to comment / take a look: https://github.com/dagger/dagger/issues/7218 🙏
is there any webassembly modules?
There doesn't seem to be one yet: https://daggerverse.dev/search?q=webassembly
What are you planning on doing ? What is the use case ?
I could use some help with this: https://github.com/dagger/dagger/issues/7220
OpenSSL cannot read SSH keys mounted as ...
I don't know yet, just starting to learn wasm as I see the value it has
👋 just updated my proposal with some feedback from our previous interactions @sharp zealot and also added a new UX section with an idea of how that could work. Would love some 👀 if anyone has the time 🙏 https://github.com/dagger/dagger/issues/7217#ux
GitHub
Problem # In many cases it's not clear for module consumers how to use them once they find them in the Daggerverse. Even though https://daggerverse.dev has detailed docs about the module functi...
Experimenting with a possible scripting DX: embed a bash-compatible interpreter in dagger, bind it to dagger without argument. Basically making dagger a repl.
Even with bash-compatible syntax, command execution would be resolved dynamically based on the current pipeline. So, we could take advantage of the familiar pipeline syntax:
dagger install github.com/shykes/git github.com/shykes/daggerverse/wolfi
#!/usr/bin/env dagger
base() {
wolfi | container --packages git,openssh,go | without-entrypoint
}
repo() {
git | clone --url https://github.com/dagger/dagger | checkout --ref=v0.11.2 | directory
}
container() {
base | with-mounted-directory --path=/src --source=$(repo) | with-workdir --path=/src
}
ctr | terminal
GitHub
Problem In monorepos, it's common for each sub-project of the repo to have its own submodule. But there is no easy way for the root module to "pass through" the functions of its submo...
Feedback on latest Traces UI changes:
- I love that the "error path" is highlighted
- I find it confusing that the error path is shown twice: first in the special "errors" section, then again in the "general" view.
- It would be better IMO to collapse the two: only show one view (the usual spans view), but when there is an error, collapse everything except the error path. This would get the best of both worlds
Also the structure of the call tree is less clear, there is more noise:
- "Spans" repeated each time: noisy
- "Logs" and "Spans": there's both. What is their relationship? Logs are shown first, so were they chronologically first? Or are logs and spans interleaved, but if so why not render them as interleaved?
- Getting mixed signals on the hierarchy: are "Logs" and "Spans" nested inside the
clone()call? They're not inside the call's "box". There is a branching line that says maybe yes; but the branch happens after theclone()box, so maybe it's unrelated? Confusing. Multiply by each span, and add the "duplicate error path", I no longer am confident I know what's going on
@sharp zealot what's the rationale behind keeping git state and workdir in separate directories in your Git module?
flexibility and accuracy mostly. git itself supports decoupling them with --worktree, so I wanted to make sure my API can model everything you can do in git.
Apparently there is no WithoutSecretVariable and WithoutEnvVariable doesn't clear those env vars. Is that intentional?
Quick fix: WithSecretVariable("VAR", dag.SetSecret("reset", ""))
That sounds like an oversight to me, I can create an issue
Yeah oversight
I think we're going to do this. Now's the time to review the design, and share your thoughts! https://github.com/dagger/dagger/issues/7199
Added a few more comments, but overall, I like it very much.
Finally I had time to read. I need a little bit more time to digest to whole discussion but I find this exciting especially possible future extentions.
Dagger just started randomly doing this without me changing anything:
Quesion on rendering of comments today and examples in future in modules from @acoustic forge
So if you see the code I do have the function descriptions written here: https://github.com/okteto/dagger-module/blob/main/dagger/main.go#L44-L47 but ever since I add a gap between the description and the example command it stopped showing the description. My problem is that if I don't add that gap line then it renders the description and example in the same line (see screenshot)
// Deploys a preview environment in the specified Okteto context
// example usage:
// dagger call preview-deploy --repo=https://github.com/RinkiyaKeDad/okteto-dagger-sample --branch=name-change --pr=https://github.com/RinkiyaKeDad/okteto-dagger-sample/pull/1 --context=yourinstance.okteto.com --token=$OKTETO_TOKEN
func (m *OktetoDaggerModule) PreviewDeploy(ctx context.Context,
// Repo to deploy
repo string,
...
cc @dense canyon @void widget
Has anyone seen this?
Failed to connect; retrying... make request: Post "http://dagger/query": rpc error: code = Unknown desc = failed to verify client: client ID "***" registered with different secret token
Happens after upgrading to 0.11.3
Figured it out: https://github.com/sagikazarmark/daggerverse/pull/96/commits/1090eee44f94be6aa09e20d28301af0e8d582261
Setting the same secret in parallel causes Dagger to hang.
GitHub
What is the issue? Failed to connect; retrying... make request: Post "http://dagger/query": rpc error: code = Unknown desc = failed to verify client: client ID "***" registered ...
@rocky harbor could this be related to recent session shenanigans?
Nothing purposely change in v0.11.3 related to sessions, looking though
Ah wait, I saw the registered with different secret token error message now, that is possibly related to some changes. I'll see if I can repro
I figured it out in the meantime (setting the same secret in parallel) and it kinda makes sense that it doesn't work, but I wouldn't expect Dagger to hang.
Yeah that will coincidentally avoid the problem, but I think I know the underlying cause and it's a bit more generic than just setting secrets.
Fortunately the fix is pretty straightforward and already part of something else I was working on, so I'll just extract that out and we can get it in for the release tomorrow. cc @jed funnily enough this is a problem that ftp_proxy unintentionally masked but now was revealed by removing that hack lol. Thankfully we have better ways of fixing it now via all the recent improvements, don't need to go back to that 😮💨
Fix here: https://github.com/dagger/dagger/pull/7335 The fix was what I was imagining originally but while testing some more I did realize that we aren't getting cache hits as expected when providing args of type Secret to functions, which is quite odd, but a separate issue (more details in the commit message). The fix there is still good to go either way.
Ah, I may have found the problem with the caching, @thorn moat these OTEL values appear to be random every time the same function is invoked with the same inputs: https://github.com/sipsma/dagger/blob/47a8a80c1109b1032cd167f011bda3aafda36904/core/modfunc.go#L209
So they end up invalidating the buildkit cache every function call. Fortunately dagql caching masked most of that, but if there's an impure ID (such as Secret) then we don't hit dagql caching and get buildkit cache misses.
Fortunately the new way of passing random IDs without busting cache that I also used in the above PR should be perfect for this too, just FYI in case it's not expected those values are different every time.
Fix for that one here: https://github.com/dagger/dagger/pull/7336 To be confirmed, but wouldn't be surprised if that resulted in a noticeable performance improvement 🎉
The Daggerverse use markdown format to render function doc on the web?
No, we decided to start with no markdown rendered. Could you tell me more about what you'd like to do?
I just see it highlight as a code block when I used backquote (`), that's what I'm curious. No issue specific.
ah, I'll take a look, thanks!
@void widget it might be in the comments, right?
Yes exactly, just the comments, but this is already being abused by some modules in a sense that it dephases the page when people use the markdown too extensively, so it might change a bit 💯
Do you like it ?
Do you have an ETA for updating Dagger under daggerverse?
https://daggerverse.dev/crawl/github.com/sagikazarmark/daggerverse/helm@v0.4.0
does dagger utilize gpu's when running modules?
oi, not sure how i didn't think of that busting caches
- thanks for fixing it!
Should have been upgraded to 0.11.3 an hour ago 👍
hm, doesn't look like it is
https://daggerverse.dev/crawl/github.com/sagikazarmark/daggerverse/golangci-lint@v0.2.0
https://x.com/sagikazarmark/status/1788527291800170928
Shame-driven development, nicely done @latent trellis 😂
How to update all your @dagger_io dependencies:
cat dagger.json | jq -r '.dependencies[].source' | cut -d '@' -f 1 | xargs -L1 dagger install
LOL, that definitely wasn't my purpose 🤣
But now that you mention it... dagger install -u would be easier 😄
GitHub
What are you trying to do? Automate/make dependency updates easier. Dependency update strategies: Update one dependency because I need something from a newer version: dagger install github.com/... ...
Covered in https://github.com/dagger/dagger/issues/6605
@kind carbon a user today with hatch was having trouble with his VS Code IDE with the pip install -e ./sdk instructions.... not sure if there is something special he needs
Yep, for example: https://github.com/dagger/dagger/blob/main/sdk/python/dev/pyproject.toml
There's instructions about using hatch here also Jeremy: https://docs.dagger.io/manuals/developer/python/742020/ide-integration
This looks like it's with trivy and not dagger, unless i'm missing some context 🙂
i had crashed or weird project (repo)... when i rewrote it it works
Trying out a random idea: how would you feel about a dagger embed command, to help you embed dagger functions in your own native software project? Basically the "classic" use case, but legitimized by a clear framing ("embedding dagger in your code") and a proper UX (dedicated subcommand).
Things you could do with dagger embed (and its subcommands, tbd):
- Manage the installation of a Dagger client library for your language
- Manage generation of native client bindings for dagger modules you wish to call
Thoughts?
If the discussion yields anything, I'll write it up in an issue
Trying out a random idea: how would you
I'm currently trying to gale to v0.11.x and trying some non-sense combinations with new features. But it's too hard to find what is breaking to code. Is there any better way to diagnose what is breaking my code?
dagger develop
✘ ModuleSource.asModule: Module! 0.4s
! failed to create module: select: failed to update codegen and runtime: failed to generate code: failed to get modified source directory for go module sdk codegen: select: process "/usr/local/bin/codegen --output /src --module-context-path /src/dagger/gale --module-name gale --introspection-json-path /schema.json" did not complete successfully: exit code: 1
✘ Module.withSource(
source: ✔ ModuleSource.resolveFromCaller: ModuleSource! 0.0s
): Module! 0.4s
! failed to update codegen and runtime: failed to generate code: failed to get modified source directory for go module sdk codegen: select: process "/usr/local/bin/codegen --output /src --module-context-path /src/dagger/gale --module-name gale --introspection-json-path /schema.json" did not complete successfully: exit code: 1
✘ Container.directory(path: "/src"): Directory! 0.3s
! process "/usr/local/bin/codegen --output /src --module-context-path /src/dagger/gale --module-name gale --introspection-json-path /schema.json" did not complete successfully: exit code: 1
✘ exec /usr/local/bin/codegen --output /src --module-context-path /src/dagger/gale --module-name gale --introspection-json-path /schema.json 0.3s
! process "/usr/local/bin/codegen --output /src --module-context-path /src/dagger/gale --module-name gale --introspection-json-path /schema.json" did not complete successfully: exit code: 1
┃ generating go module: gale
┃ writing dagger/gale/dagger.gen.go
┃ writing dagger/gale/go.mod
┃ writing dagger/gale/go.sum
┃ running post-command: go mod tidy
┃ running post-command: go work use .
┃ needs another pass...
┃ Error: generate code: template: alias.go.tmpl:76:3: executing "_da
┃ .go/alias.go.tmpl" at <ModuleMainSrc>: error calling ModuleMainSrc
┃ ed type spec to be a struct, got *ast.SelectorExpr
Error: failed to get module SDK: input: moduleSource.withContextDirectory.asModule resolve: failed to create module: select: failed to update codegen and runtime: failed to generate code: failed to get modified source directory for go module sdk codegen: select: process "/usr/local/bin/codegen --output /src --module-context-path /src/dagger/gale --module-name gale --introspection-json-path /schema.json" did not complete successfully: exit code: 1
Stdout:
generating go module: gale
writing dagger/gale/dagger.gen.go
writing dagger/gale/go.mod
writing dagger/gale/go.sum
running post-command: go mod tidy
running post-command: go work use .
needs another pass...
Stderr:
Error: generate code: template: alias.go.tmpl:76:3: executing "_dagger.gen.go/alias.go.tmpl" at <ModuleMainSrc>: error calling ModuleMainSrc: expected type spec to be a struct, got *ast.SelectorExpr
I find it kinda weird that I have to name secrets: dag.SetSecret("name", "value").
Is there a way to skip that?
It makes APIs kinda bloated when a function creating a secret is called repeatedly.
It's been a while, but that API was the result of a long and relatively painful design process. Here's the context: https://github.com/dagger/dagger/issues/4426
I would have to refresh my memory on how we landed here, and whether we learned anything new since, that would justify changing.
One thing I do remember, is that we thought of this API as an intermediary step towards pluggable secrets providers. Having a caller-supplied secret name would give a path to this future design
From the comments: https://github.com/dagger/dagger/issues/4426#issuecomment-1439002686. The "option D" was the compromise that unblocked us.
From what I can tell, what's new since is the introduction of functions. Modules can provide an API for accessing secret management solutions.
I'd also argue that with the introduction of functions, the current design just became a lot more confusing.
For example: what if I have a function that creates secrets? Can I reuse the name? Do I have to expose an option and make sure each secret has a unique name.
The alternative is generating random UUIDs I guess?
But that might mess with caching.
I agree that we should revisit the API in the context of functions.
Well secrets already have an ID
I mean as a secret name.
I mean, assigning a name to the secret is mandatory, right? And it has to / should be unique.
Yes. I honestly don't know if we could/should do that, but it's a good question. Now is a good time to revisit it
Would you mind creating an issue? 🙏 Otherwise I can do it monday (need to wrap up a few other things this week-end, with the crumbs of time I get in between family time 😛
I'm experimenting with doing this for now: https://github.com/sagikazarmark/daggerverse/pull/104/files#diff-9939fe6b52f57b7d55107ef277a7ecfb88c8336b43d0257431041d709f232b21R105
Why not hardcode an arbitrary string in the code?
Basically like cache volume names
Well, I'm guessing if I call this function multiple times (with different content), it may cause issues when using the secret in different places?
Oh, meaning there might be a namespace conflict? Similar to cache volume namespace conflict?
yep
I opened an issue: https://github.com/dagger/dagger/issues/7358
GitHub
What are you trying to do? I have a function that creates a secret: https://daggerverse.dev/mod/github.com/sagikazarmark/daggerverse/registry-config@b45dbd7448bb967aca4a538af9ce7f042abf0316#Registr...
Yes I guess you need to interpolate into the secret name each variable that might change in the context of creating the secret (for a given session)
I'm generating the secret name based on the content. I think that should be enough for now.
Yeah, and I see your point that, if that works better for you, and has no downsides, it may be a wake up call to that name argument not being needed or helpful at all
That's basically what the CLI is doing when you provide a secret (hash based on the content). Helps with cache as well, but leaves an opening for a brute force attack, however difficult that is.
At a hackathon and it would really help to hack the compose / api service. We're hacking on a benchmark tooling of LLMs based on Dagger (pretty cool) @mossy hazel if you're around, seing you connected
PS: can we expose as service a function that also receives services ? I am getting an Invalid host header/ error which does seem to come from us.
PS: was my fault - The terminal DX loop is amazing
@dense canyon saved me 😍
@void widget how's the hackathon going?
Mmmh, lots of learnings along the way. It's a nice edge case. I'm hitting all the issues on module consumption atm. The perfect design will be a follow-up
But, Dagger functions fit very well as the engine for their python based DSL. Pretty bullish 😇
I seem to be in daggerverse publish limbo - has anyone ever seen this error?
trying to publish this via the site: github.com/levlaz/daggerverse/docusaurus@v0.2.1
get name: input: moduleSource.asModule resolve: failed to create module: select: failed to update codegen and runtime: failed to diff generated code: select: TODO: cannot diff with different relative paths: "" != "/"
Can you update your module's engine version from 0.11.2 and retry?
That being said, we need to update Daggerverse to 0.11.4 (currently at 0.11.3)
I seem to be in daggerverse publish
Which API do you like better?
Option A:
func (m *Module) Func (
// +optional
// +default=true
cache bool,
)
CLI invoke: dagger call func --cache=false
Option B:
func (m *Module) Func (
// +optional
noCache bool,
)
CLI invoke: dagger call func --no-cache
I prefer option A. More natural, and leverages native support for default values
Default you want to see gone? 🤣
I get the point though
To be totally fair. That was slightly more than a month ago. If dog years are 7x, dag years are at least 10x 😁
I love default values, wasn't sure about the best way to express them in Go. We cycled through different options.
I have accepted that they are all bad in some way
FYI I've been avoiding using +default mostly due to that issue. Maybe I shouldn't have read too much into it. But I definitely see the challenge: Go is opinionated and it doesn't always get everything right (and it never admits it)
What's the current status of Go workspaces support while developing dagger functions? — There are some utility functions in Go that most of my modules shared, and I truly hate DRY 😅 .
If you hate DRY, does that mean you like repeating yourself? 🤔
In my experience Go workspaces cause more trouble in Dagger than not. Why not just import it as a module?
You can also use pointer types and let NULL be the default value. This requires the user to covert to a default value inside the function, but is only 1-3 long longer than using an optional or a default argument
I don't consider them as modules. When I refer to utility functions, I'm talking about those that perform mundane tasks, such as converting a comma-separated string into a slice or performing very basic validations. I prefer to use the natural capabilities of the language of choice. In this particular case, that means utilizing Go workspaces instead of creating an entire module when it's not justified (I don't need a module :), I need to just share reusable code).
If the Go workspace + dagger combination wouldn't be problematic, would you create a module for sharing code?
I meant a Go module, not a Dagger one.
That's precisely my scenario —that it wasn't working properly with Dagger modules in the past, hence my question. I have a go module that encapsulates a set of reusable Go functions that normally I use in all my dagger modules. For that, in my Daggerverse mono repo I've configured a Go workspace to precisely allow my Dagger modules (Go modules) to reuse it. It works fine, but it fails when I try to publish (at least the last time I tried) without recognizing the go modules used in some of my dagger modules (more details here: https://discord.com/channels/707636530424053791/1232967596366757911)
Discord
Discord is the easiest way to communicate over voice, video, and text. Chat, hang out, and stay close with your friends and communities.
does this relate to https://discord.com/channels/707636530424053791/1238628471920525352 by any chance? kinda looks like it - just crossing streams 🙂
It relates to making sure certain actions are not cached.
Like pushing to a remote service
@thorn moat I guess this is a gap in our TTL discussion: we discussed how the callee can specify its caching TTL, but not how the caller might want to change it
yeah, makes me wonder if there's some generalized 'cache key' thing instead, and TTL is automation for 'generate one based on now().truncate(ttl)'
@latent trellis the other discussion is a way for your function to specify its own caching behavior:
"I want my function to always be cached, with a TTL of 1 second"
// +ttl=1000
func (m *Module) Func () {
}
"I want my function to never be cached (ttl=0)"
// +ttl=0
func (m *Module) Func () {
}
IMO there's no benefit to that
(that I could find)
yea not sure. it'd be sort of a formalization of the withEnvVariable("BUSTER", time.Now().Truncate(...)) pattern i guess?
But whether TTL is enough or not, either way we're missing a mechanism for the caller to change it at runtime
yes exactly
I find myself using that pattern a lot. That's what I'm hiding with the cache/noCache option.
Do you actually need the caller of your function to configure how it's cached? Or is there one correct caching behavior?
Couple things I probably never want cached:
- git clone
- git push
- helm push
I guess TTL could be considered an operator concern, rather than something you write in the code? 🤔
Ehm, no....in this case that's a generalized interface. Something like GitCommand in your git module.
i'd presume you would want git clone cached but only if it's preceded by a 'get the commit to clone' call that's not cached (and then the commit is the 'cache key') - or is cached with a TTL (like 1 minute)
Higher level commands like push/pull rely on that interface.
Yup. I'm currently working on a GitOps workflow which starts with "clone the latest state of the gitops repo". I don't want that cached.
That's where lookup functions would come in IMO.
- Lookup function gets the commit. As a lookup function, it's cached in a special way
- Other function uses the result of the lookup, so can be cached aggressively
(continuing the thread in #1238628471920525352 )
What's the story behind remotes.docker.resolver.HTTPRequest in the TUI? Is that the actual path of a function? But then why not show the call tree eg:
remotes()
docker()
resolver()
HTTPRequest()
Any way we could make this message more user-friendly? It comes up a lot
it comes from internal buildkit plumbing that we don't control; it's not a function path. @deft rain is looking into wrapping this in an encapsulating span so you won't see it unless it fails
What if we just didn't show it? We'd still see the encapsulating function from(address: "foo") which is probably all we need right?
yea true, we could just make the from span encapsulate, don't need to wrap it in another
yup, looking at this now ❤️
i mentioned this to @thorn moat yesterday coincidentally
this is generally part of trying to make the plain progress better, some of this noise gets lost in the fast tui, but when it's in the logs forever, it sticks out a lot more
have a pr: https://github.com/dagger/dagger/pull/7386
there's a fairly horrendous hack in there, so need to go do some little bits of work in buildkit+containerd
Hey Ian, did you manage to get some example? I am also looking for some
It's not really unit testing, but all of my modules have a tests submodule: https://github.com/sagikazarmark/daggerverse/
Thanks for sharing will take a look 😉
I think exposing custom otel spans so quickly, without much discussion on use cases and tradeoffs, was a mistake
"no is temporary, yes if forever"
I am seeing confused users trying to use this bonus feature correctly, when we don't even have the basics fully figured out
And scarse SDK dev cycles going into parity for this, when we have more urgent issues
the thought process was:
- this is inevitable (why integrate with otel without integrating with otel)
- we get this for free (buildkit already handled 90% of the plumbing) - one of the benefits of embracing an existing ecosystem in the first place
- users don't need to solve for "dagger + otel" - they just need to understand otel, and only if they want/care to, there's no special aspect of dagger, it's just otel like usual
so:
- where is the confusion coming from? isn't it all just standard otel integration?
- what are the "basics" that we haven't fully figured out?
from my POV it was a tiny amount of effort in the Go SDK to point to plumbing that we already needed there for other reasons and everything "just worked" the same way otel always does, so I'm confused to see this tbh
there is an extra catch for emitting live telemetry data, but it degrades gracefully (telemetry gets flushed on span completion like otel normally does), so I saw that as a sort of 'progressive enhancement' option for SDK authors with little time
we also knew there would be kinks to iron out with swapping out the entire telemetry infra in such a short timeframe, but figured that was the lesser evil to doubling down on 100% bespoke telemetry infra that was also not really figured out. i know that's not the part you contend with, but compared to the other kinks this was assumed to be a more certain thing, given all of the above
maybe we just un-document it until we have the cycles to expose it properly? the entire tracing functionality has been framed as 'beta' so it's nothing is really 'forever' yet
yeah switching to otel was an excellent decision for sure
yes I think we should hide the custom spans feature completely from the docs until we can clearly explain when how and why you should use it.
It is about dagger+otel, because we show spans alongside function calls in our Traces feature, and in the TUI. So to understand our visualization you have to understand otel spans. And if you emit custom spans from a dagger function you're changing how that function and its subfunctions will be visualized
Right, by that I only meant there are no special "dagger otel" APIs to learn, it's at least supposed to be as if you just integrated otel into any other project. But there definitely is an aspect of how it interacts with Dagger's lazy/async APIs that you need to be familiar with, and our docs really need to drive that point home - they're not there for you to use constantly in the same breath as Dagger APIs, since Dagger functions should be handling 99% of that. They're more of a "you should only use this if you are already pretty sure you need to" (e.g. measuring individual test performance)
actually, there are magical span attributes that users may want to use that are worth bikeshedding, and maybe exposing convenience APIs for in the SDK (e.g. whether to encapsulate) - so there really is a "dagger + otel" to some extent, in a progressive-enhancement kind of way
Why isn't there a dag.NewFile method?
I find myself writing code like this a lot lately:
dag.Directory().WithNewFile("file.json", content).File("file.json")
Yeah, I've felt the same need 🙂
I resisted the urge to create a new-file module. We don't want Dagger to become the new NPM/JS, do we? 😛
I asked myself the same question last week 🙂 Agree
I think there may be a technical limitation - in buildkit, files can only exist in the context of a directory - they have a name property. So a file in a vacuum is not possible in buildkit I believe. But perhaps we can implement it in dagger anyway
Just collecting random feedback — It'd be awesome to have more human-readable sort of errors. When facing errors during the development of a module such as:
Stdout:
invoke: input: container.from.withEnvVariable.withMountedDirectory.withWorkdir.withMountedCache.withEnvVariable.withExec.withExec.withExec
.stdout resolve: process "xyz command" did not complete successfully: exit co
de: 125
If there's an invalid parameter passed or unexpected by the Dagger APIs, would be awesome to have something like the environment variable passed is invalid due to or the mounted directory could not be found or you haven't set enough permissions, etc. I think it'll reduce the initial friction for new module builders who aren't so familiarised with the Dagger APIs. 🤔
Maybe a good addition to https://github.com/dagger/dagger/issues/6718
(also: I completely agree)
How does everyone feel about the dagger develop command? Do you find it clear and useful? Or confusing and cumbersome? 🙂
(I'm asking in connection to the design puzzle that is contextual modules: https://github.com/dagger/dagger/issues/7199)
How would the IDE support work without dagger develop?
I use it to actually get my IDE to do anything at all to detect issues
vscode extension?
i'd definitely like to do something like that (i briefly investigated integrating into gopls using the same approach that bazel does: https://github.com/bazelbuild/rules_go/issues/512)
but imo, we shouldn't remove dagger develop until we have a fully working solution like that (manual is better than nothing right now)
Assuming everyone uses vscode? 🙂
Yes I'm not suggesting we remove it - was wondering if we should consider either renaming it, or splitting its different features in more focused commands
(both ideas are speculative)
Things dagger develop does today:
- Install and initialize an SDK (if needed)
- Set some SDK configuration (where to store source directory)
- Have the SDK one-time generate boilerplate (if needed)
- Have the SDK generate client bindings
- Have the SDK build the runtime containers and print any errors
https://docs.dagger.io/reference/typescript/modules/api_client_gen/#containerwithdirectoryopts
Any reason we don't have a permissions opt to complement owner on withDirectory()?
We have it for withFile() and withFiles() ...
https://docs.dagger.io/reference/typescript/modules/api_client_gen/#containerwithfileopts
https://docs.dagger.io/reference/typescript/modules/api_client_gen/#containerwithfilesopts
I'd say that it's also a sort of static checker, or at least is another usage that I give to it. If there's something 'wrong' in your code, the code generation part will complain and you'll notice it. Having a dedicated command for static analysis or a more advanced linter would be helpful. It's more or less similar to what @deft rain commented.
I think having more scoped/focused commands will be more readable, like dagger develop check (for static analysis, code-generation validations, a canonical fmt that we'd like to enforce as part of a more standardise way of developing modules?
, if the module has dependencies on another modules, check basic things such as the dependency path, versions, etc. ). By the way, I use mostly Jetbrains IDE(s) (Goland), and I hook it to my On Save/File Watcher settings, it's a sort of a hook that helps me to get quick feedback whenever I'm developing a module.
I agree
DX request 🙂 https://github.com/dagger/dagger/issues/7399
How would you feel about dagger sdk? Since all these features have in common that they're about interacting with a Dagger SDK?
I use it to make the development tool works (autocomplete, jump to definition, etc.). However, I got a little confuse when trying to debug or print the information what is the runtime doing because the runtime didn’t use file from dagger develop but regenerate code again.
dagger sdk install -> install an sdk
dagger sdk generate -> ask the sdk to regenerate bindings
dagger sdk update -> update sdk
dagger sdk config -> configure sdk
maybe?
also need to figure out how to differentiate "I'm developing dagger functions" and "I'm developing my own project and want to embed generated client bindings into it" ( #1238585212523384832 )
That makes sense. Provide nice (dev) tooling for quick feedback, rapid troubleshooting, and hopefully, a seamless integration with the IDE will help in reducing a lot of the friction, and encourage more folks to develop modules. What about dagger sdk lint or dagger sdk validate, so it's easily hooked into git hooks, or even CI made for Dagger modules?
Personally —I think it's a scenario reached by folks that have developed modules already— is how to enrich the debugging experience #1230026862860963920 message — I'd love to have an integrated way to hit my breaking points in my IDE while debugging functions, instead of just relying in plain logs that aren't necessarily human-readable.
Calling for comments on an important design decision.
The decision is: are we serious about making the Dagger CLI scriptable?. Do we want to support users implementing logic in a shell script beyond a unique dagger call?
This is important because it will influence the structure of our docs, and our best practices in general. It will also affect our priorities.
- Docs: does it make sense to keep "user manual" and "developer manual" separate? If we want the CLI to be scriptable, then it doesn't.
- Best practices: is it realistic to daggerize your project without writing Go, Typescript or Python? Today the answer is "no". If we make the CLI truly scriptable, it might become possible in the future.
- Features: if we want the CLI to be scriptable... We need to prioritize work to make it happen. The longer we wait, the harder it will be to change best practices and docs later.
Related design discussions:
GitHub
Somewhat related to #6112 but a bit more general Passing a large number of flags and args when using dagger call can become way too tedious to type out by hand. One example would be support for fil...
GitHub
Problem There are two types of Dagger modules: those that are standalone software projects, and those that exist in the context of another software project. Let's call those standalone modules ...
GitHub
Problem There is no way to call core functions from the CLI Solution Allow calling core functions from the CLI. See https://daggerverse.dev/mod/github.com/shykes/core for a userland implementation.
GitHub
Problem When calling a function that returns a core type, like Container or Directory, I can then call any function from that core type... except id. This makes it unnecessarily difficult to stitch...
Separate topic: what happens if I write a go module that uses graphql interfaces? Can python and ts clients consume that module?
Yeah interfaces only requires SDK support on the authoring side. Consumer-side all SDKs support it without any effort because it just ends up resulting in more fields being available on types; basically, interfaces don't appear any different to consumers than regular types/fields.
is posible to use something like:
@dagger.task()
some async function
to make task like in Taskfile.yml on newest version?
is posible to use something like:
FYI: alternative proposal to contextual modules, after in-depth discussions with @rocky harbor and @thorn moat : https://github.com/dagger/dagger/issues/7432
(not completely fleshed out, but wanted to get the discussion going asap)
@rocky harbor it's basically your idea of explicitly configuring the context in dagger.json, but flipped: the context module designates its toolchain, instead of the other way around.
Also, no more .dagger in this one 🙂
hey all, if i have a tool inside the container WithExec but it returns a non 0 status code, i seem to be having issues exporting a file that is generated from the tool (its exit code = bad if something fails validation)
is there a pattern on returning or grabbing a file from a container with a bad exit code, which is expected behaviour in some ways
is there a pattern on returning or
Conversation starter. How does this script snippet feel?
#!/usr/bin/env dagger
# Build a base image
base() {
wolfi | with-packages git openssh go | container
}
# Build the app
build() {
base | with-directory /app $(
base |
with-directory /src "$(context directory)" |
with-workdir /src |
with-exec go build -o ./bin ./... |
directory ./bin
)
}
build
I am trying to pass a Github URL as a default arg for *Directory but it's not happy. Is there any way to get this to work?
this:
func (m *MyModule) Build(
ctx context.Context,
// Source code Directory
// +optional
// +default="https://github.com/golang/example#master:hello"
dir *Directory,
) string {
// build app
builder := dag.Container().
From("golang:latest").
WithDirectory("/src", dir).
WithWorkdir("/src").
WithEnvVariable("CGO_ENABLED", "0").
WithExec([]string{"go", "build", "-o", "myapp"})
results in:
levlaz@Levs-MacBook-Pro build % dagger call build
✘ initialize 0.1s
! query module objects: returned error 400 Bad Request: failed to get schema for mod
Error: query module objects: returned error 400 Bad Request: failed to get schema fo
r module "MyModule": failed to get field spec: failed to decode default value for ar
g "dir": decode "Directory" ID: failed to decode base64: illegal base64 data at inpu
t byte 5
@plucky ermine I don't think you can set objects as default values
Scalars only
The solution is to implement the default value in code:
if dir == nil {
dir = dag.Git("https://github.com/golang/example").Branch("master").Tree().Directory("hello")
}
This is good to know! My specific thing is for the cookbook and I think this might be a bit too advance for what I am trying to show, so ill just not have a default for now.
But, this is super helpful, will come in handy for me soon. Thank you!
Conversation starter - scripting snippet
So daggerverse only supports github.com urls for publishing but is it possible to host modules on your self hosted git instance and get them executed with dagger call?
Hey 😄
For now we only support GitHub url but we're actively working on it, you can follow our progress in the following issue https://github.com/dagger/dagger/issues/7218
GitHub
Problem Dagger modules and Daggerverse do not work with other SCM than GitHub. For the past few months, several discussions have occurred around the best way to solve it. This is now a top-priority...
awesome, thanks. Would be really nice to have that working.
Has there been any thought to using something other then git as a repo/registry for dagger modules? I know that is what go does, but it isn't awesome IMO. It makes things not very portable. You end up using something like Athens that ends up pulling down the equivalent of an artifact. And it also expects weird hacks from git providers (github, gitlab) to support discovery. Most other languages, even non-compiled ones, do this better. Even docker/helm has the concept of a registry that I can pull a distrinct bundle from.
Git only?
A lot of the cookbook seems to be using dagger in quite a different way. Any examples of "container status code failure, fail CI Platform Pipeline, but export results"?
Is there a way to tell dagger to ignore a flag when it's passed in but the value is the default null value? For example if I have a string arg in Go which is // +optional . I want it to still work work when I pass in the flag but empty value. The reason I ask is when I use dagger in a CI orchestrator I want to be able to do the bare minimum within the CI system. I don't want to conditionally modify the dagger call. just want to pass in a basic set of user inputs regardless of them being null or "".
Right now I get flag needs an argument: error.
Is there a way to tell dagger to ignore
Heads up on an upcoming breaking change in a small part of the API: handling of container entrypoints. https://github.com/dagger/dagger/pull/7136
Now is the time to share your thoughts
Has anyone seen dagger init --sdk=go fail with Error: load package "<foo/bar>": package name is empty ?
I wish we had gone the route of calling construtors ModuleName() rather than New()
It would give me more control on the name of my top-level type
For example in a Go module, I want my top-level type to be a project. But I'm stuck having to call it Go
So I have:
func New(version string, source *Directory) *Go {}
// A Go project
type Go struct {
// The project's Go version
Version string
// The project source code
Source *Directory
}
But would prefer:
func Go(version string, source *Directory) *Project {}
// A Go project
type Project struct {
// The project's Go version
Version string
// The project source code
Source *Directory
}
@thorn moat @chrome pilot I have a trick otel question 🙂
- I want my test function to expose test results as structured data, instead of a flat wall of logs + exit code
- Right now I need to parse a report file to achieve this
- But if my tooling already instrument tests with otel spans, and dagger magically gobbles those otel frames for visualization... Then perhaps I don't need to parse a report file?
- Is there any way the Dagger API could give my function access to the custom otel spans generated by the containers I'm running? 😇
you could subscribe to your own trace via the engine otel pub/sub grpc service, same way dagger watch works
I didn't even realize dagger watch existed 😄
Nice thanks
Do you think that could be made a super-easy pattern in the future? Just wondering if it could become the "standard" way of wrapping testing tools in a module
yeah it's been a hidden command since otel was introduced; its implementation was practically a freebie, so I snuck it in
hmmm maybe! right now the pub/sub is fire-and-forget, so you'd need to subscribe before running the suite, and then process the stream of spans, so it's a bit involved. We could perhaps add persistence and allow querying spans in the API, sort of like how Buildkit has a History API now. I'm not sure about super-easy though. You'd probably want to figure out how to identify the test spans in particular for example. Or maybe just look for all spans beneath the command's span, but then how do you identify the command's span. There's probably something there but it'd take a lot of noodling
yeah sounds interesting. I think buffering the spans and letting me query them would be killer. unlike buildkit it wouldn't need to be persisted at all. my function just needs its spans while it's running.
I don't know enough about otel format to know what to query the spans for, or how to figure out which span is which test. but seems like a solvable problem
it'd probably mean querying by the ScopeName field (aka instrumentation library, not sure what the most accurate terminology is), e.g. the Ruby RSpec instrumentation sets it to OpenTelemetry::Instrumentation::RSpec: https://github.com/open-telemetry/opentelemetry-ruby-contrib/blob/main/instrumentation/rspec/lib/opentelemetry/instrumentation/rspec/formatter.rb#L32 - and then it creates a span for each test ("example")
Hey guys, I'm exploring some alternatives and crazy ideas about how to effectively test my modules. I've thought in these two approaches — I'm planning to include them both actually, but I'd like to get your thoughts about them first:
- For each module, ship a
test(vanilla) Go module that's going to have Go tests using testcontainers. With this, testing the module from the CLI interface (it entails installing the Dagger CLI into the testcontainer container, and ensure the dagger engine works properly) will ensure that the dagger module as commands works as expected. - For each module, similarly to what @latent trellis suggested I'll create a test module where the module's APIs will be tested as code (
dag.MyModule().WithMyAPI()).
Also, is there any plan to include a built-in testing feature for quickly test modules/functions in future releases?
Re: point 1. You are better off testing the dagger CLI within dagger itself. Dagger supports nesting natively (dagger in dagger) so you won't have to worry about the logistics of gluing together 1) dagger cli 2) dagger runtime container 3) docker 4) testcontainers.
This is how we develop dagger with dagger
in other words your test module can handle both testing the code and CLI interface of your module
Hey @sharp zealot , about the first point, that'd be ideal, indeed. Do you have an example of a dagger in dagger approach that I can look?
Here is quick example of a go module that makes a dagger call in a container that has Dagger's CLI installed using Dagger's SDK. Given its dagger in dagger, it is using the dagger engine of the underlying host (my computer). The important parameter is within the last WithExec, dagger.ContainerWithExecOpts{ExperimentalPrivilegedNesting: true}. This will allow the underlying container to access the engine:
package main
import (
"context"
"fmt"
"log"
"dagger.io/dagger"
)
func main() {
c, err := dagger.Connect(context.Background())
if err != nil {
log.Fatal(err)
}
daggerVersion := "0.11.4"
out, err := c.Container().From("ubuntu:lunar").
WithExec([]string{"sh", "-c", "apt update && apt install -y curl"}).
WithExec([]string{"sh", "-c", fmt.Sprintf(`cd / && DAGGER_VERSION="%s" curl -L https://dl.dagger.io/dagger/install.sh | DAGGER_VERSION="%s" sh`, daggerVersion, daggerVersion)}).
WithEntrypoint([]string{"/bin/dagger"}).
WithExec([]string{"call", "-m", "github.com/shykes/daggerverse/hello", "hello"}, dagger.ContainerWithExecOpts{ExperimentalPrivilegedNesting: true}).
Stdout(context.Background())
fmt.Println(out, err)
}
I can't wait to test this https://github.com/dagger/dagger/pull/7272 when released. It looks great! Dagger pipeline console output within our CI orchestrator (Jenkins), left a lot to be desired as it was confusing and borderline incomprehensible. IMO the plain output experience is equally important as the terminal TUI output as I expect a huge portion of dagger workloads to run on CI orchestrators due to various reasons within enterprises.
That's precisely the use case, thanks a lot!
Ooohhh......
Yeah 🙂
Glad to hear it! Any/all feedback appreciated, I've already started working on some follow ups 🎉
question - could we potentially support the file/env prefixes for normal string arguments? i've gotten caught several times where i change an arg to not be a secret, and then the args that are passed to it work entirely differently
is the only way to "upgrade" dagger engine version of a module to manually edit the dagger.json right now?
it should automagically update when you run dagger develop with a new engine
but fyi right now, that number doesn't affect the behavior of any dagger command - yet
ah... then is the install script maybe installing 0.11.4 on my CI, let me retest
When testing the new plain progress, I was seeing a bunch of HTTP stuff. I only noticed later it pulled engine 0.11.4
aha, yes, so v0.11.5 of the engine is required to eliminate the repetitive http stuff
sadly can't just be done with a client side fix
funny enough, HTTP stuff is still showing in the TUI. Now the "plain" progress is cleaner than the TUI 😄
Ok now I'm definitely on 0.11.5, but I am still seeing the HTTP spans when doing a Publish. Did that get missed? CC: @deft rain
do you also have a matching v0.11.5 cli?
it's potentially possible publish might have been missed
Yes matching CLI, engine and SDK version
Everything else but Publish seems to be showing the new output
okay, do you have a screenshot?
sigh yeah that'll do it
I had to switch to dark mode to properly see them
do you mind if i open an issue with your screenshot?
Nope please go ahead. I only shared what I could 😄
Maybe one for @thorn moat also. Is it possible to output colors that work for both light/dark backgrounds? In light background it's hard to read
hm, so we only use the 16 color pallete configured by your terminal
that said, default configurations of a lot of these colors is excessively terrible - i remember when working on similar things in buildkit, it's hard to strike a balance
the good thing is that if you don't like the colors, you just to configure your terminal to get the results you want
oops i might actually just have an easy fix, gimme a moment
thanks for the quick report
Nice! Thanks for the quick fix!
Re: colors. The above output is from Jenkins console log. I don't know/think there's an option to configure the terminal. Even if there is, that's only available to the platform owners.
honestly there's not a lot that can be done in the CLI for this - like @deft rain said, we're already restricted to a 16 color palette, it's the outer software's responsibility (terminal emulator, Jenkins) to ensure those colors are all readable. unfortunately, many of them suck at that. 😦 for example the default 'blue' color is unreadable on dark backgrounds on macOS defaults, so I've already learned to stop using it, but there's only so much you can do... (not being able to use blue is already a crazy thing to me)
buildkit's tty output uses that blue color, and it's fairly sad, yup 😦
If I want to install Dagger from main, and use that as my every day install, is there a set of reproduceable dagger calls you can give me?
Is this enough? Or do I need to set additional env variables to make sure the right engine container is downloaded:
# Mac-specific
dagger call -m github.com/dagger/dagger --source https://github.com/dagger/dagger \
cli \
file --platform darwin/arm64 \
-o ~/bin/
In this case, would it make more sense to remove colors from "plain" output altogether? Would plaintext (black for light and white for black) be easier to read than a "pretty" output that's hard to read? IF that's even possible.
this is only going to grab the cli - you sadly also need to do the right enginey things as well.
ideally. we should have our install.sh script install from an arbitrary main commit i think
and then have a dagger function that can wrap that / vice versa
setting NO_COLOR=1 should work - I don't think it should be the default, though, since plenty of systems have properly configured color
