#daggernauts
1 messages · Page 1 of 1 (latest)

ongoing PR: https://github.com/dagger/dagger/pull/5308
Python implementation draft: https://github.com/dagger/dagger/pull/5300
Discussion of standardizing project entrypoint: https://github.com/dagger/dagger/issues/4414
Hello! Here are some high level thoughts around problems I’ve been facing recently around pipelines that perhaps dagger do plus the API itself can help solve. It might be interesting to look at each one of these and designate whether they should be handled by SDK libraries or in the API/CLI/engine itself, or left up to the end user to implement themselves
Pipeline orchestration
- How to execute pipelines concurrently vs in sequence
- How to arbitrarily nest pipelines
- How to safely share data asynchronously across pipelines
- How to pass one pipeline/step result to the next when it’s one pipeline
- How to collect multiple pipelines/steps results that ran concurrently and pass them into a new pipeline or list of pipelines
- How to inject configuration across pipelines/commands
Project Entrypoints - How to discover commands within a project and across projects
- How to scope what a project is
- How to define commands and groups
- How to nest commands and groups
- How to make the things that commands do composable and have dependencies
- Simple Example: I want to have one command: ci. I want it to run build, test, and publish pipelines. These should each be their own separate commands as well though. Publish should depend on test which should depend on build in sequence. - How to marry the concept of commands, groups, and pipelines
- How to query for what commands and groups are available along with all of their metadata (arguments, descriptions, etc)
- How to run my own hooks and validations on top of whatever dagger implements whenever I run dagger do
@honest hearth do you have the need for multiple projects in the same monorepo?
for the “pipeline orchestration” part: our assumption is that we can keep that a separate topic, to prevent scope creep in Zenith (already a lot going on between CLI, entrypoints and possibly extensions). But I know you weren’t 100% sure how realistic that decoupling is, so we can double-check together.
The ideal outcome for me is that we address your pipeline orchestration issues (which I happen to share 🙂 with a combination of 1) incremental improvements to the core Dagger API, and possibly 2) opinionated extensions
My educated guess / wishful thinking for your project-related questions:
How to discover commands within a project and across projects
100% of project-related operations, including discovering and invoking commands, should be available via the Dagger API. Ideally via a simple client implementation.
How to scope what a project is
To keep things simple, a project maps to a directory with dagger.json. There are still open questions on the details of that mapping though 😁 including:
- dagger.json optional?
- relationship to parent and child directories with their own dagger.json ?
conor 8783 do you have the need for
👋 I’m interested to see how this plays out ^^
Really nice summary from conor 8783 For
config management is a good topic for DX improvements. having something built-in would be pretty nice. without a solid configuration system to work with, i found that my dagger code quickly turned to spaghetti. ended up trying a bunch of different things, and settled on this implementation https://github.com/rancher/opni/blob/dagger/dagger/config (usage doc is in dagger/main.go) which works extremely well for my use cases. I hope this gives you some inspiration 😄
config management is a good topic for DX
👋 @kind carbon @upbeat herald
RE: Project Entrypoints
What Solomon said earlier about this all being 100% in scope for us to support, plus you can also see the (extremely primitive, subject to change, experimental, etc.) API here, which is part of the core API and thus available in each client SDK: https://github.com/dagger/dagger/blob/736a68be4640078cb2e67aca4da547d1b0e1e4ba/core/schema/project.graphqls#L26-L58
Lots missing still, but the biggest one is support for actually invoking a command in a project, which still requires submitting a raw graphql query. We plan on adding that too though, at which time you will be able to load projects, see all the commands provided by them (including doc strings, input arg names+types, output types, etc.), and invoke any of those commands all just with a dagger client.
WIP user-facing docs for project commands here: https://github.com/dagger/dagger/pull/5357
Still some work left but have questions in the PR description for reviewers in the meantime too 🙏
Doing a bit of dogfooding in Progrock: https://github.com/vito/progrock/blob/main/ci/ci.go (excuse the "Biome" pun)
Along the way, ported Bass's automagic Nix image builder to Dagger: https://github.com/vito/progrock/blob/main/ci/nix.go
Usage:
dagger do -p ci generate=> rungo generate ./...and copy the results back to the hostdagger do -p ci test=> run tests
Collecting feedback along the way, so I guess I'll make this a 🧵
Trying out a "focus mode" TUI for dagger do: https://github.com/dagger/dagger/issues/5156#issuecomment-1603619303
@rocky harbor @sharp zealot Just added support for importing OCI layout directories instead of tarballs. It's WAY faster! This should make it totally viable to use Nix (or any other tool) to build images.
- Using OCI tarballs (
Container.Import): https://asciinema.org/a/k0YwdT2c18guGoFcMo6hgH2kj (note the slowimport(...)call even on the second cached run) - Using OCI layout dirs (
Container.ImportDir- maybe it should beFromOCILayout?): https://asciinema.org/a/oKZhIhZLz2f0mh0078EK17kzq
Another nice thing is it doesn't need the client-side content.Store; it's all remote, and it only transfers blobs that haven't been imported into Buildkit already.
Will have a PR up soon, this is currently implemented on top of the "focus" changes for maximal dogfooding but it's totally independent
PR is up for ☝️ https://github.com/dagger/dagger/pull/5363 - still a draft; needs tests
oh is that the call we discussed way back at api design time, but agreed would have to wait because of implementation difficulty?
or maybe I’m confusing with container.export
Yeah sort of - we talked about trying to get around the client-side content.Store in https://github.com/dagger/dagger/pull/4876#discussion_r1159116223. I don't remember when/where we talked about switching to a layout directory instead, but it has come up
Related to our discussion today @sharp zealot @rocky harbor @thorn moat - from #1122992818407878777 message
@young lintel this project is where the discussions around extensions will happen. We're keen to support your ideal use case 🙂
do we have any design docs or discussion around extensions? In #github we would need different components/extensions for certain tasks / behaviours. Maybe we can leverage extensions inside of the gale as well.
Not yet, but we are actively working on it. There is a live hacking session going on this week 🙂
more soon
@ember walrus @thorn moat @rocky harbor I propose switching to this open channel for this second phase of our little hack week
it may not all make sense out of context, but it may prompt conversations
Sounds good! Let's do it
@hexed flume I find out the problem with integration tests for Typescript entrypoint!
The Dagger TS library needs to be built in order to be used, but since we're not pushing build artifact, the only case where we cannot access to built library is in our own CI...
In others this would work since they use the release package, in local we can built our library to test it but in the CI we do not.
A fix would be to add an extra step in case of Typescript test so it build the library with new changes before we test it.
What do you think?
/cc @rocky harbor @strong ingot
@rocky harbor @thorn moat - would this issue "go away" with environments? https://discord.com/channels/707636530424053791/1123261502208626688
Yeah building it before running the tests seems like the right approach. We can just make this same sort of call: https://github.com/sipsma/dagger/blob/0c8da0a136047f58930ba69d0b5779cfcffb93b7/internal/mage/sdk/nodejs.go#L141-L141 but in the container we run the tests in here: https://github.com/sipsma/dagger/blob/0c8da0a136047f58930ba69d0b5779cfcffb93b7/internal/mage/engine.go#L242-L242
@wintry prism This is very exciting!
From Wikipedia:
In software deployment, an environment or tier is a computer system or set of systems in which a computer program or software component is deployed and executed. In simple cases, such as developing and immediately executing a program on the same machine, there may be a single environment, but in industrial use, the development environment (where changes are originally made) and production environment (what end users use) are separated, often with several stages in between. This structured release management process allows phased deployment (rollout), testing, and rollback in case of problems.
Environments may vary significantly in size: the development environment is typically an individual developer's workstation, while the production environment may be a network of many geographically distributed machines in data centers, or virtual machines in cloud computing. Code, data, and configuration may be deployed in parallel, and need not connect to the corresponding tier—for example, pre-production code might connect to a production database.
@ember walrus @thorn moat 👆
Oh also, I saw you mention somewhere that you were gonna jump right into command hierarchies, I would actually hold off on that for now. I think we may be changing some aspects of how those work, so it would be safer to just wait for things to settle
Dev environment:
The development environment (dev) is the environment in which changes to software are developed, most simply an individual developer's workstation. This differs from the ultimate target environment in various ways – the target may not be a desktop computer (it may be a smartphone, embedded system, headless machine in a data center, etc.), and even if otherwise similar, the developer's environment will include development tools like a compiler, integrated development environment, different or additional versions of libraries and support software, etc., which are not present in a user's environment.
Testing environment:
The purpose of the test environment is to allow human testers to exercise new and changed code via either automated checks or non-automated techniques. After the developer accepts the new code and configurations through unit testing in the development environment, the items are moved to one or more test environments.[3] Upon test failure, the test environment can remove the faulty code from the test platforms, contact the responsible developer, and provide detailed test and result logs. If all tests pass, the test environment or a continuous integration framework controlling the tests can automatically promote the code to the next deployment environment.
Staging:
A stage, staging or pre-production environment is an environment for testing that exactly resembles a production environment.[7] It seeks to mirror an actual production environment as closely as possible and may connect to other production services and data, such as databases. For example, servers will be run on remote machines, rather than locally (as on a developer's workstation during dev, or on a single test machine during the test), which tests the effects of networking on the system.
Production:
The production environment is also known as live, particularly for servers, as it is the environment that users directly interact with.
This is just a refresher on the baseline, mainstream understanding of the word. It may not be perfectly accurate - but it's roughly what a beginner will know about the word after some basic googling.
Notably absent is "preview environment" which is like a hipster, cloud-native take on "staging"
That's perfect description for preview environment
Think I found an approach to move to the new "environment builder" model that has the same niceties of the previous hierarchy approach in terms of global configuration that is also lower boilerplate (deletes more lines than adds): https://github.com/sipsma/dagger/commit/695e3807998e8f0864fc35af46b60951d0f2450b
Gonna try splitting out at least one of the SDKs to get a feel for how we can have one environment use/consume/depend-on/whatever another environment.
Then I'll see what I can get actually implemented, cheating as necessary, and start hooking up with the stuff you've been doing @thorn moat to try out a real working universe 🙂 cc @ember walrus @sharp zealot
That' aligns to my existing world view of environment - and I don't think it matches 1:1 with what we're hacking out today for .
For instance, let's take a webapp.
- The frontend team wants its own contained sphere for its setup, services, etc that they can cultivate.
- The backend team wants the same.
Each team needs to be able to run, build, test these separately. And they also want to do that for the full webapp (backend and frontend).
We could look at frontend and backend being their own environments that get composed into the webapp environment.
I'm having difficulty reconciling the different uses of the word environment - in one case, it's basically a stage from development to production. In another, it's a definition of all of the pieces and logic that you need to ensure that your app works since all of those dependencies are built and tested the way that they need to be.
Hey,
I have been encountering some issues with managing individual components for the #github recently.I am considering the possibility of utilizing #daggernauts to develop a catalog or extension system that can effectively organize, manage, and maintain individual services and binaries.
if I need to extend this use-case:
The primary issue here, To ensure efficient execution of the 'gale', it is necessary to integrate various customized binaries and services. This strategy has revealed the need for additional specialized components in the future.
Ultimately, all these components can be categorized as File, Directory, or Container, each with its own designated entry point.
Couple of examples of extensions
- Artifact/Cache Service
- Workflow state for communication between multiple dagger.containers
- Github Action Executor for executing steps/jobs
What I need here mostly:
- Loading extension from a source(local , git or registry)
- Configure the extension
- Integrate it to my existing container (like copy file to container or bind extension as service to given container etc)
This kind of integration would make huge difference for #github
cc: @rocky harbor , @sharp zealot
This was a pretty cool experience. I wanted to hack on devbox, and devbox (in true geeky style) is developed with devbox. So I cloned the repo, changed the one line of code I cared about, ran devbox run build. And it built a binary. That was some pleasant magic.
Coincidentally I just moved the Dagger CI dogfooding I've been working on from ci/ to universe/dagger, in anticipation of just making it an environment 🙂 so dagger do -e dagger cli --output ./bin or something
with git remote mapping, you could me that -e dagger implicit, so:
dagger do cli —output ./bin
We did a first pass of design discussion on an environment schema for Zenith. This would be additive to the current Dagger API schema.
extend type Query {
"The current environment"
here: Environment!
"Load a new environment"
environment(
"Source code of the environment"
source: Directory!,
"Working directory of the environment"
workdir: Directory!): Environment!
}
"API for your Dagger environment"
type Environment {
"Command-line tools available in the environment"
tools: [Tool!]
"Lookup a command-line tool by name"
tool(name: String!): Tool!
"Artifacts available in the environment"
artifacts: [Artifact!]
"Lookup an artifact by name"
artifact(name: String!): Artifact!
"Tests available in the environment"
tests: [Test!]
"Lookup a test by name"
test(name: String!): Test!
"Services available in the environment"
services: [Service!]
"Lookup a service by name"
service(name: String!): Service!
"Interactive shells available in the environment"
shells: [Shell!]
"Lookup a shell by name"
shell(name: String!): Shell!
"The working directory for this environment"
workdir: Directory!
"Direct access to the environment as a data graph. Great for scripting and composition"
graph: EnvironmentGraph!
"""
Extend this environment with the capabilities of other environments.
If no namespace is provided, environments are merged - this may cause naming conflicts.
"""
withExtension(namespace: String!, environment: Environment!): Environment!
"Extensions currently added to the environment"
extensions: [String!]!
"Lookup an extension by its namespace"
extension(namespace: String!) Environment!
"Warm up the environment cache by pre-executing as much of the DAG as possible. This may make subsequent operations considerably faster"
warmup(timeout: Number)
}
type EnvironmentGraph {
# This type will be extended by an environment-specific graphql schema
}
type Tool {
name: String!
description: String
commands: [ToolCommand!]!
}
type ToolCommand {
name: String!
description: String
subcommands: [ToolCommand!]
# invocation?
}
type Artifact {
name: String!
description: String
labels: [String!]
contents: Directory!
}
type Test {
name: String!
description: String
result: TestResult!
}
type TestResult {
success: Boolean!
output: String!
}
type Shell {
name: String!
description: String
terminal: Stream
}
// A bi-directional byte stream (eg. for terminal emulation)
type Stream {
// Path to the websocket stream, relative to the current HTTP server
wsPath: String!
}
courtesy of:
https://github.com/opencontainers/artifacts/blob/main/artifact-authors.md#defining-a-unique-artifact-type some more artifact fields
extend type Query {
"The current environment"
here: Environment!
"Load a new environment"
environment(
"Source code of the environment"
source: Directory!,
"Working directory of the environment"
workdir: Directory!): Environment!
}
"API for your Dagger environment"
type Environment {
"Command-line tools available in the environment"
tools: [Tool!]
"Lookup a command-line tool by name"
tool(name: String!): Tool!
"Artifacts available in the environment"
artifacts(filters: [String!]): [Artifact!]
"""
Checks available in the environment
This could be unit tests, integration tests, linting, etc.
"""
checks: [Checks!]
"Lookup a check by name"
check(name: String!): Check!
"Services available in the environment"
services: [Service!]
"Lookup a service by name"
service(name: String!): Service!
"Interactive shells available in the environment"
shells: [Shell!]
"Lookup a shell by name"
shell(name: String!): Shell!
"The working directory for this environment"
workdir: Directory!
"Direct access to the environment as a data graph. Great for scripting and composition"
graph: EnvironmentGraph!
"""
Extend this environment with the capabilities of other environments.
If no namespace is provided, environments are merged - this may cause naming conflicts.
"""
withExtension(namespace: String, environment: Environment!): Environment!
"Extensions currently added to the environment"
extensions: [String!]!
"Lookup an extension by its namespace"
extension(namespace: String!) Environment!
"Warm up the environment cache by pre-executing as much of the DAG as possible. This may make subsequent operations considerably faster"
warmup: Environment!
}
type EnvironmentGraph {
# This type will be extended by an environment-specific graphql schema
}
type Tool {
name: String!
description: String
commands: [ToolCommand!]!
}
type ToolCommand {
name: String!
description: String
subcommands: [ToolCommand!]
# invocation?
}
type Artifact {
name: String!
description: String
version: String
labels: [String!]
contents: ArtifactData!
sbom: String!
}
union ArtifactData {
Directory
File
Container
}
type Checks {
name: String!
description: String
result: CheckResult!
subchecks: [Check!]
}
type CheckResult {
success: Boolean!
output: String!
}
type Shell {
name: String!
description: String
terminal: Stream
}
// A bi-directional byte stream (eg. for terminal emulation)
type Stream {
// Path to the websocket stream, relative to the current HTTP server
wsPath: String!
}
@thorn moat https://edu.chainguard.dev/chainguard/chainguard-images/reference/ I think those are all based on wolfi-base
could be wrong
I want to point out one important aspect of the Zenith design: you use Dagger/zenith to develop environments, and environments have their own source code repository.
This is different from the current best practice, where environment code is embedded into the repository that will be used as its working directory. From the point of view of the environment's programmer, this mixes data and code. In the Zenith design, the environment's code will be cleanly separate from its data.
@thorn moat https://github.com/sipsma/dagger/tree/zenith
Rough draft of how we might explain Dagger post-Zenith:
# Dagger
Standardized environments for modern software teams.
## What is Dagger?
Dagger defines a new standard for packaging, distributing and running any software environment as a DAG. Once "daggerized", environments have the following properties:
* Runs anywhere
* Shareable
* Repeatable
* Cached by default
* Scriptable
## Why Dagger?
Using Dagger can solve or mitigate the following problems:
- New developers take too long to be productive
- Tests pass in development but not in CI
- CI environment lags behind development
- End-to-end testing requires artisanal scripts to glue incompatible environments together
- Platform teams struggle to integrate MLops environments into the continuous delivery pipeline
- Major stack changes cause disruption or delays, because environments are hard to change and test reliably
- CI/CD pipelines gets slower as the stack and team grow
good short blog on the 4 different meanings of "container": https://brooker.co.za/blog/2023/06/19/container.html
Zenith README, take 2 🙂
# Dagger: standardize your dev environments
## What is Dagger?
Dagger defines a new standard for packaging, distributing and running development environments as a containerized DAG. Once "daggerized", environments have the following properties:
- **Portable**: any machine that can run standard containers can run a DAG.
- **Familiar**: keep using the tools you know, packaged in containers.
- **Scriptable**: automate custom tasks in any language, using a powerful API and growing list of SDKs
- **Extensible**: easily incorporate the capabilities of other environments into your own
- **Scalable**: all operations in the DAG are scheduled concurrently, which allows seamless parallelization across cores and if needed, across machines in a cluster (*coming soon*)
- **Fast**: all operations in the DAG are continuously cached, making all computation magically incremental. As a result, daggerizing an environment typically makes builds and other cpu-intensive tasks much faster out of the box.
## What is a containerized DAG?
A containerized DAG is a computing environment which can run programs made of many concurrent containers, each running a simple operation, with data flowing between the containers in a graph layout.
## Why Dagger?
Daggerizing your team's environments can solve or mitigate the following problems:
- New developers take too long to be productive
- Tests pass in development but not in CI
- CI environment lags behind development
- End-to-end testing requires artisanal scripts to glue incompatible environments together
- Platform teams struggle to integrate MLops environments into the continuous delivery pipeline
- Major stack changes cause disruption or delays, because environments are hard to change and test reliably
- CI/CD pipelines gets slower as the stack and team grow
## Why not just use a container?
There is an emerging trend of running development environments in a container (see Devbox, Devpod, Gitpod, Nix, Replit). This is a considerable improvement from the previous status quo. But it's not enough, because most environments are too complex and dynamic to fit in one container. Docker-compose is slightly better, because it can package a multi-container application; but in spite of its name, Docker-compose is neither composable nor scriptable.
## What kind of environments?
In theory, any software environment can be daggerized, as long as its individual components can run in a container. In practice, Dagger is most commonly used for non-production environments, such as:
* Development
* Build
* Test, especiall end-to-end integration testing
* CI/CD
* QA and staging, also known as "preview environments"
* MLOps
* Data engineering
* Research
Although Daggerized environments often integrate into production - for example by building production artifacts, or deploying to a remote production environment - the production environment itself rarely runs in Dagger.
I like this revision a lot. I have a few suggestions but will sleep on it and post tomorrow
Draft PR with README and GraphQL schema: https://github.com/dagger/dagger/pull/5378
Let's move discussions of those two documents to the PR please
First draft of Zenith README and GraphQL...
Will Zenith still work without dagger CLI? Would someone for example be able to go run main.go ? Today, we've built a CLI/SDK wrapping the Go dagger SDK that can work with or without the dagger CLI. I wonder what the experience will be like for something like that when Zenith comes into the picture. I am hoping the interface will be much simplified but also hoping we don't have to make developers rely on the dagger CLI if they don't want to.
We will still support it. But increasingly using the CLI will be the main way to use dagger. Note that you can use the CLI as an API gateway, and then just talk to the API with your tool of choice
In practice I believe we will have a good way to continue supporting embedding dagger in custom tooling. We will need to work out some details but we don’t anticipate any dealbreakers
Quick update @restive shore after discussing this live. Our educated guess is that SDKs will continue to work exactly as today for your use case. The only difference might be that SDKs would no longer-autoinstall the CLI. So your tool would have a new runtime dependency: the dagger CLI. So your end users would need dagger installed - even if they never interact with it directly.
Hmm, do you mean the sdk won't download the engine automatically? Because the SDK doesn't pull the dagger CLI today either afaik.
It currently does because it needs the CLI as a helper to run pipelines. It will skip the automatic download if you set an _EXPERIMENTAL_DAGGER_CLI_BIN env var to a pre-downloaded CLI: https://github.com/dagger/dagger/blob/main/core/docs/d7yxc-operator_manual.md#dsi-advanced---automatic-provisioning
We just want to move away from all the hacky _EXPERIMENTAL_* stuff, part of that will likely include not doing the automatic download anymore, which was always meant to just be a temporary convenience hack before we made it easy to install a CLI anywhere
Oh? TIL.. I was under the impression that the SDK only downloaded the dagger engine image. Is the CLI embedded in the engine image? I assume what the SDK downloads is temporary. It's not the same as installing the CLI via something like homebrew right?
If that's the case, the SDK can technically do all the TUI stuff too?
Yeah the automatic download stashes it in $XDG_CACHE_HOME/dagger/dagger-<cli version> ($XDG_CACHE_HOME is by default ~/.cache), and it cleans up old versions after an upgrade, but it's a totally different place than the hombrew install
I think that would be plausible to get working, but isn't possible yet due to the fact that in this automatic mode the CLI is a subprocess of the SDK and it uses up the stdout/stderr of the CLI for other purposes, which interferes with the TUI
I see! It would be nice to be de-coupled from the CLI or have the dagger SDK provide a way to define how to pull all the required tooling for it to work, but I understand if that's not the direction you decide to go. I am happy that the SDK is still going to work pretty much the same way as today. We are building a library of sorts of capabilities for developers. A thin wrapper over the dagger SDK and the idea is to distribute that as a CLI that developers can just use OOTB to perform CI/CD for their applications. Mostly adhering to our company conventions and standards. More adventurous devs/teams can extend this SDK to compose their own patterns. At least that's the plan. I expect zenith to vastly improve tool/library developer experience as well as enable new and better interfaces for the consumers of our tool. Very excited for that but it's important to me that it doesn't require us to entirely throw away what we'd be building from now till when Zenith is GA.
Totally, we have a few other user's with usecases very similar to exactly what you're describing and the direction we are heading will support it too!
The quick explanation is that while dagger do is special in that it's the "official" dagger cli and comes with our built-in TUIs, the implementation is actually just using core APIs available in any SDK to load environments and invoke entrypoints from them. So if someone wanted to build their own CLIs on top, their own web interface, their own code libraries, etc. that is still 100% supported and easier than ever actually since you'll have the Zenith APIs to help you out with low-level details rather than needing to reinvent everything from scratch necessarily.
@thorn moat Continued working yesterday fixing up the implementation in my zenith branch to get it ready for integrating with your environments, but I keep hitting problems related to the whole issue of sessions being separate. Most recent set was due to the fact that when you stitch the APIs, you don't stitch it in the other session, which I had a workaround for but then that workaround had its own issues and I was starting to workaround my workaround, etc.
Long story short, I'm gonna spend today seeing if I can get an MVP of the session frontend idea working, even if I just temporarily comment out a few of the trickier parts where some of the APIs have hardcoded assumptions about reading/writing local dirs. That seems more productive than fighting the current approach, especially since it will also simplify SDKs even further. I'll make a call EOD if it's the most time efficient path forward. Just FYI, cc @sharp zealot
Best of luck! I agree that seems like the best path to try at this point 👍
Here's what a "provider" for devpod looks like: https://github.com/dirien/devpod-provider-equinix
As requested last week, I added our mockup example (progrock-env) to the PR: https://github.com/dagger/dagger/pull/5378
When you set up the chain after NewEnvironment() like that, from what you've discussed so far, does it appear that the order of the elements in that chain will matter?
That's a good question, I don't think it should at least right now. The only thing would be if there were namespace conflicts, but I think we should return an error in that case rather than have "override" behavior.
(copying from my linear update) Have session frontends passing basic tests now: https://github.com/sipsma/dagger/tree/session-frontend
e.g. you can pull that and run ./hack/dev go test -v -count=1 -run=TestDirectoryWithDirectory ./core/integration/
Will panic if you try to use any session attachables (secrets, sockets, etc.) or do an export as I haven't updated those implementations yet.
Going to get the MVP needed for environments working now, which is really just host import/export. Import shouldn't be hard, may actually work already. And I think there's a potentially easy route to support exports by just directly calling the worker exporter method.
If that goes as planned I'll start rebasing my zenith branch on that one and have smoother sailing going forward
Nice demos @rocky harbor @thorn moat 🙂
Thanks, they are only going to get better and better too! 🙂
@rocky harbor When you have a few second: https://github.com/dagger/dagger/pull/5305#issuecomment-1624087770 🙂
I might take a break on the typescript entrypoint regarding all these changes that will happens with Zenith
But at least we could merge what has been done so far so people can already try entrypoints
Thinking about next week's demo. It would be nice to highlight the future experience a bit more, in the current demos it's overshadowed by the current implementation. This makes it great for our current audience of power users looking for the next incremental improvement (project commands basically). But it won't show the potential of Zenith to make Dagger more approachable to a new audience (devs).
I know it's easier said than done, because the future experience is, well, mostly in the future. But if we could somehow "fake it" even partially, it would be really worth it.
IMO between now and next thursday, it would be a worthwhile investment to scaffold a fake (or partially fake) implementation of other entrypoints, and the CLI experience for them - by the way that was an unfinished topic we wanted to discuss @thorn moat
Makes sense. I can start mocking up a full set of commands and start scaffolding it. I also left one comment earlier about a potential dagger use: https://github.com/dagger/dagger/pull/5378/files#r1254780635
I can start a PR that just adds a markdown file or something and we can do linewise comments?
Also we should try to introduce the standalone environment aspect of the design - even faked or partially faked - to start conversation on that part, since it's so important
works for me, whatever you think can get the ball rolling
breaking for dinner, but here's a start: https://github.com/dagger/dagger/pull/5420/files#diff-7340b8a6d2c5b52c935f75ec72038d28b8c606323ea41bd29ced4b521eae7761
At this point I have no clue why I haven't assembled a "tools" docker image for debugging crap. I always just run alpine/ubuntu and apt/apk crap. Just think of the hours lost.
Reviving the dependency pinning topic: currently reading https://www.chainguard.dev/unchained/reproducing-chainguards-reproducible-image-builds (cc @rocky harbor out of probable interest, it's a new post). Basically want a way to ensure Wolfi([]string{"go"}) always fetches the same packages until I run something like dagger bump, maybe with a way to specify what to bump. (That's how this connects back to CLI mockups. 😁)
Dogfooding opportunity: I'm trying to make a small-to-medium contribution to the Dagger docs, and could really use a turnkey environment that guides me 🙂
Just to update on my progress here, ran into weird errors and flakiness while trying to rebase zenith, turns out I needed to implement a big chunk of work that I thought I could cheat on: https://github.com/dagger/dagger/pull/5415#issuecomment-1626392187. Got it working now though: https://github.com/dagger/dagger/pull/5415#issuecomment-1629571175
So now I'm gonna get zenith rebased on that new and improved branch as quickly as possible to unblock everyone else. Sorry about the delay! Besides just making it possible to implement zenith, the new architecture is gonna enable so many other neat things, so the wait should be worth it hopefully
Thanks for the update! Quick update on my end:
-
Having fun bikeshedding mock UI with @thorn moat here: https://github.com/dagger/dagger/pull/5420.
-
Long story, but we may want to "backport" a minimal concept of environment into current Dagger, as a basic namespacing construct to unblock Dagger Cloud. See https://github.com/dagger/dagger/issues/3345
-
I am concerned that by this thursday (first community demo) we will have lots of powerful plumbing to show, but not a lot of context for why it's awesome or how it changes the overall UX. @thorn moat I'm wondering if maybe we need 2 mockup tracks: one where we focus on depth (seek out hard design topics to bikeshed), and another focused on width (give the illusion of maximum functionality with minimum underlying design or implementation work)?
--> 5420 is our depth-first track 🙂
--> perhaps another track where we show off more detail on artifacts & checks, and do some "fake dogfooding" on top of that?
GitHub is where people build software. More than 100 million people use GitHub to discover, fork, and contribute to over 330 million projects.
I think point 3 is really about making the demo more "robin hood friendly".
For example as I mentioned in this thread: #1126976209591472158 . Today I have used Dagger to contribute docs to the dagger repo. At the moment my experience is worse than if we just had a Makefile or npm script. The main difference is that I get more noise in the output (something about containers?). But if I could somehow:
- Type one command to see all checks
- See a bunch of red: failed checks! With the reason why
- fix my code, repeat...
That would be a much better experience.
I would love to convey a little bit of that feeling to the audience on thursday
Still in the same use case: my docs contribution includes a code snippet in several languages. I am getting linter errors on those snippets. One of them is "code is not formatted with gofmt" but perhaps I'm not a go developer and am not sure how to godfmt correctly - it would be nice to have a tool to do that for me.
It's hard for me to imagine a breadth-first track not immediately turning depth-first as soon as we start making comments. 😁 5420 was meant to be breadth-first and even robin-hood focused, but one thing leads to another...
From my POV we're at an "innovation thrives in mess" phase in the CLI design where we just need to hash out anything we can and try to let one answer lead to another. Anything is on the table. I'm hesitant to demo a totally made-up list of commands without having some idea of the underlying mental model, because I'd guess everyone watching would be the critical engineer type that would be running their brain at 120% capacity trying to draw connections that might not actually exist.
But by all means, I could use some help covering any gaps I missed along the way, since there are almost certainly parts of the DX you've given more thought than me. Is there an outlet you feel is missing for throwing more CLI ideas out there? Or did you have something concrete in mind for representing these parallel tracks?
Also all of this is based on the assumption that the actual task to create the faked-out CLI won't take very long once we know what to fake out.
yeah I'm with you, I don't have a specific outlet in mind. Just wanted to point out that on the current trajectory, our demo will be plumbing-heavy.
oh yeah totally. I'll pop the stack and move on to higher level things 👍
@sharp zealot Going to try adding real commands into the dagger CLI, but hardcoded against a certain environment (so e.g. dagger test will just always run Progrock's test entrypoint). Should be easy enough to iterate with code at this point and just add as many aliases as we want, and the upside is we'll have a functioning demo at the end where we can actually change code and re-run tests.
nice
Docker Compose getting a little more composable: https://twitter.com/glours/status/1678777310068244482
Hey 👋
We just release @Docker Compose v2.20.0
This version introduce include keyword which allow you to use an existing Compose configuration as part of your Compose stack
https://t.co/xIyLrtPFOu
@sharp zealot if you want to kick the tires, this branch has the functional CLI: https://github.com/vito/dagger/commits/vito-zenith
Usage:
$ go install ./cmd/dagger
$ cd progrock
$ dagger checks # or dagger tests
$ dagger check # runs first defined check, TODO should run all in parallel
$ dagger artifacts
$ dagger export demo # or dagger build
Some of these commands probably work in other Go repos too, feel free to try. 😛
oh, you'll need a ./hack/dev in there somewhere actually
Nice! Thanks for cranking this out so quickly
I still feel like we won't need a top-level verb for "build" or equivalent. Argument: in modern software projects there is rarely only one thing to build, or only one way to build it; so devs are ready for a noun-oriented approach. Instead of "build the thing!", I say the world is ready for "show me the artifacts!"
We definitely don't need it, but a little sugar in the CLI can go a long way imo. If you go too far towards the theoretical/abstract truth of it all, you get further away from meeting most users where they are, and start designing for things they don't need. Most of my projects have one important thing I want to build and test, and I don't want to have to type too much for commands I run all day. But part of this exercise is to see how that actually feels, so I'll be playing with all the variants anyway.
Yeah I agree with that - my guess is the ergonomic polish will keep moving quite a bit, while we figure out the foundations.
Which is why I'm so happy you're shipping something real so fast, gives us more opportunity to try things
totally - feel free to toss more command ideas my way btw, it's a good time to just try things on. I can start adding noun-verb hierarchies like artifact get too
One related itch I can't help scratching: in theory, a noun-oriented interface makes it way easier to create a super simple web UI. For example a list of red/green checks... I have a feeling that we could make that a prominent feature, possibly a game changer for robin hood hats, with relatively little effort... but I'm not sure exactly how
I think part of the blockage is that, as soon as we talk about "API", we think "codegen, SDKs in every language, top hat".
But maybe there's a simpler version of the API, that is specifically for developing web UIs for your Dagger environment, which means no codegen, and only JS support?
I mean, if we're talking about "wow effect" in a demo...
Most of that could be accomplished by using the GraphQL API directly right?
Yes I believe so. But would need to try to be sure. Maybe we'll find there are easy ways to make the API more accessible in this use case? But could be a no-op
Yeah hopefully it's a no-op API wise just to minimize surface area. There are other devils in the details too. Showing red/green check status for example implies that they have run at some point, and that we're able to "cache" failed results. I don't think we would want the page that shows all the tests to require running them all, so it'd be nice if there was a way to show a green check but only if there's a cache hit. I've wanted something like that from Buildkit before
I'm thinking something like dagger checks => shows each check status, which is pending if their cache busted, or successful if they've passed and will just be a cache hit if you run again. Then you run them all with dagger check and they should all have an up-to-date state, until you change code again.
The web UI could reflect this constraint (that some queries are expensive), and deal with that in the UI. For example, list all the checks, but require that the user click a button before querying the result (unless they're cached, which would require the ability to check for cache status in the API)
yup!
But maybe a first version could just go ahead and make the queries - firing off a flurry of pipelines in the background. Might not be so bad
(ie. we may not have to wait for a new API to query cache state to explore cool web UIs, either built by us or by the community)
pushed a few noun-verb aliases: check list, check run, artifact list, artifact get
"check" seemed a little iffy because it's both a noun and a verb, but it works in practice. dagger check still runs the first check, dagger check test still runs the test check, and sub-commands work fine; I guess they take precedence
small UX note: it'd be really nice if exporting artifacts listed the files that it wrote. especially because that sometimes means "overlaying" onto your working directory, updating a bunch of files across the tree (e.g. go generate ./...)
Got my zenith branch rebased on the re-architecture PR w/ enough basics working for a draft PR, TODOs listed there: https://github.com/dagger/dagger/pull/5443
Gonna go look at what you're working on @thorn moat and see how plausible it could be to join that with the implementation PR before the demo, which would be great obviously, but we'll see if the timing works out
(also planning on catching up on the other discussions now that there's a minute of breathing room 🙂 )
@thorn moat @sharp zealot any concrete ideas yet on what specifically we'd like to show in the demo? I can focus on integrating those parts.
Maybe just the cli commands you listed here in that order?
I think if we had a working, credible example of querying checks and artifacts - that would really help show the potential of Zenith to make Dagger more accessible via the CLI
ideally the first part of the demo involves no code - just using the CLI. Then we switch to top hat, and show the code that made the magic possible. Ideally it looks like not a lot of code, for so many cool features
Cool yeah I totally agree, I'll start there and see how much we can get working. Won't start here, but if there's time I'm very tempted to see if we could throw together dagger shell using @chrome pilot's tty-over-websocket implementation from back in the day quickly. For me personally that would be maximally 🤯
yeah that would be killer
I'd love to have this, too. It would make working with various tooling so much easier.
ha I was tempted to try this too. I suspect there's a path to this again, on top of https://github.com/dagger/dagger/pull/5322. btw @sharp zealot I elected to keep the breaking API change that adds the Service type, since we're planning to do a breaking-changes release soon anyway
My head is spinning with all the things in flight already though:
- WithFocus() API
- importing OCI layout dirs
- services v2
- upstream buildkit PR
- today's zenith CLI spike
- prospective universe code
a few of these have mutual rebase conflicts, too, and that's not counting the rocket surgery going on on your branch @rocky harbor 😛
Yeah I'm feeling that very acutely too. My plan was to ignore until immediately after the demo and then figure out a plan on merging it all 😄
One thing is that we should talk through my pr for re-architecting the graphql server and yours for services and see if there's new ways of reconciling them. Part of the re-arch is that we now have extremely fine grained control over sessions, which I'm sure will impact the approach in your upstream buildkit PR (and possibly give new routes for accomplishing it)
if anyone has a moment, WithFocus() is ready to go, and almost definitely has an impact on the demos, and is the source of some merge conflicts, so it'd be nice to land it: https://github.com/dagger/dagger/pull/5364
neat, I'm also curious if this can help with container importing too. theoretically that can all happen within the engine now 👀
I'd say at this point our imagination is the limit, in theory at least. We can add new APIs as we need rather than trying to retrofit on upstream. With great power comes great responsibility and all else being equal upstreaming is gonna be preferable, but when all else is not equal we don't have to be limited anymore.
just nit comments, :shipit:, let me know if there's anything else that's a relatively quick review that will help with disentangling
sweet,
- I think we can do the layout dir importing easily too, but I'm thinking of renaming the API to Container.fromOCILayout, curious if you or @sharp zealot have thoughts on that. We can technically do the demo without it, but I think it's pretty cool to show the apko/wolfi/nixpkgs stuff, and Container.import is embarrassingly slow for that
we could also rename Container.import to Container.fromOCITarball but I'm tempted to just deprecate it tbh
ah I guess we'd want it for symmetry with Container.export?
If import is just not going to cut it because it’s too slow, and we don’t think we will ever miss it (because importing from a directory is just as easy, and/or importing from a tarball can be implemented in userland) then maybe simpler to just break import to take a directory instead of a tarball
hmm, yeah I think the only weird thing is what to do with export. it's weird to have it write a .tar, which is more generally useful with the outside world at the moment, but then you have to untar it to pass it back in. (maybe that's not so bad...)
that's the current PR. the part I like about fromFoo is it keeps us from being boxed in to one format, and aligns it with from. but I guess that argument goes for build too - would that be fromDockerfile? 
(OK with importDir, just exploring other options while an API breaking change window is opening)
also, to be totally fair, there's always a chance that we can fix import performance, maybe a much higher chance now with @rocky harbor's latest rearchitecture. so maybe dropping it entirely is premature, and we don't need importDir anyway?
that would be most ideal, really. maybe I should look into that instead... 🤔
starts reviewing https://github.com/dagger/dagger/pull/5443
In the future if we do ship an ‘artifact’ type that can be either directory or file, we may not need two different calls at all…
Just took a quick look at your oci layout PR, yeah the big bottleneck (IIUC) of "export back to the client, unpack, import back to the engine" would no longer be an issue. Sincesince the gql server is in the engine process, even if we still do the same "round trip" it's not actually going far (it will traverse a session that's actually just over a net.Pipe, so very hard to become a bottleneck).
The other thing we can do now is when we make solve calls, the result/reference has the same API as before but also can be turned into the underlying buildkit cache ref, which means you can just straight-up mount it and make direct syscalls to interact with it. I already used that in the PR to simplify the process of getting stdout/stderr after a failed exec: rather than using the shim as a proxy we just read the stdout/stderr files directly.
Not sure if that'd be useful in this context, but seems like it possibly could be
Cool, yeah this seems like it'll almost certainly help. I was also thinking we might be able to just import directly to Buildkit's content store, and use that as the OCI layout directly, so the oci-layout:// source is always a no-op. Not sure if there are dragons there
it already exposes its content.Store through the client interface, but it's read-only (sensibly). It was originally exposed for build history reasons iirc. (edit: actually it looks like it's a different interface anyway)
Oh yeah that'd be cool too. It would rely on the implementation of the source op to check buildkit's content store first for a matching digest and use that if available. We'd need to check if that's the case, and even if not that sounds like a potentially easy upstream contribution
I think it does, assuming it's same store. When you import a layout dir for example the first oci-layout:// call is slow, and the rest are immediate
--- a/engine/server/server.go
+++ b/engine/server/server.go
@@ -101,8 +101,8 @@ func (s *Server) Run(ctx context.Context) (*frontend.Result, error) {
BuildkitClient: s.bkClient,
Platform: s.worker.Platforms(true)[0],
ProgSockPath: progSockPath,
+ OCIStore: s.worker.ContentStore(),
/* TODO:
- OCIStore content.Store
Auth *auth.RegistryAuthProvider
Secrets *session.SecretStore
*/
that was easy (TODO: see if it actually works)
btw, it would be really really useful to have a way to export a container as anything (directory or tarball) without requiring an export to the host filesystem. I'm guessing that's a separately annoying problem to solve, but thought I'd put it out there - people are asking for it
We can now convert a container to whatever we want now without needing to send it back to the host, can be 100% server-side. I guess my question is where would it go? Just cached, or exported somewhere besides the caller's host fs?
lmk if you want to see where the skeletons are hidden 🙂
@rocky harbor Does this also fix the longstanding issue of Export/Publish/etc establishing a new session and possibly rerunning things (due to source refs resolving to new things)?
Will do! I'm gonna save it for last, so could be delayed to a future demo depending on timing 🙂
Yeah it does because we just call the worker exporters directly now: https://github.com/sipsma/dagger/blob/07f666be1964900123ffe6588890536468b9479b/engine/session/manager.go#L187-L187
I would still greatly prefer upstream supported exports right in the gateway API (technically we use the "LLBBridge" api now, but it's pretty much the same thing, just slightly different layer in the abstraction cake). Then we could just pick everything up rather than have to do it ourselves, but yeah we at least have this much better option in the meantime now.
@rocky harbor Trying to dogfood, getting a strange error - here's what I'm running: https://github.com/vito/progrock/commit/c6e0f6534dbcd4217d2b66c166c2019e5512d870
Error: failed to get environment commands: input:1: environment.load.commands[0].runtime Cannot return null for non-nullable field EnvironmentCommand.runtime.
strangely the examples from the PR worked fine, can't see what I'm doing differently
Hm yeah I'm not sure why it's trying to get that runtime field in your case only, but it's also just leftover from previous iterations and null because it's not set anymore, so I'll just delete it from the schema
oh wait, they're not working now either. maybe I broke something.
Side note: I tried using just a plain func a bit ago and it works again now, so you shouldn't need to make it a method (unless you want to of course)
oh good, I remember that being borked at one point so that was the first thing I tried when I saw that error 😛
I pushed a commit to remove that field. The error was happening because our codegen handles lists of objects by requesting every field, but runtime wasn't there. What I still don't understand is why it just started happening for you and the examples in my pr worked, but let me know if it's fixed now
maybe the go sdk generated code was out date
ah yeah that was it. I regenerated it on my local branch
Yeah that should be de-borked now. Also btw, I skipped implementing namespacing for now to save time, so every command (and soon check, artifact) has its named stitched right under query, so there's annoying conflicts if you e.g. have commands named "lint" in separate environments. Let me know if that gets very in the way, I can bump priority on fixing if helpful for demoing, I don't think it's too bad to setup
the container import change works! 🥹 total diff: https://gist.github.com/vito/7ef6581bd6ad4b572343795caee8679a
That's amazing! Wow yeah hindsight being 20/20 we've been artificially limiting ourselves for a long time by not having our API in the engine server-side
Feel free to push that to the zenith PR if you want
done!
could be fed into tools that take oci-packed images as their input. For example a daggerized docker client that could docker load it into a docker client local or remote
Oh sure, yeah we can do the conversion very efficiently server-side now, then once we have support for a "stream" type too we can support that exact use case (and other similar ones) I think
@thorn moat I pushed a commit with a placeholder Checks API and support in the Go SDK: https://github.com/dagger/dagger/pull/5443/commits/51c40b82b0faf80d775a58da9c960f02aba19fd6
I also changed WITHCommand to be WithCommand_ in addition to adding WithCheck_, so it's at least slightly uglier pending the codegen fixes to make that work as intended 🙂
Haven't tried using it yet, but gonna try pulling in bits and pieces of your branch w/ the CLI updates + new universe envs and see what happens. Or actually if you already have a rebase of that branch on the zenith one, feel free to just push your commits to the PR and I'll go from there
Nice! Don't have any rebase in progress, go for it
maybe it’s too much for thursday, but any chance we could support sub-checks, so that eg. progrock’s go test suite could be exposed both 1) as a single top-level check, and 2) as a list of individual sub-checks, one per go test? I’m happy to be the guinea pig and try implementing the top hat side (by generating gotestsum’s json file, parsing the result and plugging into the zenith checks API)
there’s a pseudo-code version of that in the draft schema/readme PR
it may seem superfluous but IMO it could be the difference between “meh just a complicated shell script wrapper” to “ok I want access to that API”
I can't currently think of any reason that would be very much work on top of the current state of things, at least in terms of the API+sdk. Once I successfully run a single top-level check, I can look at adding subchecks to the api + go sdk. In the meantime, if you want to write the part that parses out the json file and calls to some dummy placeholder api, that sounds great, we'll need that code eventually so no risk of wasted time.
Just to double check, the API should let you list all checks, invoke individual subchecks and get individual subcheck results?
fyi: trying out the latest changes now, I noticed dagger do was printing cryptic "vertex is not in group?" errors, so I just fixed it in Progrock (it had to do with focus mode)
current progress: https://github.com/vito/progrock/blob/zenith/ci/ci.go
looking forward to getting some of this into Universe - especially the apko/nixpkgs parts, which I guess will need support for general API extensions
Nice! I have to run in a sec and don't have the types we use there offhand, but are you thinking general api extensions just because they accept/return more exotic types?
Also just pushed to the zenith pr with more fleshed out plumbing for checks, last step is to hook up to the cli you added and see what happens. May have time later tonight, otherwise early tomorrow
They return a Container, so maybe we could model that as an artifact, as long as it can be parameterized sufficiently. Otherwise I figured it'd just be an API extension yeah. You can see the usage in the Base function in the previous link.
And sounds good! I may take a swing at it in the morning too, will let you know (update: I haven't - trying to figure out if services can benefit from the new architecture, instead)
Right, yeah it looks like we'd need to support
Containerreturn, which is trivial to support in terms of low-level plumbing since the code can handle any id-able return value pretty generically[]stringinput, fairly easy in terms of go sdk updates. For the CLI i guess we could just accept repeated flags likedagger artifact --pkg foo --pkg bar...ApkOpts, which requires a bit more work since we'll need the schema to include aninput. Less clear whether we'd even try to expose that in the CLI, maybe that is just an api extension only thing.
For the api extension part, obviously codegen is the ultimate solution, but I realized the type-unsafe invocation builder api I added to command and check could in theory be made to support generic resolvers too. It would just be ugly, e.g. .SetStringSliceFlag("pkgs", []string{foo, bar}), .SetStructFlag("opts", map[string]any{...})
Starting on the CLI bit now!
Thinking about it more, to me these APIs feel more like extensions. Closer to scripting/helpers than making use of an 'artifact.' Maybe because the result of these APIs is rarely the final value you use; all the call sites actually chain more project-specific things after it, like installing gotestsum. As for ApkoOpts, that was an attempt at modeling the ideal codegen'd API, so maybe the actual implementation would just have all that as params, assuming there's a way to mark optional params.
Also, @thorn moat @sharp zealot how about we check in at 1pm PT to finalize what we want to show for sure in the demo tomorrow based on what's working so far? I have a hard stop from 6-10 PT tonight, so want to get that straightened out earlier than later.
Flexible on 1pm too
2pm?
Sure works for me
Pushed barebones dagger check support: https://github.com/dagger/dagger/pull/5443/commits/8d38eb0e8dc9201591aba2f9c3828650e3e9e57a
Was pretty straightforward, mostly the same as commands except some trickier handling around the fact that a check entrypoint returning an error needs to get converted into a CheckResult rather than propagated as an error per-se all the way back to end clients.
Examples:
- Listing checks:
./hack/dev ./bin/dagger check list -e ./universe/dagger - Passing check:
./hack/dev ./bin/dagger check -e ./universe/dagger python-lint - Failing check (warning: there is a ton of output):
./hack/dev ./bin/dagger check -e ./universe/dagger engine-lint
TODOs:
- The output of
check listlooks a little weird. Also not delighted by the output ofcheck, especially when there's a ton of output, but it's maybe okay enough for now. - Integrate with the demoenv, I just used the existing lints in
universe/daggerto start. I cherry picked your commits but a lot of the files needed updates to compile, so saved time by just rm'ing for now.
@thorn moat Do you want to try that out and then see what you think makes sense to polish some more for the demo?
My next step is to try out subchecks quickly. After that, artifacts, which I'm hoping is even easier than checks? @thorn moat feel free to try out artifacts too if you have time, I think the commit for adding check support is a good skeleton for how to add new entrypoints
@rocky harbor Just hit an interesting scenario: 1. run something that uses Container.import, 2. run buildctl prune, 3. run that thing again, and you'll hit an error where oci-layout:// refers to an unknown digest. This happens because Container.import caches in-memory, and now that spans across Dagger runs. I think the fix for now is "don't do that" but in general the global caching is something to watch out for now.
Oh right, I think we can remove that caching we wrapped container.import in. The caching for dockerfile build, not sure yet, but maybe there's a route to not needing that anymore too
I've been trying out some more polish for the focus-mode TUI: https://asciinema.org/a/6YyLozDrqW38U1ZLgLYy6JNxq
- Now shows the last line of output from whichever vertex is running.
- For vertexes that have sub-tasks (e.g. image fetching), a single progress bar is shown summarizing all inner progress bars (by just summing current/total), and the last active task is shown
- Got rid of the info section and help text to make room. Info is still shown at the end.
- Current vertex name is in bold instead of in yellow, for better readability.
will push soon and try it out on top of the checks stuff 🙌
@rocky harbor fyi, pushing a tiny go.mod bump to your branch for ☝️
I think the check command output is clashing with Progrock's TUI, so I'll find a way to make the two play nice. But yeah, everything works here! awesome stuff
Awesome, yeah I'm guessing it's interleaved, sounds great!
@rocky harbor re:
// TODO: why doesn't cmd.Printf work?
// cmd.Printf("Check %s: %t\n%s\n", envCheckName, success, output)
the session's *progrock.Recorder wasn't being added to the ctx, so that (along with other places) was logging to the void. Working on a fix
Some of the progrock recorder/writer setup is a bit clunky, related to the way we collect pipeline labels, since those have to be on the root group, which is automatically created when you construct the Recorder. Would like to clean it up someday so the Recorder can be set up in the outermost layers somehow.
hmm, checks interact kind of strangely with WithFocus(); you get duplicate output if you use it. I guess we would suggest against using WithFocus() for checks, except for troubleshooting?
Worth noting that in this case the top-hat (me) added WithFocus() to the Gotestsum helper, so sometimes you can't tell how it's going to be used
also, one perk of using WithFocus() is that you can see the logs streaming, rather than having everything buffered up into the string return value
Joining teams in 1 min
oh hey, we already have $DAGGER_PROJECT 👍
@thorn moat For the demo script, I guess for now it would make sense just assume the current set of features, and then provided nothing unexpectedly explodes I should push the subcheck support in the next hour or two and you can update to include that?
makes sense!
haha I forgot about that, I think I missed doing a sed -i s/PROJECT/ENVIRONMENT/g **/*.go
@rocky harbor Not sure if I'll be able to env-ify all the code under ci/pkgs/ actually, even the Go stuff. You need to be able to pass in a base image, which doesn't seem to really fit into our model at the moment.
Unless you had something in mind there. (Example: https://github.com/vito/progrock/blob/b4bf857f7c958b51e453e285a04a61567c49db3d/ci/ci.go#L30)
I mean, I can add a progrock environment, but that feels like it sends a weird message since it's so specific.
At least for the first part of the demo, this is fine, since I can just set DAGGER_PROJECT=./ci and it's all invisible anyway
Yeah makes sense, just to double check your idea before this was to have go be a separate env under universe and then just use that one to list your progrock tests, run your builds, etc. ? As opposed to having a progrock-specific env that calls out to universe envs like the go one?
yeah, I figured the Go parts of ci/pkgs/ could be the start of the canonical Go environment in universe, but in practice I also expect to maintain an environment for Progrock anyway that builds upon it. I think it's TBD how these "canonical <X language>" environments pan out
but at least for really simple Go packages it'd be nice if you could just dagger use go and dagger check away
whether that's a real useful thing and not just a parlor trick, we'll see 😛
Okay right, so I think it would be okay then to have your progrock specific env for now. Like you said, shouldn't really impact the first part of the demo. And then when we show the code, you could just call directly to the "go environment", which is actually just a separate package under universe at the moment that you are calling directly, as opposed to through the APIs. That will get the idea across enough to hold everyone over for future demos I think?
Besides entrypoints not currently covering accepting inputs like container, we also still haven't split out "environment" and "context" or added WithExtension yet, which you'd need for the "no-code" version
ah got it - yeah, I can try that. Hopefully I don't hit a dagger <=> progrock dependency cycle 
if that happens i can just demo using Booklit instead 😛
actually Booklit might be a less confusing demo anyway, since it also has a binary to build
I'll make sure that works too, maybe we can show off two repos
@rocky harbor pushed a couple of small commits fyi, one to change Container.import to use a separate content.Store (so it doesn't flake during the demo), and just some more UI polish
pushed universe packages too, universe/{goenv,apkoenv,nixenv} - ain't the prettiest names, but go is a reserved word, and these will be replaced by real envs at some point anyway (which will be package main
)
@thorn moat will be setting up my demo env soon, where should I start?
1 sec!
still need to actually add the lint check, could have sworn I implemented that, maybe I dreamt it...
@thorn moat so I should not use your dagger branch, correct?
Right, use sipsma/dagger
hummm..
The path /home/sipsma/.docker is not shared from the host and is not known to Docker.
lol, I needed to hardcode a hack to get my docker creds into the engine container so I didn't hit dockerhub rate limits: https://github.com/sipsma/dagger/blob/336f428abfae7f0dde915274dd2d62f7d81a2ae9/internal/mage/engine.go#L348
I even included a few //TODO: comments so it gets removed before the PR is merged, as you can see 😁
I can push a fix so it finds your homedir instead of hardcoding mine
I'm confused how @thorn moat didn't hit though
❯ ls -al /home/sipsma/
total 12
drwxr-xr-x 3 root root 4096 Jul 11 10:22 .
drwxr-xr-x 4 root root 4096 Jul 11 10:22 ..
drwxr-xr-x 2 root root 4096 Jul 11 16:55 .docker
oops
😄
sorry 😅
Stderr:
go: downloading github.com/juju/ansiterm v1.0.0
go: downloading github.com/rs/zerolog v1.29.1
go: downloading github.com/spf13/cobra v1.6.1
go: downloading github.com/spf13/pflag v1.0.5
go: downloading github.com/shurcooL/graphql v0.0.0-20220606043923-3cf50f8a0a29
go: downloading github.com/lunixbochs/vtclean v1.0.0
go: downloading github.com/mattn/go-colorable v0.1.13
go: downloading golang.org/x/tools v0.10.0
go: downloading github.com/99designs/gqlgen v0.17.31
package github.com/dagger/dagger/cmd/dagger
imports github.com/dagger/dagger/core
imports github.com/dagger/dagger/core/reffs
imports github.com/dagger/dagger/engine/buildkit
imports github.com/dagger/dagger/engine/session
imports github.com/moby/buildkit/exporter
imports github.com/moby/buildkit/cache
imports github.com/moby/buildkit/snapshot
imports github.com/containerd/containerd/snapshots/overlay/overlayutils: build constraints exclude all Go files in /go/pkg/mod/github.com/containerd/containerd@v1.7.2/snapshots/overlay/overlayutils
Please visit https://dagger.io/help#go for troubleshooting guidance.
I didn't mean to infect your machine with my name
all good, I'll disinfect it
oh I bet it doesn't build on macos right now... do you have linux available? otherwise I can see if rearranging packages will fix it
obviously that'll have to be the long term fix either way
I'm running ./hack/dev though, wouldn't that build everything in a container?
Pushed a fix, should use $HOME/.docker now instead. I would recommend doing a docker login too just to make sure you have fresh creds and don't get rate limited during the demo
The problem is the dagger cli has a several levels deep dependency on something from containerd
and that has to be built for darwin if you are running there
i'm looking to see how much it'll take to disentangle
I'm assuming a simple go build won't work?
no should be the same result
I think it might be easy to workaround, trying something quick
hm okay I got rid of the dep you were hitting, but that just revealed another path. I'll see how long the whackamole lasts
ok, sorry for adding that complication
no worries, it was gonna happen someday anyways! Took about 7 rounds of whackamole and a lot of copying, but I got the build working again. Pushed a fix
However, I think I must have copied something incorrectly in the process because when I'm trying to run the commands from before it's freezing. I'll keep looking but @thorn moat if you're around would appreciate a second pair of eyes, I'm sure it's just some dumb oversight
oh weird, I was doing ./hack/dev ./bin/dagger check -e ./universe/dagger python-lint
@sharp zealot worth a try again on your end
on it
@rocky harbor hm, I can repro the hang in Booklit zenith branch and in Dagger, investigating
oh, it eventually errored:
Error: connect: make request: Post "http://dagger/query": command [docker exec -i dagger-engine.dev buildctl --addr=unix:///run/dagger/server-vkixxy6or4eapjzxb4z97k0x
7.sock dial-stdio] has exited with exit status 1, please make sure the URL is valid, and Docker 18.09 or later is installed on the remote host: stderr=error: dial uni
x /run/dagger/server-vkixxy6or4eapjzxb4z97k0x7.sock: connect: no such file or directory
Can I wrap ./hack/dev in a dagger run or is that asking for trouble? 😇
Ok I have a working binary, thanks
@rocky harbor ah, the shell what worked was running the old dagger binary - can confirm everything fails with the previous error
I don't have direnv installed, how crucial is that step?
pretty crucial - but you could maybe just source .envrc
that's the step that lets you say dagger check foo instead of ~/src/dagger/hack/dev ~/src/dagger/bin/dagger check --env ./ci foo
it's a pretty tiny tool, one of my favorites really. does one thing, does it well
Is DAGGER_SRC_ROOT only needed for setting $PATH? Or also used somewhere outside that .envrc?
it's for $PATH and the DAGGER_CLI_BIN env
I literally just installed direnv. All I need to run is direnv allow?
I don't understand how it can affect my shell's environment without a builtin
ah! thanks 🙂
beautiful
Is export _EXPERIMENTAL_DAGGER_RUNNER_HOST=docker-container://dagger-engine.dev important?
yup
Ok. so far dagger check list hangs for a while then fail with a docker error that seems related to engine provisioning
(will copy-paste in a bit)
waiting for it to timeout again
% dagger check list
• Cloud URL: https://dagger.cloud/runs/b4db1f8f-fd3d-4901-a31a-db10a2cbae86
• Engine: b730877185eb
Error: connect: make request: Post "http://dagger/query": command [docker exec -i dagger-engine.dev buildctl --addr=unix:///run/dagger/server-rmgox0zau9n65q7xtvxa1upoj.sock dial-stdio] has exited with exit status 1, please make sure the URL is valid, and Docker 18.09 or later is installed on the remote host: stderr=error: dial unix /run/dagger/server-rmgox0zau9n65q7xtvxa1upoj.sock: connect: no such file or directory
lol yeah that's where we are too, I am truly confused as to what could have changed since all I did was copy paste some stuff to different packages. Hoping it's not related to some init() or something somewhere
i'm going back to the previous commit and running one by one with each change
I noticed this part - maybe the path is different? https://github.com/sipsma/dagger/commit/f4fa6a9e08318feea2eebd0d5761fcfc31f998b1#diff-375c41f6a94e797edee687b8fa151865e2192d8aa9088acaffa174d0de2c3578R333-R334
looks fine on further analysis...
Yeah I can't see anything wrong either...
I have to get ready to leave at 6:10. It's to go see a show I bought tickets for for my girlfriend for her birthday a few months ago, so non-negotiable :-). Will keeping looking until then
I'll keep looking too 👍
oh... I think I may have found it, one min
@thorn moat can you double check what I just pushed fixes it for you too
yup! 🎉
@sharp zealot freeze should be fixed, hopefully nothing else darwin-related remains
@thorn moat gotta go, I was very close to subchecks, was just implementing the part that ran checks w/ subchecks in parallel, i'll push my progress to a separate branch in case you happen to have time and want to finish it. But no worries if not since it's super late for you obviously.
I'll be back at 10, think I can finish it then. I've also been waking up super early lately, so I'll be online 7:30ish my time tomorrow morning for any last minute coordination
sounds good! I'll send a ping if I jump into it, but odds are low 😛
no worries at all! put it here on the offchance: https://github.com/sipsma/dagger/commit/2b35178053a0d14c53994063cf503e6db5e13b7f
@sharp zealot added lint to Progrock and Booklit, and docs for each command:
❯ dagger check list
[0.97s] list checks
check name description
unit Unit runs all Go tests.
lint Lint runs golangci-lint against all Go code.
• Engine: 51021dfa219a
thanks! sorry I’m on family break, will resume in 1h or so
pushed a fix for an occasional ~5s hang I was seeing on start: https://github.com/sipsma/dagger/commit/867b364b9307dc45244310f2b34f27b2b2e9190a
back at it
@thorn moat when I run dagger check list is immediately "bricks" my terminal - cursor disappears, all inputs ignored etc. This is while it times out as described above. Was wondering if that's expected
also still stuck at: Error: connect: make request: Post "http://dagger/query": command [docker exec -i dagger-engine.dev buildctl --addr=unix:///run/dagger/server-j6kxgoz3t8ecp1t0t3hqby4jz.sock dial-stdio] has exited with exit status 1, please make sure the URL is valid, and Docker 18.09 or later is installed on the remote host: stderr=error: dial unix /run/dagger/server-j6kxgoz3t8ecp1t0t3hqby4jz.sock: connect: no such file or directory
The timeout should be fixed now, if you pull and re-run hack/dev (and pull in Progrock/Buildkit too)
I thought I just did that, but maybe did somethign wrong. trying again
This commit?
commit 867b364b9307dc45244310f2b34f27b2b2e9190a (HEAD, sipsma/zenith)
Author: Alex Suraci <alex@dagger.io>
Date: Wed Jul 12 23:24:38 2023 -0400
engine client: faster retries
Signed-off-by: Alex Suraci <alex@dagger.io>
yup
and pull in Progrock/Buildkit too)
--> not sure what that step is
oops I meant Booklit there - just the repos where you'll be running dagger commands
Ah ok - possible that not having the latest progrock explains still having the timeout?
what does which dagger say?
it's the right location (inside the dagger repo)
I'm rebuilding just in case
is it safe to just go build ./cmd/dagger to save time, or important to go through the whole ./hack/dev?
Ah, rebuilding failed:
Error: input:1: pipeline.pipeline.container.from.withExec.withEnvVariable.withExec.withWorkdir.withDirectory.withMountedCache.withExec.withMountedDirectory.withMountedCache.withEnvVariable.withEnvVariable.withExec.file process "go build -o ./bin/dagger -ldflags -s -w ./cmd/dagger" did not complete successfully: exit code: 1
Stdout:
Stderr:
package github.com/dagger/dagger/cmd/dagger
imports github.com/dagger/dagger/engine/client
imports github.com/dagger/dagger/engine/server
imports github.com/dagger/dagger/core
imports github.com/dagger/dagger/core/reffs
imports github.com/dagger/dagger/engine/buildkit
imports github.com/dagger/dagger/engine/session
imports github.com/moby/buildkit/exporter
imports github.com/moby/buildkit/cache
imports github.com/moby/buildkit/snapshot
imports github.com/containerd/containerd/snapshots/overlay/overlayutils: build constraints exclude all Go files in /go/pkg/mod/github.com/containerd/containerd@v1.7.2/snapshots/overlay/overlayutils
Please visit https://dagger.io/help#go for troubleshooting guidance.
exit status 1
~/dev/dagger/dagger %
maybe it had failed the first time and I hadn't noticed - would explain the timeouts not going away
o_O that's back to the error from before the darwin fix?
looks like it
trying again after git clean
there was a universe.tar lying around, with a little luck that was the issue
I think there's just more moles to whack, working on a fix
god I am such a robin hood hat
@sharp zealot ok try pulling
I think you'll need a full ./hack/dev, but you can check with go build first
pulling
Would be awesome if even the git jugglery could be daggerized
This whole scenario we're going through right now, feels like a good use case for a standalone env 🙂
so instead of telling me "try pulling again, and re-run the steps on the new commit", hoping I don't get it wrong - you could just say "refresh the artifact" or something like that
OK it built successfuly this time!
yay no more hanging either!
Moving to next problem 😛
Error: failed to get environment commands: input:1: environment.load failed to load environment: failed to get runtime container for schema: error getting credentials - err: exec: "docker-credential-desktop": executable file not found in $PATH, out: ``
I'm guessing my hosts's docker config.json ends up mounted into a container or something like that?
yeah tried that, didn't fix it
hmm. do you have docker-credential-desktop?
yes 🙂
(wondering if $PATH is getting unset/reset somewhere)
my $PATH is looking weird, but can't tell for sure that it's because of this
/Users/shykes/dev/dagger/dagger/bin:/Users/shykes/.docker/bin:/Users/shykes/.docker/bin:/Users/shykes/bin:/opt/homebrew/bin:/opt/homebrew/sbin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/Users/shykes/.docker/bin:/Users/shykes/bin:/opt/homebrew/bin:/opt/homebrew/sbin
never seen that before 😄
theoretically it should be mounting ~/.docker to /root/.docker in the engine container - you could exec into it and see if it made it in?
the first entry is added by the .envrc, but yeah some of that repetition is a little funny
that's the problem exactly
my ~/.docker has a config that says "use this binary helper to authenticate" but it's a mac-only helper
lol, makes sense
sadly you can't trust .docker in this scenario
we had this problem a long time ago and found a solution that we liked - which of course I can't remember at all
hmm is there some way to skip the cred helper and have docker login just write a plain old token?
to config.json
are you actually trying to mount .docker/config.json?
yeah
that's my guess, since that's how all this behaves on Linux (without Docker for Desktop I suppose being the difference)
this is an artifact of the session-frontend refactor, there's probably a TODO in there to move this part back to client-side somehow
ok
man I wish I could remember our fix, it was exactly this problem
I think I'm down to crafting a config.json manually using creds copy-pasted from mac os keychain
ok I've done that, testing now..
Yes this is the reason for all that, didn’t have time to re-add buildkit’s auth session attachable so mounting the auth right in was faster
weird, I definitely succeeded in fixing my docker/config.json... but I'm still getting the same error
% dagger check list
[0.41s] ERROR dagger check list
[0.00s] connecting to Dagger
[0.00s] loading environment
[0.41s] ERROR list checks
[0.24s] ERROR resolve image config for docker.io/library/golang:1.20-alpine
• Cloud URL: https://dagger.cloud/runs/3f252714-c328-4d1c-8ce3-66af6dca036a
• Engine: 4b7070b6a638
Error: failed to get environment commands: input:1: environment.load failed to load environment: failed to get runtime container for schema: error getting credentials - err: exec: "docker-credential-desktop": executable file not found in $PATH, out: ``
Please visit https://dagger.io/help#go for troubleshooting guidance.
~/dev/progrock % cat ~/.docker/config.json | grep docker-cred
~/dev/progrock %
there's definitely a base64-encoded password in there 😛 yay
did the change propagate into the container? 🤔
looks like it didn't. But I don't know anything about that container's lifecycle
should I nuke something long-running?
./hack/dev again should work
I have to take the trash out, I’ll see whether reincorporating auth attachable is quick or not after
@rocky harbor I don;t think you need to worry about it for the demo at least, I think we're close
Yeah I'm just checking if it's like a 5 min task, no biggie
Hurray!!
% dagger check list
[2.92s] list checks
check name description
unit Unit runs all unit tests.
lint Lint runs golangci-lint against all Go code.
• Cloud URL: https://dagger.cloud/runs/7d77143b-6d2f-4593-8d26-ed9f1dfbcbd7
• Engine: 02ffb188d9f8
Eh yeah it's more like a 30 minute task and too complicated to risk breaking before the demo if you have something working, so I won't touch it tonight 🙂
lol, funny how that ends up in Cloud https://dagger.cloud/runs/7d77143b-6d2f-4593-8d26-ed9f1dfbcbd7
oh my at the load(source: ... that goes on forever to the right...
haha, I want to fix that, they used to show sha256 digests but it broke
is linter check supposed to have tons of errors?
yes 😅
both progrock's and booklit's fails, I could fake one out if you want
I don't think we have a run-all-checks command at the moment though so it might not make much difference (vs just showing passing tests)
it's fine as it is, just making sure those were errors I should be seeing 🙂
fixed booklit's linter issues if you want to pull either way. 😛 there weren't too many
@thorn moat no .envrc in booklit, expected?
added!
@sharp zealot @thorn moat Got subchecks working, but just pushed to a separate branch for now to keep demo safety maximized, probably a bit too late to incorporate, but maybe we can sync up tomorrow morning, will merge it into the pr after either way https://github.com/sipsma/dagger/tree/zenith-subchecks
./hack/dev ./bin/dagger check -e universe/dagger lint automatically runs all the sdk lints as subchecks in parallel in individually cached execs and shows the results.
Just want to confirm this as a general outline for the demo:
- @sharp zealot pitches and shows robinhood cli-based demo
- Q&A
- @thorn moat shows the progrock+booklit env code (with caveats that the DX there is extra WIP still). I'll chime in as needed too of course but think it makes sense for you to drive this part Alex since you wrote that code.
- Q&A
Sound good? Obviously if questions pull in a different direction we can improvise too. Also, feel bad I'm just running support this time, I'll drive parts in future demos so we can share the load.
Sorry for the last minute swerve but do you think you would be able to drive the second part with me around for support? I'm having a bit of a medical issue, weird recurring muscle spasm/sharp pain that makes it hard to talk when it spikes 😮💨
Oh sure, no problem at all, sorry to hear that!!
I'll go look through the progrock/booklit code quick to refresh
No worries in the slightest, I'm happy to
@rocky harbor as a stretch, if you have a terminal with your latest sub-checks version ready to go, can't hurt to have that ready to go
I was really hoping to have it ready, but had family emergencies so couldn't do it
Sure thing, I'll give it a double check quick. It will be for the dagger CI env, but that's probably fine
The TUI hasn't been updated to show it in a nice way, but it works, so will keep it ready to go and can talk about the benefits in terms of automatic parallelization and all that
nicely done 🎉
Lots of great questions 🙂
That was a great demo and most exciding dagger feature
Thanks Ali! I can't wait to load a gale extension into any environment, and instantly add GHA compat to my workflows
Great work guys. I can't wait to use zenith as part of a gale . This saves me. from lot's of nightmares
re-sending my gist link from zoom chat in case anyone wants to kick the tires: https://gist.github.com/vito/9afdfb85bfd2caef53b3b60616b588b0
IDK how familiar folks here are with zuul-ci, but that community would align with what you're trying to do with Zenith.
Zuul can be implemented with different components, but the core benefits are:
- dealing with multi-repo / multi-language projects
- running the same tests before and after a merge.
https://youtu.be/aWA8HFxFpos?t=491
Zuul is a Project Gating System, or a CI/CD system like no other.
It brings multiple projects together to test the future as if it were the present.
It spans code review systems and clouds. It uses Ansible for orchestration and has no single points of failure. It tests some of the largest Open Source projects in the world and can run on your...
@dense canyon made a little joke about dagger-ci but I wonder if something like that is possible? I would be open to hosting a dagger CI service.
it’s 100% possible 😁
(or will be, with Zenith shipped)
CI is really a software platform + batch compute infrastructure. They are tightly coupled but really shouldn’t be
Side note - interesting developments + standardization for "OCI Artifacts:" https://www.chainguard.dev/unchained/oci-announces-upcoming-changes-for-registries
With dagger/zenith it becomes possible to decouple them.
FYI @thorn moat Pushed the subcheck commit to the Zenith PR and I'm now gonna go rebase it on main so the focus-related commits aren't there anymore to simplify a bit, just in case you have anything in flight atm.
Doing that as part of trying to plot out how to get everything incrementally merged since the Zenith PR is now at +10,064 −5,241 lines changed 😵💫. I'll start a thread about that after I finish the rebase
sounds good! I started on the "proper" fix for Container.import w/ leases but I'll hold off until the dust has settled, since I want to do some more local testing with it anyway
Zenith Development Planning
I've noticed when I run buildctl prune now it seems to keep a lot of data still, only pruning a relatively small portion. I wonder if the long-lived session is keeping refs alive somehow?
Yep, though it's actually not the long-lived session exactly but instead the fact that our buildkit.Client needs to release all the refs that get solved through it. The closest thing to that object in buildkit's codebase is this BridgeClient, which has this discard method, which we'll need to add the equivalent of: https://github.com/sipsma/buildkit/blob/cdf28d6fff9583a0b173c62ac9a28d1626599d3b/frontend/gateway/forwarder/forward.go#L209-L209
That reminds me we need to add test coverage for this though. Could even just be that when any integ test suite finishes it calls prune on the engine and then fails if anything isn't releasable. That's what buildkit's own integ tests do
Yeah that sounds like a good idea
Pushed a commit with a stub of the code and TODOs so it's harder to lose track of: https://github.com/dagger/dagger/pull/5415
Btw I backported the relevant stuff in the Zenith PR to that one, except for the oci store things since it's being re-worked. Feel free to push that (or anything else relevant) to that PR. Rebasing the Zenith one on it is gonna be painful until merged but we'll be able to merge faster by separating out
@thorn moat re: CacheKey #1129130729469657218 message
Nice! Yeah totally agree that the digest after resolving sources is more often what we want rather than the llb vertex digest.
One thing to be careful of is that the digest you get when calling op.CacheMap is a digest of that op only, it doesn't include the (recursive) digests of any inputs. Still useful, but not always what you'd expect
right - that was a bit confusing. That's handled by this right? https://gist.github.com/vito/cff6ac28aa27cccc8e599c0bc0c05bc2#file-cachekey-go-L25-L29 (my understanding is Deps has the digest for each input)
Oh I missed that part, but while that would make sense, it also is sadly more complicated. Deps is a slice that has to have the same length as the number inputs and configures how the digest of the input should be calculated, but it doesn't actually have the digests right after you call CacheMap. E.g. see merge-op here: https://github.com/sipsma/buildkit/blob/cdf28d6fff9583a0b173c62ac9a28d1626599d3b/solver/llbsolver/ops/merge.go#L51-L51
Selector specifically is used when you want "something" specifically from the input rather than the input as a whole. So when you mount a subpath of an input into an exec rather than "/", Selector will be set to a digest of the subpath (approximately, going off memory here).
But there's also a way to specify specific callbacks for how the digest gets calculated
oo, interesting, that explains some things, thanks!
@rocky harbor in merge-op's case (your link above), is every field zero-value to indicate that the outer Digest is sufficient as a cache key? (edit: oh, I just read the later part again, it does sound more complicated. hmm)
Dear Santa. I've been a good boy this year. I would love for dagger query or dagger listen to support Zenith so that I can show all my friends the cool graphql queries they can do.
Thanks Santa!
Sincerely,
Solomon
Yes, unfortunately the code in buildkit around all this is extremely complicated, you'd expect that at some point buildkit calculates a digest that combines the digest of the op itself with the digests of the inputs into one hash (similar to git commits, but for a DAG), but after reading through all that code for magicache stuff, to my knowledge it never does that. What it actually does is... hard to describe 
Let me check quick how much effort that'd actually be 🎅
It was really easy, pushed support for query+listen here to zenith here: https://github.com/dagger/dagger/pull/5443/commits/b73bfa1a892b84454885e049b94e559043da0f21
Example: echo '{pythonLint{success}}' | ./hack/dev ./bin/dagger query -e ./universe/dagger
The only hard part I got stuck on for a while was that I forgot the environment load API is lazy and was confused why nothing was loading 😂 I guess we need sync there too sometime.
@rocky harbor how are thinking on supporting API namespacing?
If anyone is following this channel, but wants to learn more about the Project Zenith, check out this demo from the last community call - #1129800905798193263 message
I got the chance to go back and watch the rest of the community call (had to drop out early for another meeting). Nice work! Some stream of consciousness thoughts and questions here:
Checks: Are we thinking something like a CheckResult data structure that stores individual test results for various checks? Seems like it could be neat. Imagine a dagger extension that you can install in your pipeline that takes pytest or junit output and stores it in a DaggerCheckResult object, which gets first class visualization and control flow treatment. And otherwise if you have some custom custom test suite that doesn't write to a standard like junit, you are given the primitives to easily write to this object for Dagger to store and conflate and visualize
Environments: Based on what Erik mentioned about how to distribute the environments, my naïve first thought is that it makes more sense for end users to be generating their own client with codegen, since it means that it offloads the responsibility of hosting and distributing every single permutation of dependencies of every single environment. picture running dagger env build when you need to update your env dependencies to produce the client that you need for your code, as Erik mentioned. It feels more scalable, at the cost of pushing slightly more work to end users. Otherwise, adding more SDK's and hosting packages for them becomes more difficult as "universe" hosts more environments. Feels like misaligned incentives
checks: yes that is the idea 😁
@honest hearth checks are nested. So “running the python linter” would be a check. But you could refine the implementation to extract a list of each individual linter test as a sub-check. Same idea for any other test suite that supports some sort of structured report output (so, all of them 😁)
Python DX
@rocky harbor Throwing an idea out there, trying to de-risk the stuck Buildkit PR (going on a month now 😬). What if I replace the whole "session attachable-based dynamic network config" part with just adding llb.DNSConfig instead, and align its behavior with llb.ExtraHosts? So it won't count towards the cache key in Buildkit1, but we would still have to remove it when we're calculating a stable digest, using the same mechanism we just used for stripping llb.SessionID from local sources.
The difference on Dagger's side would be that now our ContainerID/FileID/DirectoryIDs would have their session-specific search domain baked in to every WithExec call, and every HTTP or Git call that uses a service. I think that can work as long as any embedded service bindings also retain the same domain, so that they use it when they're lazily started regardless of which Dagger session starts them.
Alternative services v2 ideas
Thought experiment: what would it mean to package something like this exciting new AI playground (one of many) as a Dagger environment? https://twitter.com/mascobot/status/1681334370584637441
✨NEW LAUNCH! LLaMA2 chat API & open-source playground💫:
We're releasing tools that make it easy to test @meta's latest LLM & add it to your own app with @replicatehq.
Playground: https://t.co/YRxDyl5fVW
Live chat API here: https://t.co/TFUOsy44oT
Repos & instructions below:
471
108
Hello, I’m testing entrypoints with Go SDK v0.7.3, and I’m wondering how I can export a directory (containing my build artifact)? I’ve tried to do mydir.Export(ctx, exportPath) in my target, but it doesn’t seem to work. If I return a *dagger.Directory from my target, its content is put at the root of my repo, not in the subdir I’d like to. Also, I’m wondering how I can remove this directory in clean target? Using os.RemoveAll doesn’t work (I guess it’s expected since it runs in a container).
To place things in a subdir, the best pattern we've found so far is to return a *dagger.Directory that places your desired files in a subdirectory: ctx.Client().Directory().WithDirectory("dist", myDir)
Good question about cleaning it up, I don't think we've talked about that at all. 🤔 First thing that comes to mind is having some way to list files to clean up, but this definitely needs more thinking if we want to support it. cc @rocky harbor
In fact, that’s what I was just testing as a last resort! It works as expected, thanks 😉
It took me a bit to get there too haha, in the end it feels intuitive, but maybe not super discoverable
I’ve tried several things like returning ctx.Client().Directory(".").WithoutDirectory("dir-to-remove"), but that doesn’t work (that was expected, though).
Yeah I don't think this is quite possible yet, but the underlying plumbing for "applying deletes" to a host dir exists already, we'd just need to find a way to expose that.
The thing I'd want to be careful about is that it's not easy to accidentally write code that e.g. deletes all your source code or something. Like if you were using this to build+export a binary based on local source code changes, it would be extremely sad if you made a typo somewhere and accidentally overwrote all your unstaged changes and lost them. So just need to think about how to make the DX safe in that sense.
Also, thank you for trying this out! As you can tell it's a very early state, but appreciate you letting us know how it goes, happy to hear any more feedback any time.
For mydir.Export(ctx, exportPath), as you noted all that code runs in a container, so when you call export you are actually exporting to the filesystem within that container. This can be useful for certain use cases, but it definitely isn't obvious enough right now.
How do optional parameters work? From a glance at the code, it seemed to me that using pointers would do the trick, but pointers aren’t affected even when specifying the parameter on the command line. Also, I saw a weird thing where parameters which name contain upper letters were considered mandatory, whereas they were optional when using only lower letters. It seems so strange to me, that I’m wondering if I did my tests correctly 🤔
Yeah at the moment all parameters are essentially optional, if you don't provide them when calling dagger do they should just be set to e.g. an empty string. We have talked about making that more explicit such that you could mark parameters as optional or required (and probably also define default values), but doesn't exist yet.
We are currently in the midst of a big refactor of all of this, which won't yet include support for all of that but should make adding support a lot easier.
Also, I saw a weird thing where parameters which name contain upper letters were considered mandatory, whereas they were optional when using only lower letters. It seems so strange to me, that I’m wondering if I did my tests correctly
That in particular does indeed seem very strange, highly likely it's just a bug on our part 😄 . If you can share the code you're using and how you're invoking it I can confirm. Even though we're refactoring it's highly possible that bug would still be there, so would be good to identify and fix anyways.
Quick thoughts on terminology:
-
cliperhaps a better entrypoint name thantool. Even though it's annoying to capitalize; it's still less ambiguous. (low conviction) -
functionsmight be a better entrypoint name thangraph. Like "here are composable functions which you can use for scripting your own pipelines". What bothers me with "graph" is that it makes sense once you explain it (kind of), but it doesn't have a name for the "things" that you're getting.
Hi. Been a while since i looked at what's coming to dagger. I might get involved into doing "real" CI/CD stuff for some teams, and i would love to try bringing dagger into it (it would be a little hard knowing our client x) ). I would love to redo some dagger related code and try zenith UX at the same time, is there a way to start ? Also would love to try the dagger cloud alpha 😄
I'll DM you about Dagger Cloud!
Great to hear @dusky magnet ! Looking forward to having Jermey show you the latest and getting you access to Project Zenith. We are looking for testers for Project Zenith, so your timing is great 😉
If anyone else is interested in testing/providing feedback on Project Zenith or would like to get a demo, please DM me 🙂
Too bad we have to implement Zenith before we can use it. 😭 Would really like a high-level way to navigate test output right now.
Currently:
Hello @rocky harbor, here is a reproducer: https://github.com/yann-soubeyrand/dagger-entrypoints-test/blob/args/main.go. dagger do --debug test:three gives me an error, whereas dagger do --debug test:two works as expected.
With --progress plain the error is missing required argument aRG.
Hello, how are Docker credentials handled with entrypoints? I guess that, contrary to the “classic use” of SDKs, host credentials aren’t accessible, right? Then how to pass secrets to entrypoints? Again, I guess that host environment variables aren’t accessible.
Design is still TBD but there will be a way to pass host environment variables into the daggerized environment.
Thanks! So, at the time, the only way to publish an image is by passing credentials as entrypoint arguments, right?
Hello, will it be a valid use case to use Dagger entrypoints to start long-running services (like, for example, hugo server, which watches filesystem changes and generates website on the fly, exposing it on an HTTP server on port 1313)? If so, what would be the UI to stop these services (pressing q, I guess, though it doesn’t work in some situations for me)? Also, I’m pretty sure I saw a discussion on service port exposition on host, but I can’t find it anymore with the search, could you point me to it please?
Absolutely will be a valid use case, but there are a few primitives we need to build first: 1. host => container networking (which you refer to at the end there), and 2. watching/syncing filesystem changes, and possibly 3. either re-evaluating the graph when those changes arrive, or somehow allowing things like hugo to just point to a mount point whose content changes as it syncs
I'm planning to work on host => container networking soon (as in within the next days/week)
In the meantime, I saw your PoC on #general, looks very promising indeed, thanks!
Also realizing probably why pressing q doesn’t work in my case (using a shell script as an entrypoint which doesn’t pass signals to child, I’ll try using an exec instead).
Curious to hear if you find the reason, having something not quit when you tell it to is a pet peeve of mine 🙂
Curious to hear if you find the reason
Just pushed barebones support for shell entrypoints in environments to the Zenith branch: https://github.com/dagger/dagger/pull/5443
It just barely works at the moment and only on Linux (not sure what's different w/ MacOS, maybe some TTY thing but haven't investigated yet), there's a long awkward silence while things build before you drop into a shell, you need to ctrl-C after you ctrl-D to fully exit it, etc. etc. etc. but if you want to try pull that branch down and run ./hack/dev ./bin/dagger shell --env ./universe/dagger dev-shell
You can change the container the shell executes in by just updating the DevShell func in ./universe/dagger/engine.go and re-running the above. Pretty fun to play with already, even in its extremely unpolished form.
Actually, after rebooting my laptop, it does work directly on macos... so if anyone gives this a try, I'm curious to know what your result is 😄
Ah, I have the thing again: : "Can't add archive to itself" 😁
It's because the tar flags are different in mac (go generate)
I have to put --exclude universe.tar because -C works differently in linux vs darwin. On does it in the beginning the other in the end, or something like that.
Just finished building 🥁
Oh I get that error too on Linux (slightly different message, but same thing), it's just a warning fwict and ends up skipping it, which is what we want
Err..
❯ dagger shell --env ./universe/dagger dev-shell
Error: unknown command "shell" for "dagger"
Run 'dagger --help' for usage.`
That's running off the branch in PR 5443?
with the latest commit pulled?
Oh, I didn't notice I didn't reset 😁 Let me try again 🙂
phew 😅
I'm trying without that now 🙂
Still waiting here
Ah okay... that's what I got too before I rebooted... I will just need to do some investigation, thank you for trying though! At least Linux has worked 100% of the time so far for me.
The code implementing this is a beautiful frankenstein of the new architecture's support for opening net.Conns between client<->server, @chrome pilot's tty-over-websocket code and bits and pieces of @thorn moat's services v2 code, which are all good by themselves but glued together pretty haphazardly in the PR atm, so there's a good chance there's just a race condition somewhere still, which I suppose could somehow be nudged enough by a reboot to work 🤷♂️
python envs
🤯
Sweet lord, this is awesome! Many people will love this
Btw, I just restarted Docker desktop!
cat-this-file 
Wow yeah, I guess that's what I inherently did when I rebooted my machine. I wonder what this could be... it's such a strange symptom to be fixed by restarting docker desktop... there's a lot of networking shenanigans going on though, so in combination with docker desktop's networking shenanigans maybe something is going wrong in such a way that restarting fixes
I also dagger-reset before the restart so I don't know which was which.
Nice
So we could do just this:
+@env.shell("dev-shell")
async def build(client: dagger.Client) -> dagger.Container:
return (
client
.container()
.from("alpine")
...
)
To debug this container. 🎉
Yes! And I mean obviously we'll also want to layer on the whole "automatically drop into shell for a failed exec" stuff and a million other cool things that can be layered on top here, but that sort of use case really makes the decorator approach shine (too bad go doesn't have them...)
Well.. that's it for me! Outstanding work @rocky harbor 🙂 That session PR was massive! 64+ commits! Can't believe it's merged 🙂
Cya tomorrow 🙂
Thanks! Yeah not what you ever want to do, but in this case there was no other way, and now we can move onto the fun stuff
Have a good night!
Looking forward to playing with shell when I'm back! 👀
I’ve not even tried it yet, but I already love it!
@rocky harbor, just tried to build dev:
universe/embed.go:9:5: embed universe.tar: file too large (2706312704 bytes > 2000000000 bytes)
Oh, yeah that file is supposed to only contain the source code of the dagger repo, so not expected to be 2.7ish GB 😅 Do you have other stuff in the repo that isn't ignored here https://github.com/dagger/dagger/blob/587beab9aa0c7de638ba41135666a5850265cb3c/universe/embed.go#L1 like venvs or similar?
btw that whole thing is not going to be a permanent fixture, it was just a quick way to bootstrap being able to call stuff from universe without needing to rely on an already published git repo
so shouldn't be a permanent headache thankfully
Yeah, node_modules 🙂
Ah yeah, that's a lot of modules! but to be expected I suppose...
I manage my python venvs centrally, outside projects. Node is a pain because you need a node_modules in the file hiearchy.
Ah yeah, will take a little bit but no problem, been meaning to do that anyways
Pushed, was a minor gitastrophe but sorted through it, let me know if something is unexpectedly not working
here's a troublemaking question, what is the npx of dagger?
npm but irresponsibly short time from command to executing anything on the npm registry 😆
I see, so like an alternative UX, on top of the same underlying platform, but optimized for a very specific use case?
Sort of like shortening:
curl -L https://dl.dagger.io/dagger/install.sh | DAGGER_VERSION=0.6.2 sh
./bin/dagger version
(+ a handful of environment identifiers?)
to something like (Extreme version):
curl -L https://dl.dagger.io/dagger/node/run.sh | sh -- npx create-react-app
(not sure if that's a format haha)
that would be more like "curating context of packages for an environment to run in" sort of one-liner
but it'd be cool to have a one liner that can run anything in a known working environment with some magic caching support or somethin
iiuc the closest for us is dagger do --env git://github.com/org/repo <some command defined in an environment in that repo>, with the biggest difference between npx being that the command executes containerized (and with dagger caching, etc.), so it's actually less irresponsible 🙂
Though obviously being containerized means you need to explicitly pass host resources more often, which might be slightly more tedious in exchange for a lot more security-by-default
it'd also enable my use case of having one short project.sh shell script that can be a self-contained "define and run headless doom and a web server that serves a stream of that to local 8080 " sorta dealie
it's been a struggle to have it e.g. write out its own dockerfile or use some specific one when it could just run dagger cmd along the way for what it needs
Alex (on PTO, otherwise would tag) has just the PR for you (support for proxying network ports between host+container): https://github.com/dagger/dagger/pull/5557 It will need to be integrated with our in-progress Zenith work of course, but I think it'd enable exactly that sort of use case
finally we can have our dream of a bash heavy one file project format that's not a zip file that runs anything anywhere consistently 😛
ohh I see as the way to handle proxying traffic from sub-contexts to host executor?
The only thing I'd add is that ideally you wouldn't even need bash (unless you really want to of course), just SDK code and dagger cli one-liners
I'm not above shoving some message bus dealie in there to proxy any key traffic haha
what I like about sh file installers is just that they work in pretty much any shell context, and about dagger that it always works once you reach that point haha
Ooh nice this is cool!
Not if the API allows for environments to request host resources (eg. variables), and for the user to grant them in a safe way (with proper trust management etc).
In that case the friction might reduce itself to "Do you trust the authors of this environment, yes/no"
Yeah for sure, we can minimize the tediousness to the point where users appreciate the extra layer of security rather than consider it annoying
"I trust dagger" (or some local dagger proxy, or that install file saved out) is better than "I trust npm, and whoever wrote these packages, with root access to my computer while I'm logged in lmao"
This would require "I trust dagger + the author of this particular Dagger environment, with this very specific list of access privileges to my host machine"
right, not bad! kind of deno-esque in the secure by default-iness
not sure how sort of downloading package of contexts remotely works, is that sort of building on a git repo based system?
Yes, all git
Actually, even the git part is optional. You can run a Dagger pipeline to download any directory from anywhere; then dynamically ask Dagger to load it as an environment
that is awesome
can it be a base64 encoded string that's part of the sh curl one liner
joking but only kinda
And so on recursively; since Dagger environments can be nested. For example you could load a top-level environment, that gives you a pipeline that takes say, a git repo URL as argument; then from there it will iterate over all branches of that repo, and load a sub-environment with that branch checkout as input, and run the same test pipeline in each. For a sort of programmatic testing grid
damn yes
Another example is that we use it to test Dagger with Dagger 🙂
types.d.ts but for execution environments + docs + other useful programming context (looks like there's already support for completion environment?)
could be cool to have like a well known environment combinations system too for given git/node/etc repos
Yet another example is that @modern fossil embeds Dagger as an engine in his tool - but then he also wants to use Dagger to run CI for his tool. So he has a Dagger environment loading and instrumenting another Dagger environment
that is sweet
Yes there will be a curated catalog of reusable environments, which you can load into your own as extensions. We call that catalog the "universe". Kind of like a regular distribution
does dagger have a mechanism for fanning out across computers / adding computers to a fleet to run stuff on?
(I guess gitlab-runner style for the latter part? fly-machines-like for the first part)
We actually discussed hardcoding the types of that catalog directly in the Dagger API. So for example, if you want to run an AWS-specific pipeline, the Dagger API may include (graphql notation) query { aws(auth: ....) { s3 { bucket(id: "foo") { upload(source: <directory>) { ... } } }
One use case that I’ve been thinking about is building something like sourcegraph batch changes, but with dagger. Essentially, you could run the tool, and it would migrate the current repo to the next version of an api. Dagger comes in to simplify distribution and compilation of these tools because the need access to lots of compiler internals and are hard to package.
https://docs.sourcegraph.com/batch_changes/how-tos/creating_a_batch_change
Is that something that could be a dagger environment or tool?
yeah I ask about compressing the shell initialization to one line because I've been experimenting with LLM code-generation and finding it's really good at outputting and iterating on entire projects one-shot—as long as you stuff in enough context about what it needs to do + allow it to define its entire own execution environment. so defining the Dockerfile and executing the dockerfile in the same project.sh file works very consistently across languages/frameworks/project types
and I imagine a format for defining dagger dependencies via CLI is more ergonomic / intuitive / can have instructions compressed more than writing out a Dockerfile covering all used tech and docker run executing it (the build + run phase separation is just awkward for one-shot executions)
That sounds like a really good use case. So you would encapsulate all the tooling messiness in a Dagger "function" that would take a directory as input, and return a (migrated) directory as output?
Yep
It would probably need a few “escape hatches” for exposing /usr/include and other system directories, but yes
Sure those could be optional arguments I guess
But yes, definitely a great use case IMO
it is building tiiime! 😄
Sourcegraph extension
Possibly sacrilegious suggestion to add to the check vs checks debate: what if it was dagger checks/foo instead of dagger checks foo? Kind of conveys a hierarchical query selection, and leaves the door open for passing additional commands after, like dagger checks/foo history (totally making up a command there but you get the idea). There's some precedent for path-style selectors from tools like Bazel, though this is a different form of it.
I had to run docker system prune -a on my dev vm to clear out 130GB of disk space, but I just restarted my devenv and the dockerfile build lost all its cache, and of course now I am getting 502s from github for the step that installs neovim 😩 😩 😩
Only mentioning here because I am very much looking forward to the day where I can throw that dockerfile away and just use dagger shell... Between the better caching (including cloud cache service so I can clear my local disk without losing everything) and the ability to easily use nix/wolfi/etc. from universe rather than yolo RUNs that depend on flaky internet services, I think these sorts problems will be a thing of the past 
@rocky harbor I have the Go universe Build function working, which took a bunch of fixes to support optional params, but I'm thinking of changing how they work. (🧵 since I'm about to paste a large code snippet.)
Let’s start a thread of possible Zenith extensions 😁
Fixed checks in the Zenith branch, ended up including some improvements relevant to our discussions @sharp zealot @thorn moat ( @kind carbon already knows since I was chatting with him about it).
Previously, user code implementing a check returned (string, error) (or equivalent in python), with the string being the output and the error indicating whether the check failed, which also resulted in the environment exec itself to fail.
- This caused all sorts of problems though, i.e. calling checks from other envs was extremely convoluted and it wasn't possible for us to have the caching behavior we want in terms of being able to cache a check failure.
Now, SDKs are expected to return an EnvironmentCheckResult object instead, with fields set to indicate check pass/fail and any output. If an error is returned (or an exception thrown), that's treated like an "internal server error", would leave check pass/fail in an unknown state.
Among other things, this brings us much closer to the caching behavior we want. EnvironmentCheckResult is returned by environment code, so that means even if it's marked as failed, the execution of the environment code will still be cached until something changes that invalidates the cache. Basically, a check failure can actually be cached now, and will be uncached only once it actually makes sense to retry it.
Examples:
- Implementing a check directly in user code: https://github.com/sipsma/dagger/blob/232874f1ead482d4f7f64f7829346c10011a2162/universe/_demo/main.go#L43-L43
- Implementing a check by combining checks from other envs as subchecks: https://github.com/sipsma/dagger/blob/232874f1ead482d4f7f64f7829346c10011a2162/universe/_demo/main.go#L35-L35
As the comments on the code mention, the change here currently results in some extra boilerplate, but that's just for now as I was trying to lay out the new model. We can still support the less boilerplatey style of code by adding sugar on top that e.g. allows you to return (string, error), merge all checks from another env into yours, etc. It's just that underneath the hood all that sugar will be deconstructed into shortcuts for constructing EnvironmentCheckResult.
I also btw tried to change dagger check -> dagger checks, but in cobra a command's name is set by reading the first word of the Usage (????), and when I changed check->checks here for some reason cobra was still naming the command check... https://github.com/sipsma/dagger/blob/232874f1ead482d4f7f64f7829346c10011a2162/cmd/dagger/check.go#L21-L21
I might be overlooking something or otherwise being dumb, but just leaving that as is for the moment
Pretty sure you can control the command name manually?
I can't find a way of doing that, and the docs on cobra.Command.Name() say Name returns the command's name: the first word in the use line.
Again, could easily be missing something
I guess I can set an alias, but that's not really what we want
My money is on "you're running the wrong dagger binary" 😛
I SWEAR I checked that before, but I just restarted everything and yeah, it's checks now 
it's a well known developer curse, damn these code goblins. This is their job.
I have issues with them as well 😄
I firmly believe that the moment you publicly announce something isn't working as expected, the universe quantum fluctuates into a state where it's working totally fine and it's all your fault
Several physicists spent their career on this theory, but somehow they can only replicate it when nobody is looking
Thinking about my “simple web UI” obsession…
With C2H coming up thanks to @thorn moat , and introspection already possible, I guess I have everything I need to implement a toy web UI for zenith, as a zenith extension?
does introspection work with the Zenith API?
Yep that's how the codegen works, but you also don't necessarily need introspection. If you want to query the checks on an env, you can just do e.g. {environment(id: "..."){ checks { name } } }
You can use introspection too though
but how would I get the ID?
Once you load the environment you can query the ID, but I guess we should also add support for something like {environments { name id } } to make that easier since you probably aren't going to be loading the environment from the gql client and instead just rely on the environments that are automatically loaded when you call dagger listen -e ...
yeah I’d just bootstrap from the current CLI context
so the current environment (here ?)
I was hoping for something like query { here { checks { name } } }
Oh I missed you want to run the client in an env itself, re-read now, got it. Yeah here would pretty easy to add too, I'll append that to my queue
@rocky harbor sorry I know you already wrote this, but I can't find it anymore... What README should I use as my entrypoint in your branch?
No worries, it's at universe/README.md, it's extremely barebones at the moment; just let me know what's missing and I'll add more to it: https://github.com/dagger/dagger/blob/ad9533501d95f121b678a99d163abd492c6bff8f/universe/README.md
anything special I need to do to build dagger itself in that branch?
Same as before, ./hack/dev will build ./bin/dagger and run the dev engine in docker at dagger-engine.dev. It prints the env vars you need to set to use it (or you can do ./hack/dev bash to open a shell where they are set already, or you can use the direnv from the previous demo, etc.)
Ironically the perfect example of why standard entrypoints are useful 🙂
Can't wait to dagger artifacts my way out of this one
The entrypoint even exists already! https://github.com/dagger/dagger/blob/ad9533501d95f121b678a99d163abd492c6bff8f/universe/dagger/engine.go#L20
Just need to get over the bootstrapping hump and we'll be there
Pushed that to the zenith branch, I just called it { currentEnvironment } for now since .Here() looks a little funny in the codegen, but we can figure that out later 🙂
Yeah that's a good idea, we collect doc strings but there's no cohesive way to collect it all together and display as actual docs. Would be nice
That’s awesome!
In case anyone missed it, here is the Project Zenith update that @rocky harbor shared at yesterday's community call - https://youtu.be/-QMGe0QX6JI
Erik provides the lastest update on Project Zenith development
We will have full demo ready at the upcoming Dagger Community Call on August 24th. You can register here: https://dagger-io.zoom.us/webinar/register/7316691559833/WN_USQjVBGXT0SWhNMvqYVvCA
Join the conversation on our Discord:
https://discord.com/channels/707636530424053791/11205...
Some DX feedback: I'm finding it hard to remember to re-codegen, which results in cryptic schema errors. Have we thought about making the codegen somehow happen transparently?
codegen as in the custom codegen of non-universe envs? or of the universe too? same problem applies to both, but solution is probably different since universe is (currently) in the standard client and non-universe is the custom client
In this case it was in-universe, but yeah in general. I guess in-universe mostly affects Dagger contributors, and maybe out-of-universe could be solved by just regenerating at dependency bump time
Here's a checks TUI update. This is currently just using the same graph TUI as dagger run but with focus support integrated. Finally got the data flowing in all the right places after all sorts of hacking about. Next step could be to switch it to a more succinct tree UI somehow.
Yeah in-universe is the same problem as adding a core api right now. Though I have been questioning whether we actually should put universe envs in the standard codegen. If we instead just make it easy to add a dependency on a universe env (i.e. dagger env add universe://go universe://nix ... for adding a dep on something in universe), that might simplify a lot for us and create an incentive to use environments. Still unsure, would rely on making adding deps super trivial, but that's a good thing to do anyways, so we'll see what makes sense once we get to the point of actually merging this functionality into main.
But either way, for non-universe, totally agree we should help out more here. At the very minimum we should do what our SDK codegen does and check if there's a mismatch between the current generated code in the user's source and what would be there if generated again. We could either make that a warning or an error.
(cross-posting from a thread) Just pushed artifacts support; dagger artifact list lists them and dagger artifact export --output /some/path <artifact name> exports it to a local path. File and dir exports behave in obvious way, container is exported as a tar.
Can add more subcommands as desired (dagger artifact publish would be good for container, for file/dir it could either publish an OCI artifact or just be an error for now, not sure yet)
For user code, you can return either a File, Directory or Container. I don't love the approach I went with in terms of the API for all this yet, but works atm and was interesting to try out.
Basically, user code doesn't ever have to create an artifact specifically; instead all the artifact apis that weren't already on file/directory/container have now been added to each of those objects (version/withVersion, sbom, etc.). So the EnvironmentArtifact object is actually just a wrapper around file/directory/container that has the common fields between them (and dispatches to the correct method).
I think what we really want is to update our SDKs w/ support for graphql interfaces and then make EnvironmentArtifact an interface. Obviously too much work to update every sdk w/ that right now, but will be worth consideration once we're trying to merge this for real.
Agree + it can just be Artifact 🙂
Oh for sure, I forget exactly why I prefixed everything with Environment* (there was some conflict or something at some point probably due to lack of namespacing previously), but I'll go back and de-prefix everything now that it's not needed
Yeah I remember that and also don’t remember why 😁
Just updated demo code to have the python client actually have source code and a build step, I just gotta say even in this very early state it's SO ridiculously nice to have these absurdly simple dev loops. I change some source code in one or both of the dependency envs, call dagger shell dev-shell and everything is rebuilt and I can play with it directly. Same for dagger checks. And while the code for everything is already simple, it's only gonna get simpler as universe is fleshed out more and you can do higher-and-higher level stuff out of the box
We're very much onto something great here 
Oh also, as part of adding the above I updated dagger shell so that when it's called with no args (i.e. no shell entrypoint) it will instead drop you into the container that the environment itself executes in. I'm not sure that's exactly how we'll want to expose that functionality in the end (maybe, or maybe it should be a special builtin shell name or something), but it was really nice while trying to figure out how to package stuff in python because it gives me a shell where both the base python toolchain is pre-installed and the whole environment source code is already loaded in as my workdir.
More checks TUI progress: https://asciinema.org/a/h7X92OpBj3u6N93UaEl8H7Q0g
More checks TUI progress
I pushed some fixes to the above branch to make dagger shell work more reliably, mainly this commit: https://github.com/vito/dagger/commit/2ff893312c6e89b912326d5d0cfc0c3493621c42
Previously it would either hang (before attempted fix #1) or raise a cryptic error 90% of attempts (after attempted fix #1), after the above PR it starts reliably 👍
I'm also working on running it with the fancy TUI, which is something I've been meaning to support in Progrock in general (otherwise you can't run a Bass REPL against Dagger). It's going well, but it's forcing me to fix more things in the vterm package, so I'll see how much I can get done; we can skip if it doesn't make the cut.
Will probably just merge my branch when I'm back from 🦮🚶♂️since the other TUI stuff feels pretty solid now
I pushed some fixes to the above branch
@rocky harbor pushed the above changes, I'm investigating an issue with labels affecting v0.8.2 at the moment, but let me know if there are any issues! Also check out the new TUI, there are more changes since the update above 👀 - just didn't want to spam with asciinema links 😛
notably the Big Ugly Bar has been replaced with a Small Pretty Status Summary
Along with the rest of the changes is a medium-size refactor of the CheckResults API to be ID-able, which you might want to sync up on. Was just trying to align everything on the same patterns to make it easier to pass data around without guessing structures.
I was also thinking we might want to change "ID-able" things that we serialize (core.Directory, core.File, now core.EnvironmentCheckResult) to write to a different file from regular output, or something like that, so we can tell the intent more clearly, but haven't explored trade-offs there
@rocky harbor @thorn moat any chance you'd be available to show a sneak preview of the new demo to @bleak nest (ideally with @ember walrus at the same time), so we can start workshopping the docs, and overall storytelling? I'm thinking we could do in #911305510882513037 in case any Daggernaut wants to listen in 🙂
Yeah for sure, I just pushed a readme w/ a rough outline a few mins ago, currently in the process of rebasing some changes on top of Alex's commits. Let me just double check everything in working as expected still and I will be good to show
Erik Sipsma pushed the above changes I
Okay good to go whenever everyone else is! We also have time scheduled for 2 PST today to run through everything, but I'm guessing based on time zones that's not ideal for Vikram, so happy to now
Yeah timezone math is why we're trying to do it earlier
Ready too, @bleak nest @ember walrus ?
Yup, joining in 2 min
yeah that demo was great @rocky harbor 🙏
(I didn't want to consume everyone's day, but today is my "zenith day" so I'm happy to chat some more as needed, just ping me)
@rocky harbor I had a note about dagger checks being more exciting if there are at least 2 different kinds of checks. This addresses upfront the objection of "how is this better than just running go test natively?". But actually if we start with the combined environment, it takes care of that.
For follow-up discussion: how do we organize built-in extensions:
-
Maintenance burden. How many can we afford to maintain, and how do we know the number?
-
Namespacing. How do we avoid making the API a mess? Can we add intermediary fields for categorization? Like
query { linux { alpine { ... } wolfi { .. } ubuntu { ... } } }?
For follow-up discussion: so should dagger do be dagger cli, for consistency with other subcommands that match the entrypoint name?
dagger cli is going to create some weird sentences eg. "Use the Dagger CLI to run dagger cli"...
(not an objection, just a note)
Did we already consider dagger functions or dagger operations or similar?
well functions is taken (there is a different entrypoint called that, for scripting and composition) And yes agree with your note
I mean there’s dagger run we could coopt… 🤷
could we somehow land on our feet without breaking backwards compat?
For follow up discussion how do we
I've wondered about this exact thing previously since it is kind of confusing to explain the difference between dagger run and dagger do to someone uninitiated. I think if we made it such that dagger run --env ... becomes dagger do (or, equivalently, dagger run executed in an env dir, where it defaults to dagger run --env .), maybe that could be made to work??
But idk, then we have a single command that ultimately has pretty divergent behavior depending on subtle things
Which is maybe even worse than before
Interactive dagger shell progress, still not perfect but getting there. I'm deep in the weeds of ANSI escape sequences and ancient sparsely-documented terminal behavior, since this involves implementing a terminal emulator.
(It did before too, but people weren't running htop before, so it only had to slightly work!)
https://asciinema.org/a/PRVFm5tKJnCVKSee4zvcCPWi4
-
amazing
-
I’m surprised there isn’t a turnkey go terminal emulator package you can use?
none that I could find, there are about 10 abandoned/half-finished ones
Mine https://github.com/vito/vt100 is a fork of Buildkit's (https://github.com/tonistiigi/vt100), which is a fork of https://github.com/jaguilar/vt100, to give you an idea. 😅 It's like a game of hot potato.
Trying to run the latest zenith build and not sure what to do with this line of the README:
When running any
dagger commands, you will need to either prefix commands with./hack/dev ./bin/daggeror use a direnv-like setup that accomplishes the same.
Running that exact command is insanely slow, so I'm assuming there are env vars I can set to achieve the same result. But which env vars is not spelled out
(got it to work)
Yeah it's the same as the direnv setup used in the last demo, added more instructions now: https://github.com/dagger/dagger/pull/5443/commits/af2559a53b9aa3d272fd9773296a6a485ed9d37f
That looks great! It's always amazing to me how much arcane wizardry is needed to get that stuff working 🧙♂️
The ultimate stress test someday might be to play the notcurses demo, which blew my mind the first time I ran it and it started playing videos in my terminal 😄 https://github.com/dankamongmen/notcurses
Oo, added to my TODO list 😛
@here anybody want to see a sneak preview of zenith?
I'm interested in seeing the latest. 🙂
We had a demo scheduled but had a last minute cancellation, so might as well use the slot to show it to someone, cc @rocky harbor @thorn moat @ember walrus @sleek nest 🙂
Just when I have to go out too,
OK anyone interested, see you in #911305510882513037 in 2mn 🙂
For you Nic we'll schedule a demo anytime
@normal blaze I'll DM you to coordinate 🙂
ty 🙂
Hey guys, long time lurker, you've maybe seen me around (Disc name was luis guzman for a while.... lol) . Had to drop but wanted to say thanks for the adhoc demo and letting folks like me listen in. Really stoked for the zenith release!
Thanks Luis! Of course we remember you, you've been pretty active in the past! "lurker" isn't a very accurate description 😛 Glad you're as excited about Zenith as we are
FYI @normal blaze Project Zenith has reached a point where it makes sense to do such a call every week. This will be separate from the bi-weekly community meetup, more lowkey and less polished. We'll send notifications here.
Awesome, I’ll look forward to catching up
Quick demo notes @rocky harbor @thorn moat (before I forget) 🧵
well I was going to start on a refactor today but now I think I'll wait until zenith is ready 😂
ha 🙂 Well the underlying APIs won't break, so whenever you decide to do your refactor, it won't be wasted effort
ah awesome. where can I go to get started? 🙂
https://github.com/dagger/dagger/pull/5443
Look for universe/README.md
The README is extremely "high level" (a.k.a vague) right now, so if you have questions that's totally expected. Feel free to ask away here and we'll help out and flesh out the README more along the way
I’m still unsure how to just get a zenith build that “just works” without ./hack/dev shenanigans?
In order to run zenith you need a CLI built off that branch and an engine running built off that branch. That's what ./hack/dev does, builds the CLI and puts it in ./bin/dagger and builds the engine and runs it in docker container dagger-engine.dev. Then in order for that dev engine to be used you need to set the correct _EXPERIMENTAL_DAGGER_RUNNER_HOST value and make sure you are using the ./bin/dagger cli (which is easiest by just updating your PATH to prefer that dagger).
That's what these lines are saying basically: https://github.com/sipsma/dagger/blob/b0d40157b455e18aaef34e2fc5a6f85960cb79df/universe/README.md?plain=1#L4-L7
Would it help if I update the README to be more explicit like that? I am just coming in having run that thousands of times since it's the normal development workflow (for now), so I'm probably still assuming too much pre-knowledge
Pushed a quick update with that: https://github.com/sipsma/dagger/blob/ca5fc66308ed51b47d30eae655879eb0c787d6dc/universe/README.md?plain=1#L2-L11
In order to run dagger with Zenith functionality, you will need to build a Dagger CLI off this branch and build a Dagger Engine off this branch.
Our existing command for doing this is `./hack/dev`. That script will:
1. Build the Dagger CLI and export it to `./bin/dagger`
1. Build the Dagger Engine and run it in your local docker installation in a container named `dagger-engine.dev`
In order to ensure you are using the dev CLI+Engine; it's suggested to set these environment variables:
* `_EXPERIMENTAL_DAGGER_RUNNER_HOST=docker-container://dagger-engine.dev`
* `$PATH=$(pwd)/bin:$PATH`
* This assumes `$(pwd)` points to the root of the dagger repo, replace it with the actual root if that's not the case
I just removed the other stuff for now. The whole thing with wrapping commands in ./hack/dev is only useful for dev loops where you're making changes to the engine and need to rebuild it constantly. That's not the case for anyone playing with Zenith, and if you're developing on the engine you are most likely already familiar with that, so probably not needed in there.
yes please 🙏
I just read the whole thing and still don’t get it. Is the problem basically that there’s no registry that the dev dagger CLI can pull the corresponding dev engine image from?
Now I understand what you meant with zenith dogfooding zenith: there could be a zenith-dev environment that runs a mock registry.dagger.io service and the CLI could download from that
Also maybe the dagger CLI could use a “dev mode” escape hatch to do this without a wrapper script?
The dev engine image itself is being built off the code from that branch, you can't use the image from any of the registries we push to, they won't have the zenith changes in them. So instead ./hack/dev just builds the dev engine and runs it in docker. You could push it to a registry, but that would be extra complication
possibly via a custom “engine driver”?
Also to be clear, none of this is custom to zenith, this is just how it works today
I don't know really how that would work; the fundamental need is for a dev cli and a dev engine to exist, both built off your local code, that's what ./hack/dev does. Builds both and runs the dev engine. If the dev CLI itself was responsible for building the dev engine you'd create a bunch of catch-22 situations and also I think end up constantly rebuilding the engine everytime you run the CLI
I’m picturing hack/dev almost exactly, just as a hook rather than a wrapper. anyway it’s a side quest, not important
(hooks like this: https://github.com/dagger/dagger/issues/5583)
Yeah we've discussed various improvements but decided that it was better to just wait for what is now called Zenith 🙂 Once we can bootstrap ourselves, I think the workflow will change so that all we assume is you have a previously released dagger cli installed, we'll most likely delete ./hack/dev.
Then you'd just call dagger -e universe/dagger artifact export cli --output ./bin/dagger to get the dev CLI and something like dagger -e universe/dagger engine up (or whatever we settle on for running a service). Then you just use ./bin/dagger and you will be good to go
Can I join the session? Just want to understand how it works. 🙂
I would also be interested if you guys put together another session, it would be interesting to start thinking about integrations and the like
💯✋
that one was a one-off since a demo got rescheduled, but we have been talking about doing a weekly office hours type thing!
➕
Yep we're finalizing the dates and details but will let everyone know once that's settled!
FYI I think it’s an anti pattern to consume checks, commands, artifacts etc with codegen, because it makes 1) dynamic entrypoints and 2) vanilla graphql clients second-class citizens
Quick idea on slightly modified go sdk approach (🧵)
Insight from demos so far: one of the benefits of Zenith is allowing each dev team to package their dev environment into a standardized interface that makes it easy for other devs to use it, even if they're not familiar with the tooling. So it's not just about centralized dev-to-platform integration; it's also about decentralized dev-to-dev collaboration
FYI I'm starting this: https://github.com/dagger/dagger/issues/5655
in theory we could do all API bikeshedding in the PR directly, but in practice we're doing a lot of doing it in Discord. It seems like a fast-moving, well-curated issue would be a nice middle ground, wdyt?
I was just finishing up some docs and was gonna message about my plan for next steps, so good timing 🙂 My thinking is that the Zenith PR was great for putting the demo together and exploration, but we're not gonna merge that. It's a big pile of prototype-quality code and too much to really review or use for design discussions.
Instead I was gonna next start working on breaking out one component from it and open a PR for that. I was actually thinking Checks first since they seem to be fairly interesting. So that PR would include the API for checks and a clean implementation (using the lessons we learned from the Zenith PR)
So my thinking was that we would do the api bikeshedding in that PR, and just for checks to start.
Obviously we lose a little bit by not bikeshedding all the APIs all at once, but I also think that might get overwhelming. No strong opinion either way on that
If you agree with that though, we can start quickly by just sending out a PR with the API schema changes only for checks. It will take a few days to clean up all the relevant code (there's a lot, even discluding the other entrypoint types, and most of it needs to be refactored), so there will be plenty of meantime to bikeshed APIs before the implementation even catches up
Pushed a few updates to the Zenith branch:
- Improved go codegen, all environments use clients more consistently and less verbosely
- New
dagger env extend,dagger env synccommands for adding dependencies (currently just used for codegen) and refreshing codegen from changes to dependencies, respectively dagger env initnow also handles running custom codegen for Go environments (custom codegen is a TODO for Python)- An updated README with instructions on creating an environment (using those commands): https://github.com/sipsma/dagger/blob/zenith/universe/README.md#creating-an-environment
Like I said above, I am not planning on there being a ton more updates to that branch going forward, and instead am going to start focusing on breaking the monolith PR down and getting it into a mergeable state
Here's that PR for just checks: https://github.com/dagger/dagger/pull/5659
Consists only of schema for Environment and Check so far. I like having a PR for the api bikeshedding just because it's easier to leave comments on particular parts of the api, but I don't mind using an issue either. If others prefer using that issue, then I'll just use the PR for implementation side of things and have it track the API discussions.
Apropos of nothing, here's Bass running in dagger shell: https://asciinema.org/a/flETRxpizNQVuQai3TZ4SmLrv
Also shows functioning htop without any hacks needed anymore. Altogether this demo took a lot of work, just endless tiny details to get right. 😵💫 Pretty fun to work on though.
Gory details: https://github.com/vito/vt100/pull/1/files
It might be easy to miss, so it's worth pointing out that the fact that the progress UI is working inside of the progress UI is incredible 🤩 And also very useful for anyone in the future using dagger shell as their full blown development environment
vim also works. 😛 Dang, I should have have shown that.
In neovim I have a plugin that uses OSC codes to enable yank to actually copy to my system keyboard (despite the fact that I'm ssh'ing to a linux vm running neovim from my macbook). I'll save that feature request for the future though 😄
This one? https://github.com/ojroques/nvim-osc52
Yes exactly, super nice. But yeah don't worry about that, we're a ways away from that use case 😁
too late, already worrying about it. (this might be a freebie, since I already had to implement something similar)
@rocky harbor OK if I keep pushing to sipsma/zenith for more dogfooding and experiments? I just pushed before thinking since I still had it as my tracking branch.
Oh yeah of course! I just meant that I'm personally gonna focus on merging pieces of the PR now rather than adding major features. But that branch will still be what we use for demos until everything is merged and also the perfect place for experiments and stuff; we'll pull stuff from it into separate PRs until there's nothing left to pull 🙂
sweet 👍
I think I implemented OSC52 support, but to test it I want to install Neovim via nixpkgs, which led to implementing the Nix builtin env, which led to [...] - almost done now 😛
There was an interesting pattern I landed on, using checks to test the env itself: https://github.com/sipsma/dagger/blob/c9036df66e12404b02eb567feec72c5977a2d361/universe/nix/main.go#L51
It would be pretty cool if I could write that as an actual Go test, since it's so close (I even called it TestPkgs initially)
I had to tweak things to support returning just an error from a check, since I was too lazy to construct a result 😅
Nice! Now you can check yourself, before you wreck yourself (bah dum tiss)
But yeah that makes perfect sense, I was previously using shell to debug the env, why not use checks too.
NB: not sure if this is a bug, but (*dagger.Client).Pipeline returns a *dagger.DAG instead of a *dagger.Client now, which is a breaking change
┃ pkg/runtimes/dagger.go:89:37: cannot use client (variable of type *dagger.DAG) as *dagger.Client value in argument to runtime.container
┃ pkg/runtimes/dagger.go:117:37: cannot use client (variable of type *dagger.DAG) as *dagger.Client value in argument to runtime.container
┃ pkg/runtimes/dagger.go:138:37: cannot use client (variable of type *dagger.DAG) as *dagger.Client value in argument to runtime.container
┃ pkg/runtimes/dagger.go:171:37: cannot use client (variable of type *dagger.DAG) as *dagger.Client value in argument to runtime.container
┃ pkg/runtimes/dagger.go:214:37: cannot use client (variable of type *dagger.DAG) as *dagger.Client value in argument to runtime.container
┃ pkg/runtimes/dagger.go:492:12: cannot use client.Pipeline(fmt.Sprintf("import %s [platform=%s]", name, archive.Platform)) (value of type *dagger.DAG) as *dagger.Cli
┃ t value in assignment
┃ pkg/runtimes/dagger.go:507:12: cannot use client.Pipeline(fmt.Sprintf("docker build %s", build.Context.ToValue())) (value of type *dagger.DAG) as *dagger.Client val
Perfect, we should always enable maximal laziness 🙂 For the separated out checks PR, I'm currently working on cleaning up all the various kludge by unifying everything around Container. So whether the check result is being returned by invoking a env resolver or it's being determined by running a container set via Check.withContainer, it's all just a container. And then the server handles the polymorphism as much as possible.
The connection point being that I think we'll be able to handle that case and all the variations in a minimally convoluted way now.
Ah good to know! Yeah I'm not actually sure after all the dust settled that the changes I made to the existing codegen will be needed, they were just kind of picked up while getting the env codegen in place. So shouldn't be hard to fix that once we are merging all that.
Let me know if it's causing hardship currently though, I can patch it in the zenith branch quickly
Not blocked, I just tweaked the code, just wanted to flag 👍
Oh on this note, I'm not sure if there's any changes related to the stuff you did to the progress or anything else that can be cleanly separated out in small independent PRs, but if so, feel free to do so. Whatever little things can be split out and merged on their own will make our lives easier in the long run (that's the hope anyways)
Sure thing
@random beacon during the demo you mentioned you were initially confused by "environment" (but then no longer confused). Another words we considered is "DAG". Would that have been less confusing?
HI all!
We are starting a weekly low-key community call cadence for anyone who is interested in Project Zenith updates.
Come join us as we show the latest demos and get in the weeds of the project to discuss design, features, feedback etc.
**When: Every Friday at 9 am PDT
Where: Dev-audio on Dagger Discord server.** If you'd like an event reminder, I suggest going to the Discord events tab at the top of the server and clicking "interested" for each of the events. You can find the event invite for the next one on August 25th here:
The main difference from the regular community meetup, is that 1) obviously it's all about Zenith, and 2) it will be a mix of demos and work sessions. The call will be used to give updates and get work done in the open
@rocky harbor
https://asciinema.org/a/xQXpzYBeWnfHcBUjHzT7mCGBu
It's beautiful 🥹 Every day we are getting closer to me being able to delete my stupid devenv dockerfile. I have a lot on my "do when there's spare time" list right now, but I'm bumping up "run existing neovim env with dagger shell" up on it 🙂
Here's the implementation! https://github.com/vito/bass/blob/6d267b8f4ffb94661f7ded92801cf5a329e1da10/ci/ci.go#L33-L52
I'm curious, is the way osc52 works underneath the hood like "client sends esoteric byte sequence" -> "terminal emits another esoteric byte sequence that also embeds the whole string to be copied into the system clipboard"?
Nice, for better or worse, mine will be c.Container().Build(...) rather than nix. That is until I fully daggerize it of course
lol, yep - e.g. printf "\e]52;c;%s;\x07" $(date | base64)
Wow yeah, that explains why my IDE freezes for over a minute when I try to yank 1MB+ strings 😄
obligatory https://xkcd.com/2347/ but with terminal tech from the 70's
Also, looking forward to this! Don't want it to get lost in the scrollback 😛
HI all
More confusing, I think. Because one environment (as I understand it) could easily be many graphs. Like, all the commands in my environment could be totally separate functions that share no code at all; completely different graphs. It would be a weird thing to do, but the model totally allows for it.
true
actually I think it is an actual DAG:
- There is always a root node that initializes the environment
- Each query adds a layer to the DAG
Ohh, I think I see what you're getting at. You're saying that an instance of that reusable functionality is a dag.
Right, one that is not modeled statically, but dynamically as you query it
To be specific, are we looking for a word to describe the thing produced when you write a nameofthing/dagger.json file, or the thing produced when later, in code, when you call Client.NameOfThing()
Because they are different things, right? In oop terms the first one is the class and the second one is the object
To call the first one a DAG seems wrong to me. The second, possibly. Am I thinking about this the right way?
I’m wondering about what to call the former at the moment. Currently that’s “environment” but at some point we considered “DAG”. The former we can discuss too 🙂 Currently I call that a pipeline, made by chaining functions.
Actually I’m not sure. I think possibly both need naming.
you’re talking about “the code” vs “a running instance of the code” right?
My mental model pre-Zenith has been that there's this infinitely sized DAG of every possible Container, Directory, File, etc. that could possibly exist. The types (or classes, as mentioned above) are types of vertexes in that DAG. And our Core API lets you query that DAG, resolving each vertex type to particular vertex instances in the infinite DAG.
In that frame, the new types we're adding in Zenith like Checks, Artifacts, etc. are just new types sibling to existing core types like Container, Directory, etc. The true fundamental heart of Zenith is really just a way of allowing users to define ways of resolving vertex types to vertex instances. The new vertex types are just coming along for that ride because they are useful for our overall goal of improving usability.
So, that almost ends up feeling like an argument for dropping "Environment" and just calling the new feature "Extensions" (or equivalent term). You are extending the Core API with new ways of resolving vertex types to vertex instances.
That personally makes sense to me, but that's because I have my head buried in this 24/7. Fairly sure my eyes would start to glaze over if I heard the words "inifinite DAG" if I was coming from a totally different context 🙂 That's why I also personally don't mind the term Environment necessarily; it feels like a nice relatively-concrete idea to grasp onto without devolving into abstract stuff. But I nonetheless also get the confusion due to pre-existing usages of the term "environment" in other contexts.
Terminology 🚲🏠
Kinda neat: using the Nix + Go environments together to build one Container - https://github.com/vito/bass/blob/6da9489119b0ac015f1b39019c52ed70a2a87a2f/ci/ci.go#L62-L105
@sharp zealot @thorn moat The checks PR is waiting and ready for api bikeshedding 🙂 https://github.com/dagger/dagger/pull/5659 I slightly modified it last Friday, but I don't currently foresee any other changes to the API. Been squashing more corner cases and fixing the progress stuff today, but haven't had to change the API anymore 🤞
Yes. Sorry I missed this!
@rocky harbor I have time blocked tomorrow to work on the Zenith demo FYI. I took notes after the last batch, but didn't have time to sit down and act on it.
Sounds great! I have nothing on the calendar after the community meeting, so happy join
@warped canyon 👆 FYI in case you could get involved and get all of your extensions questions answered for the authoring guide 😉
OK I have 30mn now, and more free time after lunch (Pacific time) if we need it
Joining dev-audio in 2mn
Quick notes before going in there:
-
Thinking about terminology and the discussion here #1142151291108335698 . Wondering if we should tweak the demo flow to try any of the ideas in there
-
OK one specific terminology topic so I don't forget. "micro-pipelines" vs. "DAG". We talk about pipelines (and sometimes "micro-pipelines" to differentiate with the big, static yaml-defined pipelines). and we talk about DAG. But we never clearly explain the relationship between the two.
-
We throw lots of concepts all at once at the audience. Maybe we could start from the bottom up, with only functions. How you can compose pipelines from them. Then, after a digestion phase, add the next layer: convenience to expose your pipelines as checks, artifacts, CLIs, shells etc
-
We need a "DAG thinking 101". Not sure how or when, but we can use the demo to experiment. Clearly, to "get Dagger" you need to shift how you look at the problem - you need to adopt "DAG thinking". Right now we don't explain that at all - you have to survive long enough to "get it" on your own.
-
More cosmetic things. top hat vs. lower hat. Which sequence do we like. And can we switch to 4-hands: one person delivers each. Seems silly but can make a huge difference in clarity.
Be there in a few
For anyone who is interested, we are doing a low-key project zenith community call in dev-audio right now. Feel free to join if you want to see the latest or to ask questions
Quick list of interesting "side quests" we've discussed in the last few days:
- A simple web UI to show your artifacts, checks etc
- A simple CI tool that "replaces CircleCI in 100 lines of code" on top of Zenith (by plugging github events into dagger checks)
- Bringing back the VS code extension (see: web ui above)
- Writing an extension, duh 🙂
- A simple local registry backed by your dagger artifacts (so you can
docker pullstraight from your DAG)
Separately: starting a thread about the idea to use the word "configuration" in the UI, to see if it helps with the confusion caused by "environment"
Now that there are several PRs, what branch should I build from?
If you are iterating on the demo, just continue using the original Zenith branch: https://github.com/dagger/dagger/pull/5443
To bump the previous messages about this that got buried, the idea is that Zenith branch will still be what we use for demos until everything is merged and also the perfect place for experiments and stuff; we'll pull stuff from it into separate PRs until there's nothing left to pull.
The Zenith Checks PR is just the first thing we are extracting out from there, it has a cleaner implementation but only has Checks, so not good for demo iteration. Very good for API bikeshedding comments though! 🙂 https://github.com/dagger/dagger/pull/5659
I see so the Checks PR is downstream of the WIP branch?
Checks PR -> next candidate for an experimental feature merge?
Yes exactly. I wrote out the whole thinking on this here: #daggernauts message
I think it probably got lost in the thread though
It definitely did 😛 Thanks for reposting
One thing we did, that might help. At some point we merged into main a subdirectory just called "cloak" (and I think we did something for Europa). Initially it didn't have any code. Just a source of truth for "what is this project and where do I go from here"
Might be time to merge a zenith/ directory in the main repo. With a super basic README that is a source of truth for this kind of information
Yeah makes total sense, to start I'll just put in links to the PRs, "how do I build this" instructions, etc. And then subsequent PRs can update it as we go.
I'm in the far reaching depths of a can of worms related to some fixes to the Checks PR, once I make my way out I'll go send that README out 🙂
I'm happy to get it started, you have more pressing things to do
It will be my excuse to get a basic README going, too
Yeah if you have the time+desire, that sounds great too, thanks!
on it
Question @thorn moat . We have this capability of environments being anonymous objects in the API, which you can instantiate and reference at will. We imagined some cool use cases for this, like eg. you're implementing a test matrix which loads the same environment from N commits etc.
--> How much do we actually depend on that capability today? Ie. is it worth me exploring versions where the "environment" is simply the current session, and if you want a new environment, you just open a new session? It would make things simpler; but would also maybe make some of those use cases impossible (how do you reference things across sessions etc)
(moved this out of the thread because of topic creep)
Keeping in mind that those environments aren't perfectly encapsulated today... ie. schema stitching happens in the global namespace
I'd say it's worth exploring alternatives either way
There might be other ways to do that, and they might be even cleaner. iirc those APIs were very type-unsafe and didn't feel great to use; there's a chance that a more constrained API ends up with a different but more ergonomic pattern. (I'm being extremely vague here, sorry 😅)
Yeah, maybe dagger-in-dagger gets us further than we think in those scenarios
(it's the "option-2.graphqls")
you had me at "modules"
I've been wondering that lately, we're so close already with "functions" which was like the first name we unanimously agreed on
you make a bunch of tradeoffs, later the preconditions for your tradeoff change completely, but you never go back to revisit the tradeoff, rinse and repeat 10,000x
lol, yep
oh right, “module” and “package” I remember objecting to because it sounded like a regular code import, instead of an API extension
worry being that developers expect everything to work exactly like a regular Go or NPM package , when in fact it’s subtly different (codegen etc)
but maybe that worry was unfounded?
Yeah, that's true, you'd have to be clear whether you mean Dagger module or Go module. (for example)
It meets the bar for exploring further though
Looks great! Merged it
--> How much do we actually depend on that capability today? Ie. is it worth me exploring versions where the "environment" is simply the current session, and if you want a new environment, you just open a new session? It would make things simpler; but would also maybe make some of those use cases impossible (how do you reference things across sessions etc)
We rely on it currently to implement the CLI. E.g.dagger checksneeds to handle arbitrary envs, so it just lists the checks and calls them that way.
In general, while that sort of "dynamic" api is definitely only for power-users, it's pretty invaluable there. It's also not a burden to support in terms of the implementation at all, it kind of just falls in place as part of having all the underlying plumbing to support envs/entrypoints anyways; not work on top of that.
Keeping in mind that those environments aren't perfectly encapsulated today... ie. schema stitching happens in the global namespace
One thing worth noting is that right now you can't use an environment without loading it and stitching its API in; but it would be extremely trivial to modify it such that the schema stitching is optional (just a matter of a single optional parameter toenvironment { load }). So then if you want to dynamically load a ton of envs and call them dynamically, you wouldn't need to worry about conflicts.
In general the schema stitching is useful for:
- Raw graphql clients, since they can make high level queries like
{ myCoolEnv { myCoolCheck { result { success } } } } - Codegen, since our existing codegen relies on the actual schema existing.
- However, this is not a fundamental requirement at all. We could change it so that codegen clients make the "dynamic" api calls rather than relying on the schema being stitched.
- The barrier to that is mainly just that it will take a lot of time+effort to update everything.
Having written that out, it does make me wonder if we should put more serious consideration into whether we actually need the schema stitching anymore.
It used to be a pretty hard requirement because it was baked in everywhere; e.g. we used to require SDKs to actually generate a graphql schema file and output that. But we've now replaced that aspect with the whole "environment builder api" (i.e. Environment().WithCheck(...).WithArtifact(...), etc.).
Getting rid of that made implementing the SDKs quite a bit easier, but I guess it also made it much easier to skip the schema stitching too as a side effect.
The remaining pain of changing our codegen to use the "dynamic" api instead of relying on the schema being pre-stitched is real, but it does feel like it would simplify quite a bit in the long term. So it could be worth just eating that annoyance now rather than deal with it perpetually...

Raw graphql clients would be our sacrificial lamb in this, but I wouldn't be surprised if most of the use cases for a raw graphql client end up needing the dynamic api anyways, in which case they are completely unaffected
I confess I don’t really understand this part. What would it mean to remove schema stitching?
-
The only graphql API to interact with an environment would be the "dynamic" ones that rely on querying for names of entrypoints and invoking them based on those names (which are all just strings, thus "dynamic"). e.g.
{ env { load(...) { check(name: "myCoolCheck") { result { ... } } } } -
Our codegen would present the same type safe interface as today though. The inner implementation would just change so that rather than relying on the schema being stitched in an creating graphql queries based on that, it would be implemented by calling the dynamic API, e.g.
func (env *MyEnv) MyCoolCheck() *Check {
return env.Check("myCoolCheck")
}
- Raw graphql clients could no longer use stitched schemas like
{ myEnv { myCoolCheck { result { ... } } } }. They would have to use the dynamic API. Which is a sacrifice, I'm just not sure how much of one in practice relative to the possible benefits of entirely avoiding the namespacing problem.
oh I see! first reaction is I think the schema stitching is too valuable to give up
because it makes graphql the source of truth which feels right at various levels
Yeah I agree, this would be a divergence from graphql. And no longer having it as a source of truth is what causes it to be painful to go and update all the SDK codegen to handle this, since it currently is all based on the graphql introspection.
But nonetheless I feel torn since removing the headache of namespacing is so tempting. It's probably worth keeping this in our back pocket if nothing else.
Is namespacing problem that bad ?
I don't know yet because we've pretty much just ignored it so far 🙂 The main potential source of problems are environments w/ overlapping names that get loaded at the same time. And honestly, depending on how we approaching versioning, if we end up allowing two versions of the same env to be loaded at different points in the dependency DAG, that's essentially the same sort of problem.
IIRC our most recent thoughts on this were that if we don't want this to be an error cases, we'd need to stitch in objects with some sort of unique id (combination of name, version, and hash of the env definition). So we'd be stitching in like MyEnv_v_1_2_3_abcdef123 rather than MyEnv. Which should work, but obviously does make things ugly for raw graphql clients anyways. (edit: not sure if that's true since it'd just be object names, which usually aren't in queries; only field names are there)
So it might not be that bad if that idea works out. And it's not like we've really thought through all that in detail, I'm sure we could also come up with more ideas on how to approach it.
So yeah, that's a good point, it's probably not worth changing everything right now to avoid, just worth keeping in mind if namespacing ends up harder than it currently seems
Warning: this is deep rabbit hole, feel free to ignore. 😁 The sort-of-content-addressed types/functions reminds me of https://www.unison-lang.org/learn/the-big-idea/. Lots of curiosities and some parallels to what we're doing. Haven't found a reason (or time) to really dive in, so still don't know what to make of it myself.
I'm going to be trying to "sell" Dagger into a client, could I get a small update on the state of Zenith, when might we expect the ability to reuse JS pipeline from Go?
Read through that article, @thorn moat. Super interesting. I love the idea of codebase as database of immutable+hashed+cached syntax trees.
Looking at the README to try the demo out and notice the same directory and environment name being used for the go and python examples if I follow from top to bottom. Guessing that we'd want two different dirs and environment names? Or could I use two dirs and init an environment with the same name in each? Or one dir and init two differently-named enviros?
https://github.com/dagger/dagger/blob/19fe2de0c22a485d9456b4ed471d97346566af3c/universe/README.md
mkdir -p ./example && cd ./example
dagger env init --name example --sdk go --root ..
...
mkdir -p ./example && cd ./example
dagger env init --name example --sdk python --root ..
Is the second example env (python) going to clobber the first one (go)?
Or should it throw an error?
IMO the 2nd command should fail, a-la git, wdyt?
Yeah the intention (but not clear) there wasn't for it to be followed top-to-bottom; the different sections for different languages were supposed to be "siblings", so you'd branch out to the language you want to write your env in. I'll update it to make that more clear.
Also yes, there is code that is supposed to enforce this, it should fail if there is already a dagger.json rather than overwrite it: https://github.com/sipsma/dagger/blob/179525ff35a1e4c5b338472e47d350d4dbee8fb2/cmd/dagger/env.go#L118-L118
I have a PR I want to make against your dev branch (README stuff) @rocky harbor but not sure what's the best way. PR against your repo?
Maybe time to move the dev branch to dagger repo so we can push to it in parallel without the overhead of PR to a fork?
You can also just push directly to sipsma/zenith. That's what I've been doing, with a heads-up
Yeah just push to the pr directly. I don’t mind a dev branch on the dagger repo either but we don’t need to PR stuff to there, just need PRs for the stuff going into main 🙂
Demo notes...
- I want to try some of the new terminology we talked about... Modules, configuration
- We need diagrams
- Need to talk about the component system first, then move up to higher-level entrypoints as we discussed
- Still need to show the GraphQL API more obviously (simple queries and/or simple web UI)
- We haven't resolved CLI vs command vs tools..
- I worry that we're moving too much work to the SDKs. Maybe time to make a list of things we could move to the core (free for all SDKs)
Just finished walking through the demo, interested in starting to build some environments, but seems a little challenging outside dagger repo.
Is it supported to init a zenith dagger env with a root from git? I see some references to git support here, but getting an error when running the below.
Example:
dagger env init --name foo --sdk go --root 'https://github.com/sipsma/dagger?ref=zenith'
# codegen runs, things seem ok, I can write a pipeline in `main.go`
dagger checks
➜ ci git:(master) ✗ dagger checks
• Engine: 0a64c1c084ee (version devel ())
• Engine: 0a64c1c084ee (version devel ())
⧗ 2.83s ✔ 8 ∅ 7 ✘ 1
Error: failed to load environment: environment config path "/Users/steven.tobias/repos/misc_projects/foo/ci/dagger.json" is not under environment root "/Users/steven.tobias/repos/misc_projects/foo/ci/https:/github.com/sipsma/dagger?ref=zenith"
A portable devkit for CI/CD pipelines. Contribute to sipsma/dagger development by creating an account on GitHub.
(demo notes) May want something like dagger env override similar to go mod override where if you want to dev on a dependency env you can temporarily use a local checkout of it, even if that dep is git://
I'll join dev-audio around 11:30 pacific in 90mn if anyone is around
sorry I can't join before
(ping me if I forget to join at that time)
I worry that we're moving too much work to the SDKs. Maybe time to make a list of things we could move to the core (free for all SDKs)
For this specifically, that's being done in the Checks PR, maximizing how much is done by the engine and, for what's left in terms of what the engine needs from SDKs, it's encoded into a set of "internal" graphql apis. Alex asked about this too yesterday, I outlined some more details here: https://github.com/dagger/dagger/pull/5659#discussion_r1309460335
I m going to be trying to sell Dagger
Thoughts from our chat (thanks Dagger team for the presentation!). I wanted to spend some time anchoring Zenith in some real world use cases and unwrap this a bit more (these may not have immediate answers, they're just top of mind):
Envision a system with two different components implemented in two different langues. One is a Golang backend system, and the second is a Typescript frontend system. Let’s identify some users for our stories.
- Platform engineer (Alice)
- Backend engineer (Bob)
- Frontend engineer (Charlie)
Alice wants to create a shared functions library for Bob and Charlie. An example that Alice would like to expose to everyone is "uploadS3", a function that takes a Dagger file or directory and uploads it to S3 bucket. This is a generic function that both Bob and Charlie will use in Go or Typescript since they each need to upload things to s3 as part of their pipelines.
Alice wants to create a CLI and pipelines zenith environment that exposes the following composable commands and artifacts:
- Build (calls frontend build and backend build)
- Test (calls frontend test and backend test)
- Publish (Calls frontend publish and backend publish)
- Deploy (Calls frontend deploy and backend deploy)
Alice also wants to allow Bob and charlie to be able discover each other’s pipelines from the CLI and call things from them
What does the above setup look like for end users in Zenith?
How might Universe come into play here, especially for Alice’s “uploadS3” function?
What might be a typical workflow for someone who just wants to be handed an environment and be able to build and test it with no local dependencies?
What might be a typical workflow for Bob/Charlie, who want to modify their code but not the others
What might be a typical workflow for Alice, who is responsible for exposing integrations to end users?
Who is responsible for writing checks/artifacts in this setup? Is it bob/Charlie or Alice? Or maybe it’s up to the end users?
Conor's test case
Running through the README of the Zenith PR #5443
I'd love feedback from
as it sits silently for a while. Maybe like
generating Go code...
or similar
Finally getting around to reviewing the Zenith Checks PR, sorry that it took so long. I hadn't really realized that it was the desired place for API bikeshedding.
Yes that one has been on my TODO list for the Zenith Checks PR too; I'll pop that one now and then after that will be support for git deps (cc @warped canyon @lapis willow), will backport all that to the Zenith branch too
Question that came up from chatting with @wintry prism earlier:
Now that the top level pipeline code is running in a container rather than host runtime, does that basically restrict us from using os.Getenv in pipelines, or is there some way around that?
As of right now, the solution is that you pass any env vars as parameters, which works out okayish, e.g.
func MyCommand(ctx context.Context, foo string) (string, error) {
...
}
Can be invoked like dagger do my-command --foo $MYFOOVAL
We've talked about formalizing a whole api for extensions to request access to host env vars (and for hosts to selectively grant access), but it doesn't exist yet and will be a medium-size project of its own most likely.
Makes sense!
Ah, so that's why with Zenith we have dag.Host().Directory(".") as with SDKs, but we've always leaned on the language for dealing with env vars.
The calling shell's state is a more variable beast from the filesystem state of a host too, I suppose. Either way you have to do a snapshot of that state at some point.
Yep, that is a whole topic we'll need to cover in our docs (and maybe even consider renaming some APIs to improve clarity). Basically, dag.Host() always refers to the "host" of wherever it's being called; it doesn't refer to the "caller host" (as in the host of the CLI).
Which is great for consistency and makes it possible for envs to do stuff like write a local file and then load it into dagger (we already rely on that in the port of dagger's integ tests to be a Check in the Zenith Check PR).
It's also great for security-by-default and reproducibility since envs are by default only able to refer to their own resources, not just grab arbitrary stuff from the caller's host (or from other envs' hosts).
It's going to be a pain if you have various env vars like in https://docs.dagger.io/620301/azure-pipelines-container-instances#step-2-create-the-dagger-pipeline (leads to making a makefile or bash script to wrap the dagger cli call), we def need a hook/config for that.
But I have wondered if Host is the right term anymore. I'm not sure what would be better, but a bad example of a more clear name would be like dag.MyFilesystem() as a replacement for dag.Host().Directory. That would be more clear, but obviously MyFilesystem is clunky 😄 Maybe something along those lines though
Yeah totally agree
Seems like a good opportunity for extensions to 'auto configure' for things like azure/aws/gcp/etc
In that case those are account details and secrets so you need to provide them. I'd rather use a 1password secrets provider from code rather than passing on env vars though.
Most of the time, for sure. Sometimes you want to rely on the instance profile which we'd need to make sure 'just works'
IMO we need to revisit the host access API so an env can declaratively say “I need these things from the host” and the user can decide whether it trusts that env to get access or not
Yes agreed that's what I was referring to here #daggernauts message
sorry had missed that. yup agreed 🙂
btw I plan on reviewing/bikeshedding checks pr today
sorry slow to get going
wondering how much bikeshedding I can fit in comments but will try
No worries! And if the PR comment format becomes a limitation, no problem at all discussing elsewhere. We can just try to use the PR's schema as the "current schema intended to be merged into main" and update it as needed from discussions elsewhere
first pass at zenith on the greetings-api project: https://github.com/kpenfound/greetings-api/blob/zenith/ci/main.go (not working yet)
Contribute to kpenfound/greetings-api development by creating an account on GitHub.
Kyle Zenith first pass
A few questions on Zenith internals...
- @rocky harbor on the checks PR, I see some types eg
Checkseem to be the same for consumer and provider: there isresultto query the result, but alsowithNameetc for registering the actual check function. Is that right?
Another question about zenith codegen…
TIL that go's default json marshallers URL escape every string, which explains why I thought I was going insane the last hour
: https://go.dev/play/p/7v6waY3ppYI
Registering functions?
Pushed fixes for dagger env and friends not showing output (cc @wintry prism) + support for git deps to the Zenith (and Zenith Checks) branch (cc @warped canyon @lapis willow).
Updated docs with this section: https://github.com/dagger/dagger/blob/4e0ad448ad3041fb5ad18550399a07e8242d96cd/zenith/EXAMPLES.md#referencing-environments-in-git Copying the main part here so it's not buried since it's kind of cool to see:
For example, you can run this to execute the current demo:
dagger checks -e 'git://github.com/sipsma/dagger?ref=zenith&subdir=universe/_demo'
Or you can execute this to add a dependency on the demo server environment:
dagger env extend 'git://github.com/sipsma/dagger?ref=zenith&subdir=universe/_demo/server'
The git:// format is awful, we need to improve that, but was simplest to start with
Request: can we retire the word “entrypoint” as a load-bearing term in the UI and API… I know it’s annoying but I think the way we use it today will end up confusing people. And with the ongoing terminology refactoring & bikeshedding, the less words to worry about, the faster we can move…
To be replaced with "function" ?
If so, SGTM
yeah I think so. Wondering if ut would end up overloading it if we start talking about “regular functions” and “special functions” but worth a try
alternatively, instead of messing with checks pr, we try a parallel experiment, a branch that only talks about functions and not checks (yet). And that branch doesn’t have the word entrypoint. Then we compare.
Hey Daggernauts! If you want to join the open project discussion, feel free to join dev-audio right now for the Weekly Zenith Community Call. It is a low-key open forum to discuss the project and answer any community questions. Everyone is welcome!
FYI I'm trying to clear my calendar to resolve the checks PR bikeshedding from morning call, I don't want to throw a wrench then walk away.
Free to meet anytime today
I'm free in another 15mn or so
@latent trellis Thanks for your time today! We're excited to finally bring you closer to the extension experience that you wanted 🙂 @warped canyon is working on a lot of the examples and documentations for it, so I mentioned that you'd be a great Daggernaut to get feedback from 😁
He may reach out as we get further along
@rocky harbor maybe we should leave the Checks PR untouched, and start another "Functions" PR?
to preserve the history so far?
Doesn't matter to me either way, I'll have the history in my fork whenever we need to refer back to it. If it's simpler to start anew in terms of discussion I'll just cherry-pick as needed 🙂
I think it might be simpler to reset the discussion yeah
Cool, if you have an updated schema proposal from the other thread that sounds like a good first commit for it 🙂
Yeah that makes sense. We can all push to each other's forks once it's a PR so it really doesn't matter who opens it
@rocky harbor so I rebase from main, with only a README and mock graphql schema, and you'll cherry-pick from other branches on top?
Yep!
I've been reworking the "internal SDK" api to account for generalized functions, so we'll have that to bikeshed too. I'll push it as a separate schema file though to keep things less confusing.
you know that could be a mutation too
not the constructing of the "$THING" - but the registering it
installModule is called from the "outside" and installFunction from the "inside" right?
Yeah, I mixed the two while typing it out, I will unmix them in the PR
what do you currently call the code executed by the engine, that "runs" the module, registers its functions etc?
The module's init function?
The module's entrypoint? (confusing I know 🙂
In comments in the codebase I think I use terminology like "environment initialization", so yeah if we're going for an official term "module init function" sgtm
This may be a stupid idea: could there be a Module type that represents both 1) what a client gets when loading a module source directory, and 2) what a module init function gets when registering all its types and functions?
The former is the "frontend" of the module. And the latter is its "backend" if that makes sense
It is even underneath the hood using the same plumbing we use to invoke functions, it's just a special invocation that requests the module definition as a return value
IIUC that's how it's implemented currently
Nice, ok let me try something in that PR then 😛
Let's put my last 15mn of freedom to good use
What if I load a module from a source directory, then add my own functions on top of that? Would that kind of mix & match work seamlessly?
The idea is that installFunction is only valid to be called during module initialization, it will return an error any other time.
I've thought of ways of loosening that restriction, but I'm not sure it's worth the complication.
eg. query { module { fromDirectory("./ci") { withFunction(name: "hello", ...) { id } } } } --> If I install this module, will it successfully install my ci module + a monkeypatched "hello" function?
EDIT: assume I'm doing this during initialization of my own module, to account for your last message
this is really to test my own understanding of the plumbing
EDIT: assume I'm doing this during initialization of my own module, to account for your last message
Ah I see, yes actually we literally already do the equivalent of that in the demo where the CI environment registers artifacts from other environments:
dag.CurrentEnvironment().WithArtifact(dag.DemoServer().ServerImage())
Which results in the ServerImage artifact being part of the CI environment's definition, but when it comes time to actually evaluate ServerImage, it's DemoServer that's invoked.
So yeah that all works
Where's the best withFunction and type Function to plagiarize for the PR?
@rocky harbor I need to switch to childcare mode before the PR is fully ready... But will very gladly send it tonight after putting the kids to bed. I did want to share this snippet 🙂
type Module {
"""
Serve a module's API in the current session.
Note: this can only be called once per session.
In the future, it could return a stream or service to remove the side effect.
"""
serve(workdir: Directory, environment: [String!]): Void!
withFunction(id: FunctionID!): Module!
}
extend type Directory {
"Load the directory as a Dagger module"
asModule: Module!
}
Just trying a fun alternative to the mutation
Sounds good! And yeah I like asModule, easier to chain ⛓️
also addresses @thorn moat 's concern about "from"
True!
Note the serve, that's the part that would replace the install... mutation
the idea being that maybe down the road, it doesn't have to be a special case with side effects at all...
once the API has a stream multiplexing feature - which we know we'll need anyway
- "please serve this module's API"
- You got it, please head over to stream ID 'foo' for a working http session with that graphql API loaded
You got it, please head over to stream ID 'foo' for a working http session with that graphql API loaded
Interestingly enough,dagger shellin the demo works by adding a field toContainercalledshellEndpoint, which returns a subpath of the http server that can be connected to over websocket and will stream the shell.
We wouldn't even need streaming or websockets for this though. We already today could change serve to just return an http endpoint that will serve the schema
All the plumbing to support that exists across various branches, would just need a little surgery. The part that would cause some actual elbow grease to be needed is the fact that SDKs would all need major updating
Which inclines me to think it's not worth it at this exact time. But should leave it open as an option in the API maybe
Yes totally this would be a future improvement
in the meantime module.serve would take over the current session
but the API style would set the stage for that future improvement
this really feels like all the pieces are falling together
Thank you @sleek nest . I was really looking for these features and I have to say, it already looks better than what I had in mind/expected.
I'll try to play with the existing examples in the coming weeks. @warped canyon happy to give feedback.
My initial feedback based on the demo is I really like that the interface is centered around the common use cases of a build system. Dagger is no longer just a portable CI environment, but an actual build system at this point which is great. It's an easier sell to developers IMO. (Especially when you tell them they can use any language, not just Starlark :D)
I'm still not used to environment as a term. Module or package would better reflect the reusable aspect. Or you could just come up with some fantasy names, like Orbs (although I pretty much hated Orbs, so don't use that one 😄 ).
Thanks for the feedback! Yes we’re going for modules
getting that PR going. sorry for delay
Another Go SDK approach
I saw the XRC2 post yesterday, and I was wondering if Zenith is far enough along to be worth trying. In addition to the source graph functions I mentioned earlier in a seperate thread, how would dagger check handle the following?
I have 5 distros that I want to validate against, each each distro runs a cmake ctest suite with something like 350 unittests. How can I help Zenith report this from the Python SDK?
Ideally, I would be able to see primarily that say Fedora 38 is green, but maybe centos 7 has a build failure, and centos 8 has a single test failure relating to say some function (e.g. unit test 119 failed). What would this look like with dagger check? What code do I need to write in the SDK?
Can check type actions also have artifacts as outputs? eg. code coverage reports, lint results, etc
That's a good question. I think it should, but I haven't seen this being discussed. Even though you can make your function an artifact, you'll also want the enhanced UI you get from checks surely.
Absolutely!
Also, I would probably want those reports uploaded somewhere after the checks run in CI.
@kind carbon @latent trellis we got a lot of questions like this (basically “how strict is the straight jacket and how do I wiggle out of it?”), and for the next experimental release we’re going to remove the straight jacket and see how it feels. Specifically we’re shelving (for now) specialized entrypoints like artifact, check, command, shell - in favor of general-purpose functions that map to graphql resolver and therefore are not limited at all.
Flipside is that there will be less convenience and “magic” for users, and each project will still need to reinvent some conventions on how to name their functions, what arguments etc.
The idea is that once we get more usage with functions, patterns will emerge and we can incorporate them gradually into the core.
Have we decided on how to invoke the general-purpose functions from the CLI?
Have we decided on how to invoke the
Makes perfect sense!
nesting + Unix sockets/C2H networking
@latent trellis thew PR for what I described above: https://github.com/dagger/dagger/pull/5757
For those who couldn't attend the Zenith Call today, we talked about the new Modules+Functions approach today (see above linked PR), some of the new possibilities it unlocks.
Biggest takeaway for me were the big +1s from @spiral whale and @warped canyon to support for extending existing types like Container from Modules, which I was a bit surprised by since I thought it would be a niche feature at most, but bumped much higher in priority in my mind now 🙂 Sounds like it will make a lot of code cleaner by being a more advanced version of .With essentially. Fortunately, the plumbing so far is mostly setup to handle that, so won't be a huge lift
Love that
FYI, big week for Zenith! Going to need help https://github.com/dagger/dagger/pull/5757#issuecomment-1713142436
FYI: this discussion veered towards Zenith at the end: #1149771633863688314
FYI, I'm writing an issue on dagger script to get us started, since I think it's a linchpin of the xrc2 design. And one of the medium-to-large pieces we'll need to build on top of @rocky harbor 's branch while he's away
Still WIP: https://github.com/dagger/dagger/issues/5774
(added rough architecture diagram)
@thorn moat with the latest changes to #5757, when I run
./hack make engine:build I get a dagger binary in the bin dir that is killed immediately after I invoke it:
dagger-fork ➤ which dagger git:zenith-functions
/Users/jeremyadams/src/dagger-fork/bin/dagger
dagger-fork ➤ ls -al `which dagger` git:zenith-functions
-rwxr-xr-x 1 jeremyadams staff 32418274 Sep 12 07:31 /Users/jeremyadams/src/dagger-fork/bin/dagger
dagger-fork ➤ dagger git:zenith-functions
[1] 50441 killed dagger
I also see a strange env var that is set
_=/usr/bin/env
@wintry prism @warped canyon @bleak nest @ember walrus Wrote up an initial walkthrough.
- From 0 to running a Zenith module: https://github.com/shykes/dagger/tree/zenith-functions/zenith#how-to-test-it
- Writing a Zenith module: https://github.com/shykes/dagger/tree/zenith-functions/zenith#creating-your-first-module
There's a lot more to be written, but it's a start!