From dbbd57caf34d7b360b5f04bc9b5cefcf025a72b4 Mon Sep 17 00:00:00 2001 From: Vasil Sudakou Date: Sun, 22 Dec 2024 23:43:38 +0300 Subject: [PATCH 01/20] feat: init typescript --- .gitignore | 1 + package.json | 6 ++- tsconfig.json | 111 ++++++++++++++++++++++++++++++++++++++++++++++++++ yarn.lock | 5 +++ 4 files changed, 121 insertions(+), 2 deletions(-) create mode 100644 tsconfig.json diff --git a/.gitignore b/.gitignore index d1de6cc..b327074 100644 --- a/.gitignore +++ b/.gitignore @@ -10,3 +10,4 @@ state.json .idea .vscode lib/manual-test.js +dist/ diff --git a/package.json b/package.json index 16a1cba..6c992e4 100644 --- a/package.json +++ b/package.json @@ -36,7 +36,8 @@ "proxyquire": "^1.8.0", "shelljs": "^0.6.1", "sinon": "^18.0.0", - "sinon-chai": "^3.7.0" + "sinon-chai": "^3.7.0", + "typescript": "^5.7.2" }, "engines": { "node": ">=16.20.2 <=20" @@ -47,6 +48,7 @@ "test": "node ./node_modules/mocha/bin/_mocha './{,!(node_modules)/**/}*.spec.js' --exit", "test:ci": "yarn test", "start": "node lib/index.js", - "version": "exit 0" + "version": "exit 0", + "build": "rm -rf dist && tsc -p tsconfig.json" } } diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..c9c555d --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,111 @@ +{ + "compilerOptions": { + /* Visit https://aka.ms/tsconfig to read more about this file */ + + /* Projects */ + // "incremental": true, /* Save .tsbuildinfo files to allow for incremental compilation of projects. */ + // "composite": true, /* Enable constraints that allow a TypeScript project to be used with project references. */ + // "tsBuildInfoFile": "./.tsbuildinfo", /* Specify the path to .tsbuildinfo incremental compilation file. */ + // "disableSourceOfProjectReferenceRedirect": true, /* Disable preferring source files instead of declaration files when referencing composite projects. */ + // "disableSolutionSearching": true, /* Opt a project out of multi-project reference checking when editing. */ + // "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */ + + /* Language and Environment */ + "target": "es2016", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */ + // "lib": [], /* Specify a set of bundled library declaration files that describe the target runtime environment. */ + // "jsx": "preserve", /* Specify what JSX code is generated. */ + // "experimentalDecorators": true, /* Enable experimental support for legacy experimental decorators. */ + // "emitDecoratorMetadata": true, /* Emit design-type metadata for decorated declarations in source files. */ + // "jsxFactory": "", /* Specify the JSX factory function used when targeting React JSX emit, e.g. 'React.createElement' or 'h'. */ + // "jsxFragmentFactory": "", /* Specify the JSX Fragment reference used for fragments when targeting React JSX emit e.g. 'React.Fragment' or 'Fragment'. */ + // "jsxImportSource": "", /* Specify module specifier used to import the JSX factory functions when using 'jsx: react-jsx*'. */ + // "reactNamespace": "", /* Specify the object invoked for 'createElement'. This only applies when targeting 'react' JSX emit. */ + // "noLib": true, /* Disable including any library files, including the default lib.d.ts. */ + // "useDefineForClassFields": true, /* Emit ECMAScript-standard-compliant class fields. */ + // "moduleDetection": "auto", /* Control what method is used to detect module-format JS files. */ + + /* Modules */ + "module": "commonjs", /* Specify what module code is generated. */ + // "rootDir": "./", /* Specify the root folder within your source files. */ + // "moduleResolution": "node10", /* Specify how TypeScript looks up a file from a given module specifier. */ + // "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */ + // "paths": {}, /* Specify a set of entries that re-map imports to additional lookup locations. */ + // "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */ + // "typeRoots": [], /* Specify multiple folders that act like './node_modules/@types'. */ + // "types": [], /* Specify type package names to be included without being referenced in a source file. */ + // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ + // "moduleSuffixes": [], /* List of file name suffixes to search when resolving a module. */ + // "allowImportingTsExtensions": true, /* Allow imports to include TypeScript file extensions. Requires '--moduleResolution bundler' and either '--noEmit' or '--emitDeclarationOnly' to be set. */ + // "rewriteRelativeImportExtensions": true, /* Rewrite '.ts', '.tsx', '.mts', and '.cts' file extensions in relative import paths to their JavaScript equivalent in output files. */ + // "resolvePackageJsonExports": true, /* Use the package.json 'exports' field when resolving package imports. */ + // "resolvePackageJsonImports": true, /* Use the package.json 'imports' field when resolving imports. */ + // "customConditions": [], /* Conditions to set in addition to the resolver-specific defaults when resolving imports. */ + // "noUncheckedSideEffectImports": true, /* Check side effect imports. */ + // "resolveJsonModule": true, /* Enable importing .json files. */ + // "allowArbitraryExtensions": true, /* Enable importing files with any extension, provided a declaration file is present. */ + // "noResolve": true, /* Disallow 'import's, 'require's or ''s from expanding the number of files TypeScript should add to a project. */ + + /* JavaScript Support */ + // "allowJs": true, /* Allow JavaScript files to be a part of your program. Use the 'checkJS' option to get errors from these files. */ + // "checkJs": true, /* Enable error reporting in type-checked JavaScript files. */ + // "maxNodeModuleJsDepth": 1, /* Specify the maximum folder depth used for checking JavaScript files from 'node_modules'. Only applicable with 'allowJs'. */ + + /* Emit */ + // "declaration": true, /* Generate .d.ts files from TypeScript and JavaScript files in your project. */ + // "declarationMap": true, /* Create sourcemaps for d.ts files. */ + // "emitDeclarationOnly": true, /* Only output d.ts files and not JavaScript files. */ + // "sourceMap": true, /* Create source map files for emitted JavaScript files. */ + // "inlineSourceMap": true, /* Include sourcemap files inside the emitted JavaScript. */ + // "noEmit": true, /* Disable emitting files from a compilation. */ + // "outFile": "./", /* Specify a file that bundles all outputs into one JavaScript file. If 'declaration' is true, also designates a file that bundles all .d.ts output. */ + // "outDir": "./", /* Specify an output folder for all emitted files. */ + // "removeComments": true, /* Disable emitting comments. */ + // "importHelpers": true, /* Allow importing helper functions from tslib once per project, instead of including them per-file. */ + // "downlevelIteration": true, /* Emit more compliant, but verbose and less performant JavaScript for iteration. */ + // "sourceRoot": "", /* Specify the root path for debuggers to find the reference source code. */ + // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */ + // "inlineSources": true, /* Include source code in the sourcemaps inside the emitted JavaScript. */ + // "emitBOM": true, /* Emit a UTF-8 Byte Order Mark (BOM) in the beginning of output files. */ + // "newLine": "crlf", /* Set the newline character for emitting files. */ + // "stripInternal": true, /* Disable emitting declarations that have '@internal' in their JSDoc comments. */ + // "noEmitHelpers": true, /* Disable generating custom helper functions like '__extends' in compiled output. */ + // "noEmitOnError": true, /* Disable emitting files if any type checking errors are reported. */ + // "preserveConstEnums": true, /* Disable erasing 'const enum' declarations in generated code. */ + // "declarationDir": "./", /* Specify the output directory for generated declaration files. */ + + /* Interop Constraints */ + // "isolatedModules": true, /* Ensure that each file can be safely transpiled without relying on other imports. */ + // "verbatimModuleSyntax": true, /* Do not transform or elide any imports or exports not marked as type-only, ensuring they are written in the output file's format based on the 'module' setting. */ + // "isolatedDeclarations": true, /* Require sufficient annotation on exports so other tools can trivially generate declaration files. */ + // "allowSyntheticDefaultImports": true, /* Allow 'import x from y' when a module doesn't have a default export. */ + "esModuleInterop": true, /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */ + // "preserveSymlinks": true, /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */ + "forceConsistentCasingInFileNames": true, /* Ensure that casing is correct in imports. */ + + /* Type Checking */ + "strict": true, /* Enable all strict type-checking options. */ + // "noImplicitAny": true, /* Enable error reporting for expressions and declarations with an implied 'any' type. */ + // "strictNullChecks": true, /* When type checking, take into account 'null' and 'undefined'. */ + // "strictFunctionTypes": true, /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */ + // "strictBindCallApply": true, /* Check that the arguments for 'bind', 'call', and 'apply' methods match the original function. */ + // "strictPropertyInitialization": true, /* Check for class properties that are declared but not set in the constructor. */ + // "strictBuiltinIteratorReturn": true, /* Built-in iterators are instantiated with a 'TReturn' type of 'undefined' instead of 'any'. */ + // "noImplicitThis": true, /* Enable error reporting when 'this' is given the type 'any'. */ + // "useUnknownInCatchVariables": true, /* Default catch clause variables as 'unknown' instead of 'any'. */ + // "alwaysStrict": true, /* Ensure 'use strict' is always emitted. */ + // "noUnusedLocals": true, /* Enable error reporting when local variables aren't read. */ + // "noUnusedParameters": true, /* Raise an error when a function parameter isn't read. */ + // "exactOptionalPropertyTypes": true, /* Interpret optional property types as written, rather than adding 'undefined'. */ + // "noImplicitReturns": true, /* Enable error reporting for codepaths that do not explicitly return in a function. */ + // "noFallthroughCasesInSwitch": true, /* Enable error reporting for fallthrough cases in switch statements. */ + // "noUncheckedIndexedAccess": true, /* Add 'undefined' to a type when accessed using an index. */ + // "noImplicitOverride": true, /* Ensure overriding members in derived classes are marked with an override modifier. */ + // "noPropertyAccessFromIndexSignature": true, /* Enforces using indexed accessors for keys declared using an indexed type. */ + // "allowUnusedLabels": true, /* Disable error reporting for unused labels. */ + // "allowUnreachableCode": true, /* Disable error reporting for unreachable code. */ + + /* Completeness */ + // "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */ + "skipLibCheck": true /* Skip type checking all .d.ts files. */ + } +} diff --git a/yarn.lock b/yarn.lock index c7101e2..09092c2 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5293,6 +5293,11 @@ typed-array-length@^1.0.6: is-typed-array "^1.1.13" possible-typed-array-names "^1.0.0" +typescript@^5.7.2: + version "5.7.2" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.7.2.tgz#3169cf8c4c8a828cde53ba9ecb3d2b1d5dd67be6" + integrity sha512-i5t66RHxDvVN40HfDd1PsEThGNnlMCMT3jMUuoh9/0TaqWevNontacunWyN02LA9/fIbEWlcHZcgTKb9QoaLfg== + uglify-js@^3.1.4: version "3.7.6" resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.7.6.tgz#0783daa867d4bc962a37cc92f67f6e3238c47485" From 3031024677fe30cd90fc710dbbd22124b5921429 Mon Sep 17 00:00:00 2001 From: Vasil Sudakou Date: Mon, 23 Dec 2024 02:44:57 +0300 Subject: [PATCH 02/20] feat: configure eslint for typescript --- .eslintignore | 1 + .eslintrc.json | 40 ++++++++++- package.json | 2 + yarn.lock | 185 ++++++++++++++++++++++++++++++++++++++++++++++--- 4 files changed, 216 insertions(+), 12 deletions(-) diff --git a/.eslintignore b/.eslintignore index 76c0c86..4eb6da6 100644 --- a/.eslintignore +++ b/.eslintignore @@ -3,6 +3,7 @@ # Ignore built files except build/index.js build/* !build/index.js +dist/* coverage/* # Directory for instrumented libs generated by jscoverage/JSCover diff --git a/.eslintrc.json b/.eslintrc.json index 6ca9238..f7fcc79 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -14,7 +14,7 @@ "impliedStrict": true } }, - + "plugins": [ "chai-friendly", "import", @@ -89,5 +89,41 @@ "node/no-deprecated-api": "warn", "no-useless-constructor": "warn", "no-return-await": "off" - } + }, + + "overrides": [ + { + "files": ["**/*.ts"], + "parser": "@typescript-eslint/parser", + "plugins": ["@typescript-eslint/eslint-plugin"], + "extends": ["plugin:@typescript-eslint/recommended"], + "parserOptions": { + "project": "tsconfig.json", + "sourceType": "module" + }, + "env": { + "node": true + }, + "rules": { + "no-restricted-syntax": "warn", + "import/prefer-default-export": "off", + "node/no-unsupported-features": "off", + "node/no-unsupported-features/es-builtins": "error", + "node/no-unsupported-features/es-syntax": ["error", { + "ignores": ["modules"] + }], + "node/no-unsupported-features/node-builtins": "error", + "no-empty-function": "warn", + "lines-between-class-members": "off", + "@typescript-eslint/no-explicit-any": "warn", + "@typescript-eslint/no-var-requires": "warn", + "@typescript-eslint/no-unused-vars": ["error", { + "argsIgnorePattern": "^_", + "varsIgnorePattern": "^_", + "caughtErrorsIgnorePattern": "^_" + } + ] + } + } + ] } diff --git a/package.json b/package.json index 6c992e4..aaf6852 100644 --- a/package.json +++ b/package.json @@ -22,6 +22,8 @@ "q": "^1.5.1" }, "devDependencies": { + "@typescript-eslint/eslint-plugin": "^8.18.1", + "@typescript-eslint/parser": "^8.18.1", "chai": "^4.4.1", "eslint": "^8.57.0", "eslint-config-airbnb-base": "^15.0.0", diff --git a/yarn.lock b/yarn.lock index 09092c2..902c3bb 100644 --- a/yarn.lock +++ b/yarn.lock @@ -543,6 +543,18 @@ dependencies: eslint-visitor-keys "^3.3.0" +"@eslint-community/eslint-utils@^4.4.0": + version "4.4.1" + resolved "https://registry.yarnpkg.com/@eslint-community/eslint-utils/-/eslint-utils-4.4.1.tgz#d1145bf2c20132d6400495d6df4bf59362fd9d56" + integrity sha512-s3O3waFUrMV8P/XaF/+ZTp1X9XBZW1a4B97ZnjQF2KYWaFD2A8KyFBsrsfSjEmjn3RGWAIuvlneuZm3CUK3jbA== + dependencies: + eslint-visitor-keys "^3.4.3" + +"@eslint-community/regexpp@^4.10.0": + version "4.12.1" + resolved "https://registry.yarnpkg.com/@eslint-community/regexpp/-/regexpp-4.12.1.tgz#cfc6cffe39df390a3841cde2abccf92eaa7ae0e0" + integrity sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ== + "@eslint-community/regexpp@^4.6.1": version "4.11.0" resolved "https://registry.yarnpkg.com/@eslint-community/regexpp/-/regexpp-4.11.0.tgz#b0ffd0312b4a3fd2d6f77237e7248a5ad3a680ae" @@ -630,12 +642,12 @@ "@nodelib/fs.stat" "2.0.5" run-parallel "^1.1.9" -"@nodelib/fs.stat@2.0.5": +"@nodelib/fs.stat@2.0.5", "@nodelib/fs.stat@^2.0.2": version "2.0.5" resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz#5bd262af94e9d25bd1e71b05deed44876a222e8b" integrity sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A== -"@nodelib/fs.walk@^1.2.8": +"@nodelib/fs.walk@^1.2.3", "@nodelib/fs.walk@^1.2.8": version "1.2.8" resolved "https://registry.yarnpkg.com/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz#e95737e8bb6746ddedf69c556953494f196fe69a" integrity sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg== @@ -1142,6 +1154,87 @@ "@types/node" "*" "@types/webidl-conversions" "*" +"@typescript-eslint/eslint-plugin@^8.18.1": + version "8.18.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.18.1.tgz#992e5ac1553ce20d0d46aa6eccd79dc36dedc805" + integrity sha512-Ncvsq5CT3Gvh+uJG0Lwlho6suwDfUXH0HztslDf5I+F2wAFAZMRwYLEorumpKLzmO2suAXZ/td1tBg4NZIi9CQ== + dependencies: + "@eslint-community/regexpp" "^4.10.0" + "@typescript-eslint/scope-manager" "8.18.1" + "@typescript-eslint/type-utils" "8.18.1" + "@typescript-eslint/utils" "8.18.1" + "@typescript-eslint/visitor-keys" "8.18.1" + graphemer "^1.4.0" + ignore "^5.3.1" + natural-compare "^1.4.0" + ts-api-utils "^1.3.0" + +"@typescript-eslint/parser@^8.18.1": + version "8.18.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-8.18.1.tgz#c258bae062778b7696793bc492249027a39dfb95" + integrity sha512-rBnTWHCdbYM2lh7hjyXqxk70wvon3p2FyaniZuey5TrcGBpfhVp0OxOa6gxr9Q9YhZFKyfbEnxc24ZnVbbUkCA== + dependencies: + "@typescript-eslint/scope-manager" "8.18.1" + "@typescript-eslint/types" "8.18.1" + "@typescript-eslint/typescript-estree" "8.18.1" + "@typescript-eslint/visitor-keys" "8.18.1" + debug "^4.3.4" + +"@typescript-eslint/scope-manager@8.18.1": + version "8.18.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-8.18.1.tgz#52cedc3a8178d7464a70beffed3203678648e55b" + integrity sha512-HxfHo2b090M5s2+/9Z3gkBhI6xBH8OJCFjH9MhQ+nnoZqxU3wNxkLT+VWXWSFWc3UF3Z+CfPAyqdCTdoXtDPCQ== + dependencies: + "@typescript-eslint/types" "8.18.1" + "@typescript-eslint/visitor-keys" "8.18.1" + +"@typescript-eslint/type-utils@8.18.1": + version "8.18.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-8.18.1.tgz#10f41285475c0bdee452b79ff7223f0e43a7781e" + integrity sha512-jAhTdK/Qx2NJPNOTxXpMwlOiSymtR2j283TtPqXkKBdH8OAMmhiUfP0kJjc/qSE51Xrq02Gj9NY7MwK+UxVwHQ== + dependencies: + "@typescript-eslint/typescript-estree" "8.18.1" + "@typescript-eslint/utils" "8.18.1" + debug "^4.3.4" + ts-api-utils "^1.3.0" + +"@typescript-eslint/types@8.18.1": + version "8.18.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-8.18.1.tgz#d7f4f94d0bba9ebd088de840266fcd45408a8fff" + integrity sha512-7uoAUsCj66qdNQNpH2G8MyTFlgerum8ubf21s3TSM3XmKXuIn+H2Sifh/ES2nPOPiYSRJWAk0fDkW0APBWcpfw== + +"@typescript-eslint/typescript-estree@8.18.1": + version "8.18.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-8.18.1.tgz#2a86cd64b211a742f78dfa7e6f4860413475367e" + integrity sha512-z8U21WI5txzl2XYOW7i9hJhxoKKNG1kcU4RzyNvKrdZDmbjkmLBo8bgeiOJmA06kizLI76/CCBAAGlTlEeUfyg== + dependencies: + "@typescript-eslint/types" "8.18.1" + "@typescript-eslint/visitor-keys" "8.18.1" + debug "^4.3.4" + fast-glob "^3.3.2" + is-glob "^4.0.3" + minimatch "^9.0.4" + semver "^7.6.0" + ts-api-utils "^1.3.0" + +"@typescript-eslint/utils@8.18.1": + version "8.18.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-8.18.1.tgz#c4199ea23fc823c736e2c96fd07b1f7235fa92d5" + integrity sha512-8vikiIj2ebrC4WRdcAdDcmnu9Q/MXXwg+STf40BVfT8exDqBCUPdypvzcUPxEqRGKg9ALagZ0UWcYCtn+4W2iQ== + dependencies: + "@eslint-community/eslint-utils" "^4.4.0" + "@typescript-eslint/scope-manager" "8.18.1" + "@typescript-eslint/types" "8.18.1" + "@typescript-eslint/typescript-estree" "8.18.1" + +"@typescript-eslint/visitor-keys@8.18.1": + version "8.18.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-8.18.1.tgz#344b4f6bc83f104f514676facf3129260df7610a" + integrity sha512-Vj0WLm5/ZsD013YeUKn+K0y8p1M0jPpxOkKdbD1wB0ns53a5piVY02zjf072TblEweAbcYiFiPoSMF3kp+VhhQ== + dependencies: + "@typescript-eslint/types" "8.18.1" + eslint-visitor-keys "^4.2.0" + "@ungap/structured-clone@^1.2.0": version "1.2.0" resolved "https://registry.yarnpkg.com/@ungap/structured-clone/-/structured-clone-1.2.0.tgz#756641adb587851b5ccb3e095daf27ae581c8406" @@ -1598,6 +1691,13 @@ brace-expansion@^2.0.1: dependencies: balanced-match "^1.0.0" +braces@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.3.tgz#490332f40919452272d55a8480adc0c441358789" + integrity sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA== + dependencies: + fill-range "^7.1.1" + braces@~3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107" @@ -1978,6 +2078,13 @@ debug@^4.3.1, debug@^4.3.2, debug@^4.3.5: dependencies: ms "2.1.2" +debug@^4.3.4: + version "4.4.0" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.4.0.tgz#2b3f2aea2ffeb776477460267377dc8710faba8a" + integrity sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA== + dependencies: + ms "^2.1.3" + decamelize@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-4.0.0.tgz#aa472d7bf660eb15f3494efd531cab7f2a709837" @@ -2508,6 +2615,11 @@ eslint-visitor-keys@^3.3.0, eslint-visitor-keys@^3.4.1, eslint-visitor-keys@^3.4 resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz#0cd72fe8550e3c2eae156a96a4dddcd1c8ac5800" integrity sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag== +eslint-visitor-keys@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-4.2.0.tgz#687bacb2af884fcdda8a6e7d65c606f46a14cd45" + integrity sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw== + eslint@^8.57.0: version "8.57.1" resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.57.1.tgz#7df109654aba7e3bbe5c8eae533c5e461d3c6ca9" @@ -2645,6 +2757,17 @@ fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3: resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525" integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q== +fast-glob@^3.3.2: + version "3.3.2" + resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.3.2.tgz#a904501e57cfdd2ffcded45e99a54fef55e46129" + integrity sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow== + dependencies: + "@nodelib/fs.stat" "^2.0.2" + "@nodelib/fs.walk" "^1.2.3" + glob-parent "^5.1.2" + merge2 "^1.3.0" + micromatch "^4.0.4" + fast-json-stable-stringify@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633" @@ -2755,6 +2878,13 @@ fill-range@^7.0.1: dependencies: to-regex-range "^5.0.1" +fill-range@^7.1.1: + version "7.1.1" + resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.1.1.tgz#44265d3cac07e3ea7dc247516380643754a05292" + integrity sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg== + dependencies: + to-regex-range "^5.0.1" + find-my-way@^8.0.0: version "8.2.2" resolved "https://registry.yarnpkg.com/find-my-way/-/find-my-way-8.2.2.tgz#f3e78bc6ead2da4fdaa201335da3228600ed0285" @@ -2949,6 +3079,13 @@ getpass@^0.1.1: dependencies: assert-plus "^1.0.0" +glob-parent@^5.1.2, glob-parent@~5.1.2: + version "5.1.2" + resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4" + integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow== + dependencies: + is-glob "^4.0.1" + glob-parent@^6.0.2: version "6.0.2" resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-6.0.2.tgz#6d237d99083950c79290f24c7642a3de9a28f9e3" @@ -2956,13 +3093,6 @@ glob-parent@^6.0.2: dependencies: is-glob "^4.0.3" -glob-parent@~5.1.2: - version "5.1.2" - resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4" - integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow== - dependencies: - is-glob "^4.0.1" - glob@^5.0.15: version "5.0.15" resolved "https://registry.yarnpkg.com/glob/-/glob-5.0.15.tgz#1bc936b9e02f4a603fcc222ecf7633d30b8b93b1" @@ -3203,6 +3333,11 @@ ignore@^5.2.0: resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.3.1.tgz#5073e554cd42c5b33b394375f538b8593e34d4ef" integrity sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw== +ignore@^5.3.1: + version "5.3.2" + resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.3.2.tgz#3cd40e729f3643fd87cb04e50bf0eb722bc596f5" + integrity sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g== + import-fresh@^3.2.1: version "3.3.0" resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.3.0.tgz#37162c25fcb9ebaa2e6e53d5b4d88ce17d9e0c2b" @@ -3909,6 +4044,19 @@ merge-descriptors@~1.0.0: resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.1.tgz#b00aaa556dd8b44568150ec9d1b953f3f90cbb61" integrity sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E= +merge2@^1.3.0: + version "1.4.1" + resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae" + integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg== + +micromatch@^4.0.4: + version "4.0.8" + resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.8.tgz#d66fa18f3a47076789320b9b1af32bd86d9fa202" + integrity sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA== + dependencies: + braces "^3.0.3" + picomatch "^2.3.1" + mime-db@1.52.0: version "1.52.0" resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70" @@ -3952,6 +4100,13 @@ minimatch@^5.0.1, minimatch@^5.1.6: dependencies: brace-expansion "^2.0.1" +minimatch@^9.0.4: + version "9.0.5" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-9.0.5.tgz#d74f9dd6b57d83d8e98cfb82133b03978bc929e5" + integrity sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow== + dependencies: + brace-expansion "^2.0.1" + minimist@0.0.8: version "0.0.8" resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d" @@ -4320,7 +4475,7 @@ performance-now@^2.1.0: resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b" integrity sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns= -picomatch@^2.0.4, picomatch@^2.2.1: +picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.3.1: version "2.3.1" resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== @@ -4775,6 +4930,11 @@ semver@^7.5.4: dependencies: lru-cache "^6.0.0" +semver@^7.6.0: + version "7.6.3" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.6.3.tgz#980f7b5550bc175fb4dc09403085627f9eb33143" + integrity sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A== + serialize-javascript@^6.0.2: version "6.0.2" resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-6.0.2.tgz#defa1e055c83bf6d59ea805d8da862254eb6a6c2" @@ -5188,6 +5348,11 @@ triple-beam@^1.3.0: resolved "https://registry.yarnpkg.com/triple-beam/-/triple-beam-1.3.0.tgz#a595214c7298db8339eeeee083e4d10bd8cb8dd9" integrity sha512-XrHUvV5HpdLmIj4uVMxHggLbFSZYIn7HEWsqePZcI50pco+MPqJ50wMGY794X7AOOhxOBAjbkqfAbEe/QMp2Lw== +ts-api-utils@^1.3.0: + version "1.4.3" + resolved "https://registry.yarnpkg.com/ts-api-utils/-/ts-api-utils-1.4.3.tgz#bfc2215fe6528fecab2b0fba570a2e8a4263b064" + integrity sha512-i3eMG77UTMD0hZhgRS562pv83RC6ukSAC2GMNWc+9dieh/+jDM5u5YG+NHX6VNDRHQcHwmsTHctP9LhbC3WxVw== + tsconfig-paths@^3.15.0: version "3.15.0" resolved "https://registry.yarnpkg.com/tsconfig-paths/-/tsconfig-paths-3.15.0.tgz#5299ec605e55b1abb23ec939ef15edaf483070d4" From cc8a07e7bcc6a6370e88c72e107a7e0081f2c566 Mon Sep 17 00:00:00 2001 From: Vasil Sudakou Date: Mon, 23 Dec 2024 02:48:39 +0300 Subject: [PATCH 03/20] feat: add http server module --- lib/http-server/index.ts | 102 ++++++++++++++++++ lib/logger.js | 50 ++------- .../deprecated-images/deprecated-image.dto.ts | 3 + .../deprecated-images.collector.ts | 20 ++++ 4 files changed, 133 insertions(+), 42 deletions(-) create mode 100644 lib/http-server/index.ts create mode 100644 lib/metric/deprecated-images/deprecated-image.dto.ts create mode 100644 lib/metric/deprecated-images/deprecated-images.collector.ts diff --git a/lib/http-server/index.ts b/lib/http-server/index.ts new file mode 100644 index 0000000..85c78b6 --- /dev/null +++ b/lib/http-server/index.ts @@ -0,0 +1,102 @@ +import fastify from 'fastify'; + +// @ts-expect-error it's a js library +import cfLogs from 'cf-logs'; + +import { saveServerAddress } from '../helpers'; +import deprecatedImagesCollector from '../metric/deprecated-images/deprecated-images.collector'; + +const logger = cfLogs.Logger('codefresh:containerLogger'); + +export class HttpServer { + + private readonly host; + private readonly port; + private readonly server; + + constructor(private taskLogger: any) { + try { + this.host = process.env.HOST || '0.0.0.0'; + this.port = +(process.env.PORT || 8080); + this.server = fastify(); + + this.initSecrets(); + this.initDeprecatedImages(); + } catch (error) { + logger.error(`could not initialize server for engine's requests due to error: ${error}`); + throw error; + } + } + + private initSecrets() { + const secretsOptions = { + schema: { + body: { + type: 'object', + required: ['key', 'value'], + properties: { + key: { type: 'string' }, + value: { type: 'string' }, + }, + }, + }, + }; + + this.server.post('/secrets', secretsOptions, async (request, reply) => { + try { + const { body }: { body: any } = request; + const { secret } = body; + logger.info(`got request to add new mask: ${secret.key}`); + this.taskLogger.addNewMask(secret); + reply.code(201); + return 'secret added'; + } catch (err) { + logger.info(`could not create new mask for due to error: ${err}`); + reply.code(500); + throw err; + } + }); + } + + private initDeprecatedImages() { + this.server.get('/deprecated-images', async () => { + logger.info(`got request to retrieve deprecated images`); + return deprecatedImagesCollector.consumeAll(); + }); + + this.server.post<{ Body: { count: number } }>('/deprecated-images/ack', async (request, reply) => { + const { count } = request.body; + + if (typeof count !== 'number' || count < 1) { + return reply.status(400).send({ error: 'You must provide a valid count (positive integer).' }); + } + + deprecatedImagesCollector.destroyConsumed(count); + + return reply.status(200).send({ count }); + }); + } + + async start() { + let address: string; + try { + address = await this.server.listen({ + host: this.host, + port: this.port, + }); + + logger.info(`listening for engine's requests on ${address}`); + } catch (error) { + logger.error(`could not start server for engine updates due to error: ${error}`); + throw error; + } + + try { + await saveServerAddress(address); + } catch (error) { + logger.error(`could not save server address due to error: ${error}`); + throw error; + } + } + +} diff --git a/lib/logger.js b/lib/logger.js index 7b2a71e..5629975 100644 --- a/lib/logger.js +++ b/lib/logger.js @@ -6,12 +6,14 @@ const DockerEvents = require('docker-events'); const CFError = require('cf-errors'); const logger = require('cf-logs').Logger('codefresh:containerLogger'); const { TaskLogger } = require('@codefresh-io/task-logger'); -const fastify = require('fastify'); const { ContainerStatus } = require('./enums'); const { LoggerStrategy } = require('./enums'); const { ContainerHandlingStatus } = require('./enums'); const ContainerLogger = require('./ContainerLogger'); -const { getPromiseWithResolvers, saveServerAddress } = require('./helpers'); +const { getPromiseWithResolvers } = require('./helpers'); + +// eslint-disable-next-line import/no-unresolved,import/extensions +const { HttpServer } = require('./http-server'); const initialState = { pid: process.pid, status: 'init', lastLogsDate: new Date(), failedHealthChecks: [], restartCounter: 0, containers: {} @@ -38,6 +40,7 @@ class Logger { this.finishedContainers = 0; this.finishedContainersEmitter = new EventEmitter(); this.showProgress = showProgress; + this.httpServer = new HttpServer(); let dockerSockPath; if (process.platform === 'win32') { @@ -123,7 +126,7 @@ class Logger { }); - await this._listenForEngineUpdates(); + await this._listenForEngineRequests(); } _readState() { @@ -351,45 +354,8 @@ class Logger { }); } - async _listenForEngineUpdates() { - try { - const port = +(process.env.PORT || 8080); - const host = process.env.HOST || '0.0.0.0'; - - const server = fastify(); - const secretsOptions = { - schema: { - body: { - type: 'object', - required: ['key', 'value'], - properties: { - key: { type: 'string' }, - value: { type: 'string' }, - }, - }, - }, - }; - server.post('/secrets', secretsOptions, async (request, reply) => { - try { - const { body: secret } = request; - logger.info(`got request to add new mask: ${secret.key}`); - this.taskLogger.addNewMask(secret); - reply.code(201); - return 'secret added'; - } catch (err) { - logger.info(`could not create new mask for due to error: ${err}`); - reply.code(500); - throw err; - } - }); - - const address = await server.listen({ host, port }); - await saveServerAddress(address); - logger.info(`listening for engine updates on ${address}`); - } catch (error) { - logger.error(`could not start server for engine updates due to error: ${error}`); - throw error; - } + async _listenForEngineRequests() { + await this.httpServer.start(); } _handleContainerStreamEnd(containerId) { diff --git a/lib/metric/deprecated-images/deprecated-image.dto.ts b/lib/metric/deprecated-images/deprecated-image.dto.ts new file mode 100644 index 0000000..e73b14b --- /dev/null +++ b/lib/metric/deprecated-images/deprecated-image.dto.ts @@ -0,0 +1,3 @@ +export interface DeprecatedImageDto { + image: string; +} diff --git a/lib/metric/deprecated-images/deprecated-images.collector.ts b/lib/metric/deprecated-images/deprecated-images.collector.ts new file mode 100644 index 0000000..01dc202 --- /dev/null +++ b/lib/metric/deprecated-images/deprecated-images.collector.ts @@ -0,0 +1,20 @@ +import { DeprecatedImageDto } from './deprecated-image.dto'; + +class DeprecatedImagesCollector { + + private list: DeprecatedImageDto[] = []; + + push(deprecatedImageDto: DeprecatedImageDto) { + this.list.push(deprecatedImageDto); + } + + consumeAll() { + return this.list; + } + + destroyConsumed(consumedNumber: number) { + this.list = this.list.slice(consumedNumber); + } +} + +export default new DeprecatedImagesCollector(); From 5fd3ab219bb78701a86565fd7e0a70b409de8b97 Mon Sep 17 00:00:00 2001 From: Vasil Sudakou Date: Mon, 23 Dec 2024 02:49:12 +0300 Subject: [PATCH 04/20] feat: configure tsconfig --- tsconfig.json | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/tsconfig.json b/tsconfig.json index c9c555d..76ea6d5 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -11,7 +11,7 @@ // "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */ /* Language and Environment */ - "target": "es2016", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */ + "target": "es2022", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */ // "lib": [], /* Specify a set of bundled library declaration files that describe the target runtime environment. */ // "jsx": "preserve", /* Specify what JSX code is generated. */ // "experimentalDecorators": true, /* Enable experimental support for legacy experimental decorators. */ @@ -26,7 +26,7 @@ /* Modules */ "module": "commonjs", /* Specify what module code is generated. */ - // "rootDir": "./", /* Specify the root folder within your source files. */ + "rootDir": "./lib", /* Specify the root folder within your source files. */ // "moduleResolution": "node10", /* Specify how TypeScript looks up a file from a given module specifier. */ // "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */ // "paths": {}, /* Specify a set of entries that re-map imports to additional lookup locations. */ @@ -46,7 +46,7 @@ // "noResolve": true, /* Disallow 'import's, 'require's or ''s from expanding the number of files TypeScript should add to a project. */ /* JavaScript Support */ - // "allowJs": true, /* Allow JavaScript files to be a part of your program. Use the 'checkJS' option to get errors from these files. */ + "allowJs": true, /* Allow JavaScript files to be a part of your program. Use the 'checkJS' option to get errors from these files. */ // "checkJs": true, /* Enable error reporting in type-checked JavaScript files. */ // "maxNodeModuleJsDepth": 1, /* Specify the maximum folder depth used for checking JavaScript files from 'node_modules'. Only applicable with 'allowJs'. */ @@ -54,11 +54,11 @@ // "declaration": true, /* Generate .d.ts files from TypeScript and JavaScript files in your project. */ // "declarationMap": true, /* Create sourcemaps for d.ts files. */ // "emitDeclarationOnly": true, /* Only output d.ts files and not JavaScript files. */ - // "sourceMap": true, /* Create source map files for emitted JavaScript files. */ + "sourceMap": true, /* Create source map files for emitted JavaScript files. */ // "inlineSourceMap": true, /* Include sourcemap files inside the emitted JavaScript. */ // "noEmit": true, /* Disable emitting files from a compilation. */ // "outFile": "./", /* Specify a file that bundles all outputs into one JavaScript file. If 'declaration' is true, also designates a file that bundles all .d.ts output. */ - // "outDir": "./", /* Specify an output folder for all emitted files. */ + "outDir": "./dist", /* Specify an output folder for all emitted files. */ // "removeComments": true, /* Disable emitting comments. */ // "importHelpers": true, /* Allow importing helper functions from tslib once per project, instead of including them per-file. */ // "downlevelIteration": true, /* Emit more compliant, but verbose and less performant JavaScript for iteration. */ @@ -107,5 +107,12 @@ /* Completeness */ // "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */ "skipLibCheck": true /* Skip type checking all .d.ts files. */ - } + }, + "exclude": [ + "node_modules", + "**/*.unit*", + "**/*.spec*", + "coverage/**", + "dist", + ] } From 7f9f56db1867c766d79ffe45698aa1b91d666afc Mon Sep 17 00:00:00 2001 From: Vasil Sudakou Date: Mon, 23 Dec 2024 03:15:38 +0300 Subject: [PATCH 05/20] feat: modify Docker configs for typescript --- .dockerignore | 1 + Dockerfile | 14 +++++++++++--- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/.dockerignore b/.dockerignore index 49919f3..83b1b3c 100644 --- a/.dockerignore +++ b/.dockerignore @@ -8,3 +8,4 @@ lib/state.json .eslintrc.json test .eslintignore +dist diff --git a/Dockerfile b/Dockerfile index 545b505..7f20c02 100644 --- a/Dockerfile +++ b/Dockerfile @@ -3,7 +3,7 @@ RUN adduser --disabled-password -home /home/cfu -shell /bin/bash cfu WORKDIR /root/cf-runtime COPY package.json yarn.lock ./ -FROM base AS dependencies +FROM base AS build-dependencies RUN apt-get update \ && apt upgrade -y \ && apt-get install -y \ @@ -11,14 +11,22 @@ RUN apt-get update \ git \ make \ python3 + +FROM build-dependencies AS build +RUN yarn install --frozen-lockfile +COPY . . +RUN yarn build + +FROM build-dependencies AS prod-dependencies RUN yarn install --frozen-lockfile --production FROM base AS production -COPY --from=dependencies /root/cf-runtime/node_modules ./node_modules +COPY --from=prod-dependencies /root/cf-runtime/node_modules ./node_modules +COPY --from=build /root/cf-runtime/dist ./dist COPY . . #purpose of security RUN npm -g uninstall npm USER cfu -CMD ["node", "lib/index.js"] +CMD ["node", "dist/index.js"] From 52c455283aa370b9297d8ff3900b7467db16efe0 Mon Sep 17 00:00:00 2001 From: Vasil Sudakou Date: Mon, 23 Dec 2024 11:31:51 +0300 Subject: [PATCH 06/20] feat: rename path "lib" to "dist" --- lib/forever.ps1 | 2 +- lib/isReady.js | 2 +- lib/isReady.ps1 | 4 ++-- lib/isReady.sh | 4 ++-- package.json | 2 +- 5 files changed, 7 insertions(+), 7 deletions(-) diff --git a/lib/forever.ps1 b/lib/forever.ps1 index 45afb93..3e33432 100644 --- a/lib/forever.ps1 +++ b/lib/forever.ps1 @@ -1,4 +1,4 @@ while ($true) { Start-Sleep -s 1 - & node lib/index.js + & node dist/index.js } diff --git a/lib/isReady.js b/lib/isReady.js index 93c3511..5f3407e 100644 --- a/lib/isReady.js +++ b/lib/isReady.js @@ -23,7 +23,7 @@ function isContainerLoggerReady(state) { (() => { const containerId = process.argv[2]; - const state = JSON.parse(readFileSync('./lib/state.json').toString('utf-8')); + const state = JSON.parse(readFileSync('./dist/state.json').toString('utf-8')); let isReady = false; if (containerId) { isReady = isContainerReady(state, containerId); diff --git a/lib/isReady.ps1 b/lib/isReady.ps1 index efe297b..421779d 100644 --- a/lib/isReady.ps1 +++ b/lib/isReady.ps1 @@ -6,7 +6,7 @@ $CONTAINER_ID=$args[0] if ( $CONTAINER_ID ) { echo "checking if container:$CONTAINER_ID exists" - if (select-string -Pattern $CONTAINER_ID -Path ./lib/state.json) { + if (select-string -Pattern $CONTAINER_ID -Path ./dist/state.json) { echo "container $CONTAINER_ID is ready" Exit 0 } else { @@ -15,7 +15,7 @@ if ( $CONTAINER_ID ) { } } else { echo "checking if container logger is ready" - if (select-string -Pattern "ready" -Path ./lib/state.json) { + if (select-string -Pattern "ready" -Path ./dist/state.json) { echo "ready" Exit 0 } else { diff --git a/lib/isReady.sh b/lib/isReady.sh index 3032647..329e7ce 100755 --- a/lib/isReady.sh +++ b/lib/isReady.sh @@ -7,10 +7,10 @@ CONTAINER_ID=$1 if [ -n "$CONTAINER_ID" ]; then echo "checking if container: $CONTAINER_ID exists" - grep -q $CONTAINER_ID ./lib/state.json + grep -q $CONTAINER_ID ./dist/state.json else echo "checking if container logger is ready" - grep -q "ready" ./lib/state.json + grep -q "ready" ./dist/state.json fi diff --git a/package.json b/package.json index aaf6852..7c84ab8 100644 --- a/package.json +++ b/package.json @@ -49,7 +49,7 @@ "lint-fix": "eslint '*/**/*.js' --fix", "test": "node ./node_modules/mocha/bin/_mocha './{,!(node_modules)/**/}*.spec.js' --exit", "test:ci": "yarn test", - "start": "node lib/index.js", + "start": "node dist/index.js", "version": "exit 0", "build": "rm -rf dist && tsc -p tsconfig.json" } From 19812b40f3e3a6bed5be1bb698f4f3aff21b1f43 Mon Sep 17 00:00:00 2001 From: Vasil Sudakou Date: Thu, 19 Dec 2024 19:24:45 +0300 Subject: [PATCH 07/20] feat: add parsing logic to detect deprecated images --- lib/ContainerLogger.js | 16 +++++++-- .../deprecated-images.collector.ts | 35 +++++++++++++++++++ service.yaml | 2 +- 3 files changed, 50 insertions(+), 3 deletions(-) diff --git a/lib/ContainerLogger.js b/lib/ContainerLogger.js index 3ecf107..cf7a41e 100644 --- a/lib/ContainerLogger.js +++ b/lib/ContainerLogger.js @@ -3,9 +3,11 @@ const Q = require('q'); const promiseRetry = require('promise-retry'); const logger = require('cf-logs').Logger('codefresh:containerLogger'); const CFError = require('cf-errors'); -const { Transform } = require('stream'); +const { Transform, PassThrough } = require('stream'); + const _ = require('lodash'); const { LoggerStrategy } = require('./enums'); +const deprecatedImagesCollector = require('./metric/deprecated-images/deprecated-images.collector').default; const CONTAINER_START_RETRY_TIMEOUT_SECONDS = 1; const CONTAINER_START_RETRY_LIMIT = 10; @@ -74,6 +76,7 @@ class ContainerLogger extends EventEmitter { this._registerToTtyStreams(stdout, stderr); } else { + // TODO: parse deprecated images here this._handleNonTtyStream(stdout, false); if (stderr) { this._handleNonTtyStream(stderr, true); @@ -131,6 +134,7 @@ class ContainerLogger extends EventEmitter { // { end = false } on the stepLoggerWritableStream because there is only one instance of it for all the steps. this.handledStreams++; let stdoutStream = stdout + .pipe(this._interceptDeprecatedImagesStream()) .pipe(this._logSizeLimitStream()) .pipe(this.stepLogger.createMaskingStream()); @@ -148,6 +152,7 @@ class ContainerLogger extends EventEmitter { this.handledStreams++; let stderrStream = stderr + .pipe(this._interceptDeprecatedImagesStream()) .pipe(this._logSizeLimitStream()) .pipe(this._errorTransformerStream()) .pipe(this.stepLogger.createMaskingStream()); @@ -182,7 +187,9 @@ class ContainerLogger extends EventEmitter { this.handledStreams++; stream.on('end', this._handleFinished.bind(this)); stream.on('data', (chunk) => { - this._logMessage(Buffer.from(chunk).toString('utf-8'), isError); + const message = Buffer.from(chunk).toString('utf-8'); + deprecatedImagesCollector.catchDeprecatedImage(message); + this._logMessage(message, isError); }); logger.info(`Listening on stream 'data' event for container: ${this.containerId}`); } @@ -233,6 +240,11 @@ class ContainerLogger extends EventEmitter { this.emit('message.logged', curLogSize); } + _interceptDeprecatedImagesStream() { + return new PassThrough() + .on('data', (chunk) => deprecatedImagesCollector.catchDeprecatedImage(chunk.toString('utf8'))); + } + _errorTransformerStream() { return new Transform({ transform: (data, encoding, done) => { diff --git a/lib/metric/deprecated-images/deprecated-images.collector.ts b/lib/metric/deprecated-images/deprecated-images.collector.ts index 01dc202..af81360 100644 --- a/lib/metric/deprecated-images/deprecated-images.collector.ts +++ b/lib/metric/deprecated-images/deprecated-images.collector.ts @@ -1,5 +1,10 @@ +// @ts-expect-error it's a js library +import cfLogs from 'cf-logs'; + import { DeprecatedImageDto } from './deprecated-image.dto'; +const logger = cfLogs.Logger('codefresh:containerLogger'); + class DeprecatedImagesCollector { private list: DeprecatedImageDto[] = []; @@ -15,6 +20,36 @@ class DeprecatedImagesCollector { destroyConsumed(consumedNumber: number) { this.list = this.list.slice(consumedNumber); } + + catchDeprecatedImage(logText: string) { + if (logText.includes('[DEPRECATION NOTICE]')) { + const imageName = this._parseImageName(logText); + + if (imageName === null) { + logger.error(`detected pulling of the deprecated image but failed to parse the image name. The original log text: '${logText}'`); + } else { + logger.warn(`detected pulling of the deprecated image '${imageName}'. The original log text: '${logText}'`); + + this.push({ + image: imageName, + }); + } + } + } + + private _parseImageName(logText: string) { + const startMarker = 'Suggest the author of '; + const endMarker = ' to upgrade the image'; + + const startIndex = logText.indexOf(startMarker); + const endIndex = logText.indexOf(endMarker); + + if (startIndex > -1 && endIndex > -1 && endIndex > startIndex) { + return logText.substring(startIndex + startMarker.length, endIndex); + } + + return null; + } } export default new DeprecatedImagesCollector(); diff --git a/service.yaml b/service.yaml index 0c28069..90fbe49 100644 --- a/service.yaml +++ b/service.yaml @@ -1 +1 @@ -version: 1.11.8 +version: 1.12.0 From f7ede74844353626ce656d0a415e3e2313a05cd4 Mon Sep 17 00:00:00 2001 From: Vasil Sudakou Date: Mon, 23 Dec 2024 16:38:57 +0300 Subject: [PATCH 08/20] feat: add nodejs scripts to interact with http api --- .eslintrc.json | 2 +- .../ack-deprecated-images.script.js | 33 +++++++++++++++++++ .../get-deprecated-images.script.js | 20 +++++++++++ 3 files changed, 54 insertions(+), 1 deletion(-) create mode 100755 lib/metric/deprecated-images/ack-deprecated-images.script.js create mode 100755 lib/metric/deprecated-images/get-deprecated-images.script.js diff --git a/.eslintrc.json b/.eslintrc.json index f7fcc79..fbef7fa 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -85,7 +85,7 @@ "node/no-unsupported-features": "error", "node/process-exit-as-throw": "error", - "node/shebang": "warn", + "node/shebang": "off", "node/no-deprecated-api": "warn", "no-useless-constructor": "warn", "no-return-await": "off" diff --git a/lib/metric/deprecated-images/ack-deprecated-images.script.js b/lib/metric/deprecated-images/ack-deprecated-images.script.js new file mode 100755 index 0000000..3e3ab07 --- /dev/null +++ b/lib/metric/deprecated-images/ack-deprecated-images.script.js @@ -0,0 +1,33 @@ +#!/usr/bin/env node + +async function ackDeprecatedImages() { + try { + const count = Number(process.argv[2]); + if (Number.isNaN(count)) { + console.error('Usage: node ./ack-deprecated-images.script.js '); + process.exit(1); + } + + const URL = 'http://0.0.0.0:8080/deprecated-images/ack'; + + const response = await fetch(URL, { + method: 'POST', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ count }), + }); + + if (!response.ok) { + throw new Error(`Request failed with status ${response.status}`); + } + + const data = await response.json(); + console.log(JSON.stringify(data)); + } catch (error) { + console.error('Error: ', error); + process.exit(1); + } +} + +ackDeprecatedImages(); diff --git a/lib/metric/deprecated-images/get-deprecated-images.script.js b/lib/metric/deprecated-images/get-deprecated-images.script.js new file mode 100755 index 0000000..9d6d5e1 --- /dev/null +++ b/lib/metric/deprecated-images/get-deprecated-images.script.js @@ -0,0 +1,20 @@ +#!/usr/bin/env node + +async function getDeprecatedImages() { + try { + const URL = 'http://0.0.0.0:8080/deprecated-images'; + + const response = await fetch(URL); + if (!response.ok) { + throw new Error(`Request failed with status ${response.status}`); + } + + const data = await response.json(); + console.log(JSON.stringify(data)); + } catch (error) { + console.error('Error: ', error); + process.exit(1); + } +} + +getDeprecatedImages(); From 1f50574f9c32d16bf2aa09c730565c423daf6f47 Mon Sep 17 00:00:00 2001 From: Vasil Sudakou Date: Tue, 24 Dec 2024 15:58:27 +0300 Subject: [PATCH 09/20] fix: eslint warning --- lib/ContainerLogger.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/ContainerLogger.js b/lib/ContainerLogger.js index cf7a41e..a2397da 100644 --- a/lib/ContainerLogger.js +++ b/lib/ContainerLogger.js @@ -7,6 +7,8 @@ const { Transform, PassThrough } = require('stream'); const _ = require('lodash'); const { LoggerStrategy } = require('./enums'); + +// eslint-disable-next-line import/no-unresolved const deprecatedImagesCollector = require('./metric/deprecated-images/deprecated-images.collector').default; const CONTAINER_START_RETRY_TIMEOUT_SECONDS = 1; From 8c2b7067934131bd9ccf2a951250c8fcd1fece93 Mon Sep 17 00:00:00 2001 From: Vasil Sudakou Date: Thu, 9 Jan 2025 05:40:12 +0300 Subject: [PATCH 10/20] fix: use regex for parsing the deprecated image --- .../deprecated-images.collector.ts | 36 +++++++------------ 1 file changed, 13 insertions(+), 23 deletions(-) diff --git a/lib/metric/deprecated-images/deprecated-images.collector.ts b/lib/metric/deprecated-images/deprecated-images.collector.ts index af81360..9ce0cda 100644 --- a/lib/metric/deprecated-images/deprecated-images.collector.ts +++ b/lib/metric/deprecated-images/deprecated-images.collector.ts @@ -1,6 +1,7 @@ // @ts-expect-error it's a js library import cfLogs from 'cf-logs'; +// eslint-disable-next-line import/no-unresolved import { DeprecatedImageDto } from './deprecated-image.dto'; const logger = cfLogs.Logger('codefresh:containerLogger'); @@ -22,33 +23,22 @@ class DeprecatedImagesCollector { } catchDeprecatedImage(logText: string) { - if (logText.includes('[DEPRECATION NOTICE]')) { - const imageName = this._parseImageName(logText); - - if (imageName === null) { - logger.error(`detected pulling of the deprecated image but failed to parse the image name. The original log text: '${logText}'`); - } else { - logger.warn(`detected pulling of the deprecated image '${imageName}'. The original log text: '${logText}'`); - - this.push({ - image: imageName, - }); - } - } - } - - private _parseImageName(logText: string) { - const startMarker = 'Suggest the author of '; - const endMarker = ' to upgrade the image'; + const imageName = this._parseImageName(logText); - const startIndex = logText.indexOf(startMarker); - const endIndex = logText.indexOf(endMarker); + if (imageName !== null) { + logger.warn(`detected pulling of the deprecated image '${imageName}'. The original log text: '${logText}'`); - if (startIndex > -1 && endIndex > -1 && endIndex > startIndex) { - return logText.substring(startIndex + startMarker.length, endIndex); + this.push({ + image: imageName, + }); } + } - return null; + private _parseImageName(logText: string) { + // eslint-disable-next-line no-control-regex + const regex = /^\u001b\[31m\u001b\[1m\[DEPRECATION NOTICE].+?Suggest the author of (?.+?) to/; + const match = logText.match(regex); + return match?.groups?.image ?? null; } } From a018a221313ad1bfa2580e895f4d91b12e7a12f2 Mon Sep 17 00:00:00 2001 From: Vasil Sudakou Date: Thu, 9 Jan 2025 05:42:02 +0300 Subject: [PATCH 11/20] fix: convert chunks to text lines before parsing them --- lib/ContainerLogger.js | 22 ++++---- .../deprecated-images-interceptor.stream.ts | 52 +++++++++++++++++++ 2 files changed, 61 insertions(+), 13 deletions(-) create mode 100644 lib/metric/deprecated-images/deprecated-images-interceptor.stream.ts diff --git a/lib/ContainerLogger.js b/lib/ContainerLogger.js index a2397da..02246cc 100644 --- a/lib/ContainerLogger.js +++ b/lib/ContainerLogger.js @@ -3,13 +3,13 @@ const Q = require('q'); const promiseRetry = require('promise-retry'); const logger = require('cf-logs').Logger('codefresh:containerLogger'); const CFError = require('cf-errors'); -const { Transform, PassThrough } = require('stream'); +const { Transform } = require('stream'); const _ = require('lodash'); const { LoggerStrategy } = require('./enums'); // eslint-disable-next-line import/no-unresolved -const deprecatedImagesCollector = require('./metric/deprecated-images/deprecated-images.collector').default; +const { DeprecatedImagesInterceptorStream } = require('./metric/deprecated-images/deprecated-images-interceptor.stream'); const CONTAINER_START_RETRY_TIMEOUT_SECONDS = 1; const CONTAINER_START_RETRY_LIMIT = 10; @@ -78,9 +78,10 @@ class ContainerLogger extends EventEmitter { this._registerToTtyStreams(stdout, stderr); } else { - // TODO: parse deprecated images here + stdout = stdout.pipe(new DeprecatedImagesInterceptorStream()); this._handleNonTtyStream(stdout, false); if (stderr) { + stderr = stderr.pipe(new DeprecatedImagesInterceptorStream()); this._handleNonTtyStream(stderr, true); } } @@ -136,7 +137,7 @@ class ContainerLogger extends EventEmitter { // { end = false } on the stepLoggerWritableStream because there is only one instance of it for all the steps. this.handledStreams++; let stdoutStream = stdout - .pipe(this._interceptDeprecatedImagesStream()) + .pipe(new DeprecatedImagesInterceptorStream()) .pipe(this._logSizeLimitStream()) .pipe(this.stepLogger.createMaskingStream()); @@ -154,7 +155,7 @@ class ContainerLogger extends EventEmitter { this.handledStreams++; let stderrStream = stderr - .pipe(this._interceptDeprecatedImagesStream()) + .pipe(new DeprecatedImagesInterceptorStream()) .pipe(this._logSizeLimitStream()) .pipe(this._errorTransformerStream()) .pipe(this.stepLogger.createMaskingStream()); @@ -174,9 +175,11 @@ class ContainerLogger extends EventEmitter { } _registerToTtyStreams(stdout, stderr) { + stdout = stdout.pipe(new DeprecatedImagesInterceptorStream()); this._handleTtyStream(stdout, false); if (stderr) { + stderr = stderr.pipe(new DeprecatedImagesInterceptorStream()); stderr.once('end', () => { this.stepFinished = true; logger.info(`stderr end event was fired for container: ${this.containerId}`); @@ -189,9 +192,7 @@ class ContainerLogger extends EventEmitter { this.handledStreams++; stream.on('end', this._handleFinished.bind(this)); stream.on('data', (chunk) => { - const message = Buffer.from(chunk).toString('utf-8'); - deprecatedImagesCollector.catchDeprecatedImage(message); - this._logMessage(message, isError); + this._logMessage(Buffer.from(chunk).toString('utf-8'), isError); }); logger.info(`Listening on stream 'data' event for container: ${this.containerId}`); } @@ -242,11 +243,6 @@ class ContainerLogger extends EventEmitter { this.emit('message.logged', curLogSize); } - _interceptDeprecatedImagesStream() { - return new PassThrough() - .on('data', (chunk) => deprecatedImagesCollector.catchDeprecatedImage(chunk.toString('utf8'))); - } - _errorTransformerStream() { return new Transform({ transform: (data, encoding, done) => { diff --git a/lib/metric/deprecated-images/deprecated-images-interceptor.stream.ts b/lib/metric/deprecated-images/deprecated-images-interceptor.stream.ts new file mode 100644 index 0000000..30ac6a2 --- /dev/null +++ b/lib/metric/deprecated-images/deprecated-images-interceptor.stream.ts @@ -0,0 +1,52 @@ +import { Transform, TransformCallback } from 'stream'; + +// eslint-disable-next-line import/no-unresolved +import deprecatedImagesCollector from './deprecated-images.collector'; + +export class DeprecatedImagesInterceptorStream extends Transform { + private _lastChunk: Buffer; + + constructor() { + super(); + this._lastChunk = Buffer.alloc(0); + } + + _transform(chunk: Buffer, encoding: BufferEncoding, callback: TransformCallback): void { + try { + + const text = Buffer + .concat([this._lastChunk, chunk]) + .toString('utf8'); + + const lines = text.split('\n'); + + // the final element in 'lines' may be an incomplete line + // save it in _lastChunk for next time + this._lastChunk = Buffer.from(lines.pop() ?? '', 'utf8'); + + for (const line of lines) { + deprecatedImagesCollector.catchDeprecatedImage(line.trim()); + } + + this.push(chunk); + callback(); + } catch (error) { + callback(error as any); + } + } + + /** + * _flush() is called when there is no more incoming data. + * If we still have leftover data that didn't end with a newline, + * treat it as a final line to be processed. + */ + _flush(callback: TransformCallback): void { + try { + const finalLine = this._lastChunk.toString('utf8'); + deprecatedImagesCollector.catchDeprecatedImage(finalLine.trim()); + callback(); + } catch (error) { + callback(error as any); + } + } +} From 325495a38231343cac521bb29df818463a69afa3 Mon Sep 17 00:00:00 2001 From: Vasil Sudakou Date: Thu, 9 Jan 2025 05:54:01 +0300 Subject: [PATCH 12/20] fix: remove the scripts and Dockerfile for windows os which are unused and confusing --- Dockerfile.windows | 55 ---------------------------------------------- lib/forever.ps1 | 4 ---- lib/isReady.ps1 | 25 --------------------- 3 files changed, 84 deletions(-) delete mode 100644 Dockerfile.windows delete mode 100644 lib/forever.ps1 delete mode 100644 lib/isReady.ps1 diff --git a/Dockerfile.windows b/Dockerfile.windows deleted file mode 100644 index 1dcbec8..0000000 --- a/Dockerfile.windows +++ /dev/null @@ -1,55 +0,0 @@ -ARG OS_RELEASE - -FROM mcr.microsoft.com/windows/servercore:${OS_RELEASE} as download - -SHELL ["powershell", "-Command", "$ErrorActionPreference = 'Stop'; $ProgressPreference = 'SilentlyContinue';"] - -ENV GIT_VERSION 2.39.0 -ENV NODE_VERSION 16.20.0 -ENV YARN_VERSION 1.22.19 - -# Download and install git -RUN Invoke-WebRequest $('https://github.com/git-for-windows/git/releases/download/v{0}.windows.1/MinGit-{0}-64-bit.zip' -f $env:GIT_VERSION) -OutFile 'MinGit.zip' -UseBasicParsing ; \ - Expand-Archive c:\MinGit.zip -DestinationPath c:\MinGit; \ - $env:PATH = $env:PATH + ';C:\MinGit\cmd\;C:\MinGit\cmd'; \ - Set-ItemProperty -Path 'HKLM:\SYSTEM\CurrentControlSet\Control\Session Manager\Environment\' -Name Path -Value $env:PATH - -# Download and install node.js -RUN Invoke-WebRequest $('https://nodejs.org/dist/v{0}/node-v{0}-win-x64.zip' -f $env:NODE_VERSION) -OutFile 'node.zip' -UseBasicParsing ; \ - # $sum = $(cat SHASUMS256.txt.asc | sls $(' node-v{0}-win-x64.zip' -f $env:NODE_VERSION)) -Split ' ' ; \ - # if ((Get-FileHash node.zip -Algorithm sha256).Hash -ne $sum[0]) { Write-Error 'SHA256 mismatch' } ; \ - Expand-Archive node.zip -DestinationPath C:\ ; \ - Rename-Item -Path $('C:\node-v{0}-win-x64' -f $env:NODE_VERSION) -NewName 'C:\nodejs' - -# Download and install yarn -RUN [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 ; \ - Invoke-WebRequest $('https://github.com/yarnpkg/yarn/releases/download/v{0}/yarn-{0}.msi' -f $env:YARN_VERSION) -OutFile yarn.msi -UseBasicParsing ; \ - Start-Process msiexec.exe -ArgumentList '/i', 'yarn.msi', '/quiet', '/norestart' -NoNewWindow -Wait - -FROM download as install - -SHELL ["powershell", "-Command", "$ErrorActionPreference = 'Stop'; $ProgressPreference = 'SilentlyContinue';"] - -ENV NPM_CONFIG_LOGLEVEL info - -COPY --from=download /nodejs /nodejs -COPY --from=download [ "/Program Files (x86)/yarn", "/yarn" ] - -RUN $env:PATH = 'C:\nodejs;C:\yarn\bin;{0}' -f $env:PATH ; \ - [Environment]::SetEnvironmentVariable('PATH', $env:PATH, [EnvironmentVariableTarget]::Machine) - -FROM install - -WORKDIR C:/cf-container-logger - -COPY package.json ./ - -COPY yarn.lock ./ - -RUN yarn install --frozen-lockfile --production - -COPY . ./ - -LABEL owner="codefresh.io" - -CMD ["powershell", "./lib/forever.ps1"] diff --git a/lib/forever.ps1 b/lib/forever.ps1 deleted file mode 100644 index 3e33432..0000000 --- a/lib/forever.ps1 +++ /dev/null @@ -1,4 +0,0 @@ -while ($true) { - Start-Sleep -s 1 - & node dist/index.js -} diff --git a/lib/isReady.ps1 b/lib/isReady.ps1 deleted file mode 100644 index 421779d..0000000 --- a/lib/isReady.ps1 +++ /dev/null @@ -1,25 +0,0 @@ -# DEPRECATED: -# This script is no longer maintained, you should use the ./isReady.js script -# Leaving this script for backwards compatibility (so this container logger can work with older engines) - -$CONTAINER_ID=$args[0] - -if ( $CONTAINER_ID ) { - echo "checking if container:$CONTAINER_ID exists" - if (select-string -Pattern $CONTAINER_ID -Path ./dist/state.json) { - echo "container $CONTAINER_ID is ready" - Exit 0 - } else { - echo "container $CONTAINER_ID is not ready" - Exit 1 - } -} else { - echo "checking if container logger is ready" - if (select-string -Pattern "ready" -Path ./dist/state.json) { - echo "ready" - Exit 0 - } else { - echo "not ready" - Exit 1 - } -} From 90caf0947ff9f696744475cf7db94522ba20af0c Mon Sep 17 00:00:00 2001 From: Vasil Sudakou Date: Thu, 9 Jan 2025 07:28:36 +0300 Subject: [PATCH 13/20] fix: move tests to lib directory --- .dockerignore | 2 +- .../test}/ContainerLogger.unit.spec.js | 4 +- {test => lib/test}/addNewMask.unit.spec.js | 14 ++-- {test => lib/test}/helpers.unit.spec.js | 16 ++-- {test => lib/test}/isReady.unit.spec.js | 16 ++-- {test => lib/test}/logger.unit.spec.js | 84 +++++++++---------- {test => lib/test}/waitUntilFinish.spec.js | 8 +- package.json | 2 +- tsconfig.json | 4 +- 9 files changed, 75 insertions(+), 75 deletions(-) rename {test => lib/test}/ContainerLogger.unit.spec.js (99%) rename {test => lib/test}/addNewMask.unit.spec.js (96%) rename {test => lib/test}/helpers.unit.spec.js (91%) rename {test => lib/test}/isReady.unit.spec.js (90%) rename {test => lib/test}/logger.unit.spec.js (96%) rename {test => lib/test}/waitUntilFinish.spec.js (91%) diff --git a/.dockerignore b/.dockerignore index 83b1b3c..3862197 100644 --- a/.dockerignore +++ b/.dockerignore @@ -6,6 +6,6 @@ logs/*.log lib/state.json *.md .eslintrc.json -test +lib/test .eslintignore dist diff --git a/test/ContainerLogger.unit.spec.js b/lib/test/ContainerLogger.unit.spec.js similarity index 99% rename from test/ContainerLogger.unit.spec.js rename to lib/test/ContainerLogger.unit.spec.js index e382571..e96b0b4 100644 --- a/test/ContainerLogger.unit.spec.js +++ b/lib/test/ContainerLogger.unit.spec.js @@ -6,7 +6,7 @@ const sinon = require('sinon'); const proxyquire = require('proxyquire'); const promiseRetry = require('promise-retry'); const sinonChai = require('sinon-chai'); -const LoggerStrategy = require('../lib/enums').LoggerStrategy; +const LoggerStrategy = require('../enums').LoggerStrategy; const { EventEmitter } = require('events'); const { Writable, Readable, PassThrough } = require('stream'); @@ -15,7 +15,7 @@ chai.use(sinonChai); const promiseRetrySpy = sinon.spy((err) => Q.reject(err)); -const ContainerLogger = proxyquire('../lib/ContainerLogger', { +const ContainerLogger = proxyquire('../ContainerLogger', { 'promise-retry': (cb) => cb(promiseRetrySpy, 1), }); diff --git a/test/addNewMask.unit.spec.js b/lib/test/addNewMask.unit.spec.js similarity index 96% rename from test/addNewMask.unit.spec.js rename to lib/test/addNewMask.unit.spec.js index 64bf80d..ffa8c60 100644 --- a/test/addNewMask.unit.spec.js +++ b/lib/test/addNewMask.unit.spec.js @@ -57,7 +57,7 @@ describe('addNewMask', () => { stubGetServerAddress.resolves(serverAddress); stubGot.post.resolves({ statusCode: 201 }); - const { updateMasks, exitHandler } = proxyquire('../lib/addNewMask', { + const { updateMasks, exitHandler } = proxyquire('../addNewMask', { './helpers': { getServerAddress: stubGetServerAddress }, }); process.listeners('exit').forEach((listener) => { @@ -77,7 +77,7 @@ describe('addNewMask', () => { describe('negative', () => { it('should fail if the server address is not available', async () => { stubGetServerAddress.rejects('could not get server address'); - const { updateMasks, exitHandler } = proxyquire('../lib/addNewMask', { + const { updateMasks, exitHandler } = proxyquire('../addNewMask', { './helpers': { getServerAddress: stubGetServerAddress, }, @@ -94,7 +94,7 @@ describe('addNewMask', () => { it('should fail if the server address is not valid URL', async () => { stubGetServerAddress.resolves('foo'); - const { updateMasks, exitHandler } = proxyquire('../lib/addNewMask', { + const { updateMasks, exitHandler } = proxyquire('../addNewMask', { './helpers': { getServerAddress: stubGetServerAddress, }, @@ -116,7 +116,7 @@ describe('addNewMask', () => { statusCode: 500, body: 'Internal Server Error', }); - const { updateMasks, exitHandler } = proxyquire('../lib/addNewMask', { + const { updateMasks, exitHandler } = proxyquire('../addNewMask', { './helpers': { getServerAddress: stubGetServerAddress }, }); process.listeners('exit').forEach((listener) => { @@ -132,7 +132,7 @@ describe('addNewMask', () => { describe('exitHandler', () => { it('should set exit code to 3 if the original exit code is 0 and variable was not masked', () => { - const { exitHandler } = proxyquire('../lib/addNewMask', {}); + const { exitHandler } = proxyquire('../addNewMask', {}); process.listeners('exit').forEach((listener) => { if (listener === exitHandler) { process.removeListener('exit', listener); @@ -145,7 +145,7 @@ describe('addNewMask', () => { }); it('should set exit code to 3 if the original exit code is 0 and variable was not masked', () => { - const { exitHandler } = proxyquire('../lib/addNewMask', {}); + const { exitHandler } = proxyquire('../addNewMask', {}); process.listeners('exit').forEach((listener) => { if (listener === exitHandler) { process.removeListener('exit', listener); @@ -165,7 +165,7 @@ describe('addNewMask', () => { const serverAddress = 'https://xkcd.com/605/' stubGetServerAddress.resolves(serverAddress); stubGot.post.resolves({ statusCode: 201 }); - const { updateMasks, exitHandler } = proxyquire('../lib/addNewMask', { + const { updateMasks, exitHandler } = proxyquire('../addNewMask', { './helpers': { getServerAddress: stubGetServerAddress }, }); process.listeners('exit').forEach((listener) => { diff --git a/test/helpers.unit.spec.js b/lib/test/helpers.unit.spec.js similarity index 91% rename from test/helpers.unit.spec.js rename to lib/test/helpers.unit.spec.js index 40dccd4..4927afe 100644 --- a/test/helpers.unit.spec.js +++ b/lib/test/helpers.unit.spec.js @@ -28,7 +28,7 @@ describe('helpers', () => { it('should write the server address to the file', async () => { const SERVER_ADDRESS_PATH = 'little/bobby/tables/we/call/him'; const serverAddress = 'foo'; - const { saveServerAddress } = proxyquire('../lib/helpers.js', { + const { saveServerAddress } = proxyquire('../helpers.js', { 'node:fs/promises': stubFsPromises, 'cf-logs': { Logger: () => stubLogger }, './const': { SERVER_ADDRESS_PATH }, @@ -36,9 +36,9 @@ describe('helpers', () => { await saveServerAddress(serverAddress); expect(stubFsPromises.writeFile).to.have.been.calledOnceWithExactly(SERVER_ADDRESS_PATH, serverAddress, { encoding: 'utf8' }); }); - + it('should fail if the file cannot be written', async () => { - const { saveServerAddress } = proxyquire('../lib/helpers.js', { + const { saveServerAddress } = proxyquire('../helpers.js', { 'node:fs/promises': stubFsPromises, 'cf-logs': { Logger: () => stubLogger }, }); @@ -53,12 +53,12 @@ describe('helpers', () => { } }); }); - + describe('getServerAddress()', () => { it('should read the server address from the file', async () => { const SERVER_ADDRESS_PATH = 'little/bobby/tables/we/call/him'; const serverAddress = 'foo'; - const { getServerAddress } = proxyquire('../lib/helpers.js', { + const { getServerAddress } = proxyquire('../helpers.js', { 'node:fs/promises': stubFsPromises, 'cf-logs': { Logger: () => stubLogger }, './const': { SERVER_ADDRESS_PATH }, @@ -68,9 +68,9 @@ describe('helpers', () => { expect(result).to.be.equal(serverAddress); expect(stubFsPromises.readFile).to.have.been.calledOnceWithExactly(SERVER_ADDRESS_PATH, { encoding: 'utf8' }); }); - + it('should fail if the file cannot be read', async () => { - const { getServerAddress } = proxyquire('../lib/helpers.js', { + const { getServerAddress } = proxyquire('../helpers.js', { 'node:fs/promises': stubFsPromises, 'cf-logs': { Logger: () => stubLogger }, }); @@ -87,7 +87,7 @@ describe('helpers', () => { }); it('should write/read to/from the same location', async () => { - const { saveServerAddress, getServerAddress } = require('../lib/helpers.js'); + const { saveServerAddress, getServerAddress } = require('../helpers.js'); const serverAddress = 'http://g.codefresh.io'; await saveServerAddress(serverAddress); const result = await getServerAddress(); diff --git a/test/isReady.unit.spec.js b/lib/test/isReady.unit.spec.js similarity index 90% rename from test/isReady.unit.spec.js rename to lib/test/isReady.unit.spec.js index 92486cf..4dd92d0 100644 --- a/test/isReady.unit.spec.js +++ b/lib/test/isReady.unit.spec.js @@ -1,6 +1,6 @@ const chai = require('chai'); const sinon = require('sinon'); -const { ContainerHandlingStatus } = require('../lib/enums'); +const { ContainerHandlingStatus } = require('../enums'); const proxyquire = require('proxyquire'); const expect = chai.expect; @@ -21,7 +21,7 @@ describe('isReady script', () => { it('Should check exit with 0 code if container logger is ready', () => { const state = JSON.stringify({ status: 'ready', containers: {} }) process.argv = []; - proxyquire('../lib/isReady.js', { + proxyquire('../isReady.js', { 'fs': { readFileSync: () => Buffer.from(state), }, @@ -31,7 +31,7 @@ describe('isReady script', () => { it('Should check exit with 1 code if container logger is not ready', () => { const state = JSON.stringify({ status: 'notReady', containers: {} }) process.argv = []; - proxyquire('../lib/isReady.js', { + proxyquire('../isReady.js', { 'fs': { readFileSync: () => Buffer.from(state), }, @@ -43,7 +43,7 @@ describe('isReady script', () => { it('Should check exit with 0 code if container is ready', () => { const state = JSON.stringify({ status: 'ready', containers: { 'container-id': { status: ContainerHandlingStatus.LISTENING } } }) process.argv = ['foo', 'bar', 'container-id']; - proxyquire('../lib/isReady.js', { + proxyquire('../isReady.js', { 'fs': { readFileSync: () => Buffer.from(state), }, @@ -53,7 +53,7 @@ describe('isReady script', () => { it('Should check exit with 0 code if container is waiting for start status', () => { const state = JSON.stringify({ status: 'ready', containers: { 'container-id': { status: ContainerHandlingStatus.WAITING_FOR_START } } }) process.argv = ['foo', 'bar', 'container-id']; - proxyquire('../lib/isReady.js', { + proxyquire('../isReady.js', { 'fs': { readFileSync: () => Buffer.from(state), }, @@ -63,7 +63,7 @@ describe('isReady script', () => { it('Should check exit with 0 code if container is finished status', () => { const state = JSON.stringify({ status: 'ready', containers: { 'container-id': { status: ContainerHandlingStatus.FINISHED } } }) process.argv = ['foo', 'bar', 'container-id']; - proxyquire('../lib/isReady.js', { + proxyquire('../isReady.js', { 'fs': { readFileSync: () => Buffer.from(state), }, @@ -73,7 +73,7 @@ describe('isReady script', () => { it('Should check exit with 1 code if container is not ready', () => { const state = JSON.stringify({ status: 'ready', containers: { 'container-id': { status: ContainerHandlingStatus.INITIALIZING } } }) process.argv = ['foo', 'bar', 'container-id']; - proxyquire('../lib/isReady.js', { + proxyquire('../isReady.js', { 'fs': { readFileSync: () => Buffer.from(state), }, @@ -81,4 +81,4 @@ describe('isReady script', () => { expect(process.exit).to.have.been.calledOnceWith(1); }); }); -}); \ No newline at end of file +}); diff --git a/test/logger.unit.spec.js b/lib/test/logger.unit.spec.js similarity index 96% rename from test/logger.unit.spec.js rename to lib/test/logger.unit.spec.js index eaf196d..6970936 100644 --- a/test/logger.unit.spec.js +++ b/lib/test/logger.unit.spec.js @@ -5,9 +5,9 @@ const chai = require('chai'); const sinon = require('sinon'); const sinonChai = require('sinon-chai'); const { EventEmitter } = require('events'); -const { ContainerStatus } = require('../lib/enums'); -const { LoggerStrategy } = require('../lib/enums'); -const { getPromiseWithResolvers } = require('../lib/helpers'); +const { ContainerStatus } = require('../enums'); +const { LoggerStrategy } = require('../enums'); +const { getPromiseWithResolvers } = require('../helpers'); const expect = chai.expect; chai.use(sinonChai); @@ -43,7 +43,7 @@ describe('Logger tests', () => { describe('constructor', () => { it('should define workflow log size limit default in case of non provided value', () => { - const Logger = proxyquire('../lib/logger', { + const Logger = proxyquire('../logger', { 'fastify': stubFastify, './helpers': { saveServerAddress: stubSaveServerAddress, @@ -68,7 +68,7 @@ describe('Logger tests', () => { }); it('should use passed workflow log size limit in case passed', () => { - const Logger = proxyquire('../lib/logger', { + const Logger = proxyquire('../logger', { 'fastify': stubFastify, './helpers': { saveServerAddress: stubSaveServerAddress, @@ -111,7 +111,7 @@ describe('Logger tests', () => { return Q.resolve(taskLogger); }); - const Logger = proxyquire('../lib/logger', { + const Logger = proxyquire('../logger', { '@codefresh-io/task-logger': { TaskLogger: TaskLoggerFactory }, 'fastify': stubFastify, './helpers': { @@ -159,7 +159,7 @@ describe('Logger tests', () => { return Q.resolve(taskLogger); }); - const Logger = proxyquire('../lib/logger', { + const Logger = proxyquire('../logger', { '@codefresh-io/task-logger': { TaskLogger: TaskLoggerFactory }, 'fastify': stubFastify, './helpers': { @@ -205,7 +205,7 @@ describe('Logger tests', () => { return Q.resolve(taskLogger); }); - const Logger = proxyquire('../lib/logger', { + const Logger = proxyquire('../logger', { '@codefresh-io/task-logger': { TaskLogger: TaskLoggerFactory }, 'fastify': stubFastify, './helpers': { @@ -250,7 +250,7 @@ describe('Logger tests', () => { return Q.resolve(taskLogger); }); - const Logger = proxyquire('../lib/logger', { + const Logger = proxyquire('../logger', { '@codefresh-io/task-logger': { TaskLogger: TaskLoggerFactory }, 'fastify': stubFastify, './helpers': { @@ -300,7 +300,7 @@ describe('Logger tests', () => { return Q.reject(new Error('my error')); }); - const Logger = proxyquire('../lib/logger', { + const Logger = proxyquire('../logger', { '@codefresh-io/task-logger': { TaskLogger: TaskLoggerFactory }, 'fastify': stubFastify, './helpers': { @@ -334,7 +334,7 @@ describe('Logger tests', () => { callback(null, [{}, {}]); }); - const Logger = proxyquire('../lib/logger', { + const Logger = proxyquire('../logger', { 'dockerode': function () { return { listContainers: listContainersSpy @@ -362,7 +362,7 @@ describe('Logger tests', () => { callback(null, []); }); - const Logger = proxyquire('../lib/logger', { + const Logger = proxyquire('../logger', { 'dockerode': function () { return { listContainers: listContainersSpy @@ -394,7 +394,7 @@ describe('Logger tests', () => { callback(new Error('getting containers error')); }); - const Logger = proxyquire('../lib/logger', { + const Logger = proxyquire('../logger', { 'dockerode': function () { return { listContainers: listContainersSpy @@ -428,7 +428,7 @@ describe('Logger tests', () => { it('should call handleContainer in case of an create event', () => { const startSpy = sinon.spy(); const onSpy = sinon.spy(); - const Logger = proxyquire('../lib/logger', { + const Logger = proxyquire('../logger', { 'docker-events': function () { return { start: startSpy, @@ -460,7 +460,7 @@ describe('Logger tests', () => { callback(); }); - const Logger = proxyquire('../lib/logger', { + const Logger = proxyquire('../logger', { 'fs': { writeFile: writeFileSpy, readFileSync: sinon.spy(() => { @@ -485,7 +485,7 @@ describe('Logger tests', () => { callback(new Error('write error')); }); - const Logger = proxyquire('../lib/logger', { + const Logger = proxyquire('../logger', { 'fs': { writeFile: writeFileSpy, readFileSync: sinon.spy(() => { @@ -510,7 +510,7 @@ describe('Logger tests', () => { describe('validate', () => { it('should call process exit in case firebase authentication url was not provided', () => { - const Logger = proxyquire('../lib/logger', { + const Logger = proxyquire('../logger', { 'fastify': stubFastify, './helpers': { saveServerAddress: stubSaveServerAddress, @@ -537,7 +537,7 @@ describe('Logger tests', () => { }); process.exit = processExitSpy; - const Logger = proxyquire('../lib/logger', { + const Logger = proxyquire('../logger', { 'fastify': stubFastify, './helpers': { saveServerAddress: stubSaveServerAddress, @@ -564,7 +564,7 @@ describe('Logger tests', () => { }); process.exit = processExitSpy; - const Logger = proxyquire('../lib/logger', { + const Logger = proxyquire('../logger', { 'fastify': stubFastify, './helpers': { saveServerAddress: stubSaveServerAddress, @@ -591,7 +591,7 @@ describe('Logger tests', () => { }); process.exit = processExitSpy; - const Logger = proxyquire('../lib/logger', { + const Logger = proxyquire('../logger', { 'fastify': stubFastify, './helpers': { saveServerAddress: stubSaveServerAddress, @@ -632,7 +632,7 @@ describe('Logger tests', () => { emitter.start = startSpy; return emitter; }); - const Logger = proxyquire('../lib/logger', { + const Logger = proxyquire('../logger', { 'cf-logs': { Logger: () => { return { @@ -685,7 +685,7 @@ describe('Logger tests', () => { it('should pass received step log size limit to ContainerLogger', async () => { const infoSpy = sinon.spy(); const errorSpy = sinon.spy(); - const Logger = proxyquire('../lib/logger', { + const Logger = proxyquire('../logger', { 'cf-logs': { Logger: () => { return { @@ -737,7 +737,7 @@ describe('Logger tests', () => { it('should pass undefined step log size limit to ContainerLogger in case of no label', async () => { const infoSpy = sinon.spy(); const errorSpy = sinon.spy(); - const Logger = proxyquire('../lib/logger', { + const Logger = proxyquire('../logger', { 'cf-logs': { Logger: () => { return { @@ -785,7 +785,7 @@ describe('Logger tests', () => { it('should update total log size when new log message event was sent', async () => { const infoSpy = sinon.spy(); const errorSpy = sinon.spy(); - const Logger = proxyquire('../lib/logger', { + const Logger = proxyquire('../logger', { 'cf-logs': { Logger: () => { return { @@ -849,7 +849,7 @@ describe('Logger tests', () => { }); const infoSpy = sinon.spy(); const errorSpy = sinon.spy(); - const Logger = proxyquire('../lib/logger', { + const Logger = proxyquire('../logger', { 'cf-logs': { Logger: () => { return { @@ -923,7 +923,7 @@ describe('Logger tests', () => { it('was previously handled', () => { const infoSpy = sinon.spy(); const errorSpy = sinon.spy(); - const Logger = proxyquire('../lib/logger', { + const Logger = proxyquire('../logger', { 'cf-logs': { Logger: () => { return { @@ -973,7 +973,7 @@ describe('Logger tests', () => { it('no loggerId', () => { const infoSpy = sinon.spy(); const errorSpy = sinon.spy(); - const Logger = proxyquire('../lib/logger', { + const Logger = proxyquire('../logger', { 'cf-logs': { Logger: () => { return { @@ -1018,7 +1018,7 @@ describe('Logger tests', () => { it('no containerId', () => { const infoSpy = sinon.spy(); const errorSpy = sinon.spy(); - const Logger = proxyquire('../lib/logger', { + const Logger = proxyquire('../logger', { 'cf-logs': { Logger: () => { return { @@ -1056,7 +1056,7 @@ describe('Logger tests', () => { it('no container status', () => { const infoSpy = sinon.spy(); const errorSpy = sinon.spy(); - const Logger = proxyquire('../lib/logger', { + const Logger = proxyquire('../logger', { 'cf-logs': { Logger: () => { return { @@ -1094,7 +1094,7 @@ describe('Logger tests', () => { it('no step name', () => { const infoSpy = sinon.spy(); const errorSpy = sinon.spy(); - const Logger = proxyquire('../lib/logger', { + const Logger = proxyquire('../logger', { 'cf-logs': { Logger: () => { return { @@ -1132,7 +1132,7 @@ describe('Logger tests', () => { it('no strategy provided', () => { const infoSpy = sinon.spy(); const errorSpy = sinon.spy(); - const Logger = proxyquire('../lib/logger', { + const Logger = proxyquire('../logger', { 'cf-logs': { Logger: () => { return { @@ -1171,7 +1171,7 @@ describe('Logger tests', () => { it('provided strategy does not exist', () => { const infoSpy = sinon.spy(); const errorSpy = sinon.spy(); - const Logger = proxyquire('../lib/logger', { + const Logger = proxyquire('../logger', { 'cf-logs': { Logger: () => { return { @@ -1211,7 +1211,7 @@ describe('Logger tests', () => { it('container status is create and strategy is logs', () => { const infoSpy = sinon.spy(); const errorSpy = sinon.spy(); - const Logger = proxyquire('../lib/logger', { + const Logger = proxyquire('../logger', { 'cf-logs': { Logger: () => { return { @@ -1262,7 +1262,7 @@ describe('Logger tests', () => { it('should return true in case log limit exceeded', async () => { const infoSpy = sinon.spy(); const errorSpy = sinon.spy(); - const Logger = proxyquire('../lib/logger', { + const Logger = proxyquire('../logger', { 'cf-logs': { Logger: () => { return { @@ -1315,7 +1315,7 @@ describe('Logger tests', () => { it('should return false in case log limit not exceeded', async () => { const infoSpy = sinon.spy(); const errorSpy = sinon.spy(); - const Logger = proxyquire('../lib/logger', { + const Logger = proxyquire('../logger', { 'cf-logs': { Logger: () => { return { @@ -1376,7 +1376,7 @@ describe('Logger tests', () => { it('should return false in case log limit was not defined', async () => { const infoSpy = sinon.spy(); const errorSpy = sinon.spy(); - const Logger = proxyquire('../lib/logger', { + const Logger = proxyquire('../logger', { 'cf-logs': { Logger: () => { return { @@ -1432,7 +1432,7 @@ describe('Logger tests', () => { it('should return true in case log limit exceeded for one container logger', async () => { const infoSpy = sinon.spy(); const errorSpy = sinon.spy(); - const Logger = proxyquire('../lib/logger', { + const Logger = proxyquire('../logger', { 'cf-logs': { Logger: () => { return { @@ -1488,7 +1488,7 @@ describe('Logger tests', () => { emitter.start = sinon.spy(() => Q.resolve()); return emitter; }); - const Logger = proxyquire('../lib/logger', { + const Logger = proxyquire('../logger', { 'cf-logs': { Logger: () => { return { @@ -1560,7 +1560,7 @@ describe('Logger tests', () => { const containerLogger = new EventEmitter(); containerLogger.start = () => Q.resolve(); - const Logger = proxyquire('../lib/logger', { + const Logger = proxyquire('../logger', { '@codefresh-io/task-logger': { TaskLogger: () => Q.resolve(taskLogger) }, 'docker-events': function () { return dockerEvents; }, './ContainerLogger': function () { return containerLogger; }, @@ -1654,7 +1654,7 @@ describe('Logger tests', () => { const containerLogger = new EventEmitter(); containerLogger.start = () => Q.resolve(); - const Logger = proxyquire('../lib/logger', { + const Logger = proxyquire('../logger', { '@codefresh-io/task-logger': { TaskLogger: () => Q.resolve(taskLogger) }, 'docker-events': function () { return dockerEvents; }, './ContainerLogger': function () { return containerLogger; }, @@ -1696,7 +1696,7 @@ describe('Logger tests', () => { }; const TaskLoggerFactory = sinon.spy(async () => taskLogger); - const Logger = proxyquire('../lib/logger', { + const Logger = proxyquire('../logger', { '@codefresh-io/task-logger': { TaskLogger: TaskLoggerFactory }, 'fastify': stubFastify, './helpers': { @@ -1739,7 +1739,7 @@ describe('Logger tests', () => { }; const TaskLoggerFactory = sinon.spy(async () => taskLogger); - const Logger = proxyquire('../lib/logger', { + const Logger = proxyquire('../logger', { '@codefresh-io/task-logger': { TaskLogger: TaskLoggerFactory }, 'fastify': stubFastify, './helpers': { diff --git a/test/waitUntilFinish.spec.js b/lib/test/waitUntilFinish.spec.js similarity index 91% rename from test/waitUntilFinish.spec.js rename to lib/test/waitUntilFinish.spec.js index 8271ee5..2fd962a 100644 --- a/test/waitUntilFinish.spec.js +++ b/lib/test/waitUntilFinish.spec.js @@ -12,11 +12,11 @@ const expect = chai.expect; const sinon = require('sinon'); const sinonChai = require('sinon-chai'); const proxyquire = require('proxyquire'); -const { BuildFinishedSignalFilename } = require('../lib/enums'); +const { BuildFinishedSignalFilename } = require('../enums'); chai.use(sinonChai); const writeFileSpy = sinon.spy(); -const Waiter = proxyquire('../lib/waitUntilFinish', { +const Waiter = proxyquire('../waitUntilFinish', { fs: { ...fs, writeFileSync: writeFileSpy, @@ -49,7 +49,7 @@ describe('waitUntilFinish script test', function () { it('should write build finished file to the correct location', async () => { writeDate(undefined, 'done', 1111); await Waiter.wait(statePath); - const expectedPath = path.join(path.resolve(__dirname, '../lib'), BuildFinishedSignalFilename); + const expectedPath = path.join(path.resolve(__dirname, '../'), BuildFinishedSignalFilename); expect(writeFileSpy).to.have.been.calledOnceWith(expectedPath, 'build is finished'); }); @@ -61,6 +61,6 @@ describe('waitUntilFinish script test', function () { await Q.delay(300); writeDate(Date.now(), 'done'); await waitPromise; - expect(Waiter.prototype._checkFinished.getCalls()).to.have.lengthOf(3); + expect(Waiter.prototype._checkFinished.getCalls()).to.have.lengthOf(3); }); }); diff --git a/package.json b/package.json index 7c84ab8..a2715bd 100644 --- a/package.json +++ b/package.json @@ -47,7 +47,7 @@ "scripts": { "lint": "eslint '*/**/*.js'", "lint-fix": "eslint '*/**/*.js' --fix", - "test": "node ./node_modules/mocha/bin/_mocha './{,!(node_modules)/**/}*.spec.js' --exit", + "test": "node ./node_modules/mocha/bin/_mocha 'dist/**/*.spec.js' --exit", "test:ci": "yarn test", "start": "node dist/index.js", "version": "exit 0", diff --git a/tsconfig.json b/tsconfig.json index 76ea6d5..79e6733 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -110,8 +110,8 @@ }, "exclude": [ "node_modules", - "**/*.unit*", - "**/*.spec*", + // "**/*.unit*", + // "**/*.spec*", "coverage/**", "dist", ] From 1653fd7e6b362fbefc306323e790d5c34758dd06 Mon Sep 17 00:00:00 2001 From: Vasil Sudakou Date: Thu, 9 Jan 2025 07:30:48 +0300 Subject: [PATCH 14/20] fix: support streams without pipes --- lib/ContainerLogger.js | 19 +++++++++++++------ .../deprecated-images-interceptor.stream.ts | 19 +++++++++++-------- 2 files changed, 24 insertions(+), 14 deletions(-) diff --git a/lib/ContainerLogger.js b/lib/ContainerLogger.js index 02246cc..b404eca 100644 --- a/lib/ContainerLogger.js +++ b/lib/ContainerLogger.js @@ -78,10 +78,8 @@ class ContainerLogger extends EventEmitter { this._registerToTtyStreams(stdout, stderr); } else { - stdout = stdout.pipe(new DeprecatedImagesInterceptorStream()); this._handleNonTtyStream(stdout, false); if (stderr) { - stderr = stderr.pipe(new DeprecatedImagesInterceptorStream()); this._handleNonTtyStream(stderr, true); } } @@ -175,11 +173,9 @@ class ContainerLogger extends EventEmitter { } _registerToTtyStreams(stdout, stderr) { - stdout = stdout.pipe(new DeprecatedImagesInterceptorStream()); this._handleTtyStream(stdout, false); if (stderr) { - stderr = stderr.pipe(new DeprecatedImagesInterceptorStream()); stderr.once('end', () => { this.stepFinished = true; logger.info(`stderr end event was fired for container: ${this.containerId}`); @@ -190,8 +186,13 @@ class ContainerLogger extends EventEmitter { _handleTtyStream(stream, isError) { this.handledStreams++; - stream.on('end', this._handleFinished.bind(this)); + const deprecatedImagesInterceptor = new DeprecatedImagesInterceptorStream(true); + stream.on('end', () => { + this._handleFinished(); + deprecatedImagesInterceptor.end(); + }); stream.on('data', (chunk) => { + deprecatedImagesInterceptor.write(chunk); this._logMessage(Buffer.from(chunk).toString('utf-8'), isError); }); logger.info(`Listening on stream 'data' event for container: ${this.containerId}`); @@ -199,18 +200,24 @@ class ContainerLogger extends EventEmitter { _handleNonTtyStream(stream, isError) { this.handledStreams++; + const deprecatedImagesInterceptor = new DeprecatedImagesInterceptorStream(true); stream.on('readable', () => { let header = stream.read(8); while (header !== null) { + deprecatedImagesInterceptor.write(header); const payload = stream.read(header.readUInt32BE(4)); if (payload === null) { break; } + deprecatedImagesInterceptor.write(payload); this._logMessage(Buffer.from(payload).toString('utf8'), isError); header = stream.read(8); } }); - stream.on('end', this._handleFinished.bind(this)); + stream.on('end', () => { + this._handleFinished(); + deprecatedImagesInterceptor.end(); + }); logger.info(`Listening on stream 'readable' event for container: ${this.containerId}`); } diff --git a/lib/metric/deprecated-images/deprecated-images-interceptor.stream.ts b/lib/metric/deprecated-images/deprecated-images-interceptor.stream.ts index 30ac6a2..02ee56b 100644 --- a/lib/metric/deprecated-images/deprecated-images-interceptor.stream.ts +++ b/lib/metric/deprecated-images/deprecated-images-interceptor.stream.ts @@ -4,31 +4,34 @@ import { Transform, TransformCallback } from 'stream'; import deprecatedImagesCollector from './deprecated-images.collector'; export class DeprecatedImagesInterceptorStream extends Transform { - private _lastChunk: Buffer; + private lastChunk: Buffer; - constructor() { + constructor(private readonly noPush = false) { super(); - this._lastChunk = Buffer.alloc(0); + this.lastChunk = Buffer.alloc(0); } _transform(chunk: Buffer, encoding: BufferEncoding, callback: TransformCallback): void { try { const text = Buffer - .concat([this._lastChunk, chunk]) + .concat([this.lastChunk, chunk]) .toString('utf8'); const lines = text.split('\n'); // the final element in 'lines' may be an incomplete line - // save it in _lastChunk for next time - this._lastChunk = Buffer.from(lines.pop() ?? '', 'utf8'); + // save it in lastChunk for next time + this.lastChunk = Buffer.from(lines.pop() ?? '', 'utf8'); for (const line of lines) { deprecatedImagesCollector.catchDeprecatedImage(line.trim()); } - this.push(chunk); + if (!this.noPush) { + this.push(chunk); + } + callback(); } catch (error) { callback(error as any); @@ -42,7 +45,7 @@ export class DeprecatedImagesInterceptorStream extends Transform { */ _flush(callback: TransformCallback): void { try { - const finalLine = this._lastChunk.toString('utf8'); + const finalLine = this.lastChunk.toString('utf8'); deprecatedImagesCollector.catchDeprecatedImage(finalLine.trim()); callback(); } catch (error) { From c51e9e9489e6ca3dea503acae81391896ab0314f Mon Sep 17 00:00:00 2001 From: Vasil Sudakou Date: Thu, 9 Jan 2025 07:41:29 +0300 Subject: [PATCH 15/20] fix: add ts-node --- package.json | 2 + yarn.lock | 111 +++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 113 insertions(+) diff --git a/package.json b/package.json index a2715bd..1eb41e4 100644 --- a/package.json +++ b/package.json @@ -22,6 +22,7 @@ "q": "^1.5.1" }, "devDependencies": { + "@types/mocha": "^10.0.10", "@typescript-eslint/eslint-plugin": "^8.18.1", "@typescript-eslint/parser": "^8.18.1", "chai": "^4.4.1", @@ -39,6 +40,7 @@ "shelljs": "^0.6.1", "sinon": "^18.0.0", "sinon-chai": "^3.7.0", + "ts-node": "^10.9.2", "typescript": "^5.7.2" }, "engines": { diff --git a/yarn.lock b/yarn.lock index 902c3bb..632b1cc 100644 --- a/yarn.lock +++ b/yarn.lock @@ -527,6 +527,13 @@ resolved "https://registry.yarnpkg.com/@colors/colors/-/colors-1.6.0.tgz#ec6cd237440700bc23ca23087f513c75508958b0" integrity sha512-Ir+AOibqzrIsL6ajt3Rz3LskB7OiMVHqltZmspbW/TJuTVuyOMirVqAkjfY6JISiLHgyNqicAC8AyHHGzNd/dA== +"@cspotcode/source-map-support@^0.8.0": + version "0.8.1" + resolved "https://registry.yarnpkg.com/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz#00629c35a688e05a88b1cda684fb9d5e73f000a1" + integrity sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw== + dependencies: + "@jridgewell/trace-mapping" "0.3.9" + "@dabh/diagnostics@^2.0.2": version "2.0.3" resolved "https://registry.yarnpkg.com/@dabh/diagnostics/-/diagnostics-2.0.3.tgz#7f7e97ee9a725dffc7808d93668cc984e1dc477a" @@ -627,6 +634,24 @@ resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz#4a2868d75d6d6963e423bcf90b7fd1be343409d3" integrity sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA== +"@jridgewell/resolve-uri@^3.0.3": + version "3.1.2" + resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz#7a0ee601f60f99a20c7c7c5ff0c80388c1189bd6" + integrity sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw== + +"@jridgewell/sourcemap-codec@^1.4.10": + version "1.5.0" + resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz#3188bcb273a414b0d215fd22a58540b989b9409a" + integrity sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ== + +"@jridgewell/trace-mapping@0.3.9": + version "0.3.9" + resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz#6534fd5933a53ba7cbf3a17615e273a0d1273ff9" + integrity sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ== + dependencies: + "@jridgewell/resolve-uri" "^3.0.3" + "@jridgewell/sourcemap-codec" "^1.4.10" + "@mongodb-js/saslprep@^1.1.0": version "1.1.5" resolved "https://registry.yarnpkg.com/@mongodb-js/saslprep/-/saslprep-1.1.5.tgz#0c48a96c8d799e81fae311b7251aa5c1dc7c6e95" @@ -1119,6 +1144,26 @@ dependencies: defer-to-connect "^2.0.1" +"@tsconfig/node10@^1.0.7": + version "1.0.11" + resolved "https://registry.yarnpkg.com/@tsconfig/node10/-/node10-1.0.11.tgz#6ee46400685f130e278128c7b38b7e031ff5b2f2" + integrity sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw== + +"@tsconfig/node12@^1.0.7": + version "1.0.11" + resolved "https://registry.yarnpkg.com/@tsconfig/node12/-/node12-1.0.11.tgz#ee3def1f27d9ed66dac6e46a295cffb0152e058d" + integrity sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag== + +"@tsconfig/node14@^1.0.0": + version "1.0.3" + resolved "https://registry.yarnpkg.com/@tsconfig/node14/-/node14-1.0.3.tgz#e4386316284f00b98435bf40f72f75a09dabf6c1" + integrity sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow== + +"@tsconfig/node16@^1.0.2": + version "1.0.4" + resolved "https://registry.yarnpkg.com/@tsconfig/node16/-/node16-1.0.4.tgz#0b92dcc0cc1c81f6f306a381f28e31b1a56536e9" + integrity sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA== + "@types/http-cache-semantics@^4.0.4": version "4.0.4" resolved "https://registry.yarnpkg.com/@types/http-cache-semantics/-/http-cache-semantics-4.0.4.tgz#b979ebad3919799c979b17c72621c0bc0a31c6c4" @@ -1129,6 +1174,11 @@ resolved "https://registry.yarnpkg.com/@types/json5/-/json5-0.0.29.tgz#ee28707ae94e11d2b827bcbe5270bcea7f3e71ee" integrity sha1-7ihweulOEdK4J7y+UnC86n8+ce4= +"@types/mocha@^10.0.10": + version "10.0.10" + resolved "https://registry.yarnpkg.com/@types/mocha/-/mocha-10.0.10.tgz#91f62905e8d23cbd66225312f239454a23bebfa0" + integrity sha512-xPyYSz1cMPnJQhl0CLMH68j3gprKZaTjG3s5Vi+fDgx+uhG9NOXwbVt52eFS8ECyXhyKcjDLCBEqBExKuiZb7Q== + "@types/node@*": version "20.12.2" resolved "https://registry.yarnpkg.com/@types/node/-/node-20.12.2.tgz#9facdd11102f38b21b4ebedd9d7999663343d72e" @@ -1267,6 +1317,18 @@ acorn-jsx@^5.3.2: resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.3.2.tgz#7ed5bb55908b3b2f1bc55c6af1653bada7f07937" integrity sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ== +acorn-walk@^8.1.1: + version "8.3.4" + resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-8.3.4.tgz#794dd169c3977edf4ba4ea47583587c5866236b7" + integrity sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g== + dependencies: + acorn "^8.11.0" + +acorn@^8.11.0, acorn@^8.4.1: + version "8.14.0" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.14.0.tgz#063e2c70cac5fb4f6467f0b11152e04c682795b0" + integrity sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA== + acorn@^8.9.0: version "8.12.1" resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.12.1.tgz#71616bdccbe25e27a54439e0046e89ca76df2248" @@ -1351,6 +1413,11 @@ anymatch@~3.1.2: normalize-path "^3.0.0" picomatch "^2.0.4" +arg@^4.1.0: + version "4.1.3" + resolved "https://registry.yarnpkg.com/arg/-/arg-4.1.3.tgz#269fc7ad5b8e42cb63c896d5666017261c144089" + integrity sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA== + argparse@^1.0.7: version "1.0.10" resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911" @@ -2002,6 +2069,11 @@ cpu-features@~0.0.9: buildcheck "~0.0.6" nan "^2.19.0" +create-require@^1.1.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/create-require/-/create-require-1.1.1.tgz#c1d7e8f1e5f6cfc9ff65f9cd352d37348756c333" + integrity sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ== + cross-spawn@^7.0.2: version "7.0.6" resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.6.tgz#8a58fe78f00dcd70c370451759dfbfaf03e8ee9f" @@ -2185,6 +2257,11 @@ detect-indent@^4.0.0: dependencies: repeating "^2.0.0" +diff@^4.0.1: + version "4.0.2" + resolved "https://registry.yarnpkg.com/diff/-/diff-4.0.2.tgz#60f3aecb89d5fae520c11aa19efc2bb982aade7d" + integrity sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A== + diff@^5.2.0: version "5.2.0" resolved "https://registry.yarnpkg.com/diff/-/diff-5.2.0.tgz#26ded047cd1179b78b9537d5ef725503ce1ae531" @@ -4034,6 +4111,11 @@ lru-cache@^6.0.0: dependencies: yallist "^4.0.0" +make-error@^1.1.1: + version "1.3.6" + resolved "https://registry.yarnpkg.com/make-error/-/make-error-1.3.6.tgz#2eb2e37ea9b67c4891f684a1394799af484cf7a2" + integrity sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw== + memory-pager@^1.0.2: version "1.5.0" resolved "https://registry.yarnpkg.com/memory-pager/-/memory-pager-1.5.0.tgz#d8751655d22d384682741c972f2c3d6dfa3e66b5" @@ -5353,6 +5435,25 @@ ts-api-utils@^1.3.0: resolved "https://registry.yarnpkg.com/ts-api-utils/-/ts-api-utils-1.4.3.tgz#bfc2215fe6528fecab2b0fba570a2e8a4263b064" integrity sha512-i3eMG77UTMD0hZhgRS562pv83RC6ukSAC2GMNWc+9dieh/+jDM5u5YG+NHX6VNDRHQcHwmsTHctP9LhbC3WxVw== +ts-node@^10.9.2: + version "10.9.2" + resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-10.9.2.tgz#70f021c9e185bccdca820e26dc413805c101c71f" + integrity sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ== + dependencies: + "@cspotcode/source-map-support" "^0.8.0" + "@tsconfig/node10" "^1.0.7" + "@tsconfig/node12" "^1.0.7" + "@tsconfig/node14" "^1.0.0" + "@tsconfig/node16" "^1.0.2" + acorn "^8.4.1" + acorn-walk "^8.1.1" + arg "^4.1.0" + create-require "^1.1.0" + diff "^4.0.1" + make-error "^1.1.1" + v8-compile-cache-lib "^3.0.1" + yn "3.1.1" + tsconfig-paths@^3.15.0: version "3.15.0" resolved "https://registry.yarnpkg.com/tsconfig-paths/-/tsconfig-paths-3.15.0.tgz#5299ec605e55b1abb23ec939ef15edaf483070d4" @@ -5536,6 +5637,11 @@ uuid@^9.0.1: resolved "https://registry.yarnpkg.com/uuid/-/uuid-9.0.1.tgz#e188d4c8853cc722220392c424cd637f32293f30" integrity sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA== +v8-compile-cache-lib@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz#6336e8d71965cb3d35a1bbb7868445a7c05264bf" + integrity sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg== + verror@1.10.0: version "1.10.0" resolved "https://registry.yarnpkg.com/verror/-/verror-1.10.0.tgz#3a105ca17053af55d6e270c1f8288682e18da400" @@ -5739,6 +5845,11 @@ yargs@^16.2.0: y18n "^5.0.5" yargs-parser "^20.2.2" +yn@3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/yn/-/yn-3.1.1.tgz#1e87401a09d767c1d5eab26a6e4c185182d2eb50" + integrity sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q== + yocto-queue@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b" From 4cafee31d85102aa183cc15b18e7910163aea0a7 Mon Sep 17 00:00:00 2001 From: Vasil Sudakou Date: Thu, 9 Jan 2025 07:42:17 +0300 Subject: [PATCH 16/20] Revert "fix: move tests to lib directory" This reverts commit 90caf0947ff9f696744475cf7db94522ba20af0c. --- .dockerignore | 2 +- package.json | 2 +- .../ContainerLogger.unit.spec.js | 4 +- {lib/test => test}/addNewMask.unit.spec.js | 14 ++-- {lib/test => test}/helpers.unit.spec.js | 16 ++-- {lib/test => test}/isReady.unit.spec.js | 16 ++-- {lib/test => test}/logger.unit.spec.js | 84 +++++++++---------- {lib/test => test}/waitUntilFinish.spec.js | 8 +- tsconfig.json | 4 +- 9 files changed, 75 insertions(+), 75 deletions(-) rename {lib/test => test}/ContainerLogger.unit.spec.js (99%) rename {lib/test => test}/addNewMask.unit.spec.js (96%) rename {lib/test => test}/helpers.unit.spec.js (91%) rename {lib/test => test}/isReady.unit.spec.js (90%) rename {lib/test => test}/logger.unit.spec.js (96%) rename {lib/test => test}/waitUntilFinish.spec.js (91%) diff --git a/.dockerignore b/.dockerignore index 3862197..83b1b3c 100644 --- a/.dockerignore +++ b/.dockerignore @@ -6,6 +6,6 @@ logs/*.log lib/state.json *.md .eslintrc.json -lib/test +test .eslintignore dist diff --git a/package.json b/package.json index 1eb41e4..80c8357 100644 --- a/package.json +++ b/package.json @@ -49,7 +49,7 @@ "scripts": { "lint": "eslint '*/**/*.js'", "lint-fix": "eslint '*/**/*.js' --fix", - "test": "node ./node_modules/mocha/bin/_mocha 'dist/**/*.spec.js' --exit", + "test": "node ./node_modules/mocha/bin/_mocha './{,!(node_modules)/**/}*.spec.js' --exit", "test:ci": "yarn test", "start": "node dist/index.js", "version": "exit 0", diff --git a/lib/test/ContainerLogger.unit.spec.js b/test/ContainerLogger.unit.spec.js similarity index 99% rename from lib/test/ContainerLogger.unit.spec.js rename to test/ContainerLogger.unit.spec.js index e96b0b4..e382571 100644 --- a/lib/test/ContainerLogger.unit.spec.js +++ b/test/ContainerLogger.unit.spec.js @@ -6,7 +6,7 @@ const sinon = require('sinon'); const proxyquire = require('proxyquire'); const promiseRetry = require('promise-retry'); const sinonChai = require('sinon-chai'); -const LoggerStrategy = require('../enums').LoggerStrategy; +const LoggerStrategy = require('../lib/enums').LoggerStrategy; const { EventEmitter } = require('events'); const { Writable, Readable, PassThrough } = require('stream'); @@ -15,7 +15,7 @@ chai.use(sinonChai); const promiseRetrySpy = sinon.spy((err) => Q.reject(err)); -const ContainerLogger = proxyquire('../ContainerLogger', { +const ContainerLogger = proxyquire('../lib/ContainerLogger', { 'promise-retry': (cb) => cb(promiseRetrySpy, 1), }); diff --git a/lib/test/addNewMask.unit.spec.js b/test/addNewMask.unit.spec.js similarity index 96% rename from lib/test/addNewMask.unit.spec.js rename to test/addNewMask.unit.spec.js index ffa8c60..64bf80d 100644 --- a/lib/test/addNewMask.unit.spec.js +++ b/test/addNewMask.unit.spec.js @@ -57,7 +57,7 @@ describe('addNewMask', () => { stubGetServerAddress.resolves(serverAddress); stubGot.post.resolves({ statusCode: 201 }); - const { updateMasks, exitHandler } = proxyquire('../addNewMask', { + const { updateMasks, exitHandler } = proxyquire('../lib/addNewMask', { './helpers': { getServerAddress: stubGetServerAddress }, }); process.listeners('exit').forEach((listener) => { @@ -77,7 +77,7 @@ describe('addNewMask', () => { describe('negative', () => { it('should fail if the server address is not available', async () => { stubGetServerAddress.rejects('could not get server address'); - const { updateMasks, exitHandler } = proxyquire('../addNewMask', { + const { updateMasks, exitHandler } = proxyquire('../lib/addNewMask', { './helpers': { getServerAddress: stubGetServerAddress, }, @@ -94,7 +94,7 @@ describe('addNewMask', () => { it('should fail if the server address is not valid URL', async () => { stubGetServerAddress.resolves('foo'); - const { updateMasks, exitHandler } = proxyquire('../addNewMask', { + const { updateMasks, exitHandler } = proxyquire('../lib/addNewMask', { './helpers': { getServerAddress: stubGetServerAddress, }, @@ -116,7 +116,7 @@ describe('addNewMask', () => { statusCode: 500, body: 'Internal Server Error', }); - const { updateMasks, exitHandler } = proxyquire('../addNewMask', { + const { updateMasks, exitHandler } = proxyquire('../lib/addNewMask', { './helpers': { getServerAddress: stubGetServerAddress }, }); process.listeners('exit').forEach((listener) => { @@ -132,7 +132,7 @@ describe('addNewMask', () => { describe('exitHandler', () => { it('should set exit code to 3 if the original exit code is 0 and variable was not masked', () => { - const { exitHandler } = proxyquire('../addNewMask', {}); + const { exitHandler } = proxyquire('../lib/addNewMask', {}); process.listeners('exit').forEach((listener) => { if (listener === exitHandler) { process.removeListener('exit', listener); @@ -145,7 +145,7 @@ describe('addNewMask', () => { }); it('should set exit code to 3 if the original exit code is 0 and variable was not masked', () => { - const { exitHandler } = proxyquire('../addNewMask', {}); + const { exitHandler } = proxyquire('../lib/addNewMask', {}); process.listeners('exit').forEach((listener) => { if (listener === exitHandler) { process.removeListener('exit', listener); @@ -165,7 +165,7 @@ describe('addNewMask', () => { const serverAddress = 'https://xkcd.com/605/' stubGetServerAddress.resolves(serverAddress); stubGot.post.resolves({ statusCode: 201 }); - const { updateMasks, exitHandler } = proxyquire('../addNewMask', { + const { updateMasks, exitHandler } = proxyquire('../lib/addNewMask', { './helpers': { getServerAddress: stubGetServerAddress }, }); process.listeners('exit').forEach((listener) => { diff --git a/lib/test/helpers.unit.spec.js b/test/helpers.unit.spec.js similarity index 91% rename from lib/test/helpers.unit.spec.js rename to test/helpers.unit.spec.js index 4927afe..40dccd4 100644 --- a/lib/test/helpers.unit.spec.js +++ b/test/helpers.unit.spec.js @@ -28,7 +28,7 @@ describe('helpers', () => { it('should write the server address to the file', async () => { const SERVER_ADDRESS_PATH = 'little/bobby/tables/we/call/him'; const serverAddress = 'foo'; - const { saveServerAddress } = proxyquire('../helpers.js', { + const { saveServerAddress } = proxyquire('../lib/helpers.js', { 'node:fs/promises': stubFsPromises, 'cf-logs': { Logger: () => stubLogger }, './const': { SERVER_ADDRESS_PATH }, @@ -36,9 +36,9 @@ describe('helpers', () => { await saveServerAddress(serverAddress); expect(stubFsPromises.writeFile).to.have.been.calledOnceWithExactly(SERVER_ADDRESS_PATH, serverAddress, { encoding: 'utf8' }); }); - + it('should fail if the file cannot be written', async () => { - const { saveServerAddress } = proxyquire('../helpers.js', { + const { saveServerAddress } = proxyquire('../lib/helpers.js', { 'node:fs/promises': stubFsPromises, 'cf-logs': { Logger: () => stubLogger }, }); @@ -53,12 +53,12 @@ describe('helpers', () => { } }); }); - + describe('getServerAddress()', () => { it('should read the server address from the file', async () => { const SERVER_ADDRESS_PATH = 'little/bobby/tables/we/call/him'; const serverAddress = 'foo'; - const { getServerAddress } = proxyquire('../helpers.js', { + const { getServerAddress } = proxyquire('../lib/helpers.js', { 'node:fs/promises': stubFsPromises, 'cf-logs': { Logger: () => stubLogger }, './const': { SERVER_ADDRESS_PATH }, @@ -68,9 +68,9 @@ describe('helpers', () => { expect(result).to.be.equal(serverAddress); expect(stubFsPromises.readFile).to.have.been.calledOnceWithExactly(SERVER_ADDRESS_PATH, { encoding: 'utf8' }); }); - + it('should fail if the file cannot be read', async () => { - const { getServerAddress } = proxyquire('../helpers.js', { + const { getServerAddress } = proxyquire('../lib/helpers.js', { 'node:fs/promises': stubFsPromises, 'cf-logs': { Logger: () => stubLogger }, }); @@ -87,7 +87,7 @@ describe('helpers', () => { }); it('should write/read to/from the same location', async () => { - const { saveServerAddress, getServerAddress } = require('../helpers.js'); + const { saveServerAddress, getServerAddress } = require('../lib/helpers.js'); const serverAddress = 'http://g.codefresh.io'; await saveServerAddress(serverAddress); const result = await getServerAddress(); diff --git a/lib/test/isReady.unit.spec.js b/test/isReady.unit.spec.js similarity index 90% rename from lib/test/isReady.unit.spec.js rename to test/isReady.unit.spec.js index 4dd92d0..92486cf 100644 --- a/lib/test/isReady.unit.spec.js +++ b/test/isReady.unit.spec.js @@ -1,6 +1,6 @@ const chai = require('chai'); const sinon = require('sinon'); -const { ContainerHandlingStatus } = require('../enums'); +const { ContainerHandlingStatus } = require('../lib/enums'); const proxyquire = require('proxyquire'); const expect = chai.expect; @@ -21,7 +21,7 @@ describe('isReady script', () => { it('Should check exit with 0 code if container logger is ready', () => { const state = JSON.stringify({ status: 'ready', containers: {} }) process.argv = []; - proxyquire('../isReady.js', { + proxyquire('../lib/isReady.js', { 'fs': { readFileSync: () => Buffer.from(state), }, @@ -31,7 +31,7 @@ describe('isReady script', () => { it('Should check exit with 1 code if container logger is not ready', () => { const state = JSON.stringify({ status: 'notReady', containers: {} }) process.argv = []; - proxyquire('../isReady.js', { + proxyquire('../lib/isReady.js', { 'fs': { readFileSync: () => Buffer.from(state), }, @@ -43,7 +43,7 @@ describe('isReady script', () => { it('Should check exit with 0 code if container is ready', () => { const state = JSON.stringify({ status: 'ready', containers: { 'container-id': { status: ContainerHandlingStatus.LISTENING } } }) process.argv = ['foo', 'bar', 'container-id']; - proxyquire('../isReady.js', { + proxyquire('../lib/isReady.js', { 'fs': { readFileSync: () => Buffer.from(state), }, @@ -53,7 +53,7 @@ describe('isReady script', () => { it('Should check exit with 0 code if container is waiting for start status', () => { const state = JSON.stringify({ status: 'ready', containers: { 'container-id': { status: ContainerHandlingStatus.WAITING_FOR_START } } }) process.argv = ['foo', 'bar', 'container-id']; - proxyquire('../isReady.js', { + proxyquire('../lib/isReady.js', { 'fs': { readFileSync: () => Buffer.from(state), }, @@ -63,7 +63,7 @@ describe('isReady script', () => { it('Should check exit with 0 code if container is finished status', () => { const state = JSON.stringify({ status: 'ready', containers: { 'container-id': { status: ContainerHandlingStatus.FINISHED } } }) process.argv = ['foo', 'bar', 'container-id']; - proxyquire('../isReady.js', { + proxyquire('../lib/isReady.js', { 'fs': { readFileSync: () => Buffer.from(state), }, @@ -73,7 +73,7 @@ describe('isReady script', () => { it('Should check exit with 1 code if container is not ready', () => { const state = JSON.stringify({ status: 'ready', containers: { 'container-id': { status: ContainerHandlingStatus.INITIALIZING } } }) process.argv = ['foo', 'bar', 'container-id']; - proxyquire('../isReady.js', { + proxyquire('../lib/isReady.js', { 'fs': { readFileSync: () => Buffer.from(state), }, @@ -81,4 +81,4 @@ describe('isReady script', () => { expect(process.exit).to.have.been.calledOnceWith(1); }); }); -}); +}); \ No newline at end of file diff --git a/lib/test/logger.unit.spec.js b/test/logger.unit.spec.js similarity index 96% rename from lib/test/logger.unit.spec.js rename to test/logger.unit.spec.js index 6970936..eaf196d 100644 --- a/lib/test/logger.unit.spec.js +++ b/test/logger.unit.spec.js @@ -5,9 +5,9 @@ const chai = require('chai'); const sinon = require('sinon'); const sinonChai = require('sinon-chai'); const { EventEmitter } = require('events'); -const { ContainerStatus } = require('../enums'); -const { LoggerStrategy } = require('../enums'); -const { getPromiseWithResolvers } = require('../helpers'); +const { ContainerStatus } = require('../lib/enums'); +const { LoggerStrategy } = require('../lib/enums'); +const { getPromiseWithResolvers } = require('../lib/helpers'); const expect = chai.expect; chai.use(sinonChai); @@ -43,7 +43,7 @@ describe('Logger tests', () => { describe('constructor', () => { it('should define workflow log size limit default in case of non provided value', () => { - const Logger = proxyquire('../logger', { + const Logger = proxyquire('../lib/logger', { 'fastify': stubFastify, './helpers': { saveServerAddress: stubSaveServerAddress, @@ -68,7 +68,7 @@ describe('Logger tests', () => { }); it('should use passed workflow log size limit in case passed', () => { - const Logger = proxyquire('../logger', { + const Logger = proxyquire('../lib/logger', { 'fastify': stubFastify, './helpers': { saveServerAddress: stubSaveServerAddress, @@ -111,7 +111,7 @@ describe('Logger tests', () => { return Q.resolve(taskLogger); }); - const Logger = proxyquire('../logger', { + const Logger = proxyquire('../lib/logger', { '@codefresh-io/task-logger': { TaskLogger: TaskLoggerFactory }, 'fastify': stubFastify, './helpers': { @@ -159,7 +159,7 @@ describe('Logger tests', () => { return Q.resolve(taskLogger); }); - const Logger = proxyquire('../logger', { + const Logger = proxyquire('../lib/logger', { '@codefresh-io/task-logger': { TaskLogger: TaskLoggerFactory }, 'fastify': stubFastify, './helpers': { @@ -205,7 +205,7 @@ describe('Logger tests', () => { return Q.resolve(taskLogger); }); - const Logger = proxyquire('../logger', { + const Logger = proxyquire('../lib/logger', { '@codefresh-io/task-logger': { TaskLogger: TaskLoggerFactory }, 'fastify': stubFastify, './helpers': { @@ -250,7 +250,7 @@ describe('Logger tests', () => { return Q.resolve(taskLogger); }); - const Logger = proxyquire('../logger', { + const Logger = proxyquire('../lib/logger', { '@codefresh-io/task-logger': { TaskLogger: TaskLoggerFactory }, 'fastify': stubFastify, './helpers': { @@ -300,7 +300,7 @@ describe('Logger tests', () => { return Q.reject(new Error('my error')); }); - const Logger = proxyquire('../logger', { + const Logger = proxyquire('../lib/logger', { '@codefresh-io/task-logger': { TaskLogger: TaskLoggerFactory }, 'fastify': stubFastify, './helpers': { @@ -334,7 +334,7 @@ describe('Logger tests', () => { callback(null, [{}, {}]); }); - const Logger = proxyquire('../logger', { + const Logger = proxyquire('../lib/logger', { 'dockerode': function () { return { listContainers: listContainersSpy @@ -362,7 +362,7 @@ describe('Logger tests', () => { callback(null, []); }); - const Logger = proxyquire('../logger', { + const Logger = proxyquire('../lib/logger', { 'dockerode': function () { return { listContainers: listContainersSpy @@ -394,7 +394,7 @@ describe('Logger tests', () => { callback(new Error('getting containers error')); }); - const Logger = proxyquire('../logger', { + const Logger = proxyquire('../lib/logger', { 'dockerode': function () { return { listContainers: listContainersSpy @@ -428,7 +428,7 @@ describe('Logger tests', () => { it('should call handleContainer in case of an create event', () => { const startSpy = sinon.spy(); const onSpy = sinon.spy(); - const Logger = proxyquire('../logger', { + const Logger = proxyquire('../lib/logger', { 'docker-events': function () { return { start: startSpy, @@ -460,7 +460,7 @@ describe('Logger tests', () => { callback(); }); - const Logger = proxyquire('../logger', { + const Logger = proxyquire('../lib/logger', { 'fs': { writeFile: writeFileSpy, readFileSync: sinon.spy(() => { @@ -485,7 +485,7 @@ describe('Logger tests', () => { callback(new Error('write error')); }); - const Logger = proxyquire('../logger', { + const Logger = proxyquire('../lib/logger', { 'fs': { writeFile: writeFileSpy, readFileSync: sinon.spy(() => { @@ -510,7 +510,7 @@ describe('Logger tests', () => { describe('validate', () => { it('should call process exit in case firebase authentication url was not provided', () => { - const Logger = proxyquire('../logger', { + const Logger = proxyquire('../lib/logger', { 'fastify': stubFastify, './helpers': { saveServerAddress: stubSaveServerAddress, @@ -537,7 +537,7 @@ describe('Logger tests', () => { }); process.exit = processExitSpy; - const Logger = proxyquire('../logger', { + const Logger = proxyquire('../lib/logger', { 'fastify': stubFastify, './helpers': { saveServerAddress: stubSaveServerAddress, @@ -564,7 +564,7 @@ describe('Logger tests', () => { }); process.exit = processExitSpy; - const Logger = proxyquire('../logger', { + const Logger = proxyquire('../lib/logger', { 'fastify': stubFastify, './helpers': { saveServerAddress: stubSaveServerAddress, @@ -591,7 +591,7 @@ describe('Logger tests', () => { }); process.exit = processExitSpy; - const Logger = proxyquire('../logger', { + const Logger = proxyquire('../lib/logger', { 'fastify': stubFastify, './helpers': { saveServerAddress: stubSaveServerAddress, @@ -632,7 +632,7 @@ describe('Logger tests', () => { emitter.start = startSpy; return emitter; }); - const Logger = proxyquire('../logger', { + const Logger = proxyquire('../lib/logger', { 'cf-logs': { Logger: () => { return { @@ -685,7 +685,7 @@ describe('Logger tests', () => { it('should pass received step log size limit to ContainerLogger', async () => { const infoSpy = sinon.spy(); const errorSpy = sinon.spy(); - const Logger = proxyquire('../logger', { + const Logger = proxyquire('../lib/logger', { 'cf-logs': { Logger: () => { return { @@ -737,7 +737,7 @@ describe('Logger tests', () => { it('should pass undefined step log size limit to ContainerLogger in case of no label', async () => { const infoSpy = sinon.spy(); const errorSpy = sinon.spy(); - const Logger = proxyquire('../logger', { + const Logger = proxyquire('../lib/logger', { 'cf-logs': { Logger: () => { return { @@ -785,7 +785,7 @@ describe('Logger tests', () => { it('should update total log size when new log message event was sent', async () => { const infoSpy = sinon.spy(); const errorSpy = sinon.spy(); - const Logger = proxyquire('../logger', { + const Logger = proxyquire('../lib/logger', { 'cf-logs': { Logger: () => { return { @@ -849,7 +849,7 @@ describe('Logger tests', () => { }); const infoSpy = sinon.spy(); const errorSpy = sinon.spy(); - const Logger = proxyquire('../logger', { + const Logger = proxyquire('../lib/logger', { 'cf-logs': { Logger: () => { return { @@ -923,7 +923,7 @@ describe('Logger tests', () => { it('was previously handled', () => { const infoSpy = sinon.spy(); const errorSpy = sinon.spy(); - const Logger = proxyquire('../logger', { + const Logger = proxyquire('../lib/logger', { 'cf-logs': { Logger: () => { return { @@ -973,7 +973,7 @@ describe('Logger tests', () => { it('no loggerId', () => { const infoSpy = sinon.spy(); const errorSpy = sinon.spy(); - const Logger = proxyquire('../logger', { + const Logger = proxyquire('../lib/logger', { 'cf-logs': { Logger: () => { return { @@ -1018,7 +1018,7 @@ describe('Logger tests', () => { it('no containerId', () => { const infoSpy = sinon.spy(); const errorSpy = sinon.spy(); - const Logger = proxyquire('../logger', { + const Logger = proxyquire('../lib/logger', { 'cf-logs': { Logger: () => { return { @@ -1056,7 +1056,7 @@ describe('Logger tests', () => { it('no container status', () => { const infoSpy = sinon.spy(); const errorSpy = sinon.spy(); - const Logger = proxyquire('../logger', { + const Logger = proxyquire('../lib/logger', { 'cf-logs': { Logger: () => { return { @@ -1094,7 +1094,7 @@ describe('Logger tests', () => { it('no step name', () => { const infoSpy = sinon.spy(); const errorSpy = sinon.spy(); - const Logger = proxyquire('../logger', { + const Logger = proxyquire('../lib/logger', { 'cf-logs': { Logger: () => { return { @@ -1132,7 +1132,7 @@ describe('Logger tests', () => { it('no strategy provided', () => { const infoSpy = sinon.spy(); const errorSpy = sinon.spy(); - const Logger = proxyquire('../logger', { + const Logger = proxyquire('../lib/logger', { 'cf-logs': { Logger: () => { return { @@ -1171,7 +1171,7 @@ describe('Logger tests', () => { it('provided strategy does not exist', () => { const infoSpy = sinon.spy(); const errorSpy = sinon.spy(); - const Logger = proxyquire('../logger', { + const Logger = proxyquire('../lib/logger', { 'cf-logs': { Logger: () => { return { @@ -1211,7 +1211,7 @@ describe('Logger tests', () => { it('container status is create and strategy is logs', () => { const infoSpy = sinon.spy(); const errorSpy = sinon.spy(); - const Logger = proxyquire('../logger', { + const Logger = proxyquire('../lib/logger', { 'cf-logs': { Logger: () => { return { @@ -1262,7 +1262,7 @@ describe('Logger tests', () => { it('should return true in case log limit exceeded', async () => { const infoSpy = sinon.spy(); const errorSpy = sinon.spy(); - const Logger = proxyquire('../logger', { + const Logger = proxyquire('../lib/logger', { 'cf-logs': { Logger: () => { return { @@ -1315,7 +1315,7 @@ describe('Logger tests', () => { it('should return false in case log limit not exceeded', async () => { const infoSpy = sinon.spy(); const errorSpy = sinon.spy(); - const Logger = proxyquire('../logger', { + const Logger = proxyquire('../lib/logger', { 'cf-logs': { Logger: () => { return { @@ -1376,7 +1376,7 @@ describe('Logger tests', () => { it('should return false in case log limit was not defined', async () => { const infoSpy = sinon.spy(); const errorSpy = sinon.spy(); - const Logger = proxyquire('../logger', { + const Logger = proxyquire('../lib/logger', { 'cf-logs': { Logger: () => { return { @@ -1432,7 +1432,7 @@ describe('Logger tests', () => { it('should return true in case log limit exceeded for one container logger', async () => { const infoSpy = sinon.spy(); const errorSpy = sinon.spy(); - const Logger = proxyquire('../logger', { + const Logger = proxyquire('../lib/logger', { 'cf-logs': { Logger: () => { return { @@ -1488,7 +1488,7 @@ describe('Logger tests', () => { emitter.start = sinon.spy(() => Q.resolve()); return emitter; }); - const Logger = proxyquire('../logger', { + const Logger = proxyquire('../lib/logger', { 'cf-logs': { Logger: () => { return { @@ -1560,7 +1560,7 @@ describe('Logger tests', () => { const containerLogger = new EventEmitter(); containerLogger.start = () => Q.resolve(); - const Logger = proxyquire('../logger', { + const Logger = proxyquire('../lib/logger', { '@codefresh-io/task-logger': { TaskLogger: () => Q.resolve(taskLogger) }, 'docker-events': function () { return dockerEvents; }, './ContainerLogger': function () { return containerLogger; }, @@ -1654,7 +1654,7 @@ describe('Logger tests', () => { const containerLogger = new EventEmitter(); containerLogger.start = () => Q.resolve(); - const Logger = proxyquire('../logger', { + const Logger = proxyquire('../lib/logger', { '@codefresh-io/task-logger': { TaskLogger: () => Q.resolve(taskLogger) }, 'docker-events': function () { return dockerEvents; }, './ContainerLogger': function () { return containerLogger; }, @@ -1696,7 +1696,7 @@ describe('Logger tests', () => { }; const TaskLoggerFactory = sinon.spy(async () => taskLogger); - const Logger = proxyquire('../logger', { + const Logger = proxyquire('../lib/logger', { '@codefresh-io/task-logger': { TaskLogger: TaskLoggerFactory }, 'fastify': stubFastify, './helpers': { @@ -1739,7 +1739,7 @@ describe('Logger tests', () => { }; const TaskLoggerFactory = sinon.spy(async () => taskLogger); - const Logger = proxyquire('../logger', { + const Logger = proxyquire('../lib/logger', { '@codefresh-io/task-logger': { TaskLogger: TaskLoggerFactory }, 'fastify': stubFastify, './helpers': { diff --git a/lib/test/waitUntilFinish.spec.js b/test/waitUntilFinish.spec.js similarity index 91% rename from lib/test/waitUntilFinish.spec.js rename to test/waitUntilFinish.spec.js index 2fd962a..8271ee5 100644 --- a/lib/test/waitUntilFinish.spec.js +++ b/test/waitUntilFinish.spec.js @@ -12,11 +12,11 @@ const expect = chai.expect; const sinon = require('sinon'); const sinonChai = require('sinon-chai'); const proxyquire = require('proxyquire'); -const { BuildFinishedSignalFilename } = require('../enums'); +const { BuildFinishedSignalFilename } = require('../lib/enums'); chai.use(sinonChai); const writeFileSpy = sinon.spy(); -const Waiter = proxyquire('../waitUntilFinish', { +const Waiter = proxyquire('../lib/waitUntilFinish', { fs: { ...fs, writeFileSync: writeFileSpy, @@ -49,7 +49,7 @@ describe('waitUntilFinish script test', function () { it('should write build finished file to the correct location', async () => { writeDate(undefined, 'done', 1111); await Waiter.wait(statePath); - const expectedPath = path.join(path.resolve(__dirname, '../'), BuildFinishedSignalFilename); + const expectedPath = path.join(path.resolve(__dirname, '../lib'), BuildFinishedSignalFilename); expect(writeFileSpy).to.have.been.calledOnceWith(expectedPath, 'build is finished'); }); @@ -61,6 +61,6 @@ describe('waitUntilFinish script test', function () { await Q.delay(300); writeDate(Date.now(), 'done'); await waitPromise; - expect(Waiter.prototype._checkFinished.getCalls()).to.have.lengthOf(3); + expect(Waiter.prototype._checkFinished.getCalls()).to.have.lengthOf(3); }); }); diff --git a/tsconfig.json b/tsconfig.json index 79e6733..76ea6d5 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -110,8 +110,8 @@ }, "exclude": [ "node_modules", - // "**/*.unit*", - // "**/*.spec*", + "**/*.unit*", + "**/*.spec*", "coverage/**", "dist", ] From 5b6a3975875d71884716b1c2e43a81d4102c0245 Mon Sep 17 00:00:00 2001 From: Vasil Sudakou Date: Thu, 9 Jan 2025 10:55:05 +0300 Subject: [PATCH 17/20] fix: unit tests --- lib/http-server/index.ts | 2 ++ package.json | 6 +++--- test/logger.unit.spec.js | 22 +++++++++++++++++----- tsconfig.json | 4 ++-- 4 files changed, 24 insertions(+), 10 deletions(-) diff --git a/lib/http-server/index.ts b/lib/http-server/index.ts index 85c78b6..eb06be4 100644 --- a/lib/http-server/index.ts +++ b/lib/http-server/index.ts @@ -4,6 +4,8 @@ import fastify from 'fastify'; import cfLogs from 'cf-logs'; import { saveServerAddress } from '../helpers'; + +// eslint-disable-next-line import/no-unresolved import deprecatedImagesCollector from '../metric/deprecated-images/deprecated-images.collector'; const logger = cfLogs.Logger('codefresh:containerLogger'); diff --git a/package.json b/package.json index 80c8357..3d14d09 100644 --- a/package.json +++ b/package.json @@ -47,9 +47,9 @@ "node": ">=16.20.2 <=20" }, "scripts": { - "lint": "eslint '*/**/*.js'", - "lint-fix": "eslint '*/**/*.js' --fix", - "test": "node ./node_modules/mocha/bin/_mocha './{,!(node_modules)/**/}*.spec.js' --exit", + "lint": "eslint '*/**/*.{j,t}s'", + "lint-fix": "eslint '*/**/*.{j,t}s' --fix", + "test": "node ./node_modules/mocha/bin/_mocha --require ts-node/register 'test/**/*.spec.js' --exit", "test:ci": "yarn test", "start": "node dist/index.js", "version": "exit 0", diff --git a/test/logger.unit.spec.js b/test/logger.unit.spec.js index eaf196d..ef42a66 100644 --- a/test/logger.unit.spec.js +++ b/test/logger.unit.spec.js @@ -14,10 +14,12 @@ chai.use(sinonChai); const mockAddress = 'mockAddress'; const stubFastifyPost = sinon.stub(); +const stubFastifyGet = sinon.stub(); const stubFastifyListen = sinon.stub().resolves(mockAddress); const stubFastify = sinon.stub().returns({ listen: stubFastifyListen, post: stubFastifyPost, + get: stubFastifyGet, }); const stubSaveServerAddress = sinon.stub().resolves(); @@ -1696,11 +1698,17 @@ describe('Logger tests', () => { }; const TaskLoggerFactory = sinon.spy(async () => taskLogger); + const HttpServer = proxyquire('../lib/http-server', { + 'fastify': stubFastify, + '../helpers': { + saveServerAddress: stubSaveServerAddress, + } + }); + const Logger = proxyquire('../lib/logger', { '@codefresh-io/task-logger': { TaskLogger: TaskLoggerFactory }, - 'fastify': stubFastify, + './http-server': HttpServer, './helpers': { - saveServerAddress: stubSaveServerAddress, getPromiseWithResolvers, }, }); @@ -1709,6 +1717,8 @@ describe('Logger tests', () => { const taskLoggerConfig = { task: {}, opts: {} }; const findExistingContainers = false; + process.env.PORT = 1337; + process.env.HOST = '127.0.0.1'; const logger = new Logger({ loggerId, taskLoggerConfig, @@ -1717,8 +1727,6 @@ describe('Logger tests', () => { logger._listenForNewContainers = sinon.spy(); logger._writeNewState = sinon.spy(); logger._listenForExistingContainers = sinon.spy(); - process.env.PORT = 1337; - process.env.HOST = '127.0.0.1'; await logger.start(); expect(stubFastify).to.have.been.calledOnce; @@ -1739,9 +1747,13 @@ describe('Logger tests', () => { }; const TaskLoggerFactory = sinon.spy(async () => taskLogger); + const HttpServer = proxyquire('../lib/http-server', { + 'fastify': stubFastify, + }); + const Logger = proxyquire('../lib/logger', { '@codefresh-io/task-logger': { TaskLogger: TaskLoggerFactory }, - 'fastify': stubFastify, + './http-server': HttpServer, './helpers': { saveServerAddress: stubSaveServerAddress, getPromiseWithResolvers, diff --git a/tsconfig.json b/tsconfig.json index 76ea6d5..2bfb9fd 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -25,9 +25,9 @@ // "moduleDetection": "auto", /* Control what method is used to detect module-format JS files. */ /* Modules */ - "module": "commonjs", /* Specify what module code is generated. */ + "module": "node16", /* Specify what module code is generated. */ "rootDir": "./lib", /* Specify the root folder within your source files. */ - // "moduleResolution": "node10", /* Specify how TypeScript looks up a file from a given module specifier. */ + "moduleResolution": "node16", /* Specify how TypeScript looks up a file from a given module specifier. */ // "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */ // "paths": {}, /* Specify a set of entries that re-map imports to additional lookup locations. */ // "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */ From 2013cfbecc0f0cdbc9258bc797550f301f82cf75 Mon Sep 17 00:00:00 2001 From: Vasil Sudakou Date: Thu, 9 Jan 2025 11:16:24 +0300 Subject: [PATCH 18/20] Revert "fix: remove the scripts and Dockerfile for windows os which are unused and confusing" This reverts commit 325495a38231343cac521bb29df818463a69afa3. --- Dockerfile.windows | 55 ++++++++++++++++++++++++++++++++++++++++++++++ lib/forever.ps1 | 4 ++++ lib/isReady.ps1 | 25 +++++++++++++++++++++ 3 files changed, 84 insertions(+) create mode 100644 Dockerfile.windows create mode 100644 lib/forever.ps1 create mode 100644 lib/isReady.ps1 diff --git a/Dockerfile.windows b/Dockerfile.windows new file mode 100644 index 0000000..1dcbec8 --- /dev/null +++ b/Dockerfile.windows @@ -0,0 +1,55 @@ +ARG OS_RELEASE + +FROM mcr.microsoft.com/windows/servercore:${OS_RELEASE} as download + +SHELL ["powershell", "-Command", "$ErrorActionPreference = 'Stop'; $ProgressPreference = 'SilentlyContinue';"] + +ENV GIT_VERSION 2.39.0 +ENV NODE_VERSION 16.20.0 +ENV YARN_VERSION 1.22.19 + +# Download and install git +RUN Invoke-WebRequest $('https://github.com/git-for-windows/git/releases/download/v{0}.windows.1/MinGit-{0}-64-bit.zip' -f $env:GIT_VERSION) -OutFile 'MinGit.zip' -UseBasicParsing ; \ + Expand-Archive c:\MinGit.zip -DestinationPath c:\MinGit; \ + $env:PATH = $env:PATH + ';C:\MinGit\cmd\;C:\MinGit\cmd'; \ + Set-ItemProperty -Path 'HKLM:\SYSTEM\CurrentControlSet\Control\Session Manager\Environment\' -Name Path -Value $env:PATH + +# Download and install node.js +RUN Invoke-WebRequest $('https://nodejs.org/dist/v{0}/node-v{0}-win-x64.zip' -f $env:NODE_VERSION) -OutFile 'node.zip' -UseBasicParsing ; \ + # $sum = $(cat SHASUMS256.txt.asc | sls $(' node-v{0}-win-x64.zip' -f $env:NODE_VERSION)) -Split ' ' ; \ + # if ((Get-FileHash node.zip -Algorithm sha256).Hash -ne $sum[0]) { Write-Error 'SHA256 mismatch' } ; \ + Expand-Archive node.zip -DestinationPath C:\ ; \ + Rename-Item -Path $('C:\node-v{0}-win-x64' -f $env:NODE_VERSION) -NewName 'C:\nodejs' + +# Download and install yarn +RUN [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 ; \ + Invoke-WebRequest $('https://github.com/yarnpkg/yarn/releases/download/v{0}/yarn-{0}.msi' -f $env:YARN_VERSION) -OutFile yarn.msi -UseBasicParsing ; \ + Start-Process msiexec.exe -ArgumentList '/i', 'yarn.msi', '/quiet', '/norestart' -NoNewWindow -Wait + +FROM download as install + +SHELL ["powershell", "-Command", "$ErrorActionPreference = 'Stop'; $ProgressPreference = 'SilentlyContinue';"] + +ENV NPM_CONFIG_LOGLEVEL info + +COPY --from=download /nodejs /nodejs +COPY --from=download [ "/Program Files (x86)/yarn", "/yarn" ] + +RUN $env:PATH = 'C:\nodejs;C:\yarn\bin;{0}' -f $env:PATH ; \ + [Environment]::SetEnvironmentVariable('PATH', $env:PATH, [EnvironmentVariableTarget]::Machine) + +FROM install + +WORKDIR C:/cf-container-logger + +COPY package.json ./ + +COPY yarn.lock ./ + +RUN yarn install --frozen-lockfile --production + +COPY . ./ + +LABEL owner="codefresh.io" + +CMD ["powershell", "./lib/forever.ps1"] diff --git a/lib/forever.ps1 b/lib/forever.ps1 new file mode 100644 index 0000000..3e33432 --- /dev/null +++ b/lib/forever.ps1 @@ -0,0 +1,4 @@ +while ($true) { + Start-Sleep -s 1 + & node dist/index.js +} diff --git a/lib/isReady.ps1 b/lib/isReady.ps1 new file mode 100644 index 0000000..421779d --- /dev/null +++ b/lib/isReady.ps1 @@ -0,0 +1,25 @@ +# DEPRECATED: +# This script is no longer maintained, you should use the ./isReady.js script +# Leaving this script for backwards compatibility (so this container logger can work with older engines) + +$CONTAINER_ID=$args[0] + +if ( $CONTAINER_ID ) { + echo "checking if container:$CONTAINER_ID exists" + if (select-string -Pattern $CONTAINER_ID -Path ./dist/state.json) { + echo "container $CONTAINER_ID is ready" + Exit 0 + } else { + echo "container $CONTAINER_ID is not ready" + Exit 1 + } +} else { + echo "checking if container logger is ready" + if (select-string -Pattern "ready" -Path ./dist/state.json) { + echo "ready" + Exit 0 + } else { + echo "not ready" + Exit 1 + } +} From cff922662ab19a51510318efce105d1f6d9f5f54 Mon Sep 17 00:00:00 2001 From: Vasil Sudakou Date: Mon, 13 Jan 2025 12:57:28 +0300 Subject: [PATCH 19/20] fix: move regex out of class as constant --- .../deprecated-images/deprecated-images.collector.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/metric/deprecated-images/deprecated-images.collector.ts b/lib/metric/deprecated-images/deprecated-images.collector.ts index 9ce0cda..c055a20 100644 --- a/lib/metric/deprecated-images/deprecated-images.collector.ts +++ b/lib/metric/deprecated-images/deprecated-images.collector.ts @@ -1,4 +1,3 @@ -// @ts-expect-error it's a js library import cfLogs from 'cf-logs'; // eslint-disable-next-line import/no-unresolved @@ -6,6 +5,9 @@ import { DeprecatedImageDto } from './deprecated-image.dto'; const logger = cfLogs.Logger('codefresh:containerLogger'); +// eslint-disable-next-line no-control-regex +const DEPRECATED_IMAGE_REGEX = /^\u001b\[31m\u001b\[1m\[DEPRECATION NOTICE].+?Suggest the author of (?.+?) to/; + class DeprecatedImagesCollector { private list: DeprecatedImageDto[] = []; @@ -35,9 +37,7 @@ class DeprecatedImagesCollector { } private _parseImageName(logText: string) { - // eslint-disable-next-line no-control-regex - const regex = /^\u001b\[31m\u001b\[1m\[DEPRECATION NOTICE].+?Suggest the author of (?.+?) to/; - const match = logText.match(regex); + const match = logText.match(DEPRECATED_IMAGE_REGEX); return match?.groups?.image ?? null; } } From ea8b6efe8f6409d8c3eeed1983aaa8da95db1b62 Mon Sep 17 00:00:00 2001 From: Vasil Sudakou Date: Mon, 13 Jan 2025 13:22:22 +0300 Subject: [PATCH 20/20] fix: ts declarations --- lib/@types/index.d.ts | 1 + lib/http-server/index.ts | 2 -- package.json | 2 +- tsconfig.json | 4 +++- 4 files changed, 5 insertions(+), 4 deletions(-) create mode 100644 lib/@types/index.d.ts diff --git a/lib/@types/index.d.ts b/lib/@types/index.d.ts new file mode 100644 index 0000000..83c264c --- /dev/null +++ b/lib/@types/index.d.ts @@ -0,0 +1 @@ +declare module 'cf-logs'; diff --git a/lib/http-server/index.ts b/lib/http-server/index.ts index eb06be4..5281f56 100644 --- a/lib/http-server/index.ts +++ b/lib/http-server/index.ts @@ -1,6 +1,4 @@ import fastify from 'fastify'; - -// @ts-expect-error it's a js library import cfLogs from 'cf-logs'; import { saveServerAddress } from '../helpers'; diff --git a/package.json b/package.json index 3d14d09..f4c0a29 100644 --- a/package.json +++ b/package.json @@ -49,7 +49,7 @@ "scripts": { "lint": "eslint '*/**/*.{j,t}s'", "lint-fix": "eslint '*/**/*.{j,t}s' --fix", - "test": "node ./node_modules/mocha/bin/_mocha --require ts-node/register 'test/**/*.spec.js' --exit", + "test": "node ./node_modules/mocha/bin/_mocha --require ts-node/register './{,!(node_modules|dist)/**/}*.spec.js' --exit", "test:ci": "yarn test", "start": "node dist/index.js", "version": "exit 0", diff --git a/tsconfig.json b/tsconfig.json index 2bfb9fd..2ebd563 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -29,7 +29,9 @@ "rootDir": "./lib", /* Specify the root folder within your source files. */ "moduleResolution": "node16", /* Specify how TypeScript looks up a file from a given module specifier. */ // "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */ - // "paths": {}, /* Specify a set of entries that re-map imports to additional lookup locations. */ + "paths": { + "cf-logs": ["./lib/@types"] + }, /* Specify a set of entries that re-map imports to additional lookup locations. */ // "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */ // "typeRoots": [], /* Specify multiple folders that act like './node_modules/@types'. */ // "types": [], /* Specify type package names to be included without being referenced in a source file. */