Merge pull request #869 from aluzzardi/ci-use-case
docs: add the CI use case
This commit is contained in:
commit
2401855052
203
docs/use-cases/1012-ci.md
Normal file
203
docs/use-cases/1012-ci.md
Normal file
@ -0,0 +1,203 @@
|
|||||||
|
---
|
||||||
|
slug: /1012/ci
|
||||||
|
---
|
||||||
|
|
||||||
|
# Continuous Integration
|
||||||
|
|
||||||
|
Dagger is the perfect tool for CI workflows.
|
||||||
|
|
||||||
|
## Benefits
|
||||||
|
|
||||||
|
- **Develop and run your CI pipeline locally.** No need to create a Pull Request
|
||||||
|
to trigger CI, you can run the pipeline locally. Since dagger workflows
|
||||||
|
are containerized, you can expect the same results no matter where the pipeline
|
||||||
|
is executed.
|
||||||
|
- **Write once, Run anywhere.** The same pipeline can run in any CI, goodbye
|
||||||
|
vendor lock in.
|
||||||
|
- **Blazing Fast**: Dagger will automatically build an optimized execution
|
||||||
|
graph, completing the job as fast as possible. Spend less time staring at CI to
|
||||||
|
complete and reduce costs.
|
||||||
|
- **Effortless Cache Optimizations**. Dagger will automatically
|
||||||
|
re-use cached execution results if no changes are detected. Made a change to the
|
||||||
|
frontend? The backend won't be built again.
|
||||||
|
- **Composable & Reusable**. Define re-usable steps and [share](../learn/1010-dev-cue-package.md) them across all
|
||||||
|
your projects. Or with the world. Dagger
|
||||||
|
ships with [dozens of re-usable components](../reference/universe/README.md)
|
||||||
|
|
||||||
|
## Example
|
||||||
|
|
||||||
|
This example illustrates how to use Dagger to test and lint a Go project. The
|
||||||
|
use of Go is irrelevant and the example can be easily adapted to other languages.
|
||||||
|
|
||||||
|
From the project repository, create a file named `ci/main.cue` and add the
|
||||||
|
following configuration to it.
|
||||||
|
|
||||||
|
```cue title="ci/main.cue"
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"alpha.dagger.io/dagger"
|
||||||
|
"alpha.dagger.io/os"
|
||||||
|
"alpha.dagger.io/docker"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Source directory of the repository. We'll connect this from the CLI using `dagger input`
|
||||||
|
source: dagger.#Artifact
|
||||||
|
|
||||||
|
// Here we define a test phase.
|
||||||
|
// We're using `os.#Container`, a built-in package that will spawn a container
|
||||||
|
// We're also using `docker.#Pull` to execute the container from a Docker image
|
||||||
|
// comifrom a registry.
|
||||||
|
test: os.#Container & {
|
||||||
|
image: docker.#Pull & {
|
||||||
|
from: "golang:1.16-alpine"
|
||||||
|
}
|
||||||
|
mount: "/app": from: source
|
||||||
|
command: "go test -v ./..."
|
||||||
|
dir: "/app"
|
||||||
|
}
|
||||||
|
|
||||||
|
// Likewise, here we define a lint phase.
|
||||||
|
lint: os.#Container & {
|
||||||
|
image: docker.#Pull & {
|
||||||
|
from: "golangci/golangci-lint:v1.39.0"
|
||||||
|
}
|
||||||
|
mount: "/app": from: source
|
||||||
|
command: "golangci-lint run -v"
|
||||||
|
dir: "/app"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
The configuration above defines:
|
||||||
|
|
||||||
|
- **source** code of the project. More on this later.
|
||||||
|
- **test** *task* which executes `go test` inside the source artifact
|
||||||
|
using the `golang` Docker image
|
||||||
|
- **lint** *task* which executes `golangci-lint` inside the source artifact
|
||||||
|
using the `golangci-lint` Docker image.
|
||||||
|
|
||||||
|
Before we can execute the configuration, we need to set up the Dagger workspace and environment.
|
||||||
|
|
||||||
|
```shell
|
||||||
|
# Initialize a dagger workspace at the root of your project
|
||||||
|
dagger init
|
||||||
|
|
||||||
|
# Create a CI environment using the CUE files in the `./ci` directory
|
||||||
|
dagger new ci -p ./ci
|
||||||
|
|
||||||
|
# Link the `source` artifact defined in the configuration with the project
|
||||||
|
# source code.
|
||||||
|
dagger input dir source .
|
||||||
|
```
|
||||||
|
|
||||||
|
Next, bring up the CI environment (e.g. execute the CI configuration):
|
||||||
|
|
||||||
|
```shell
|
||||||
|
$ dagger up
|
||||||
|
# ...
|
||||||
|
7:15PM INF test | computing environment=ci
|
||||||
|
7:15PM INF lint | computing environment=ci
|
||||||
|
# ...
|
||||||
|
```
|
||||||
|
|
||||||
|
Since `test` and `lint` do not depend on each other, they are executed in
|
||||||
|
parallel.
|
||||||
|
|
||||||
|
Running `dagger up` a second time will return almost immediately: since no
|
||||||
|
changes were made to `source`, Dagger will re-use the cached results for both `test` nor `lint`.
|
||||||
|
|
||||||
|
## Integrating with CI
|
||||||
|
|
||||||
|
All it takes to execute a Dagger workflow in CI is to run `dagger up`.
|
||||||
|
|
||||||
|
We provide a [GitHub Actions](../learn/1009-github-actions.md) to make
|
||||||
|
integration with GitHub easier.
|
||||||
|
|
||||||
|
## Monorepos
|
||||||
|
|
||||||
|
Dagger workflows scale really well with CI complexity.
|
||||||
|
|
||||||
|
The following example illustrates how to test two different projects in the same
|
||||||
|
repository: a *Node* frontend (located in *./frontend*) along with a *Go* backend (located in *./backend*).
|
||||||
|
|
||||||
|
From the project repository, update the file named `ci/main.cue` with the
|
||||||
|
following configuration.
|
||||||
|
|
||||||
|
```cue title="ci/main.cue"
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"alpha.dagger.io/dagger"
|
||||||
|
"alpha.dagger.io/os"
|
||||||
|
"alpha.dagger.io/docker"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Source directory of the repository. We'll connect this from the CLI using `dagger input`
|
||||||
|
source: dagger.#Artifact
|
||||||
|
|
||||||
|
backend: {
|
||||||
|
// We use `os.#Dir` to grab a sub-directory of `source`
|
||||||
|
code: os.#Dir & {
|
||||||
|
from: source
|
||||||
|
path: "."
|
||||||
|
}
|
||||||
|
|
||||||
|
test: os.#Container & {
|
||||||
|
image: docker.#Pull & {
|
||||||
|
from: "golang:1.16-alpine"
|
||||||
|
}
|
||||||
|
mount: "/app": from: code
|
||||||
|
command: "go test -v ./..."
|
||||||
|
dir: "/app"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
frontend: {
|
||||||
|
// We use `os.#Dir` to grab a sub-directory of `source`
|
||||||
|
code: os.#Dir & {
|
||||||
|
from: source
|
||||||
|
path: "./frontend"
|
||||||
|
}
|
||||||
|
|
||||||
|
test: os.#Container & {
|
||||||
|
image: docker.#Pull & {
|
||||||
|
from: "node:16-alpine"
|
||||||
|
}
|
||||||
|
mount: "/app": from: code
|
||||||
|
command: """
|
||||||
|
# Install Dependencies
|
||||||
|
yarn
|
||||||
|
|
||||||
|
# Run the test script
|
||||||
|
yarn test
|
||||||
|
"""
|
||||||
|
dir: "/app"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
:::tip
|
||||||
|
Larger configurations can be split into multiple files, for example `backend.cue` and `frontend.cue`
|
||||||
|
:::
|
||||||
|
|
||||||
|
The configuration above defines a *frontend* and *backend* structure, each
|
||||||
|
containing:
|
||||||
|
|
||||||
|
- A **code** directory, defined as a subdirectory of **source**
|
||||||
|
- A language specific **test** task using either `yarn` or `go`
|
||||||
|
|
||||||
|
```shell
|
||||||
|
$ dagger up
|
||||||
|
7:15PM INF frontend.test | computing environment=ci
|
||||||
|
7:15PM INF backend.test | computing environment=ci
|
||||||
|
7:15PM INF frontend.test | #8 0.370 yarn install v1.22.5 environment=ci
|
||||||
|
7:15PM INF frontend.test | #8 0.689 [1/4] Resolving packages... environment=ci
|
||||||
|
7:15PM INF frontend.test | #8 1.626 [2/4] Fetching packages... environment=ci
|
||||||
|
...
|
||||||
|
```
|
||||||
|
|
||||||
|
`frontend.test` and `backend.test` are running in parallel since there are no
|
||||||
|
dependencies between each other.
|
||||||
|
|
||||||
|
If you were to make changes to the *./frontend* directory, only
|
||||||
|
`frontend.test` will be executed.
|
5
docs/use-cases/_category_.json
Normal file
5
docs/use-cases/_category_.json
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"label": "Use Cases",
|
||||||
|
"position": 2,
|
||||||
|
"collapsed": false
|
||||||
|
}
|
Reference in New Issue
Block a user