GitHub Action
Multi Labeler
Multi labeler for title, body, comments, commit messages, branch, base branch, author or files. Optionally, generate a status check based on the labels.
Who is using fuxingloh/multi-labeler
?
- Single compiled javascript file, extremely fast. Use fewer credits!
- Append based multi-labeler, using
.github/labeler.yml
as config. - Automatically fail if
labeler.yml
is malformed, type-checked. - Set label to sync for conditional labeling, removed if condition failed.
- Regex Matcher:
- PR/Issue title
- PR/Issue body
- PR/Issue comments
- PR commit messages
- PR branch name
- PR base (target) branch name
- File Matcher:
- Files count
- Files any glob match
- Files all glob match
- Author Matcher
- Generate status checks:
- Any label match
- All label match
on:
pull_request_target:
# for OSS with public contributions (forked PR)
pull_request:
# Useful for triaging code review, and generate compliance status check.
# Semantic release? Done.
# Make a file change in a mono repo. Tag the mono repo getting changed to generate better release!
issues:
# Useful for triaging error!
# '- [x] Is this a bug?' = 'bug' label!
issue_comment:
# To pickup comment body in pr or issue and generate a label.
# Imagine someone comment 'Me too, I get TimeoutException from ...' in comment body.
# Generate a 'bug/timeout' label for better triaging!
permissions:
# Setting up permissions in the workflow to limit the scope of what it can do. Optional!
contents: read # the config file
issues: write # for labeling issues (on: issues)
pull-requests: write # for labeling pull requests (on: pull_request_target or on: pull_request)
statuses: write # to generate status
checks: write # to generate status
jobs:
labeler:
name: Labeler
runs-on: ubuntu-latest
steps:
# follows semantic versioning. Lock to different version: v1, v1.5, v1.5.0 or use a commit hash.
- uses: fuxingloh/multi-labeler@v4 # v4
with:
github-token: ${{secrets.GITHUB_TOKEN}} # optional, default to '${{ github.token }}'
config-path: .github/labeler.yml # optional, default to '.github/labeler.yml'
config-repo: my-org/my-repo # optional, default to '${{ github.repository }}'
# .github/labeler.yml
version: v1
labels:
- label: 'feat'
sync: true # remove label if match failed, default: false (pull_request/issue only)
matcher:
# Matcher will match on any 8 matchers
title: '^feat:.*'
body: '/feat'
comment: '/feat'
branch: '^feat/.*'
baseBranch: '^feat/.*'
commits: '^feat:.*'
author:
- github-actions
- fuxingloh
files:
any: ['app/*']
all: ['!app/config/**']
count:
gte: 1
lte: 1000
# Optional, if you want labels to generate a success/failure status check
checks:
- context: 'Status Check'
url: 'https://go.to/detail'
description:
success: 'Ready for review & merge.'
failure: 'Missing labels for release.'
labels:
any:
- any
- have
all:
- all
- must
- have
Semantic Pull Request
on:
pull_request:
types: [opened, edited, synchronize, ready_for_review]
branches: [master, main]
jobs:
labeler:
name: Labeler
runs-on: ubuntu-latest
steps:
- uses: fuxingloh/multi-labeler@v4
version: v1
labels:
- label: 'feat'
matcher:
title: '^feat: .*'
commits: '^feat: .*'
- label: 'fix'
matcher:
title: '^fix: .*'
commits: '^fix: .*'
- label: 'chore'
matcher:
title: '^chore: .*'
commits: '^chore: .*'
- label: 'docs'
matcher:
title: '^docs: .*'
commits: '^docs: .*'
checks:
- context: 'Semantic Pull Request'
url: 'https://github.com/fuxingloh/multi-labeler/blob/main/.github/labeler.yml'
description:
success: Ready for review & merge.
failure: Missing semantic label for merge.
labels:
any:
- feat
- fix
- chore
- docs
PR Triage
on:
pull_request:
types: [opened, edited, synchronize, ready_for_review]
branches: [master, main]
jobs:
labeler:
name: Labeler
runs-on: ubuntu-latest
steps:
- uses: fuxingloh/multi-labeler@v4
version: v1
labels:
- label: 'feat'
matcher:
title: '^feat:.*'
branch: '^feat/.*'
commits: '^feat:.*'
- label: 'fix'
matcher:
title: '^fix:.*'
branch: '^fix/.*'
commits: '^fix:.*'
- label: 'release'
matcher:
baseBranch: '^release/.*'
Issue Triage
on:
issues:
types: [opened, edited]
jobs:
labeler:
name: Labeler
runs-on: ubuntu-latest
steps:
- uses: fuxingloh/multi-labeler@v4
version: v1
labels:
- label: 'bug'
matcher:
body: "(\\n|.)*- \\[x\\] bug(\\n|.)*"
Comment Triage
on:
issue_comment:
types: [created, edited]
jobs:
labeler:
name: Labeler
runs-on: ubuntu-latest
steps:
- uses: fuxingloh/multi-labeler@v4
version: v1
labels:
- label: 'coverage'
matcher:
comment: "# \\[Codecov\\] .*"
- label: 'stale'
matcher:
comment: '/stale'
Once you’ve added fuxingloh/multi-labeler to your repository,
it must be enabled by adding a .github/labeler.yml
configuration file to the repository.
If you want to use a configuration file shared across multiple repositories,
you can set theconfig-repo
input to point to a different repository.
However, make sure to set a github-token
that has permissions to access the provided repository,
as the default GITHUB_TOKEN
only has access to the repository the action is running in.
RegEx matcher requires backslash '' to be double slashed '\'. Hence, to match brackets '()' you need a regex of '\(\)'. See #103
version: v1
labels:
- label: 'feat'
matcher:
title: '^feat:.*'
version: v1
labels:
- label: 'bug'
matcher:
# e.g. '- [x] bug'
body: "(\\n|.)*- \\[x\\] bug(\\n|.)*"
version: v1
labels:
- label: 'stale'
matcher:
comment: '/stale'
version: v1
labels:
- label: 'feat'
matcher:
branch: '^feat/.*'
version: v1
labels:
- label: 'release'
matcher:
baseBranch: '^release/.*'
Check all commits and find any match, max of 250 commits only.
version: v1
labels:
- label: 'feat'
matcher:
commits: '^feat: .*'
Check for pr or issue author match.
version: v1
labels:
- label: 'single'
matcher:
author: 'fuxingloh'
- label: 'any'
matcher:
author:
- adam
- claire
PR Files: Glob Matcher
Maximum of 3000 files only. If you use this to audit changes, take note of the 3000 files limitation. Matchers within files are 'and condition'; all must match.
version: v1
labels:
- label: 'github'
sync: true
matcher:
# This is shorthand for any: [".github/**"]
files: '.github/**'
- label: 'security'
sync: true
matcher:
# This is shorthand for any: ["web/security/**", "security/**"]
files: ['web/security/**', 'security/**']
version: v1
labels:
- label: 'size: s'
sync: true
matcher:
files:
count:
gte: 1
lte: 4
- label: 'size: m'
sync: true
matcher:
files:
count:
gte: 5
lte: 10
- label: 'size: l'
sync: true
matcher:
files:
count:
gte: 11
version: v1
labels:
- label: 'ci'
sync: true
matcher:
files:
any: ['.github/workflow/**', '.circleci/**']
all: ['!app/**']
- label: 'attention'
sync: true
matcher:
files:
any: ['app/**']
count:
neq: 1
version: v1
checks:
- context: 'Release Drafter'
url: 'https://go.to/detail'
description:
success: 'Ready for review & merge.'
failure: 'Missing labels for release.'
labels:
any:
- feat
- fix
- chore
- docs
version: v1
checks:
- context: 'Merge check'
description: 'Labels for merge.'
labels:
any: ['reviewed', 'size:s']
all: ['app']
version: v1
checks:
- context: 'Merge check'
description: "Disable merging when 'DO NOT MERGE' label is set"
labels:
none: ['DO NOT MERGE']
There are so many labelers why create another? 😧
- I want a lightweight labeler written in TypeScript so that it doesn't have to build a docker image every time it runs.
- I want a simple match first append based multi-labeler without it being a turing complete solution.
- I want to write my rules with
.github/labeler.yml
for a single source of label truth. - I don't want it to do anything else, labels only.
- Assume you are using GitHub branch protection (labels only).
- I want to run this in PR triage before everything else (labels only).
- Chain this action with another action; this should just be for (labels only).