Skip to content
GitRiverGitRiver
RU
Navigation

CI/CD Pipelines

How to set up automated build, testing, and deployment in GitRiver

GitRiver has a built-in CI/CD system. You don’t need to install external tools - everything works out of the box.

Configuration is described in YAML files in the .gitriver/workflows/ directory describing jobs and steps.

How It Works

  1. You create a YAML file in .gitriver/workflows/ in your repository
  2. On push, pull request creation, or on a schedule - GitRiver checks all workflow files
  3. If the trigger matches - the pipeline starts
  4. Each job runs in a separate Docker container
  5. The result is displayed in the “CI/CD” tab of the repository

First Workflow

Create the file .gitriver/workflows/ci.yml:

name: CI

on:
  push:
    branches: [main]
  pull_request:

jobs:
  test:
    image: node:22
    steps:
      - run: npm ci
      - run: npm test

What’s here:

  • name - the display name of the pipeline
  • on - when to run: on push to main and on pull request creation/update
  • jobs - a set of tasks. We have one: test
  • image - the Docker image in which steps are executed
  • steps - a sequence of commands

Push the file to the repository (git push) - the pipeline will start automatically.


Triggers - When to Run

On Push to a Branch

Run on push to specific branches:

on:
  push:
    branches: [main, develop, 'release/**']

Only when certain files change:

on:
  push:
    branches: [main]
    paths: ['src/**', 'Cargo.toml']
    paths_ignore: ['docs/**', '*.md']

On Tag Push

For building releases:

on:
  push:
    tags: ['v*']

On Pull Request Creation/Update

on:
  pull_request:
    types: [opened, synchronize, reopened]
    branches: [main]

On Schedule

For nightly builds or periodic checks:

on:
  schedule:
    - cron: '0 2 * * *'

Minimum interval is 15 minutes. Runs on the default branch.

Manual Trigger

To run a pipeline manually from the interface (“Run” button):

on:
  workflow_dispatch:
    inputs:
      environment:
        description: 'Deployment environment'
        type: choice
        options: [staging, production]

Jobs

By default, jobs run in parallel. To set an order, use needs:

jobs:
  build:
    image: rust:1.93
    steps:
      - run: cargo build --release

  test:
    needs: [build]
    image: rust:1.93
    steps:
      - run: cargo test

  deploy:
    needs: [test]
    if: $CI_COMMIT_BRANCH == "main"
    steps:
      - run: ./deploy.sh

Here test waits for build to complete, and deploy waits for test and only runs for the main branch.

Docker Image

Each job runs in a Docker container. Specify the image:

jobs:
  lint:
    image: golangci/golangci-lint:latest
    steps:
      - run: golangci-lint run

Timeout

By default, a job is terminated after 1 hour. You can change this:

jobs:
  long-test:
    timeout: 2h
    steps:
      - run: make integration-tests

Formats: 30s, 10m, 1h, 1h30m. Maximum is 6 hours.


Service Containers

If your tests need a database, Redis, or another service - run them alongside:

jobs:
  test:
    image: python:3.12
    services:
      - image: postgres:16
        alias: db
        env:
          POSTGRES_DB: test
          POSTGRES_USER: test
          POSTGRES_PASSWORD: test
      - image: redis:7
        alias: cache
    env:
      DATABASE_URL: postgres://test:test@db:5432/test
      REDIS_URL: redis://cache:6379
    steps:
      - run: pip install -r requirements.txt
      - run: pytest

Services are accessible by alias (db, cache) within the same Docker network.


Artifacts

Artifacts are files that need to be saved after a job completes (binaries, reports, logs):

jobs:
  build:
    image: rust:1.93
    steps:
      - run: cargo build --release
    artifacts:
      paths:
        - target/release/myapp
      expire_in: 7 days

Artifacts are available:

  • In dependent jobs (via needs)
  • For download through the interface (“CI/CD” tab -> click on the job -> “Artifacts” button)

Test Reports

    artifacts:
      paths:
        - target/release/myapp
      reports:
        junit: test-results.xml
        coverage_report: coverage.xml

GitRiver will display test results and coverage directly in the interface.


Caching

Cache speeds up repeated builds by saving dependencies between runs:

jobs:
  test:
    image: node:22
    cache:
      key: npm-$CI_COMMIT_BRANCH
      paths:
        - node_modules/
      policy: pull-push
    steps:
      - run: npm ci
      - run: npm test
Policy What it does
pull-push Restore cache before the job + save after (default)
pull Only restore (don’t update)
push Only save (useful for jobs that generate cache)

You can use CI variables in the key (key): $CI_COMMIT_BRANCH, $CI_COMMIT_REF_SLUG.


Environment Variables

In the Workflow File

Variables can be set at three levels:

env:
  GLOBAL_VAR: hello

jobs:
  test:
    env:
      JOB_VAR: world
    steps:
      - run: echo $GLOBAL_VAR $JOB_VAR $STEP_VAR
        env:
          STEP_VAR: "!"

In Repository Settings

For secrets (passwords, tokens), don’t store values in YAML. Add them through the interface:

  1. Open the repository -> “Settings” (gear icon) -> “CI/CD Variables”
  2. Click “Add Variable”
  3. Enter the name and value
  4. Check “Mask” - the value will be hidden in logs as [MASKED]

Variables from repository settings are available in all jobs of that repository. They can also be set at the group and instance level (via Administration).


A pipeline from a fork waits for approval

Added in 1.1.0.

Anyone who can write to their own fork may open a pull request from it - no rights on the base repository are needed. But checks occupy runners, so code from outside has a second gate besides secrets.

A pipeline of a pull request whose author has no write access to the base repository is created but not started. It is visible in the pipeline list and on the request page marked “waiting for approval”; the jobs stand still. Any participant with write access approves the run - with the “Approve run” button on the pipeline page or with a request:

POST /api/v1/repos/{owner}/{name}/pipelines/{id}/approve

Approval is one-off and applies to a single pipeline: the next push to the request’s branch creates a new one, which has to be approved as well. Trust is not recalculated on approval - it is taken from the pipeline, so secrets stay closed after the button is pressed, even if the author has gained rights by then.

A pull request from a fork opened by a participant of the base repository does not wait for approval: the gate is on foreign code, not on forks as such. Such a pipeline is still not given secrets - the code comes from another repository.

The wait survives a server restart: the pipeline stays in the queue instead of being lost.


Viewing Results

  1. Open the repository in GitRiver
  2. Go to the “CI/CD” tab (rocket icon)
  3. You’ll see a list of pipeline runs with status icons
  4. Click on a run - a DAG visualization opens (which jobs depend on which)
  5. Click on a specific job - real-time logs open

Buttons:

  • Cancel - abort execution
  • Restart All - run the pipeline again
  • Restart Failed - retry only failed jobs

Status Badge

Add to README.md to display CI status:

![CI](https://git.example.com/owner/repo/badge.svg)

What’s Next