CI/CD (Continuous Integration e Continuous Delivery) e a pratica de automatizar a integracao, teste e entrega de software. Para projetos Kotlin, um pipeline de CI/CD bem configurado garante que cada mudanca de codigo seja compilada, testada e, quando aprovada, entregue automaticamente ao ambiente de producao. Neste guia, vamos configurar pipelines completos usando GitHub Actions, GitLab CI e Jenkins, cobrindo desde testes unitarios ate deploy em ambientes de producao com Docker e Kubernetes.
Fundamentos de CI/CD
O ciclo basico de CI/CD para um projeto Kotlin envolve: compilar o codigo, executar testes unitarios e de integracao, analisar qualidade de codigo, gerar artefatos (JAR, Docker image) e fazer deploy. Cada etapa e automatizada e executada em sequencia, com falhas bloqueando etapas subsequentes.
Um bom pipeline segue o principio de fail fast: testes rapidos rodam primeiro para dar feedback imediato, enquanto testes mais demorados e deploy ficam em etapas posteriores.
GitHub Actions para Projetos Kotlin
O GitHub Actions e a solucao de CI/CD integrada ao GitHub. Crie o arquivo .github/workflows/ci.yml:
// .github/workflows/ci.yml
name: CI Pipeline
on:
push:
branches: [ main, develop ]
pull_request:
branches: [ main ]
env:
GRADLE_OPTS: -Dorg.gradle.daemon=false
jobs:
build-and-test:
runs-on: ubuntu-latest
services:
postgres:
image: postgres:16
env:
POSTGRES_DB: testdb
POSTGRES_USER: testuser
POSTGRES_PASSWORD: testpass
ports:
- 5432:5432
options: >-
--health-cmd pg_isready
--health-interval 10s
--health-timeout 5s
--health-retries 5
steps:
- uses: actions/checkout@v4
- name: Configurar JDK 17
uses: actions/setup-java@v4
with:
java-version: '17'
distribution: 'temurin'
- name: Cache Gradle
uses: actions/cache@v4
with:
path: |
~/.gradle/caches
~/.gradle/wrapper
key: gradle-${{ hashFiles('**/*.gradle.kts') }}
restore-keys: gradle-
- name: Dar permissao ao Gradle Wrapper
run: chmod +x gradlew
- name: Compilar
run: ./gradlew build -x test
- name: Executar testes unitarios
run: ./gradlew test
- name: Executar testes de integracao
run: ./gradlew integrationTest
env:
DATABASE_URL: jdbc:postgresql://localhost:5432/testdb
DATABASE_USER: testuser
DATABASE_PASSWORD: testpass
- name: Publicar relatorio de testes
uses: dorny/test-reporter@v1
if: always()
with:
name: Relatorio de Testes
path: '**/build/test-results/test/*.xml'
reporter: java-junit
- name: Upload artefatos
uses: actions/upload-artifact@v4
with:
name: build-artifacts
path: build/libs/*.jar
Pipeline de Deploy
// .github/workflows/deploy.yml
name: Deploy Pipeline
on:
push:
tags:
- 'v*'
jobs:
deploy:
runs-on: ubuntu-latest
needs: build-and-test
steps:
- uses: actions/checkout@v4
- name: Configurar JDK 17
uses: actions/setup-java@v4
with:
java-version: '17'
distribution: 'temurin'
- name: Build do projeto
run: ./gradlew build
- name: Login no Docker Hub
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
- name: Build e push da imagem Docker
uses: docker/build-push-action@v5
with:
context: .
push: true
tags: |
meuusuario/meu-app:${{ github.ref_name }}
meuusuario/meu-app:latest
- name: Deploy para producao
uses: appleboy/ssh-action@v1
with:
host: ${{ secrets.SERVER_HOST }}
username: ${{ secrets.SERVER_USER }}
key: ${{ secrets.SERVER_SSH_KEY }}
script: |
docker pull meuusuario/meu-app:latest
docker-compose up -d --force-recreate app
GitLab CI para Projetos Kotlin
O GitLab CI usa o arquivo .gitlab-ci.yml na raiz do projeto:
// .gitlab-ci.yml
stages:
- build
- test
- quality
- package
- deploy
variables:
GRADLE_OPTS: "-Dorg.gradle.daemon=false"
GRADLE_USER_HOME: "$CI_PROJECT_DIR/.gradle"
cache:
key: "$CI_COMMIT_REF_SLUG"
paths:
- .gradle/wrapper
- .gradle/caches
build:
stage: build
image: eclipse-temurin:17-jdk
script:
- chmod +x gradlew
- ./gradlew assemble
artifacts:
paths:
- build/libs/*.jar
unit-tests:
stage: test
image: eclipse-temurin:17-jdk
script:
- ./gradlew test
artifacts:
when: always
reports:
junit: build/test-results/test/*.xml
integration-tests:
stage: test
image: eclipse-temurin:17-jdk
services:
- postgres:16
variables:
POSTGRES_DB: testdb
POSTGRES_USER: testuser
POSTGRES_PASSWORD: testpass
DATABASE_URL: "jdbc:postgresql://postgres:5432/testdb"
script:
- ./gradlew integrationTest
code-quality:
stage: quality
image: eclipse-temurin:17-jdk
script:
- ./gradlew detekt
artifacts:
paths:
- build/reports/detekt/
docker-build:
stage: package
image: docker:24
services:
- docker:24-dind
script:
- docker build -t $CI_REGISTRY_IMAGE:$CI_COMMIT_TAG .
- docker push $CI_REGISTRY_IMAGE:$CI_COMMIT_TAG
only:
- tags
deploy-production:
stage: deploy
image: alpine
script:
- apk add --no-cache openssh-client
- ssh $SERVER_USER@$SERVER_HOST "docker pull $CI_REGISTRY_IMAGE:$CI_COMMIT_TAG && docker-compose up -d"
only:
- tags
when: manual
Configuracao do Gradle para CI
Otimize o build do Gradle para ambientes de CI:
// build.gradle.kts
tasks.test {
useJUnitPlatform()
// Relatorios para CI
reports {
junitXml.required.set(true)
html.required.set(true)
}
// Testes em paralelo
maxParallelForks = Runtime.getRuntime().availableProcessors() / 2
}
// Task separada para testes de integracao
val integrationTest by tasks.registering(Test::class) {
description = "Executa testes de integracao"
group = "verificacao"
testClassesDirs = sourceSets["integrationTest"].output.classesDirs
classpath = sourceSets["integrationTest"].runtimeClasspath
useJUnitPlatform()
shouldRunAfter(tasks.test)
}
// Analise de codigo com Detekt
plugins {
id("io.gitlab.arturbosch.detekt") version "1.23.4"
}
detekt {
config.setFrom("$rootDir/config/detekt/detekt.yml")
buildUponDefaultConfig = true
allRules = false
}
Analise de Qualidade de Codigo
Integre ferramentas de analise estatica no pipeline:
// Detekt - Analise estatica para Kotlin
// config/detekt/detekt.yml
complexity:
LongMethod:
threshold: 30
ComplexCondition:
threshold: 4
TooManyFunctions:
thresholdInFiles: 15
style:
MagicNumber:
ignoreNumbers:
- '-1'
- '0'
- '1'
- '2'
MaxLineLength:
maxLineLength: 120
// Ktlint - Formatacao de codigo
plugins {
id("org.jlleitschuh.gradle.ktlint") version "12.0.3"
}
ktlint {
android.set(true)
outputToConsole.set(true)
reporters {
reporter(ReporterType.CHECKSTYLE)
}
}
Seguranca no Pipeline
Proteja secrets e credenciais no pipeline:
// Nunca hardcode credenciais. Use variaveis de ambiente:
// GitHub: Settings > Secrets and variables > Actions
// GitLab: Settings > CI/CD > Variables
// No codigo Kotlin, leia do ambiente:
val databaseUrl = System.getenv("DATABASE_URL")
?: "jdbc:postgresql://localhost:5432/devdb"
val databaseUser = System.getenv("DATABASE_USER")
?: "devuser"
Boas Praticas de CI/CD para Kotlin
- Fail fast: coloque testes unitarios antes de testes de integracao no pipeline. Feedback rapido e essencial.
- Cache de dependencias: configure cache do Gradle para evitar download de dependencias a cada build.
- Builds reproduziveis: use versoes fixas de JDK, Gradle e dependencias. Evite
latestem imagens Docker. - Testes em paralelo: configure
maxParallelForksno Gradle para aproveitar multiplos cores. - Branch protection: exija que o pipeline passe antes de permitir merge em branches protegidas.
- Deploy gradual: use estrategias como blue-green ou canary para deploys seguros.
- Monitore o pipeline: acompanhe metricas como tempo de build, taxa de falha e cobertura de testes.
Erros Comuns e Armadilhas
- Pipeline lento sem cache: sem cache de Gradle, cada build baixa todas as dependencias novamente, adicionando minutos ao pipeline.
- Testes flakey: testes que falham intermitentemente corroem a confianca no pipeline. Investigue e corrija testes instáveis imediatamente.
- Secrets expostos em logs: cuidado com comandos que imprimem variaveis de ambiente. Use mascaramento de secrets.
- Falta de testes de integracao: confiar apenas em testes unitarios nao garante que componentes funcionem juntos.
- Deploy manual como unica opcao: se o deploy depende de um processo manual, nao e CD verdadeiro. Automatize o maximo possivel.
- Ignorar falhas do pipeline: nunca faça merge com pipeline falhando. Corrija antes de prosseguir.
Conclusao e Proximos Passos
Um pipeline de CI/CD robusto e o alicerce de entregas confiaveis e frequentes. Com GitHub Actions ou GitLab CI, voce pode automatizar todo o ciclo de vida do seu projeto Kotlin, desde a compilacao ate o deploy em producao. Para aprofundar, explore nossos guias sobre Docker para containerizacao, microservicos para arquitetura distribuida e testes para maximizar a cobertura do seu pipeline. A automacao bem feita libera tempo para o que realmente importa: escrever codigo de qualidade.