English | 한국어
This document explains the structure of the configuration file and how to write it. The configuration file is located in
the .github directory.
- 1. Quick Start
- 2. Top-Level Structure
- 3. settings
- 4. rules
- 5. conditions
- 6. When Configuration Validation Fails
- 7. Practical Examples
- 8. Common Mistakes
settings:
skipIfBot: false
removeUnmatchedLabels: false
onMissingLabel: create
dryRun: false
rules:
issue:
- label: bug
matches:
# The title starts with `[bug]`, the body contains the `error` keyword,
# and the `wip` keyword is not included
- operator: all
conditions:
- title: /^\[bug\]/i
- body: /\berror\b/i
- body: /\bwip\b/i
negate: true
pr:
- label: large-change
matches:
# The changed line count is 200 or more and the PR is not a draft
- operator: all
conditions:
- changed-lines: '>=200'
- draft: false
- label: documentation
skipIfBot: true
matches:
# The `docs` directory or the `README.md` file changed
- operator: any
conditions:
- changed-files: 'docs/**/*.md'
- changed-files: 'README.md'
# The title contains the `docs` keyword
- operator: any
skipIfBot: false
conditions:
- title: /\bdocs?\b/iNote
- Configure the
pull_request_targetevent underrules.pras well. - If you want to understand how rules, matches, and conditions are evaluated, see Rule Evaluation Policy.
settings: {}
rules:
issue: []
pr: []- Only the root keys
settingsandrulesare allowed. - If the configuration file is empty (
null) orsettings/rulesis missing, default values are injected automatically. rules.issueandrules.prare treated as empty arrays ([]) even when they arenullor not specified.
| Option | Allowed values | Default | Description |
|---|---|---|---|
skipIfBot |
true, false |
false |
Skips evaluation when the event was triggered by a bot. |
removeUnmatchedLabels |
true, false |
false |
Can remove an existing label when all evaluated matches fail. |
onMissingLabel |
create, skip, error |
create |
Determines how to handle labels that do not exist in the repo. |
dryRun |
true, false |
false |
Simulates the run without calling the actual add/remove APIs. |
This option is used during match evaluation.
It determines whether to skip match evaluation when the event was triggered by a bot. If true, evaluation is skipped.
- This option can be configured at
settings, each rule, and each match. - If a value is not specified, it inherits the parent setting.
settings.skipIfBot(global)rule.skipIfBot(overrides the global setting)match.skipIfBot(overrides the rule setting)
Example:
settings:
skipIfBot: true # Skip evaluation by default for bot-triggered events in all matches
rules:
pr:
- label: release-review
skipIfBot: false # Matches in this rule are still evaluated for bot-triggered events
matches:
- operator: any
skipIfBot: true # Only this match is skipped for bot-triggered events
conditions:
- title: /release/iThis option is used during rule evaluation.
It determines whether to remove the label when all evaluated (non-skip) matches fail. If true, it removes the label
already attached to the issue or PR when the evaluation result is as follows.
- If there is at least one match that is not
skipand all of them arefail, the label is removed. - In other words, the label is not removed if there is at least one
pass, or if all matches areskip.
Note
- Each match has one of the states
pass|fail|skip.
This option is used when adding or removing labels.
It determines how to handle labels that do not exist in the repository when the action tries to add or remove them from an issue or PR.
create- If the action tries to add a label that does not exist in the repository, it creates the label in the repository first and then adds it.
skip- If the action tries to add or remove a label that does not exist in the repository, it skips the operation.
error- It pre-checks the labels declared in the configuration file and exits immediately if any label does not exist in the repository.
- This fails early so that label add/remove operations do not run.
⚠️ This check is performed against the entire configuration file (rules.issue + rules.pr), not only the labels configured for the currently triggered event (issueorpr).
This option is used when adding or removing labels.
When true, the action simulates label add/remove behavior without calling the label add/remove APIs.
- It does not call the label add/remove APIs, but it still calls the read APIs required to collect context and evaluate rules.
- In the action output
labels, you can check whether each item was simulated through itssimulatedByDryRunfield. - In the summary, you can check whether it was simulated through the parenthesized notation attached to the label name.
rules.issue: GitHubissueseventrules.pr: GitHubpull_request,pull_request_targetevents
Defines label rules for each event.
rules:
issue:
- label: bug
skipIfBot: false # optional
matches:
- operator: any
conditions:
- title: /bug/i| Key | Type | Required | Description |
|---|---|---|---|
label |
string |
Yes | Target label name |
skipIfBot |
boolean |
No | Overrides settings.skipIfBot |
matches |
Match[] |
Yes | List of one or more matches |
Constraints:
- Within the same event bucket (
rules.issueorrules.pr), a duplicatelabelcauses an error after trimming leading/trailing whitespace and converting to lowercase.- Example:
bug,BUG," bug","bug ", and" bug "are all treated as the same label and cause a duplicate-label error.
- Example:
labelcannot be a string made of whitespace only.matchescannot be an empty array.
matches:
- operator: all
skipIfBot: true # optional
conditions:
- body: /release note/i| Key | Type | Required | Description |
|---|---|---|---|
operator |
any | all |
Yes | How conditions are combined |
skipIfBot |
boolean |
No | Overrides rule.skipIfBot |
conditions |
Condition[] |
Yes | List of one or more conditions |
Evaluation rules:
any: pass when at least one condition is trueall: fail when at least one condition is false- Conditions are short-circuited.
conditionscannot be an empty array.
A condition object must have exactly one property key, excluding negate. Each property defines which value types
are allowed.
Correct example:
conditions:
- title: /bug/i
- body: /wip/i
negate: trueIncorrect example:
conditions:
- title: /bug/i
body: /error/i # Error because there are two property keys| Property | Issue | PR | Allowed value types (in precedence order) |
|---|---|---|---|
title |
O | O | regex |
body |
O | O | regex |
author |
O | O | regex, string |
base-branch |
X | O | regex, string |
head-branch |
X | O | regex, string |
draft |
X | O | boolean |
changed-lines |
X | O | numeric-comparison |
changed-files |
X | O | glob-pattern, string |
- Checks the issue/PR title (
issue.title,pullRequest.title).
- Checks the issue/PR body (
issue.body,pullRequest.body). - If the body is empty, it is evaluated after treating the body value as an empty string (
'').
- Checks the issue/PR author's login (
issue.author.login,pullRequest.author.login).
- Checks the PR's base branch name (
pullRequest.baseRefName).
- Checks the PR's head branch name (
pullRequest.headRefName).
- Checks whether the PR is in draft state (
pullRequest.isDraft).
- Checks against the PR's total changed lines (
pullRequest.additions + pullRequest.deletions). - In other words, it uses the sum of added lines and deleted lines in the PR.
- Checks against the list of changed file paths in the PR.
- Each file path is checked one by one, and the condition becomes true if any one of them matches.
- Format:
/pattern/flagsstring - Examples:
/bug/i,/^release\//
- Uses exact match comparison (
===). - It is not interpreted like a regular expression.
trueorfalse
- Only strings recognized by
is-globas glob patterns are treated asglob-pattern. - Examples:
src/**/*.ts,**/*.md
- Format:
operator + integer(whitespace after the operator is optional) - Operators:
>,>=,<,<=,==,!= - Examples:
'>10','>= 200','==0','!= 3' - Only integers are allowed. Negative numbers and decimals are not supported.
- You can add
negateto every condition. - Adding
negate: trueinverts the condition result.
When a property allows two or more value types, precedence is applied in the order shown in the Supported Properties by Event table.
For example, author is interpreted in the order regex -> string.
author: /octo.*/is evaluated as a regular expression.author: octocatis evaluated as an exact string match.
For example, changed-files is interpreted in the order glob-pattern -> string.
changed-files: 'src/**/*.ts'is evaluated as a glob pattern.changed-files: 'README.md'is evaluated as an exact string match.
Below are common cases that fail during parsing.
- Adding an unsupported key at the root
- Adding an unsupported key to
settings,rules, each rule, each match, or each condition - Using an unsupported event key
- Duplicate labels within the same event bucket
- Using an invalid
onMissingLabelvalue - Using an unsupported condition property
- Writing zero condition properties or two or more condition properties
- Writing
matchesas an empty array - Writing
conditionsas an empty array - Using a condition value format that does not match any allowed type for that property
settings:
skipIfBot: true
rules:
pr:
- label: auto-merge-candidate
skipIfBot: false
matches:
- operator: all
conditions:
- head-branch: /^release\//rules:
issue:
- label: ready
matches:
- operator: all
conditions:
- title: /ready/i
- body: /wip/i
negate: truerules:
pr:
- label: docs
matches:
- operator: any
conditions:
- changed-files: 'docs/**/*.md'
- changed-files: 'README.md'rules:
issue:
- label: triage-bot
matches:
- operator: any
conditions:
- author: /.*\[bot\]/
- author: 'octocat'- Writing two or more properties in a single condition
- Writing a
regexcondition as a normal string, or not following the/pattern/flagsformat - Using an invalid comparison expression for
numeric-comparison, such as decimal values, negative values, or invalid operators