Dagger 0.8: Big Summer Clean Up
August 3, 2023
Aug 3, 2023
We're continuously improving and adding features to Dagger and occasionally, those improvements require us to make breaking changes to the Dagger API. Dagger 0.8 introduces several such breaking changes and this blog post explains the most important ones.
Be sure to consult the Dagger 0.8 release notes for the complete list of changes, breaking and otherwise, and to the update instructions for information on how to update to Dagger 0.8.
Container.exitCode
API field removed
Dagger 0.8 removes the Container.exitCode
field. As a result, command execution status must now be retrieved with ExecError
in the SDKs:
Additional information
Using the exit code of a command to check if it failed or not never worked. Consider the following Go example code:
exitCode, err := ctr.ExitCode(ctx) if err != nil { return err } if exitCode != 0 { // ❌ Never called!! 😕 fmt.Println("FAILED") } else { fmt.Println("PASSED") } return nil
When a command fails, the API returns an error and a null
result (example). So, in the previous example, .ExitCode(ctx)
would always return 0
(zero) on success, but nil
on failure. However, the actual exit code value of the failed command is in the error itself.
The recommended approach is to check dagger.ExecError
to specifically handle errors from an exec operation. The ExecError
struct gives easy access to various properties related to the failure.
Here's a revised Go example that demonstrates this:
_, err := ctr.Sync(ctx) if err != nil { var e *dagger.ExecError if errors.As(err, &e) { fmt.Println("FAILED") return nil } return err } fmt.Println("PASSED") return nil
Note: If your container doesn't define any WithExec()
operation, Sync()
won’t execute the container’s entrypoint and/or default arguments like Stdout
and Stderr
. You need to add an empty WithExec(nil)
for that. However, it’s equally useful if that’s actually what you want - for example, building from a Dockerfile
without executing the defined ENTRYPOINT
or CMD
.
In Node.js and Python exceptions are used instead. For example, here's how it looks in Node.js:
try { await ctr.sync() } catch (e) { if (e instanceof ExecError) { console.log("FAILED") return } throw e } console.log("PASSED")
And in Python:
try: await ctr.sync() except dagger.ExecError: print("FAILED") else: print("PASSED")
Refer to the Dagger Cookbook for more examples of error handling with Dagger.
For more information on this breaking change, refer to the following GitHub issue:
Host.envVariable
API field removed
Reading environment variables from the host with Host.envVariable
is no longer supported. Use the programming language's built-in features for this instead:
Go: Replace
Host().EnvVariable()
withos.Getenv
Python: Replace
Host().env_variable()
withos.getenv
Node.js: Replace
Host().envVariable()
withprocess.env
Additional information
Host.envVariable
was previously required to turn an environment variable into a secret (with HostVariable.secret
, also removed). This is no longer necessary and to avoid confusion, it has been removed in favor of using the language's native ability to read environment variables.
For more information on this breaking change, refer to the following GitHub discussion:
Other deprecated API fields removed
Dagger 0.8 removes the following API fields, deprecated since Dagger 0.3.6:
Container.exec
: Replace withContainer.withExec
Container.fs
: Replace withContainer.rootfs
Container.withFS
: Replace withContainer.withRootfs
Host.workdir
: Replace withHost.directory
andpath
set to "."`
Dagger 0.8 also removes the following secret related API fields, deprecated since Dagger 0.5.0:
File.secret
andHostVariable.secret
: Replace with the safersetSecret
. More information is available in the documentation on using secrets.
For more information on these breaking changes, refer to the following GitHub issue:
Optional keyword arguments enforced in the Python SDK
Dagger 0.8 now requires the use of keyword arguments when they’re optional.
Additional information
All API field arguments in Python are grouped, with required arguments first and optional arguments later. Until now, you could choose to use either a positional or keyword argument. With Dagger 0.8, you need to use only keyword arguments when they’re optional. For example:
# ❌ this will now fail ctr.with_exec(["foobar"], None, None, "/out/stderrr") # ✅ use this instead ctr.with_exec(["foobar"], redirect_stderr="/out/stderr")
This improves readability and is incidentally more consistent with the Node.js and Go SDKs, since they both use a separate data structure for the optional arguments.
For more information on this breaking change, refer to the following GitHub issue:
Synchronous client removed from the Python SDK
Dagger 0.8 removes SyncClient
and supporting code.
Follow the instructions on how to migrate to the asynchronous client, and refer to the resources section to learn more.
Additional information
The Python SDK used to have two clients: Client
(asynchronous, supporting coroutines) and SyncClient
(synchronous, supporting only regular functions). This led to confusion, fragmentation and a higher maintenance burden.
Most importantly, non-blocking I/O works best with Dagger, so the synchronous client had a big performance bottleneck and we didn’t see any usage or demand to justify keeping it.
For more information on this breaking change, refer to the following GitHub issue:
Client export modified in the Node.js SDK
Dagger 0.8 makes Client
a named export (instead of default) in TypeScript.
Additional information
Use the example below as a reference to update your Dagger pipelines written in TypeScript:
// ❌ this will now fail import Client, { connect } from "@dagger.io/dagger" // ✅ use this instead import { connect, Client } from "@dagger.io/dagger" connect(async (client: Client) => { // ... })
For more information on this breaking change, refer to the following GitHub issue:
Other changes
There are various other changes, bug fixes and improvements in this release. For a complete list, refer to the respective release notes:
Engine & CLI 0.8.0 changelog and documentation
Go SDK 0.8.0 changelog and documentation
Python SDK 0.8.0 changelog and documentation
Node.js SDK 0.8.0 changelog and documentation
As you are reading this, there is likely to be a 0.8 patch release. To benefit from all bug fixes, please remember to upgrade to the latest 0.8 patch release.
It's also worth pointing out that Dagger 0.8 brings all SDKs together under the same version number, matching the Engine and CLI. This bump will make it easier to know which versions are compatible to update together. Learn more about updating Dagger.
If you get stuck or have additional questions about this release, please reach out to us through this 🐙 GitHub Discussion
We look forward to releasing more features soon! In the meanwhile, if you have general feedback or would like to suggest new features or documentation, let us know on Discord or create a GitHub issue.
We're continuously improving and adding features to Dagger and occasionally, those improvements require us to make breaking changes to the Dagger API. Dagger 0.8 introduces several such breaking changes and this blog post explains the most important ones.
Be sure to consult the Dagger 0.8 release notes for the complete list of changes, breaking and otherwise, and to the update instructions for information on how to update to Dagger 0.8.
Container.exitCode
API field removed
Dagger 0.8 removes the Container.exitCode
field. As a result, command execution status must now be retrieved with ExecError
in the SDKs:
Additional information
Using the exit code of a command to check if it failed or not never worked. Consider the following Go example code:
exitCode, err := ctr.ExitCode(ctx) if err != nil { return err } if exitCode != 0 { // ❌ Never called!! 😕 fmt.Println("FAILED") } else { fmt.Println("PASSED") } return nil
When a command fails, the API returns an error and a null
result (example). So, in the previous example, .ExitCode(ctx)
would always return 0
(zero) on success, but nil
on failure. However, the actual exit code value of the failed command is in the error itself.
The recommended approach is to check dagger.ExecError
to specifically handle errors from an exec operation. The ExecError
struct gives easy access to various properties related to the failure.
Here's a revised Go example that demonstrates this:
_, err := ctr.Sync(ctx) if err != nil { var e *dagger.ExecError if errors.As(err, &e) { fmt.Println("FAILED") return nil } return err } fmt.Println("PASSED") return nil
Note: If your container doesn't define any WithExec()
operation, Sync()
won’t execute the container’s entrypoint and/or default arguments like Stdout
and Stderr
. You need to add an empty WithExec(nil)
for that. However, it’s equally useful if that’s actually what you want - for example, building from a Dockerfile
without executing the defined ENTRYPOINT
or CMD
.
In Node.js and Python exceptions are used instead. For example, here's how it looks in Node.js:
try { await ctr.sync() } catch (e) { if (e instanceof ExecError) { console.log("FAILED") return } throw e } console.log("PASSED")
And in Python:
try: await ctr.sync() except dagger.ExecError: print("FAILED") else: print("PASSED")
Refer to the Dagger Cookbook for more examples of error handling with Dagger.
For more information on this breaking change, refer to the following GitHub issue:
Host.envVariable
API field removed
Reading environment variables from the host with Host.envVariable
is no longer supported. Use the programming language's built-in features for this instead:
Go: Replace
Host().EnvVariable()
withos.Getenv
Python: Replace
Host().env_variable()
withos.getenv
Node.js: Replace
Host().envVariable()
withprocess.env
Additional information
Host.envVariable
was previously required to turn an environment variable into a secret (with HostVariable.secret
, also removed). This is no longer necessary and to avoid confusion, it has been removed in favor of using the language's native ability to read environment variables.
For more information on this breaking change, refer to the following GitHub discussion:
Other deprecated API fields removed
Dagger 0.8 removes the following API fields, deprecated since Dagger 0.3.6:
Container.exec
: Replace withContainer.withExec
Container.fs
: Replace withContainer.rootfs
Container.withFS
: Replace withContainer.withRootfs
Host.workdir
: Replace withHost.directory
andpath
set to "."`
Dagger 0.8 also removes the following secret related API fields, deprecated since Dagger 0.5.0:
File.secret
andHostVariable.secret
: Replace with the safersetSecret
. More information is available in the documentation on using secrets.
For more information on these breaking changes, refer to the following GitHub issue:
Optional keyword arguments enforced in the Python SDK
Dagger 0.8 now requires the use of keyword arguments when they’re optional.
Additional information
All API field arguments in Python are grouped, with required arguments first and optional arguments later. Until now, you could choose to use either a positional or keyword argument. With Dagger 0.8, you need to use only keyword arguments when they’re optional. For example:
# ❌ this will now fail ctr.with_exec(["foobar"], None, None, "/out/stderrr") # ✅ use this instead ctr.with_exec(["foobar"], redirect_stderr="/out/stderr")
This improves readability and is incidentally more consistent with the Node.js and Go SDKs, since they both use a separate data structure for the optional arguments.
For more information on this breaking change, refer to the following GitHub issue:
Synchronous client removed from the Python SDK
Dagger 0.8 removes SyncClient
and supporting code.
Follow the instructions on how to migrate to the asynchronous client, and refer to the resources section to learn more.
Additional information
The Python SDK used to have two clients: Client
(asynchronous, supporting coroutines) and SyncClient
(synchronous, supporting only regular functions). This led to confusion, fragmentation and a higher maintenance burden.
Most importantly, non-blocking I/O works best with Dagger, so the synchronous client had a big performance bottleneck and we didn’t see any usage or demand to justify keeping it.
For more information on this breaking change, refer to the following GitHub issue:
Client export modified in the Node.js SDK
Dagger 0.8 makes Client
a named export (instead of default) in TypeScript.
Additional information
Use the example below as a reference to update your Dagger pipelines written in TypeScript:
// ❌ this will now fail import Client, { connect } from "@dagger.io/dagger" // ✅ use this instead import { connect, Client } from "@dagger.io/dagger" connect(async (client: Client) => { // ... })
For more information on this breaking change, refer to the following GitHub issue:
Other changes
There are various other changes, bug fixes and improvements in this release. For a complete list, refer to the respective release notes:
Engine & CLI 0.8.0 changelog and documentation
Go SDK 0.8.0 changelog and documentation
Python SDK 0.8.0 changelog and documentation
Node.js SDK 0.8.0 changelog and documentation
As you are reading this, there is likely to be a 0.8 patch release. To benefit from all bug fixes, please remember to upgrade to the latest 0.8 patch release.
It's also worth pointing out that Dagger 0.8 brings all SDKs together under the same version number, matching the Engine and CLI. This bump will make it easier to know which versions are compatible to update together. Learn more about updating Dagger.
If you get stuck or have additional questions about this release, please reach out to us through this 🐙 GitHub Discussion
We look forward to releasing more features soon! In the meanwhile, if you have general feedback or would like to suggest new features or documentation, let us know on Discord or create a GitHub issue.
We're continuously improving and adding features to Dagger and occasionally, those improvements require us to make breaking changes to the Dagger API. Dagger 0.8 introduces several such breaking changes and this blog post explains the most important ones.
Be sure to consult the Dagger 0.8 release notes for the complete list of changes, breaking and otherwise, and to the update instructions for information on how to update to Dagger 0.8.
Container.exitCode
API field removed
Dagger 0.8 removes the Container.exitCode
field. As a result, command execution status must now be retrieved with ExecError
in the SDKs:
Additional information
Using the exit code of a command to check if it failed or not never worked. Consider the following Go example code:
exitCode, err := ctr.ExitCode(ctx) if err != nil { return err } if exitCode != 0 { // ❌ Never called!! 😕 fmt.Println("FAILED") } else { fmt.Println("PASSED") } return nil
When a command fails, the API returns an error and a null
result (example). So, in the previous example, .ExitCode(ctx)
would always return 0
(zero) on success, but nil
on failure. However, the actual exit code value of the failed command is in the error itself.
The recommended approach is to check dagger.ExecError
to specifically handle errors from an exec operation. The ExecError
struct gives easy access to various properties related to the failure.
Here's a revised Go example that demonstrates this:
_, err := ctr.Sync(ctx) if err != nil { var e *dagger.ExecError if errors.As(err, &e) { fmt.Println("FAILED") return nil } return err } fmt.Println("PASSED") return nil
Note: If your container doesn't define any WithExec()
operation, Sync()
won’t execute the container’s entrypoint and/or default arguments like Stdout
and Stderr
. You need to add an empty WithExec(nil)
for that. However, it’s equally useful if that’s actually what you want - for example, building from a Dockerfile
without executing the defined ENTRYPOINT
or CMD
.
In Node.js and Python exceptions are used instead. For example, here's how it looks in Node.js:
try { await ctr.sync() } catch (e) { if (e instanceof ExecError) { console.log("FAILED") return } throw e } console.log("PASSED")
And in Python:
try: await ctr.sync() except dagger.ExecError: print("FAILED") else: print("PASSED")
Refer to the Dagger Cookbook for more examples of error handling with Dagger.
For more information on this breaking change, refer to the following GitHub issue:
Host.envVariable
API field removed
Reading environment variables from the host with Host.envVariable
is no longer supported. Use the programming language's built-in features for this instead:
Go: Replace
Host().EnvVariable()
withos.Getenv
Python: Replace
Host().env_variable()
withos.getenv
Node.js: Replace
Host().envVariable()
withprocess.env
Additional information
Host.envVariable
was previously required to turn an environment variable into a secret (with HostVariable.secret
, also removed). This is no longer necessary and to avoid confusion, it has been removed in favor of using the language's native ability to read environment variables.
For more information on this breaking change, refer to the following GitHub discussion:
Other deprecated API fields removed
Dagger 0.8 removes the following API fields, deprecated since Dagger 0.3.6:
Container.exec
: Replace withContainer.withExec
Container.fs
: Replace withContainer.rootfs
Container.withFS
: Replace withContainer.withRootfs
Host.workdir
: Replace withHost.directory
andpath
set to "."`
Dagger 0.8 also removes the following secret related API fields, deprecated since Dagger 0.5.0:
File.secret
andHostVariable.secret
: Replace with the safersetSecret
. More information is available in the documentation on using secrets.
For more information on these breaking changes, refer to the following GitHub issue:
Optional keyword arguments enforced in the Python SDK
Dagger 0.8 now requires the use of keyword arguments when they’re optional.
Additional information
All API field arguments in Python are grouped, with required arguments first and optional arguments later. Until now, you could choose to use either a positional or keyword argument. With Dagger 0.8, you need to use only keyword arguments when they’re optional. For example:
# ❌ this will now fail ctr.with_exec(["foobar"], None, None, "/out/stderrr") # ✅ use this instead ctr.with_exec(["foobar"], redirect_stderr="/out/stderr")
This improves readability and is incidentally more consistent with the Node.js and Go SDKs, since they both use a separate data structure for the optional arguments.
For more information on this breaking change, refer to the following GitHub issue:
Synchronous client removed from the Python SDK
Dagger 0.8 removes SyncClient
and supporting code.
Follow the instructions on how to migrate to the asynchronous client, and refer to the resources section to learn more.
Additional information
The Python SDK used to have two clients: Client
(asynchronous, supporting coroutines) and SyncClient
(synchronous, supporting only regular functions). This led to confusion, fragmentation and a higher maintenance burden.
Most importantly, non-blocking I/O works best with Dagger, so the synchronous client had a big performance bottleneck and we didn’t see any usage or demand to justify keeping it.
For more information on this breaking change, refer to the following GitHub issue:
Client export modified in the Node.js SDK
Dagger 0.8 makes Client
a named export (instead of default) in TypeScript.
Additional information
Use the example below as a reference to update your Dagger pipelines written in TypeScript:
// ❌ this will now fail import Client, { connect } from "@dagger.io/dagger" // ✅ use this instead import { connect, Client } from "@dagger.io/dagger" connect(async (client: Client) => { // ... })
For more information on this breaking change, refer to the following GitHub issue:
Other changes
There are various other changes, bug fixes and improvements in this release. For a complete list, refer to the respective release notes:
Engine & CLI 0.8.0 changelog and documentation
Go SDK 0.8.0 changelog and documentation
Python SDK 0.8.0 changelog and documentation
Node.js SDK 0.8.0 changelog and documentation
As you are reading this, there is likely to be a 0.8 patch release. To benefit from all bug fixes, please remember to upgrade to the latest 0.8 patch release.
It's also worth pointing out that Dagger 0.8 brings all SDKs together under the same version number, matching the Engine and CLI. This bump will make it easier to know which versions are compatible to update together. Learn more about updating Dagger.
If you get stuck or have additional questions about this release, please reach out to us through this 🐙 GitHub Discussion
We look forward to releasing more features soon! In the meanwhile, if you have general feedback or would like to suggest new features or documentation, let us know on Discord or create a GitHub issue.