cd ..
CI/CD

Understanding GitHub Actions Triggers

A GitHub Actions workflow needs to know when it should run.

It can start when:

The events that initiate a workflow are called triggers.

In the YAML file, they are configured using the on property.

on:
  push:

In this example, the workflow will be initiated when a push occurs.

Workflow Structure

A GitHub Actions workflow is created inside the folder:

.github/workflows/

For example:

.github/workflows/pipeline.yml

A simple workflow can be written like this:

name: Primeiro workflow

on:
  push:

jobs:
  exemplo:
    runs-on: ubuntu-latest

    steps:
      - name: Exibir mensagem
        run: echo "O workflow foi executado"

The on property defines when the workflow will run.

The jobs property defines which tasks will be performed.

flowchart LR
    A[Evento acontece] --> B[Trigger é identificado]
    B --> C[Workflow é iniciado]
    C --> D[Jobs são executados]
    D --> E[Steps são processados]

push Trigger

The push trigger initiates the workflow when commits or tags are pushed to the repository.

on:
  push:

With this configuration, any push can initiate the workflow.

For example:

git add .
git commit -m "feat: adiciona tela de login"
git push origin main

After the push, GitHub looks for workflows configured with this event.

Running only on a specific branch

We can limit the workflow to a specific branch:

on:
  push:
    branches:
      - main

Now the workflow will only run when there’s a push to main.

We can also monitor multiple branches:

on:
  push:
    branches:
      - main
      - develop

Using branch patterns

We can use patterns to monitor groups of branches:

on:
  push:
    branches:
      - main
      - "feature/**"

This pattern can match branches like:

feature/login
feature/cadastro
feature/pagamento/pix

When using characters like *, it’s recommended to enclose the value in quotes.

Ignoring branches

We can also define branches that should not initiate the workflow:

on:
  push:
    branches-ignore:
      - develop
      - "feature/**"

In this case, pushes made to develop or feature branches will be ignored.

Running workflows with tags

The push event can also monitor tags:

on:
  push:
    tags:
      - "v*"

This workflow can be initiated by tags like:

v1.0.0
v1.1.0
v2.0.0

To create and push a tag:

git tag v1.0.0
git push origin v1.0.0

This type of trigger is common in workflows used for:

Example:

name: Publicar versão

on:
  push:
    tags:
      - "v*"

jobs:
  release:
    runs-on: ubuntu-latest

    steps:
      - name: Baixar o código
        uses: actions/checkout@v4

      - name: Mostrar versão
        run: echo "Publicando a versão ${{ github.ref_name }}"

File filters with paths

Not every change needs to run all pipelines.

Imagine a repository with:

frontend/
backend/
infra/
docs/
.github/

A change only in the documentation doesn’t necessarily need to run backend tests.

We can use the paths filter:

on:
  push:
    branches:
      - main
    paths:
      - "backend/**"
      - ".github/workflows/**"

The workflow will run when:

  1. the push occurs on main;
  2. any file in backend or .github/workflows is modified.
flowchart TD
    A[Push realizado] --> B{Foi na main?}
    B -- Não --> C[Workflow não executa]
    B -- Sim --> D{Alterou arquivos monitorados?}
    D -- Não --> C
    D -- Sim --> E[Workflow executa]

Ignoring files

We can also use paths-ignore:

on:
  push:
    paths-ignore:
      - "docs/**"
      - "**/*.md"

In this case, changes made only to Markdown files or in the docs folder will not initiate the workflow.

pull_request Trigger

The pull_request event initiates the workflow when any activity related to a Pull Request occurs.

on:
  pull_request:

It is frequently used for:

Example:

name: Validar Pull Request

on:
  pull_request:

jobs:
  test:
    runs-on: ubuntu-latest

    steps:
      - name: Baixar o código
        uses: actions/checkout@v4

      - name: Executar testes
        run: echo "Executando testes do Pull Request"

Pull Request for a specific branch

We can run the workflow only when the target branch is main:

on:
  pull_request:
    branches:
      - main

Consider this Pull Request:

feature/login → main

The source is:

feature/login

The target is:

main

In the pull_request event, the branches filter considers the target branch.

Pull Request activity types

We can control which activities will initiate the workflow:

on:
  pull_request:
    types:
      - opened
      - synchronize
      - reopened

In this example, the workflow will be initiated when the Pull Request is:

Full example:

name: Testes do Pull Request

on:
  pull_request:
    branches:
      - main
    types:
      - opened
      - synchronize
      - reopened

jobs:
  test:
    runs-on: ubuntu-latest

    steps:
      - name: Baixar o repositório
        uses: actions/checkout@v4

      - name: Executar testes
        run: echo "Validando o Pull Request"

Filtering files in Pull Request

We can also use paths:

on:
  pull_request:
    branches:
      - main
    paths:
      - "backend/**"

The workflow will run when:

workflow_dispatch Trigger

The workflow_dispatch trigger allows you to run the workflow manually.

on:
  workflow_dispatch:

With it, the workflow can be started from the GitHub Actions tab.

This trigger is useful for:

Example:

name: Workflow manual

on:
  workflow_dispatch:

jobs:
  executar:
    runs-on: ubuntu-latest

    steps:
      - name: Exibir mensagem
        run: echo "O workflow foi iniciado manualmente"

Receiving parameters manually

The workflow_dispatch can also receive user-provided values.

name: Executar imagem Docker

on:
  workflow_dispatch:
    inputs:
      imagem:
        description: Imagem Docker que será utilizada
        required: true
        default: nginx:latest

jobs:
  executar:
    runs-on: ubuntu-latest

    steps:
      - name: Mostrar imagem
        run: echo "Imagem selecionada: ${{ inputs.imagem }}"

When starting the workflow manually, you will be able to specify which image should be used.

schedule Trigger

The schedule trigger runs workflows at scheduled times.

on:
  schedule:
    - cron: "0 9 * * 1-5"

In this example, the workflow will run Monday through Friday at 09:00 UTC.

A cron expression has five positions:

┌──────────── minute
│ ┌────────── hour
│ │ ┌──────── day of month
│ │ │ ┌────── month
│ │ │ │ ┌──── day of week
│ │ │ │ │
0 9 * * 1-5

The expression:

0 9 * * 1-5

means:

minute: 0
hour: 9
day of month: any
month: any
day of week: Monday to Friday

Example:

name: Testes agendados

on:
  schedule:
    - cron: "0 9 * * 1-5"

jobs:
  test:
    runs-on: ubuntu-latest

    steps:
      - name: Baixar o código
        uses: actions/checkout@v4

      - name: Executar testes
        run: echo "Executando testes agendados"

Times configured in schedule use UTC.

create Trigger

The create event initiates a workflow when a Git reference is created.

This reference can be:

on:
  create:

For example, the event may occur when a new branch is pushed:

git checkout -b feature/login
git push -u origin feature/login

It can also occur when pushing a tag:

git tag v1.0.0
git push origin v1.0.0

Example:

name: Monitorar criação de referências

on:
  create:

jobs:
  audit:
    runs-on: ubuntu-latest

    steps:
      - name: Mostrar referência
        run: |
          echo "Referência: ${{ github.ref }}"
          echo "Tipo: ${{ github.ref_type }}"

delete Trigger

The delete event initiates a workflow when a branch or tag is deleted.

on:
  delete:

For example:

git push origin --delete feature/login

This trigger can be used for:

Example:

name: Monitorar exclusão de referências

on:
  delete:

jobs:
  audit:
    runs-on: ubuntu-latest

    steps:
      - name: Registrar exclusão
        run: |
          echo "Referência excluída: ${{ github.event.ref }}"
          echo "Tipo: ${{ github.event.ref_type }}"

branch_protection_rule Trigger

The branch_protection_rule event initiates a workflow when a branch protection rule is created, edited, or deleted.

on:
  branch_protection_rule:

We can define the activity types:

on:
  branch_protection_rule:
    types:
      - created
      - edited
      - deleted

The types represent:

created
└── rule created

edited
└── rule modified

deleted
└── rule removed

This event can help with repository auditing.

Example:

name: Auditoria da proteção de branches

on:
  branch_protection_rule:
    types:
      - created
      - edited
      - deleted

jobs:
  audit:
    runs-on: ubuntu-latest

    steps:
      - name: Mostrar alteração
        run: |
          echo "Uma regra de proteção foi alterada"
          echo "Ação: ${{ github.event.action }}"

Combining multiple triggers

A workflow can have more than one trigger.

name: Pipeline principal

on:
  push:
    branches:
      - main

  pull_request:
    branches:
      - main

  workflow_dispatch:

jobs:
  validar:
    runs-on: ubuntu-latest

    steps:
      - name: Baixar o código
        uses: actions/checkout@v4

      - name: Executar validação
        run: echo "Validando o projeto"

This workflow can be initiated:

by a push to main
        or
by a Pull Request to main
        or
manually

Identifying the event that initiated the workflow

We can find out which trigger initiated the workflow using:

${{ github.event_name }}

Example:

name: Identificar evento

on:
  push:
  pull_request:
  workflow_dispatch:

jobs:
  identificar:
    runs-on: ubuntu-latest

    steps:
      - name: Mostrar evento
        run: echo "Evento recebido: ${{ github.event_name }}"

The result could be:

push
pull_request
workflow_dispatch

Running steps based on the trigger

We can also use conditions:

name: Pipeline por evento

on:
  push:
    branches:
      - main

  pull_request:
    branches:
      - main

  workflow_dispatch:

jobs:
  pipeline:
    runs-on: ubuntu-latest

    steps:
      - name: Baixar o código
        uses: actions/checkout@v4

      - name: Executar testes
        run: echo "Executando testes"

      - name: Executar deploy
        if: github.event_name == 'push'
        run: echo "Executando deploy"

In this example:

Complete pipeline example

name: Pipeline da aplicação

on:
  push:
    branches:
      - main
    paths:
      - "src/**"
      - "package.json"
      - "package-lock.json"

  pull_request:
    branches:
      - main
    paths:
      - "src/**"
      - "package.json"
      - "package-lock.json"

  workflow_dispatch:

jobs:
  test:
    runs-on: ubuntu-latest

    steps:
      - name: Baixar o código
        uses: actions/checkout@v4

      - name: Configurar Node.js
        uses: actions/setup-node@v4
        with:
          node-version: 22

      - name: Instalar dependências
        run: npm ci

      - name: Executar testes
        run: npm test

  deploy:
    if: github.event_name == 'push'
    needs: test
    runs-on: ubuntu-latest

    steps:
      - name: Realizar deploy
        run: echo "Realizando deploy da aplicação"

The flow of this pipeline will be:

flowchart TD
    A[Push, Pull Request ou execução manual] --> B[Executar testes]
    B --> C{Testes passaram?}
    C -- Não --> D[Pipeline falha]
    C -- Sim --> E{Evento foi push?}
    E -- Não --> F[Pipeline finalizado]
    E -- Sim --> G[Executar deploy]

Summary of main triggers

TriggerWhen executed
pushWhen commits or tags are pushed
pull_requestWhen an activity occurs in a Pull Request
workflow_dispatchWhen the workflow is manually initiated
scheduleWhen a scheduled time arrives
createWhen a branch or tag is created
deleteWhen a branch or tag is deleted
branch_protection_ruleWhen a branch protection rule is changed

Best practices

Avoid running all workflows on every change.

Instead of:

on:
  push:

We can be more specific:

on:
  push:
    branches:
      - main
    paths:
      - "backend/**"

It’s also good practice to separate workflows according to their responsibilities.

A test workflow can use:

on:
  pull_request:

A deploy workflow can use:

on:
  push:
    branches:
      - main

Manual maintenance can use:

on:
  workflow_dispatch:

This way, each pipeline will run only when truly necessary.

Conclusion

Triggers define when a GitHub Actions workflow should run.

The push reacts to pushes of commits or tags. The pull_request allows validating changes before merging. The workflow_dispatch offers manual execution, while the schedule allows creating scheduled automations.

Events like create, delete, and branch_protection_rule can also be used for repository auditing, security, and management.

With branch and path filters, we can precisely control when the workflow should run:

on:
  push:
    branches:
      - main
    paths:
      - "backend/**"

Thus, the pipeline stops running for every change and only responds to events important for the project.

References

What did you think?