srvaroa / labeler

Label manager for PRs and Issues based on configurable conditions
https://github.com/srvaroa/labeler
MIT License
83 stars 39 forks source link
actions automation codereview github github-actions go golang issues labels labels-generator project-management pull-requests

Label manager for PRs and issues based on configurable conditions

labeler release (latest SemVer) sponsor the project!

Implements an all-in-one GitHub Action that can manage multiple labels for both Pull Requests and Issues using configurable matching rules. Available conditions:

Sponsors

Please consider supporting the project if your organization finds it useful, you can do this through GitHub Sponsors. Sponsorships also help speed up bug fixes or new features.

Thanks to Launchgood and others that preferred to remain private for supporting this project!

Installing

The action is configured by adding a file .github/labeler.yml (which you can override). The file contains matching rules expanded in the Configuration section below.

The action will strive to maintain backwards compatibility with older configuration versions. It is nevertheless encouraged to update your configuration files to benefit from newer features. Please follow our releases page to stay up to date.

GitHub Enterprise support

Add GITHUB_API_HOST to your env variables, it should be in the form http(s)://[hostname]/

Please consider sponsoring the project if you're using Labeler in your organization!

How to trigger action

To trigger the action on events, add a file .github/workflows/main.yml to your repository:

name: Label PRs

on:
- pull_request
- issues

jobs:
  build:

    runs-on: ubuntu-latest

    steps:
    - uses: srvaroa/labeler@master
      env:
        GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}"

Using @master will run the latest available release. Feel free to pin this to a specific version from the releases page. We also maintain a floating tag on the major v1. This gets updated whenever a new minor/patch v1.x.y version is released.

Use the on clause to control when to run it.

You may combine multiple event triggers.

A final option is to trigger the action periodically using the schedule trigger. For backwards compatibility reasons this will examine all active pull requests and update their labels. If you wish to examine issues as well, you'll need to explicitly add the issues flag in your config file:

version: 1
issues: True
labels:
- label: "WIP"
  title: "^WIP:.*"

Advanced action settings

Please refer to the action.yml file in the repository for the available inputs to the action. Below is an example using all of them:

name: Label PRs

on:
- pull_request
- issues

jobs:
  build:

    runs-on: ubuntu-latest

    steps:

    - name: Checkout your code
      uses: actions/checkout@v3

    - uses: srvaroa/labeler@master
      with:
        config_path: .github/labeler.yml
        use_local_config: false
        fail_on_error: false
      env:
        GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}"

Use config_path to provide an alternative path for the configuration file for the action. The default is .github/labeler.yml.

Use use_local_config to chose where to read the config file from. By default, the action will read the file from the default branch of your repository. If you set use_local_config to true, then the action will read the config file from the local checkout. Note that you may need to checkout your branch before the action runs!

Use fail_on_error to decide whether an error in the action execution should trigger a failure of the workflow. By default it's disabled to prevent the action from disrupting CI pipelines.

Troubleshooting

To avoid blocking CI pipelines, the action will never return an error code and just log information about the problem. Typical errors are related to non-existing configuration file or invalid yaml.

Configuring matching rules

Configuration can be stored at .github/labeler.yml as a plain list of label matchers, which consist of a label and a set of conditions for each. When all conditions for a label match, then the Action will set the given label. When any condition for a label does not match, then the Action will unset the given label.

All matchers follow this configuration pattern:

<label>: "MyLabel"
<condition_name>: <condition_parameters>
<condition_name>: <condition_parameters>

For example, this .github/labeler.yml contains a single matcher with a single condition:

version: 1
labels:
- label: "WIP"
  title: "^WIP:.*"

A PR or issue with title "WIP: this is work in progress" would be labelled as WIP. If the title changes to "This is done", then the WIP label would be removed.

Each label may combine multiple conditions. The action combines all conditions with an AND operation. That is, the label will be applied if all conditions are satisfied, removed otherwise.

For example, given this .github/labeler.yml:

version: 1
labels:
- label: "WIP"
  title: "^WIP:.*"
  mergeable: false

A pull request with title "WIP: this is work in progress" and not in a mergeable state would be labelled as WIP. If the title changes to "This is done", or it becomes mergeable, then the WIP label would be removed.

If you wish to apply an OR, you may set multiple matchers for the same label. For example:

version: 1
labels:
- label: "WIP"
  title: "^WIP:.*"
- label: "WIP"
  mergeable: false

The WIP label will be set if the title matches ^WIP:.* OR the label is not in a mergeable state.

Negate rules

Adding a negate property inside the label block will negate the result of the evaluation of all conditions inside the label. For example:

version: 1
labels:
- label: "unknown"
  negate: True
  branch: "(master|hotfix)"

In this case, label unknown will be set if the branch does NOT match master or hotfix.

The same behaviour occurs with multiple conditions:

version: 1
labels:
- label: "unknown"
  negate: True
  branch: "master"
  title: "(feat).*"

Only PRs that do NOT match one of the two conditions will get the unknown label.

Append-only mode

The default behaviour of this action includes removing labels that have a rule configured that does not match anymore. For example, given this configuration:

version: 1
labels:
- label: "WIP"
  title: "^WIP:.*"

A PR or issue with title 'WIP: my feature' will get the WIP label.

Now the title changes to My feature the label will get remove. This is because the labeler configuration includes the WIP label, and its rule does not match anymore.

In some cases you would prefer that the action adds labels, but never removes them regardless of the matching status. To achieve this you can enable the appendOnly flag.

version: 1
appendOnly: true
labels:
- label: "WIP"
  title: "^WIP:.*"

With this config, the behaviour changes:

Conditions

Below are the conditions currently supported in label matchers, in alphabetical order. Some important considerations:

Age (PRs and Issues)

This condition evaluates the creation date of the PR or Issue.

If you're looking to evaluate on the modification date of the issue or PR, check on

This condition is best used when with a schedule trigger.

Examples:

age-range:
  at-most: 1d

Will label PRs or issues that were created at most one day ago.

age-range:
  at-least: 1w

Will label PRs or issues that were created at least one week ago.

The syntax for values is based on a number, followed by a suffix:

For example, 2d means 2 days, 4w means 4 weeks, and so on.

Author can merge (PRs)

This condition is satisfied when the author of the PR can merge it. This is implemented by checking if the author is an owner of the repo.

author-can-merge: True

Author is member (PRs and Issues)

This condition is satisfied when the author of the PR is an active member of the given team (identified by its url slug).

author-in-team: core-team

Authors (PRs and Issues)

This condition is satisfied when the author of the PR or Issue matches any of the given usernames.

authors: ["serubin"]

Base branch (PRs only)

This condition is satisfied when the PR base branch matches on the given regex.

base-branch: "master"

Body (PRs and Issues)

This condition is satisfied when the body (description) matches on the given regex.

body: "^patch.*"

Branch (PRs only)

This condition is satisfied when the PR branch matches on the given regex.

branch: "^feature/.*"

Draft status (PRs only)

This condition is satisfied when the PR draft state matches that of the PR.

draft: True

Matches if the PR is a draft.

draft: False

Matches if the PR is not a draft.

Files affected (PRs only)

This condition is satisfied when any of the PR files matches on the given regexs.

files:
- "cmd\\/.*_tests.go"
- ".*\\/subfolder\\/.*\\.md"

NOTICE the double backslash (\\) in the example above. This GitHub Action is coded in Go (Golang), which means you need to pay special attention to regular expressions (Regex). Special characters need to be escaped with double backslashes. This is because the backslash in Go strings is an escape character and therefore must be escaped itself to appear as a literal in the regex.

Last Modified (PRs and Issues)

This condition evaluates the modification date of the PR or Issue.

If you're looking to evaluate on the creation date of the issue or PR, check on

This condition is best used when with a schedule trigger.

Examples:

last-modified:
  at-most: 1d

Will label PRs or issues that were last modified at most one day ago

last-modified:
  at-least: 1d

Will label PRs or issues that were last modified at least one day ago

The syntax for values is based on a number, followed by a suffix:

For example, 2d means 2 days, 4w means 4 weeks, and so on.

Mergeable status (PRs only)

This condition is satisfied when the mergeable state matches that of the PR.

mergeable: True

Will match if the label is mergeable.

mergeable: False

Will match if the label is not mergeable.

Size (PRs only)

This condition is satisfied when the total number of changed lines in the PR is within given thresholds.

The number of changed lines is calculated as the sum of all additions + deletions in the PR.

For example, given this .github/labeler.yml:

- label: "S"
  size:
      below: 10
- label: "M"
  size:
      above: 9
      below: 100
- label: "L"
  size:
      above: 100

These would be the labels assigned to some PRs, based on their size as reported by the GitHub API.

PR additions deletions Resulting labels
First example 1 1 S
Second example 5 42 M
Third example 68 148 L

You can exclude some files so that their changes are not taken into account for the overall count. This can be useful for yarn.lock, go.sum and such. Use exclude-files, which supports both an explicit file or a Regex expression:

- label: "L"
    size:
        exclude-files: ["yarn.lock", "\\/root\\/.+\\/test.md"]
        above: 100

This condition will apply the L label if the diff is above 100 lines, but NOT taking into account changes in yarn.lock, or any test.md file that is in a subdirectory of root.

NOTICE the double backslash (\\) in the example above. This GitHub Action is coded in Go (Golang), which means you need to pay special attention to regular expressions (Regex). Special characters need to be escaped with double backslashes. This is because the backslash in Go strings is an escape character and therefore must be escaped itself to appear as a literal in the regex.

NOTICE the old format for specifying size properties (size-above and size-below) has been deprecated. The action will continue supporting old configs for now, but users are encouraged to migrate to the new configuration schema.

Title

This condition is satisfied when the title matches on the given regex.

title: "^WIP:.*"

Type

By setting the type attribute in your label configuration, you can specify whether a rule applies exclusively to Pull Requests (PRs) or Issues. This allows for more precise label management based on the type of GitHub record. The type condition accepts one of two values:

  • pull_request
  • issue

This functionality increases the adaptability of this GitHub Action, allowing users to create more tailored labeling strategies that differentiate between PRs and Issues or apply universally to both.

Pull-Request Only:

- label: "needs review"
  type: "pull_request"
  name: ".*bug.*"

This rule applies the label "needs review" to Pull Requests with "bug" in the title.

Issue Only:

- label: "needs triage"
  type: "issue"
  name: ".*bug.*"

This rule applies the label "needs triage" to Issues with "bug" in the title.