Skip to content

Setting up your repository

How to wire a GitLab repository to the PEACH build pipeline (deploy_on_peach_v2), with or without a Python package of your own. This is the detail behind the overview in the Data Science workflow; promotion and rollback are covered in Promotion and rollback. If your repository still runs the previous (v1) pipeline, start from Migrating to deploy_on_peach_v2.

Wiring your repository to the build

Any GitLab repository on git.ebu.io can be built by the PEACH pipeline. Add a .gitlab-ci.yml that includes the shared CI template:

include:
  project: pipe/peach-ray-ci
  file: deploy_on_peach_v2.yml

That single line is the entire file for most repositories. The runner, image, configuration validation, deploy and image build all come from the template. No job token permissions need to be granted and no tokens need to be declared as CI/CD variables in your repository — the pipeline reads credentials from group-level variables managed by the PEACH core team.

What a push builds

A push to your default branch (main or master) runs in order:

  1. Validate — checks your peach.conf against the PEACH schema.
  2. Deploy — peach-ray-build generates the Ray Serve config and Dockerfiles and writes them to your group's peach-ray repo and to peach-k8s.
  3. Build image — runs the Docker build on AWS CodeBuild through the ops-service relay and pushes the image to ECR.
  4. Promote — registers the new tag with peach-ops-service, which rolls it out to your codops' dev environment.

A push never deploys to production: you promote a tag there deliberately, once you are happy with it in dev. (A codops that has no dev environment is deployed straight to prod.)

Repos without a Python package

The default configuration above covers this case. The only file you need is .gitlab-ci.yml. Add any override variables you need above the include::

variables:
  PROMOTE: "false"   # build + publish the image tag but don't auto-deploy

include:
  project: pipe/peach-ray-ci
  file: deploy_on_peach_v2.yml

Repos that publish a Python package

If your repository contains a Python package (a pyproject.toml using hatch-vcs) that your notebooks depend on, set HAS_PACKAGE: "true". This changes the pipeline shape so the image is always built after the package is published to CodeArtifact:

variables:
  HAS_PACKAGE: "true"

include:
  project: pipe/peach-ray-ci
  file: deploy_on_peach_v2.yml

How it works:

  • A push to master runs validation and then semantic-release. A feat: commit cuts a minor version, a fix: commit cuts a patch. The master pipeline stops there — no image build happens yet.
  • The new tag fires a second pipeline that publishes the package to CodeArtifact and then builds the image. This guarantees the image's uv sync always resolves the freshly published version.

Prerequisites — ask the PEACH core team to:

  1. Add your group to the codebuildRelayAllowedGroups allowlist in peach-ops-service.
  2. Add a host/<group> entry to the peach-ops-codebuild-relay-runner-tokens secret (a group access token with api + create_runner, Maintainer role).

You also need to mint a project access token on your own repo (api scope, Developer role) and set it as a masked CI/CD variable named GITLAB_TOKEN. This is the credential semantic-release uses to push the version tag and create the GitLab release. Without it the release job skips loudly and no tag is ever cut.

Releasing your library with semantic commit messages

There is no version to bump by hand — not in pyproject.toml (the version is the git tag, via hatch-vcs), not in peach.conf (the pin is the LATEST_PUBLISHED_VERSION sentinel), not in uv.lock. The commit message is the release mechanism: semantic-release reads the messages that land on master and decides whether — and how much — to bump.

Commit message starts with Release cut Example
fix: patch (1.2.3 → 1.2.4) fix: handle empty user history in ranker
feat: minor (1.2.3 → 1.3.0) feat: add language boost to scoring
feat!: or a BREAKING CHANGE: footer major (1.2.3 → 2.0.0) feat!: rename score() to rank()
chore:, docs:, ci:, style:, refactor:, test: none docs: explain the fallback chain

Day to day this means:

  • A library-only change ships by itself. Commit it as feat: or fix:, merge to master, and the release pipeline bumps, publishes and redeploys — you do not need to touch peach.conf or a notebook to trigger a deploy.
  • The message that counts is the one that lands on master. If you squash-merge a merge request, it is the squash commit's message that semantic-release reads — set it to feat: …/fix: … even if the branch commits were messy.
  • A push with several feat:/fix: commits cuts one release, with the highest bump among them.
  • A chore:/docs: commit deploys nothing. That is the point — but it also means a library change mislabelled as chore: silently never ships. If that happens, follow up with an empty fix: commit to cut the release.

Migrating an existing package: before switching to this flow, tag master with the version you currently publish (e.g. git tag v1.4.2 && git push origin v1.4.2) — semantic-release continues numbering from the latest vX.Y.Z tag it finds, and without a baseline it would restart at v0.1.0.

Each release is visible in three places: the vX.Y.Z tag and GitLab release on your repo, and the published my-package==X.Y.Z in CodeArtifact.

Pinning the just-published version with LATEST_PUBLISHED_VERSION

If your peach.conf depends on the package your own repo publishes, you can pin the dependency to the exact version produced by the same pipeline run using the LATEST_PUBLISHED_VERSION sentinel:

# peach.conf/endpoints.yaml
py_environments:
  base:
    dependencies:
      - my-package==LATEST_PUBLISHED_VERSION
      - other-dep

The deploy job exports LATEST_PUBLISHED_VERSION=<tag> (e.g. 1.1.1) and peach-ray-lib resolves the sentinel before generating the pyproject.toml for your uv workspace. The image is therefore built with the exact version that was just published — not whatever uv would resolve to as "latest".

This sentinel only works in the HAS_PACKAGE=true tag pipeline. If it appears in a master-push pipeline where the variable is not set, peach-ray-lib raises a ValueError early rather than producing a broken image.

Package setup — using hatch-vcs

For the version to be derived from the git tag (rather than a hardcoded string in setup.py) your package should use hatch-vcs:

# pyproject.toml
[project]
name = "my-package"
dynamic = ["version"]

[build-system]
requires = ["hatchling", "hatch-vcs"]
build-backend = "hatchling.build"

[tool.hatch.build.targets.wheel]
packages = ["my_package"]

[tool.hatch.version]
source = "vcs"

With this in place each tag pipeline publishes my-package==<tag> to CodeArtifact, matching the version the LATEST_PUBLISHED_VERSION sentinel resolves to.