8c13e3855e
This is unnecessary hard in shell when compared to a proper programming language. It becomes even easier with a node-js script, as that gives us access to the underlying ESLint module rather than just the CLI interface. Besides that, node-js has the added benefit that we don't need to add more dependencies to the CI image. https://gitlab.gnome.org/GNOME/gnome-shell/-/merge_requests/1497
129 lines
3.8 KiB
JavaScript
Executable File
129 lines
3.8 KiB
JavaScript
Executable File
#!/usr/bin/env node
|
|
|
|
const { ESLint } = require('eslint');
|
|
const fs = require('fs');
|
|
const path = require('path');
|
|
const { spawn } = require('child_process');
|
|
|
|
function createConfig(config) {
|
|
const options = {
|
|
cache: true,
|
|
cacheLocation: `.eslintcache-${config}`,
|
|
};
|
|
|
|
if (config === 'legacy')
|
|
options.overrideConfigFile='lint/eslintrc-legacy.yml';
|
|
|
|
return new ESLint(options);
|
|
}
|
|
|
|
function git(...args) {
|
|
const git = spawn('git', args, { stdio: ['ignore', null, 'ignore'] });
|
|
git.stdout.setEncoding('utf8');
|
|
|
|
return new Promise(resolve => {
|
|
let out = '';
|
|
git.stdout.on('data', chunk => out += chunk);
|
|
git.stdout.on('end', () => resolve(out.trim()));
|
|
});
|
|
}
|
|
|
|
function createCommon(report1, report2, ignoreColumn=false) {
|
|
return report1.map(result => {
|
|
const { filePath, messages } = result;
|
|
const match =
|
|
report2.find(r => r.filePath === filePath) || { messages: [] };
|
|
|
|
const filteredMessages = messages.filter(
|
|
msg => match.messages.some(
|
|
m => m.line === msg.line && (ignoreColumn || m.column === msg.column)));
|
|
|
|
const [errorCount, warningCount] = filteredMessages.reduce(
|
|
([e, w], msg) => {
|
|
return [
|
|
e + Number(msg.severity === 2),
|
|
w + Number(msg.severity === 1)];
|
|
}, [0, 0]);
|
|
|
|
return {
|
|
filePath,
|
|
messages: filteredMessages,
|
|
errorCount,
|
|
warningCount,
|
|
};
|
|
});
|
|
}
|
|
|
|
async function getMergeRequestChanges(remote, branch) {
|
|
await git('fetch', remote, branch);
|
|
const branchPoint = await git('merge-base', 'HEAD', 'FETCH_HEAD');
|
|
const diff = await git('diff', '-U0', `${branchPoint}...HEAD`);
|
|
|
|
const report = [];
|
|
let messages = null;
|
|
for (const line of diff.split('\n')) {
|
|
if (line.startsWith('+++ b/')) {
|
|
const filePath = path.resolve(line.substring(6));
|
|
messages = filePath.endsWith('.js') ? [] : null;
|
|
if (messages)
|
|
report.push({ filePath, messages });
|
|
} else if (messages && line.startsWith('@@ ')) {
|
|
[, , changes] = line.split(' ');
|
|
[start, count] = `${changes},1`.split(',').map(i => parseInt(i));
|
|
for (let i = start; i < start + count; i++)
|
|
messages.push({ line: i });
|
|
}
|
|
}
|
|
|
|
return report;
|
|
}
|
|
|
|
function getOption(...names) {
|
|
const optIndex =
|
|
process.argv.findIndex(arg => names.includes(arg)) + 1;
|
|
|
|
if (optIndex === 0)
|
|
return undefined;
|
|
|
|
return process.argv[optIndex];
|
|
}
|
|
|
|
(async function main() {
|
|
const outputOption = getOption('--output-file', '-o');
|
|
const outputPath = outputOption ? path.resolve(outputOption) : null;
|
|
|
|
const sourceDir = path.dirname(process.argv[1]);
|
|
process.chdir(path.resolve(sourceDir, '..'));
|
|
|
|
const remote = getOption('--remote') || 'origin';
|
|
const branch = getOption('--branch', '-b');
|
|
|
|
const sources = ['js', 'subprojects/extensions-app/js'];
|
|
const regular = createConfig('regular');
|
|
|
|
const ops = [];
|
|
ops.push(regular.lintFiles(sources));
|
|
if (branch)
|
|
ops.push(getMergeRequestChanges(remote, branch));
|
|
else
|
|
ops.push(createConfig('legacy').lintFiles(sources));
|
|
|
|
const results = await Promise.all(ops);
|
|
const commonResults = createCommon(...results, branch !== undefined);
|
|
|
|
const formatter = await regular.loadFormatter();
|
|
const resultText = formatter.format(commonResults);
|
|
|
|
if (outputPath) {
|
|
fs.mkdirSync(path.dirname(outputPath), { recursive: true });
|
|
fs.writeFileSync(outputPath, resultText);
|
|
} else {
|
|
console.log(resultText);
|
|
}
|
|
|
|
process.exitCode = commonResults.some(r => r.errorCount > 0) ? 1 : 0;
|
|
})().catch((error) => {
|
|
process.exitCode = 1;
|
|
console.error(error);
|
|
});
|