From f0c98e23f17456b9b0bd68ae0fa651c5ad496968 Mon Sep 17 00:00:00 2001 From: Steven Palma Date: Wed, 17 Dec 2025 17:52:45 +0100 Subject: [PATCH] feat(ci): simple automatic labelling (#2667) * ci: add pr labeler * ci: add issue labeler * ci: minor fixes for labelers * fix(ci): add explicit path for pr labeler --- .github/workflows/issue_labeler.yml | 105 ++++++++++++++++++++++++++++ .github/workflows/labeler.yml | 68 ++++++++++++++++++ .github/workflows/pr_labeler.yml | 39 +++++++++++ 3 files changed, 212 insertions(+) create mode 100644 .github/workflows/issue_labeler.yml create mode 100644 .github/workflows/labeler.yml create mode 100644 .github/workflows/pr_labeler.yml diff --git a/.github/workflows/issue_labeler.yml b/.github/workflows/issue_labeler.yml new file mode 100644 index 000000000..352819db1 --- /dev/null +++ b/.github/workflows/issue_labeler.yml @@ -0,0 +1,105 @@ +# Copyright 2025 The HuggingFace Inc. team. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# This workflow automatically labels issues based on their content. +name: Issue Labeler +on: + # Trigger on new issues and edits to existing issues + issues: + types: [opened, edited] + +permissions: + contents: read + issues: write + +jobs: + label-issue: + name: Auto Label Issue + runs-on: ubuntu-latest + if: github.repository == 'huggingface/lerobot' + steps: + - uses: actions/github-script@v8 + with: + script: | + // Setup Input Text (Unified Title + Body) + const body = (context.payload.issue.body || ''); + const title = (context.payload.issue.title || ''); + + // We keep a lowercased version for keyword matching + const text = `${title}\n${body}`.toLowerCase(); + + const labelsToAdd = new Set(); + + // Helper: Simple regex test + const matches = (re) => re.test(text); + + // Issue Type Detection (Dropdowns & Explicit Headers) + if (text.includes('bug report') || /\bissue type:.*bug/.test(text)) { + labelsToAdd.add('bug'); + } + if (text.includes('feature request') || /\bissue type:.*feature/.test(text)) { + labelsToAdd.add('enhancement'); + } + if (text.includes('technical question') || /\bissue type:.*question/.test(text)) { + labelsToAdd.add('question'); + } + if (text.includes('maintenance') || /\bissue type:.*maintenance/.test(text)) { + labelsToAdd.add('documentation'); + } + + // Keyword Heuristic + + // Domain Specific + if (matches(/example(s)?\b|script(s)?\b|sample(s)?\b|demo(s)?\b|notebook(s)?\b/i)) labelsToAdd.add('examples'); + if (matches(/dataset(s)?\b|data loader|data augmentation|data preprocessing/i)) labelsToAdd.add('dataset'); + if (matches(/mujoco|isaac|\bsimulation\b|\bsim /i)) labelsToAdd.add('simulation'); + if (matches(/train|loss|optimizer|backward|gradient|wandb|sac\b/i)) labelsToAdd.add('training'); + if (matches(/rerun|plot|video|render|visualiz|gif/i)) labelsToAdd.add('visualization'); + if (matches(/camera|realsense|lidar|depth|sensor|imu|microphone|rgbd/i)) labelsToAdd.add('sensors'); + if (matches(/aloha|koch|so-100|so100|mobile|teleop|manipulator|robot(s)?\b/i)) labelsToAdd.add('robots'); + if (matches(/teleop|teleoperator|controller|leader|follower|joystick|gamepad/i)) labelsToAdd.add('teleoperators'); + if (matches(/policy|policies|p0licy/i)) labelsToAdd.add('policies'); + if (matches(/processor(s)?\b|implement.*processor|processor pipeline/i)) labelsToAdd.add('processor'); + if (matches(/eval|evaluate|evaluation|metric(s)?\b|score|benchmark/i)) labelsToAdd.add('evaluation'); + + // Infrastructure & Code Quality + if (matches(/test|pytest|unittest|failing test/i)) labelsToAdd.add('tests'); + if (matches(/ci|github actions|workflow|gha|action(s)?\b|pipeline/i)) { + labelsToAdd.add('CI'); + labelsToAdd.add('github_actions'); + } + if (matches(/perf|latency|benchmark|throughput|fps|speed|performance|benchmarking/i)) labelsToAdd.add('performance'); + if (matches(/dependency|requirements|pip|conda|install error|importerror|package not found/i)) labelsToAdd.add('dependencies'); + if (matches(/python\b|pyproject|requirements(\.txt)?|pip install|typing error/i)) labelsToAdd.add('python'); + + // Documentation & Meta + if (matches(/doc|documentation|docs|readme|typo|how to/i)) labelsToAdd.add('documentation'); + if (matches(/refactor|cleanup|restructure|rename|modernize code/i)) labelsToAdd.add('refactor'); + if (matches(/release|changelog|version bump|cut a release|tag v/i)) labelsToAdd.add('release'); + + // Fixed: "BREAKING CHANGE" must be lowercase in regex because 'text' is lowercase + if (matches(/breaking change|breaking:|major change/i)) labelsToAdd.add('breaking change'); + + // Apply Labels + const labels = Array.from(labelsToAdd).filter(Boolean); + + if (labels.length > 0) { + console.log(`Adding labels: ${labels.join(', ')}`); + await github.rest.issues.addLabels({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: context.issue.number, + labels, + }); + } diff --git a/.github/workflows/labeler.yml b/.github/workflows/labeler.yml new file mode 100644 index 000000000..1ff046882 --- /dev/null +++ b/.github/workflows/labeler.yml @@ -0,0 +1,68 @@ +# Copyright 2025 The HuggingFace Inc. team. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +CI: + - changed-files: + - any-glob-to-any-file: + - '.github/**' + - 'docker/**' + +github_actions: + - changed-files: + - any-glob-to-any-file: '.github/**' + +documentation: + - changed-files: + - any-glob-to-any-file: + - '**/*.md' + - 'docs/**' + +examples: + - changed-files: + - any-glob-to-any-file: 'examples/**' + +tests: + - changed-files: + - any-glob-to-any-file: 'tests/**' + +sensors: + - changed-files: + - any-glob-to-any-file: 'src/lerobot/cameras/**' + +configuration: + - changed-files: + - any-glob-to-any-file: 'src/lerobot/configs/**' + +dataset: + - changed-files: + - any-glob-to-any-file: 'src/lerobot/datasets/**' + +evaluation: + - changed-files: + - any-glob-to-any-file: 'src/lerobot/envs/**' + +robots: + - changed-files: + - any-glob-to-any-file: + - 'src/lerobot/teleoperators/**' + - 'src/lerobot/robots/**' + - 'src/lerobot/motors/**' + +policies: + - changed-files: + - any-glob-to-any-file: 'src/lerobot/policies/**' + +processor: + - changed-files: + - any-glob-to-any-file: 'src/lerobot/processor/**' diff --git a/.github/workflows/pr_labeler.yml b/.github/workflows/pr_labeler.yml new file mode 100644 index 000000000..70338e221 --- /dev/null +++ b/.github/workflows/pr_labeler.yml @@ -0,0 +1,39 @@ +# Copyright 2025 The HuggingFace Inc. team. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# This workflow labels pull requests based on the files that were changed. +name: Pull Request Labeler + +on: + # Allows labeling pull requests when they are opened or updated + pull_request: + branches: + - main + types: [opened, synchronize, reopened, ready_for_review] + +permissions: + contents: read + pull-requests: write + +jobs: + triage: + name: Label PR + runs-on: ubuntu-latest + if: github.repository == 'huggingface/lerobot' + steps: + - uses: actions/labeler@v6 + with: + repo-token: ${{ secrets.GITHUB_TOKEN }} + sync-labels: true # Removes labels if files are removed from the PR + configuration-path: '.github/workflows/labeler.yml'