https://github.com/fuxingloh/multi-labeler
Multi labeler for title, body, comments, commit messages, branch, author or files with automated status checks.
https://github.com/fuxingloh/multi-labeler
commits conventional-commits files github-actions github-marketplace multi-labeler pr-description pr-title pull-requests status status-check
Last synced: about 2 months ago
JSON representation
Multi labeler for title, body, comments, commit messages, branch, author or files with automated status checks.
- Host: GitHub
- URL: https://github.com/fuxingloh/multi-labeler
- Owner: fuxingloh
- License: mit
- Created: 2021-01-13T09:32:38.000Z (over 4 years ago)
- Default Branch: main
- Last Pushed: 2025-03-30T14:38:21.000Z (about 2 months ago)
- Last Synced: 2025-04-02T00:49:53.601Z (about 2 months ago)
- Topics: commits, conventional-commits, files, github-actions, github-marketplace, multi-labeler, pr-description, pr-title, pull-requests, status, status-check
- Language: TypeScript
- Homepage:
- Size: 7.02 MB
- Stars: 37
- Watchers: 2
- Forks: 15
- Open Issues: 11
-
Metadata Files:
- Readme: README.md
- License: LICENSE
- Code of conduct: .github/CODE_OF_CONDUCT.md
Awesome Lists containing this project
README
# Multi Labeler
[](https://codecov.io/gh/fuxingloh/multi-labeler)
[](https://www.codefactor.io/repository/github/fuxingloh/multi-labeler)
[](https://github.com/fuxingloh/multi-labeler/releases)
[](https://github.com/fuxingloh/multi-labeler/blob/main/LICENSE)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`?](https://github.com/search?o=desc&q=fuxingloh+%2F+multi-labeler&s=indexed&type=Code)
## Features
- 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## Usage
#### `.github/workflows/labeler.yml`
```yml
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 statusjobs:
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`
```yml
# .github/labeler.ymlversion: 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
```### Examples
Semantic Pull Request
#### `.github/workflow/pr-triage.yml`
```yml
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
```#### `.github/labeler.yml`
```yml
version: v1labels:
- 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
#### `.github/workflow/pr-triage.yml`
```yml
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
```#### `.github/labeler.yml`
```yml
version: v1labels:
- 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
#### `.github/workflow/issue-triage.yml`
```yml
on:
issues:
types: [opened, edited]jobs:
labeler:
name: Labeler
runs-on: ubuntu-latest
steps:
- uses: fuxingloh/multi-labeler@v4
```#### `.github/labeler.yml`
```yml
version: v1labels:
- label: 'bug'
matcher:
body: "(\\n|.)*- \\[x\\] bug(\\n|.)*"
```Comment Triage
#### `.github/workflow/comment-slash.yml`
```yml
on:
issue_comment:
types: [created, edited]jobs:
labeler:
name: Labeler
runs-on: ubuntu-latest
steps:
- uses: fuxingloh/multi-labeler@v4
```#### `.github/labeler.yml`
```yml
version: v1labels:
- label: 'coverage'
matcher:
comment: "# \\[Codecov\\] .*"- label: 'stale'
matcher:
comment: '/stale'
```## Configuration
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 the`config-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.## Matchers
> RegEx matcher requires backslash '\' to be double slashed '\\'. Hence, to match brackets '()' you need a regex of '\\(\\)'. See https://github.com/fuxingloh/multi-labeler/issues/103
### PR/Issue Title: RegEx
```yml
version: v1labels:
- label: 'feat'
matcher:
title: '^feat:.*'
```### PR/Issue Body: RegEx
```yml
version: v1labels:
- label: 'bug'
matcher:
# e.g. '- [x] bug'
body: "(\\n|.)*- \\[x\\] bug(\\n|.)*"
```### PR/Issue Comment: RegEx
```yml
version: v1labels:
- label: 'stale'
matcher:
comment: '/stale'
```### PR Branch: RegEx
```yml
version: v1labels:
- label: 'feat'
matcher:
branch: '^feat/.*'
```### PR Base Branch: RegEx
```yml
version: v1labels:
- label: 'release'
matcher:
baseBranch: '^release/.*'
```### PR Commits: RegEx
Check all commits and find any match, max of 250 commits only.
```yml
version: v1labels:
- label: 'feat'
matcher:
commits: '^feat: .*'
```### PR/Issue Author
Check for pr or issue author match.
```yml
version: v1labels:
- label: 'single'
matcher:
author: 'fuxingloh'
- label: 'any'
matcher:
author:
- adam
- claire
```### PR Files: [Glob Matcher](https://github.com/isaacs/minimatch)
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.#### PR Files Basic
```yml
version: v1labels:
- 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/**']
```#### PR Files Count
```yml
version: v1labels:
- 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
```#### PR Files Any & All
```yml
version: v1labels:
- label: 'ci'
sync: true
matcher:
files:
any: ['.github/workflow/**', '.circleci/**']
all: ['!app/**']- label: 'attention'
sync: true
matcher:
files:
any: ['app/**']
count:
neq: 1
```### PR Status Checks
#### PR Check any
```yml
version: v1checks:
- 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
```#### PR Check any + all
```yml
version: v1checks:
- context: 'Merge check'
description: 'Labels for merge.'
labels:
any: ['reviewed', 'size:s']
all: ['app']
```#### PR Check none
```yml
version: v1checks:
- context: 'Merge check'
description: "Disable merging when 'DO NOT MERGE' label is set"
labels:
none: ['DO NOT MERGE']
```## Why?
> There are so many labelers why create another? 😧
1. I want a lightweight labeler written in TypeScript so that it doesn't have to build a docker image every time it runs.
2. I want a simple match first append based multi-labeler without it being a turing complete solution.
3. I want to write my rules with `.github/labeler.yml` for a single source of label truth.
4. I don't want it to do anything else, labels only.
1. Assume you are using GitHub branch protection (labels only).
2. I want to run this in PR triage before everything else (labels only).
3. Chain this action with another action; this should just be for (labels only).