Skip to content

About

⚓ A lightweight TypeScript action for signal-based CI/CD workflow control

Topics

Resources

Code of conduct

Contributing

Security policy

Stars

2 stars

Watchers

0 watching

Forks

Use this GitHub action with your project
Add this Action to an existing workflow or create a new one
View on Marketplace

Latest commit

 

History

61 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Belay is a signal-based workflow control action for GitHub Actions. It evaluates commit messages, pull request titles, and labels against configured signals - tags, regex patterns, and PR labels - and issues a belay order when a match is found. On match, Belay can either report the result via output for the caller to act on, or cancel the workflow run entirely via the GitHub API.

Overview

Belay solves a common CI/CD problem: running expensive workflows on commits that don't need them. Instead of duplicating skip logic across every workflow with bash scripts and environment variables, Belay centralizes signal detection into a single reusable action.

Concept Description
Signal A condition that triggers a belay order - a tag substring, a regex pattern, or a PR label
Belay order The result of signal evaluation - issued when any configured signal matches
On match The action executed when a belay order is issued - report or cancel
Issued The issued output - "true" if any signal matched, "false" otherwise

How It Works

The following diagram illustrates the lifecycle of a GitHub workflow run when evaluated by Belay Action:

graph TD
  Event[GitHub Event: Push / PR] --> Job[Job: Signal Evaluation <br/> Belay Action]
  Job                            --> Evaluation{Signal Match Found?}

  Evaluation -- "Yes" --> LogMatch[issued='true' <br/> Logs match details]
  Evaluation -- "No"  --> Continue[issued='false' <br/> Logs execution & proceeds]

  LogMatch --> OnMatch{on_match strategy?}

  OnMatch -- "cancel" --> Cancel[Terminates run via GitHub API]
  OnMatch -- "report" --> Report[Logs result, workflow continues]

  style Event      fill:#f6d9f5,stroke:#b7a1b6,stroke-width:2px,color:#000
  style Evaluation fill:#fff2cc,stroke:#d6b656,stroke-width:2px,color:#000
  style LogMatch   fill:#ccefff,stroke:#9cb7c4,stroke-width:2px,color:#000
  style OnMatch    fill:#fff2cc,stroke:#d6b656,stroke-width:2px,color:#000
  style Cancel     fill:#f9cedc,stroke:#b79ca5,stroke-width:2px,color:#000
  style Report     fill:#e2f0cb,stroke:#a8b796,stroke-width:2px,color:#000
  style Continue   fill:#e2f0cb,stroke:#a8b796,stroke-width:2px,color:#000
Loading

Usage

Report mode

The default mode. Belay sets the issued output and logs the result. The caller decides what to do next.

jobs:
  check:
    name: "Skip Check"
    runs-on: ubuntu-latest
    outputs:
      should_skip: ${{ steps.belay.outputs.issued }}
    steps:
      - name: "Setup: Checkout repository"
        uses: actions/checkout@v6

      - name: "Run: Belay"
        id: belay
        uses: OctalMesh/belay-action@v1
        with:
          signal_tags: "[ci-skip],[skip-ci]"
          signal_labels: "ci-skip,skip-ci"

  build:
    needs: check
    if: needs.check.outputs.should_skip != 'true'
    runs-on: ubuntu-latest
    steps:
      - run: pnpm build

Cancel mode

Belay cancels the entire workflow run via the GitHub API when a signal is matched. The run is marked as canceled, not failed.

jobs:
  check:
    name: "Skip Check"
    runs-on: ubuntu-latest
    permissions:
      actions: write # Required for cancel mode
    steps:
      - name: "Setup: Checkout repository"
        uses: actions/checkout@v6

      - name: "Run: Belay"
        uses: OctalMesh/belay-action@v1
        with:
          signal_tags: "[ci-skip],[skip-ci]"
          on_match: "cancel"

Note

Cancel mode requires actions: write permission on the job or workflow level. The github_token input defaults to ${{ github.token }} and is passed automatically - no manual configuration needed in most cases.

Regex patterns

Use signal_patterns for more expressive matching. Patterns are evaluated as standard JavaScript regular expressions.

- uses: OctalMesh/belay-action@v1
  with:
    signal_patterns: "^chore\\(deps\\),^chore\\(release\\)"
    signal_labels: "dependencies,release"
    on_match: "cancel"

Tip

Escape backslashes in YAML - \( becomes \\( in the input string.

Inputs

Input Required Default Description
signal_tags No [ci-skip],[skip-ci] Comma-separated substrings to match against the commit message and PR title
signal_patterns No - Comma-separated regex patterns to match against the commit message and PR title
signal_labels No ci-skip,skip-ci Comma-separated PR label names that trigger a belay order
on_match No report Action to execute on match. Accepted values: report, cancel
github_token No ${{ github.token }} GitHub token used to cancel the workflow run. Required only when on_match is cancel

Outputs

Output Description
issued "true" if a belay order was issued, "false" otherwise

Note

The issued output is always set regardless of the on_match value. In cancel mode it is still available to subsequent steps that run before the cancellation is processed.

Signals

Belay evaluates three independent signal types. A belay order is issued if any signal matches.

Tags

Substring matching against the commit message and PR title. Fast and simple - use for conventional skip markers.

signal_tags: "[ci-skip],[skip-ci],[docs-only]"

Matches any commit message or PR title that contains at least one of the listed substrings.

Patterns

Regex matching against the commit message and PR title. Use when tag matching is too broad, or you need anchored, structured patterns.

signal_patterns: "^chore\\(deps\\),^docs:"

Each pattern is compiled as a JavaScript RegExp and tested independently. The first match issues a belay order.

Labels

PR label matching. Evaluated only on pull_request events - on push events the label list is empty and this signal never matches.

signal_labels: "ci-skip,dependencies,release"

Tip

Combine all three signal types in a single step. Belay evaluates them in parallel and stops at the first match.

Permissions

Mode Required permission
report contents: read (default)
cancel actions: write

Permissions can be set at the workflow or job level:

permissions:
  contents: read
  actions: write


OctalMesh

Telegram   YouTube   TikTok   Instagram   X   Reddit
• • •

This project is licensed under the MIT License

  • Feel free to use this project for any purpose, including commercial applications.
  • You are permitted to modify, distribute, and include this project in any form, as long as the original copyright notice is retained.
  • If you share or publish modified versions, attribution to the original GitHub repository is appreciated.
  • This software is provided "as is", without any warranties or guarantees, as detailed in the license terms.

About

⚓ A lightweight TypeScript action for signal-based CI/CD workflow control

Topics

Resources

Code of conduct

Contributing

Security policy

Stars

2 stars

Watchers

0 watching

Forks

Releases

Sponsor this project

Used by

Contributors

Languages