CollabOps

Core

Checkout, Docker build, cache, artifacts — essential building blocks for pipelines

collabops/checkout@v2

On-Premise: ✅ airgapped compatible

Checks out a Git repository. Auto-detects SSH or HTTPS based on the repo-url scheme. HTTPS uses the platform-injected Job Token, so no credentials setup is required.

Recommended: HTTPS repo-url with automatic JobToken auth. Use ssh-key only for external hosts or SSH-only environments, and prefer a per-repository deploy key over a personal account key. See the Authentication page for the full rationale and a migration walkthrough.

InputRequiredDefaultDescription
repo-urlYES-Git repository URL. SSH (git@host:ns/repo.git, ssh://...) or HTTPS (https://host/ns/repo.git)
refNO$\{\{ collabops.ref_name \}\}Git ref to check out (branch, tag, SHA)
event-nameNO$\{\{ collabops.event_name \}\}Event type. Automatically uses head-ref for change_request events
head-refNO$\{\{ collabops.head_ref \}\}Source (head) branch name for change_request events
shaNO$\{\{ collabops.sha \}\}Exact commit SHA to check out
ssh-keyNO""SSH private key (base64-encoded). Required when using an SSH URL
fetch-depthNO"1"History depth (0 = full, 1 = shallow)
cleanNO"true"Clean existing source directory before cloning
pathNO"/workspace/source"Checkout target path

Examples

jobs:
  build:
    steps:
      # The common case. JobToken is auto-injected; no credentials setup required.
      - name: checkout
        uses: "collabops/checkout@v2"
        with:
          repo-url: "https://<collabops-host>/<workspace>/<repository>.git"
        image: node:22-alpine

Change Request — auto head branch

# Change Request event — use the change_request trigger.
triggers:
  change_request:
    branches: [main]

jobs:
  test:
    steps:
      # event-name defaults to collabops.event_name. For change_request,
      # head-ref (source branch) is used automatically — no ref override needed.
      - name: checkout-pr-head
        uses: "collabops/checkout@v2"
        with:
          repo-url: "https://<collabops-host>/<workspace>/<repository>.git"
        image: node:22-alpine

Full history + custom path

jobs:
  release-notes:
    steps:
      - name: checkout-full-history
        uses: "collabops/checkout@v2"
        with:
          repo-url: "https://<collabops-host>/<workspace>/<repository>.git"
          fetch-depth: "0"            # needed when git log / diff spans the full history
          path: "/workspace/src"      # custom path instead of the default /workspace/source
        image: alpine/git:2.45.2
      - name: generate-changelog
        run: |
          cd /workspace/src
          git log --oneline --no-merges \
            $(git describe --tags --abbrev=0)..HEAD > /workspace/source/CHANGELOG.txt
        image: alpine/git:2.45.2

External host — SSH deploy key

jobs:
  mirror:
    steps:
      # External SaaS (e.g. GitHub.com) or other SSH-only host.
      # Prefer a per-repo Deploy Key (base64-encoded) over a personal SSH key.
      - name: checkout-external
        uses: "collabops/checkout@v2"
        with:
          repo-url: "git@github.com:my-org/private-repo.git"
          ref: main
          ssh-key: ${{ secrets.MIRROR_DEPLOY_KEY_B64 }}
        image: alpine/git:2.45.2

Key points — HTTPS + JobToken is the default and recommended path; reserve SSH for external hosts. On change_request events the head branch is selected automatically. Only set fetch-depth: 0 when a job needs the full history (git log, semantic-release, etc.). When checking out multiple repos in one Job, use path to avoid collisions.

collabops/docker-login@v1

On-Premise: ✅ airgapped compatible

Generic Docker registry authentication. Generates .docker/config.json from username/password so that docker-build-push can authenticate its push. Defaults to Docker Hub when registry is omitted. For GCP Artifact Registry use gcloud-docker-auth, for AWS ECR use aws-ecr-auth.

InputRequiredDefaultDescription
registryNO"docker.io"Docker registry host (e.g., ghcr.io). Defaults to Docker Hub
usernameYES-Registry username
passwordYES-Registry password or access token. Pass via $\{\{ secrets.* \}\}
config-pathNO"/workspace/source"Base path for .docker/config.json. Must match docker-build-push's docker-config

Examples

GHCR (GitHub Container Registry)

jobs:
  publish:
    services:
      - docker
    steps:
      - name: docker-login
        uses: "collabops/docker-login@v1"
        with:
          registry: ghcr.io
          username: ${{ secrets.GHCR_USER }}
          # PAT or GHCR token. Needs read:packages / write:packages scope.
          password: ${{ secrets.GHCR_TOKEN }}
      - name: build-push
        uses: "collabops/docker-build-push@v1"
        with:
          tags: "ghcr.io/my-org/api:${{ collabops.sha }}"

Docker Hub (registry omitted)

jobs:
  publish:
    services:
      - docker
    steps:
      - name: docker-login
        # Omit registry → docker.io (Docker Hub) is the default.
        uses: "collabops/docker-login@v1"
        with:
          username: ${{ secrets.DOCKERHUB_USER }}
          password: ${{ secrets.DOCKERHUB_TOKEN }}
      - name: build-push
        uses: "collabops/docker-build-push@v1"
        with:
          tags: "my-org/api:latest"

Private registry + custom config-path

jobs:
  publish:
    services:
      - docker
    steps:
      - name: login-internal-registry
        uses: "collabops/docker-login@v1"
        with:
          registry: registry.internal.example.com
          username: ${{ secrets.INTERNAL_REG_USER }}
          password: ${{ secrets.INTERNAL_REG_TOKEN }}
          # Must point to the same directory used by docker-build-push's docker-config.
          config-path: /workspace/source/.ci
      - name: build-push
        uses: "collabops/docker-build-push@v1"
        with:
          tags: "registry.internal.example.com/team/api:${{ collabops.sha }}"
          docker-config: /workspace/source/.ci/.docker/config.json

Key points — Always pass username/password via secrets. Use the dedicated aws-ecr-auth / gcloud-docker-auth templates for ECR or Artifact Registry instead of docker-login. If you override config-path, set docker-build-push's docker-config to the matching location.

collabops/docker-build-push@v1

On-Premise: ✅ airgapped compatible

Builds Docker images and pushes with multiple tags. To push an image, run an authentication template first — docker-login · gcloud-docker-auth · aws-ecr-auth.

InputRequiredDefaultDescription
tagsYES-List of image tags (newline-separated)
contextNO"/workspace/source"Build context path
fileNO"Dockerfile"Dockerfile path (relative to context)
pushNO"true"Whether to push after building
build-argsNO""Build arguments (KEY=VALUE, newline-separated)
targetNO""Target stage for multi-stage builds
platformNO""Target platform (e.g., linux/amd64). Single platform only — multi-arch requires buildx
cache-fromNO""Cache source
cache-toNO""Cache destination (type=inline). type=registry,mode=max requires buildx
extra-argsNO""Additional docker build arguments
docker-configNO"/workspace/source/.docker/config.json"Auth config.json path. The file generated by docker-login or another auth template

Examples

Single-tag build + push

jobs:
  build:
    services:
      - docker
    steps:
      - name: login
        uses: "collabops/docker-login@v1"
        with:
          registry: ghcr.io
          username: ${{ secrets.GHCR_USER }}
          password: ${{ secrets.GHCR_TOKEN }}
      - name: build-push
        uses: "collabops/docker-build-push@v1"
        with:
          # Single commit-SHA tag — the simplest shape.
          tags: "ghcr.io/my-org/api:${{ collabops.sha }}"

Multi-tag (SHA + latest + branch)

jobs:
  build:
    services:
      - docker
    steps:
      - name: login
        uses: "collabops/docker-login@v1"
        with:
          registry: ghcr.io
          username: ${{ secrets.GHCR_USER }}
          password: ${{ secrets.GHCR_TOKEN }}
      - name: build-push-multi
        uses: "collabops/docker-build-push@v1"
        with:
          # Newline-separated tags push in a single shot. ref_name is the branch name.
          tags: |
            ghcr.io/my-org/api:${{ collabops.sha }}
            ghcr.io/my-org/api:${{ collabops.ref_name }}
            ghcr.io/my-org/api:latest

Multi-stage target + build-args + platform

jobs:
  build:
    services:
      - docker
    steps:
      - name: login
        uses: "collabops/docker-login@v1"
        with:
          registry: ghcr.io
          username: ${{ secrets.GHCR_USER }}
          password: ${{ secrets.GHCR_TOKEN }}
      - name: build-runner-stage
        uses: "collabops/docker-build-push@v1"
        with:
          tags: "ghcr.io/my-org/web:${{ collabops.sha }}"
          file: Dockerfile
          target: runner               # Final stage name in a multi-stage Dockerfile
          platform: linux/amd64        # Single platform only (multi-arch needs buildx)
          build-args: |
            NODE_ENV=production
            BUILD_REVISION=${{ collabops.sha }}

Inline cache for faster rebuilds

jobs:
  build:
    services:
      - docker
    steps:
      - name: login
        uses: "collabops/docker-login@v1"
        with:
          registry: ghcr.io
          username: ${{ secrets.GHCR_USER }}
          password: ${{ secrets.GHCR_TOKEN }}
      - name: build-with-inline-cache
        uses: "collabops/docker-build-push@v1"
        with:
          tags: |
            ghcr.io/my-org/api:${{ collabops.sha }}
            ghcr.io/my-org/api:cache
          # type=inline works without buildx. Re-use the previous :cache tag as the source.
          cache-from: type=registry,ref=ghcr.io/my-org/api:cache
          cache-to: type=inline

Key points — Always run an auth step first, in the same Job. tags accepts a newline-separated list to push many tags at once. Buildx-only cache forms (e.g. type=registry,mode=max) need a buildx-enabled image — stick to type=inline on the standard docker:27.1 image. Switch to a buildx-enabled image when you need multi-arch builds.

collabops/cache@v2

On-Premise: ✅ airgapped compatible

Stores and restores dependency caches using platform storage. Use separate steps for restore and save operations. Airgapped On-Premise compatible — copies the mc binary from the minio/mc image into the workspace, so no runtime external download is needed.

InputRequiredDefaultDescription
actionYES-Cache action (restore or save)
pathYES-Directory path to cache (relative paths use /workspace/source as base)
keyYES-Cache key (unique identifier)
restore-keysNO""Fallback cache key prefixes (newline-separated, used only during restore)

Examples

pnpm node_modules — restore → build → save

# Cache key combines the lockfile filename with the branch name. hashFiles() is unsupported.
# When the lockfile is unchanged on the same branch the key matches and the cache hits.
jobs:
  install:
    steps:
      - name: checkout
        uses: "collabops/checkout@v2"
        with:
          repo-url: "https://<collabops-host>/<workspace>/<repository>.git"
      - name: cache-restore
        uses: "collabops/cache@v2"
        with:
          action: restore
          path: node_modules
          key: "pnpm-${{ collabops.ref_name }}"
      - name: install-deps
        run: |
          corepack enable
          pnpm install --frozen-lockfile
        image: node:22-alpine
      - name: build
        run: pnpm build
        image: node:22-alpine
      - name: cache-save
        uses: "collabops/cache@v2"
        with:
          action: save
          path: node_modules
          key: "pnpm-${{ collabops.ref_name }}"

restore-keys fallback — reuse partial cache after lockfile churn

jobs:
  install:
    steps:
      - name: checkout
        uses: "collabops/checkout@v2"
        with:
          repo-url: "https://<collabops-host>/<workspace>/<repository>.git"
      - name: cache-restore-with-fallbacks
        uses: "collabops/cache@v2"
        with:
          action: restore
          path: node_modules
          key: "pnpm-${{ collabops.ref_name }}-${{ collabops.sha }}"
          # If no exact match, fall back to the freshest cache by prefix.
          # Tried top to bottom — the first matching prefix wins.
          restore-keys: |
            pnpm-${{ collabops.ref_name }}-
            pnpm-main-
            pnpm-

Key pointsrestore and save must be separate steps. hashFiles() is unsupported, so derive the key from deterministic values like collabops.ref_name. Use restore-keys to fall back to a more generic prefix after a lockfile churn. Step-level if is not supported — to avoid poisoning the cache on a failed build, split the save into a separate Job with if: "success()".

collabops/upload-artifact@v2

On-Premise: ✅ airgapped compatible

Uploads build artifacts to platform storage. Used for sharing files between jobs. Airgapped On-Premise compatible.

InputRequiredDefaultDescription
nameYES-Artifact name (e.g., build-output, dist)
pathYES-File or directory path to upload (relative paths use /workspace/source as base)

Examples

Upload a single directory

jobs:
  build:
    steps:
      - name: checkout
        uses: "collabops/checkout@v2"
        with:
          repo-url: "https://<collabops-host>/<workspace>/<repository>.git"
      - name: build
        run: |
          npm ci
          npm run build       # writes /workspace/source/dist
        image: node:22-alpine
      # Upload the build output so a downstream Job can consume it.
      - name: upload-dist
        uses: "collabops/upload-artifact@v2"
        with:
          name: web-dist
          path: dist           # relative paths resolve against /workspace/source

Key points — Use it to hand files from one Job to another. name must be unique within the workflow — download-artifact uses it to identify the upload. Single files work, but a directory makes parameterization easier.

collabops/download-artifact@v2

On-Premise: ✅ airgapped compatible

Downloads build artifacts from platform storage. Used to retrieve files uploaded by upload-artifact within the same workflow. Airgapped On-Premise compatible.

InputRequiredDefaultDescription
nameYES-Artifact name to download
pathNO""Restore path (relative paths use /workspace/source as base, defaults to artifact name if empty)

Examples

Two-Job flow — build uploads, deploy downloads

jobs:
  build:
    steps:
      - name: checkout
        uses: "collabops/checkout@v2"
        with:
          repo-url: "https://<collabops-host>/<workspace>/<repository>.git"
      - name: build-app
        run: |
          npm ci
          npm run build
        image: node:22-alpine
      - name: upload-dist
        uses: "collabops/upload-artifact@v2"
        with:
          name: web-dist
          path: dist

  deploy:
    needs: [build]                # Runs only after the build Job in the same workflow
    steps:
      # Receive the artifact under the same name. When path is omitted it expands
      # into a directory matching the name.
      - name: pull-build-output
        uses: "collabops/download-artifact@v2"
        with:
          name: web-dist
          path: dist
      - name: list-dist
        run: ls -la /workspace/source/dist   # Use the artifact in subsequent steps
        image: alpine:3.20

Key points — The name must match the upload-artifact exactly. Use needs to enforce Job ordering; otherwise the download Job may start before the upload finishes. If path is omitted the files expand into a directory named after name — declare it explicitly when that surprises callers.

Table of Contents