mirror of
https://github.com/Cog-Creators/Red-DiscordBot.git
synced 2025-11-06 11:18:54 -05:00
Revamp of automatically applied PR labels (#5954)
Co-authored-by: Jakub Kuczys <6032823+jack1142@users.noreply.github.com>
This commit is contained in:
parent
7e7d5322b7
commit
6c32ff58e4
391
.github/labeler.yml
vendored
391
.github/labeler.yml
vendored
@ -1,188 +1,319 @@
|
|||||||
"Category: Admin":
|
"Category: CI":
|
||||||
|
- .github/workflows/**/*
|
||||||
|
|
||||||
|
|
||||||
|
"Category: Cogs - Admin":
|
||||||
# Source
|
# Source
|
||||||
- redbot/cogs/admin/*
|
- redbot/cogs/admin/*
|
||||||
# Docs
|
# Docs
|
||||||
- docs/cog_guides/admin.rst
|
- docs/cog_guides/admin.rst
|
||||||
"Category: Alias":
|
- docs/.resources/admin/**/*
|
||||||
|
"Category: Cogs - Alias":
|
||||||
# Source
|
# Source
|
||||||
- redbot/cogs/alias/*
|
- redbot/cogs/alias/*
|
||||||
# Docs
|
# Docs
|
||||||
- docs/cog_guides/alias.rst
|
- docs/cog_guides/alias.rst
|
||||||
"Category: Audio Cog":
|
# Tests
|
||||||
|
- redbot/pytest/alias.py
|
||||||
|
- tests/cogs/test_alias.py
|
||||||
|
- docs/.resources/alias/**/*
|
||||||
|
"Category: Cogs - Audio":
|
||||||
|
# Source
|
||||||
- any:
|
- any:
|
||||||
# Source
|
|
||||||
- redbot/cogs/audio/**/*
|
- redbot/cogs/audio/**/*
|
||||||
# Docs
|
|
||||||
- docs/cog_guides/audio.rst
|
|
||||||
all:
|
|
||||||
- "!redbot/cogs/audio/**/locales/*"
|
- "!redbot/cogs/audio/**/locales/*"
|
||||||
"Category: Bank API":
|
|
||||||
# Source
|
|
||||||
- redbot/core/bank.py
|
|
||||||
# Docs
|
# Docs
|
||||||
- docs/framework_bank.rst
|
- docs/cog_guides/audio.rst
|
||||||
"Category: Bot Core":
|
"Category: Cogs - Bank": [] # historical label for a removed cog
|
||||||
# Source
|
"Category: Cogs - Cleanup":
|
||||||
- redbot/*
|
|
||||||
- redbot/core/__init__.py
|
|
||||||
- redbot/core/_debuginfo.py
|
|
||||||
- redbot/core/_diagnoser.py
|
|
||||||
- redbot/core/_sharedlibdeprecation.py
|
|
||||||
- redbot/core/bot.py
|
|
||||||
- redbot/core/checks.py
|
|
||||||
- redbot/core/cli.py
|
|
||||||
- redbot/core/cog_manager.py
|
|
||||||
- redbot/core/core_commands.py
|
|
||||||
- redbot/core/data_manager.py
|
|
||||||
- redbot/core/errors.py
|
|
||||||
- redbot/core/events.py
|
|
||||||
- redbot/core/global_checks.py
|
|
||||||
- redbot/core/settings_caches.py
|
|
||||||
# Docs
|
|
||||||
- docs/framework_apikeys.rst
|
|
||||||
- docs/framework_bot.rst
|
|
||||||
- docs/framework_cogmanager.rst
|
|
||||||
- docs/framework_datamanager.rst
|
|
||||||
- docs/framework_events.rst
|
|
||||||
- docs/cog_guides/cog_manager_ui.rst
|
|
||||||
- docs/cog_guides/core.rst
|
|
||||||
"Category: CI":
|
|
||||||
- .github/workflows/*
|
|
||||||
"Category: Cleanup Cog":
|
|
||||||
# Source
|
# Source
|
||||||
- redbot/cogs/cleanup/*
|
- redbot/cogs/cleanup/*
|
||||||
# Docs
|
# Docs
|
||||||
- docs/cog_guides/cleanup.rst
|
- docs/cog_guides/cleanup.rst
|
||||||
"Category: Command Module":
|
"Category: Cogs - CustomCommands":
|
||||||
# Source
|
|
||||||
- any:
|
|
||||||
# Source
|
|
||||||
- redbot/core/commands/*
|
|
||||||
# Docs
|
|
||||||
- docs/framework_checks.rst
|
|
||||||
- docs/framework_commands.rst
|
|
||||||
all:
|
|
||||||
- "!redbot/core/commands/help.py"
|
|
||||||
"Category: Config":
|
|
||||||
# Source
|
|
||||||
- redbot/core/drivers/*
|
|
||||||
- redbot/core/config.py
|
|
||||||
# Docs
|
|
||||||
- docs/framework_config.rst
|
|
||||||
"Category: CustomCom":
|
|
||||||
# Source
|
# Source
|
||||||
- redbot/cogs/customcom/*
|
- redbot/cogs/customcom/*
|
||||||
# Docs
|
# Docs
|
||||||
- docs/cog_customcom.rst
|
- docs/cog_customcom.rst
|
||||||
- docs/cog_guides/customcommands.rst
|
- docs/cog_guides/customcommands.rst
|
||||||
"Category: Dev Cog":
|
"Category: Cogs - Dev":
|
||||||
# Source
|
# Source
|
||||||
- redbot/core/dev_commands.py
|
- redbot/core/dev_commands.py
|
||||||
# Docs
|
# Docs
|
||||||
- docs/cog_guides/dev.rst
|
- docs/cog_guides/dev.rst
|
||||||
"Category: Docs":
|
"Category: Cogs - Downloader":
|
||||||
- docs/**/*
|
|
||||||
"Category: Downloader":
|
|
||||||
# Source
|
# Source
|
||||||
- redbot/cogs/downloader/*
|
- redbot/cogs/downloader/*
|
||||||
# Docs
|
# Docs
|
||||||
- docs/cog_guides/downloader.rst
|
- docs/cog_guides/downloader.rst
|
||||||
"Category: Economy Cog":
|
# Tests
|
||||||
|
- redbot/pytest/downloader.py
|
||||||
|
- redbot/pytest/downloader_testrepo.*
|
||||||
|
- tests/cogs/downloader/**/*
|
||||||
|
"Category: Cogs - Economy":
|
||||||
# Source
|
# Source
|
||||||
- redbot/cogs/economy/*
|
- redbot/cogs/economy/*
|
||||||
# Docs
|
# Docs
|
||||||
- docs/cog_guides/economy.rst
|
- docs/cog_guides/economy.rst
|
||||||
"Category: Filter":
|
# Tests
|
||||||
|
- redbot/pytest/economy.py
|
||||||
|
- tests/cogs/test_economy.py
|
||||||
|
"Category: Cogs - Filter":
|
||||||
# Source
|
# Source
|
||||||
- redbot/cogs/filter/*
|
- redbot/cogs/filter/*
|
||||||
# Docs
|
# Docs
|
||||||
- docs/cog_guides/filter.rst
|
- docs/cog_guides/filter.rst
|
||||||
"Category: General Cog":
|
"Category: Cogs - General":
|
||||||
# Source
|
# Source
|
||||||
- redbot/cogs/general/*
|
- redbot/cogs/general/*
|
||||||
# Docs
|
# Docs
|
||||||
- docs/cog_guides/general.rst
|
- docs/cog_guides/general.rst
|
||||||
"Category: Help":
|
"Category: Cogs - Image":
|
||||||
|
# Source
|
||||||
|
- redbot/cogs/image/*
|
||||||
|
# Docs
|
||||||
|
- docs/cog_guides/image.rst
|
||||||
|
"Category: Cogs - Mod":
|
||||||
|
# Source
|
||||||
|
- redbot/cogs/mod/*
|
||||||
|
# Docs
|
||||||
|
- docs/cog_guides/mod.rst
|
||||||
|
# Tests
|
||||||
|
- redbot/pytest/mod.py
|
||||||
|
- tests/cogs/test_mod.py
|
||||||
|
"Category: Cogs - Modlog":
|
||||||
|
# Source
|
||||||
|
- redbot/cogs/modlog/*
|
||||||
|
# Docs
|
||||||
|
- docs/cog_guides/modlog.rst
|
||||||
|
"Category: Cogs - Mutes":
|
||||||
|
# Source
|
||||||
|
- redbot/cogs/mutes/*
|
||||||
|
# Docs
|
||||||
|
- docs/cog_guides/mutes.rst
|
||||||
|
"Category: Cogs - Permissions":
|
||||||
|
# Source
|
||||||
|
- redbot/cogs/permissions/*
|
||||||
|
# Docs
|
||||||
|
- docs/cog_guides/permissions.rst
|
||||||
|
- docs/cog_permissions.rst
|
||||||
|
# Tests
|
||||||
|
- redbot/pytest/permissions.py
|
||||||
|
- tests/cogs/test_permissions.py
|
||||||
|
"Category: Cogs - Reports":
|
||||||
|
# Source
|
||||||
|
- redbot/cogs/reports/*
|
||||||
|
# Docs
|
||||||
|
- docs/cog_guides/reports.rst
|
||||||
|
"Category: Cogs - Streams":
|
||||||
|
# Source
|
||||||
|
- redbot/cogs/streams/*
|
||||||
|
# Docs
|
||||||
|
- docs/cog_guides/streams.rst
|
||||||
|
"Category: Cogs - Trivia":
|
||||||
|
# Source
|
||||||
|
- redbot/cogs/trivia/*
|
||||||
|
# Docs
|
||||||
|
- docs/cog_guides/trivia.rst
|
||||||
|
- docs/guide_trivia_list_creation.rst
|
||||||
|
- docs/.resources/trivia/**/*
|
||||||
|
# Tests
|
||||||
|
- tests/cogs/test_trivia.py
|
||||||
|
"Category: Cogs - Trivia - Lists":
|
||||||
|
- redbot/cogs/trivia/data/lists/*
|
||||||
|
"Category: Cogs - Warnings":
|
||||||
|
# Source
|
||||||
|
- redbot/cogs/warnings/*
|
||||||
|
# Docs
|
||||||
|
- docs/cog_guides/warnings.rst
|
||||||
|
|
||||||
|
|
||||||
|
"Category: Core - API - Audio": [] # potential future feature
|
||||||
|
"Category: Core - API - Bank":
|
||||||
|
# Source
|
||||||
|
- redbot/core/bank.py
|
||||||
|
# Docs
|
||||||
|
- docs/framework_bank.rst
|
||||||
|
"Category: Core - API - Commands Package":
|
||||||
|
# Source
|
||||||
|
- any:
|
||||||
|
- redbot/core/commands/*
|
||||||
|
- "!redbot/core/commands/help.py"
|
||||||
|
# this isn't in commands package but it just re-exports things from it
|
||||||
|
- redbot/core/checks.py
|
||||||
|
# Docs
|
||||||
|
- docs/framework_checks.rst
|
||||||
|
- docs/framework_commands.rst
|
||||||
|
# Tests
|
||||||
|
- tests/core/test_commands.py
|
||||||
|
"Category: Core - API - Config":
|
||||||
|
# Source
|
||||||
|
- any:
|
||||||
|
- redbot/core/drivers/**/*
|
||||||
|
- "!redbot/core/drivers/**/locales/*"
|
||||||
|
- redbot/core/config.py
|
||||||
|
# Docs
|
||||||
|
- docs/framework_config.rst
|
||||||
|
# Tests
|
||||||
|
- tests/core/test_config.py
|
||||||
|
"Category: Core - API - Other":
|
||||||
|
# Source
|
||||||
|
- redbot/__init__.py
|
||||||
|
- redbot/core/__init__.py
|
||||||
|
- redbot/core/cog_manager.py # TODO: privatize cog manager module
|
||||||
|
- redbot/core/data_manager.py
|
||||||
|
- redbot/core/errors.py
|
||||||
|
# Docs
|
||||||
|
- docs/framework_cogmanager.rst # TODO: privatize cog manager module
|
||||||
|
- docs/framework_datamanager.rst
|
||||||
|
# Tests
|
||||||
|
- redbot/pytest/cog_manager.py # TODO: privatize cog manager module
|
||||||
|
- redbot/pytest/data_manager.py
|
||||||
|
- tests/core/test_cog_manager.py
|
||||||
|
- tests/core/test_data_manager.py
|
||||||
|
- tests/core/test_version.py
|
||||||
|
"Category: Core - API - Utils Package":
|
||||||
|
# Source
|
||||||
|
- any:
|
||||||
|
- redbot/core/utils/*
|
||||||
|
- "!redbot/core/utils/_internal_utils.py"
|
||||||
|
# Docs
|
||||||
|
- docs/framework_utils.rst
|
||||||
|
# Tests
|
||||||
|
- tests/core/test_utils.py
|
||||||
|
"Category: Core - Bot Class":
|
||||||
|
# Source
|
||||||
|
- redbot/core/bot.py
|
||||||
|
# Docs
|
||||||
|
- docs/framework_apikeys.rst
|
||||||
|
- docs/framework_bot.rst
|
||||||
|
"Category: Core - Bot Commands":
|
||||||
|
# Source
|
||||||
|
- redbot/core/core_commands.py
|
||||||
|
- redbot/core/_diagnoser.py
|
||||||
|
# Docs
|
||||||
|
- docs/.resources/cog_manager_ui/**/*
|
||||||
|
- docs/cog_guides/cog_manager_ui.rst
|
||||||
|
- docs/cog_guides/core.rst
|
||||||
|
"Category: Core - Command-line Interfaces":
|
||||||
|
- redbot/__main__.py
|
||||||
|
- redbot/launcher.py
|
||||||
|
- redbot/logging.py
|
||||||
|
- redbot/core/_debuginfo.py
|
||||||
|
- redbot/core/cli.py
|
||||||
|
- redbot/setup.py
|
||||||
|
"Category: Core - Help":
|
||||||
- redbot/core/commands/help.py
|
- redbot/core/commands/help.py
|
||||||
"Category: i18n":
|
"Category: Core - i18n":
|
||||||
# Source
|
# Source
|
||||||
- redbot/core/i18n.py
|
- redbot/core/i18n.py
|
||||||
# Locale files
|
# Locale files
|
||||||
- redbot/**/locales/*
|
- redbot/**/locales/*
|
||||||
# Docs
|
# Docs
|
||||||
- docs/framework_i18n.rst
|
- docs/framework_i18n.rst
|
||||||
"Category: Image":
|
"Category: Core - Modlog":
|
||||||
# Source
|
|
||||||
- redbot/cogs/image/*
|
|
||||||
# Docs
|
|
||||||
- docs/cog_guides/image.rst
|
|
||||||
"Category: Meta":
|
|
||||||
- ./*
|
|
||||||
- .github/*
|
|
||||||
- .github/ISSUE_TEMPLATE/*
|
|
||||||
- .github/PULL_REQUEST_TEMPLATE/*
|
|
||||||
- schema/*
|
|
||||||
- tools/*
|
|
||||||
"Category: Mod Cog":
|
|
||||||
# Source
|
|
||||||
- redbot/cogs/mod/*
|
|
||||||
# Docs
|
|
||||||
- docs/cog_guides/mod.rst
|
|
||||||
"Category: Modlog API":
|
|
||||||
# Source
|
# Source
|
||||||
- redbot/core/generic_casetypes.py
|
- redbot/core/generic_casetypes.py
|
||||||
- redbot/core/modlog.py
|
- redbot/core/modlog.py
|
||||||
# Docs
|
# Docs
|
||||||
- docs/framework_modlog.rst
|
- docs/framework_modlog.rst
|
||||||
"Category: Modlog Cog":
|
"Category: Core - Other Internals":
|
||||||
# Source
|
# Source
|
||||||
- redbot/cogs/modlog/*
|
- redbot/core/_sharedlibdeprecation.py
|
||||||
# Docs
|
- redbot/core/events.py
|
||||||
- docs/cog_guides/modlog.rst
|
- redbot/core/global_checks.py
|
||||||
"Category: Mutes Cog":
|
- redbot/core/settings_caches.py
|
||||||
# Source
|
- redbot/core/utils/_internal_utils.py
|
||||||
- redbot/cogs/mutes/*
|
# Tests
|
||||||
# Docs
|
- redbot/pytest/__init__.py
|
||||||
- docs/cog_guides/mutes.rst
|
- redbot/pytest/core.py
|
||||||
"Category: Permissions":
|
- tests/core/test_installation.py
|
||||||
# Source
|
"Category: Core - RPC/ZMQ":
|
||||||
- redbot/cogs/permissions/*
|
|
||||||
# Docs
|
|
||||||
- docs/cog_guides/permissions.rst
|
|
||||||
- docs/cog_permissions.rst
|
|
||||||
"Category: Reports Cog":
|
|
||||||
# Source
|
|
||||||
- redbot/cogs/reports/*
|
|
||||||
# Docs
|
|
||||||
- docs/cog_guides/reports.rst
|
|
||||||
"Category: RPC/ZMQ API":
|
|
||||||
# Source
|
# Source
|
||||||
- redbot/core/rpc.py
|
- redbot/core/rpc.py
|
||||||
# Docs
|
# Docs
|
||||||
- docs/framework_rpc.rst
|
- docs/framework_rpc.rst
|
||||||
"Category: Streams":
|
# Tests
|
||||||
# Source
|
- redbot/pytest/rpc.py
|
||||||
- redbot/cogs/streams/*
|
- tests/core/test_rpc.py
|
||||||
# Docs
|
- tests/rpc_test.html
|
||||||
- docs/cog_guides/streams.rst
|
|
||||||
"Category: Tests":
|
|
||||||
- redbot/pytest/*
|
"Category: Docker": [] # potential future feature
|
||||||
- tests/**/*
|
|
||||||
"Category: Trivia Cog":
|
|
||||||
# Source
|
"Category: Docs - Changelogs":
|
||||||
- redbot/cogs/trivia/*
|
- docs/changelog_*.rst
|
||||||
# Docs
|
- docs/release_notes_*.rst
|
||||||
- docs/cog_guides/trivia.rst
|
"Category: Docs - For Developers":
|
||||||
- docs/guide_trivia_list_creation.rst
|
- docs/framework_events.rst
|
||||||
"Category: Trivia Lists":
|
- docs/guide_cog_creation.rst
|
||||||
- redbot/cogs/trivia/data/lists/*
|
- docs/guide_cog_creators.rst
|
||||||
"Category: Utility Functions":
|
- docs/guide_migration.rst
|
||||||
# Source
|
- docs/guide_publish_cogs.rst
|
||||||
- redbot/core/utils/*
|
"Category: Docs - Install Guides":
|
||||||
# Docs
|
- docs/about_venv.rst
|
||||||
- docs/framework_utils.rst
|
- docs/autostart_*.rst
|
||||||
"Category: Warnings":
|
- docs/.resources/bot-guide/**/*
|
||||||
# Source
|
- docs/bot_application_guide.rst
|
||||||
- redbot/cogs/warnings/*
|
- docs/install_guides/**/*
|
||||||
# Docs
|
- docs/update_red.rst
|
||||||
- docs/cog_guides/warnings.rst
|
"Category: Docs - Other":
|
||||||
|
- docs/host-list.rst
|
||||||
|
- docs/index.rst
|
||||||
|
- docs/version_guarantees.rst
|
||||||
|
- README.md
|
||||||
|
"Category: Docs - User Guides":
|
||||||
|
- docs/getting_started.rst
|
||||||
|
- docs/intents.rst
|
||||||
|
- docs/red_core_data_statement.rst
|
||||||
|
# TODO: move these to `docs/.resources/getting_started` subfolder
|
||||||
|
- docs/.resources/red-console.png
|
||||||
|
- docs/.resources/code-grant.png
|
||||||
|
- docs/.resources/instances-ssh-button.png
|
||||||
|
- docs/.resources/ssh-output.png
|
||||||
|
|
||||||
|
|
||||||
|
"Category: Meta":
|
||||||
|
# top-level files
|
||||||
|
- any:
|
||||||
|
- '*'
|
||||||
|
- '!README.md'
|
||||||
|
# .gitattributes files
|
||||||
|
- '**/.gitattributes'
|
||||||
|
# GitHub configuration files, with the exception of CI configuration
|
||||||
|
- .github/*
|
||||||
|
- .github/ISSUE_TEMPLATE/*
|
||||||
|
- .github/PULL_REQUEST_TEMPLATE/*
|
||||||
|
# documentation configuration, extensions, scripts, templates, etc.
|
||||||
|
- docs/conf.py
|
||||||
|
- docs/_ext/**/*
|
||||||
|
- docs/_html/**/*
|
||||||
|
- docs/make.bat
|
||||||
|
- docs/Makefile
|
||||||
|
- docs/prolog.txt
|
||||||
|
- docs/_templates/**/*
|
||||||
|
# empty file
|
||||||
|
- redbot/cogs/__init__.py
|
||||||
|
# can't go more meta than that :)
|
||||||
|
# TODO: remove this useless file
|
||||||
|
- redbot/meta.py
|
||||||
|
# py.typed file
|
||||||
|
- redbot/py.typed
|
||||||
|
# requirements files
|
||||||
|
- requirements/*
|
||||||
|
# schema files
|
||||||
|
- schema/*
|
||||||
|
# tests configuration, global fixtures, etc.
|
||||||
|
- tests/conftest.py
|
||||||
|
- tests/__init__.py
|
||||||
|
- tests/*/__init__.py
|
||||||
|
# repository tools
|
||||||
|
- tools/*
|
||||||
|
|
||||||
|
|
||||||
|
# "Category: RPC/ZMQ methods": [] # can't be matched by file patterns
|
||||||
|
|
||||||
|
|
||||||
|
"Category: Vendored Packages":
|
||||||
|
- redbot/vendored/**/*
|
||||||
|
|||||||
3
.github/workflows/auto_labeler_issues.yml
vendored
3
.github/workflows/auto_labeler_issues.yml
vendored
@ -7,8 +7,7 @@ permissions:
|
|||||||
issues: write
|
issues: write
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build:
|
apply_triage_label_to_issues:
|
||||||
|
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Apply Triage Label
|
- name: Apply Triage Label
|
||||||
|
|||||||
15
.github/workflows/auto_labeler_pr.yml
vendored
15
.github/workflows/auto_labeler_pr.yml
vendored
@ -1,16 +1,27 @@
|
|||||||
name: Auto Labeler - PRs
|
name: Auto Labeler - PRs
|
||||||
on:
|
on:
|
||||||
pull_request_target:
|
pull_request_target:
|
||||||
|
types:
|
||||||
|
- opened
|
||||||
|
- synchronize
|
||||||
|
- reopened
|
||||||
|
- labeled
|
||||||
|
- unlabeled
|
||||||
|
|
||||||
permissions:
|
permissions:
|
||||||
pull-requests: write
|
pull-requests: write
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build:
|
label_pull_requests:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Apply Type Label
|
- name: Apply Type Label
|
||||||
uses: actions/labeler@v4
|
uses: actions/labeler@v4
|
||||||
with:
|
with:
|
||||||
repo-token: "${{ secrets.GITHUB_TOKEN }}"
|
repo-token: "${{ secrets.GITHUB_TOKEN }}"
|
||||||
sync-labels: "" # this is a temporary workaround, see #4844
|
sync-labels: true
|
||||||
|
|
||||||
|
- name: Label documentation-only changes.
|
||||||
|
uses: Jackenmen/label-doconly-changes@v1
|
||||||
|
env:
|
||||||
|
LDC_LABELS: Docs-only
|
||||||
|
|||||||
23
.github/workflows/check_label_pattern_exhaustiveness.yaml
vendored
Normal file
23
.github/workflows/check_label_pattern_exhaustiveness.yaml
vendored
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
name: Check label pattern exhaustiveness
|
||||||
|
on:
|
||||||
|
pull_request:
|
||||||
|
push:
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
check_label_pattern_exhaustiveness:
|
||||||
|
name: Check label pattern exhaustiveness
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout the repository
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
- name: Set up Python
|
||||||
|
uses: actions/setup-python@v4
|
||||||
|
with:
|
||||||
|
python-version: "3.8"
|
||||||
|
- name: Install script's pre-requirements
|
||||||
|
run: |
|
||||||
|
python -m pip install -U pip
|
||||||
|
python -m pip install -U pathspec pyyaml rich
|
||||||
|
- name: Check label pattern exhaustiveness
|
||||||
|
run: |
|
||||||
|
python .github/workflows/scripts/check_label_pattern_exhaustiveness.py
|
||||||
215
.github/workflows/scripts/check_label_pattern_exhaustiveness.py
vendored
Normal file
215
.github/workflows/scripts/check_label_pattern_exhaustiveness.py
vendored
Normal file
@ -0,0 +1,215 @@
|
|||||||
|
import itertools
|
||||||
|
import operator
|
||||||
|
import os
|
||||||
|
import subprocess
|
||||||
|
from pathlib import Path
|
||||||
|
from typing import Any, Dict, Iterable, List, Optional
|
||||||
|
from typing_extensions import Self
|
||||||
|
|
||||||
|
import rich
|
||||||
|
import yaml
|
||||||
|
from rich.console import Console, ConsoleOptions, RenderResult
|
||||||
|
from rich.tree import Tree
|
||||||
|
from pathspec import PathSpec
|
||||||
|
from pathspec.patterns.gitwildmatch import GitWildMatchPattern
|
||||||
|
|
||||||
|
|
||||||
|
ROOT_PATH = Path(__file__).resolve().parents[3]
|
||||||
|
|
||||||
|
|
||||||
|
class Matcher:
|
||||||
|
def __init__(self, *, any: Iterable[str] = (), all: Iterable[str] = ()) -> None:
|
||||||
|
self.any_patterns = tuple(any)
|
||||||
|
self.any_specs = self._get_pathspecs(self.any_patterns)
|
||||||
|
self.all_patterns = tuple(all)
|
||||||
|
self.all_specs = self._get_pathspecs(self.all_patterns)
|
||||||
|
|
||||||
|
def __repr__(self) -> str:
|
||||||
|
return f"Matcher(any={self.any_patterns!r}, all={self.all_patterns!r})"
|
||||||
|
|
||||||
|
def __eq__(self, other: Any) -> bool:
|
||||||
|
if isinstance(other, self.__class__):
|
||||||
|
return (
|
||||||
|
self.any_patterns == other.any_patterns and self.all_patterns == other.all_patterns
|
||||||
|
)
|
||||||
|
return NotImplemented
|
||||||
|
|
||||||
|
def __hash__(self) -> int:
|
||||||
|
return hash((self.any_patterns, self.all_patterns))
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _get_pathspecs(cls, patterns: Iterable[str]) -> List[PathSpec]:
|
||||||
|
return tuple(
|
||||||
|
PathSpec.from_lines(GitWildMatchPattern, cls._get_pattern_lines(pattern))
|
||||||
|
for pattern in patterns
|
||||||
|
)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _get_pattern_lines(pattern: str) -> List[str]:
|
||||||
|
# an approximation of actions/labeler's minimatch globs
|
||||||
|
if pattern.startswith("!"):
|
||||||
|
pattern_lines = ["*", f"!/{pattern[1:]}"]
|
||||||
|
else:
|
||||||
|
pattern_lines = [f"/{pattern}"]
|
||||||
|
if pattern.endswith("*") and "**" not in pattern:
|
||||||
|
pattern_lines.append(f"!/{pattern}/")
|
||||||
|
return pattern_lines
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_label_matchers(cls) -> Dict[str, List[Self]]:
|
||||||
|
with open(ROOT_PATH / ".github/labeler.yml", encoding="utf-8") as fp:
|
||||||
|
label_definitions = yaml.safe_load(fp)
|
||||||
|
label_matchers: Dict[str, List[Matcher]] = {}
|
||||||
|
for label_name, matcher_definitions in label_definitions.items():
|
||||||
|
matchers = label_matchers[label_name] = []
|
||||||
|
for idx, matcher_data in enumerate(matcher_definitions):
|
||||||
|
if isinstance(matcher_data, str):
|
||||||
|
matchers.append(cls(any=[matcher_data]))
|
||||||
|
elif isinstance(matcher_data, dict):
|
||||||
|
matchers.append(
|
||||||
|
cls(any=matcher_data.pop("any", []), all=matcher_data.pop("all", []))
|
||||||
|
)
|
||||||
|
if matcher_data:
|
||||||
|
raise RuntimeError(
|
||||||
|
f"Unexpected keys at index {idx} for label {label_name!r}: "
|
||||||
|
+ ", ".join(map(repr, matcher_data))
|
||||||
|
)
|
||||||
|
elif matcher_data is not None:
|
||||||
|
raise RuntimeError(f"Unexpected type at index {idx} for label {label_name!r}")
|
||||||
|
|
||||||
|
return label_matchers
|
||||||
|
|
||||||
|
|
||||||
|
class PathNode:
|
||||||
|
def __init__(self, parent_tree: Tree, path: Path, *, label: Optional[str] = None) -> None:
|
||||||
|
self.parent_tree = parent_tree
|
||||||
|
self.path = path
|
||||||
|
self.label = label
|
||||||
|
|
||||||
|
def __rich__(self) -> str:
|
||||||
|
if self.label is not None:
|
||||||
|
return self.label
|
||||||
|
return self.path.name
|
||||||
|
|
||||||
|
|
||||||
|
class DirectoryTree:
|
||||||
|
def __init__(self, label: str) -> None:
|
||||||
|
self.root = Tree(PathNode(Tree(""), Path(), label=label))
|
||||||
|
self._previous = self.root
|
||||||
|
|
||||||
|
def __bool__(self) -> bool:
|
||||||
|
return bool(self.root.children)
|
||||||
|
|
||||||
|
def __rich_console__(self, console: Console, options: ConsoleOptions) -> RenderResult:
|
||||||
|
yield from self.root.__rich_console__(console, options)
|
||||||
|
|
||||||
|
def add(self, file: Path) -> Tree:
|
||||||
|
common_path = Path(os.path.commonpath([file.parent, self._previous.label.path]))
|
||||||
|
|
||||||
|
parent_tree = self._previous
|
||||||
|
while parent_tree != self.root and parent_tree.label.path != common_path:
|
||||||
|
parent_tree = parent_tree.label.parent_tree
|
||||||
|
|
||||||
|
for part in file.relative_to(common_path).parts:
|
||||||
|
if parent_tree.label.path.name == "locales":
|
||||||
|
if not parent_tree.children:
|
||||||
|
parent_tree.add(PathNode(parent_tree, parent_tree.label.path / "*.po"))
|
||||||
|
continue
|
||||||
|
parent_tree = parent_tree.add(PathNode(parent_tree, parent_tree.label.path / part))
|
||||||
|
|
||||||
|
self._previous = parent_tree
|
||||||
|
return parent_tree
|
||||||
|
|
||||||
|
|
||||||
|
class App:
|
||||||
|
def __init__(self) -> None:
|
||||||
|
self.exit_code = 0
|
||||||
|
self.label_matchers = Matcher.get_label_matchers()
|
||||||
|
self.tracked_files = [
|
||||||
|
Path(filename)
|
||||||
|
for filename in subprocess.check_output(
|
||||||
|
("git", "ls-tree", "-r", "HEAD", "--name-only"), encoding="utf-8", cwd=ROOT_PATH
|
||||||
|
).splitlines()
|
||||||
|
]
|
||||||
|
self.matches_per_label = {label_name: set() for label_name in self.label_matchers}
|
||||||
|
self.matches_per_file = []
|
||||||
|
self.used_matchers = set()
|
||||||
|
|
||||||
|
def run(self) -> int:
|
||||||
|
old_cwd = os.getcwd()
|
||||||
|
try:
|
||||||
|
os.chdir(ROOT_PATH)
|
||||||
|
self._run()
|
||||||
|
finally:
|
||||||
|
os.chdir(old_cwd)
|
||||||
|
return self.exit_code
|
||||||
|
|
||||||
|
def _run(self) -> None:
|
||||||
|
self._collect_match_information()
|
||||||
|
self._show_matches_per_label()
|
||||||
|
self._show_files_without_labels()
|
||||||
|
self._show_files_with_multiple_labels()
|
||||||
|
self._show_unused_matchers()
|
||||||
|
|
||||||
|
def _collect_match_information(self) -> None:
|
||||||
|
tmp_matches_per_file = {file: [] for file in self.tracked_files}
|
||||||
|
|
||||||
|
for file in self.tracked_files:
|
||||||
|
for label_name, matchers in self.label_matchers.items():
|
||||||
|
matched = False
|
||||||
|
for matcher in matchers:
|
||||||
|
if all(
|
||||||
|
path_spec.match_file(file)
|
||||||
|
for path_spec in itertools.chain(matcher.all_specs, matcher.any_specs)
|
||||||
|
):
|
||||||
|
self.matches_per_label[label_name].add(file)
|
||||||
|
matched = True
|
||||||
|
self.used_matchers.add(matcher)
|
||||||
|
if matched:
|
||||||
|
tmp_matches_per_file[file].append(label_name)
|
||||||
|
|
||||||
|
self.matches_per_file = sorted(tmp_matches_per_file.items(), key=operator.itemgetter(0))
|
||||||
|
|
||||||
|
def _show_matches_per_label(self) -> None:
|
||||||
|
for label_name, files in self.matches_per_label.items():
|
||||||
|
top_tree = DirectoryTree(f"{label_name}:")
|
||||||
|
for file in sorted(files):
|
||||||
|
top_tree.add(file)
|
||||||
|
rich.print(top_tree)
|
||||||
|
print()
|
||||||
|
|
||||||
|
def _show_files_without_labels(self) -> None:
|
||||||
|
top_tree = DirectoryTree("\n--- Not matched ---")
|
||||||
|
for file, labels in self.matches_per_file:
|
||||||
|
if not labels:
|
||||||
|
top_tree.add(file)
|
||||||
|
if top_tree:
|
||||||
|
self.exit_code = 1
|
||||||
|
rich.print(top_tree)
|
||||||
|
else:
|
||||||
|
print("--- All files match at least one label's patterns ---")
|
||||||
|
|
||||||
|
def _show_files_with_multiple_labels(self) -> None:
|
||||||
|
top_tree = DirectoryTree("\n--- Matched by more than one label ---")
|
||||||
|
for file, labels in self.matches_per_file:
|
||||||
|
if len(labels) > 1:
|
||||||
|
tree = top_tree.add(file)
|
||||||
|
for label_name in labels:
|
||||||
|
tree.add(label_name)
|
||||||
|
if top_tree:
|
||||||
|
rich.print(top_tree)
|
||||||
|
else:
|
||||||
|
print("--- None of the files are matched by more than one label's patterns ---")
|
||||||
|
|
||||||
|
def _show_unused_matchers(self) -> None:
|
||||||
|
for label_name, matchers in self.label_matchers.items():
|
||||||
|
for idx, matcher in enumerate(matchers):
|
||||||
|
if matcher not in self.used_matchers:
|
||||||
|
print(
|
||||||
|
f"--- Matcher {idx} for label {label_name!r} does not match any files! ---"
|
||||||
|
)
|
||||||
|
self.exit_code = 1
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
raise SystemExit(App().run())
|
||||||
Loading…
x
Reference in New Issue
Block a user