Skip to content

fix: enable copilot-local ESLint rules in PR CI#316121

Merged
benvillalobos merged 2 commits into
microsoft:mainfrom
benvillalobos:bv/fix-copilot-eslint-plugin
May 13, 2026
Merged

fix: enable copilot-local ESLint rules in PR CI#316121
benvillalobos merged 2 commits into
microsoft:mainfrom
benvillalobos:bv/fix-copilot-eslint-plugin

Conversation

@benvillalobos
Copy link
Copy Markdown
Member

@benvillalobos benvillalobos commented May 12, 2026

🤖 AI Assisted PR

Problem

The Copilot ESLint plugin (.eslintplugin/) has two bugs that prevent copilot-local/* rules from running in PR CI:

Bug 1 — Plugin fails to load. index.ts uses import * as glob from 'glob' + glob.sync(). In the root ESLint's ESM context, the namespace import on CJS glob v5 gives { default: [function] } — no sync property. The plugin silently fails to load, registering zero rules.

Bug 2 — Rule checks absolute paths. no-unlayered-files.ts splits context.filename (an absolute path) and checks if ANY segment matches a layer name. Since vscode is both a valid layer name AND the repo checkout directory, every file's path matches → the rule never fires.

Impact

Since the root ESLint integration was added on April 28 (371c4a0a73c), no copilot-local/* rules have executed in PR CI. This includes no-unlayered-files, no-test-imports, no-runtime-import, and 8+ other custom rules.

On May 7, PR #314783 added a test file to the wrong folder. PR CI passed (copilot rules were dead). The ADO build caught it post-merge, causing 6 consecutive build failures across all platforms (~55 cascading task failures, 2-hour recovery window).

Data: Download Copilot VSIX is the #1 root-cause task in the 14-day OData dataset (81 of 479 root-cause failures). 68% of those were caused by Copilot Lint failures that escaped PR CI.

Fix

Two changes in extensions/copilot/.eslintplugin/:

1. index.ts — Replace glob.sync with fs.readdirSync

The glob package (v5, CJS) doesn't export sync as an ESM named export. fs.readdirSync is a Node.js built-in — zero external dependency, works in both CJS and ESM.

2. no-unlayered-files.ts — Use relative path

Strip the absolute path to be relative to extensions/copilot/ before checking for layer folders. This prevents the repo directory name (vscode) from being matched as a valid layer.

Verification

Local

# Create a misplaced file (same pattern as the May 7 incident)
echo "export const x = 1;" > extensions/copilot/src/platform/chat/test/repro.ts

# Before fix: no copilot-local warnings (plugin broken + path bug)
node build/eslint.ts  # → only header/semi errors, no copilot-local rules

# After fix: copilot-local/no-unlayered-files fires
node build/eslint.ts  # → "File should be inside a 'common, vscode, node...' folder"

Verified locally: bad files caught ✅, correctly layered files pass ✅, no regressions on existing codebase ✅

CI verification PRs (now closed)

PR Fix? Bad file? CI result ADO result
#316122 (closed) ✅ First fix only Passed — rule path bug prevented detection N/A
#316123 (closed) Passed (the bug — CI doesn't catch it) Failed (build 438627) — 23 failed tasks, Copilot Lint caught it

PR #316123 + ADO build 438627 prove the current state: CI passes what ADO fails on. This PR closes that gap.

Root cause chain

  1. Copilot extension migrated into vscode repo (~March 2026)
  2. April 28: root eslint.config.js integrated Copilot ESLint plugin (371c4a0a73c)
  3. Plugin's import * as glob doesn't work in ESM → plugin silently fails to load (Bug 1)
  4. Even if loaded, no-unlayered-files checks absolute paths containing vscode dir → never fires (Bug 2)
  5. May 7: misplaced file escapes CI → ADO Lint catches it post-merge → 6 builds fail → ~55 cascade task failures
  6. May 8: PR Run copilot extension lint in PR CI #315368 added npm run lint step to Copilot CI jobs — but both bugs persist, so the step is ineffective

References

The copilot eslint plugin used \import * as glob from 'glob'\ and called
\glob.sync()\. In ESM context (which is how the root eslint.config.js loads
this plugin), the namespace import on the CJS glob package produces
\{ default: [function] }\ — no \sync\ property. This causes a silent failure
that prevents ALL copilot-local/* ESLint rules from running in PR CI.

Replace with \s.readdirSync\ which has no external dependency and works
identically for listing .ts files in a single directory.

Impact: Enables copilot-local/no-unlayered-files and 10+ other custom lint
rules in PR CI. These rules have been silently broken since the root eslint
integration was added on April 28 (371c4a0).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR fixes the Copilot local ESLint plugin’s rule discovery so that copilot-local/* rules actually load and run under the repo’s ESM-based ESLint configuration, restoring enforcement in PR CI.

Changes:

  • Replace glob.sync('*.ts', …) with fs.readdirSync(…) to enumerate rule files without relying on CJS glob interop.
  • Keep the existing filtering to exclude index.ts and utils.ts, and dynamically import each rule module.
Show a summary per file
File Description
extensions/copilot/.eslintplugin/index.ts Switches rule-file enumeration from glob.sync to fs.readdirSync to avoid ESM/CJS interop issues and ensure copilot-local/* rules load in ESLint.

Copilot's findings

  • Files reviewed: 1/1 changed files
  • Comments generated: 0

The rule checked absolute paths for layer folder names. Since 'vscode' is
both a valid layer name AND the repo checkout directory, every file's
absolute path matched → the rule never fired.

Now strips the path to be relative to extensions/copilot/ before checking,
so only actual layer folders within the extension structure are matched.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@benvillalobos benvillalobos marked this pull request as ready for review May 13, 2026 00:01
@benvillalobos benvillalobos merged commit 78905ec into microsoft:main May 13, 2026
25 checks passed
@vs-code-engineering vs-code-engineering Bot added this to the 1.121.0 milestone May 13, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants