From 05204ed4699f983887db85416dba9a387b1c235a Mon Sep 17 00:00:00 2001 From: Kevin J Hoerr Date: Mon, 9 Dec 2019 14:48:56 -0500 Subject: Add linting to project using Eslint --- src/.prettierrc.json | 6 ++++++ src/formats.ts | 39 ++++++++++++++++++++++----------------- src/index.ts | 20 ++++++++++---------- src/metadata.ts | 4 ++-- src/routes.ts | 49 ++++++++++++++++++++++++------------------------- src/util/config.ts | 16 ++++++++-------- src/util/logger.ts | 10 +++++++++- 7 files changed, 81 insertions(+), 63 deletions(-) create mode 100644 src/.prettierrc.json (limited to 'src') diff --git a/src/.prettierrc.json b/src/.prettierrc.json new file mode 100644 index 0000000..fca24df --- /dev/null +++ b/src/.prettierrc.json @@ -0,0 +1,6 @@ +{ + "trailingComma": "none", + "tabWidth": 2, + "semi": true, + "singleQuote": false +} diff --git a/src/formats.ts b/src/formats.ts index 4b432e3..e878399 100644 --- a/src/formats.ts +++ b/src/formats.ts @@ -1,9 +1,11 @@ import { InvalidReportDocumentError } from "./errors"; +type CoverageResult = number | InvalidReportDocumentError; + export interface Format { // returns the coverage value as %: Number(90.0), Number(100.0), Number(89.5) - parse_coverage: (file: Document) => number | InvalidReportDocumentError; - match_color: (coverage: number, style: GradientStyle) => string; + parseCoverage: (file: Document) => CoverageResult; + matchColor: (coverage: number, style: GradientStyle) => string; } interface FormatList { @@ -12,37 +14,40 @@ interface FormatList { interface FormatObj { formats: FormatList; - list_formats: () => string[]; - get_format: (format: string) => Format; + listFormats: () => string[]; + getFormat: (format: string) => Format; } export interface GradientStyle { - stage_1: number; - stage_2: number; + stage1: number; + stage2: number; } // color is a gradient from green (>=stage_1) -> yellow (stage_2) -> red. Stage values should come from metadata. -const default_color_matches = (coverage: number, style: GradientStyle) => { +const defaultColorMatches = ( + coverage: number, + style: GradientStyle +): string => { const gradient = - coverage >= style.stage_1 + coverage >= style.stage1 ? 15 - : coverage >= style.stage_2 - ? (Math.floor(coverage) - style.stage_2) * 16 + 15 - : 240 + Math.floor(coverage / (style.stage_2 / 15)); + : coverage >= style.stage2 + ? (Math.floor(coverage) - style.stage2) * 16 + 15 + : 240 + Math.floor(coverage / (style.stage2 / 15)); return gradient.toString(16) + "0"; }; const FormatsObj: FormatObj = { formats: { tarpaulin: { - parse_coverage: (file: Document) => { + parseCoverage: (file: Document): CoverageResult => { const scripts = file.getElementsByTagName("script"); if (scripts.length == 0) { return new InvalidReportDocumentError(); } const data = scripts[0].text; - const accumFunc = (regex: RegExp) => { - let acc: number = 0; + const accumFunc = (regex: RegExp): number => { + let acc = 0; while (true) { const match = regex.exec(data); if (match === null) break; @@ -61,15 +66,15 @@ const FormatsObj: FormatObj = { } return (100 * covered) / coverable; }, - match_color: default_color_matches + matchColor: defaultColorMatches } }, - list_formats: function() { + listFormats: function() { return Object.keys(this.formats); }, - get_format: function(format: string) { + getFormat: function(format: string) { return this.formats[format]; } }; diff --git a/src/index.ts b/src/index.ts index fdcdcaf..aab1da6 100644 --- a/src/index.ts +++ b/src/index.ts @@ -11,18 +11,18 @@ dotenv.config(); import routes from "./routes"; import Metadata from "./metadata"; -import logger_config from "./util/logger"; -import { config_or_error, handle_shutdown } from "./util/config"; +import loggerConfig from "./util/logger"; +import { configOrError, handleShutdown } from "./util/config"; // Start-up configuration const BIND_ADDRESS = process.env.BIND_ADDRESS || "localhost"; const PORT = Number(process.env.PORT || 3000); -const logger = winston.createLogger(logger_config("ROOT")); +const logger = winston.createLogger(loggerConfig("ROOT")); -const MONGO_URI = config_or_error("MONGO_URI"); +const MONGO_URI = configOrError("MONGO_URI"); const MONGO_DB = process.env.MONGO_DB || "ao-coverage"; -const HOST_DIR = config_or_error("HOST_DIR"); +const HOST_DIR = configOrError("HOST_DIR"); fs.accessSync(HOST_DIR, fs.constants.R_OK | fs.constants.W_OK); if (!path.isAbsolute(HOST_DIR)) { @@ -42,7 +42,7 @@ new MongoClient(MONGO_URI, { useUnifiedTopology: true }).connect( app.use( expressWinston.logger({ - ...logger_config("HTTP"), + ...loggerConfig("HTTP"), colorize: true, // filter out token query param from URL msg: @@ -53,16 +53,16 @@ new MongoClient(MONGO_URI, { useUnifiedTopology: true }).connect( // actual app routes app.use(routes(metadata)); - app.use(expressWinston.errorLogger(logger_config("_ERR"))); + app.use(expressWinston.errorLogger(loggerConfig("_ERR"))); const server = app.listen(PORT, BIND_ADDRESS, () => { logger.info("Express has started: http://%s:%d/", BIND_ADDRESS, PORT); }); // application exit handling - const handle_codes: NodeJS.Signals[] = ["SIGTERM", "SIGHUP", "SIGINT"]; - handle_codes.map((code: NodeJS.Signals) => { - process.on(code, handle_shutdown(mongo, server)); + const signalCodes: NodeJS.Signals[] = ["SIGTERM", "SIGHUP", "SIGINT"]; + signalCodes.map((code: NodeJS.Signals) => { + process.on(code, handleShutdown(mongo, server)); }); } ); diff --git a/src/metadata.ts b/src/metadata.ts index 07e420d..f09f2b3 100644 --- a/src/metadata.ts +++ b/src/metadata.ts @@ -1,7 +1,7 @@ import { Db } from "mongodb"; import winston from "winston"; -import logger_config from "./util/logger"; +import loggerConfig from "./util/logger"; import { BranchNotFoundError } from "./errors"; interface Branch { @@ -25,7 +25,7 @@ export interface Repository { branches: BranchList; } -const logger = winston.createLogger(logger_config("META")); +const logger = winston.createLogger(loggerConfig("META")); class Metadata { database: Db; diff --git a/src/routes.ts b/src/routes.ts index 9d435af..becf4da 100644 --- a/src/routes.ts +++ b/src/routes.ts @@ -1,4 +1,4 @@ -import express from "express"; +import express, { Router } from "express"; import { JSDOM } from "jsdom"; import { badgen } from "badgen"; import winston from "winston"; @@ -7,18 +7,18 @@ import fs from "fs"; import formats, { GradientStyle } from "./formats"; import Metadata, { HeadIdentity } from "./metadata"; -import { config_or_error } from "./util/config"; -import logger_config from "./util/logger"; +import { configOrError } from "./util/config"; +import loggerConfig from "./util/logger"; import { Messages } from "./errors"; const TOKEN = process.env.TOKEN || ""; const UPLOAD_LIMIT = Number(process.env.UPLOAD_LIMIT || 4194304); -const HOST_DIR = config_or_error("HOST_DIR"); +const HOST_DIR = configOrError("HOST_DIR"); -const logger = winston.createLogger(logger_config("HTTP")); +const logger = winston.createLogger(loggerConfig("HTTP")); -export default (metadata: Metadata) => { - const router = express.Router(); +export default (metadata: Metadata): Router => { + const router = Router(); // Upload HTML file router.post("/v1/:org/:repo/:branch/:commit.html", (req, res) => { @@ -30,11 +30,11 @@ export default (metadata: Metadata) => { return res.status(401).send(Messages.InvalidToken); } - if (!formats.list_formats().includes(format)) { + if (!formats.listFormats().includes(format)) { return res.status(406).send(Messages.InvalidFormat); } - var contents = ""; + let contents = ""; req.on("data", raw => { if (contents.length + raw.length > UPLOAD_LIMIT) { res.status(413).send(Messages.FileTooLarge); @@ -45,24 +45,23 @@ export default (metadata: Metadata) => { req.on("end", () => { let coverage: number; const doc = new JSDOM(contents).window.document; - const formatter = formats.get_format(format); - const result = formatter.parse_coverage(doc); + const formatter = formats.getFormat(format); + + const result = formatter.parseCoverage(doc); if (typeof result === "number") { coverage = result; } else { return res.status(400).send(result.message); } - const report_path = path.join(HOST_DIR, org, repo, branch, commit); + const reportPath = path.join(HOST_DIR, org, repo, branch, commit); fs.promises - .mkdir(report_path, { recursive: true }) + .mkdir(reportPath, { recursive: true }) .then( () => //TODO @Metadata stage values should come from metadata - new Promise(solv => - solv({ stage_1: 95, stage_2: 80 }) - ) + new Promise(solv => solv({ stage1: 95, stage2: 80 })) ) .then( style => @@ -71,16 +70,16 @@ export default (metadata: Metadata) => { badgen({ label: "coverage", status: Math.floor(coverage).toString() + "%", - color: formatter.match_color(coverage, style) + color: formatter.matchColor(coverage, style) }) ) ) ) .then(badge => - fs.promises.writeFile(path.join(report_path, "badge.svg"), badge) + fs.promises.writeFile(path.join(reportPath, "badge.svg"), badge) ) .then(() => - fs.promises.writeFile(path.join(report_path, "index.html"), contents) + fs.promises.writeFile(path.join(reportPath, "index.html"), contents) ) .then(() => metadata.updateBranch({ @@ -98,11 +97,11 @@ export default (metadata: Metadata) => { }); }); - const retrieve_file = ( + const retrieveFile = ( res: express.Response, identity: HeadIdentity, file: string - ) => { + ): void => { const { organization: org, repository: repo, branch, head } = identity; const pathname = path.join(HOST_DIR, org, repo, branch, head, file); @@ -125,7 +124,7 @@ export default (metadata: Metadata) => { branch, head: result.toString() }; - retrieve_file(res, identity, "badge.svg"); + retrieveFile(res, identity, "badge.svg"); } else { res.status(404).send(result.message); } @@ -149,7 +148,7 @@ export default (metadata: Metadata) => { branch, head: result.toString() }; - retrieve_file(res, identity, "index.html"); + retrieveFile(res, identity, "index.html"); } else { res.status(404).send(result.message); } @@ -170,7 +169,7 @@ export default (metadata: Metadata) => { branch, head: commit }; - retrieve_file(res, identity, "badge.svg"); + retrieveFile(res, identity, "badge.svg"); }); // provide hard link for commit @@ -182,7 +181,7 @@ export default (metadata: Metadata) => { branch, head: commit }; - retrieve_file(res, identity, "index.html"); + retrieveFile(res, identity, "index.html"); }); return router; diff --git a/src/util/config.ts b/src/util/config.ts index c155e64..6f8b60b 100644 --- a/src/util/config.ts +++ b/src/util/config.ts @@ -2,23 +2,23 @@ import winston from "winston"; import { MongoClient } from "mongodb"; import { Server } from "http"; -import logger_config from "./logger"; +import loggerConfig from "./logger"; -const logger = winston.createLogger(logger_config("ROOT")); +const logger = winston.createLogger(loggerConfig("ROOT")); -export const config_or_error = (var_name: string) => { - if (!process.env[var_name]) { - logger.error("%s must be defined", var_name); +export const configOrError = (varName: string): string => { + if (!process.env[varName]) { + logger.error("%s must be defined", varName); process.exit(1); return ""; } else { - return process.env[var_name] || ""; + return process.env[varName] || ""; } }; -export const handle_shutdown = (mongo: MongoClient, server: Server) => ( +export const handleShutdown = (mongo: MongoClient, server: Server) => ( signal: NodeJS.Signals -) => { +): void => { logger.warn("%s signal received. Closing shop.", signal); mongo diff --git a/src/util/logger.ts b/src/util/logger.ts index bafb829..d108ae0 100644 --- a/src/util/logger.ts +++ b/src/util/logger.ts @@ -1,4 +1,6 @@ import winston from "winston"; +import { Format } from "logform"; +import * as Transport from "winston-transport"; const { combine, splat, timestamp, label, colorize, printf } = winston.format; const { Console } = winston.transports; @@ -7,7 +9,13 @@ const LOG_LEVEL = process.env.LOG_LEVEL || "info"; /** * Provides standard logging format and output for the server. */ -export default (clazz: string, level: string = LOG_LEVEL) => ({ +export default ( + clazz: string, + level: string = LOG_LEVEL +): { + format: Format; + transports: Transport[]; +} => ({ format: combine( splat(), timestamp(), -- cgit