Pular para o conteúdo

Testador de Expressões do GitHub Actions · CI/CD

Teste suas condições if: e seus triggers antes de fazer push.

Avalie expressões ${{ }} contra um contexto fictício editável, pegue o if: que é silenciosamente sempre verdadeiro, e simule quais jobs rodam para um push, PR ou tag — na hora, no seu navegador. Sem o ciclo commit-push-pray.

Roda no seu navegador — nada do que você cola sai desta página. Como comprovamos isso

Roda no seu navegador Sem cadastro Semântica exata do GitHub Atualizado em 29 de jul. de 2026

Playground de expressões e triggers do GitHub Actions

if-condition
context (editable mock)

Results update as you type — press ⌘/Ctrl + Enter to run now. Press Esc to release the editor. Your input never leaves the browser.

Result

Load an example or write an if: condition, then Evaluate to see whether it is true, the returned value, and a token-by-token breakdown.

.github/workflows/ci.yml
Event scenario

Results update as you type — press ⌘/Ctrl + Enter to run now. Press Esc to release the editor. Nothing is uploaded.

Decision

Load an example or paste a workflow, set an event, then Simulate to see which jobs run or are skipped — and why.

100% in your browser · no signup

A lacuna

Pare de depurar fazendo push.

Todo mundo já fez isso: adiciona um if: a um passo, faz push, vê ele rodar quando não deveria, ajusta, faz push de novo — vinte commits inúteis depois você descobre que a condição era uma string literal o tempo todo. O GitHub só avalia o que está dentro de ${{ }}; qualquer coisa de fora é texto literal, e uma string não vazia é sempre truthy.

O lado dos triggers é igualmente opaco: um workflow que não roda não produz saída nenhuma — a decisão acontece na filtragem de eventos do GitHub antes que qualquer runner inicie. Os filtros de branch e path se combinam com AND, os pushes de tag são excluídos quando você define branches mas não tags, e ** se comporta de forma diferente de *.

Esta ferramenta avalia os dois — uma única expressão, ou um workflow inteiro contra um evento — usando as regras exatas do GitHub, para que você obtenha a resposta no navegador. Veja a documentação de expressões e de triggers de workflow do GitHub, e a issue da armadilha do sempre verdadeiro.

Pule para a cola ou para o playground ao vivo acima.

O pipeline

Como funciona.

Cinco passos determinísticos rodam de ponta a ponta em cada avaliação — todos dentro da aba do seu navegador, toda vez.

  1. Escolha uma aba.

    Avalie um único if: / expressão, ou troque para o simulador de triggers para testar um workflow inteiro contra um evento.

  2. Defina o contexto.

    Edite o JSON fictício github/env/matrix/steps/needs (ou descreva o evento: tipo, ref, arquivos alterados) para que ele corresponda à execução que lhe interessa.

  3. Analise com a gramática do GitHub.

    A expressão é tokenizada e analisada com a mesma precedência de operadores e o mesmo conjunto de funções que o runner usa — sem shell-out, sem rede.

  4. Aplique a semântica exata.

    A coerção, a igualdade que ignora maiúsculas e minúsculas, o && / || que retornam um operando, os filtros de glob e a regra de AND entre branch e path são replicados contra um corpus de conformidade versionado.

  5. Mostre o veredito + o porquê.

    Você recebe o resultado truthy/falsy e o valor retornado, o aviso da armadilha do sempre verdadeiro onde ele se aplica, e uma tabela RUNS/SKIPPED por job com o motivo decisivo.

Cola

As regras que pegam as pessoas de surpresa.

A armadilha, as surpresas da coerção, as funções e os globs de trigger — cada um com um exemplo executável que você pode colar no playground.

A armadilha do "sempre verdadeiro"

Mais comum

O GitHub só avalia o que está dentro de ${{ }}. Os operadores deixados de fora viram texto literal após a substituição — uma string não vazia, que é sempre truthy. O avaliador sinaliza isso (actions/runner#1173).

Sempre verdadeiro

.github/workflows/ci.yml
# ALWAYS TRUE — operators sit OUTSIDE ${{ }}
jobs:
  deploy:
    if: ${{ github.ref }} == 'refs/heads/main'
    # after substitution this is the literal string
    #   refs/heads/main == 'refs/heads/main'
    # a non-empty string => truthy => runs on EVERY branch

Corrigido

.github/workflows/ci.yml
# CORRECT — wrap the WHOLE condition in one ${{ }}
jobs:
  deploy:
    if: ${{ github.ref == 'refs/heads/main' }}
    # now GitHub evaluates the comparison, not a literal string

Operadores e coerção

YAML
# GitHub's coercion is JS-like and case-insensitive:
${{ 'ABC' == 'abc' }}      # true  (strings compare case-insensitively)
${{ null == 0 }}           # true  (both coerce to the number 0)
${{ '' || 'fallback' }}    # 'fallback'  (|| returns an OPERAND, not a bool)
${{ github.x && 'yes' }}   # 'yes' when github.x is truthy
${{ 'true' == true }}      # false (string 'true' coerces to NaN)

Funções

YAML
${{ contains('refs/heads/main', 'main') }}     # true (substring, case-insensitive)
${{ startsWith(github.ref, 'refs/tags/') }}    # is this a tag push?
${{ format('{0}-{1}', 'app', github.sha) }}    # 'app-d6cd1e2…'
${{ fromJSON('["a","b"]') }}                   # a real array
${{ always() }}  ${{ success() }}  ${{ failure() }}  # status checks

Triggers, branches e paths

YAML
on:
  push:
    branches: [main]      # AND
    paths: ['src/**']     # — both must match to trigger
# feature/* matches feature/a but NOT feature/a/b
# feature/** matches both (** crosses '/')

Fidelidade e escopo

Isto é um playground de semântica, não um runner. Ele replica o comportamento documentado de expressões e triggers do GitHub contra um corpus de conformidade versionado (mostrado como o rótulo semantics: na ferramenta), mas não executa jobs, não busca o conteúdo ao vivo das ações referenciadas, nem calcula um hashFiles() real — isso precisa de arquivos que só o runner consegue ver, então é exibido como um placeholder. O payload completo de github.event é modelado como um mock editável que você controla. Trate um resultado limpo como uma forte confiança antes do push, e ainda assim combine-o com o actionlint para a sintaxe.

FAQ

Suas perguntas, respondidas.

Toque em uma pergunta para expandir a resposta.

Ele tem duas abas. O Avaliador de Expressões roda as suas expressões ${{ }} contra um contexto fictício editável (github, env, matrix, steps, needs) usando a semântica exata do GitHub Actions — os operadores, o == de strings que ignora maiúsculas e minúsculas, as regras de coerção parecidas com as do JS e funções documentadas como contains, startsWith, endsWith, format, join, toJSON, fromJSON, success(), failure(), always() e cancelled(). O Simulador de Triggers permite que você descreva um evento de push, pull_request ou tag e mostra uma tabela RUN ou SKIPPED por job que explica exatamente qual filtro on:, branches, tags, paths ou paths-ignore decidiu o resultado. Juntos, eles respondem "este if: vai ser verdadeiro?" e "este workflow vai sequer disparar?" antes de você fazer o push.

Quase sempre porque o if: contém texto literal fora de ${{ }} — por exemplo if: "${{ github.event_name }}" == 'push' ou if: always-deploy. O GitHub não avalia a linha inteira como uma única expressão; os caracteres literais transformam a condição em uma string não vazia, e uma string não vazia é truthy, então o passo roda toda vez. Envolva a condição inteira em um único ${{ }} (por exemplo if: ${{ github.event_name == 'push' }}) e o Avaliador de Expressões vai sinalizar a armadilha (actions/runner#1173) e mostrar o resultado corrigido, truthy ou falsy.

Cole a expressão na aba do Avaliador de Expressões e edite o contexto fictício github/env/matrix/steps/needs para corresponder à execução que lhe interessa — sem commit, sem push, sem esperar por um runner. Você recebe o valor avaliado na hora, além de um aviso caso a sintaxe fosse silenciosamente coergida para sempre verdadeira. É a maneira mais rápida de verificar uma condição if: ou uma interpolação ${{ }} antes que ela chegue ao GitHub Actions.

Essas são funções de verificação de status que você usa em um if:. success() é verdadeira apenas quando todos os passos anteriores ou jobs necessários tiveram sucesso (é o padrão implícito no momento em que você não escreve nenhum if:), failure() é verdadeira quando algum deles falhou, cancelled() é verdadeira quando o workflow foi cancelado, e always() força o passo a rodar independentemente do status anterior — inclusive em caso de cancelamento. O detalhe é que escrever qualquer if: personalizado remove a proteção implícita de success(), então if: env.DEPLOY == 'true' vai rodar mesmo depois que um passo anterior falhou, a menos que você adicione && success(). O avaliador permite que você alterne o status fictício e veja cada função ser resolvida.

As causas usuais são uma ref que não corresponde ao glob de on: branches ou tags, o arquivo de workflow ainda não existir na branch de destino, ou um filtro de paths excluindo todos os arquivos alterados. Uma sutil: quando você define tanto branches quanto paths sob o mesmo evento, eles se combinam com AND — o evento precisa corresponder a ambos, não a um ou outro. Descreva o seu evento no Simulador de Triggers e ele reproduz os filtros on: e diz o motivo decisivo para cada job.

Dentro de um único evento, branches (ou tags) e paths são combinados com AND: um push precisa estar em uma branch que corresponda e tocar em um path que corresponda para o workflow rodar. Dentro de um único filtro, os padrões são combinados com OR — qualquer um glob de branch ou qualquer um path alterado que corresponda já é suficiente. O Simulador de Triggers torna isso explícito ao mostrar separadamente a decisão de branch e a decisão de path, e em seguida o veredito combinado RUN ou SKIPPED.

* corresponde a quaisquer caracteres exceto o separador de caminho /, enquanto ** corresponde através dos separadores, incluindo o /, então feature/** corresponde a feature/a/b mas feature/* corresponde apenas a feature/a. O motor de glob também respeita +, ?, a negação ! e o escape \ da mesma forma que o GitHub faz. O Simulador de Triggers usa uma reimplementação fiel dessas regras para que você possa testar um padrão como 'release/**' ou '!**/*.md' contra uma ref ou lista de arquivos reais e ver o que corresponde.

No Simulador de Triggers você fornece o tipo de evento, o nome da ref e a lista de arquivos alterados; a ferramenta então avalia os filtros on: de cada job e qualquer if: no nível do job contra esse evento simulado e renderiza uma linha RUN ou SKIPPED com o motivo decisivo — "branch correspondeu mas o path não", "sem filtro de paths", "if: avaliado como falso" e assim por diante. Ela espelha a ordem de decisão do GitHub Actions em vez de adivinhar, então o veredito corresponde ao que o runner real faria para aquele evento.

O actionlint é um linter estático para a sintaxe de workflows e a tipagem de expressões, e o act de fato executa os seus jobs em containers Docker locais — ambos são ótimos e valem a pena usar. Esta ferramenta não faz nenhum dos dois: ela não roda os seus passos e não é um verificador de tipos. É um playground de semântica que avalia uma única expressão ${{ }} ou simula a filtragem de triggers contra um contexto que você controla, no navegador, para que você possa raciocinar sobre por que um if: é truthy ou por que um workflow disparou ou não, sem subir containers nem fazer commits.

Qualquer coisa que dependa do estado real do runner. hashFiles() precisa dos arquivos reais em disco, então o avaliador o trata como um placeholder opaco em vez de calcular um hash verdadeiro; o payload completo do webhook é muito maior do que o contexto github fictício que expomos; e o conteúdo ao vivo das ações, os secrets e os labels do runner não são resolvidos. Trate um resultado limpo como uma forte confiança antes do push sobre a lógica de expressões e triggers — não como uma garantia sobre o hashing de arquivos ou o payload completo do evento.

Não. As duas abas rodam 100% no lado do cliente. As expressões, o contexto fictício, os filtros do workflow e os payloads de eventos que você insere são avaliados dentro da aba do seu navegador — nada é enviado, não há conta e não há cadastro. Você pode colar com segurança workflows internos ou proprietários, inclusive nomes de secrets, labels de runners privados e listas reais de branches e paths.

Não. Esta é uma ferramenta independente e comunitária, e não é afiliada, endossada nem patrocinada pela GitHub, Inc. "GitHub" e "GitHub Actions" são usados aqui apenas de forma descritiva, para identificar o formato de expressões e triggers de workflow que a ferramenta avalia.

More free, private DevOps tools.

O Testador de Expressões do GitHub Actions é uma ferramenta dentro do OpsCanopy — uma copa crescente de validadores, conversores e testadores baseados em navegador que nunca tocam um servidor.

39 ferramentas gratuitas, todas capazes de funcionar offline — o opscanopy.com não exige cadastro e não envia nada.

Ferramentas relacionadas: o Validador do GitHub Actions e o AlertLint, o testador de regras do Loki. Explore o diretório completo de ferramentas.

Não é afiliado, endossado nem patrocinado pela GitHub, Inc. GitHub e GitHub Actions são marcas comerciais da GitHub, Inc., usadas aqui apenas de forma descritiva para identificar o formato de expressões e triggers de workflow que esta ferramenta avalia.