Skip to content

Examples

Runnable examples live in the lexicon’s examples/ directory. Clone the repo and try them:

Terminal window
cd examples/getting-started
bun install
chant build # produces .gitlab-ci.yml
chant lint # runs lint rules
bun test # runs the example's tests

examples/getting-started/ — a 2-stage Node.js pipeline with build and test jobs.

src/
├── config.ts # Shared config: image, cache
└── pipeline.ts # Job definitions: build, test

config.ts extracts reusable objects — image and cache — so jobs stay concise:

config.ts
/**
* Shared pipeline configuration
*/
import { Image, Cache } from "@intentius/chant-lexicon-gitlab";
// Default image for all jobs
export const defaultImage = new Image({
name: "node:20-alpine",
});
// Standard cache configuration
export const npmCache = new Cache({
key: "$CI_COMMIT_REF_SLUG",
paths: ["node_modules/"],
policy: "pull-push",
});

pipeline.ts defines two jobs that import shared config:

pipeline.ts
import { Job, Artifacts } from "@intentius/chant-lexicon-gitlab";
import { defaultImage, npmCache } from "./config";
export const junitReports = { junit: "coverage/junit.xml" };
export const testArtifacts = new Artifacts({
reports: junitReports,
paths: ["coverage/"],
expire_in: "1 week",
});
export const build = new Job({
stage: "build",
image: defaultImage,
cache: npmCache,
script: ["npm install", "npm run build"],
});
export const test = new Job({
stage: "test",
image: defaultImage,
cache: npmCache,
script: ["npm install", "npm test"],
artifacts: testArtifacts,
});

chant build produces this .gitlab-ci.yml:

stages:
- build
- test
build:
stage: build
image:
name: node:20-alpine
cache:
key: '$CI_COMMIT_REF_SLUG'
paths:
- node_modules/
policy: pull-push
script:
- npm install
- npm run build
test:
stage: test
image:
name: node:20-alpine
cache:
key: '$CI_COMMIT_REF_SLUG'
paths:
- node_modules/
policy: pull-push
script:
- npm install
- npm test
artifacts:
reports:
junit: coverage/junit.xml
paths:
- coverage/
expire_in: '1 week'

Patterns demonstrated:

  1. Shared config — reusable image and cache extracted into config.ts
  2. JUnit reports — test artifacts include JUnit XML for GitLab MR display
  3. Stage ordering — stages collected automatically from job declarations

examples/docker-build/ — builds and pushes a Docker image using the DockerBuild composite.

pipeline.ts
import { DockerBuild, Job, Image } from "@intentius/chant-lexicon-gitlab";
export const docker = DockerBuild({
dockerfile: "Dockerfile",
tagLatest: true,
});
export const test = new Job({
stage: "test",
image: new Image({ name: "node:22-alpine" }),
script: ["node test.js"],
});

The DockerBuild composite expands to a job with Docker-in-Docker service, registry login, build, and push steps.

examples/node-pipeline/ — a full Node.js CI pipeline using the NodePipeline composite.

pipeline.ts
import { NodePipeline } from "@intentius/chant-lexicon-gitlab";
export const app = NodePipeline({
nodeVersion: "22",
installCommand: "npm install",
buildScript: "build",
testScript: "test",
});

examples/python-pipeline/ — a Python CI pipeline using the PythonPipeline composite.

pipeline.ts
import { PythonPipeline } from "@intentius/chant-lexicon-gitlab";
export const app = PythonPipeline({
pythonVersion: "3.12",
lintCommand: null,
});

examples/review-app/ — deploys a review environment per merge request using the ReviewApp composite.

pipeline.ts
import { ReviewApp, Job, Image } from "@intentius/chant-lexicon-gitlab";
export const review = ReviewApp({
name: "review",
deployScript: "echo deploy",
});
export const test = new Job({
stage: "test",
image: new Image({ name: "node:22-alpine" }),
script: ["node test.js"],
});

A cross-lexicon example showing how to deploy AWS CloudFormation stacks from GitLab CI. Three separate pipelines mirror the separate-project AWS ALB pattern:

Deploys the shared ALB stack (VPC, ALB, ECS cluster, ECR repos):

import { Job, Image, Rule } from "@intentius/chant-lexicon-gitlab";
const awsImage = new Image({ name: "amazon/aws-cli:latest" });
export const deployInfra = new Job({
stage: "deploy",
image: awsImage,
script: [
"aws cloudformation deploy --template-file templates/template.json --stack-name shared-alb --capabilities CAPABILITY_IAM --no-fail-on-empty-changeset",
],
rules: [
new Rule({ if: "$CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH" }),
],
});

Builds a Docker image, pushes to ECR, and deploys the API service stack with cross-stack parameter passing. The full source lives in the cross-lexicon example examples/gitlab-aws-alb-api/:

pipeline.ts
import { Job, Image, Service, Need, Rule } from "@intentius/chant-lexicon-gitlab";
import { CI } from "@intentius/chant-lexicon-gitlab";
const ECR_URL = "$AWS_ACCOUNT_ID.dkr.ecr.$AWS_DEFAULT_REGION.amazonaws.com";
const ECR_REPO = "alb-api";
const STACK_NAME = "shared-alb-api";
const INFRA_STACK = "shared-alb";
const fullImage = `${ECR_URL}/${ECR_REPO}`;
const awsImage = new Image({ name: "amazon/aws-cli:latest", entrypoint: [""] });
const dockerImage = new Image({ name: "docker:27-cli" });
const dind = new Service({ name: "docker:27-dind", alias: "docker" });
const defaultBranchOnly = [
new Rule({ if: "$CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH" }),
];
const dockerVariables = { DOCKER_TLS_CERTDIR: "/certs" };
export const buildImage = new Job({
stage: "build",
image: dockerImage,
services: [dind],
variables: dockerVariables,
before_script: [
"apk add --no-cache aws-cli",
`aws ecr get-login-password | docker login --username AWS --password-stdin ${ECR_URL}`,
],
script: [
`docker build -t ${fullImage}:${CI.CommitRefSlug} .`,
`docker push ${fullImage}:${CI.CommitRefSlug}`,
`if [ "${CI.CommitBranch}" = "${CI.DefaultBranch}" ]; then docker tag ${fullImage}:${CI.CommitRefSlug} ${fullImage}:latest && docker push ${fullImage}:latest; fi`,
],
rules: defaultBranchOnly,
});
export const deployService = new Job({
stage: "deploy",
image: awsImage,
needs: [new Need({ job: "build-image" })],
script: [
`OUTPUTS=$(aws cloudformation describe-stacks --stack-name ${INFRA_STACK} --query 'Stacks[0].Outputs' --output json)`,
`PARAMS=$(echo "$OUTPUTS" | jq -r '[(.[] | select(.OutputKey == "ClusterArn") | "clusterArn=" + .OutputValue), (.[] | select(.OutputKey == "ListenerArn") | "listenerArn=" + .OutputValue), (.[] | select(.OutputKey == "AlbSgId") | "albSgId=" + .OutputValue), (.[] | select(.OutputKey == "ExecutionRoleArn") | "executionRoleArn=" + .OutputValue), (.[] | select(.OutputKey == "VpcId") | "vpcId=" + .OutputValue), (.[] | select(.OutputKey == "PrivateSubnet1") | "privateSubnet1=" + .OutputValue), (.[] | select(.OutputKey == "PrivateSubnet2") | "privateSubnet2=" + .OutputValue)] | join(" ")')`,
`IMAGE_URI=$(echo "$OUTPUTS" | jq -r '.[] | select(.OutputKey == "ApiRepoUri") | .OutputValue'):\${CI_COMMIT_REF_SLUG}`,
`aws cloudformation deploy --template-file templates/template.json --stack-name ${STACK_NAME} --capabilities CAPABILITY_IAM --no-fail-on-empty-changeset --parameter-overrides $PARAMS image=$IMAGE_URI`,
],
rules: defaultBranchOnly,
});

Key patterns:

  1. ECR login — uses aws ecr get-login-password instead of GitLab registry credentials
  2. Cross-stack parameter passingdescribe-stacks fetches outputs from the infra stack, jq maps them to --parameter-overrides
  3. Job namingbuildImage serializes to build-image in YAML; Need references must use kebab-case
  4. Docker-in-Dockerdocker:27-cli image with docker:27-dind service for container builds

The full examples live in examples/gitlab-aws-alb-infra/, examples/gitlab-aws-alb-api/, and examples/gitlab-aws-alb-ui/.