diff options
author | Florian Müllner <fmuellner@gnome.org> | 2022-02-17 22:54:22 +0100 |
---|---|---|
committer | Marge Bot <marge-bot@gnome.org> | 2023-04-21 18:28:32 +0000 |
commit | 0a420404c6035b66706c5b5747e9f04d64a75e6f (patch) | |
tree | 682300e3f2784cc7f94664d908614696b3169c1c | |
parent | ddae41456dff308d6ba2bd7fd47033b5eb6d5e4b (diff) | |
download | gnome-shell-0a420404c6035b66706c5b5747e9f04d64a75e6f.tar.gz |
ci: Update JS tooling
Provided we use the correct version of the SpiderMonkey shell, we
can perform checks using the same engine that is used by gjs.
However some engine features are opt-in, so the set of features enabled
by gjs and js102 may differ. The obvious option for avoiding this is
replacing js102 with gjs for tests.
For that reason the check-potfiles.js script has been ported to gjs
and a second (simpler) script to replace `js102 --compileonly` was
added. This work happened in a separate repository to make sharing
between different JS-based projects easier.
Update the CI image to pull in those scripts and include gjs.
This will also address the issue that `js102 --compileonly` does not
handle modules.
Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell/-/merge_requests/2193>
-rw-r--r-- | .gitlab-ci.yml | 24 | ||||
-rw-r--r-- | .gitlab-ci/check-potfiles.js | 207 |
2 files changed, 14 insertions, 217 deletions
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 0fba285bc..db4a4a8b2 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -28,7 +28,6 @@ default: variables: FDO_UPSTREAM_REPO: GNOME/gnome-shell BUNDLE: "extensions-git.flatpak" - JS_LOG: "js-report.txt" LINT_LOG: "eslint-report.xml" LINT_MR_LOG: "eslint-mr-report.xml" @@ -49,13 +48,13 @@ workflow: .gnome-shell.fedora: variables: FDO_DISTRIBUTION_VERSION: 38 - FDO_DISTRIBUTION_TAG: '2023-04-20.0' + FDO_DISTRIBUTION_TAG: '2023-04-21.1' FDO_DISTRIBUTION_PACKAGES: - findutils - mozjs102-devel + gjs nodejs npm meson + pkgconfig(gobject-introspection-1.0) pkgconfig(gio-2.0) pkgconfig(gio-unix-2.0) pkgconfig(gnome-autoar-0) @@ -68,6 +67,10 @@ workflow: 'C Development Tools and Libraries' && ./.gitlab-ci/install-meson-project.sh \ + https://gitlab.gnome.org/fmuellner/gjs-ci-tools.git \ + main && + + ./.gitlab-ci/install-meson-project.sh \ --subdir subprojects/extensions-tool/ \ --prepare ./generate-translations.sh \ -Dman=false \ @@ -126,12 +129,10 @@ js_check: - .gnome-shell.fedora stage: review script: - - find js -name '*.js' $(printf "! -wholename %s " $(cat .jscheckignore)) -exec js102 -c '{}' ';' 2>&1 | tee $JS_LOG - - (! grep -q . $JS_LOG) + - gjs-check-syntax artifacts: - paths: - - ${JS_LOG} - when: on_failure + reports: + junit: gjs-check-syntax.junit.xml eslint: extends: @@ -177,7 +178,10 @@ potfile_js_check: - .gnome-shell.fedora stage: review script: - - js102 -m .gitlab-ci/check-potfiles.js + - gjs-check-potfiles + artifacts: + reports: + junit: gjs-check-potfiles.junit.xml build: stage: build diff --git a/.gitlab-ci/check-potfiles.js b/.gitlab-ci/check-potfiles.js deleted file mode 100644 index 0c8885e25..000000000 --- a/.gitlab-ci/check-potfiles.js +++ /dev/null @@ -1,207 +0,0 @@ -const gettextFuncs = new Set([ - '_', - 'N_', - 'C_', - 'NC_', - 'dcgettext', - 'dgettext', - 'dngettext', - 'dpgettext', - 'gettext', - 'ngettext', - 'pgettext', -]); - -function dirname(file) { - const split = file.split('/'); - split.pop(); - return split.join('/'); -} - -const scriptDir = dirname(import.meta.url); -const root = dirname(scriptDir); - -const excludedFiles = new Set(); -const foundFiles = new Set() - -function addExcludes(filename) { - const contents = os.file.readFile(filename); - const lines = contents.split('\n') - .filter(l => l && !l.startsWith('#')); - lines.forEach(line => excludedFiles.add(line)); -} - -addExcludes(`${root}/po/POTFILES.in`); -addExcludes(`${root}/po/POTFILES.skip`); - -function walkAst(node, func) { - func(node); - nodesToWalk(node).forEach(n => walkAst(n, func)); -} - -function findGettextCalls(node) { - switch(node.type) { - case 'CallExpression': - if (node.callee.type === 'Identifier' && - gettextFuncs.has(node.callee.name)) - throw new Error(); - if (node.callee.type === 'MemberExpression' && - node.callee.object.type === 'Identifier' && - node.callee.object.name === 'Gettext' && - node.callee.property.type === 'Identifier' && - gettextFuncs.has(node.callee.property.name)) - throw new Error(); - break; - } - return true; -} - -function nodesToWalk(node) { - switch(node.type) { - case 'ArrayPattern': - case 'BreakStatement': - case 'CallSiteObject': // i.e. strings passed to template - case 'ContinueStatement': - case 'DebuggerStatement': - case 'EmptyStatement': - case 'Identifier': - case 'Literal': - case 'MetaProperty': // i.e. new.target - case 'Super': - case 'ThisExpression': - return []; - case 'ArrowFunctionExpression': - case 'FunctionDeclaration': - case 'FunctionExpression': - return [...node.defaults, node.body].filter(n => !!n); - case 'AssignmentExpression': - case 'BinaryExpression': - case 'ComprehensionBlock': - case 'LogicalExpression': - return [node.left, node.right]; - case 'ArrayExpression': - case 'TemplateLiteral': - return node.elements.filter(n => !!n); - case 'BlockStatement': - case 'Program': - return node.body; - case 'StaticClassBlock': - return [node.body]; - case 'ClassField': - return [node.name, node.init]; - case 'CallExpression': - case 'NewExpression': - case 'OptionalCallExpression': - case 'TaggedTemplate': - return [node.callee, ...node.arguments]; - case 'CatchClause': - return [node.body, node.guard].filter(n => !!n); - case 'ClassExpression': - case 'ClassStatement': - return [...node.body, node.superClass].filter(n => !!n); - case 'ClassMethod': - return [node.name, node.body]; - case 'ComprehensionExpression': - case 'GeneratorExpression': - return [node.body, ...node.blocks, node.filter].filter(n => !!n); - case 'ComprehensionIf': - return [node.test]; - case 'ComputedName': - return [node.name]; - case 'ConditionalExpression': - case 'IfStatement': - return [node.test, node.consequent, node.alternate].filter(n => !!n); - case 'DoWhileStatement': - case 'WhileStatement': - return [node.body, node.test]; - case 'ExportDeclaration': - return [node.declaration, node.source].filter(n => !!n); - case 'ImportDeclaration': - return [...node.specifiers, node.source]; - case 'LetStatement': - return [...node.head, node.body]; - case 'ExpressionStatement': - return [node.expression]; - case 'ForInStatement': - case 'ForOfStatement': - return [node.body, node.left, node.right]; - case 'ForStatement': - return [node.init, node.test, node.update, node.body].filter(n => !!n); - case 'LabeledStatement': - return [node.body]; - case 'MemberExpression': - return [node.object, node.property]; - case 'ObjectExpression': - case 'ObjectPattern': - return node.properties; - case 'OptionalExpression': - return [node.expression]; - case 'OptionalMemberExpression': - return [node.object, node.property]; - case 'Property': - case 'PrototypeMutation': - return [node.value]; - case 'ReturnStatement': - case 'ThrowStatement': - case 'UnaryExpression': - case 'UpdateExpression': - case 'YieldExpression': - return node.argument ? [node.argument] : []; - case 'SequenceExpression': - return node.expressions; - case 'SpreadExpression': - return [node.expression]; - case 'SwitchCase': - return [node.test, ...node.consequent].filter(n => !!n); - case 'SwitchStatement': - return [node.discriminant, ...node.cases]; - case 'TryStatement': - return [node.block, node.handler, node.finalizer].filter(n => !!n); - case 'VariableDeclaration': - return node.declarations; - case 'VariableDeclarator': - return node.init ? [node.init] : []; - case 'WithStatement': - return [node.object, node.body]; - default: - print(`Ignoring ${node.type}, you should probably fix this in the script`); - } -} - -function walkDir(dir) { - os.file.listDir(dir).forEach(child => { - if (child.startsWith('.')) - return; - - const path = os.path.join(dir, child); - const relativePath = path.replace(`${root}/`, ''); - if (excludedFiles.has(relativePath)) - return; - - if (!child.endsWith('.js')) { - try { - walkDir(path); - } catch (e) { - // not a directory - } - return; - } - - try { - const script = os.file.readFile(path); - const ast = Reflect.parse(script); - walkAst(ast, findGettextCalls); - } catch (e) { - foundFiles.add(path); - } - }); -} - -walkDir(root); - -if (foundFiles.size === 0) - quit(0); - -print('The following files are missing from po/POTFILES.in:') -foundFiles.forEach(f => print(` ${f}`)); -quit(1); |