[gnome-shell] ci: Use node-js script for running eslint
- From: Florian Müllner <fmuellner src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-shell] ci: Use node-js script for running eslint
- Date: Fri, 13 Nov 2020 21:45:08 +0000 (UTC)
commit 8c13e3855e0adae812d812aa05e7b3d28d25160b
Author: Florian Müllner <fmuellner gnome org>
Date: Sat Nov 7 07:11:09 2020 +0100
ci: Use node-js script for running eslint
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
.gitlab-ci.yml | 6 ++-
.gitlab-ci/run-eslint | 128 +++++++++++++++++++++++++++++++++++++++++++++++
.gitlab-ci/run-eslint.sh | 116 ------------------------------------------
3 files changed, 132 insertions(+), 118 deletions(-)
---
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index adad8f958d..52e60764d7 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -9,6 +9,7 @@ stages:
variables:
BUNDLE: "extensions-git.flatpak"
JS_LOG: "js-report.txt"
+ LINT_LOG: "eslint-report.txt"
.only_default: &only_default
only:
@@ -42,11 +43,12 @@ eslint:
image: registry.gitlab.gnome.org/gnome/gnome-shell/extension-ci:v2
stage: review
script:
- - ./.gitlab-ci/run-eslint.sh
+ - export NODE_PATH=$(npm root -g)
+ - ./.gitlab-ci/run-eslint --output-file ${LINT_LOG}
<<: *only_default
artifacts:
paths:
- - reports
+ - ${LINT_LOG}
when: always
potfile_check:
diff --git a/.gitlab-ci/run-eslint b/.gitlab-ci/run-eslint
new file mode 100755
index 0000000000..68a664109f
--- /dev/null
+++ b/.gitlab-ci/run-eslint
@@ -0,0 +1,128 @@
+#!/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);
+});
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]