CollabOps

Steps

Step schema, shell commands (run), execution image (image), template references (uses/with)

A Step is the smallest unit of execution that runs sequentially within a Job. Each Step is defined using either a shell command (run) or a template reference (uses).

Below is an example of a Step execution log.

Below is an example of an error log from a failed Step.

Step Schema

FieldRequiredTypeDescription
nameYES (object form)stringStep name (1-255 chars, [a-zA-Z0-9_-])
runNOstringShell command to execute. Cannot be used together with uses
imageNOstringImage to run the command in
envNOobjectStep-level environment variables
usesNOstringTemplate reference (\{owner\}/\{name\}@\{version\} format). Cannot be used together with run
withNOobjectInput parameters to pass to the template (when using uses)
idNOstringIdentifier for referencing Step outputs
working-directoryNOstringWorking directory override (relative path, must not contain ..)
timeout-minutesNOintStep timeout in minutes (must be positive, only supported with run)

Shorthand Syntax

Simple commands can be written as shorthand strings.

steps:
  # Shorthand — writing just a string is treated as run
  - npm install
  - npm test
  - npm run build

The above is equivalent to:

steps:
  - name: npm-install
    run: npm install
  - name: npm-test
    run: npm test
  - name: npm-run-build
    run: npm run build

run (Shell Command Execution)

run executes shell commands. It supports both single commands and multiline scripts.

Each Step runs in an isolated environment, so you can use any shell command available in the specified image. Tools like npm, python, go, make, curl, wget, and more can all be used as long as they are installed in the image.

The shell used is /bin/sh (POSIX sh). If you need Bash-specific syntax ([[ ]], arrays, etc.), add #!/bin/bash at the top of your script, provided Bash is installed in the image.

Single Command

steps:
  - name: install
    run: npm ci
    image: node:18

Multiline Script

Use YAML's | (literal block) to write multiline scripts.

steps:
  - name: build-and-test
    image: node:18
    run: |
      # Install dependencies
      npm ci

      # Run lint checks
      npm run lint

      # Run unit tests
      npm test

      # Production build
      npm run build

Various Tool Examples

You can run any command as long as it is available in the specified image.

steps:
  # Go build
  - name: build-go
    image: golang:1.22
    run: |
      go mod download
      go build -o app ./cmd/server

  # Python tests
  - name: test-python
    image: python:3.12
    run: |
      pip install -r requirements.txt
      pytest tests/ --cov=src

  # API call with cURL
  - name: health-check
    image: alpine:3.19
    run: |
      apk add --no-cache curl
      curl -f https://api.example.com/health

  # Run a custom shell script
  - name: custom-script
    image: ubuntu:24.04
    run: |
      chmod +x ./scripts/deploy.sh
      ./scripts/deploy.sh

Using Environment Variables

steps:
  - name: deploy
    image: alpine:3.19
    env:
      DEPLOY_ENV: production
      API_URL: "https://api.example.com"
    run: |
      echo "Deploying to $DEPLOY_ENV"
      echo "API: $API_URL"
      ./deploy.sh

image (Execution Image)

Each Step runs independently in the specified image environment. Use image to specify the image.

steps:
  # Build in a Node.js 18 image
  - name: build
    run: npm run build
    image: node:18

  # Test in a Python 3.11 image
  - name: test-python
    run: pytest tests/
    image: python:3.11

  # Official Docker image (specific registry)
  - name: custom
    run: ./run.sh
    image: asia-northeast3-docker.pkg.dev/my-project/my-repo/my-image:latest

If image is omitted, the default image ubuntu:24.04 is used. It is recommended to explicitly specify an image that includes the tools you need.

uses (Template Reference)

uses references a predefined template to execute a Step. Use with to pass input parameters.

Format

uses: "{owner}/{name}@{version}"

Example: Source Code Checkout

steps:
  - name: checkout
    uses: "collabops/checkout@v2"
    with:
      # Using an HTTPS URL, the platform-injected Job Token authenticates automatically.
      repo-url: "https://<collabops-host>/<workspace>/<repository>.git"
      # Checkout a specific branch (defaults to the trigger branch if omitted)
      ref: main

Example: Docker Image Build and Push

steps:
  - name: build-push
    uses: "collabops/docker-build-push@v1"
    with:
      # Multiple tags (separated by newlines)
      tags: |
        my-registry/my-app:latest
        my-registry/my-app:${{ collabops.sha }}
      # Build arguments
      build-args: |
        NODE_ENV=production
        API_URL=https://api.example.com

Example: Slack Notification

steps:
  - name: notify
    uses: "collabops/slack-notify@v1"
    with:
      # Webhook URL (registered in secrets)
      webhook-url: ${{ secrets.SLACK_WEBHOOK }}
      # Notification message
      message: "Deployment complete: ${{ collabops.ref_name }} (${{ collabops.sha }})"
      title: "Deploy Success"
      color: good

run and uses Are Mutually Exclusive

run and uses cannot be used together in a single Step.

run and uses cannot be used at the same time. Each Step must specify exactly one of them.

# Correct usage
- name: checkout
  uses: "collabops/checkout@v2"
  with:
    repo-url: "https://<collabops-host>/<workspace>/<repository>.git"

- name: build
  run: npm run build
  image: node:18

# Incorrect usage — run and uses cannot be used together
- name: invalid
  uses: "collabops/checkout@v2"
  run: npm run build

id (Step Output Reference)

By specifying an id, you can reference that Step's output values from other Steps.

steps:
  # 1. Save version information to output
  - name: prepare-version
    id: version
    image: node:18
    run: |
      # Extract version from package.json
      VERSION=$(node -p "require('./package.json').version")
      # Save as key=value pairs to $COLLABOPS_OUTPUT
      echo "app_version=${VERSION}" >> $COLLABOPS_OUTPUT
      echo "build_date=$(date -u +%Y%m%d)" >> $COLLABOPS_OUTPUT

  # 2. Use the saved output values in another Step
  - name: build-image
    run: |
      echo "Building version: ${{ steps.version.outputs.app_version }}"
      echo "Build date: ${{ steps.version.outputs.build_date }}"
      docker build \
        --build-arg VERSION=${{ steps.version.outputs.app_version }} \
        -t my-app:${{ steps.version.outputs.app_version }} .

Step Name Rules

Allowed characters: [a-zA-Z0-9_-]

Length: 1-255 characters

Must be unique within the same Job

working-directory

Overrides the working directory for a Step. Only relative paths are allowed.

steps:
  - name: test-frontend
    run: npm test
    image: node:18
    working-directory: frontend

  - name: test-backend
    run: npm test
    image: node:18
    working-directory: backend

working-directory must be a relative path and cannot contain ...

timeout-minutes

Sets a timeout for a Step or Job. If execution exceeds the specified time, it is automatically terminated.

steps:
  - name: long-test
    run: npm run test:e2e
    image: node:18
    timeout-minutes: 30

timeout-minutes is only supported with run. It cannot be used with uses.

Unsupported Features

FeatureAlternative
Step-level ifUse Job-level if or shell conditionals inside run

Step-level Condition Alternative

Since Step-level if is not supported, you can achieve the same effect using shell conditionals inside run.

steps:
  - name: conditional-deploy
    run: |
      # Implement Step-level condition using shell conditional
      if [ "$DEPLOY_ENV" = "production" ]; then
        echo "Deploying to production..."
        ./deploy-prod.sh
      else
        echo "Skipping production deploy"
      fi
    env:
      DEPLOY_ENV: ${{ vars.DEPLOY_ENV }}

Table of Contents