Pular para o conteúdo principal

Rules

Antes de começar a falar de rules saiba que ela é uma evolução de algo que ainda é utilizado mas está em desuso chamado only.

Antes era utilizado duas coisas juntas (only e except) que hoje resolvemos só com rules. Use rules sempre que possível. only tá de saída.

Só para entender o contexto do que tinhamos antes...

job:
script: echo "Rodando job"
only:
- main # Roda só na branch main
- tags

only: roda o job somente quando o commit vem de certas condições (branch, tag, etc).

Ou except...

job:
script: echo "Rodando job"
except:
- develop

except: não roda o job se cair em alguma dessas condições.

Limitações:

  • Não temos if ou lógica condicional usando only e except.
  • Não podemos fazer lógicas combinadas utilizando as variáveis.

Então esquece isso e vamos direto pro que nos dá mais poder, rules.

job:
script:
...
rules: [] # É uma lista
  1. As regras são avaliadas em ordem, a que der match primeiro define o comportamento do job.
  2. Super customizável com expressões, variáveis, tags, branch, MR, etc.

Uma tabela rápida para entender diferença.

Aspectoonly / exceptrules
Suporte oficialDepreciadoAtual e recomendado
FlexibilidadeBaixaAlta
Condicional (if)NãoSim
Ordem de avaliaçãoLimitadaSequencial e lógica
MR detectionLimitadaAvançada
ExpressividadeBaixaAlta

Only e except só estão presentes por uma questão de retrocompatibilidade e nada mais.

Documentação Oficial Rules

Documentação Oficial Only e Except

A estrutura de um bloco rules é a seguinte.

job:
script:
...
rules:
- if: <expressão>
when: [on_success | on_failure | manual | always | never | delayed]
start_in: <tempo>
allow_failure: true/false
exists:
- <caminho/do/arquivo>
changes:
- <arquivo ou pasta>
variables:
- <variável>
CampoObrigatório?Descrição
if❌Expressão booleana usando variáveis do GitLab ($CI_*, etc).
when❌Define quando o job será executado (on_success, manual, etc).
start_in❌Usado com when: delayed (ex: "5 minutes").
allow_failure❌Se true, falha no job não quebra o pipeline.
exists❌Roda o job se o(s) arquivo(s) existir(em).
changes❌Roda o job se os arquivos listados foram modificados.
variables❌Lista de variáveis obrigatórias para essa regra ser aplicada.

when​

Temos um item importante aí que além de estar dentro de rules também pode ser declarado fora (diretamente no job) que é o when. Primeiro vamos entender o que ele faz e depois entender a diferença entre usar em rules e fora dele.

Valor de whenComportamento
on_successExecuta o job somente se nenhum job anterior falhar. (Padrão)
on_failureExecuta o job somente se algum job anterior falhar.
neverNunca executa o job, independentemente de qualquer condição. Só pode ser usado em rules, afinal não faria sentido
alwaysExecuta o job sempre, mesmo que jobs anteriores falhem.
manualO job fica aguardando execução manual (aparece botão no GitLab UI).
delayedO job é executado com atraso, conforme o tempo definido em start_in:.

Exemplo de when: manual seria que alguém precisa aprovar o deploy para ir para produção.

job_manual:
script: echo "Executando o deploy..."
when: manual

Exemplo delayed + start_in seria dar um tempo entre o deploy em staging e o deploy em produção para que dê tempo de testar e se alguém perceber um erro dá tempo de cancelar o job antes que rode. Se usar delayed, o start_in é obrigatório.

job_delayed:
script: echo "Executando o deploy..."
when: delayed
start_in: 10 minutes

Um exemplo de always poderia ser enviar uma notificação ao final do pipeline mesmo se ele falhar, por exemplo enviar um email e uma notificação no slack. Se quiser que só envie se falhar então poderia ser on_failure.

Quando declaramos o when fora das rules o que estamos fazendo na verdade é colocando o mesmo when para todas as rules. Isso serve para deixar o rules mais limpo.

job:
script: echo "Rodando"
when: manual
rules:
- if: Condição 1
- if: Condição 2

Ou seja, é a mesma coisa que fazer isso.

job:
script: echo "Rodando"
rules:
- if: Condição 1
when: manual
- if: Condição 2
when: manual

Porém podemos sobrescrever para alguma regra específica. Nesse caso o job sempre é manual, mas se for na branch develop então roda direto sem intervenção.

job:
script: echo "Deployando"
when: manual
rules:
- if: '$CI_COMMIT_BRANCH == "main"'
- if: '$CI_COMMIT_BRANCH == "staging"'
- if: '$CI_COMMIT_BRANCH == "develop"'
when: on_success

allow_failure​

O mesmo vale para allow_failure, que pode ser definido diretamente no nível do job ou individualmente dentro de cada regra em rules. Quando definido no nível do job, o valor será aplicado como padrão para todas as rules.

Por default, allow_failure é false, ou seja: se o job falhar, o pipeline também será considerado com falha. Quando definido como true, o job pode falhar sem quebrar o pipeline, permitindo que os próximos jobs continuem normalmente.

Isso é útil, por exemplo, para testes experimentais, análises estáticas ou qualquer etapa não crítica que você não quer que bloqueie o restante da execução.

exists, changes e variables​

Muitas vezes código sofre mudanças que não mudam nada no ambiente, um ótimo exemplo disso é fazer uma alteração no README.md. Para que vamos fazer deploy?

No bloco de rules, além de if, você pode usar exists e changes, que são formas de ativar um job com base na presença ou modificação de arquivos.

job:
script: "Criando uma imagem"
when: manual
rules:
- if: '$CI_COMMIT_BRANCH == "main"'
exists:
- Dockerfile
- .dockerignore
job:
script: "Criando uma imagem"
when: manual
rules: # Observe que pode existir que o IF. tanto changes quanto exists.
- changes: # Se algum desses arquivos sofrer mudanças
- src/**
- config/*.yaml

Já o bloco variables, como vimos antes, serve para definir variáveis personalizadas.

deploy:
stage: deploy
image: alpine
script:
- echo "Deploy iniciando com TOKEN=$TOKEN"
environment:
name: $DEPLOY_ENV
rules:
- if: '$CI_COMMIT_BRANCH == "develop"'
variables:
DEPLOY_ENV: develop
- if: '$CI_COMMIT_BRANCH == "main"'