chore: Add a lint step for field name constants (#32769)

We have a small linter NodeJS script that checks if any field name
constants are defined incorrectly. This PR adds this linter to the build
script, so it'll be run in CI.
This commit is contained in:
Shrikant Sharat Kandula 2024-04-19 10:01:09 +05:30 committed by GitHub
parent 7a50b9095f
commit 97e3791d3a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 45 additions and 13 deletions

View File

@ -34,6 +34,7 @@ if [[ -f .env ]]; then
source .env source .env
fi fi
node scripts/check-field-constants.mjs
# Build the code. $@ accepts all the parameters from the input command line and uses it in the maven build command # Build the code. $@ accepts all the parameters from the input command line and uses it in the maven build command
mvn clean package "$@" mvn clean package "$@"

View File

@ -1,7 +1,13 @@
/**
* This script checks if the field constants in the Java files are named and defined correctly.
*/
import {promises as fs} from "fs"; import {promises as fs} from "fs";
import path from "path"; import path from "path";
async function findInnerClassDefinitions(directory) { async function findInnerClassDefinitions(directory) {
let isPass = true;
try { try {
const files = await fs.readdir(directory); const files = await fs.readdir(directory);
@ -10,29 +16,37 @@ async function findInnerClassDefinitions(directory) {
const stats = await fs.stat(filePath); const stats = await fs.stat(filePath);
if (stats.isDirectory()) { if (stats.isDirectory()) {
await findInnerClassDefinitions(filePath); if (!await findInnerClassDefinitions(filePath)) {
} else if (path.extname(filePath) === '.java') { isPass = false;
await processJavaFile(filePath); }
} else if (path.extname(filePath) === ".java") {
if (!await processJavaFile(filePath)) {
isPass = false;
}
} }
} }
} catch (err) { } catch (err) {
console.error(err); console.error(err);
isPass = false;
} }
return isPass;
} }
async function processJavaFile(filePath) { async function processJavaFile(filePath) {
let isPass = true;
try { try {
const contents = await fs.readFile(filePath, 'utf8'); const contents = await fs.readFile(filePath, "utf8");
const innerClassRegex = /^ {4}([\w ]+?)\s+class\s+Fields\s+(extends (\w+)\.Fields)?\s*{(.+?\n {4})?}$/gsm; const innerClassRegex = /^ {4}([\w ]+?)\s+class\s+Fields\s+(extends (\w+)\.Fields)?\s*{(.+?\n {4})?}$/gsm;
for (const innerClassMatch of contents.matchAll(innerClassRegex)) { for (const innerClassMatch of contents.matchAll(innerClassRegex)) {
const classQualifiers = innerClassMatch[1]; // we don't care much about this const classQualifiers = innerClassMatch[1]; // we don't care much about this
const expectedParentClass = innerClassMatch[3]; const expectedParentClass = innerClassMatch[3];
console.log(filePath, classQualifiers, expectedParentClass);
for (const match of innerClassMatch[0].matchAll(/\bpublic\s+static\s+final\s+String\s+(\w+)\s+=\s+(.+?);/gs)) { for (const match of innerClassMatch[0].matchAll(/\bpublic\s+static\s+final\s+String\s+(\w+)\s+=\s+(.+?);/gs)) {
const key = match[1] const key = match[1];
const valMatcherParts = [`^dotted\\(`]; const valMatcherParts = [`^dotted\\(`];
for (const [i, field] of key.split("_").entries()) { for (const [i, field] of key.split("_").entries()) {
if (i > 0) { if (i > 0) {
@ -41,12 +55,14 @@ async function processJavaFile(filePath) {
valMatcherParts.push(`(\\w+\\.\\w+\\.)?${field}`); valMatcherParts.push(`(\\w+\\.\\w+\\.)?${field}`);
} }
valMatcherParts.push(`\\s*\\)$`); valMatcherParts.push(`\\s*\\)$`);
const valMatcher = new RegExp(valMatcherParts.join('')); const valMatcher = new RegExp(valMatcherParts.join(""));
if (!valMatcher.test(match[2])) { if (!valMatcher.test(match[2])) {
console.log("key is", key); console.log(filePath, classQualifiers, expectedParentClass);
console.log("val is", match[2]); console.log("\tkey is", key);
console.log("pattern", valMatcher); console.log("\tval is", match[2]);
console.error(`Field ${key} in ${filePath} is not looking right.`); console.log("\tpattern", valMatcher);
console.error(`\tField ${key} in ${filePath} is not looking right.`);
isPass = false;
} }
} }
} }
@ -58,8 +74,23 @@ async function processJavaFile(filePath) {
} catch (err) { } catch (err) {
console.error(err); console.error(err);
} isPass = false;
} }
const directoryPath = '.'; return isPass;
findInnerClassDefinitions(directoryPath); }
// Can't use `import.meta.dirname` because it's not available in Node.js 18.
// And v18 is what is included in GitHub Actions today.
// See <https://github.com/actions/runner-images/blob/main/images/ubuntu/Ubuntu2204-Readme.md#language-and-runtime>.
const directoryPath = import.meta.resolve("..").replace("file://", "");
findInnerClassDefinitions(directoryPath)
.then(isPass => {
if (isPass) {
console.log("All okay.");
} else {
console.error("Some field constants are not looking good.");
process.exitCode = 1;
}
});