Skip to content

CI/CD Integration

Integrate Totis CLI into your continuous integration and deployment pipelines to automatically upload builds.

Environment Variables

Set these environment variables in your CI/CD system:

Variable Description
TOTIS_SERVER_URL Totis API URL
TOTIS_CLIENT_ID Service account client ID
TOTIS_CLIENT_SECRET Service account client secret

GitHub Actions

Basic Workflow

name: Build and Upload

on:
  push:
    tags:
      - 'v*'

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

      - name: Build Application
        run: ./build.sh

      - name: Install Totis CLI
        run: |
          curl -L https://github.com/gameforgelabs/totis/releases/latest/download/totis-linux-amd64 -o totis
          chmod +x totis
          sudo mv totis /usr/local/bin/

      - name: Upload to Totis
        env:
          TOTIS_SERVER_URL: ${{ secrets.TOTIS_URL }}
        run: |
          totis auth login \
            --client-id "${{ secrets.TOTIS_CLIENT_ID }}" \
            --client-secret "${{ secrets.TOTIS_CLIENT_SECRET }}"

          totis build create \
            --workspace "${{ vars.WORKSPACE_SLUG }}" \
            --project "${{ vars.PROJECT_SLUG }}" \
            --version "${GITHUB_REF_NAME#v}" \
            --name "Release ${GITHUB_REF_NAME}" \
            --platform ANDROID \
            --type RELEASE \
            --commit "${{ github.sha }}" \
            --branch "${{ github.ref_name }}" \
            --ci-url "${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}" \
            --tag production \
            --tag "${{ github.ref_name }}" \
            --file ./app/build/outputs/apk/release/app-release.apk

Android Build with Multiple Artifacts

name: Android Release

on:
  release:
    types: [published]

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

      - name: Set up JDK
        uses: actions/setup-java@v4
        with:
          java-version: '17'
          distribution: 'temurin'

      - name: Build Release APK
        run: ./gradlew assembleRelease

      - name: Upload to Totis
        env:
          TOTIS_SERVER_URL: ${{ secrets.TOTIS_URL }}
        run: |
          # Install CLI
          curl -sL https://github.com/gameforgelabs/totis/releases/latest/download/totis-linux-amd64 -o totis
          chmod +x totis && sudo mv totis /usr/local/bin/

          # Authenticate
          totis auth login \
            --client-id "${{ secrets.TOTIS_CLIENT_ID }}" \
            --client-secret "${{ secrets.TOTIS_CLIENT_SECRET }}"

          # Upload build with all APK variants
          totis build create \
            --workspace my-company \
            --project my-android-app \
            --version "${{ github.event.release.tag_name }}" \
            --name "${{ github.event.release.name }}" \
            --platform ANDROID \
            --type RELEASE \
            --commit "${{ github.sha }}" \
            --notes "${{ github.event.release.body }}" \
            --tag release \
            --tag "${{ github.event.release.tag_name }}" \
            --file ./app/build/outputs/apk/release/app-arm64-v8a-release.apk \
            --file ./app/build/outputs/apk/release/app-armeabi-v7a-release.apk \
            --file ./app/build/outputs/apk/release/app-x86_64-release.apk \
            --file ./app/build/outputs/mapping/release/mapping.txt

GitLab CI

stages:
  - build
  - upload

build:
  stage: build
  script:
    - ./build.sh
  artifacts:
    paths:
      - build/output/

upload:
  stage: upload
  image: golang:1.21
  variables:
    TOTIS_SERVER_URL: ${TOTIS_URL}
  script:
    - go install github.com/gameforgelabs/totis@latest
    - |
      totis auth login \
        --client-id "${TOTIS_CLIENT_ID}" \
        --client-secret "${TOTIS_CLIENT_SECRET}"
    - |
      totis build create \
        --workspace "${WORKSPACE_SLUG}" \
        --project "${PROJECT_SLUG}" \
        --version "${CI_COMMIT_TAG}" \
        --name "Build ${CI_PIPELINE_ID}" \
        --platform ANDROID \
        --type CI \
        --commit "${CI_COMMIT_SHA}" \
        --branch "${CI_COMMIT_REF_NAME}" \
        --ci-url "${CI_PIPELINE_URL}" \
        --tag ci \
        --tag "${CI_COMMIT_REF_NAME}" \
        --file ./build/output/app-release.apk
  only:
    - tags

Jenkins

Pipeline Script

pipeline {
    agent any

    environment {
        TOTIS_SERVER_URL = credentials('totis-url')
        TOTIS_CLIENT_ID = credentials('totis-client-id')
        TOTIS_CLIENT_SECRET = credentials('totis-client-secret')
    }

    stages {
        stage('Build') {
            steps {
                sh './gradlew assembleRelease'
            }
        }

        stage('Upload to Totis') {
            steps {
                sh '''
                    # Install Totis CLI
                    curl -sL https://github.com/gameforgelabs/totis/releases/latest/download/totis-linux-amd64 -o totis
                    chmod +x totis

                    # Authenticate
                    ./totis auth login \
                        --client-id "${TOTIS_CLIENT_ID}" \
                        --client-secret "${TOTIS_CLIENT_SECRET}"

                    # Create build and upload
                    ./totis build create \
                        --workspace my-company \
                        --project my-app \
                        --version "${BUILD_NUMBER}" \
                        --name "Build #${BUILD_NUMBER}" \
                        --platform ANDROID \
                        --type CI \
                        --commit "${GIT_COMMIT}" \
                        --branch "${GIT_BRANCH}" \
                        --ci-url "${BUILD_URL}" \
                        --tag jenkins \
                        --tag "${GIT_BRANCH}" \
                        --file ./app/build/outputs/apk/release/app-release.apk
                '''
            }
        }
    }
}

CircleCI

version: 2.1

jobs:
  build-and-upload:
    docker:
      - image: cimg/android:2024.01

    steps:
      - checkout

      - run:
          name: Build APK
          command: ./gradlew assembleRelease

      - run:
          name: Install Totis CLI
          command: |
            curl -sL https://github.com/gameforgelabs/totis/releases/latest/download/totis-linux-amd64 -o totis
            chmod +x totis
            sudo mv totis /usr/local/bin/

      - run:
          name: Upload to Totis
          command: |
            totis auth login \
              --client-id "${TOTIS_CLIENT_ID}" \
              --client-secret "${TOTIS_CLIENT_SECRET}" \
              --server "${TOTIS_URL}"

            totis build create \
              --workspace my-company \
              --project my-app \
              --version "1.0.${CIRCLE_BUILD_NUM}" \
              --name "Build ${CIRCLE_BUILD_NUM}" \
              --platform ANDROID \
              --type CI \
              --commit "${CIRCLE_SHA1}" \
              --branch "${CIRCLE_BRANCH}" \
              --ci-url "${CIRCLE_BUILD_URL}" \
              --tag circleci \
              --file ./app/build/outputs/apk/release/app-release.apk

workflows:
  build:
    jobs:
      - build-and-upload:
          filters:
            branches:
              only: main

Bitbucket Pipelines

pipelines:
  tags:
    'v*':
      - step:
          name: Build and Upload
          image: openjdk:17
          script:
            - ./gradlew assembleRelease

            # Install Totis CLI
            - curl -sL https://github.com/gameforgelabs/totis/releases/latest/download/totis-linux-amd64 -o totis
            - chmod +x totis

            # Authenticate and upload
            - ./totis auth login --client-id "$TOTIS_CLIENT_ID" --client-secret "$TOTIS_CLIENT_SECRET" --server "$TOTIS_URL"
            - |
              ./totis build create \
                --workspace my-company \
                --project my-app \
                --version "${BITBUCKET_TAG#v}" \
                --name "Release ${BITBUCKET_TAG}" \
                --platform ANDROID \
                --type RELEASE \
                --commit "${BITBUCKET_COMMIT}" \
                --branch "${BITBUCKET_BRANCH}" \
                --ci-url "https://bitbucket.org/${BITBUCKET_WORKSPACE}/${BITBUCKET_REPO_SLUG}/pipelines/results/${BITBUCKET_BUILD_NUMBER}" \
                --tag release \
                --file ./app/build/outputs/apk/release/app-release.apk

Best Practices

Secure Credential Storage

  1. Never commit credentials to version control
  2. Use your CI/CD platform's secret management
  3. Create dedicated service accounts for CI/CD
  4. Rotate credentials regularly

Error Handling

Use --continue-on-error for non-critical files:

totis build create \
  --workspace my-company \
  --project my-app \
  --version 1.0.0 \
  --name "Release" \
  --file app.apk \
  --file mapping.txt \
  --file debug-symbols.zip \
  --continue-on-error

Tagging Strategy

Use consistent tags for filtering:

Tag Purpose
ci All CI builds
release Production releases
beta Beta releases
{branch} Branch name
{version} Version number

Versioning

Extract version from your build system:

# From package.json
VERSION=$(node -p "require('./package.json').version")

# From build.gradle
VERSION=$(grep "versionName" app/build.gradle | awk '{print $2}' | tr -d '"')

# From git tag
VERSION="${GITHUB_REF_NAME#v}"