mirror of
https://github.com/monkeytypegame/monkeytype.git
synced 2025-09-11 17:16:40 +08:00
Pr-check
This commit is contained in:
parent
a478128bc5
commit
432fedb3c0
4 changed files with 283 additions and 216 deletions
45
.github/workflows/pr-check.yml
vendored
45
.github/workflows/pr-check.yml
vendored
|
@ -11,11 +11,24 @@ jobs:
|
|||
- uses: actions/checkout@v2
|
||||
|
||||
- uses: dorny/paths-filter@v2
|
||||
id: changes
|
||||
id: filter
|
||||
with:
|
||||
filters: |
|
||||
json:
|
||||
any-json:
|
||||
- 'frontend/**/*.json'
|
||||
language-json:
|
||||
- 'frontend/static/languages/*.json'
|
||||
quotes-json:
|
||||
- 'frontend/static/quotes/*.json'
|
||||
other-json:
|
||||
- 'frontend/funbox/*.json'
|
||||
- 'frontend/fonts/*.json'
|
||||
- 'frontend/themes/*.json'
|
||||
- 'frontend/challenges/*.json'
|
||||
any-tsscss:
|
||||
- 'frontend/**/*.scss'
|
||||
- 'frontend/**/*.js'
|
||||
- 'frontend/**/*.ts'
|
||||
scss:
|
||||
- 'frontend/**/*.scss'
|
||||
ts:
|
||||
|
@ -45,14 +58,30 @@ jobs:
|
|||
# - name: Run webpack
|
||||
# run: npm run build:live
|
||||
|
||||
- name: Lint and validate JSON
|
||||
if: steps.filter.outputs.json == 'true'
|
||||
run: npm run pr-check-json
|
||||
- name: Lint JSON
|
||||
if: steps.filter.outputs.any-json == 'true'
|
||||
run: npm run pr-check-lint-json
|
||||
|
||||
- name: Lint and compile SCSS
|
||||
- name: Validate languages JSON
|
||||
if: steps.filter.outputs.language-json == 'true'
|
||||
run: npm run pr-check-language-json
|
||||
|
||||
- name: Validate quotes JSON
|
||||
if: steps.filter.outputs.quotes-json == 'true'
|
||||
run: npm run pr-check-quote-json
|
||||
|
||||
- name: Validate other JSON
|
||||
if: steps.filter.outputs.other-json == 'true'
|
||||
run: npm run pr-check-other-json
|
||||
|
||||
- name: Lint
|
||||
if: steps.filter.outputs.any-tsscss == 'true'
|
||||
run: npm run pr-check-lint-json
|
||||
|
||||
- name: Compile SCSS
|
||||
if: steps.filter.outputs.scss == 'true'
|
||||
run: npm run pr-check-scss
|
||||
|
||||
- name: Lint source code and run webpack
|
||||
if: steps.filter.outputs.scss == 'true'
|
||||
- name: Run webpack
|
||||
if: steps.filter.outputs.ts == 'true'
|
||||
run: npm run pr-check-ts
|
||||
|
|
|
@ -36,7 +36,7 @@ task("lint-json", function () {
|
|||
});
|
||||
|
||||
task("validate-json-schema", function () {
|
||||
return JSONValidation.validate();
|
||||
return JSONValidation.validateAll();
|
||||
});
|
||||
|
||||
task("copy-src-contents", function () {
|
||||
|
@ -150,8 +150,26 @@ task("build", series("clean", "compile"));
|
|||
|
||||
task("build-production", series("clean", "compile-production"));
|
||||
|
||||
task("pr-check-json", series("lint-json", "validate-json-schema"));
|
||||
//PR CHECK
|
||||
|
||||
task("pr-check-scss", series("lint", "sass"));
|
||||
task("validate-quote-json-schema", function () {
|
||||
return JSONValidation.validateQuotes();
|
||||
});
|
||||
|
||||
task("pr-check-ts", series("lint", "webpack-production"));
|
||||
task("validate-language-json-schema", function () {
|
||||
return JSONValidation.validateLanguages();
|
||||
});
|
||||
|
||||
task("validate-other-json-schema", function () {
|
||||
return JSONValidation.validateOthers();
|
||||
});
|
||||
|
||||
task("pr-check-lint-json", series("lint-json"));
|
||||
task("pr-check-quote-json", series("validate-quote-json-schema"));
|
||||
task("pr-check-language-json", series("validate-language-json-schema"));
|
||||
task("pr-check-other-json", series("validate-other-json-schema"));
|
||||
|
||||
task("pr-check-lint", series("lint"));
|
||||
task("pr-check-scss", series("sass"));
|
||||
|
||||
task("pr-check-ts", series("webpack-production"));
|
||||
|
|
|
@ -6,7 +6,7 @@ function escapeRegExp(str) {
|
|||
return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
||||
}
|
||||
|
||||
function validate() {
|
||||
function validateOthers() {
|
||||
return new Promise((resolve, reject) => {
|
||||
//fonts
|
||||
const fontsData = JSON.parse(
|
||||
|
@ -90,207 +90,6 @@ function validate() {
|
|||
return reject(new Error(themesValidator.errors));
|
||||
}
|
||||
|
||||
//languages
|
||||
const languagesData = JSON.parse(
|
||||
fs.readFileSync("./static/languages/_list.json", {
|
||||
encoding: "utf8",
|
||||
flag: "r",
|
||||
})
|
||||
);
|
||||
const languagesSchema = {
|
||||
type: "array",
|
||||
items: {
|
||||
type: "string",
|
||||
},
|
||||
};
|
||||
const languagesValidator = JSONValidator.validate(
|
||||
languagesData,
|
||||
languagesSchema
|
||||
);
|
||||
if (languagesValidator.valid) {
|
||||
console.log("Languages list JSON schema is \u001b[32mvalid\u001b[0m");
|
||||
} else {
|
||||
console.log("Languages list JSON schema is \u001b[31minvalid\u001b[0m");
|
||||
return reject(new Error(languagesValidator.errors));
|
||||
}
|
||||
|
||||
//languages group
|
||||
const languagesGroupData = JSON.parse(
|
||||
fs.readFileSync("./static/languages/_groups.json", {
|
||||
encoding: "utf8",
|
||||
flag: "r",
|
||||
})
|
||||
);
|
||||
const languagesGroupSchema = {
|
||||
type: "array",
|
||||
items: {
|
||||
type: "object",
|
||||
properties: {
|
||||
name: { type: "string" },
|
||||
languages: {
|
||||
type: "array",
|
||||
items: {
|
||||
type: "string",
|
||||
},
|
||||
},
|
||||
},
|
||||
required: ["name", "languages"],
|
||||
},
|
||||
};
|
||||
const languagesGroupValidator = JSONValidator.validate(
|
||||
languagesGroupData,
|
||||
languagesGroupSchema
|
||||
);
|
||||
if (languagesGroupValidator.valid) {
|
||||
console.log("Languages groups JSON schema is \u001b[32mvalid\u001b[0m");
|
||||
} else {
|
||||
console.log("Languages groups JSON schema is \u001b[31minvalid\u001b[0m");
|
||||
return reject(new Error(languagesGroupValidator.errors));
|
||||
}
|
||||
|
||||
//language files
|
||||
const languageFileSchema = {
|
||||
type: "object",
|
||||
properties: {
|
||||
name: { type: "string" },
|
||||
leftToRight: { type: "boolean" },
|
||||
noLazyMode: { type: "boolean" },
|
||||
bcp47: { type: "string" },
|
||||
words: {
|
||||
type: "array",
|
||||
items: { type: "string", minLength: 1 },
|
||||
},
|
||||
accents: {
|
||||
type: "array",
|
||||
items: {
|
||||
type: "array",
|
||||
items: { type: "string", minLength: 1 },
|
||||
minItems: 2,
|
||||
maxItems: 2,
|
||||
},
|
||||
},
|
||||
},
|
||||
required: ["name", "leftToRight", "words"],
|
||||
};
|
||||
let languageFilesAllGood = true;
|
||||
let languageFilesErrors;
|
||||
languagesData.forEach((language) => {
|
||||
const languageFileData = JSON.parse(
|
||||
fs.readFileSync(`./static/languages/${language}.json`, {
|
||||
encoding: "utf8",
|
||||
flag: "r",
|
||||
})
|
||||
);
|
||||
languageFileSchema.properties.name.pattern =
|
||||
"^" + escapeRegExp(language) + "$";
|
||||
const languageFileValidator = JSONValidator.validate(
|
||||
languageFileData,
|
||||
languageFileSchema
|
||||
);
|
||||
if (!languageFileValidator.valid) {
|
||||
languageFilesAllGood = false;
|
||||
languageFilesErrors = languageFileValidator.errors;
|
||||
}
|
||||
});
|
||||
if (languageFilesAllGood) {
|
||||
console.log(
|
||||
`Language word list JSON schemas are \u001b[32mvalid\u001b[0m`
|
||||
);
|
||||
} else {
|
||||
console.log(
|
||||
`Language word list JSON schemas are \u001b[31minvalid\u001b[0m`
|
||||
);
|
||||
return reject(new Error(languageFilesErrors));
|
||||
}
|
||||
|
||||
//quotes
|
||||
const quoteSchema = {
|
||||
type: "object",
|
||||
properties: {
|
||||
language: { type: "string" },
|
||||
groups: {
|
||||
type: "array",
|
||||
items: {
|
||||
type: "array",
|
||||
items: {
|
||||
type: "number",
|
||||
},
|
||||
minItems: 2,
|
||||
maxItems: 2,
|
||||
},
|
||||
},
|
||||
quotes: {
|
||||
type: "array",
|
||||
items: {
|
||||
type: "object",
|
||||
properties: {
|
||||
text: { type: "string" },
|
||||
source: { type: "string" },
|
||||
length: { type: "number" },
|
||||
id: { type: "number" },
|
||||
},
|
||||
required: ["text", "source", "length", "id"],
|
||||
},
|
||||
},
|
||||
},
|
||||
required: ["language", "groups", "quotes"],
|
||||
};
|
||||
const quoteIdsSchema = {
|
||||
type: "array",
|
||||
items: {
|
||||
type: "number",
|
||||
},
|
||||
uniqueItems: true,
|
||||
};
|
||||
let quoteFilesAllGood = true;
|
||||
let quoteFilesErrors;
|
||||
let quoteIdsAllGood = true;
|
||||
let quoteIdsErrors;
|
||||
const quotesFiles = fs.readdirSync("./static/quotes/");
|
||||
quotesFiles.forEach((quotefilename) => {
|
||||
quotefilename = quotefilename.split(".")[0];
|
||||
const quoteData = JSON.parse(
|
||||
fs.readFileSync(`./static/quotes/${quotefilename}.json`, {
|
||||
encoding: "utf8",
|
||||
flag: "r",
|
||||
})
|
||||
);
|
||||
quoteSchema.properties.language.pattern =
|
||||
"^" + escapeRegExp(quotefilename) + "$";
|
||||
const quoteValidator = JSONValidator.validate(quoteData, quoteSchema);
|
||||
if (!quoteValidator.valid) {
|
||||
console.log(
|
||||
`Quote ${quotefilename} JSON schema is \u001b[31minvalid\u001b[0m`
|
||||
);
|
||||
quoteFilesAllGood = false;
|
||||
quoteFilesErrors = quoteValidator.errors;
|
||||
}
|
||||
const quoteIds = quoteData.quotes.map((quote) => quote.id);
|
||||
const quoteIdsValidator = JSONValidator.validate(
|
||||
quoteIds,
|
||||
quoteIdsSchema
|
||||
);
|
||||
if (!quoteIdsValidator.valid) {
|
||||
console.log(
|
||||
`Quote ${quotefilename} IDs are \u001b[31mnot unique\u001b[0m`
|
||||
);
|
||||
quoteIdsAllGood = false;
|
||||
quoteIdsErrors = quoteIdsValidator.errors;
|
||||
}
|
||||
});
|
||||
if (quoteFilesAllGood) {
|
||||
console.log(`Quote file JSON schemas are \u001b[32mvalid\u001b[0m`);
|
||||
} else {
|
||||
console.log(`Quote file JSON schemas are \u001b[31minvalid\u001b[0m`);
|
||||
return reject(new Error(quoteFilesErrors));
|
||||
}
|
||||
if (quoteIdsAllGood) {
|
||||
console.log(`Quote IDs are \u001b[32munique\u001b[0m`);
|
||||
} else {
|
||||
console.log(`Quote IDs are \u001b[31mnot unique\u001b[0m`);
|
||||
return reject(new Error(quoteIdsErrors));
|
||||
}
|
||||
|
||||
//challenges
|
||||
const challengesSchema = {
|
||||
type: "array",
|
||||
|
@ -500,6 +299,224 @@ function validate() {
|
|||
});
|
||||
}
|
||||
|
||||
function validateQuotes() {
|
||||
return new Promise((resolve, reject) => {
|
||||
//quotes
|
||||
const quoteSchema = {
|
||||
type: "object",
|
||||
properties: {
|
||||
language: { type: "string" },
|
||||
groups: {
|
||||
type: "array",
|
||||
items: {
|
||||
type: "array",
|
||||
items: {
|
||||
type: "number",
|
||||
},
|
||||
minItems: 2,
|
||||
maxItems: 2,
|
||||
},
|
||||
},
|
||||
quotes: {
|
||||
type: "array",
|
||||
items: {
|
||||
type: "object",
|
||||
properties: {
|
||||
text: { type: "string" },
|
||||
source: { type: "string" },
|
||||
length: { type: "number" },
|
||||
id: { type: "number" },
|
||||
},
|
||||
required: ["text", "source", "length", "id"],
|
||||
},
|
||||
},
|
||||
},
|
||||
required: ["language", "groups", "quotes"],
|
||||
};
|
||||
const quoteIdsSchema = {
|
||||
type: "array",
|
||||
items: {
|
||||
type: "number",
|
||||
},
|
||||
uniqueItems: true,
|
||||
};
|
||||
let quoteFilesAllGood = true;
|
||||
let quoteFilesErrors;
|
||||
let quoteIdsAllGood = true;
|
||||
let quoteIdsErrors;
|
||||
const quotesFiles = fs.readdirSync("./static/quotes/");
|
||||
quotesFiles.forEach((quotefilename) => {
|
||||
quotefilename = quotefilename.split(".")[0];
|
||||
const quoteData = JSON.parse(
|
||||
fs.readFileSync(`./static/quotes/${quotefilename}.json`, {
|
||||
encoding: "utf8",
|
||||
flag: "r",
|
||||
})
|
||||
);
|
||||
quoteSchema.properties.language.pattern =
|
||||
"^" + escapeRegExp(quotefilename) + "$";
|
||||
const quoteValidator = JSONValidator.validate(quoteData, quoteSchema);
|
||||
if (!quoteValidator.valid) {
|
||||
console.log(
|
||||
`Quote ${quotefilename} JSON schema is \u001b[31minvalid\u001b[0m`
|
||||
);
|
||||
quoteFilesAllGood = false;
|
||||
quoteFilesErrors = quoteValidator.errors;
|
||||
}
|
||||
const quoteIds = quoteData.quotes.map((quote) => quote.id);
|
||||
const quoteIdsValidator = JSONValidator.validate(
|
||||
quoteIds,
|
||||
quoteIdsSchema
|
||||
);
|
||||
if (!quoteIdsValidator.valid) {
|
||||
console.log(
|
||||
`Quote ${quotefilename} IDs are \u001b[31mnot unique\u001b[0m`
|
||||
);
|
||||
quoteIdsAllGood = false;
|
||||
quoteIdsErrors = quoteIdsValidator.errors;
|
||||
}
|
||||
});
|
||||
if (quoteFilesAllGood) {
|
||||
console.log(`Quote file JSON schemas are \u001b[32mvalid\u001b[0m`);
|
||||
} else {
|
||||
console.log(`Quote file JSON schemas are \u001b[31minvalid\u001b[0m`);
|
||||
return reject(new Error(quoteFilesErrors));
|
||||
}
|
||||
if (quoteIdsAllGood) {
|
||||
console.log(`Quote IDs are \u001b[32munique\u001b[0m`);
|
||||
} else {
|
||||
console.log(`Quote IDs are \u001b[31mnot unique\u001b[0m`);
|
||||
return reject(new Error(quoteIdsErrors));
|
||||
}
|
||||
resolve();
|
||||
});
|
||||
}
|
||||
|
||||
function validateLanguages() {
|
||||
return new Promise((resolve, reject) => {
|
||||
//languages
|
||||
const languagesData = JSON.parse(
|
||||
fs.readFileSync("./static/languages/_list.json", {
|
||||
encoding: "utf8",
|
||||
flag: "r",
|
||||
})
|
||||
);
|
||||
const languagesSchema = {
|
||||
type: "array",
|
||||
items: {
|
||||
type: "string",
|
||||
},
|
||||
};
|
||||
const languagesValidator = JSONValidator.validate(
|
||||
languagesData,
|
||||
languagesSchema
|
||||
);
|
||||
if (languagesValidator.valid) {
|
||||
console.log("Languages list JSON schema is \u001b[32mvalid\u001b[0m");
|
||||
} else {
|
||||
console.log("Languages list JSON schema is \u001b[31minvalid\u001b[0m");
|
||||
return reject(new Error(languagesValidator.errors));
|
||||
}
|
||||
|
||||
//languages group
|
||||
const languagesGroupData = JSON.parse(
|
||||
fs.readFileSync("./static/languages/_groups.json", {
|
||||
encoding: "utf8",
|
||||
flag: "r",
|
||||
})
|
||||
);
|
||||
const languagesGroupSchema = {
|
||||
type: "array",
|
||||
items: {
|
||||
type: "object",
|
||||
properties: {
|
||||
name: { type: "string" },
|
||||
languages: {
|
||||
type: "array",
|
||||
items: {
|
||||
type: "string",
|
||||
},
|
||||
},
|
||||
},
|
||||
required: ["name", "languages"],
|
||||
},
|
||||
};
|
||||
const languagesGroupValidator = JSONValidator.validate(
|
||||
languagesGroupData,
|
||||
languagesGroupSchema
|
||||
);
|
||||
if (languagesGroupValidator.valid) {
|
||||
console.log("Languages groups JSON schema is \u001b[32mvalid\u001b[0m");
|
||||
} else {
|
||||
console.log("Languages groups JSON schema is \u001b[31minvalid\u001b[0m");
|
||||
return reject(new Error(languagesGroupValidator.errors));
|
||||
}
|
||||
|
||||
//language files
|
||||
const languageFileSchema = {
|
||||
type: "object",
|
||||
properties: {
|
||||
name: { type: "string" },
|
||||
leftToRight: { type: "boolean" },
|
||||
noLazyMode: { type: "boolean" },
|
||||
bcp47: { type: "string" },
|
||||
words: {
|
||||
type: "array",
|
||||
items: { type: "string", minLength: 1 },
|
||||
},
|
||||
accents: {
|
||||
type: "array",
|
||||
items: {
|
||||
type: "array",
|
||||
items: { type: "string", minLength: 1 },
|
||||
minItems: 2,
|
||||
maxItems: 2,
|
||||
},
|
||||
},
|
||||
},
|
||||
required: ["name", "leftToRight", "words"],
|
||||
};
|
||||
let languageFilesAllGood = true;
|
||||
let languageFilesErrors;
|
||||
languagesData.forEach((language) => {
|
||||
const languageFileData = JSON.parse(
|
||||
fs.readFileSync(`./static/languages/${language}.json`, {
|
||||
encoding: "utf8",
|
||||
flag: "r",
|
||||
})
|
||||
);
|
||||
languageFileSchema.properties.name.pattern =
|
||||
"^" + escapeRegExp(language) + "$";
|
||||
const languageFileValidator = JSONValidator.validate(
|
||||
languageFileData,
|
||||
languageFileSchema
|
||||
);
|
||||
if (!languageFileValidator.valid) {
|
||||
languageFilesAllGood = false;
|
||||
languageFilesErrors = languageFileValidator.errors;
|
||||
}
|
||||
});
|
||||
if (languageFilesAllGood) {
|
||||
console.log(
|
||||
`Language word list JSON schemas are \u001b[32mvalid\u001b[0m`
|
||||
);
|
||||
} else {
|
||||
console.log(
|
||||
`Language word list JSON schemas are \u001b[31minvalid\u001b[0m`
|
||||
);
|
||||
return reject(new Error(languageFilesErrors));
|
||||
}
|
||||
resolve();
|
||||
});
|
||||
}
|
||||
|
||||
function validateAll() {
|
||||
return Promise.all([validateOthers(), validateLanguages(), validateQuotes()]);
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
validate,
|
||||
validateAll,
|
||||
validateOthers,
|
||||
validateLanguages,
|
||||
validateQuotes,
|
||||
};
|
||||
|
|
|
@ -12,7 +12,10 @@
|
|||
"lint": "./node_modules/.bin/eslint './backend/**/*.js' './frontend/src/scripts/**/*.js'",
|
||||
"build:live": "cd ./frontend && npm run build:live",
|
||||
"pretty": "prettier --check './backend/**/*.js' './frontend/src/**/*.{js,scss}' './frontend/static/**/*.{json,html}'",
|
||||
"pr-check-json": "cd frontend && npx gulp pr-check-json",
|
||||
"pr-check-lint-json": "cd frontend && npx gulp pr-check-lint-json",
|
||||
"pr-check-quote-json": "cd frontend && npx gulp pr-check-quote-json",
|
||||
"pr-check-language-json": "cd frontend && npx gulp pr-check-language-json",
|
||||
"pr-check-other-json": "cd frontend && npx gulp pr-check-other-json",
|
||||
"pr-check-scss": "cd frontend && npx gulp pr-check-scss",
|
||||
"pr-check-ts": "cd frontend && npx gulp pr-check-ts"
|
||||
},
|
||||
|
|
Loading…
Add table
Reference in a new issue