---
sidebar_label: 'Examples: CI/CD workflows'
toc_max_heading_level: 2
doc_id: 4c259a33-0172-4c67-b8ec-77ae99b11a8b
description: >-
  CI/CD workflow examples for integrating nullplatform with GitHub Actions and
  Azure DevOps pipelines.
keywords:
  - CI/CD
  - nullplatform
  - GitHub Actions
  - Azure DevOps
  - Docker
---

# Examples: CI/CD workflows

This section offers CI/CD workflow examples with various CI tools integrated with nullplatform. They cover building and
deploying Docker images, pushing assets, and updating build status with the **nullplatform CLI**.

## GitHub Actions

### Example: one build, one image per application

```yaml
name: CI/CD pipeline nullplatform
env:
  NULLPLATFORM_API_KEY: ${{ secrets.NULLPLATFORM_API_KEY }}
on:
  push:
    branches:
      - main
permissions:
  id-token: write
  contents: read
  packages: read

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - name: Install nullplatform CLI
        run: curl https://cli.nullplatform.com/install.sh | sh
      - name: Check out code
        uses: actions/checkout@v4
      - name: Create build on nullplatform
        run: np build start
      - name: Run code analysis
        run: ./code_analysis.sh
      - name: Build Docker image
        run: docker build -t my-app .
      - name: Push Docker image
        run: np asset push --type docker-image --source my-app
      - name: Add metadata
        run: np metadata create --entity build --data "{\"linter\": {\"code_smells\": $CODE_SMELLS}, \"coverage\": {\"percentage\": $COVERAGE}}"
      - name: Set the build as successful or failed
        if: ${{ always() }}
        run: np build update --status ${{ contains(fromJSON('["failure", "cancelled"]'), job.status) && 'failed' || 'successful' }}
```

## Azure DevOps

### Example: one build, one image per application

```yaml
trigger:
- main

pool: Default

variables:
- group: nullplatform-${{ variables['Build.DefinitionName'] }}

jobs:
- job: build
  steps:
  - script: curl https://cli.nullplatform.com/install.sh | sh
    displayName: 'Install nullplatform CLI'

  - script: np build start
    displayName: 'Create build on nullplatform'
    env:
      NULLPLATFORM_API_KEY: $(NULLPLATFORM_API_KEY)

  - script: docker build -t main .
    displayName: 'Build and test asset'

  - script: np asset push --type docker-image --source main
    displayName: 'Add the asset to the build'
    env:
      NULLPLATFORM_API_KEY: $(NULLPLATFORM_API_KEY)

  - script: np build update --status $(if [ "$(Agent.JobStatus)" = "Failed" ] || [ "$(Agent.JobStatus)" = "Canceled" ]; then echo "failed"; else echo "successful"; fi)
    displayName: 'Set the build as successful or failed'
    condition: always()
    env:
      NULLPLATFORM_API_KEY: $(NULLPLATFORM_API_KEY)
```

## Jenkins

### Example: one build, one image per application

```groovy
pipeline {
    agent any
    
    environment {
        NULLPLATFORM_API_KEY = credentials('NULLPLATFORM_API_KEY')
    }
    
    parameters {
        string(name: 'GIT_REPOSITORY', description: 'Repository to build')
        string(name: 'BRANCH', description: 'Branch to build', defaultValue: 'master')
    }

    stages {
        stage('Prepare Workspace') {
            steps {
                cleanWs()
            }
        }
        
        stage('Clone repository') {
            steps {
                git url: "${GIT_REPOSITORY}.git", branch: "$BRANCH", credentialsId: 'gitlab-crypto-kong-user'
            }
        }
        
        stage('Prepare last commit details') {
            steps {
                script {
                    env.COMMIT_SHA = sh(script: 'git rev-parse HEAD', returnStdout: true).trim()
                    env.COMMIT_PERMALINK = "${GIT_REPOSITORY}/commit/$COMMIT_SHA"
                    env.COMMIT_DESCRIPTION = sh(script: "git log -1 --pretty=%B $COMMIT_SHA", returnStdout: true).trim()
                }
            }
        }
        
        stage('Start nullplatform CI') {
            steps {
                sh "np build start --repository $GIT_REPOSITORY --branch $BRANCH --commit-sha $COMMIT_SHA --commit-permalink $COMMIT_PERMALINK --description '$COMMIT_DESCRIPTION'"
            }
        }
        
        stage('Build Docker Image') {
            steps {
                script {
                    docker.build('main:latest')
                }
            }
        }
        
        stage('Push asset') {
            steps {
                sh "np asset push --type docker-image --source main --repository $GIT_REPOSITORY --branch $BRANCH --commit-sha $COMMIT_SHA"
            }
        }
    }
    
    post {
        always {
            script {
                def jobStatus = currentBuild.currentResult
                def status = jobStatus == 'FAILURE' || jobStatus == 'ABORTED' ? 'failed' : 'successful'
                sh "np build update --status ${status} --repository $GIT_REPOSITORY --branch $BRANCH --commit-sha $COMMIT_SHA"
            }
        }
    }
}
```

## Gitlab

### Example: one build, one image per application

```yaml
default:
  image: alpine:latest

.setup-np-cli: &setup-np-cli
  - apk add curl
  - curl https://cli.nullplatform.com/install.sh | sh
  - source /root/.bashrc

build-start:
  stage: build
  before_script:
    - *setup-np-cli
  script:
    - np build start
  except:
    - tags

build-image:
  stage: build
  image:
    name: gcr.io/kaniko-project/executor:debug
    entrypoint: [""]
  script:
    - /kaniko/executor
      --context $CI_PROJECT_DIR
      --dockerfile $CI_PROJECT_DIR/Dockerfile
      --no-push
      --destination foo
      --tar-path image.tar
  artifacts:
    paths:
      - image.tar
  except:
    - tags

build-finalize:
  stage: build
  needs: 
    - build-start
    - build-image
  before_script:
    - *setup-np-cli
    - apk add crane
  script:
    - np asset push --type docker-image --source image.tar
    - np build update --status successful
  except:
    - tags

build-failed:
  stage: .post
  before_script:
    - *setup-np-cli
  script:
    - np build update --status=failed
  except:
    - tags
  when: on_failure
```

### Example: one repository, one application, one build, multiple assets (debug and live modes)

```yaml
build:
  stage: build
  image: 
    name: public.ecr.aws/nullplatform/np-cli:kaniko
    pull_policy: always
  script:
    - /np build start
    - modes="debug,live"
    - |+
      IFS=','
      for mode in $modes; do
        /kaniko/executor --context $CI_PROJECT_DIR --dockerfile $CI_PROJECT_DIR/Dockerfile --no-push --tarPath $mode.tar --destination foo:1 --build-arg=MODE=$mode
        /np asset push --type docker-image --source $mode.tar --name $mode
      done
    - /np build update --status=successful
  except:
    - tags

build-failed:
  stage: build
  image: 
    name: public.ecr.aws/nullplatform/np-cli:kaniko
    pull_policy: always
  script:
    - /np build update --status=failed
  except:
    - tags
  when: on_failure
```

### Example: one repository, multiple apps, one build, one asset per application (monorepo)

```yaml
build:
  stage: build
  image: 
    name: public.ecr.aws/nullplatform/np-cli:kaniko
    pull_policy: always
  script:
    - changed_applications=$(git diff --name-only HEAD^ HEAD -- apps | cut -d / -f 1,2 | uniq | paste -sd "," -)
    - |+
      IFS=','
      for app in $changed_applications; do
        /np build start --path $app
        /kaniko/executor --context $CI_PROJECT_DIR/$app --dockerfile $CI_PROJECT_DIR/$app/Dockerfile --no-push --tarPath $app.tar --destination foo:1
        /np asset push --type docker-image --source $app.tar --path $app
        /np build update --status=successful --path $app
      done
  except:
    - tags
```
