Docs

CI pipelines

Wire the raptor CLI into a CI job to authenticate, log in to your registry, build and push a container image, register it with Facets, and trigger a release.

This guide walks through wiring the Facets CLI (raptor) into a CI job that builds a container image, pushes it to a registry, registers it with Facets, and (optionally) triggers a release.

Prerequisites

Step 1: Authenticate

Set three environment variables in your CI job's secret store:

export FACETS_USERNAME=<your-username>
export FACETS_TOKEN=<your-api-token>
export CONTROL_PLANE_URL=<your-control-plane-url>

All raptor commands pick these up automatically. No explicit login step is needed in CI.

Step 2: Authenticate Docker against the project's registry

raptor fetches short-lived credentials for a registry and runs the docker login itself, so the password never passes through your shell:

raptor get registries
raptor get registry-credentials <registry-name> -p <project> -a <artifact-name>

-a is required, and it is not cosmetic. Credentials are scoped to a single repository, named facets/<project>_<artifact>, and on ECR the Control Plane creates that repository if it is missing. Passing a name you did not mean provisions a repository you did not want.

That repository is also the thing you tag against, and it is not something to assemble by hand. Ask for it:

REPO=$(raptor get registry-credentials <registry-name> -p <project> -a <artifact-name> --repository-uri)

--repository-uri prints only the URI and skips the login, so it composes in a shell substitution. Use --docker-config instead of either if your runner mounts a docker config.json rather than logging in.

Which artifact? The artifact is the CI integration a resource deploys from, and its name is not always the resource name. Read it off the ARTIFACT column of raptor get resources -p <project> -o wide rather than guessing. An empty column means the resource carries a static image, so there is nothing to register builds against.

Step 3: Build and push the image

Standard Docker workflow against the repository from Step 2:

docker build -t "$REPO:<tag>" .
docker push "$REPO:<tag>"

The image does not have to live in a Facets registry. If your pipeline already pushes somewhere else, skip Step 2 and pass that URI to Step 4.

Step 4: Register the image with Facets

Register the pushed image to an environment, git ref, or release stream so blueprints can resolve it:

# By environment
raptor set artifact-uri <artifact-name> -p <project> -e <env> \
  --uri "$REPO:<tag>" \
  --registry <registry-name> \
  --external-id "${CI_RUN_ID}"

# By git ref
raptor set artifact-uri <artifact-name> -p <project> --git-ref <branch> \
  --uri "$REPO:<tag>" --registry <registry-name>

# By release stream
raptor set artifact-uri <artifact-name> -p <project> --release-stream <stream> \
  --uri "$REPO:<tag>" --registry <registry-name>

--registry is not decoration. A resource asks for its image in one of two shapes, and only one of them cares. spec.release.image: ${blueprint.self.artifacts.NAME} resolves by artifact name and needs no registry. spec.release.build: {name, artifactory} resolves by registry and then name, so the build must carry the same registry: the module reads it as all_artifactories[registry][name], and a build stored elsewhere makes it fall back to the literal string NOT_FOUND, which it then deploys as the image. Read a resource's shape with raptor get resources -p <project> <resource> -o json, and read what a build carries with raptor get builds <artifact> -p <project> -o wide. Needs raptor v0.1.98 or later.

Registering by git ref is the one case where the pipeline does not choose the target. The branch is matched against the project's branch mapping, and that decides where the build lands. To read the mapping, and to check where builds actually went:

raptor get ci-cd -p <project> -a <artifact-name>     # branch mapping and promotion ladder
raptor get builds <artifact-name> -p <project>       # what is registered, and what is unrouted

get builds flags any build whose branch matched no rule, which is otherwise invisible until a deploy comes out wrong.

If the artifact does not exist yet, create it once:

raptor create artifact <artifact-name> -p <project>

create artifact is idempotent, so it is safe to run on every build. Pass --registration-type RELEASE_STREAM when builds should target release streams rather than environments; the choice is fixed for the life of the artifact.

For zip-file artifacts (AWS Lambda, Azure Functions, etc.), use raptor set artifact-zip instead. See Attach image for how artifacts attach to services in the blueprint, and run raptor set artifact-uri --help / raptor set artifact-zip --help for the full flag set.

Step 5: Trigger a release (optional)

Only deploy from CI if your workflow requires it. Use --target so the release deploys only the resources affected by the image you just pushed, not the entire environment. The target is the resource in the blueprint, which is not necessarily named like the artifact:

raptor create release -p <project> -e <env> \
  --target service/<resource-name> \
  -w

-w waits for the release, tails its logs to completion, and exits non-zero if the release does not reach SUCCEEDED, so a CI job can gate on the command itself. A release that is skipped because there was nothing to apply (status FAULT) is not treated as a failure.

To read the final status yourself, for example to record it in a build summary:

raptor get releases -p <project> -e <env> -o json

Skipped (FAULT) releases are filtered out of that listing unless you pass --show-skipped.

Reference

For full command syntax and flag detail, see Facets-cloud/raptor-releases or run raptor <command> --help.