Giter Club home page Giter Club logo

label-bot's Introduction

Discord Build License

Label Bot

Overview

This is a GitHub app for performing label related actions in a repository. It is written by and used in projects for @facelessuser. It uses the the persona of @gir-bot, but can technically use any user. Label Bot is not a publicly available service, but can be modified and installed for personal use in Heroku or some other hosting service. Currently running and tested on Python 3.10.6.

Label bot handles a handful of label related scenarios:

  • Label Bot can manage labels by syncing them up with a list specified in a configuration file. If the configuration file changes, labels will be added, edited, or removed (if enabled) from your repository to match the configuration. This modifies the global issue list for your repository.
  • Label Bot can mark new issues with a specific labels. For instance, out of the box, it marks new issues with triage. It can also remove labels if desired.
  • Label Bot can mark new pull requests and pushes to a pull requests with specific labels. For instance, out of the box, it will mark new pull requests and new pushes to the pull request with needs-review. It can also remove remove labels if desired. This can come in handy if you've (for example) added an approved label and more changes were pushed, it could remove the approved label, and then add needs-review.
  • Label Bot will mark pull requests as pending if certain labels are present. By default it looks for things like: work-in-progress, wip, etc.
  • Label Bot can tag a pull requests with additional labels based on glob patterns. If a file matches a glob pattern, it is assigned the associated label(s).
  • Label Bot also exposes commands to retrigger tasks, sync labels, and other specialty label related commands.

Can I Use It?

Sure, you'll need to fork it and deploy it on Heroku, or host it somewhere else if desired. There is no publicly available bot on the marketplace.

  1. Make sure to set the GH_BOT environmental variable in your environment. GH_BOT should be the name of the GitHub user the bot is operating as.

  2. Also make sure you set GH_AUTH variable which is the access token by which the bot user is authenticated. Normally repo privileges are sufficient. Learn how to setup an access token by checking out the documentation.

  3. Optionally, set up GH_BOT_LINK which will link to whatever you specify when you click the "details" associated with the status of the CI event.

  4. Setup a webhook in your repository. Point the URL to your running app. Ensure it sends data via JSON. Use a token with high entropy and make sure it is used by your webhook, but also assigned to GH_SECRET in your app's environmental variables. Lastly, make sure the webhook sends requests for:

    • issues: allows triage labels task to be sent events.
    • push: , allows the repository label sync task to be sent events.
    • pull request: allows the the WIP, review, and pull request auto label task to be sent events.
    • issue comments: allows the ability to retrigger tasks via mentions to the bot through issues.
  5. If you are using a separate bot account to communicate with your repos, you may have to add the bot as a collaborator.

Which Configuration Gets Used?

All commands are run from the configuration file found on master. The only time a local reference would be used to acquire a configuration is in a pull request when the retrigger-local command is used. retrigger-local is only meant for testing a pull request.

Using a Configuration Template

You can use a configuration template file and share it across repositories. This is a good way to define common labels that you wish to reuse. You can set the template to use in your local repository file in .github/labels.yml. In our case it is facelessuser:master-labels:labels.yml:master.

When merging the template configuration and the local repo configuration, merging will occur as follows:

  • keys that contain string or bool will override the template with the local value.
  • keys that contain list values will append the local list to the template list.
  • keys that contain hash values will append the key value pair of the local to the template. In the case of duplicates, the local will override.
  • One exception is with the legacy lgtm_add which is still accepted. It is recommended to use lgtm_add_issue and lgtm_add_pull_request, but if you still use lgtm_add, its sub-keys (pull_request and issue) will append values from the local to the template. In the future, lgtm_add will be removed in favor of lgtm_add_issue and lgtm_add_pull_request. This would not occur until version 2.0.

If either the template or local configuration file fails to be acquired, an empty set of options will be returned. Since repository label syncing will not occur when the labels option is missing, this will prevent all your repository labels from getting wiped out in the case of a failure.

Triage Labels

Label Bot will mark new issue with triage.

If desired, you can control what label gets assigned by adding the following option in .github/labels.yml in your project:

triage_label: triage

If you want to turn off triage, because you are creating the issue and have a good understanding of it, you can attach the skip-triage label. If you prefer to rename it or add additional labels, simply specify a different name(s) using the following option:

triage_skip: [skip-triage]

If you'd like to remove labels when running the command triage as well, you can use the triage_remove option. This is good if you need to but it back in the triage state via a retrigger and reset some labels.

triage_remove: [confirmed]

Review Labels

Label Bot will mark new pull requests with needs-review. It will also re-add the label if it was removed, and more code is pushed.

If desired, you can control what label gets assigned by adding the following option in .github/labels.yml in your project:

review_label: needs-review

If you want to turn off this feature in a pull request, for whatever reason, you can attach the skip-review label. If you prefer to rename it, or add additional labels, simply specify a different name(s) using the following option:

review_skip: [skip-review]

If you'd like to also remove labels, such as approved labels, you can configure the review_remove option and list various labels to remove.

review_remove: [approved]

WIP Labels

Label Bot can mark a pull request as pending if certain labels are present. Simply provide a list in the YAML file at .github/labels.yml to configure it:

wip:
  - work-in-progress
  - needs-review
  - needs-decision
  - needs-confirmation
  - requires-changes
  - rejected

By default, Label Bot looks for one of the following: wip, work in progress, or work-in-progress.

Wildcard Labels

Wildcard labels is a feature that labels pull requests based on file patterns of changed files. It uses the Python library wcmatch to perform the file matching.

By default, wcmatch is configured with the following flags:

  • SPLIT: enables chaining multiple patterns together with | so they are evaluated together. For instance, if we wanted to find all Markdown and HTML files in a folder, we could use the following pattern:

    folder/*.md|folder/*.html
    
  • GLOBSTAR: enables the pattern ** to match zero or more folders. For instance, if we wanted to find Python files under any child folder of a given folder:

    src/**/*.py
    
  • DOTGLOB: enables the matching of . at the start of a file in patterns such as *, **, ? etc. Since this is enabled, we should be able to match files that start with . like .travis.yml by simply using *.

  • NEGATE: allows inverse match patterns by starting a pattern with !. It is meant to filter other normal patterns. For instance if we wanted to find all Python files except those under our tests folder:

    **/*.py|!tests/**
    
  • NEGATEALL: allows using inverse patterns when no normal patterns are given. When an inverse pattern is given with no normal patterns, the pattern of ** is assumed as the normal pattern to filter. So if we wanted find any file accept HTML files:

    !*.html
    

Check out the libraries documentation for more information on syntax.

The configuration file should be in the YAML format and should be found at .github/labels.yml. The rules consist of two parts: flags that control the behavior of the glob patterns, and rules that define patterns of modified files that must match for the associated label to be applied.

There are three global flags that alter the default behavior of the glob patterns:

Flag Description
brace_expansion Allows Bash style brace expansion in patterns: a{b,{c,d}} โ†’ ab ac ad.
extended_glob Enables Bash style extended glob patterns: @(ab|ac|ad), etc.
minus_negate. Enabled by default, MINUSNEGATE changes inverse patterns to use - instead of !. This was to avoid conflicts with the extended glob patterns of !(...). This is no longer an issue. Simply escaping the bracket (!\() will cause the pattern to be treated as an exclusion pattern instead of treating it as an EXTGLOB, and not escaping the bracket (!() will cause it to always be treated as an EXTGLOB pattern, even if it is not a valid EXTGLOB.
case_insensitive As the action is run in a Linux environment, matches are case sensitive by default. This enables case insensitive matching.

Global flags are placed at the top of the configuration file:

case_insensitive: true

rules:
  - labels: [python, code]
    patterns:
    - '**/*.py'
    - '**/*.pyc'

rules should contain a list of patterns coupled with associated to labels to apply. Both the labels key and the patterns key should be lists.

For each entry in a patterns list are handled independently from the other patterns in the list. So if we wanted to augment a normal pattern with an inverse pattern, we should use | on the same line:

rules:
  - labels: [python, code]
    patterns:
    - '**/*.py|!tests'  # Any Python file not under tests

Having these patterns on different lines will not provide the same behavior as they will be evaluated independently.

rules:
  - labels: [python, code]
    patterns:
    - '**/*.py'  # All Python files
    - '!tests'   # Any file not under tests

Label Management

A simple label manager that syncs labels in a YAML at .github/labels.yml on the master branch of your project. Labels are either added if they don't exist, or edited if they do exist and the description or color have changed. Optionally, labels not in the list will be deleted if mode is set to delete (default is normal).

Labels are stored in a list in the configuration file:

labels:
- name: bug
  color: bug
  description: Bug report.

- name: feature
  color: feature
  description: Feature request.

You can also predefine color variables. This is useful if you wish to reuse a color for multiple labels.

colors:
  bug: '#c45b46'
  feature: '#7b17d8'

labels:
- name: bug
  color: bug
  description: Bug report.

- name: feature
  color: feature
  description: Feature request.

You can also specify a label to be renamed. This is useful if you want to change the name of a label that is present on existing issues. Simply create an entry using the the new name, and add the old named under renamed. So if we had a label called bug, and we wanted to add a ๐Ÿ› emoji to the name:

labels:
- name: 'bug :bug:'
  renamed: bug
  color: bug
  description: Bug report.

When delete_labels is set to true, labels not explicitly defined are remove. While you can certainly define those labels so that they are in the list, you can also just add the to the ignore list. Maybe they are labels created by an external process like dependbot. Regardless, if you have existing labels that you do not want to explicitly define, and do not wish to lose them, you can add them to the ignore list:

colors:
  bug: '#c45b46'

ignores:
- dependencies
- security

labels:
- name: bug
  color: bug
  description: Bug report.

- name: feature
  color: feature
  description: Feature request.

Commands

Commands can be initiated in either the issue/pull request body, or comments in an issue/pull request. It is recommended to have bot commands on their own line separated from other content with a new line, but they will be scraped no matter where they are found. They are scraped from the rendered markdown. Commands that apply to open issues will not execute if the issue is closed.

Retrigger

You can force the bot to retrigger checks by commenting in issues. If a task failed for some reason you can rerun by mentioning the bot's name, and then asking it to retrigger:

@bot retrigger auto-labels

If you want to rerun all checks, you can ask it to run all:

@bot retrigger all

Available checks that can be retriggered are: wip, review, triage, and auto-label. triage cannot be run in pull requests, and the other are not run outside of pull requests.

In a pull request, you can force the SHA in the pull request to be used to obtain the configuration file for testing label changes by using retrigger-local instead of retrigger. This is meant only for testing.

Sync

If desired, you can also resync the labels on demand with the following command:

@bot sync labels

This will cause the repository's labels to be synced with the .github/labels.yml file on master.

LGTM

LGTM (looks good to me) is a command that is meant for transitioning an issue into an accepted state. This often means removing labels and maybe even adding new labels. The idea is that by stating the issue "looks good", you are indicating that no additional information is needed to understand the bug or feature request, and in the case of pull requests, that no additional work is needed.

For instance, we may have an issue tagged with triage. Once we've evaluated it and determined that it is descriptive enough, we may want to accept it by removing the triage label.

In the configuration file we simply specify when lgtm is run that we want to remove tags such as triage:

lgtm_remove:
  - triage

Then we can simply run the following command in the issue's comments:

@bot lgtm

Let's say we have a pull request, and we want to clear needs-review label, but also tag it with the label approved. We can simply create the lgtm_remove (which is shared for both pull requests and issues), and then use the lgtm_add_pull_request option to specify the desired labels to add (if specifying for a normal issue, we'd use lgtm_add_issue).

lgtm_remove:
  - needs-review

lgtm_add_pull_request: [approved]

Then when we run @bot lgtm, needs-review will be removed, and approved will be added.

Add and Remove

You can add or remove labels with the commands @bot add label-name or @bot remove label-name. You can specify multiple labels by separating them with comas: @bot add Documents, Core Code.

label-bot's People

Contributors

dependabot-preview[bot] avatar dependabot[bot] avatar facelessuser avatar gir-bot avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

label-bot's Issues

We seem to be suddenly getting this issue. We haven't changed our logic, and maybe we rarely got this before, but now it is happening a lot more. We should look into the why.

Jul 22 19:31:55 gir-label-bot app/web.1 Traceback (most recent call last):
Jul 22 19:31:55 gir-label-bot app/web.1   File "/app/label_bot/__main__.py", line 35, in deferred_commands
Jul 22 19:31:55 gir-label-bot app/web.1     async for cmd in commands.run(event, gh, bot):
Jul 22 19:31:55 gir-label-bot app/web.1   File "/app/label_bot/commands.py", line 171, in run
Jul 22 19:31:55 gir-label-bot app/web.1     comment = await gh.getitem(event.data[etype]['url'], accept=util.HTML_HEADER)
Jul 22 19:31:55 gir-label-bot app/web.1   File "/app/.heroku/python/lib/python3.6/site-packages/gidgethub/abc.py", line 126, in getitem
Jul 22 19:31:55 gir-label-bot app/web.1     "GET", url, url_vars, b"", accept, jwt=jwt, oauth_token=oauth_token
Jul 22 19:31:55 gir-label-bot app/web.1   File "/app/.heroku/python/lib/python3.6/site-packages/gidgethub/abc.py", line 106, in _make_request
Jul 22 19:31:55 gir-label-bot app/web.1     data, self.rate_limit, more = sansio.decipher_response(*response)
Jul 22 19:31:55 gir-label-bot app/web.1   File "/app/.heroku/python/lib/python3.6/site-packages/gidgethub/sansio.py", line 366, in decipher_response
Jul 22 19:31:55 gir-label-bot app/web.1     raise exc_type(*args)
Jul 22 19:31:55 gir-label-bot app/web.1 gidgethub.BadRequest: Not Found

Possibly add commands to bulk add/or remove labels

The idea would be to provide an add and remove command that would read the config and find match the parameters to real labels. If desired, you could define aliases as well for labels that are awkward to enter. We'll probably limit the scanning for certain characters, and if the label has characters outside that range, you would need to define an alias.

This may be useful for simple triage. For instance:

@gir-bot add feature
@gir-bot lgtm

or

@gir-bot remove triage
@gir-bot  add bug, needs-confrimation

@gir-bot lgtm

LGTM command

Add a way so we can say @bot lgtm in an issue, and it will clear any wip, triage, and/or review labels (depending on the issue type).

Optionally, you can say @bot lgtm, [key], where [key] is some user defined key, and appropriate labels will be set.

So, for an issue, I may say

@gir-bot lgtm, confirmed

And it may clear the triage label set the bug label and the confirmed label (as defined by the user).

Or if in a pull request, maybe:

@gir-bot lgtm, approved

And it would clear all the wip and review labels and set the label approved.

If we say:

@gir-bot lgtm

It would simply just remove the appropriate labels.

Allow running commands even when an issue is closed

Commands that run automatically should not run on closed issues, but commands that are initiated by a manual command should still run on a closed issue.

For instance, if we are closing an issue and updated labels via commands in the comment, they should still execute even though the command will be closed by time label commands execute. Also, the manual command should be respected in general, particularly add add remove commands. These are simple commands that add and remove labels.

So maybe not all commands should execute when the issue is closed, but at least add and remove.

@gir-bot add T: feature
@gir-bot lgtm

Clean up code a bit

Clean up the code a bit for easier maintenance. The project came together pretty quick, and I was unfamiliar with projects of this type, so some cleanup needs to happen. Commands in comments (and issue bodies) should be split out into their own file and should be implemented a bit cleaner.

Unit test the code

We probably need to get the code base unit tested. I'm not familiar with unit testing async/await code though, so I need to figure that out.

Use dedicated repo to share label configuration across an org

Storing label definition in a config file on the repo itself is pretty great however there are many instances where like 70% of the labels are strictly the same across repos of a given org by design to enforce convention over common ones (Severity, Priority, Kind, etc..).

It would be great if there was a way to have a dedicated repo to host the master definition which could be complemented at the repo level for specific project need.

Automate installation

Can we easily setup an app scoped just to our username via traditional GitHub app infrastructure?

Something to look into. What we are doing now works, but it requires a bit of manual setup. It would be nice if we could as a repository as easy as it is on the marketplace. But not have to support everyone as a public app.

@gir-bot add maintenance
@gir-bot lgtm

Don't update labels in sync until retrieving all labels from repo

I think I finally figured out why label syncing fails, and it isn't because of rate limit abuse.

We were getting issue 422 which is essentially invalid field, and we would get for the attribute name. This would occur when we were specifically creating labels.

It finally occurred to me that we were paging repo labels while deleting or modifying labels. I realize now that this could cause some labels that would have appeared in the next page to not appear if labels were deleted before retrieving the next page. This is because labels on page X + 1 would now be on page X after the delete.

So why does this cause a 422? Because we missed indexing the label, and we think it needs to be created. So when we create it, it already exists, and so GitHub sends back a 422.

@gir-bot add bug, confirmed
@gir-bot lgtm

App boot timeouts (rarely) in Heroku free

So, we are using the free Heroku server which is not always on. Maybe one day in the future we will change to a different one (maybe through funding via sponsorship), but currently, I don't plan to migrate away from the free solution. Occasionally, we can get app boot timeouts. We were getting them for a time, but they seem to have stopped occurring. I'm not sure if there is anything we can do to help speed up this process and become available faster, but something to look into.

I'm almost certain Heroku had just been having a period of performance issues.

Potentially throttle label sync task more

We are already waiting a second between each API call to keep GitHub from failing our calls, but we still get failures when we are bulk label adding. It only happens when we are setting up a repo for the first time, but we should maybe try and throttle a bit more so we don't have to run it twice. Once a repo is established, you are probably doing minor label changes.

@gir-bot add sync-labels, feature
@gir-bot lgtm

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.