Notification Rules
Notification rules let you send Slack notifications when merge requests or pipelines match your custom conditions. Instead of getting notified about everything, you can filter notifications to only the events that matter to your team.
How Rules Work
-
All rules are evaluated on every event - When a merge request is opened, merged, or closed, or when a pipeline status changes, all enabled rules for that repository are evaluated.
-
Lua conditions filter events - Each rule has an optional Lua condition that determines whether the rule fires. If the condition evaluates to
true, a notification is sent. -
Fire-once semantics - Once a rule fires for a specific merge request or pipeline, it won't fire again for that same entity. This prevents duplicate notifications.
Creating a Rule
- Go to Rules in your dashboard
- Click "New Rule"
- Fill in the rule details:
- Name: A descriptive name for your rule
- Repository: The repository this rule applies to
- Slack Channel: Where to send notifications (channel ID or name)
- Lua Condition: The condition that must be true to trigger the notification
Slack Channel Format
You can specify the Slack channel in two ways:
- Channel ID: e.g.,
C01234ABCDE(starts with "C") - Channel name: e.g.,
#engineering-alertsorengineering-alerts
Using a channel ID is more reliable and faster. To find a channel ID, right-click on the channel in Slack and select "Copy link" - the ID is in the URL.
Lua Condition Syntax
Lua conditions are simple expressions that evaluate to true or false. You can use the variables listed below along with standard Lua operators.
Operators
| Operator | Description | Example |
|---|---|---|
== |
Equal to | mr.status == "merged" |
~= |
Not equal to | mr.status ~= "draft" |
>, >=, <, <= |
Comparison | mr.approvals >= 2 |
and |
Logical AND | mr.target_branch == "main" and not mr.draft |
or |
Logical OR | mr.status == "merged" or mr.status == "closed" |
not |
Logical NOT | not mr.draft |
String Matching
-- Check if branch starts with a prefix
string.find(mr.target_branch, "^release/") ~= nil
-- Check if title contains a keyword
string.find(mr.title, "hotfix") ~= nil
MR/PR Variables
These variables are available when evaluating rules for merge request or pull request events:
| Variable | Type | Values | Description |
|---|---|---|---|
mr.draft |
boolean | true, false |
Is this a draft/WIP merge request |
mr.status |
string | "open", "merged", "closed" |
Overall MR state |
mr.target_branch |
string | e.g. "main", "develop" |
Branch being merged into |
mr.source_branch |
string | e.g. "feature/foo" |
Branch with changes |
mr.title |
string | Any text | MR title |
mr.author |
string | Username or slack_id | Author identifier |
mr.approvals |
integer | 0, 1, 2... |
Number of approvals |
mr.repository |
string | e.g. "org/repo" |
Repository path |
mr.iid |
integer | e.g. 42 |
MR/PR number |
mr.provider |
string | "gitlab", "github" |
Source provider |
mr.comment_review_status |
string | "approved", "requires_changes", "pending", "empty" |
Review/comment status |
mr.build_status |
string | "success", "failed", "running", "pending", nil |
CI/CD pipeline status |
Pipeline Variables
These variables are available when evaluating rules for pipeline or workflow events:
| Variable | Type | Values | Description |
|---|---|---|---|
pipeline.status |
string | "created", "running", "success", "failed", "canceled" |
Pipeline state |
pipeline.ref |
string | e.g. "main", "v1.0.0" |
Branch or tag name |
pipeline.source |
string | "push", "merge_request_event", "schedule", "web" |
What triggered it |
pipeline.duration |
integer or nil | Seconds or nil | Duration (if finished) |
pipeline.project_name |
string | e.g. "org/repo" |
Repository path |
pipeline.provider |
string | "gitlab", "github" |
Source provider |
pipeline.url |
string | URL | Link to pipeline |
Example Conditions
Notify when any MR targets main and is not a draft
mr.target_branch == "main" and not mr.draft
Notify when pipeline fails on main branch
pipeline.status == "failed" and pipeline.ref == "main"
Notify when MR is merged
mr.status == "merged"
Notify when pipeline is created (starts running)
pipeline.status == "created"
Notify when build succeeds on main
pipeline.status == "success" and pipeline.ref == "main"
Notify when MR is approved and targets main
mr.comment_review_status == "approved" and mr.target_branch == "main"
Notify when MR has at least one approval
mr.approvals >= 1
Notify on release branches
string.find(mr.target_branch, "^release/") ~= nil
Notify on hotfix MRs
string.find(mr.title, "hotfix") ~= nil or string.find(mr.source_branch, "^hotfix/") ~= nil
Empty Condition
If you leave the Lua condition empty, the rule will match all events for that repository. This is useful if you want to be notified about every merge request or pipeline.
Troubleshooting
Rule not firing?
- Check if the rule is enabled - Disabled rules are not evaluated
- Check the Lua condition - Test your condition with simpler expressions first
- Check the Slack channel - Make sure the bot is a member of the channel
- Fire-once semantics - Rules only fire once per MR/pipeline
Getting too many notifications?
- Add more specific conditions - Use
andto combine multiple conditions - Filter by branch - e.g.,
mr.target_branch == "main" - Filter by status - e.g.,
mr.status == "merged"
Lua syntax errors
Common mistakes:
- Use
==for comparison (not=) - Use
~=for not-equal (not!=) - Use
and/or/not(not&&/||/!) - String values must be quoted:
mr.status == "merged"