Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
16 commits
Select commit Hold shift + click to select a range
d31f552
fix(ci): restore strict mode file detection and fix monorepo linter c…
shivanee-p Aug 4, 2026
76c730b
🦉 Updates from OwlBot post-processor
gcf-owl-bot[bot] Aug 5, 2026
8c14a77
fix(ci): handle undefined ts.sys in linter tsconfig resolution
shivanee-p Aug 5, 2026
d7c1fb0
fix(ci): update .eslintignore and ESLint resolution to prevent exit c…
shivanee-p Aug 5, 2026
0521cde
fix(ci): handle CJS and ESM default interop for typescript import
shivanee-p Aug 5, 2026
d01a1b3
refactor(ci): simplify typescript import using standard default import
shivanee-p Aug 5, 2026
2ca7286
fix(ci): use createRequire to robustly import CommonJS typescript mod…
shivanee-p Aug 5, 2026
014a6c1
fix(ci): replace ts.findConfigFile with pure Node directory traversal
shivanee-p Aug 5, 2026
085e95b
fix(ci): update .eslintignore and replace ts.findConfigFile with pure…
shivanee-p Aug 5, 2026
6725c1c
fix(ci): use three-dot diff (ref...HEAD) in linter to avoid checking …
shivanee-p Aug 5, 2026
1665925
fix(ci): update eslint extends and ignore patterns to fix generator a…
shivanee-p Aug 6, 2026
fa48a41
🦉 Updates from OwlBot post-processor
gcf-owl-bot[bot] Aug 6, 2026
4663a91
fix(deps): upgrade c8 to ^10.1.3 in cloud-profiler and logging to res…
shivanee-p Aug 6, 2026
efe988e
fix: upgrade mocha to ^11.1.0 and restore generator .eslintrc.json
shivanee-p Aug 7, 2026
31028e1
fix(deps): upgrade c8 and mocha in logging-bunyan and storage to reso…
shivanee-p Aug 11, 2026
15031c2
fix(bigquery-storage): increase timeout for system-test and table cre…
shivanee-p Aug 19, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions .eslintignore
Original file line number Diff line number Diff line change
@@ -1,7 +1,16 @@
**/node_modules
**/build
**/system-test
**/test/fixtures
**/samples/generated
**/.coverage
**/coverage
**/baselines
**/baselines-esm
**/.test-out*
test/fixtures
build/
docs/
protos/
packages/
**/types.d.ts
66 changes: 63 additions & 3 deletions .eslintrc.json
Original file line number Diff line number Diff line change
@@ -1,20 +1,80 @@
{
"extends": [
"./node_modules/gts",
"gts",
"plugin:prettier/recommended",
"plugin:import/recommended",
"plugin:import/typescript",
"plugin:promise/recommended"
],
"root": true,
// Note: All rules configured as "error" are blocking in the PR CI pipeline.
// Only rules configured as "warn" remain non-blocking.
"rules": {
"import/no-unresolved": "off",
"import/no-extraneous-dependencies": "error",
"promise/catch-or-return": "error",
"promise/always-return": "error"
},
"overrides": [
// The overrides below were migrated from handwritten/firestore/.eslintrc.json
// during monorepo ESLint consolidation to maintain Firestore-specific rules.
{
"files": ["handwritten/firestore/dev/src/**/*.ts"],
"excludedFiles": ["handwritten/firestore/dev/src/v1/*.ts", "handwritten/firestore/dev/src/v1beta1/*.ts"],
"parser": "@typescript-eslint/parser",
"rules": {
"@typescript-eslint/explicit-function-return-type": [
"error",
{
"allowExpressions": true,
"allowTypedFunctionExpressions": true
}
],
"no-console": ["error", {"allow": ["error"]}],
"@typescript-eslint/no-unused-vars": [
"warn",
{
"argsIgnorePattern": "^_"
}
]
}
},
{
"files": ["handwritten/firestore/dev/test/*.ts", "handwritten/firestore/dev/system-test/*.ts"],
"parser": "@typescript-eslint/parser",
"rules": {
"no-restricted-properties": [
"error",
{
"object": "describe",
"property": "only"
},
{
"object": "it",
"property": "only"
}
],
"@typescript-eslint/no-unused-vars": [
"warn",
{
"argsIgnorePattern": "^_"
}
],
"@typescript-eslint/no-floating-promises": "warn"
}
},
{
"files": [
"handwritten/firestore/dev/src/v1/**/*.ts",
"handwritten/firestore/dev/src/v1beta1/**/*.ts",
"handwritten/firestore/dev/test/gapic_firestore_v1.ts",
"handwritten/firestore/dev/test/gapic_firestore_admin_v1.ts",
"handwritten/firestore/dev/test/gapic_firestore_admin_v1.ts"
],
"rules": {
"@typescript-eslint/no-explicit-any": ["off"],
"@typescript-eslint/no-floating-promises": ["off"]
}
}
],
"ignorePatterns": [
"**/node_modules",
"**/build",
Expand Down
6 changes: 4 additions & 2 deletions .github/workflows/presubmit.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -42,15 +42,17 @@ jobs:
steps:
- uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0
with:
fetch-depth: 300
fetch-depth: 2
persist-credentials: false
- name: Use Node.js 24
uses: actions/setup-node@249970729cb0ef3589644e2896645e5dc5ba9c38 # v6.5.0
with:
node-version: 24
- run: npm install
- run: npm run lint
- run: node ./bin/linter.mjs --strict
name: Run monorepo linter
env:
GIT_DIFF_ARG: "HEAD^1...HEAD"

# Consolidate shards into jobs representing aggregate status to simplify branch protection requirements
units-status:
Expand Down
146 changes: 113 additions & 33 deletions bin/linter.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -17,16 +17,20 @@ import {existsSync} from 'fs';
import path from 'path';
import {promisify} from 'util';
import {ESLint} from 'eslint';
import ts from 'typescript';

// --- Globals & Promisified API Wrappers ---
const execFileAsync = promisify(execFile);
const tsconfigCache = new Map();

// --- Main Runner (Entry Point) ---
async function run() {
try {
const changedTsFiles = getChangedFiles();
const isStrict = Boolean(process.argv.includes('--strict'));
let changedTsFiles;
if (isStrict) {
changedTsFiles = getChangedFilesStrict();
} else {
changedTsFiles = getChangedFiles();
}

if (changedTsFiles.length === 0) {
console.log('No TypeScript files changed. Skipping checks.');
Expand Down Expand Up @@ -63,6 +67,50 @@ function runGit(args, options = {}) {
});
}

function getChangedFilesStrict() {
let gitDiffArg = process.env.GIT_DIFF_ARG;

if (!gitDiffArg) {
throw new Error(
'Strict mode is enabled, but GIT_DIFF_ARG environment variable or --git-diff-arg flag was not provided. ' +
'Please set the GIT_DIFF_ARG environment variable or provide --git-diff-arg <arg>.'
);
}

// If a single ref is provided (e.g. "HEAD^1" or "origin/main"), convert to three-dot diff ("ref...HEAD")
// to compare against the merge-base and avoid listing files modified on the base branch.
if (!gitDiffArg.includes('..')) {
gitDiffArg = `${gitDiffArg}...HEAD`;
}

console.log(`Strict mode enabled. Comparing using GIT_DIFF_ARG: ${gitDiffArg}`);

const args = gitDiffArg.trim().split(/\s+/);

try {
const output = runGit([
'diff',
'--name-only',
'--diff-filter=ACMRT',
...args,
'--',
'*.ts',
]);
return output
.split('\n')
.map(f => f.trim())
.filter(f => f.length > 0 && existsSync(f));
} catch (err) {
if (err.status !== 1) {
throw new Error(
`Strict mode error: git diff ${gitDiffArg} failed with exit code ${err.status}.\n` +
`Ensure that the git reference '${gitDiffArg}' exists locally and that you have fetched the required commits/branches.\n` +
`Details: ${String(err.stderr || err.message || '').trim()}`
);
}
}
}

/**
* Returns a list of changed TypeScript files comparing against target branches/references.
*/
Expand All @@ -79,11 +127,12 @@ function getChangedFiles() {

for (const ref of refsToTry) {
try {
const diffRef = ref.includes('..') ? ref : `${ref}...HEAD`;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

is this change needed for anything?

const output = runGit([
'diff',
'--name-only',
'--diff-filter=ACMRT',
ref,
diffRef,
'--',
'*.ts',
]);
Expand Down Expand Up @@ -126,37 +175,59 @@ async function checkEslint(filesToCheck) {
return true;
}

try {
const eslint = new ESLint();
const results = await eslint.lintFiles(filesToCheck);
const formatter = await eslint.loadFormatter('stylish');
const resultText = formatter.format(results);

if (resultText) {
console.log(resultText);
// Group files by package directory to set tsconfigRootDir properly for typescript-eslint
const filesByPkg = new Map();
for (const file of filesToCheck) {
const pkgDir = findTsconfigDir(file) || process.cwd();
if (!filesByPkg.has(pkgDir)) {
filesByPkg.set(pkgDir, []);
}
filesByPkg.get(pkgDir).push(file);
}

let hasBlockingErrors = false;
let hasBlockingErrors = false;

for (const fileResult of results) {
for (const message of fileResult.messages) {
// message.severity === 2 indicates an error-level rule configuration.
if (message.severity === 2) {
hasBlockingErrors = true;
}
for (const [pkgDir, files] of filesByPkg.entries()) {
try {
const absPkgDir = path.resolve(pkgDir);
const eslint = new ESLint({
cwd: absPkgDir,
resolvePluginsRelativeTo: process.cwd(),
overrideConfig: {
parserOptions: {
tsconfigRootDir: absPkgDir,
},
},
});

const relativeFiles = files.map(f => path.relative(absPkgDir, path.resolve(f)));
const results = await eslint.lintFiles(relativeFiles);
const formatter = await eslint.loadFormatter('stylish');
const resultText = formatter.format(results);

if (resultText) {
console.log(resultText);
}
}

if (hasBlockingErrors) {
console.error('\n[ERROR] ESLint violations were detected.');
return false;
for (const fileResult of results) {
for (const message of fileResult.messages) {
if (message.severity === 2) {
hasBlockingErrors = true;
}
}
}
} catch (err) {
console.error(`\n[ERROR] Failed running ESLint in ${pkgDir}:`, err.message);
hasBlockingErrors = true;
}
}

return true;
} catch (err) {
console.error('\n[ERROR] Failed running ESLint:', err.message);
if (hasBlockingErrors) {
console.error('\n[ERROR] ESLint violations were detected.');
return false;
}

return true;
}

// --- TypeScript Type Checker ---
Expand All @@ -166,14 +237,23 @@ async function checkEslint(filesToCheck) {
* Caches directories to avoid redundant disk operations.
*/
function findTsconfigDir(filePath) {
const dir = path.dirname(filePath);
if (tsconfigCache.has(dir)) {
return tsconfigCache.get(dir);
let currentDir = path.resolve(path.dirname(filePath));
const root = path.parse(currentDir).root;

while (currentDir && currentDir !== root) {
if (tsconfigCache.has(currentDir)) {
return tsconfigCache.get(currentDir);
}
const candidate = path.join(currentDir, 'tsconfig.json');
if (existsSync(candidate)) {
tsconfigCache.set(path.dirname(filePath), currentDir);
return currentDir;
}
currentDir = path.dirname(currentDir);
}
const configPath = ts.findConfigFile(dir, ts.sys.fileExists);
const result = configPath ? path.dirname(configPath) : null;
tsconfigCache.set(dir, result);
return result;

tsconfigCache.set(path.dirname(filePath), null);
return null;
}

/**
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
{
"extends": "./node_modules/gts/"
"extends": "gts"
}
3 changes: 1 addition & 2 deletions core/generator/gapic-generator-typescript/.eslintrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,4 @@
"**/.coverage",
"**/coverage"
]
}

}
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
{
"extends": "./node_modules/gts"
"extends": "gts"
}
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
{
"extends": "./node_modules/gts"
"extends": "gts"
}
3 changes: 0 additions & 3 deletions core/packages/gaxios/.eslintrc.json

This file was deleted.

3 changes: 0 additions & 3 deletions core/packages/google-auth-library-nodejs/.eslintrc.json

This file was deleted.

4 changes: 0 additions & 4 deletions core/packages/logging-utils/.eslintrc.json

This file was deleted.

3 changes: 0 additions & 3 deletions core/packages/nodejs-googleapis-common/.eslintrc.json

This file was deleted.

3 changes: 0 additions & 3 deletions core/packages/nodejs-proto-files/.eslintrc.json

This file was deleted.

3 changes: 0 additions & 3 deletions core/packages/retry-request/.eslintrc.json

This file was deleted.

3 changes: 0 additions & 3 deletions core/packages/teeny-request/.eslintrc.json

This file was deleted.

4 changes: 0 additions & 4 deletions core/packages/tools/.eslintrc.json

This file was deleted.

3 changes: 0 additions & 3 deletions handwritten/bigquery-storage/.eslintrc.json

This file was deleted.

2 changes: 1 addition & 1 deletion handwritten/bigquery-storage/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
"prelint": "cd samples; npm link ../; npm install",
"lint": "gts check",
"prepare": "npm run compile",
"system-test": "c8 mocha build/system-test",
"system-test": "c8 mocha build/system-test --timeout 600000",
"test": "c8 mocha build/test",
"samples-test": "cd samples/ && npm link ../ && npm test && cd ../",
"precompile": "gts clean"
Expand Down
1 change: 0 additions & 1 deletion handwritten/bigquery/.eslintignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,3 @@ build/
docs/
protos/
samples/generated/
system-test/fixtures
Loading
Loading