Skip to main content

CI/CD Integration

The Roboticks CLI is designed for seamless CI/CD integration with automatic non-interactive mode detection, API key authentication, and machine-readable output.

Quick Setup

# Set environment variables
export ROBOTICKS_API_KEY=rbtk_xxxxxxxxxxxxxxxx
export ROBOTICKS_ORG=acme
export ROBOTICKS_PROJECT=warehouse

# CLI automatically uses non-interactive mode in CI
rbtk capsule push ./build.tar.gz --name app --version $VERSION

GitHub Actions

Basic Workflow

name: Deploy to Roboticks

on:
  push:
    branches: [main]

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Set up Python
        uses: actions/setup-python@v5
        with:
          python-version: '3.11'

      - name: Install Roboticks CLI
        run: pip install roboticks-cli

      - name: Build application
        run: |
          # Your build steps here
          tar -czf build.tar.gz ./dist

      - name: Upload capsule
        env:
          ROBOTICKS_API_KEY: ${{ secrets.ROBOTICKS_API_KEY }}
          ROBOTICKS_ORG: ${{ secrets.ROBOTICKS_ORG }}
          ROBOTICKS_PROJECT: ${{ secrets.ROBOTICKS_PROJECT }}
        run: |
          rbtk capsule push ./build.tar.gz \
            --name app \
            --version ${{ github.sha }}

      - name: Deploy to staging
        env:
          ROBOTICKS_API_KEY: ${{ secrets.ROBOTICKS_API_KEY }}
          ROBOTICKS_ORG: ${{ secrets.ROBOTICKS_ORG }}
          ROBOTICKS_PROJECT: ${{ secrets.ROBOTICKS_PROJECT }}
        run: |
          # Create package and rollout
          CAPSULE_ID=$(rbtk capsule list --name app --output ids | head -1)
          rbtk package create --name "release-${{ github.sha }}" --capsule $CAPSULE_ID
          PACKAGE_ID=$(rbtk package list --output ids | head -1)
          rbtk rollout create --package $PACKAGE_ID --group staging --start

With Test Simulation

name: Test and Deploy

on:
  push:
    branches: [main]

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Set up Python
        uses: actions/setup-python@v5
        with:
          python-version: '3.11'

      - name: Install CLI
        run: pip install roboticks-cli

      - name: Upload test package
        env:
          ROBOTICKS_API_KEY: ${{ secrets.ROBOTICKS_API_KEY }}
          ROBOTICKS_ORG: ${{ secrets.ROBOTICKS_ORG }}
          ROBOTICKS_PROJECT: ${{ secrets.ROBOTICKS_PROJECT }}
        run: |
          tar -czf tests.tar.gz ./tests
          rbtk test-package push ./tests.tar.gz \
            --name test-suite \
            --version ${{ github.sha }}

      - name: Run simulation tests
        env:
          ROBOTICKS_API_KEY: ${{ secrets.ROBOTICKS_API_KEY }}
          ROBOTICKS_ORG: ${{ secrets.ROBOTICKS_ORG }}
          ROBOTICKS_PROJECT: ${{ secrets.ROBOTICKS_PROJECT }}
        run: |
          TEST_PKG_ID=$(rbtk test-package list --output ids | head -1)
          JOB_ID=$(rbtk simulate run --fleet 1 --test $TEST_PKG_ID --output json | jq -r '.id')

          # Wait for completion
          rbtk simulate watch $JOB_ID

          # Check result
          STATUS=$(rbtk simulate get $JOB_ID --output json | jq -r '.status')
          if [ "$STATUS" != "completed" ]; then
            echo "Tests failed with status: $STATUS"
            exit 1
          fi

  deploy:
    needs: test
    runs-on: ubuntu-latest
    steps:
      # ... deployment steps

GitLab CI

stages:
  - build
  - test
  - deploy

variables:
  PIP_CACHE_DIR: "$CI_PROJECT_DIR/.cache/pip"

cache:
  paths:
    - .cache/pip

build:
  stage: build
  image: python:3.11
  script:
    - pip install roboticks-cli
    - tar -czf build.tar.gz ./dist
    - rbtk capsule push ./build.tar.gz --name app --version $CI_COMMIT_SHA
  variables:
    ROBOTICKS_API_KEY: $ROBOTICKS_API_KEY
    ROBOTICKS_ORG: $ROBOTICKS_ORG
    ROBOTICKS_PROJECT: $ROBOTICKS_PROJECT

test:
  stage: test
  image: python:3.11
  script:
    - pip install roboticks-cli
    - tar -czf tests.tar.gz ./tests
    - rbtk test-package push ./tests.tar.gz --name test-suite --version $CI_COMMIT_SHA
    - |
      TEST_PKG_ID=$(rbtk test-package list --output ids | head -1)
      JOB_ID=$(rbtk simulate run --fleet 1 --test $TEST_PKG_ID --output json | jq -r '.id')
      rbtk simulate watch $JOB_ID
  variables:
    ROBOTICKS_API_KEY: $ROBOTICKS_API_KEY
    ROBOTICKS_ORG: $ROBOTICKS_ORG
    ROBOTICKS_PROJECT: $ROBOTICKS_PROJECT

deploy:
  stage: deploy
  image: python:3.11
  script:
    - pip install roboticks-cli
    - |
      CAPSULE_ID=$(rbtk capsule list --name app --output ids | head -1)
      rbtk package create --name "release-$CI_COMMIT_SHA" --capsule $CAPSULE_ID
      PACKAGE_ID=$(rbtk package list --output ids | head -1)
      rbtk rollout create --package $PACKAGE_ID --group production --start
  variables:
    ROBOTICKS_API_KEY: $ROBOTICKS_API_KEY
    ROBOTICKS_ORG: $ROBOTICKS_ORG
    ROBOTICKS_PROJECT: $ROBOTICKS_PROJECT
  only:
    - main

Jenkins

pipeline {
    agent any

    environment {
        ROBOTICKS_API_KEY = credentials('roboticks-api-key')
        ROBOTICKS_ORG = 'acme'
        ROBOTICKS_PROJECT = 'warehouse'
    }

    stages {
        stage('Setup') {
            steps {
                sh 'pip install roboticks-cli'
            }
        }

        stage('Build') {
            steps {
                sh 'tar -czf build.tar.gz ./dist'
                sh "rbtk capsule push ./build.tar.gz --name app --version ${env.BUILD_NUMBER}"
            }
        }

        stage('Test') {
            steps {
                sh 'tar -czf tests.tar.gz ./tests'
                sh "rbtk test-package push ./tests.tar.gz --name test-suite --version ${env.BUILD_NUMBER}"
                script {
                    def testPkgId = sh(
                        script: "rbtk test-package list --output ids | head -1",
                        returnStdout: true
                    ).trim()
                    def jobId = sh(
                        script: "rbtk simulate run --fleet 1 --test ${testPkgId} --output json | jq -r '.id'",
                        returnStdout: true
                    ).trim()
                    sh "rbtk simulate watch ${jobId}"
                }
            }
        }

        stage('Deploy') {
            when {
                branch 'main'
            }
            steps {
                script {
                    def capsuleId = sh(
                        script: "rbtk capsule list --name app --output ids | head -1",
                        returnStdout: true
                    ).trim()
                    sh "rbtk package create --name release-${env.BUILD_NUMBER} --capsule ${capsuleId}"
                    def packageId = sh(
                        script: "rbtk package list --output ids | head -1",
                        returnStdout: true
                    ).trim()
                    sh "rbtk rollout create --package ${packageId} --group production --start"
                }
            }
        }
    }
}

Best Practices

Use Output Formats for Scripting

# Get IDs for piping
CAPSULE_ID=$(rbtk capsule list --name app --output ids | head -1)

# Get JSON for complex parsing
rbtk device list --output json | jq '.[] | select(.status == "online")'

# Use YAML for human-readable config dumps
rbtk config get production --output yaml > config-backup.yaml

Handle Errors Gracefully

#!/bin/bash
set -e  # Exit on error

# Check authentication before proceeding
if ! rbtk auth status > /dev/null 2>&1; then
    echo "Authentication failed"
    exit 1
fi

# Verify capsule upload
if ! rbtk capsule push ./build.tar.gz --name app --version $VERSION; then
    echo "Capsule upload failed"
    exit 1
fi

echo "Deployment successful"

Version Your Artifacts

# Use git SHA for traceability
VERSION="${GITHUB_SHA:-$(git rev-parse HEAD)}"

rbtk capsule push ./build.tar.gz --name app --version $VERSION
rbtk test-package push ./tests.tar.gz --name tests --version $VERSION

Store Secrets Securely

Never commit API keys or store them in plain text. Use your CI/CD platform’s secrets management.
PlatformSecret Storage
GitHub ActionsRepository Secrets
GitLab CICI/CD Variables (masked)
JenkinsCredentials Plugin
CircleCIEnvironment Variables

Troubleshooting

Ensure the environment is detected as non-interactive:
export ROBOTICKS_NO_INTERACTIVE=true
  • Verify the API key is correctly set
  • Check the key hasn’t expired
  • Ensure the key has access to the org/project
Use --output json for reliable machine parsing:
rbtk device list --output json | jq -r '.[0].id'