Set Up CI/CD for Optimizely Cloud
Why automate your pipeline
Section titled “Why automate your pipeline”Manual deployments are slow and error-prone. A developer has to remember the right steps, run the right commands, and verify the result. CI/CD automation removes this friction — every push triggers a consistent build, test, and deploy sequence. This gives your team faster feedback, fewer deployment mistakes, and a clear audit trail.
Approach overview
Section titled “Approach overview”While Optimizely Cloud has a built-in deployment system triggered by Git pushes, many teams prefer external CI/CD for additional control over build steps, test execution, and quality gates. The external pipeline builds the application, runs tests, and then pushes the deployment package to Optimizely Cloud via API.
Code Push → CI Build → Run Tests → Package → Deploy via API → VerifyOption A: GitHub Actions
Section titled “Option A: GitHub Actions”Create the workflow file
Section titled “Create the workflow file”Add .github/workflows/deploy.yml to your repository:
name: Deploy to Optimizely Cloud
on: push: branches: [develop]
env: DOTNET_VERSION: '8.0.x' OPTI_PROJECT_ID: ${{ secrets.OPTI_PROJECT_ID }} OPTI_API_KEY: ${{ secrets.OPTI_API_KEY }}
jobs: build-and-deploy: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4
- name: Setup .NET uses: actions/setup-dotnet@v4 with: dotnet-version: ${{ env.DOTNET_VERSION }}
- name: Restore dependencies run: dotnet restore
- name: Build run: dotnet build --configuration Release --no-restore
- name: Run tests run: dotnet test --no-build --configuration Release
- name: Publish run: dotnet publish --configuration Release --output ./publish
- name: Package run: | cd publish zip -r ../deploy-package.zip .
- name: Deploy to Integration run: | curl -X POST \ "https://paasportal.episerver.net/api/v1.0/projects/$OPTI_PROJECT_ID/deployments" \ -H "Authorization: Bearer $OPTI_API_KEY" \ -H "Content-Type: multipart/form-data" \ -F "file=@deploy-package.zip" \ -F "targetEnvironment=Integration"Configure secrets
Section titled “Configure secrets”In your GitHub repository:
- Go to Settings > Secrets and variables > Actions
- Add
OPTI_PROJECT_ID— Your project identifier from the management portal - Add
OPTI_API_KEY— API key generated in the portal under Settings > API Keys
Option B: Azure DevOps
Section titled “Option B: Azure DevOps”Create the pipeline file
Section titled “Create the pipeline file”Add azure-pipelines.yml to your repository:
trigger: branches: include: - develop
pool: vmImage: 'ubuntu-latest'
variables: dotnetVersion: '8.0.x' buildConfiguration: 'Release'
stages: - stage: Build jobs: - job: BuildAndTest steps: - task: UseDotNet@2 inputs: version: $(dotnetVersion)
- script: dotnet restore displayName: 'Restore dependencies'
- script: dotnet build --configuration $(buildConfiguration) --no-restore displayName: 'Build'
- script: dotnet test --configuration $(buildConfiguration) --no-build displayName: 'Run tests'
- script: dotnet publish --configuration $(buildConfiguration) --output $(Build.ArtifactStagingDirectory) displayName: 'Publish'
- task: ArchiveFiles@2 inputs: rootFolderOrFile: $(Build.ArtifactStagingDirectory) archiveType: 'zip' archiveFile: '$(Build.ArtifactStagingDirectory)/deploy-package.zip'
- publish: $(Build.ArtifactStagingDirectory)/deploy-package.zip artifact: deployment
- stage: Deploy dependsOn: Build jobs: - deployment: DeployIntegration environment: 'integration' strategy: runOnce: deploy: steps: - script: | curl -X POST \ "https://paasportal.episerver.net/api/v1.0/projects/$(OPTI_PROJECT_ID)/deployments" \ -H "Authorization: Bearer $(OPTI_API_KEY)" \ -H "Content-Type: multipart/form-data" \ -F "file=@$(Pipeline.Workspace)/deployment/deploy-package.zip" \ -F "targetEnvironment=Integration" displayName: 'Deploy to Integration'Configure variables
Section titled “Configure variables”In Azure DevOps:
- Go to Pipelines > Library > Variable Groups
- Create a variable group named
optimizely-cloud - Add
OPTI_PROJECT_IDandOPTI_API_KEY(mark the API key as secret) - Link the variable group to your pipeline
Add quality gates
Section titled “Add quality gates”Extend your pipeline with additional quality checks:
Code analysis
Section titled “Code analysis”- name: Run code analysis run: dotnet format --verify-no-changesSecurity scanning
Section titled “Security scanning”- name: Scan for vulnerabilities run: dotnet list package --vulnerable --include-transitiveSmoke tests after deployment
Section titled “Smoke tests after deployment”- name: Smoke test run: | STATUS=$(curl -s -o /dev/null -w "%{http_code}" https://mysite.inte.optimizely.cloud) if [ "$STATUS" != "200" ]; then echo "Smoke test failed with status $STATUS" exit 1 fiPromote between environments
Section titled “Promote between environments”Add manual approval gates for Preproduction and Production deployments:
- GitHub Actions — Use environments with required reviewers
- Azure DevOps — Use environment approvals and gates
This ensures code only reaches Production after a human reviews the Preproduction deployment.