Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
25 changes: 25 additions & 0 deletions .eslintrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
{
"parserOptions": {
"ecmaVersion": 2022,
"sourceType": "script"
},
"env": {
"browser": true,
"jquery": true,
"es2022": true
},
"rules": {
"no-const-assign": "error",
"no-redeclare": "error",
"no-dupe-args": "error",
"no-dupe-keys": "error",
"no-dupe-class-members": "error",
"no-unreachable": "error",
"no-self-assign": "error",
"no-self-compare": "error",
"no-unsafe-negation": "error",
"no-unsafe-finally": "error",
"no-undef": "off",
"no-unused-vars": "off"
}
}
109 changes: 109 additions & 0 deletions .github/scripts/eslint-baseline-check.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
#!/usr/bin/env node
/**
* ESLint baseline checker for Jeedom core.
*
* Runs ESLint on JS sources, compares results against eslint-baseline.json,
* and fails if a new violation appears (i.e. a new {file, ruleId, message}
* tuple not present in the baseline). Allows existing violations to
* disappear (e.g. when a fix lands).
*
* Usage:
* node .github/scripts/eslint-baseline-check.js # check
* node .github/scripts/eslint-baseline-check.js --update # regenerate baseline
*/

const { spawnSync } = require('child_process');
const fs = require('fs');
const path = require('path');

const ROOT = path.resolve(__dirname, '..', '..');
const BASELINE_PATH = path.join(ROOT, 'eslint-baseline.json');
const TARGETS = ['core/js', 'desktop/js'];

function runEslint() {
const eslintBin = path.join(ROOT, 'node_modules', '.bin', 'eslint');
const result = spawnSync(eslintBin, ['-f', 'json', ...TARGETS], {
cwd: ROOT,
encoding: 'utf8',
maxBuffer: 50 * 1024 * 1024
});
if (result.error) {
console.error('Failed to spawn ESLint:', result.error);
process.exit(2);
}
// ESLint exits non-zero when it finds errors; that's fine, we still parse stdout.
if (!result.stdout) {
console.error('ESLint produced no output. stderr:', result.stderr);
process.exit(2);
}
return JSON.parse(result.stdout);
}

function normalize(report) {
const entries = [];
for (const file of report) {
const rel = path.relative(ROOT, file.filePath).replace(/\\/g, '/');
for (const msg of file.messages || []) {
if (msg.severity !== 2) continue;
entries.push({
file: rel,
ruleId: msg.ruleId,
message: msg.message
});
}
}
entries.sort((a, b) =>
(a.file + (a.ruleId || '') + a.message).localeCompare(
b.file + (b.ruleId || '') + b.message
)
);
return entries;
}

function tupleKey(e) {
return `${e.file}|${e.ruleId || ''}|${e.message}`;
}

function loadBaseline() {
if (!fs.existsSync(BASELINE_PATH)) return [];
return JSON.parse(fs.readFileSync(BASELINE_PATH, 'utf8'));
}

function main() {
const update = process.argv.includes('--update');
const current = normalize(runEslint());

if (update) {
fs.writeFileSync(BASELINE_PATH, JSON.stringify(current, null, 2) + '\n');
console.log(`Baseline updated: ${current.length} entries written to eslint-baseline.json`);
return;
}

const baseline = loadBaseline();
const baselineKeys = new Set(baseline.map(tupleKey));
const currentKeys = new Set(current.map(tupleKey));

const added = current.filter(e => !baselineKeys.has(tupleKey(e)));
const removed = baseline.filter(e => !currentKeys.has(tupleKey(e)));

console.log(`Baseline: ${baseline.length} entries`);
console.log(`Current: ${current.length} entries`);
console.log(`Removed: ${removed.length} entries (fixes welcome)`);
console.log(`Added: ${added.length} entries`);

if (added.length > 0) {
console.error('\nNew ESLint violations not present in baseline:');
for (const e of added) {
console.error(` ${e.file}: [${e.ruleId}] ${e.message}`);
}
console.error(
'\nFix these violations or, if intentional, regenerate the baseline:\n' +
' npm run lint:baseline'
);
process.exit(1);
}

console.log('\nNo new violations. ');
}

main();
75 changes: 75 additions & 0 deletions .github/workflows/eslint.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
name: ESLint

on:
push:
branches: [ develop ]
pull_request:
branches: [ develop ]

jobs:
eslint:
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v4

- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'

- name: Install dependencies
run: npm ci || npm install

- name: Run ESLint baseline check
run: npm run lint:check

update-baseline:
needs: eslint
if: github.event_name == 'push' && github.ref == 'refs/heads/develop'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0

- name: Delete existing branch if exists
run: |
if git ls-remote --heads origin update-eslint-baseline | grep -q update-eslint-baseline; then
git push origin --delete update-eslint-baseline
fi

- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20'

- name: Install dependencies
run: npm ci || npm install

- name: Regenerate baseline
id: regen
run: |
cp eslint-baseline.json eslint-baseline.json.old
npm run lint:baseline
if ! diff -q eslint-baseline.json eslint-baseline.json.old > /dev/null; then
echo "baseline_changed=true" >> $GITHUB_OUTPUT
fi
rm -f eslint-baseline.json.old

- name: Create Pull Request
if: steps.regen.outputs.baseline_changed == 'true'
uses: peter-evans/create-pull-request@v5
with:
commit-message: '[skip ci] Update ESLint baseline'
title: '[CI] Update ESLint baseline'
body: |
Mise à jour automatique du baseline ESLint suite à la correction d'erreurs.

Cette PR a été générée automatiquement par le workflow CI.
branch: update-eslint-baseline
base: develop
delete-branch: true
add-paths: |
eslint-baseline.json
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -47,3 +47,4 @@ tmp/*
.env
.phpstan.cache
phpstan.phar
node_modules/
Loading
Loading