Skip to main content

Rules

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

Antes era utilizado duas coisas juntas (only e expect) 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ó estam presentes por uma questão de retrocompatiblidade e nada mais.

Documentação Oficial Rules

Documentação Oficial Only e Except

A estrutura do 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
ifExpressão booleana usando variáveis do GitLab ($CI_*, etc).
whenDefine quando o job será executado (on_success, manual, etc).
start_inUsado com when: delayed (ex: "5 minutes").
allow_failureSe true, falha no job não quebra o pipeline.
existsRoda o job se o(s) arquivo(s) existir(em).
changesRoda o job se os arquivos listados foram modificados.
variablesLista de variáveis obrigatórias para essa regra ser aplicada.

when

Temos uma item importante ai 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 e when: manual seria que alguém o deploy para ir para em produção.

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

Exemplo delayed + start_in seria em 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 ir cancelar o job antes que rode. Se usar de 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 fazer sobreescrever para alguma regra específica. Nesse caso o job sempre é manual, as 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. Pra 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"'