Saltar al contenido

Probador de expresiones de GitHub Actions · CI/CD

Prueba tus condiciones if: y triggers antes de hacer push.

Evalúa expresiones ${{ }} contra un contexto simulado editable, detecta el if: que es silenciosamente siempre verdadero, y simula qué jobs se ejecutan para un push, PR o tag — al instante, en tu navegador. Sin el bucle de commit-push-pray.

Se ejecuta en tu navegador: nada de lo que pegas sale de esta página. Cómo lo demostramos

Se ejecuta en tu navegador Sin registro Semántica exacta de GitHub Actualizado el 29 jul 2026

Playground de expresiones y triggers de 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

La brecha

Deja de depurar haciendo push.

Todo el mundo lo ha hecho: añades un if: a un paso, haces push, lo ves ejecutarse cuando no debería, lo ajustas, vuelves a hacer push — y veinte commits de prueba después descubres que la condición fue una cadena literal todo el tiempo. GitHub solo evalúa lo que está dentro de ${{ }}; cualquier cosa fuera es texto literal, y una cadena no vacía siempre es verdadera.

El lado de los triggers es igual de opaco: un workflow que no se ejecuta no produce ninguna salida en absoluto — la decisión ocurre en el filtrado de eventos de GitHub antes de que arranque ningún runner. Los filtros de branch y de path se combinan con AND, los pushes de tags quedan excluidos cuando defines branches pero no tags, y ** se comporta de forma distinta a *.

Esta herramienta evalúa ambas cosas —una sola expresión, o un workflow entero contra un evento— usando las reglas exactas de GitHub, para que obtengas la respuesta en el navegador. Consulta la documentación de expresiones y de triggers de workflow de GitHub, y la incidencia de la trampa del «siempre verdadero».

Salta a la chuleta o al playground en vivo de arriba.

El pipeline

Cómo funciona.

Cinco pasos deterministas se ejecutan de principio a fin en cada evaluación — todos dentro de la pestaña de tu navegador, cada vez.

  1. Elige una pestaña.

    Evalúa un único if: / expresión, o cambia al simulador de triggers para probar un workflow entero contra un evento.

  2. Configura el contexto.

    Edita el JSON simulado github/env/matrix/steps/needs (o describe el evento: tipo, ref, archivos modificados) para que coincida con la ejecución que te interesa.

  3. Analiza con la gramática de GitHub.

    La expresión se tokeniza y se analiza con la misma precedencia de operadores y el mismo conjunto de funciones que usa el runner — sin invocar al shell, sin red.

  4. Aplica la semántica exacta.

    La coerción, la igualdad insensible a mayúsculas, los operadores && / || que devuelven un operando, los filtros glob y la regla AND de branch+path se replican contra un corpus de conformidad versionado.

  5. Muestra el veredicto + el porqué.

    Obtienes el resultado verdadero/falso y el valor devuelto, la advertencia de la trampa de «siempre verdadero» donde aplique, y una tabla por job de RUNS/SKIPPED con la razón decisiva.

Chuleta

Las reglas que hacen tropezar a la gente.

La trampa, las sorpresas de la coerción, las funciones y los globs de triggers — cada una con un ejemplo ejecutable que puedes pegar en el playground.

La trampa del «siempre verdadero»

La más común

GitHub solo evalúa lo que está dentro de ${{ }}. Los operadores que quedan fuera se convierten en texto literal tras la sustitución — una cadena no vacía, que siempre es verdadera. El evaluador marca esto (actions/runner#1173).

Siempre verdadero

.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

Corregido

.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 y coerción

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)

Funciones

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 y 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 '/')

Fidelidad y alcance

Esto es un playground de semántica, no un runner. Replica el comportamiento documentado de expresiones y triggers de GitHub contra un corpus de conformidad versionado (mostrado como la etiqueta semantics: en la herramienta), pero no ejecuta jobs, no obtiene el contenido en vivo de las acciones referenciadas ni calcula un hashFiles() real — eso necesita archivos que solo el runner puede ver, así que se muestra como un marcador de posición. El payload completo de github.event se modela como un mock editable que tú controlas. Trata un resultado limpio como una sólida confianza previa al push, y aun así combínalo con actionlint para la sintaxis.

FAQ

Tus preguntas, respondidas.

Toca una pregunta para desplegar la respuesta.

Tiene dos pestañas. El evaluador de expresiones ejecuta tus expresiones ${{ }} contra un contexto simulado editable (github, env, matrix, steps, needs) usando la semántica exacta de GitHub Actions: los operadores, el == de cadenas insensible a mayúsculas, las reglas de coerción tipo JS y funciones documentadas como contains, startsWith, endsWith, format, join, toJSON, fromJSON, success(), failure(), always() y cancelled(). El simulador de triggers te permite describir un evento push, pull_request o tag y muestra una tabla por job de RUN o SKIPPED que explica exactamente qué filtro on: branches, tags, paths o paths-ignore decidió el resultado. Juntos responden «¿será verdadero este if:?» y «¿llegará a dispararse este workflow?» antes de hacer push.

Casi siempre es porque el if: contiene texto literal fuera de ${{ }} — por ejemplo if: "${{ github.event_name }}" == 'push' o if: always-deploy. GitHub no evalúa la línea entera como una sola expresión; los caracteres literales convierten la condición en una cadena no vacía, y una cadena no vacía es verdadera (truthy), así que el paso se ejecuta siempre. Envuelve la condición completa en un único ${{ }} (por ejemplo if: ${{ github.event_name == 'push' }}) y el evaluador de expresiones marcará la trampa (actions/runner#1173) y te mostrará el resultado corregido, verdadero o falso.

Pega la expresión en la pestaña del evaluador de expresiones y edita el contexto simulado github/env/matrix/steps/needs para que coincida con la ejecución que te interesa: sin commit, sin push, sin esperar a un runner. Obtienes el valor evaluado al instante, además de una advertencia si la sintaxis se convertiría silenciosamente en siempre verdadera. Es la forma más rápida de verificar una condición if: o una interpolación ${{ }} antes de que siquiera llegue a GitHub Actions.

Son funciones de comprobación de estado que usas en un if:. success() es verdadero solo cuando todos los pasos previos o jobs necesarios tuvieron éxito (es el valor por defecto implícito en el momento en que no escribes ningún if:), failure() es verdadero cuando alguno de ellos falló, cancelled() es verdadero cuando el workflow fue cancelado, y always() fuerza la ejecución del paso sin importar el estado previo — incluso en una cancelación. La trampa es que escribir cualquier if: personalizado elimina la protección implícita de success(), así que if: env.DEPLOY == 'true' se ejecutará incluso después de que un paso anterior falle, salvo que añadas && success(). El evaluador te permite alternar el estado simulado y ver cómo se resuelve cada función.

Las causas habituales son una ref que no coincide con tu glob de on: branches o tags, que el archivo del workflow todavía no exista en la rama de destino, o un filtro paths que excluye todos los archivos modificados. Una sutil: cuando defines a la vez branches y paths bajo el mismo evento, se combinan con AND — el evento debe coincidir con ambos, no con cualquiera. Describe tu evento en el simulador de triggers y reproduce los filtros on: y te dice la razón decisiva para cada job.

Dentro de un solo evento, branches (o tags) y paths se combinan con AND: un push debe estar en una rama coincidente y tocar un path coincidente para que el workflow se ejecute. Dentro de un mismo filtro los patrones se combinan con OR — basta con que coincida cualquier glob de rama o cualquier path modificado. El simulador de triggers lo hace explícito mostrando por separado la decisión de la rama y la decisión del path, y luego el veredicto combinado RUN o SKIPPED.

* coincide con cualquier carácter excepto el separador de ruta /, mientras que ** coincide a través de los separadores, incluido /, de modo que feature/** coincide con feature/a/b pero feature/* coincide solo con feature/a. El motor de globs también respeta +, ?, la negación ! y el escape \ del mismo modo que lo hace GitHub. El simulador de triggers usa una reimplementación fiel de estas reglas para que puedas probar un patrón como 'release/**' o '!**/*.md' contra una ref o una lista de archivos reales y ver qué coincide.

En el simulador de triggers proporcionas el tipo de evento, el nombre de la ref y la lista de archivos modificados; la herramienta evalúa entonces los filtros on: de cada job y cualquier if: a nivel de job contra ese evento simulado y renderiza una fila RUN o SKIPPED con la razón decisiva — «la rama coincidió pero el path no», «sin filtro de paths», «if: evaluado como falso», etc. Refleja el orden de decisión de GitHub Actions en lugar de adivinar, así que el veredicto coincide con lo que haría el runner real para ese evento.

actionlint es un linter estático para la sintaxis del workflow y el tipado de expresiones, y act ejecuta de verdad tus jobs en contenedores Docker locales — ambos son excelentes y vale la pena usarlos. Esta herramienta no hace ninguna de las dos cosas: no ejecuta tus pasos y no es un verificador de tipos. Es un playground de semántica que evalúa una sola expresión ${{ }} o simula el filtrado de triggers contra un contexto que tú controlas, en el navegador, para que puedas razonar por qué un if: es verdadero o por qué un workflow se disparó o no, sin levantar contenedores ni hacer push de commits.

Cualquier cosa que dependa del estado real del runner. hashFiles() necesita los archivos reales en disco, así que el evaluador lo trata como un marcador de posición opaco en lugar de calcular un hash real; el payload completo del webhook es mucho más grande que el contexto github simulado que exponemos; y el contenido en vivo de las acciones, los secretos y las etiquetas de runner no se resuelven. Trata un resultado limpio como una sólida confianza previa al push sobre la lógica de expresiones y triggers — no como una garantía sobre el hashing de archivos o el payload completo del evento.

No. Ambas pestañas se ejecutan 100% del lado del cliente. Las expresiones, el contexto simulado, los filtros del workflow y los payloads de eventos que introduces se evalúan dentro de la pestaña de tu navegador: no se sube nada, no hay cuenta y no hay registro. Puedes pegar con seguridad workflows internos o propietarios, incluidos nombres de secretos, etiquetas de runners privados y listas reales de ramas y paths.

No. Esta es una herramienta independiente y comunitaria, y no está afiliada, respaldada ni patrocinada por GitHub, Inc. «GitHub» y «GitHub Actions» se usan aquí solo de forma descriptiva, para identificar el formato de expresiones y de triggers de workflow que la herramienta evalúa.

More free, private DevOps tools.

El probador de expresiones de GitHub Actions es una herramienta dentro de OpsCanopy — una creciente cubierta de validadores, conversores y probadores basados en navegador que nunca tocan un servidor.

39 herramientas gratuitas, todas pueden funcionar sin conexión — opscanopy.com funciona sin registro y sin subir nada.

Herramientas relacionadas: el validador de GitHub Actions y AlertLint, el probador de reglas de Loki. Explora el directorio completo de herramientas.

No está afiliado, respaldado ni patrocinado por GitHub, Inc. GitHub y GitHub Actions son marcas comerciales de GitHub, Inc., usadas aquí solo de forma descriptiva para identificar el formato de expresiones y de triggers de workflow que esta herramienta evalúa.