Skip to main content

CI/CD Build and Release Process

Yew Search uses both GitHub Actions and GitLab CI for building and publishing Docker images. Both CI systems support versioned releases using CalVer (YYYY.MM.DD.patch) format.

Overview​

On GitLab CI, VERSION_TAG is required, not optional - each manual build job validates it against ^[0-9]{4}\.[0-9]{2}\.[0-9]{2}\.[0-9]+$ (the CalVer format) and fails immediately if it's missing or malformed. This is a deliberate choice: there's no "just build without a version" path anymore.

All GitLab builds produce these tags:

  1. Commit SHA - Unique identifier for this exact build (e.g., :9124435e)
  2. :latest - Always applied to every build
  3. CalVer version - Required (e.g., :2026.11.05.0)

GitHub Actions' manual workflows are simpler: a single tag input (default latest), no CalVer validation - you can type any string, including a CalVer one if you want parity with the GitLab-built image.

GitLab CI - Triggering Versioned Builds​

Available Jobs​

GitLab CI provides six manual build jobs:

  • manual-build-backend - Builds the NestJS backend API
  • manual-build-frontend - Builds the Svelte frontend application
  • manual-build-docs - Builds the documentation site
  • manual-build-website - Builds the marketing website
  • manual-build-api-docs - Builds the generated API reference docs
  • manual-build-proxy - Builds the Tor proxy image (proxy/)

...plus a matching manual-deploy-* job for each of backend, frontend, website, docs, and api-docs, and a separate manual-run-production-migration job for running a database migration ahead of (or independent of) a deploy. All of these are manual, triggered the same way as the build jobs below.

There's also a workflow that runs automatically on every push to any branch, not manually - .github/workflows/push->*->api-lint-e2e.yaml - which lints the backend and runs the full unit + e2e test suite against real Postgres/Redis service containers. This is the one that actually gates whether a change is safe, independent of any manual build/deploy.

How to Trigger a Build​

Step 1: Go to CI/CD Pipelines​

Navigate to your GitLab project:

Your Project → CI/CD → Pipelines

Step 2: Run Pipeline​

Click "Run pipeline" button in the top right

Step 3: Set the Version Variable (Required)​

In the pipeline configuration:

  1. Leave "Run for branch name or tag" as main (or select your desired branch)
  2. In the Variables section, add:
    • Key: VERSION_TAG
    • Value: Your CalVer version, matching YYYY.MM.DD.patch exactly (e.g., 2026.11.05.0)

Note: The job fails immediately if VERSION_TAG is missing or doesn't match that format - this isn't optional. Builds are also always tagged :latest in addition to your version.

Step 4: Run the Build Job​

  1. Click "Run pipeline"
  2. Wait for pipeline to appear
  3. Click on the pipeline
  4. Find the manual-build-backend (or whichever service you want) job under the "utility" stage
  5. Click the Play button (▶) to trigger the manual job

Example: Building Backend Version 2025.01.27.0​

1. Click "Run pipeline"
2. Branch: main
3. Add variable:
- Key: VERSION_TAG
- Value: 2025.01.27.0
4. Click "Run pipeline"
5. In pipeline view, click Play (▶) on "manual-build-backend"

Result: Image will be tagged as:

  • registry.gitlab.com/your-namespace/yew-monorepo/backend:9124435e (commit SHA)
  • registry.gitlab.com/your-namespace/yew-monorepo/backend:latest (always)
  • registry.gitlab.com/your-namespace/yew-monorepo/backend:2025.01.27.0 (your CalVer version)

Building Multiple Services​

To build multiple services with the same version:

  1. Trigger pipeline once with VERSION_TAG=2025.01.27.0
  2. Manually trigger all jobs you need:
    • Click Play on manual-build-backend
    • Click Play on manual-build-frontend
    • Click Play on manual-build-docs
    • Click Play on manual-build-website

All will use the same VERSION_TAG from the pipeline variables.

GitHub Actions - Triggering Versioned Builds​

Available Workflows​

GitHub Actions provides five manual workflows, named Manual -> Build <Service>:

  • Manual -> Build Backend - pushes ghcr.io/<owner>/yew-backend
  • Manual -> Build Frontend - pushes ghcr.io/<owner>/yew-frontend
  • Manual -> Build Docs - pushes ghcr.io/<owner>/yew-docs
  • Manual -> Build Website - pushes ghcr.io/<owner>/yew-website
  • Manual -> Hello World - builds the hello-world integration test image

Note the image names are yew-backend/yew-frontend/etc., not bare backend/frontend - don't drop the yew- prefix when pulling.

How to Trigger a Build​

Step 1: Go to Actions Tab​

Navigate to your GitHub repository:

Your Repository → Actions tab

Step 2: Select Workflow​

In the left sidebar, click on the workflow you want to run (e.g., "Manual -> Build Backend")

Step 3: Run Workflow​

  1. Click the "Run workflow" button (top right of workflow runs list)
  2. A dropdown will appear with:
    • Branch: Select branch to run from (typically main)
    • tag: Image tag, defaults to latest

Step 4: Specify Version​

In the tag field:

For versioned release:

2025.01.27.0

For latest:

latest

(or leave blank to use default)

Step 5: Trigger Build​

Click the green "Run workflow" button

Example: Building Frontend Version 2026.11.05.0​

1. Go to Actions tab
2. Click "Manual -> Build Frontend" (left sidebar)
3. Click "Run workflow" button
4. Branch: main
5. tag: 2026.11.05.0
6. Click "Run workflow"

Result: Image will be tagged as:

  • ghcr.io/<owner>/yew-frontend:<commit-sha> (commit SHA)
  • ghcr.io/<owner>/yew-frontend:2026.11.05.0 (your tag)

Building Multiple Services​

Repeat the process for each service you want to build:

  1. Run "Manual -> Build Backend" with tag 2026.11.05.0
  2. Run "Manual -> Build Frontend" with tag 2026.11.05.0
  3. Run "Manual -> Build Docs" with tag 2026.11.05.0
  4. Run "Manual -> Build Website" with tag 2026.11.05.0

CalVer Version Format​

Yew Search uses Calendar Versioning (CalVer) with the format:

YYYY.MM.DD.patch

Examples​

  • 2025.01.27.0 - First release on January 27, 2025
  • 2025.01.27.1 - Second release (hotfix) on the same day
  • 2025.02.15.0 - Release on February 15, 2025
  • 2026.03.01.0 - Release on March 1, 2026

When to Increment​

Increment date (YYYY.MM.DD):

  • Every new deployment day
  • Even if it's just one commit
  • Example: 2025.01.27.0 → next day → 2025.01.28.0

Increment patch (.patch):

  • Multiple releases on the same day
  • Usually for hotfixes or urgent deployments
  • Example: 2025.01.27.0 → hotfix same day → 2025.01.27.1

Generating Today's Version​

To generate a version for today:

# Basic version (patch = 0)
date +%Y.%m.%d.0

# Output: 2025.01.27.0

For subsequent releases on the same day, manually increment the patch number.

Best Practices​

1. Coordinate Frontend and Backend Releases​

Always build frontend and backend with the same version tag:

Backend:  registry.gitlab.com/your-namespace/yew-monorepo/backend:2025.01.27.0
Frontend: registry.gitlab.com/your-namespace/yew-monorepo/frontend:2025.01.27.0

This ensures compatibility and makes it clear which versions were released together.

2. Tag Git Commits​

After building a release, tag the git commit:

git tag 2025.01.27.0
git push origin 2025.01.27.0

This creates a permanent reference to the code that produced this release.

3. Document Releases​

Keep a record of what each release contains:

2025.01.27.0
- Added OAuth reauth functionality
- Fixed sidebar mobile navigation
- Updated polling system for integrations

2025.01.20.0
- Initial Gmail integration polling
- Migration system improvements

4. Test Before Promoting to Latest​

If testing a new feature:

  1. Build with version tag: 2025.01.27.0-beta
  2. Deploy to staging environment
  3. Test thoroughly
  4. Build production release: 2025.01.27.0 (from main branch)

5. Use Commit SHA for Debugging​

If you need to debug a specific build:

# In docker-compose.yml
image: registry.gitlab.com/your-namespace/yew-monorepo/backend:9124435e

This gives you exact reproducibility.

Image Registries​

GitLab Container Registry​

Location: registry.gitlab.com/your-namespace/yew-monorepo/

Images:

  • backend:TAG
  • frontend:TAG
  • docs:TAG
  • website:TAG

Authentication:

echo $GITLAB_TOKEN | docker login registry.gitlab.com -u your-username --password-stdin

GitHub Container Registry (ghcr.io)​

Location: ghcr.io/your-username/

Images:

  • yew-backend:TAG
  • yew-frontend:TAG
  • yew-docs:TAG
  • yew-website:TAG

Authentication:

echo $GITHUB_TOKEN | docker login ghcr.io -u your-username --password-stdin

Viewing Available Tags​

GitLab​

Navigate to:

Your Project → Packages & Registries → Container Registry

Click on any image to see all available tags.

GitHub​

Navigate to:

Your Repository → Packages (right sidebar)

Click on any package to see all available tags.

Troubleshooting​

Build Fails with "Set VERSION_TAG when starting the pipeline"​

Cause: VERSION_TAG is required on every GitLab manual build job now - it wasn't set, or was left as the literal placeholder yyyy.mm.dd.version.

Solution: Set the VERSION_TAG CI/CD variable to a real CalVer value (YYYY.MM.DD.patch) before running the pipeline.

Image Tagged as "latest" When I Specified a Version​

Expected behavior on default branch (main):

  • Custom version builds are ALSO tagged as :latest
  • This ensures :latest always points to the newest release

To prevent this: Build from a feature branch instead of main

GitHub Actions: "Tag to use for Docker image" Field Missing​

Cause: Your workflow file may be outdated

Solution: Check that your workflow file (.github/workflows/manual->build-*.yaml) has the workflow_dispatch input defined:

on:
workflow_dispatch:
inputs:
tag:
description: 'Image tag (default: latest)'
required: false
default: 'latest'