particle-os-cli/Earthfile
Gerald Pinder 8069006c03
feat: Stages (#173)
## Stages

A new property (`stages`) is being added to the recipe file schema. This
property will allow users to define a list of Containerfile stages each
with their own modules. Stages can be used to compile programs, perform
parallel operations, and copy the results into the final image without
contaminating the final image.

### Module Support

Currently the only modules that work out-of-the-box are `copy`,
`script`, `files`, and `containerfile`. Other modules are dependent on
the programs installed on the image. In order to better support some of
our essential modules, a setup script is ran at the start of each stage
that is not `scratch`. This script will install `curl`, `wget`, `bash`,
and `grep` and use the package manager for the detected distributions.

At this time, the following distributions are supported:

- Debian
- Ubuntu
- Fedora
- Alpine

Contributions to increase the size of this list is
[welcome](https://github.com/blue-build/cli)!

### Syntax

- **Required**
- `from` - The full image ref (image name + tag). This will be set in
the `FROM` statement of the stage.
- `name` - The name of the stage. This is used when referencing the
stage when using the `from:` property in the `copy` module.
- `modules` - The list of modules to execute. The exact same syntax used
by the main recipe `modules:` property.
- **Optional**
- `shell` - Allows a user to pass in an array of strings that are passed
directly into the [`SHELL`
instruction](https://docs.docker.com/reference/dockerfile/#shell).

#### Example

```yaml
stages:
- name: ubuntu-test
  from: ubuntu
  modules:
  - type: files
    files:
    - usr: /usr
  - type: script
    scripts:
    - example.sh
    snippets:
    - echo "test" > /test.txt
  - type: test-module
  - type: containerfile
    containerfiles:
    - labels
    snippets:
    - RUN echo "This is a snippet"
```

### Tasks
- [x] `from-file:` - Allows the user to store their stages in a separate
file so it can be included in multiple recipes
- [x] `no-cache:` - This will be useful for stages that want to pull the
latest changes from a git repo and not have to rely on the base image
getting an update for the build to be triggered again.
- [x] Add setup script to be able to install necessary programs to run
`bluebuild` modules in stages
- [x] Check for circular dependencies and error out

## `copy` module

This is a 1-1 for the [`COPY`
instruction](https://docs.docker.com/reference/dockerfile/#copy). It has
the ability to copy files between stages, making this a very important
addition to complete functionality for the stages feature. Each use of
this "module" will become its own layer.

### Decision to use `--link`

We use the `--link`
[option](https://docs.docker.com/reference/dockerfile/#benefits-of-using---link)
which allows that layer to have the same hash if the files haven't
changed regardless of if the previous instructions have changed. This
allows these layers to not have to be re-downloaded on the user's
computer if the copied files haven't changed.

### Syntax

- **Required**
- `src` - The source directory/file from the repo OR when `from:` is set
the image/stage that is specified.
  - `dest` - The destination directory/file inside the working image.
- **Optional**
  - `from` - The stage/image to copy from.

#### Example

```yaml
modules:
- type: copy
  from: ubuntu-test
  src: /test.txt
  dest: /
```

### Tasks
- [x] make `from:` optional
- [x] Add README.md and module.yml

## Feature gating

Gating this feature until we release for `v0.9.0`. The plan will be to
build all features (including this one) for main branch builds. This
means that these features will be available when using the `main` image
and consequently the `use_unstable_cli:` option on the GitHub Action.
All future `v0.9.0` features will be gated as well to allow for patches
to `v0.8`.

### Tasks
- [x] Build `--all-features` on non-tagged builds
- [x] Add stages and copy features
2024-05-18 13:23:50 +00:00

220 lines
6 KiB
Text

VERSION 0.8
PROJECT blue-build/cli
IMPORT github.com/earthly/lib/rust AS rust
ARG --global IMAGE=ghcr.io/blue-build/cli
all:
BUILD +build
BUILD ./integration-tests+all
build:
WAIT
BUILD +build-scripts
END
BUILD +lint
BUILD +test
BUILD +blue-build-cli
BUILD +blue-build-cli-alpine
BUILD +installer
lint:
FROM +common
DO rust+CARGO --args="clippy -- -D warnings"
DO rust+CARGO --args="clippy --all-features -- -D warnings"
DO rust+CARGO --args="clippy --no-default-features -- -D warnings"
test:
FROM +common
DO rust+CARGO --args="test -- --show-output"
DO rust+CARGO --args="test --all-features -- --show-output"
DO rust+CARGO --args="test --no-default-features -- --show-output"
install:
FROM +common
ARG --required BUILD_TARGET
DO rust+CARGO --args="build --release --target $BUILD_TARGET" --output="$BUILD_TARGET/release/[^\./]+"
SAVE ARTIFACT target/$BUILD_TARGET/release/bluebuild
install-all-features:
FROM +common
ARG --required BUILD_TARGET
DO rust+CARGO --args="build --all-features --release --target $BUILD_TARGET" --output="$BUILD_TARGET/release/[^\./]+"
SAVE ARTIFACT target/$BUILD_TARGET/release/bluebuild
common:
FROM ghcr.io/blue-build/earthly-lib/cargo-builder
WORKDIR /app
COPY --keep-ts --dir src/ template/ recipe/ utils/ /app
COPY --keep-ts Cargo.* /app
COPY --keep-ts *.md /app
COPY --keep-ts LICENSE /app
COPY --keep-ts build.rs /app
COPY --keep-ts --dir .git/ /app
RUN touch build.rs
DO rust+INIT --keep_fingerprints=true
build-scripts:
FROM alpine
LABEL org.opencontainers.image.source="https://github.com/blue-build/cli"
COPY --dir scripts/ /
FOR script IN "$(ls /scripts | grep -e '.*\.sh$')"
RUN echo "Making ${script} executable" && \
chmod +x "scripts/${script}"
END
DO --pass-args +SAVE_IMAGE --SUFFIX="-build-scripts"
blue-build-cli:
ARG BASE_IMAGE="registry.fedoraproject.org/fedora-toolbox"
FROM $BASE_IMAGE
LABEL org.opencontainers.image.base.name="$BASE_IMAGE"
RUN dnf -y install dnf-plugins-core \
&& dnf config-manager --add-repo https://download.docker.com/linux/fedora/docker-ce.repo \
&& dnf install --refresh -y \
jq \
docker-ce \
docker-ce-cli \
containerd.io \
docker-buildx-plugin \
docker-compose-plugin \
buildah \
podman \
skopeo
LABEL org.opencontainers.image.base.digest="$(skopeo inspect "docker://$BASE_IMAGE" | jq -r '.Digest')"
COPY +cosign/cosign /usr/bin/cosign
DO --pass-args +INSTALL --OUT_DIR="/usr/bin/" --BUILD_TARGET="x86_64-unknown-linux-gnu"
RUN mkdir -p /bluebuild
WORKDIR /bluebuild
ENTRYPOINT ["bluebuild"]
DO --pass-args +SAVE_IMAGE
blue-build-cli-alpine:
ARG BASE_IMAGE="alpine"
FROM $BASE_IMAGE
LABEL org.opencontainers.image.base.name="$BASE_IMAGE"
RUN apk update && apk add buildah podman skopeo fuse-overlayfs jq
LABEL org.opencontainers.image.base.digest="$(skopeo inspect "docker://$BASE_IMAGE" | jq -r '.Digest')"
COPY +cosign/cosign /usr/bin/cosign
DO --pass-args +INSTALL --OUT_DIR="/usr/bin/" --BUILD_TARGET="x86_64-unknown-linux-musl"
RUN mkdir -p /bluebuild
WORKDIR /bluebuild
ENTRYPOINT ["bluebuild"]
DO --pass-args +SAVE_IMAGE --SUFFIX="-alpine"
installer:
ARG BASE_IMAGE="alpine"
FROM $BASE_IMAGE
LABEL org.opencontainers.image.base.name="$BASE_IMAGE"
RUN apk update && apk add skopeo jq
LABEL org.opencontainers.image.base.digest="$(skopeo inspect "docker://$BASE_IMAGE" | jq -r '.Digest')"
DO --pass-args +INSTALL --OUT_DIR="/out/" --BUILD_TARGET="x86_64-unknown-linux-musl"
COPY install.sh /install.sh
CMD ["cat", "/install.sh"]
DO --pass-args +SAVE_IMAGE --SUFFIX="-installer"
SAVE ARTIFACT /out/bluebuild
cosign:
FROM gcr.io/projectsigstore/cosign
SAVE ARTIFACT /ko-app/cosign
version:
FROM rust
RUN apt-get update && apt-get install -y jq
WORKDIR /app
COPY --keep-ts --dir src/ template/ recipe/ utils/ /app
COPY --keep-ts Cargo.* /app
RUN echo "$(cargo metadata --no-deps --format-version 1 | jq -r '.packages[] | select(.name == "blue-build") .version')" > /version
SAVE ARTIFACT /version
INSTALL:
FUNCTION
ARG TAGGED="false"
ARG --required BUILD_TARGET
ARG --required OUT_DIR
IF [ "$TAGGED" = "true" ]
COPY (+install/bluebuild --BUILD_TARGET="$BUILD_TARGET") $OUT_DIR
ELSE
COPY (+install-all-features/bluebuild --BUILD_TARGET="$BUILD_TARGET") $OUT_DIR
END
SAVE_IMAGE:
FUNCTION
ARG SUFFIX=""
ARG TAGGED="false"
COPY +version/version /
ARG VERSION="$(cat /version)"
ARG MAJOR_VERSION="$(echo "$VERSION" | cut -d'.' -f1)"
ARG MINOR_VERSION="$(echo "$VERSION" | cut -d'.' -f2)"
ARG PATCH_VERSION="$(echo "$VERSION" | cut -d'.' -f3)"
ARG BUILD_TIME="$(date -Iseconds)"
DO --pass-args +LABELS
IF [ "$TAGGED" = "true" ]
SAVE IMAGE --push "${IMAGE}:v${VERSION}${SUFFIX}"
ARG LATEST=false
IF [ "$LATEST" = "true" ]
SAVE IMAGE --push "${IMAGE}:latest${SUFFIX}"
SAVE IMAGE --push "${IMAGE}:v${MAJOR_VERSION}.${MINOR_VERSION}${SUFFIX}"
SAVE IMAGE --push "${IMAGE}:v${MAJOR_VERSION}${SUFFIX}"
END
ELSE
ARG EARTHLY_GIT_BRANCH
SAVE IMAGE --push "${IMAGE}:${EARTHLY_GIT_BRANCH}${SUFFIX}"
END
ARG EARTHLY_GIT_HASH
SAVE IMAGE --push "${IMAGE}:${EARTHLY_GIT_HASH}${SUFFIX}"
LABELS:
FUNCTION
LABEL org.opencontainers.image.created="$BUILD_TIME"
LABEL org.opencontainers.image.url="https://github.com/blue-build/cli"
LABEL org.opencontainers.image.source="https://github.com/blue-build/cli"
LABEL org.opencontainers.image.version="$VERSION"
LABEL version="$VERSION"
LABEL org.opencontainers.image.vendor="BlueBuild"
LABEL vendor="BlueBuild"
LABEL org.opencontainers.image.licenses="Apache-2.0"
LABEL license="Apache-2.0"
LABEL org.opencontainers.image.title="BlueBuild CLI tool"
LABEL name="blue-build/cli"
LABEL org.opencontainers.image.description="A CLI tool built for creating Containerfile templates for ostree based atomic distros"
LABEL org.opencontainers.image.documentation="https://raw.githubusercontent.com/blue-build/cli/main/README.md"
ARG TAGGED="false"
IF [ "$TAGGED" = "true" ]
ARG EARTHLY_GIT_BRANCH
LABEL org.opencontainers.image.ref.name="$EARTHLY_GIT_BRANCH"
ELSE
LABEL org.opencontainers.image.ref.name="v$VERSION"
END