Rodando no CI
oren generate gitlab entregaoren generate github entregaoren generate cloudbuild entregaO mesmo pipeline, os mesmos contratos, as mesmas imagens travadas por digest — executados no CI.
Sem --output, cada plataforma recebe o arquivo onde ela espera encontrá-lo.
Com --properties <alias> você gera um ambiente só, e sem destino a saída vai
para o stdout — dá para canalizar.
Um ambiente por branch
Seção intitulada “Um ambiente por branch”Quando o pipeline tem propertyFiles, o oren.yaml pode dizer que branch usa
cada apelido:
propertyFiles: main: file: deploy/oren-properties/main.yaml branches: [main] develop: file: deploy/oren-properties/develop.yaml branches: [develop, 'feature/*']A forma curta (main: deploy/main.yaml) continua valendo. Quem nunca gerar CI
por branch nunca precisa da longa.
Com o mapa declarado, oren generate gera tudo de uma vez — mas o formato
muda por plataforma, e não por escolha nossa:
| Plataforma | Saída | Por quê |
|---|---|---|
| GitLab | .gitlab-ci.yml, um arquivo com rules |
o caminho do arquivo é configuração do projeto, não da branch |
| GitHub | .github/workflows/oren-<pipeline>.yml, um arquivo |
cada workflow declara os próprios gatilhos |
| Cloud Build | cloudbuild-<apelido>.yaml, um por apelido |
o gatilho é que nomeia o arquivo |
No GitLab isso vira uma regra por branch, definindo o apelido:
script: - oren run entrega --properties $OREN_PROPERTIESrules: - if: $CI_COMMIT_BRANCH == "main" variables: { OREN_PROPERTIES: main }O mapa serve só ao gerador. O oren run --properties continua sendo escolha
explícita de quem executa: ele nunca olha o git para adivinhar a branch, ou o
mesmo comando passaria a significar coisas diferentes conforme onde é digitado.
Por que o mapa fica no oren.yaml
Seção intitulada “Por que o mapa fica no oren.yaml”Porque o arquivo de propriedades não tem schema — é livre de propósito, e
você põe nele as chaves que quiser. Um campo reservado branch: lá dentro
criaria um vocabulário reservado, e a pergunta “posso ter uma propriedade
chamada branch?” passaria a ter resposta ruim.
Duas recusas
Seção intitulada “Duas recusas”A mesma branch em dois apelidos é erro, e não desempate. As duas condições seriam verdadeiras, a plataforma pegaria a primeira, e a entrega sairia com as propriedades do ambiente errado — em silêncio, que é o que faz disso o pior desfecho.
O --mode nativo não faz isso. Lá o conjunto de jobs é decidido na geração
e muda com o apelido: os steps com enabled por expressão entram ou não. Um
arquivo só não serve duas branches que geram jobs diferentes.
GitHub Actions
Seção intitulada “GitHub Actions”O job não usa container:. O GitHub sabe rodar um job dentro de uma imagem,
mas para isso injeta o próprio runner nela: precisa de Node e de glibc. Uma
imagem enxuta — como as alpine dos workers de referência — quebra, e quebra
com um erro que não se liga à causa.
Em vez disso, o job roda docker run explícito. A imagem é executada como o
oren run a executaria: só o que ela declara precisar, nada injetado.
Os segredos chegam por secrets do repositório, mapeados em env no YAML —
secrets não é indexável por nome variável dentro do run, então esse
mapeamento precisa existir, e é ele que torna explícito o que configurar.
Sem o mapa de branches, o workflow gerado só dispara por workflow_dispatch.
Um gerador não tem como adivinhar em que evento o seu pipeline deve rodar, e
supor push faria a primeira geração disparar um deploy sem ninguém pedir —
acrescente o gatilho que você quer.
Com o mapa, o push sai declarado com exatamente as branches mapeadas, porque
aí você disse quais são. Um passo antes do oren run escolhe o apelido pela
branch, e uma branch fora do mapa falha em vez de rodar sem propriedades —
que entregaria com os valores errados.
Retomar uma execução que falhou
Seção intitulada “Retomar uma execução que falhou”oren generate gitlab entrega --resumeO job passa a rodar com --resume e a plataforma guarda em cache o que a
execução anterior produziu. Numa retentativa, os steps que já tinham dado certo
são pulados.
Fora por padrão, e por três motivos: o cache custa transferência em toda execução para um benefício que só aparece quando algo falha; ligá-lo alarga a fronteira de confiança (ver abaixo); e ele é recusado em pipelines comuns, então um padrão faria a geração falhar para quem nunca pediu.
O que é cacheado
Seção intitulada “O que é cacheado”Dois conjuntos, e o segundo é o que costuma faltar:
.oren/runs/— os outputs e o status de cada step, de onde a retomada sabe o que pode pular;- os diretórios mutáveis declarados no pipeline. O estado guarda a saída em
JSON, mas o que o step escreveu no disco fica de fora: retomar depois de um
build sem o
.tarque ele gravou daria um step seguinte procurando um arquivo que não existe.
.oren/registry/ e .oren/consent.json nunca entram. Os dois são
versionados e vêm do checkout.
A chave é o commit
Seção intitulada “A chave é o commit”O estado descreve o que rodou sobre um código específico, e a retomada recusa atravessar commits:
erro A execução anterior é de outro commit (062fc199) Retomar reaproveitaria a saída de steps que rodaram sobre outro código — uma imagem já construída seria publicada com a versão nova, sem nada indicar a troca.A conferência não depende do arquivo de CI estar chaveado certo: ela está na
CLI. Sem git, ver OREN_REVISION em Comandos.
Retomar sem execução anterior não é erro — a primeira execução no CI nunca tem estado. Ela avisa e roda tudo.
Duas recusas
Seção intitulada “Duas recusas”Step que escreve na raiz do projeto. Cachear a raiz restauraria .git,
.oren/registry/ e .oren/consent.json de outra execução — e aí o cache
decidiria que worker roda e afirmaria que o acesso foi autorizado. Aponte a
dependência mutável para um subdiretório, ou gere sem --resume.
Cloud Build. Ele não tem cache nativo, e os steps param no primeiro que falha — o step que gravaria o estado não rodaria justamente quando a execução falhou, que é a única vez em que retomar interessa.
O que o gerador resolve
Seção intitulada “O que o gerador resolve”Passagem de output. No GitLab, cada job grava .oren-outputs/<id>.json como
artifact e os seguintes o recebem via needs. Artifact em vez de
reports:dotenv porque os outputs são JSON estruturado, e dotenv só carrega
pares de string.
Dependências. Credenciais viram variáveis do projeto, com verificação que falha cedo se não estiverem definidas. O valor nunca aparece no YAML.
Diretórios mutáveis. Viram artifact entre jobs, já que runners não compartilham disco.
Exige oren install
Seção intitulada “Exige oren install”Sem as imagens travadas, a configuração gerada executaria o que a tag apontar em cada dia — perdendo justamente a reprodutibilidade que justifica gerar.
Implementações locais são recusadas
Seção intitulada “Implementações locais são recusadas”erro Não é possível gerar CI: alguns steps usam implementação construída localmente Um job de CI referencia uma imagem publicada — o runner não tem o diretório do worker. Publique a imagem e troque `build:` por `image:`.Limitações
Seção intitulada “Limitações”A imagem do worker precisa ter jq quando um input vem de outro step — é ele que
compõe o input.json dentro do job, inclusive a interpolação em texto misto
(v${outputs['x'].y}-rc), que é suportada.
${properties.x} é suportado, e resolvido na geração — o valor entra
assado no job, porque arquivo de properties não existe no runner. É por isso que
o --properties é obrigatório quando o pipeline tem step condicional: o CI
gerado tem conjunto fixo de jobs, e não há lá o que avalie a expressão depois.
O que a CLI faz e o CI gerado não
Seção intitulada “O que a CLI faz e o CI gerado não”O gerador é um compilador, não um runtime: o job roda a imagem do worker
direto, e o runner não precisa de Node, nem do binário oren, nem do portal. É
justamente o ponto — mas três coisas vivem na CLI e não vão junto.
O consent. Ele é a CLI perguntando a você. Um job gerado roda o que o
arquivo diz. É por isso que vale commitar o .oren/consent.json: no CI ele é o
registro de que alguém autorizou o acesso, e não um controle que executa.
O cache. O cache do Oren é da CLI. No CI, o que a plataforma oferecer.
A validação da saída contra o contrato. Localmente, uma saída fora do
contrato falha o step mesmo com exit code zero. No job gerado a saída é copiada
como veio: um output.json ausente ainda falha o step, porque a cópia falha —
mas uma saída com tipo errado ou campo não declarado passa.
Essa é uma diferença de verdade, e a que vale ter em mente: o contrato é
conferido no oren validate e no oren run, e são esses dois que seguram a
linha. Um worker cuja saída só desvia no CI desvia em silêncio.