-
Notifications
You must be signed in to change notification settings - Fork 12
feat(ci): add issue and PR management automation #262
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,65 @@ | ||
| # SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. | ||
| # SPDX-License-Identifier: Apache-2.0 | ||
| # | ||
| # | ||
| # 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. | ||
|
|
||
| # Path-based PR labels for actions/labeler. Kept in sync with the component/* | ||
| # label family in .github/labels.yml and the triage keyword maps in | ||
| # .github/workflows/triage.yaml. | ||
|
|
||
| # Operator (controller-manager), excluding the CLI which lives under it. | ||
| component/operator: | ||
| - changed-files: | ||
| - any-glob-to-any-file: | ||
| - 'operator/**' | ||
| - all-globs-to-all-files: | ||
| - '!operator/cmd/cli/**' | ||
|
|
||
| component/cli: | ||
| - changed-files: | ||
| - any-glob-to-any-file: | ||
| - 'operator/cmd/cli/**' | ||
|
|
||
| component/agent: | ||
| - changed-files: | ||
| - any-glob-to-any-file: | ||
| - 'agent/**' | ||
|
|
||
| component/chart: | ||
| - changed-files: | ||
| - any-glob-to-any-file: | ||
| - 'chart/**' | ||
|
|
||
| component/ci: | ||
| - changed-files: | ||
| - any-glob-to-any-file: | ||
| - '.github/**' | ||
| - 'scripts/**' | ||
| - '.gitlab-ci.yml' | ||
| - '**/Makefile' | ||
| - '**/*.mk' | ||
| # Don't let vendored third-party Makefiles trip the CI label. | ||
| - all-globs-to-all-files: | ||
| - '!**/vendor/**' | ||
|
|
||
| component/tests: | ||
| - changed-files: | ||
| - any-glob-to-any-file: | ||
| - 'k8s-tests/**' | ||
|
|
||
| doc: | ||
| - changed-files: | ||
| - any-glob-to-any-file: | ||
| - 'docs/**' | ||
| - '**/*.md' | ||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,84 @@ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # SPDX-License-Identifier: Apache-2.0 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # 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. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| name: Inactive PR Reminder | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| on: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| schedule: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| - cron: '0 7 * * *' # daily at 07:00 UTC | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| workflow_dispatch: {} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| permissions: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| contents: read | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| concurrency: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| group: ${{ github.workflow }} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| jobs: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| remind: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| name: Nudge Inactive PRs | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if: github.repository == 'NVIDIA/nodewright' | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| runs-on: ubuntu-latest | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| permissions: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| pull-requests: write | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+36
to
+37
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Document the Add a brief comment explaining the write scope (commenting on PRs) to satisfy the 📝 Proposed fix permissions:
+ # Needed to post reminder comments on inactive PRs.
pull-requests: write🧰 Tools🪛 zizmor (1.25.2)[warning] 37-37: permissions without explanatory comments (undocumented-permissions): needs an explanatory comment (undocumented-permissions) 🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| timeout-minutes: 10 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| steps: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| - name: Check for inactive PRs | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| with: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| script: | | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const now = new Date(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const msPerDay = 86400000; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const skipLabels = ['lifecycle/frozen', 'do-not-merge']; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const { data: prs } = await github.rest.pulls.list({ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| owner: context.repo.owner, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| repo: context.repo.repo, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| state: 'open', | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| sort: 'updated', | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| direction: 'asc', | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| per_page: 100, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+48
to
+55
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chain🏁 Script executed: #!/bin/bash
set -euo pipefail
FILE=".github/workflows/inactive-pr-reminder.yaml"
echo "== File =="
ls -la "$FILE"
echo "== Lines 1-120 =="
nl -ba "$FILE" | sed -n '1,120p'
echo "== Search for paginate usage =="
rg -n "paginate|pagination|per_page|page:" "$FILE" || true
echo "== Search for pulls.list usage =="
rg -n "pulls\.list" "$FILE"Repository: NVIDIA/nodewright Length of output: 244 🏁 Script executed: #!/bin/bash
set -euo pipefail
FILE=".github/workflows/inactive-pr-reminder.yaml"
echo "== File =="
ls -la "$FILE"
echo "== Lines 1-160 =="
awk 'NR>=1 && NR<=160 {printf "%4d %s\n", NR, $0}' "$FILE"
echo "== Search for paginate usage =="
rg -n "paginate|pagination|per_page|page:" "$FILE" || true
echo "== Search for pulls.list usage =="
rg -n "pulls\.list" "$FILE" || true
echo "== Show surrounding context for pulls.list =="
rg -n -C 3 "pulls\.list" "$FILE" || trueRepository: NVIDIA/nodewright Length of output: 4210 🏁 Script executed: #!/bin/bash
set -euo pipefail
FILE=".github/workflows/inactive-pr-reminder.yaml"
echo "== Lines 70-140 =="
awk 'NR>=70 && NR<=160 {printf "%4d %s\n", NR, $0}' "$FILE"Repository: NVIDIA/nodewright Length of output: 861 🌐 Web query:
💡 Result: To use Citations:
🏁 Script executed: #!/bin/bash
set -euo pipefail
FILE=".github/workflows/inactive-pr-reminder.yaml"
awk '{printf "%4d %s\n", NR, $0}' "$FILE"Repository: NVIDIA/nodewright Length of output: 3572 Paginate open PR listing to avoid missing eligible PRs beyond the first 100 results. File: .github/workflows/inactive-pr-reminder.yaml Comment: The workflow fetches a single page ( Suggested fix- const { data: prs } = await github.rest.pulls.list({
- owner: context.repo.owner,
- repo: context.repo.repo,
- state: 'open',
- sort: 'updated',
- direction: 'asc',
- per_page: 100,
- });
-
- for (const pr of prs) {
+ for await (const { data: prs } of github.paginate.iterator(
+ github.rest.pulls.list,
+ {
+ owner: context.repo.owner,
+ repo: context.repo.repo,
+ state: 'open',
+ sort: 'updated',
+ direction: 'asc',
+ per_page: 100,
+ }
+ )) {
+ for (const pr of prs) {
// Skip PRs explicitly held open or parked.
if (pr.labels.some(l => skipLabels.includes(l.name))) continue;
@@
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: pr.number,
body: `@${pr.user.login} this PR has been inactive for ${daysInactive} days. Do you need help finishing it, or should we close it for now? Feel free to reopen anytime.`,
});
+ }
}📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| for (const pr of prs) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Skip PRs explicitly held open or parked. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (pr.labels.some(l => skipLabels.includes(l.name))) continue; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const updated = new Date(pr.updated_at); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const daysInactive = Math.floor((now - updated) / msPerDay); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Target the 14–29 day window, before the stale bot fires at 30. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (daysInactive < 14 || daysInactive >= 30) continue; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Don't double-remind: skip if a bot already left a reminder. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const { data: comments } = await github.rest.issues.listComments({ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| owner: context.repo.owner, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| repo: context.repo.repo, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| issue_number: pr.number, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const alreadyReminded = comments.some(c => | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| c.user.type === 'Bot' && c.body.includes('inactive for') | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (alreadyReminded) continue; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+68
to
+76
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Duplicate-reminder guard only inspects the first page of comments.
🛠️ Proposed fix- const { data: comments } = await github.rest.issues.listComments({
- owner: context.repo.owner,
- repo: context.repo.repo,
- issue_number: pr.number,
- });
+ const comments = await github.paginate(github.rest.issues.listComments, {
+ owner: context.repo.owner,
+ repo: context.repo.repo,
+ issue_number: pr.number,
+ per_page: 100,
+ });🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| await github.rest.issues.createComment({ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| owner: context.repo.owner, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| repo: context.repo.repo, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| issue_number: pr.number, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| body: `@${pr.user.login} this PR has been inactive for ${daysInactive} days. Do you need help finishing it, or should we close it for now? Feel free to reopen anytime.`, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
🌐 Web query:
In actions/labeler v6, how doall-globs-to-all-filesand negative globs behave for mixed-file PRs, and what pattern should be used to exclude a subpath (for exampleoperator/cmd/cli/or/vendor/**) without suppressing the label for the whole PR?💡 Result:
In actions/labeler, the
all-globs-to-all-filessetting requires that every glob pattern provided in its list must match against every single file changed in the pull request [1][2]. If any file in the PR fails to match any of the specified globs, the condition will not be met [1][2]. When using negative globs (prefixed with!) within this context, you are effectively adding an exclusion constraint to the global requirement [1][3]. Becauseall-globs-to-all-filesis an "AND" operation across all provided patterns, adding a negative glob means that to satisfy the condition, all files must match the positive patterns AND none of the files may match the negative patterns [1][2]. To exclude a subpath (likeoperator/cmd/cli/or/vendor/) without suppressing the label for the entire PR, you cannot simply use a negative glob inside anall-globs-to-all-filesblock, as this would likely disqualify the label if any file exists in those subpaths. Instead, you should use theanyandalltop-level keys to structure your logic [1][2]. Recommended Pattern: To apply a label based on certain file changes while explicitly ignoring specific subpaths, structure your configuration to combineany-glob-to-any-file(which triggers the label) with anall-globs-to-all-filesexclusion or by using multiple rules [1][2]. For example, to label changes insrcwhile excludingsrc/docs, you can use this structure [1][2]: label-name: - all: - changed-files: - any-glob-to-any-file: 'src//' - all-globs-to-all-files: '!src/docs/' This configuration usesany-glob-to-any-fileto ensure the label is applied if any file insrcis changed, while theall-globs-to-all-fileswith a negative glob acts as a filter that must also be satisfied (i.e., all changed files must not be insrc/docs) [1][2]. If you want to allow changes tosrc/docswithout triggering the label, you would typically define separate rules where the exclusion is handled by the scope of the matching glob itself rather than relying on global negation [4][5].Citations:
🏁 Script executed:
Repository: NVIDIA/nodewright
Length of output: 164
🏁 Script executed:
Repository: NVIDIA/nodewright
Length of output: 2446
🌐 Web query:
actions/labeler changed-files all-globs-to-all-files negative glob ! semantics💡 Result:
For actions/labeler, the semantics of the “negative glob” syntax with the! prefix inside the changed-files globs are: the glob pattern is treated as a negation (i.e., it should exclude paths), but it only makes sense in the context of the action’s described matcher logic (any/all combinations) and depends on matching all changed files vs any changed files. 1) What all-globs-to-all-files means actions/labeler defines these operators for changed-files matching across the list of changed paths: - any-glob-to-all-files: ANY glob must match ALL changed files. - all-globs-to-all-files: ALL globs must match ALL changed files. This is explicitly documented for actions/labeler’s changed-files options. [1] So with all-globs-to-all-files, every glob entry in that list must match every changed file for the rule to apply. [1] 2) How negation is written (the leading!) In actions/labeler, negation is used by prefixing a glob pattern with! (example shown in the README): - all-globs-to-all-files: '!src/docs/' The example is presented as part of a configuration where the rule matches src// but excludes the docs subfolder via a negated glob. [1] 3) Practical consequence: with all-globs-to-all-files, negation can become “too strict” Because all-globs-to-all-files requires that every glob (including a negated one) match every changed file, negated patterns work only if the negated pattern “matches” (i.e., is satisfied) for each changed path according to the action’s matcher. The README’s wording and example imply this is intended as “match all src files except docs” by combining a positive glob with an excluded docs glob within an all/changed-files context. [1] If you put only a negated glob in all-globs-to-all-files, you are effectively requiring that every changed file satisfies the negation constraint; if any changed file doesn’t satisfy it, the rule won’t apply. 4) Example pattern from the official docs The README shows: - changed-files: - any-glob-to-any-file: 'src//' - all-globs-to-all-files: '!src/docs/' This demonstrates the intended use of! to exclude docs while still matching source files under src. [1] Bottom line - Use! to express exclusion within actions/labeler’s changed-files glob list. [1] - all-globs-to-all-files means every glob entry must satisfy the rule for every changed file. [1] - Therefore, negated globs under all-globs-to-all-files exclude paths only insofar as the rule can still be satisfied for all changed files. [1]
Citations:
🌐 Web query:
actions/labeler changed-files configuration is list of matchers combined with AND or OR💡 Result:
In the official actions/labeler GitHub Action, configuration logic is handled using two primary top-level keys:
anyandall[1][2]. From a boolean logic perspective, these function as follows: - Options within theallkey are combined with an AND operation, meaning all provided conditions must be met for the label to be applied [1][3]. - Individual match rules within theanyobject are combined with an OR operation, meaning if any of the provided conditions match, the label will be applied [1][4]. - Additionally, top-level match objects are combined using an AND operation [2][3]. If a configuration is provided without an explicit top-level key (anyorall), it defaults toany[1][5]. The action supports fine-grained matching, includingbase-branch,head-branch, and variouschanged-filesglob matching strategies (such asany-glob-to-any-fileorall-globs-to-all-files) [1][3].Citations:
🌐 Web query:
actions/labeler any-glob-to-any-file negated glob ! operator/cmd/cli/** behavior💡 Result:
In the GitHub actions/labeler, the exclamation mark (!) operator is used for glob negation to create complex matching rules by excluding specific files or paths [1][2]. When combined with glob patterns, this allows you to specify which files to include while explicitly ignoring others [1][3]. Key behaviors and considerations include: - Functionality: The! operator functions as a NOT filter within your path glob definitions [1][2]. If a file matches a negated pattern, it will be excluded from the match, even if it otherwise satisfies other inclusion patterns in your configuration [1][3]. - Configuration: Glob patterns in actions/labeler are evaluated based on the Minimatch library [1]. When using negation, it is often necessary to use explicit inclusion patterns alongside your exclusions to achieve the desired logic [1][2]. - YAML Syntax: Because the asterisk () and exclamation mark (!) have special meanings in YAML (used for aliases and tags/anchors, respectively), you must wrap your glob strings in quotes (e.g., '!src//') to ensure they are interpreted as literal strings rather than YAML syntax [4]. Failing to quote these patterns can cause the action to crash or fail to parse the configuration correctly [4]. Example Usage: To label a pull request based on changes to a directory while excluding a specific subdirectory, you might structure your configuration like this: - all: - changed-files: - any-glob-to-any-file: 'src//' - any-glob-to-any-file: '!src/exclude-folder//' This ensures that any file in src/ is considered, but files within src/exclude-folder/ are ignored [1][2].
Citations:
🌐 Web query:
actions/labeler all-globs-to-all-files '!src/docs/*' PR changes both src and src/docs what happens💡 Result:
When using the actions/labeler configuration all-globs-to-all-files with a negated glob like '!src/docs/', the behavior is governed by strict boolean logic applied to the set of changed files in the Pull Request [1][2][3]. The rule all-globs-to-all-files requires that ALL specified globs must match against ALL changed files [1][3]. If a PR changes files in both src/ (e.g., src/main.js) and src/docs/ (e.g., src/docs/readme.md): 1. The set of changed files contains files that match the negation '!src/docs/' (the src/main.js file) and files that do not (the src/docs/readme.md file). 2. Because the negation '!src/docs/*' is treated as a requirement that matches files NOT in the docs directory, the rule essentially checks if all changed files are outside the docs directory. 3. Since the PR contains at least one file inside src/docs/, the condition 'all files must match the glob' fails. Consequently, the label will not be applied [1][3]. In summary, when you use a negation with all-globs-to-all-files, the rule only evaluates to true if every single file changed in the PR satisfies the condition of not being in the docs/ directory [1][2]. If even one file is changed within src/docs/, the entire rule fails because not all changed files satisfy the negated pattern [1][3].
Citations:
🌐 Web query:
actions/labeler mixed PR exclude subpath do not suppress label operator/cmd/cli all-globs-to-all-files '!**' pattern recommended💡 Result:
The “actions/labeler” action supports excluding subpaths via negated path globs using the “!” prefix inside the glob list. In the documented example, to exclude the docs sub-folder while labeling src files, the recommended pattern is: - all-globs-to-all-files: '!src/docs/' [1] In practice (and per a resolved issue report), exclusions may require array syntax and quotes; the reporter’s working fix changed from a bare string negation to a single-element list in YAML: - all-globs-to-all-files: '[!docs/source/news/index.rst]' [2] Regarding “mixed PR exclude subpath do not suppress label operator/cmd/cli all-globs-to-all-files '!' pattern”: the sources above do not document an exclusion pattern specifically using '!' (nor any special “operator/cmd/cli” semantics). What is clearly supported is negated globs combined with the all-globs-to-all-files matching mode, and the canonical negation format is '!' (with recommended YAML quoting/list form when needed) [1][2]. So, for excluding a specific file/subpath under an otherwise-matched directory, use a negated glob like '!operator/cmd/cli//' (or '!operator/cmd/cli/') as shown in the official docs pattern for “EXCEPT” cases, and if it doesn’t behave as expected, ensure you use the YAML quoting/list form for the glob string, as in the resolved issue [1][2].
Citations:
🌐 Web query:
actions/labeler any-glob-to-any-file negated glob ! operator/cmd/cli behavior mixed files💡 Result:
In the GitHub actions/labeler action, the negation operator (!) is supported for path glob patterns [1][2]. When using these patterns with configuration options like any-glob-to-any-file, the negation operator effectively excludes files or directories that would otherwise be matched by a glob [1][2]. For example, a configuration can use negation to select a broad set of files while excluding specific subsets: - changed-files: - any-glob-to-any-file: ['src//', '!src/docs/'] In this example, the rule matches any change within the src directory, excluding any changes specifically within the src/docs directory [2]. Behavioral considerations: 1. Complex Matching: Negation allows you to create more granular label logic by combining inclusion and exclusion in a single list [1]. 2. Order of Operations: The labeler processes these globs using standard glob matching libraries (minimatch), where the negation pattern (!) instructs the matcher to treat the pattern as an exclusion rule rather than an inclusion rule [3][1]. 3. Logic Context: Since any-glob-to-any-file requires that at least one of the provided globs matches a changed file, negation patterns effectively reduce the set of files that qualify for a match [1][4]. 4. Limitations: While powerful, be aware that complex negated glob sets can become difficult to debug. If a PR contains only files that are negated, the condition will not be met [1]. For best results, keep patterns simple and avoid deeply nested or contradictory negation chains. You can combine multiple conditions using the top-level all or any keys to further refine the logic [2][4].
Citations:
Fix
actions/labelerglob exclusions so mixed-file PRs don’t lose labels.github/labeler.ymlcomponent/operatorusesall-globs-to-all-files: '!operator/cmd/cli/**', which makes the rule fail if any changed file is underoperator/cmd/cli/**—so PRs touching both CLI and non-CLI operator code losecomponent/operator.component/ci:all-globs-to-all-files: '!**/vendor/**'suppressescomponent/ciwhenever the PR includes any vendored file (even alongside real CI changes).Move the
!exclusions into theany-glob-to-any-filematcher (and remove the negatedall-globs-to-all-filesblocks):🤖 Prompt for AI Agents