Revise Europa Docs - Core Concepts - It all starts with a plan

Thank you Tanguy for the "fresh pair of eyes" perspective.

Thank you Tom for the link suggestions.

Supersedes https://github.com/dagger/dagger/pull/1847

Signed-off-by: Gerhard Lazu <gerhard@lazu.co.uk>
This commit is contained in:
Gerhard Lazu 2022-03-25 14:25:01 +00:00
parent 2018ac99f0
commit 5fe04d22e9
No known key found for this signature in database
GPG Key ID: A28DE70C9444D7A6
3 changed files with 87 additions and 43 deletions

View File

@ -5,15 +5,19 @@ displayed_sidebar: europa
# It all starts with a plan
A CI/CD pipeline declared in Dagger starts with a plan, specifically `dagger.#Plan`
## Plan structure
This plan is the entrypoint for everything that runs within a pipeline. The simplest plan will usually:
A config declared in Dagger starts with a plan, specifically `dagger.#Plan`
- interact with the client filesystem to read (e.g. source code) or write files (e.g. build output)
- read environment variables
- declare a few actions, e.g. deps, test & build
Within this plan we can:
This is our **Getting Started** example app plan structure:
- interact with the `client` filesystem
- read files, usually the current directory as `.`
- write files, usually the build output as `_build`
- read `env` variables, such as `NETLIFY_TEAM` in our example
- declare a few `actions`, e.g. `deps`, `test` & `build`
This is our **Getting Started** todoapp plan structure:
```cue file=../tests/core-concepts/plan/structure.cue.fragment
```
@ -21,53 +25,87 @@ This is our **Getting Started** example app plan structure:
When the above plan gets executed via `dagger do build`, it produces the following output:
```shell
[✔] client.filesystem.".".read 0.0s
[✔] actions.deps 1.1s
[✔] actions.test.script 0.0s
[✔] actions.test 0.0s
[✔] actions.build.run.script 0.0s
[✔] actions.build.run 0.0s
[✔] actions.build.contents 0.0s
[✔] client.filesystem.build.write 0.1s
[✔] client.filesystem.".".read 0.0s
[✔] actions.deps 1.1s
[✔] actions.test.script 0.0s
[✔] actions.test 0.0s
[✔] actions.build.run.script 0.0s
[✔] actions.build.run 0.0s
[✔] actions.build.contents 0.0s
[✔] client.filesystem."./_build".write 0.1s
```
Since these actions have run before, they are cached and take less than 1 second to complete.
Since these actions have run before, they are cached and take less than 2 seconds to complete.
While the names used for the actions above - `deps`, `test` & `build` - are short & descriptive,
While the names used for the actions above - `deps`, `test` & `build` - are short and descriptive,
any other names would have worked. Put differently, action naming does not affect plan execution.
In the example above, the `deps` action is an instance of the docker package build definition.
Lastly, notice that even if the `deploy` action is defined, we did not run it.
Similar to Makefile targets, we have the option of running specific actions.
This is written as `deps: docker.#Build`
We ran the `dagger do build` command, which only runs the `build` action (and all its dependent actions).
This Dagger property enables us to keep the entire CI/CD config in a single file, while keeping the integration execution separate from the deployment one.
Separating CI & CD concerns becomes essential as our pipelines grow in complexity, and we learn about operational and security constraints specific to our systems.
Default definition configuration - `docker.#Build` in this case - can be modified via curly brackets, e.g.
## Packages & imports
In order to understand the correlation between actions, definitions and packages, let us focus on the following fragment from our **Getting Started** todoapp config:
```cue
deps: docker.#Build & {
package todoapp
import (
"dagger.io/dagger"
"universe.dagger.io/netlify"
)
dagger.#Plan & {
// ...
actions: {
// ...
deploy: netlify.#Deploy & {
// ...
}
// ...
}
}
```
We start by declaring the package name, `package todoapp` above.
Next, we import the packages that we use in our plan.
The first import is needed for the `dagger.#Plan` definition to be available.
The second import is for `netlify.#Deploy` to work.
:::info
Which other imports we are missing?
Look at all the actions in the plan structure at the top of this page.
Now check all the available packages in [universe.dagger.io](https://github.com/dagger/dagger/tree/v0.2.0/pkg/universe.dagger.io).
:::
We now understand that the `deploy` action is the deploy definition from the netlify package, written as `deploy: netlify.#Deploy`
Each definition has default values that can be modified via curly brackets. This is what that looks like in practice for our deploy action:
```cue
// ...
deploy: netlify.#Deploy & {
contents: build.contents.output
site: client.env.APP_NAME
token: client.env.NETLIFY_TOKEN
team: client.env.NETLIFY_TEAM
}
// ...
```
We can build complex pipelines efficiently by referencing any definition, from any package in our actions.
This is one of the fundamental concepts that makes Dagger a powerful language for CI/CD.
Before we can use a package in a plan, we need to declare it at the top of the pipeline configuration, like this:
This is one of the fundamental concepts that makes Dagger a powerful language for building CI/CD pipelines.
```cue
import (
"universe.dagger.io/docker"
)
```
Since we are using the plan definition from the dagger package - `dagger.#Plan` - we also need to declare it at the top of the pipeline configuration:
```cue
import (
"dagger.io/dagger"
"universe.dagger.io/docker"
)
```
If you want to learn more packages in the context of CUE, the config language used by Dagger configs, check out the [Packages](1215-what-is-cue.md#packages) section on the **What is CUE?** page.
:::tip
Now that we understand the basics of a Dagger plan, we are ready to learn more about how to interact with the client environment.
This will enable us to configure plans just-in-time, save build artefacts, and perform other interactions with the environment within which Dagger runs.
We can read the env (including secrets), run commands, use local sockets, etc.
:::

View File

@ -1,3 +1,8 @@
// ...
// A plan has pre-requisited that we cover below.
// For now we focus on the dagger.#Plan structure.
// ...
dagger.#Plan & {
client: {
filesystem: {
@ -22,5 +27,8 @@ dagger.#Plan & {
// ...
}
}
deploy: netlify.#Deploy & {
// ...
}
}
}

View File

@ -1,4 +1,4 @@
package netlify
package todoapp
import (
"dagger.io/dagger"
@ -23,12 +23,12 @@ dagger.#Plan & {
contents: dagger.#FS
exclude: [
"README.md",
"build",
"netlify.cue",
"_build",
"todoapp.cue",
"node_modules",
]
}
build: write: contents: actions.build.contents.output
"./_build": write: contents: actions.build.contents.output
}
env: {
APP_NAME: string
@ -50,8 +50,6 @@ dagger.#Plan & {
contents: client.filesystem.".".read.contents
dest: "/src"
},
// bash.#Run is a superset of docker.#Run
// install yarn dependencies
bash.#Run & {
workdir: "/src"
mounts: {