From 522d3f7732cbcf058d16cdf4da3b76feec23833e Mon Sep 17 00:00:00 2001 From: Fabio Vincenzi Date: Mon, 17 Feb 2025 16:12:08 +0100 Subject: [PATCH 01/13] feat: add TypeScript support and configure tsconfig --- index.js => index.ts | 25 +++-- package-lock.json | 252 ++++++++++++++++++++++++++++++++++++++++--- package.json | 10 +- tsconfig.json | 16 +++ 4 files changed, 278 insertions(+), 25 deletions(-) rename index.js => index.ts (67%) create mode 100644 tsconfig.json diff --git a/index.js b/index.ts similarity index 67% rename from index.js rename to index.ts index c86c0425e..d52c76a7e 100755 --- a/index.js +++ b/index.ts @@ -1,6 +1,13 @@ #!/usr/bin/env node /* eslint-disable max-len */ -const argv = require('yargs/yargs')(process.argv.slice(2)) +import yargs from 'yargs'; +import { hideBin } from 'yargs/helpers'; +import * as fs from 'fs'; +import config from './src/config/file'; +import proxy from './src/proxy'; +import service from './src/service'; + +const argv = yargs(hideBin(process.argv)) .usage('Usage: $0 [options]') .options({ validate: { @@ -8,23 +15,23 @@ const argv = require('yargs/yargs')(process.argv.slice(2)) 'Check the proxy.config.json file in the current working directory for validation errors.', required: false, alias: 'v', + type: 'boolean', }, config: { description: 'Path to custom git-proxy configuration file.', default: 'proxy.config.json', required: false, alias: 'c', + type: 'string', }, }) - .strict().argv; + .strict() + .parseSync(); -const config = require('./src/config/file'); config.configFile = argv.c ? argv.c : undefined; if (argv.v) { - const fs = require('fs'); - - if (!fs.existsSync(config.configFile)) { + if (!fs.existsSync(config.configFile as string)) { console.error( `Config file ${config.configFile} doesn't exist, nothing to validate! Did you forget -c/--config?`, ); @@ -38,11 +45,7 @@ if (argv.v) { config.validate(); -const proxy = require('./src/proxy'); -const service = require('./src/service'); - proxy.start(); service.start(); -module.exports.proxy = proxy; -module.exports.service = service; +export { proxy, service }; diff --git a/package-lock.json b/package-lock.json index e54daaee2..db4c5a143 100644 --- a/package-lock.json +++ b/package-lock.json @@ -62,6 +62,8 @@ "@babel/preset-react": "^7.22.5", "@commitlint/cli": "^19.0.0", "@commitlint/config-conventional": "^19.0.0", + "@types/node": "^22.13.4", + "@types/yargs": "^17.0.33", "@vitejs/plugin-react": "^4.0.2", "chai": "^4.2.0", "chai-http": "^4.3.0", @@ -78,7 +80,10 @@ "nyc": "^17.0.0", "prettier": "^3.0.0", "sinon": "^19.0.2", - "vite": "^4.4.2" + "ts-node": "^10.9.2", + "typescript": "^5.7.3", + "vite": "^4.4.2", + "vite-tsconfig-paths": "^5.1.4" }, "optionalDependencies": { "@esbuild/darwin-arm64": "^0.18.20", @@ -1651,6 +1656,30 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, + "node_modules/@cspotcode/source-map-support": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", + "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/trace-mapping": "0.3.9" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@cspotcode/source-map-support/node_modules/@jridgewell/trace-mapping": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", + "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.0.3", + "@jridgewell/sourcemap-codec": "^1.4.10" + } + }, "node_modules/@cypress/request": { "version": "3.0.6", "resolved": "https://registry.npmjs.org/@cypress/request/-/request-3.0.6.tgz", @@ -3491,6 +3520,34 @@ "node": ">=14.0.0" } }, + "node_modules/@tsconfig/node10": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.11.tgz", + "integrity": "sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@tsconfig/node12": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", + "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", + "dev": true, + "license": "MIT" + }, + "node_modules/@tsconfig/node14": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", + "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", + "dev": true, + "license": "MIT" + }, + "node_modules/@tsconfig/node16": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz", + "integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==", + "dev": true, + "license": "MIT" + }, "node_modules/@types/babel__core": { "version": "7.20.5", "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", @@ -3555,11 +3612,12 @@ "dev": true }, "node_modules/@types/node": { - "version": "20.10.7", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.10.7.tgz", - "integrity": "sha512-fRbIKb8C/Y2lXxB5eVMj4IU7xpdox0Lh8bUPEdtLysaylsml1hOOx1+STloRs/B9nf7C6kPRmmg/V7aQW7usNg==", + "version": "22.13.4", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.13.4.tgz", + "integrity": "sha512-ywP2X0DYtX3y08eFVx5fNIw7/uIv8hYUKgXoK8oayJlLnKcRfEYCxWMVE1XagUdVtCJlZT1AU4LXEABW+L1Peg==", + "license": "MIT", "dependencies": { - "undici-types": "~5.26.4" + "undici-types": "~6.20.0" } }, "node_modules/@types/prop-types": { @@ -3631,6 +3689,23 @@ "@types/webidl-conversions": "*" } }, + "node_modules/@types/yargs": { + "version": "17.0.33", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.33.tgz", + "integrity": "sha512-WpxBCKWPLr4xSsHgz511rFJAM+wS28w2zEO1QDNY5zM/S8ok70NNfztH0xwhqKyaK0OHCbN98LDAZuy1ctxDkA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/yargs-parser": "*" + } + }, + "node_modules/@types/yargs-parser": { + "version": "21.0.3", + "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.3.tgz", + "integrity": "sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==", + "dev": true, + "license": "MIT" + }, "node_modules/@types/yauzl": { "version": "2.10.3", "resolved": "https://registry.npmjs.org/@types/yauzl/-/yauzl-2.10.3.tgz", @@ -3710,6 +3785,19 @@ "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" } }, + "node_modules/acorn-walk": { + "version": "8.3.4", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.4.tgz", + "integrity": "sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g==", + "dev": true, + "license": "MIT", + "dependencies": { + "acorn": "^8.11.0" + }, + "engines": { + "node": ">=0.4.0" + } + }, "node_modules/activedirectory2": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/activedirectory2/-/activedirectory2-2.2.0.tgz", @@ -3865,6 +3953,13 @@ "integrity": "sha512-Xg+9RwCg/0p32teKdGMPTPnVXKD0w3DfHnFTficozsAgsvq2XenPJq/MYpzzQ/v8zrOyJn6Ds39VA4JIDwFfqw==", "dev": true }, + "node_modules/arg": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", + "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", + "dev": true, + "license": "MIT" + }, "node_modules/argparse": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", @@ -5108,6 +5203,13 @@ "node": ">=0.8" } }, + "node_modules/create-require": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", + "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", + "dev": true, + "license": "MIT" + }, "node_modules/cross-spawn": { "version": "7.0.6", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", @@ -7266,6 +7368,13 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/globrex": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/globrex/-/globrex-0.1.2.tgz", + "integrity": "sha512-uHJgbwAMwNFf5mLst7IWLNg14x1CkeqglJb/K3doi4dw6q2IvAAmM/Y81kevy83wP+Sst+nutFTYOGg3d1lsxg==", + "dev": true, + "license": "MIT" + }, "node_modules/gopd": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", @@ -9215,6 +9324,13 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/make-error": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", + "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", + "dev": true, + "license": "ISC" + }, "node_modules/math-intrinsics": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", @@ -12232,6 +12348,81 @@ "tree-kill": "cli.js" } }, + "node_modules/ts-node": { + "version": "10.9.2", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz", + "integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==", + "dev": true, + "license": "MIT", + "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" + }, + "bin": { + "ts-node": "dist/bin.js", + "ts-node-cwd": "dist/bin-cwd.js", + "ts-node-esm": "dist/bin-esm.js", + "ts-node-script": "dist/bin-script.js", + "ts-node-transpile-only": "dist/bin-transpile.js", + "ts-script": "dist/bin-script-deprecated.js" + }, + "peerDependencies": { + "@swc/core": ">=1.2.50", + "@swc/wasm": ">=1.2.50", + "@types/node": "*", + "typescript": ">=2.7" + }, + "peerDependenciesMeta": { + "@swc/core": { + "optional": true + }, + "@swc/wasm": { + "optional": true + } + } + }, + "node_modules/ts-node/node_modules/diff": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/tsconfck": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/tsconfck/-/tsconfck-3.1.5.tgz", + "integrity": "sha512-CLDfGgUp7XPswWnezWwsCRxNmgQjhYq3VXHM0/XIRxhVrKw0M1if9agzryh1QS3nxjCROvV+xWxoJO1YctzzWg==", + "dev": true, + "license": "MIT", + "bin": { + "tsconfck": "bin/tsconfck.js" + }, + "engines": { + "node": "^18 || >=20" + }, + "peerDependencies": { + "typescript": "^5.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, "node_modules/tslib": { "version": "2.6.2", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", @@ -12398,12 +12589,11 @@ } }, "node_modules/typescript": { - "version": "5.7.2", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.7.2.tgz", - "integrity": "sha512-i5t66RHxDvVN40HfDd1PsEThGNnlMCMT3jMUuoh9/0TaqWevNontacunWyN02LA9/fIbEWlcHZcgTKb9QoaLfg==", + "version": "5.7.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.7.3.tgz", + "integrity": "sha512-84MVSjMEHP+FQRPy3pX9sTVV/INIex71s9TL2Gm5FG/WG1SqXeKyZ0k7/blY/4FdOzI12CBy1vGc4og/eus0fw==", "dev": true, "license": "Apache-2.0", - "peer": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -12443,9 +12633,10 @@ } }, "node_modules/undici-types": { - "version": "5.26.5", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", - "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==" + "version": "6.20.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.20.0.tgz", + "integrity": "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==", + "license": "MIT" }, "node_modules/unicorn-magic": { "version": "0.1.0", @@ -12564,6 +12755,13 @@ "uuid": "dist/esm/bin/uuid" } }, + "node_modules/v8-compile-cache-lib": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", + "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", + "dev": true, + "license": "MIT" + }, "node_modules/vary": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", @@ -12665,6 +12863,26 @@ } } }, + "node_modules/vite-tsconfig-paths": { + "version": "5.1.4", + "resolved": "https://registry.npmjs.org/vite-tsconfig-paths/-/vite-tsconfig-paths-5.1.4.tgz", + "integrity": "sha512-cYj0LRuLV2c2sMqhqhGpaO3LretdtMn/BVX4cPLanIZuwwrkVl+lK84E/miEXkCHWXuq65rhNN4rXsBcOB3S4w==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^4.1.1", + "globrex": "^0.1.2", + "tsconfck": "^3.0.3" + }, + "peerDependencies": { + "vite": "*" + }, + "peerDependenciesMeta": { + "vite": { + "optional": true + } + } + }, "node_modules/vscode-json-languageservice": { "version": "4.2.1", "resolved": "https://registry.npmjs.org/vscode-json-languageservice/-/vscode-json-languageservice-4.2.1.tgz", @@ -13071,6 +13289,16 @@ "fd-slicer": "~1.1.0" } }, + "node_modules/yn": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", + "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, "node_modules/yocto-queue": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", diff --git a/package.json b/package.json index 9cb00c5ec..5b9ce86e8 100644 --- a/package.json +++ b/package.json @@ -6,9 +6,10 @@ "cli": "node ./packages/git-proxy-cli/index.js", "client": "vite --config vite.config.js", "clientinstall": "npm install --prefix client", - "server": "node index.js", + "server": "ts-node index.ts", "start": "concurrently \"npm run server\" \"npm run client\"", "build": "vite build", + "build-ts": "tsc", "test": "NODE_ENV=test mocha --exit", "test-coverage": "nyc npm run test", "test-coverage-ci": "nyc --reporter=lcovonly --reporter=text npm run test", @@ -79,6 +80,8 @@ "@babel/preset-react": "^7.22.5", "@commitlint/cli": "^19.0.0", "@commitlint/config-conventional": "^19.0.0", + "@types/node": "^22.13.4", + "@types/yargs": "^17.0.33", "@vitejs/plugin-react": "^4.0.2", "chai": "^4.2.0", "chai-http": "^4.3.0", @@ -95,7 +98,10 @@ "nyc": "^17.0.0", "prettier": "^3.0.0", "sinon": "^19.0.2", - "vite": "^4.4.2" + "ts-node": "^10.9.2", + "typescript": "^5.7.3", + "vite": "^4.4.2", + "vite-tsconfig-paths": "^5.1.4" }, "optionalDependencies": { "@esbuild/darwin-arm64": "^0.18.20", diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 000000000..b3353bd12 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,16 @@ +{ + "compilerOptions": { + "target": "ES6", + "lib": ["DOM", "ESNext"], + "allowJs": true, + "checkJs": false, + "jsx": "react-jsx", + "moduleResolution": "Node", + "strict": true, + "noEmit": true, + "skipLibCheck": true, + "isolatedModules": true, + "esModuleInterop": true + }, + "include": ["src"] +} From 62b8d55ebc1abaeb05213a9feb4da22fb8a5b4df Mon Sep 17 00:00:00 2001 From: Juan Escalada Date: Mon, 24 Feb 2025 16:01:44 +0900 Subject: [PATCH 02/13] refactor(ts): change file db module to TS and ESM --- src/db/file/index.js | 29 ----------- src/db/file/index.ts | 35 +++++++++++++ src/db/file/{pushes.js => pushes.ts} | 74 +++++++++++++++------------ src/db/file/{repo.js => repo.ts} | 75 +++++++++++++++++----------- src/db/file/{users.js => users.ts} | 31 ++++++------ 5 files changed, 138 insertions(+), 106 deletions(-) delete mode 100644 src/db/file/index.js create mode 100644 src/db/file/index.ts rename src/db/file/{pushes.js => pushes.ts} (57%) rename src/db/file/{repo.js => repo.ts} (60%) rename src/db/file/{users.js => users.ts} (58%) diff --git a/src/db/file/index.js b/src/db/file/index.js deleted file mode 100644 index f77833f52..000000000 --- a/src/db/file/index.js +++ /dev/null @@ -1,29 +0,0 @@ -const pushes = require('./pushes'); -const users = require('./users'); -const repo = require('./repo'); - -module.exports.getPushes = pushes.getPushes; -module.exports.writeAudit = pushes.writeAudit; -module.exports.getPush = pushes.getPush; -module.exports.authorise = pushes.authorise; -module.exports.cancel = pushes.cancel; -module.exports.reject = pushes.reject; -module.exports.canUserCancelPush = pushes.canUserCancelPush; -module.exports.canUserApproveRejectPush = pushes.canUserApproveRejectPush; - -module.exports.findUser = users.findUser; -module.exports.getUsers = users.getUsers; -module.exports.createUser = users.createUser; -module.exports.deleteUser = users.deleteUser; -module.exports.updateUser = users.updateUser; - -module.exports.getRepos = repo.getRepos; -module.exports.getRepo = repo.getRepo; -module.exports.createRepo = repo.createRepo; -module.exports.addUserCanPush = repo.addUserCanPush; -module.exports.addUserCanAuthorise = repo.addUserCanAuthorise; -module.exports.removeUserCanPush = repo.removeUserCanPush; -module.exports.removeUserCanAuthorise = repo.removeUserCanAuthorise; -module.exports.deleteRepo = repo.deleteRepo; -module.exports.isUserPushAllowed = repo.isUserPushAllowed; -module.exports.canUserApproveRejectPushRepo = repo.canUserApproveRejectPushRepo; diff --git a/src/db/file/index.ts b/src/db/file/index.ts new file mode 100644 index 000000000..be9f0c42a --- /dev/null +++ b/src/db/file/index.ts @@ -0,0 +1,35 @@ +import * as users from './users'; +import * as repo from './repo'; +import * as pushes from './pushes'; + +export const { + getPushes, + writeAudit, + getPush, + authorise, + cancel, + reject, + canUserCancelPush, + canUserApproveRejectPush, +} = pushes; + +export const { + getRepos, + getRepo, + createRepo, + addUserCanPush, + addUserCanAuthorise, + removeUserCanPush, + removeUserCanAuthorise, + deleteRepo, + isUserPushAllowed, + canUserApproveRejectPushRepo, +} = repo; + +export const { + findUser, + getUsers, + createUser, + deleteUser, + updateUser, +} = users; diff --git a/src/db/file/pushes.js b/src/db/file/pushes.ts similarity index 57% rename from src/db/file/pushes.js rename to src/db/file/pushes.ts index cbc79244a..6a0866910 100644 --- a/src/db/file/pushes.js +++ b/src/db/file/pushes.ts @@ -1,26 +1,27 @@ -const fs = require('fs'); -const _ = require('lodash'); -const Datastore = require('@seald-io/nedb'); -const Action = require('../../proxy/actions/Action').Action; -const toClass = require('../helper').toClass; -const repo = require('./repo'); +import fs from 'fs'; +import _ from 'lodash'; +import Datastore from '@seald-io/nedb'; +import { Action } from '../../proxy/actions/Action'; +import { toClass } from '../helper'; +import * as repo from './repo'; +import { PushQuery } from '../types' if (!fs.existsSync('./.data')) fs.mkdirSync('./.data'); if (!fs.existsSync('./.data/db')) fs.mkdirSync('./.data/db'); const db = new Datastore({ filename: './.data/db/pushes.db', autoload: true }); -const defaultPushQuery = { +const defaultPushQuery: PushQuery = { error: false, blocked: true, allowPush: false, authorised: false, }; -const getPushes = (query, logger) => { +export const getPushes = (query: PushQuery) => { if (!query) query = defaultPushQuery; return new Promise((resolve, reject) => { - db.find(query, (err, docs) => { + db.find(query, (err: Error, docs: Action[]) => { if (err) { reject(err); } else { @@ -34,8 +35,8 @@ const getPushes = (query, logger) => { }); }; -const getPush = async (id, logger) => { - return new Promise((resolve, reject) => { +export const getPush = async (id: string) => { + return new Promise((resolve, reject) => { db.findOne({ id: id }, (err, doc) => { if (err) { reject(err); @@ -50,7 +51,7 @@ const getPush = async (id, logger) => { }); }; -const writeAudit = async (action, logger) => { +export const writeAudit = async (action: Action) => { return new Promise((resolve, reject) => { const options = { multi: false, upsert: true }; db.update({ id: action.id }, action, options, (err) => { @@ -63,8 +64,12 @@ const writeAudit = async (action, logger) => { }); }; -const authorise = async (id, attestation) => { +export const authorise = async (id: string, attestation: any) => { const action = await getPush(id); + if (!action) { + throw new Error(`push ${id} not found`); + } + action.authorised = true; action.canceled = false; action.rejected = false; @@ -73,8 +78,12 @@ const authorise = async (id, attestation) => { return { message: `authorised ${id}` }; }; -const reject = async (id, logger) => { - const action = await getPush(id, logger); +export const reject = async (id: string) => { + const action = await getPush(id); + if (!action) { + throw new Error(`push ${id} not found`); + } + action.authorised = false; action.canceled = false; action.rejected = true; @@ -82,8 +91,11 @@ const reject = async (id, logger) => { return { message: `reject ${id}` }; }; -const cancel = async (id, logger) => { - const action = await getPush(id, logger); +export const cancel = async (id: string) => { + const action = await getPush(id); + if (!action) { + throw new Error(`push ${id} not found`); + } action.authorised = false; action.canceled = true; action.rejected = false; @@ -91,10 +103,14 @@ const cancel = async (id, logger) => { return { message: `cancel ${id}` }; }; -const canUserCancelPush = async (id, user) => { - return new Promise(async (resolve) => { +export const canUserCancelPush = async (id: string, user: any) => { + return new Promise(async (resolve) => { const pushDetail = await getPush(id); - const repoName = pushDetail.repoName.replace('.git', ''); + if (!pushDetail) { + resolve(false); + } + + const repoName = pushDetail?.repoName.replace('.git', ''); const isAllowed = await repo.isUserPushAllowed(repoName, user); if (isAllowed) { @@ -105,21 +121,15 @@ const canUserCancelPush = async (id, user) => { }); }; -const canUserApproveRejectPush = async (id, user) => { - return new Promise(async (resolve) => { +export const canUserApproveRejectPush = async (id: string, user: any) => { + return new Promise(async (resolve) => { const action = await getPush(id); - const repoName = action.repoName.replace('.git', ''); + if (!action) { + resolve(false); + } + const repoName = action?.repoName.replace('.git', ''); const isAllowed = await repo.canUserApproveRejectPushRepo(repoName, user); resolve(isAllowed); }); }; - -module.exports.getPushes = getPushes; -module.exports.writeAudit = writeAudit; -module.exports.getPush = getPush; -module.exports.authorise = authorise; -module.exports.reject = reject; -module.exports.cancel = cancel; -module.exports.canUserCancelPush = canUserCancelPush; -module.exports.canUserApproveRejectPush = canUserApproveRejectPush; diff --git a/src/db/file/repo.js b/src/db/file/repo.ts similarity index 60% rename from src/db/file/repo.js rename to src/db/file/repo.ts index e6f7dd894..98efaaa9b 100644 --- a/src/db/file/repo.js +++ b/src/db/file/repo.ts @@ -1,14 +1,16 @@ -const fs = require('fs'); -const Datastore = require('@seald-io/nedb'); +import fs from 'fs'; +import Datastore from '@seald-io/nedb' +import { Action } from '../../proxy/actions/Action'; +import { Repo } from '../types'; if (!fs.existsSync('./.data')) fs.mkdirSync('./.data'); if (!fs.existsSync('./.data/db')) fs.mkdirSync('./.data/db'); const db = new Datastore({ filename: './.data/db/repos.db', autoload: true }); -exports.getRepos = async (query = {}) => { - return new Promise((resolve, reject) => { - db.find({}, (err, docs) => { +export const getRepos = async (query = {}) => { + return new Promise((resolve, reject) => { + db.find({}, (err: Error, docs: Repo[]) => { if (err) { reject(err); } else { @@ -18,29 +20,26 @@ exports.getRepos = async (query = {}) => { }); }; -exports.getRepo = async (name) => { - return new Promise((resolve, reject) => { - db.findOne({ name: name }, (err, doc) => { +export const getRepo = async (name: string) => { + return new Promise((resolve, reject) => { + db.findOne({ name }, (err: Error | null, doc: Repo) => { if (err) { reject(err); } else { - if (!doc) { - resolve(null); - } else { - resolve(doc); - } + resolve(doc); } }); }); }; -exports.createRepo = async (repo) => { + +export const createRepo = async (repo: Repo) => { repo.users = { canPush: [], canAuthorise: [], }; - return new Promise((resolve, reject) => { + return new Promise((resolve, reject) => { db.insert(repo, (err, doc) => { if (err) { reject(err); @@ -51,9 +50,13 @@ exports.createRepo = async (repo) => { }); }; -exports.addUserCanPush = async (name, user) => { +export const addUserCanPush = async (name: string, user: string) => { return new Promise(async (resolve, reject) => { - const repo = await exports.getRepo(name); + const repo = await getRepo(name); + if (!repo) { + reject(new Error('Repo not found')); + return; + } if (repo.users.canPush.includes(user)) { resolve(null); @@ -72,9 +75,13 @@ exports.addUserCanPush = async (name, user) => { }); }; -exports.addUserCanAuthorise = async (name, user) => { +export const addUserCanAuthorise = async (name: string, user: string) => { return new Promise(async (resolve, reject) => { - const repo = await exports.getRepo(name); + const repo = await getRepo(name); + if (!repo) { + reject(new Error('Repo not found')); + return; + } if (repo.users.canAuthorise.includes(user)) { resolve(null); @@ -94,11 +101,15 @@ exports.addUserCanAuthorise = async (name, user) => { }); }; -exports.removeUserCanAuthorise = async (name, user) => { +export const removeUserCanAuthorise = async (name: string, user: string) => { return new Promise(async (resolve, reject) => { - const repo = await exports.getRepo(name); + const repo = await getRepo(name); + if (!repo) { + reject(new Error('Repo not found')); + return; + } - repo.users.canAuthorise = repo.users.canAuthorise.filter((x) => x != user); + repo.users.canAuthorise = repo.users.canAuthorise.filter((x: string) => x != user); const options = { multi: false, upsert: false }; db.update({ name: name }, repo, options, (err) => { @@ -111,9 +122,13 @@ exports.removeUserCanAuthorise = async (name, user) => { }); }; -exports.removeUserCanPush = async (name, user) => { +export const removeUserCanPush = async (name: string, user: string) => { return new Promise(async (resolve, reject) => { - const repo = await exports.getRepo(name); + const repo = await getRepo(name); + if (!repo) { + reject(new Error('Repo not found')); + return; + } repo.users.canPush = repo.users.canPush.filter((x) => x != user); @@ -128,8 +143,8 @@ exports.removeUserCanPush = async (name, user) => { }); }; -exports.deleteRepo = async (name) => { - return new Promise((resolve, reject) => { +export const deleteRepo = async (name: string) => { + return new Promise((resolve, reject) => { db.remove({ name: name }, (err) => { if (err) { reject(err); @@ -140,9 +155,9 @@ exports.deleteRepo = async (name) => { }); }; -exports.isUserPushAllowed = async (name, user) => { +export const isUserPushAllowed = async (name: string, user: string) => { name = name.toLowerCase(); - return new Promise(async (resolve, reject) => { + return new Promise(async (resolve, reject) => { const repo = await exports.getRepo(name); console.log(repo.users.canPush); console.log(repo.users.canAuthorise); @@ -155,10 +170,10 @@ exports.isUserPushAllowed = async (name, user) => { }); }; -exports.canUserApproveRejectPushRepo = async (name, user) => { +export const canUserApproveRejectPushRepo = async (name: string, user: string) => { name = name.toLowerCase(); console.log(`checking if user ${user} can approve/reject for ${name}`); - return new Promise(async (resolve, reject) => { + return new Promise(async (resolve, reject) => { const repo = await exports.getRepo(name); if (repo.users.canAuthorise.includes(user)) { console.log(`user ${user} can approve/reject to repo ${name}`); diff --git a/src/db/file/users.js b/src/db/file/users.ts similarity index 58% rename from src/db/file/users.js rename to src/db/file/users.ts index e29dfa4f7..23bab8116 100644 --- a/src/db/file/users.js +++ b/src/db/file/users.ts @@ -1,14 +1,15 @@ -const fs = require('fs'); -const Datastore = require('@seald-io/nedb'); +import fs from 'fs'; +import Datastore from '@seald-io/nedb'; +import { User } from '../types'; if (!fs.existsSync('./.data')) fs.mkdirSync('./.data'); if (!fs.existsSync('./.data/db')) fs.mkdirSync('./.data/db'); const db = new Datastore({ filename: './.data/db/users.db', autoload: true }); -exports.findUser = function (username) { - return new Promise((resolve, reject) => { - db.findOne({ username: username }, (err, doc) => { +export const findUser = (username: string) => { + return new Promise((resolve, reject) => { + db.findOne({ username: username }, (err: Error | null, doc: User) => { if (err) { reject(err); } else { @@ -22,20 +23,20 @@ exports.findUser = function (username) { }); }; -exports.createUser = function (data) { - return new Promise((resolve, reject) => { - db.insert(data, (err) => { +export const createUser = (user: User) => { + return new Promise((resolve, reject) => { + db.insert(user, (err) => { if (err) { reject(err); } else { - resolve(data); + resolve(user); } }); }); }; -exports.deleteUser = function (username) { - return new Promise((resolve, reject) => { +export const deleteUser = (username: string) => { + return new Promise((resolve, reject) => { db.remove({ username: username }, (err) => { if (err) { reject(err); @@ -46,7 +47,7 @@ exports.deleteUser = function (username) { }); }; -exports.updateUser = function (user) { +export const updateUser = (user: User) => { return new Promise((resolve, reject) => { const options = { multi: false, upsert: false }; db.update({ username: user.username }, user, options, (err) => { @@ -59,10 +60,10 @@ exports.updateUser = function (user) { }); }; -exports.getUsers = function (query) { +export const getUsers = (query: any) => { if (!query) query = {}; - return new Promise((resolve, reject) => { - db.find({}, (err, docs) => { + return new Promise((resolve, reject) => { + db.find({}, (err: Error, docs: User[]) => { if (err) { reject(err); } else { From c3ffd784da1be3aff1758244f2a3cac32ac7d89e Mon Sep 17 00:00:00 2001 From: Juan Escalada Date: Mon, 24 Feb 2025 16:08:46 +0900 Subject: [PATCH 03/13] refactor(ts): change mongo db module to use TS and ESM --- src/db/mongo/helper.js | 26 ------ src/db/mongo/helper.ts | 45 +++++++++++ src/db/mongo/index.js | 32 -------- src/db/mongo/index.ts | 40 +++++++++ src/db/mongo/pushes.js | 123 ---------------------------- src/db/mongo/pushes.ts | 129 ++++++++++++++++++++++++++++++ src/db/mongo/{repo.js => repo.ts} | 42 +++++----- src/db/mongo/users.js | 31 ------- src/db/mongo/users.ts | 33 ++++++++ 9 files changed, 269 insertions(+), 232 deletions(-) delete mode 100644 src/db/mongo/helper.js create mode 100644 src/db/mongo/helper.ts delete mode 100644 src/db/mongo/index.js create mode 100644 src/db/mongo/index.ts delete mode 100644 src/db/mongo/pushes.js create mode 100644 src/db/mongo/pushes.ts rename src/db/mongo/{repo.js => repo.ts} (63%) delete mode 100644 src/db/mongo/users.js create mode 100644 src/db/mongo/users.ts diff --git a/src/db/mongo/helper.js b/src/db/mongo/helper.js deleted file mode 100644 index 116b35c08..000000000 --- a/src/db/mongo/helper.js +++ /dev/null @@ -1,26 +0,0 @@ -const mongo = require('mongodb'); -const config = require('../../config'); -const dbConfig = config.getDatabase(); -const options = dbConfig.options; -const connectionString = dbConfig.connectionString; -const MongoDBStore = require('connect-mongo'); - -let _db; - -exports.connect = async (collectionName) => { - if (!_db) { - const client = new mongo.MongoClient(connectionString, options); - await client.connect(); - _db = await client.db(); - } - - return _db.collection(collectionName); -}; - -exports.getSessionStore = (session) => { - return new MongoDBStore({ - mongoUrl: connectionString, - collectionName: 'user_session', - mongoOptions: options, - }); -}; diff --git a/src/db/mongo/helper.ts b/src/db/mongo/helper.ts new file mode 100644 index 000000000..ca5130925 --- /dev/null +++ b/src/db/mongo/helper.ts @@ -0,0 +1,45 @@ +import { MongoClient, Db, Collection, Filter, Document, FindOptions } from 'mongodb'; +import config from '../../config'; +import MongoDBStore from 'connect-mongo'; + +const dbConfig = config.getDatabase(); +const connectionString = dbConfig.connectionString; +const options = dbConfig.options; + +let _db: Db | null = null; + +export const connect = async (collectionName: string): Promise => { + if (!_db) { + const client = new MongoClient(connectionString, options); + await client.connect(); + _db = client.db(); + } + + return _db.collection(collectionName); +}; + +export const findDocuments = async ( + collectionName: string, + filter: Filter = {}, + options: FindOptions = {} +): Promise => { + const collection = await connect(collectionName); + return collection.find(filter, options).toArray() as Promise; +}; + +export const findOneDocument = async ( + collectionName: string, + filter: Filter = {}, + options: FindOptions = {} +): Promise => { + const collection = await connect(collectionName); + return (await collection.findOne(filter, options)) as T | null; +}; + +export const getSessionStore = () => { + return new MongoDBStore({ + mongoUrl: connectionString, + collectionName: 'user_session', + mongoOptions: options, + }); +}; diff --git a/src/db/mongo/index.js b/src/db/mongo/index.js deleted file mode 100644 index d8687f30c..000000000 --- a/src/db/mongo/index.js +++ /dev/null @@ -1,32 +0,0 @@ -const pushes = require('./pushes'); -const users = require('./users'); -const repo = require('./repo'); -const helper = require('./helper'); - -module.exports.getPushes = pushes.getPushes; -module.exports.writeAudit = pushes.writeAudit; -module.exports.getPush = pushes.getPush; -module.exports.authorise = pushes.authorise; -module.exports.cancel = pushes.cancel; -module.exports.reject = pushes.reject; -module.exports.canUserApproveRejectPush = pushes.canUserApproveRejectPush; -module.exports.canUserCancelPush = pushes.canUserCancelPush; - -module.exports.findUser = users.findUser; -module.exports.getUsers = users.getUsers; -module.exports.createUser = users.createUser; -module.exports.deleteUser = users.deleteUser; -module.exports.updateUser = users.updateUser; - -module.exports.getRepos = repo.getRepos; -module.exports.getRepo = repo.getRepo; -module.exports.createRepo = repo.createRepo; -module.exports.addUserCanPush = repo.addUserCanPush; -module.exports.addUserCanAuthorise = repo.addUserCanAuthorise; -module.exports.removeUserCanPush = repo.removeUserCanPush; -module.exports.removeUserCanAuthorise = repo.removeUserCanAuthorise; -module.exports.deleteRepo = repo.deleteRepo; -module.exports.isUserPushAllowed = repo.isUserPushAllowed; -module.exports.canUserApproveRejectPushRepo = repo.canUserApproveRejectPushRepo; - -module.exports.getSessionStore = helper.getSessionStore; diff --git a/src/db/mongo/index.ts b/src/db/mongo/index.ts new file mode 100644 index 000000000..11f526c2a --- /dev/null +++ b/src/db/mongo/index.ts @@ -0,0 +1,40 @@ +import * as helper from './helper'; +import * as pushes from './pushes'; +import * as repo from './repo'; +import * as users from './users'; + +export const { + getSessionStore, +} = helper; + +export const { + getPushes, + writeAudit, + getPush, + authorise, + cancel, + reject, + canUserCancelPush, + canUserApproveRejectPush, +} = pushes; + +export const { + getRepos, + getRepo, + createRepo, + addUserCanPush, + addUserCanAuthorise, + removeUserCanPush, + removeUserCanAuthorise, + deleteRepo, + isUserPushAllowed, + canUserApproveRejectPushRepo, +} = repo; + +export const { + findUser, + getUsers, + createUser, + deleteUser, + updateUser, +} = users; diff --git a/src/db/mongo/pushes.js b/src/db/mongo/pushes.js deleted file mode 100644 index 0927a6db7..000000000 --- a/src/db/mongo/pushes.js +++ /dev/null @@ -1,123 +0,0 @@ -const connect = require('./helper').connect; -const Action = require('../../proxy/actions').Action; -const toClass = require('../helper').toClass; -const repo = require('./repo'); -const cnName = 'pushes'; - -const defaultPushQuery = { - error: false, - blocked: true, - allowPush: false, - authorised: false, -}; - -const getPushes = async (query = defaultPushQuery) => { - const collection = await connect(cnName); - return collection - .find(query, { - projection: { - _id: 0, - id: 1, - allowPush: 1, - authorised: 1, - blocked: 1, - blockedMessage: 1, - branch: 1, - canceled: 1, - commitData: 1, - commitFrom: 1, - commitTo: 1, - error: 1, - method: 1, - project: 1, - rejected: 1, - repo: 1, - repoName: 1, - timepstamp: 1, - type: 1, - url: 1, - }, - }) - .toArray(); -}; - -const getPush = async (id) => { - const collection = await connect(cnName); - const doc = await collection.findOne({ id: id }); - - if (doc) { - return toClass(doc, Action.prototype); - } - - return null; -}; - -const writeAudit = async (action) => { - const data = JSON.parse(JSON.stringify(action)); - const options = { upsert: true }; - const collection = await connect(cnName); - delete data._id; - await collection.updateOne({ id: data.id }, { $set: data }, options); - return action; -}; - -const authorise = async (id, attestation) => { - const action = await getPush(id); - action.authorised = true; - action.canceled = false; - action.rejected = false; - action.attestation = attestation; - await writeAudit(action); - return { message: `authorised ${id}` }; -}; - -const reject = async (id) => { - const action = await getPush(id); - action.authorised = false; - action.canceled = false; - action.rejected = true; - await writeAudit(action); - return { message: `reject ${id}` }; -}; - -const cancel = async (id) => { - const action = await getPush(id); - action.authorised = false; - action.canceled = true; - action.rejected = false; - await writeAudit(action); - return { message: `canceled ${id}` }; -}; - -const canUserApproveRejectPush = async (id, user) => { - return new Promise(async (resolve) => { - const action = await getPush(id); - const repoName = action.repoName.replace('.git', ''); - const isAllowed = await repo.canUserApproveRejectPushRepo(repoName, user); - - resolve(isAllowed); - }); -}; - -const canUserCancelPush = async (id, user) => { - return new Promise(async (resolve) => { - const pushDetail = await getPush(id); - const repoName = pushDetail.repoName.replace('.git', ''); - const isAllowed = await repo.isUserPushAllowed(repoName, user); - - if (isAllowed) { - resolve(true); - } else { - resolve(false); - } - }); -}; - -module.exports.getPushes = getPushes; -module.exports.writeAudit = writeAudit; -module.exports.getPush = getPush; -module.exports.authorise = authorise; -module.exports.reject = reject; -module.exports.cancel = cancel; -module.exports.canUserApproveRejectPush = canUserApproveRejectPush; -module.exports.canUserCancelPush = canUserCancelPush; diff --git a/src/db/mongo/pushes.ts b/src/db/mongo/pushes.ts new file mode 100644 index 000000000..519fc68bb --- /dev/null +++ b/src/db/mongo/pushes.ts @@ -0,0 +1,129 @@ +import { connect, findDocuments, findOneDocument } from './helper'; +import { Action } from '../../proxy/actions'; +import { toClass } from '../helper'; +import * as repo from './repo'; +import { Push, PushQuery } from '../types'; + +const collectionName = 'pushes'; + +const defaultPushQuery: PushQuery = { + error: false, + blocked: true, + allowPush: false, + authorised: false, +}; + +export const getPushes = async ( + query: PushQuery = defaultPushQuery +): Promise => { + return findDocuments(collectionName, query, { + projection: { + _id: 0, + id: 1, + allowPush: 1, + authorised: 1, + blocked: 1, + blockedMessage: 1, + branch: 1, + canceled: 1, + commitData: 1, + commitFrom: 1, + commitTo: 1, + error: 1, + method: 1, + project: 1, + rejected: 1, + repo: 1, + repoName: 1, + timepstamp: 1, + type: 1, + url: 1, + }, + }); +}; + +export const getPush = async (id: string): Promise => { + const doc = await findOneDocument(collectionName, { id }); + return doc ? toClass(doc, Action.prototype) as Action : null; +}; + +export const writeAudit = async (action: Action): Promise => { + const data = JSON.parse(JSON.stringify(action)); + const options = { upsert: true }; + const collection = await connect(collectionName); + delete data._id; + await collection.updateOne({ id: data.id }, { $set: data }, options); + return action; +}; + +export const authorise = async (id: string, attestation: any) => { + const action = await getPush(id); + if (!action) { + throw new Error(`push ${id} not found`); + } + + action.authorised = true; + action.canceled = false; + action.rejected = false; + action.attestation = attestation; + await writeAudit(action); + return { message: `authorised ${id}` }; +}; + +export const reject = async (id: string) => { + const action = await getPush(id); + if (!action) { + throw new Error(`push ${id} not found`); + } + action.authorised = false; + action.canceled = false; + action.rejected = true; + await writeAudit(action); + return { message: `reject ${id}` }; +}; + +export const cancel = async (id: string) => { + const action = await getPush(id); + if (!action) { + throw new Error(`push ${id} not found`); + } + action.authorised = false; + action.canceled = true; + action.rejected = false; + await writeAudit(action); + return { message: `canceled ${id}` }; +}; + +export const canUserApproveRejectPush = async (id: string, user: string) => { + return new Promise(async (resolve) => { + const action = await getPush(id); + if (!action) { + resolve(false); + return; + } + + const repoName = action.repoName.replace('.git', ''); + const isAllowed = await repo.canUserApproveRejectPushRepo(repoName, user); + + resolve(isAllowed); + }); +}; + +export const canUserCancelPush = async (id: string, user: string) => { + return new Promise(async (resolve) => { + const pushDetail = await getPush(id); + if (!pushDetail) { + resolve(false); + return; + } + + const repoName = pushDetail.repoName.replace('.git', ''); + const isAllowed = await repo.isUserPushAllowed(repoName, user); + + if (isAllowed) { + resolve(true); + } else { + resolve(false); + } + }); +}; diff --git a/src/db/mongo/repo.js b/src/db/mongo/repo.ts similarity index 63% rename from src/db/mongo/repo.js rename to src/db/mongo/repo.ts index 1c604069e..866db315f 100644 --- a/src/db/mongo/repo.js +++ b/src/db/mongo/repo.ts @@ -1,21 +1,23 @@ +import { Repo } from "../types"; + const connect = require('./helper').connect; -const cnName = 'repos'; +const collectionName = 'repos'; -const isBlank = (str) => { +const isBlank = (str: string) => { return !str || /^\s*$/.test(str); }; -exports.getRepos = async (query = {}) => { - const collection = await connect(cnName); +export const getRepos = async (query = {}) => { + const collection = await connect(collectionName); return collection.find().toArray(); }; -exports.getRepo = async (name) => { - const collection = await connect(cnName); +export const getRepo = async (name: string) => { + const collection = await connect(collectionName); return collection.findOne({ name: { $eq: name } }); }; -exports.createRepo = async (repo) => { +export const createRepo = async (repo: Repo) => { console.log(`creating new repo ${JSON.stringify(repo)}`); if (isBlank(repo.project)) { @@ -33,41 +35,41 @@ exports.createRepo = async (repo) => { canAuthorise: [], }; - const collection = await connect(cnName); + const collection = await connect(collectionName); await collection.insertOne(repo); console.log(`created new repo ${JSON.stringify(repo)}`); }; -exports.addUserCanPush = async (name, user) => { +export const addUserCanPush = async (name: string, user: string) => { name = name.toLowerCase(); - const collection = await connect(cnName); + const collection = await connect(collectionName); await collection.updateOne({ name: name }, { $push: { 'users.canPush': user } }); }; -exports.addUserCanAuthorise = async (name, user) => { +export const addUserCanAuthorise = async (name: string, user: string) => { name = name.toLowerCase(); - const collection = await connect(cnName); + const collection = await connect(collectionName); await collection.updateOne({ name: name }, { $push: { 'users.canAuthorise': user } }); }; -exports.removeUserCanPush = async (name, user) => { +export const removeUserCanPush = async (name: string, user: string) => { name = name.toLowerCase(); - const collection = await connect(cnName); + const collection = await connect(collectionName); await collection.updateOne({ name: name }, { $pull: { 'users.canPush': user } }); }; -exports.removeUserCanAuthorise = async (name, user) => { +export const removeUserCanAuthorise = async (name: string, user: string) => { name = name.toLowerCase(); - const collection = await connect(cnName); + const collection = await connect(collectionName); await collection.updateOne({ name: name }, { $pull: { 'users.canAuthorise': user } }); }; -exports.deleteRepo = async (name) => { - const collection = await connect(cnName); +export const deleteRepo = async (name: string) => { + const collection = await connect(collectionName); await collection.deleteMany({ name: name }); }; -exports.isUserPushAllowed = async (name, user) => { +export const isUserPushAllowed = async (name: string, user: string) => { name = name.toLowerCase(); return new Promise(async (resolve, reject) => { const repo = await exports.getRepo(name); @@ -82,7 +84,7 @@ exports.isUserPushAllowed = async (name, user) => { }); }; -exports.canUserApproveRejectPushRepo = async (name, user) => { +export const canUserApproveRejectPushRepo = async (name: string, user: string) => { name = name.toLowerCase(); console.log(`checking if user ${user} can approve/reject for ${name}`); return new Promise(async (resolve, reject) => { diff --git a/src/db/mongo/users.js b/src/db/mongo/users.js deleted file mode 100644 index c93977694..000000000 --- a/src/db/mongo/users.js +++ /dev/null @@ -1,31 +0,0 @@ -const connect = require('./helper').connect; -const usersCollection = 'users'; - -exports.findUser = async function (username) { - const collection = await connect(usersCollection); - return collection.findOne({ username: { $eq: username } }); -}; - -exports.getUsers = async function (query) { - console.log(`Getting users for query= ${JSON.stringify(query)}`); - const collection = await connect(usersCollection); - return collection.find(query, { password: 0 }).toArray(); -}; - -exports.deleteUser = async function (username) { - const collection = await connect(usersCollection); - return collection.deleteOne({ username: username }); -}; - -exports.createUser = async function (data) { - data.username = data.username.toLowerCase(); - const collection = await connect(usersCollection); - return collection.insertOne(data); -}; - -exports.updateUser = async (user) => { - user.username = user.username.toLowerCase(); - const options = { upsert: true }; - const collection = await connect(usersCollection); - await collection.updateOne({ username: user.username }, { $set: user }, options); -}; diff --git a/src/db/mongo/users.ts b/src/db/mongo/users.ts new file mode 100644 index 000000000..388527777 --- /dev/null +++ b/src/db/mongo/users.ts @@ -0,0 +1,33 @@ +import { User } from "../types"; + +const connect = require('./helper').connect; +const collectionName = 'users'; + +export const findUser = async function (username: string) { + const collection = await connect(collectionName); + return collection.findOne({ username: { $eq: username } }); +}; + +export const getUsers = async function (query: string) { + console.log(`Getting users for query= ${JSON.stringify(query)}`); + const collection = await connect(collectionName); + return collection.find(query, { password: 0 }).toArray(); +}; + +export const deleteUser = async function (username: string) { + const collection = await connect(collectionName); + return collection.deleteOne({ username: username }); +}; + +export const createUser = async function (user: User) { + user.username = user.username.toLowerCase(); + const collection = await connect(collectionName); + return collection.insertOne(user); +}; + +export const updateUser = async (user: User) => { + user.username = user.username.toLowerCase(); + const options = { upsert: true }; + const collection = await connect(collectionName); + await collection.updateOne({ username: user.username }, { $set: user }, options); +}; From b1abc41f01c3cb0b8c37c0b110a68a4c283ca466 Mon Sep 17 00:00:00 2001 From: Juan Escalada Date: Mon, 24 Feb 2025 16:12:07 +0900 Subject: [PATCH 04/13] refactor(ts): change db module to use TS and ESM --- src/db/{helper.js => helper.ts} | 4 +- src/db/index.js | 75 ------------------------------ src/db/index.ts | 81 +++++++++++++++++++++++++++++++++ src/db/types.ts | 48 +++++++++++++++++++ 4 files changed, 130 insertions(+), 78 deletions(-) rename src/db/{helper.js => helper.ts} (52%) delete mode 100644 src/db/index.js create mode 100644 src/db/index.ts create mode 100644 src/db/types.ts diff --git a/src/db/helper.js b/src/db/helper.ts similarity index 52% rename from src/db/helper.js rename to src/db/helper.ts index 8faa636e7..55c5aca0b 100644 --- a/src/db/helper.js +++ b/src/db/helper.ts @@ -1,7 +1,5 @@ -const toClass = function (obj, proto) { +export const toClass = function (obj: any, proto: any) { obj = JSON.parse(JSON.stringify(obj)); obj.__proto__ = proto; return obj; }; - -module.exports.toClass = toClass; diff --git a/src/db/index.js b/src/db/index.js deleted file mode 100644 index e685279f5..000000000 --- a/src/db/index.js +++ /dev/null @@ -1,75 +0,0 @@ -const bcrypt = require('bcryptjs'); -const config = require('../config'); -let sink; -if (config.getDatabase().type === 'mongo') { - sink = require('../db/mongo'); -} else if (config.getDatabase().type === 'fs') { - sink = require('../db/file'); -} - -module.exports.createUser = async (username, password, email, gitAccount, admin = false) => { - console.log( - `creating user - user=${username}, - gitAccount=${gitAccount} - email=${email}, - admin=${admin}`, - ); - - const data = { - username: username, - password: await bcrypt.hash(password, 10), - gitAccount: gitAccount, - email: email, - admin: admin, - }; - - if (username === undefined || username === null || username === '') { - const errorMessage = `username ${username} cannot be empty`; - throw new Error(errorMessage); - } - - if (gitAccount === undefined || gitAccount === null || gitAccount === '') { - const errorMessage = `GitAccount ${gitAccount} cannot be empty`; - throw new Error(errorMessage); - } - - if (email === undefined || email === null || email === '') { - const errorMessage = `Email ${email} cannot be empty`; - throw new Error(errorMessage); - } - const existingUser = await sink.findUser(username); - - if (existingUser) { - const errorMessage = `user ${username} already exists`; - throw new Error(errorMessage); - } - - await sink.createUser(data); -}; - -// The module exports -module.exports.authorise = sink.authorise; -module.exports.reject = sink.reject; -module.exports.cancel = sink.cancel; -module.exports.getPushes = sink.getPushes; -module.exports.writeAudit = sink.writeAudit; -module.exports.getPush = sink.getPush; -module.exports.findUser = sink.findUser; -module.exports.getUsers = sink.getUsers; -module.exports.deleteUser = sink.deleteUser; -module.exports.updateUser = sink.updateUser; -module.exports.getRepos = sink.getRepos; -module.exports.getRepo = sink.getRepo; -module.exports.createRepo = sink.createRepo; -module.exports.addUserCanPush = sink.addUserCanPush; -module.exports.addUserCanAuthorise = sink.addUserCanAuthorise; -module.exports.removeUserCanAuthorise = sink.removeUserCanAuthorise; -module.exports.removeUserCanPush = sink.removeUserCanPush; - -module.exports.deleteRepo = sink.deleteRepo; -module.exports.isUserPushAllowed = sink.isUserPushAllowed; -module.exports.canUserApproveRejectPushRepo = sink.canUserApproveRejectPushRepo; -module.exports.canUserApproveRejectPush = sink.canUserApproveRejectPush; -module.exports.canUserCancelPush = sink.canUserCancelPush; -module.exports.getSessionStore = sink.getSessionStore; diff --git a/src/db/index.ts b/src/db/index.ts new file mode 100644 index 000000000..e5118f714 --- /dev/null +++ b/src/db/index.ts @@ -0,0 +1,81 @@ +const bcrypt = require('bcryptjs'); +const config = require('../config'); +let sink: any; +if (config.getDatabase().type === 'mongo') { + sink = require('./mongo'); +} else if (config.getDatabase().type === 'fs') { + sink = require('./file'); +} + +export const createUser = async ( + username: string, + password: string, + email: string, + gitAccount: string, + admin: boolean = false +) => { + console.log( + `creating user + user=${username}, + gitAccount=${gitAccount} + email=${email}, + admin=${admin}`, + ); + + const data = { + username: username, + password: await bcrypt.hash(password, 10), + gitAccount: gitAccount, + email: email, + admin: admin, + }; + + if (username === undefined || username === null || username === '') { + const errorMessage = `username ${username} cannot be empty`; + throw new Error(errorMessage); + } + + if (gitAccount === undefined || gitAccount === null || gitAccount === '') { + const errorMessage = `GitAccount ${gitAccount} cannot be empty`; + throw new Error(errorMessage); + } + + if (email === undefined || email === null || email === '') { + const errorMessage = `Email ${email} cannot be empty`; + throw new Error(errorMessage); + } + const existingUser = await sink.findUser(username); + + if (existingUser) { + const errorMessage = `user ${username} already exists`; + throw new Error(errorMessage); + } + + await sink.createUser(data); +}; + +export const { + authorise, + reject, + cancel, + getPushes, + writeAudit, + getPush, + findUser, + getUsers, + deleteUser, + updateUser, + getRepos, + getRepo, + createRepo, + addUserCanPush, + addUserCanAuthorise, + removeUserCanAuthorise, + removeUserCanPush, + deleteRepo, + isUserPushAllowed, + canUserApproveRejectPushRepo, + canUserApproveRejectPush, + canUserCancelPush, + getSessionStore, +} = sink; diff --git a/src/db/types.ts b/src/db/types.ts new file mode 100644 index 000000000..dba9bdf3a --- /dev/null +++ b/src/db/types.ts @@ -0,0 +1,48 @@ +export type PushQuery = { + error: boolean; + blocked: boolean, + allowPush: boolean, + authorised: boolean +}; + +export type UserRole = 'canPush' | 'canAuthorise'; + +export type Repo = { + project: string; + name: string; + url: string; + users: Record; + _id: string; +}; + +export type User = { + _id: string; + username: string; + password: string | null; // null if oidcId is set + gitAccount: string; + email: string; + admin: boolean; + oidcId: string | null; +}; + +export type Push = { + id: string; + allowPush: boolean; + authorised: boolean; + blocked: boolean; + blockedMessage: string; + branch: string; + canceled: boolean; + commitData: object; + commitFrom: string; + commitTo: string; + error: boolean; + method: string; + project: string; + rejected: boolean; + repo: string; + repoName: string; + timepstamp: string; + type: string; + url: string; +}; From 91e8a4f6aff15943bc1dee42abb171b57b9aee56 Mon Sep 17 00:00:00 2001 From: Juan Escalada Date: Mon, 24 Feb 2025 16:17:52 +0900 Subject: [PATCH 05/13] refactor(ts): add missing type defs and config for ts --- .mocharc.json | 8 ++++++++ package-lock.json | 26 +++++++++++++++++++++----- package.json | 6 ++++-- tsconfig.json | 4 +++- 4 files changed, 36 insertions(+), 8 deletions(-) create mode 100644 .mocharc.json diff --git a/.mocharc.json b/.mocharc.json new file mode 100644 index 000000000..07a8828f6 --- /dev/null +++ b/.mocharc.json @@ -0,0 +1,8 @@ +{ + "require": [ + "ts-node/register" + ], + "loader": "ts-node/esm", + "exit": true, + "experimental-print-required-tla": true +} diff --git a/package-lock.json b/package-lock.json index db4c5a143..18b2a6164 100644 --- a/package-lock.json +++ b/package-lock.json @@ -62,7 +62,9 @@ "@babel/preset-react": "^7.22.5", "@commitlint/cli": "^19.0.0", "@commitlint/config-conventional": "^19.0.0", - "@types/node": "^22.13.4", + "@types/lodash": "^4.17.15", + "@types/mocha": "^10.0.10", + "@types/node": "^22.13.5", "@types/yargs": "^17.0.33", "@vitejs/plugin-react": "^4.0.2", "chai": "^4.2.0", @@ -76,7 +78,7 @@ "eslint-plugin-react": "^7.21.5", "eslint-plugin-standard": "^5.0.0", "husky": "^9.0.0", - "mocha": "^10.2.0", + "mocha": "^10.8.2", "nyc": "^17.0.0", "prettier": "^3.0.0", "sinon": "^19.0.2", @@ -3611,10 +3613,24 @@ "integrity": "sha512-he+DHOWReW0nghN24E1WUqM0efK4kI9oTqDm6XmK8ZPe2djZ90BSNdGnIyCLzCPw7/pogPlGbzI2wHGGmi4O/Q==", "dev": true }, + "node_modules/@types/lodash": { + "version": "4.17.15", + "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.17.15.tgz", + "integrity": "sha512-w/P33JFeySuhN6JLkysYUK2gEmy9kHHFN7E8ro0tkfmlDOgxBDzWEZ/J8cWA+fHqFevpswDTFZnDx+R9lbL6xw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/mocha": { + "version": "10.0.10", + "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-10.0.10.tgz", + "integrity": "sha512-xPyYSz1cMPnJQhl0CLMH68j3gprKZaTjG3s5Vi+fDgx+uhG9NOXwbVt52eFS8ECyXhyKcjDLCBEqBExKuiZb7Q==", + "dev": true, + "license": "MIT" + }, "node_modules/@types/node": { - "version": "22.13.4", - "resolved": "https://registry.npmjs.org/@types/node/-/node-22.13.4.tgz", - "integrity": "sha512-ywP2X0DYtX3y08eFVx5fNIw7/uIv8hYUKgXoK8oayJlLnKcRfEYCxWMVE1XagUdVtCJlZT1AU4LXEABW+L1Peg==", + "version": "22.13.5", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.13.5.tgz", + "integrity": "sha512-+lTU0PxZXn0Dr1NBtC7Y8cR21AJr87dLLU953CWA6pMxxv/UDc7jYAY90upcrie1nRcD6XNG5HOYEDtgW5TxAg==", "license": "MIT", "dependencies": { "undici-types": "~6.20.0" diff --git a/package.json b/package.json index 5b9ce86e8..5b33d5aa7 100644 --- a/package.json +++ b/package.json @@ -80,7 +80,9 @@ "@babel/preset-react": "^7.22.5", "@commitlint/cli": "^19.0.0", "@commitlint/config-conventional": "^19.0.0", - "@types/node": "^22.13.4", + "@types/lodash": "^4.17.15", + "@types/mocha": "^10.0.10", + "@types/node": "^22.13.5", "@types/yargs": "^17.0.33", "@vitejs/plugin-react": "^4.0.2", "chai": "^4.2.0", @@ -94,7 +96,7 @@ "eslint-plugin-react": "^7.21.5", "eslint-plugin-standard": "^5.0.0", "husky": "^9.0.0", - "mocha": "^10.2.0", + "mocha": "^10.8.2", "nyc": "^17.0.0", "prettier": "^3.0.0", "sinon": "^19.0.2", diff --git a/tsconfig.json b/tsconfig.json index b3353bd12..9b7b30543 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -10,7 +10,9 @@ "noEmit": true, "skipLibCheck": true, "isolatedModules": true, - "esModuleInterop": true + "module": "CommonJS", + "esModuleInterop": true, + "allowSyntheticDefaultImports": true }, "include": ["src"] } From 33c27a18b0be8e69e8e06a01eb847f6a980bd82c Mon Sep 17 00:00:00 2001 From: Juan Escalada Date: Mon, 3 Mar 2025 14:42:38 +0900 Subject: [PATCH 06/13] refactor(ts): change config module to use TS and ESM --- src/config/env.js | 3 - src/config/env.ts | 20 ++++++ src/config/file.js | 32 --------- src/config/file.ts | 27 +++++++ src/config/{index.js => index.ts} | 112 +++++++++++++----------------- src/config/types.ts | 45 ++++++++++++ 6 files changed, 139 insertions(+), 100 deletions(-) delete mode 100644 src/config/env.js create mode 100644 src/config/env.ts delete mode 100644 src/config/file.js create mode 100644 src/config/file.ts rename src/config/{index.js => index.ts} (57%) create mode 100644 src/config/types.ts diff --git a/src/config/env.js b/src/config/env.js deleted file mode 100644 index 709f8bbb4..000000000 --- a/src/config/env.js +++ /dev/null @@ -1,3 +0,0 @@ -const { GIT_PROXY_SERVER_PORT = 8000, GIT_PROXY_HTTPS_SERVER_PORT = 8443, GIT_PROXY_UI_PORT = 8080 } = process.env; - -exports.Vars = { GIT_PROXY_SERVER_PORT, GIT_PROXY_HTTPS_SERVER_PORT, GIT_PROXY_UI_PORT }; diff --git a/src/config/env.ts b/src/config/env.ts new file mode 100644 index 000000000..85b8475b5 --- /dev/null +++ b/src/config/env.ts @@ -0,0 +1,20 @@ +export type ServerConfig = { + GIT_PROXY_SERVER_PORT: string | number; + GIT_PROXY_HTTPS_SERVER_PORT: string | number; + GIT_PROXY_UI_HOST: string; + GIT_PROXY_UI_PORT: string | number; +}; + +const { + GIT_PROXY_SERVER_PORT = 8000, + GIT_PROXY_HTTPS_SERVER_PORT = 8443, + GIT_PROXY_UI_HOST = 'http://localhost', + GIT_PROXY_UI_PORT = 8080 +} = process.env; + +export const serverConfig: ServerConfig = { + GIT_PROXY_SERVER_PORT, + GIT_PROXY_HTTPS_SERVER_PORT, + GIT_PROXY_UI_HOST, + GIT_PROXY_UI_PORT +}; diff --git a/src/config/file.js b/src/config/file.js deleted file mode 100644 index 1cc99abb1..000000000 --- a/src/config/file.js +++ /dev/null @@ -1,32 +0,0 @@ -const path = require('path'); -// eslint-disable-next-line prefer-const -let configFile = undefined; - -/** - * Validate config file. - * @param {string} configFilePath - The path to the config file. - * @return {boolean} - Returns true if validation is successful. - * @throws Will throw an error if the validation fails. - */ -function validate(configFilePath = configFile) { - const fs = require('fs'); - const path = require('path'); - const validate = require('jsonschema').validate; - - const config = JSON.parse(fs.readFileSync(configFilePath)); - const schema = JSON.parse( - fs.readFileSync(path.join(__dirname, '..', '..', 'config.schema.json')), - ); - validate(config, schema, { required: true, throwError: true }); - return true; -} - -module.exports = { - get configFile() { - return configFile ? configFile : path.join(process.cwd(), 'proxy.config.json'); - }, - set configFile(file) { - configFile = file; - }, - validate, -}; diff --git a/src/config/file.ts b/src/config/file.ts new file mode 100644 index 000000000..e7aadcd46 --- /dev/null +++ b/src/config/file.ts @@ -0,0 +1,27 @@ +import { readFileSync } from 'fs'; +import { join } from 'path'; +import { validate as jsonSchemaValidate } from 'jsonschema'; + +export let configFile: string = join(process.cwd(), 'proxy.config.json'); + +/** + * Set the config file path. + * @param {string} file - The path to the config file. + */ +export function setConfigFile(file: string) { + configFile = file; +} + +/** + * Validate config file. + * @param {string} configFilePath - The path to the config file. + * @return {boolean} - Returns true if validation is successful. + * @throws Will throw an error if the validation fails. + */ +export function validate(configFilePath: string = configFile!): boolean { + const config = JSON.parse(readFileSync(configFilePath, 'utf-8')); + const schemaPath = join(process.cwd(), 'config.schema.json'); + const schema = JSON.parse(readFileSync(schemaPath, 'utf-8')); + jsonSchemaValidate(config, schema, { required: true, throwError: true }); + return true; +} diff --git a/src/config/index.js b/src/config/index.ts similarity index 57% rename from src/config/index.js rename to src/config/index.ts index 78184d413..cc0c1d182 100644 --- a/src/config/index.js +++ b/src/config/index.ts @@ -1,33 +1,36 @@ -const fs = require('fs'); +import { existsSync, readFileSync } from 'fs'; -const defaultSettings = require('../../proxy.config.json'); -const userSettingsPath = require('./file').configFile; +import defaultSettings from '../../proxy.config.json'; +import { configFile } from './file'; +import { Authentication, AuthorisedRepo, Database, TempPasswordConfig, UserSettings } from './types'; -let _userSettings = null; -if (fs.existsSync(userSettingsPath)) { - _userSettings = JSON.parse(fs.readFileSync(userSettingsPath)); + +let _userSettings: UserSettings | null = null; +if (existsSync(configFile)) { + _userSettings = JSON.parse(readFileSync(configFile, 'utf-8')); } -let _authorisedList = defaultSettings.authorisedList; -let _database = defaultSettings.sink; -let _authentication = defaultSettings.authentication; -let _tempPassword = defaultSettings.tempPassword; +let _authorisedList: AuthorisedRepo[] = defaultSettings.authorisedList; +let _database: Database[] = defaultSettings.sink; +let _authentication: Authentication[] = defaultSettings.authentication; +let _tempPassword: TempPasswordConfig = defaultSettings.tempPassword; let _proxyUrl = defaultSettings.proxyUrl; -let _api = defaultSettings.api; -let _cookieSecret = defaultSettings.cookieSecret; -let _sessionMaxAgeHours = defaultSettings.sessionMaxAgeHours; -let _sslKeyPath = defaultSettings.sslKeyPemPath; -let _sslCertPath = defaultSettings.sslCertPemPath; -let _plugins = defaultSettings.plugins; -let _commitConfig = defaultSettings.commitConfig; -let _attestationConfig = defaultSettings.attestationConfig; -let _privateOrganizations = defaultSettings.privateOrganizations; -let _urlShortener = defaultSettings.urlShortener; -let _contactEmail = defaultSettings.contactEmail; -let _csrfProtection = defaultSettings.csrfProtection; -let _domains = defaultSettings.domains; +let _api: Record = defaultSettings.api; +let _cookieSecret: string = defaultSettings.cookieSecret; +let _sessionMaxAgeHours: number = defaultSettings.sessionMaxAgeHours; +let _plugins: any[] = defaultSettings.plugins; +let _commitConfig: Record = defaultSettings.commitConfig; +let _attestationConfig: Record = defaultSettings.attestationConfig; +let _privateOrganizations: string[] = defaultSettings.privateOrganizations; +let _urlShortener: string = defaultSettings.urlShortener; +let _contactEmail: string = defaultSettings.contactEmail; +let _csrfProtection: boolean = defaultSettings.csrfProtection; +let _domains: Record = defaultSettings.domains; +// These are not always present in the default config file, so casting is required +let _sslKeyPath: string = (defaultSettings as any).sslKeyPemPath; +let _sslCertPath: string = (defaultSettings as any).sslCertPemPath; // Get configured proxy URL -const getProxyUrl = () => { +export const getProxyUrl = () => { if (_userSettings !== null && _userSettings.proxyUrl) { _proxyUrl = _userSettings.proxyUrl; } @@ -36,16 +39,15 @@ const getProxyUrl = () => { }; // Gets a list of authorised repositories -const getAuthorisedList = () => { +export const getAuthorisedList = () => { if (_userSettings !== null && _userSettings.authorisedList) { _authorisedList = _userSettings.authorisedList; } - return _authorisedList; }; // Gets a list of authorised repositories -const getTempPasswordConfig = () => { +export const getTempPasswordConfig = () => { if (_userSettings !== null && _userSettings.tempPassword) { _tempPassword = _userSettings.tempPassword; } @@ -53,8 +55,8 @@ const getTempPasswordConfig = () => { return _tempPassword; }; -// Gets the configuared data sink, defaults to filesystem -const getDatabase = () => { +// Gets the configured data sink, defaults to filesystem +export const getDatabase = () => { if (_userSettings !== null && _userSettings.sink) { _database = _userSettings.sink; } @@ -70,8 +72,8 @@ const getDatabase = () => { throw Error('No database cofigured!'); }; -// Gets the configuared data sink, defaults to filesystem -const getAuthentication = () => { +// Gets the configured authentication method, defaults to local +export const getAuthentication = () => { if (_userSettings !== null && _userSettings.authentication) { _authentication = _userSettings.authentication; } @@ -87,27 +89,27 @@ const getAuthentication = () => { }; // Log configuration to console -const logConfiguration = () => { +export const logConfiguration = () => { console.log(`authorisedList = ${JSON.stringify(getAuthorisedList())}`); console.log(`data sink = ${JSON.stringify(getDatabase())}`); console.log(`authentication = ${JSON.stringify(getAuthentication())}`); }; -const getAPIs = () => { +export const getAPIs = () => { if (_userSettings && _userSettings.api) { _api = _userSettings.api; } return _api; }; -const getCookieSecret = () => { +export const getCookieSecret = () => { if (_userSettings && _userSettings.cookieSecret) { _cookieSecret = _userSettings.cookieSecret; } return _cookieSecret; }; -const getSessionMaxAgeHours = () => { +export const getSessionMaxAgeHours = () => { if (_userSettings && _userSettings.sessionMaxAgeHours) { _sessionMaxAgeHours = _userSettings.sessionMaxAgeHours; } @@ -115,7 +117,7 @@ const getSessionMaxAgeHours = () => { }; // Get commit related configuration -const getCommitConfig = () => { +export const getCommitConfig = () => { if (_userSettings && _userSettings.commitConfig) { _commitConfig = _userSettings.commitConfig; } @@ -123,7 +125,7 @@ const getCommitConfig = () => { }; // Get attestation related configuration -const getAttestationConfig = () => { +export const getAttestationConfig = () => { if (_userSettings && _userSettings.attestationConfig) { _attestationConfig = _userSettings.attestationConfig; } @@ -131,7 +133,7 @@ const getAttestationConfig = () => { }; // Get private organizations related configuration -const getPrivateOrganizations = () => { +export const getPrivateOrganizations = () => { if (_userSettings && _userSettings.privateOrganizations) { _privateOrganizations = _userSettings.privateOrganizations; } @@ -139,7 +141,7 @@ const getPrivateOrganizations = () => { }; // Get URL shortener -const getURLShortener = () => { +export const getURLShortener = () => { if (_userSettings && _userSettings.urlShortener) { _urlShortener = _userSettings.urlShortener; } @@ -147,7 +149,7 @@ const getURLShortener = () => { }; // Get contact e-mail address -const getContactEmail = () => { +export const getContactEmail = () => { if (_userSettings && _userSettings.contactEmail) { _contactEmail = _userSettings.contactEmail; } @@ -155,7 +157,7 @@ const getContactEmail = () => { }; // Get CSRF protection flag -const getCSRFProtection = () => { +export const getCSRFProtection = () => { if (_userSettings && _userSettings.csrfProtection) { _csrfProtection = _userSettings.csrfProtection; } @@ -163,14 +165,14 @@ const getCSRFProtection = () => { }; // Get loadable push plugins -const getPlugins = () => { +export const getPlugins = () => { if (_userSettings && _userSettings.plugins) { _plugins = _userSettings.plugins; } return _plugins; } -const getSSLKeyPath = () => { +export const getSSLKeyPath = () => { if (_userSettings && _userSettings.sslKeyPemPath) { _sslKeyPath = _userSettings.sslKeyPemPath; } @@ -180,7 +182,7 @@ const getSSLKeyPath = () => { return _sslKeyPath; }; -const getSSLCertPath = () => { +export const getSSLCertPath = () => { if (_userSettings && _userSettings.sslCertPemPath) { _sslCertPath = _userSettings.sslCertPemPath; } @@ -190,29 +192,9 @@ const getSSLCertPath = () => { return _sslCertPath; }; -const getDomains = () => { +export const getDomains = () => { if (_userSettings && _userSettings.domains) { _domains = _userSettings.domains; } return _domains; }; - -exports.getAPIs = getAPIs; -exports.getProxyUrl = getProxyUrl; -exports.getAuthorisedList = getAuthorisedList; -exports.getDatabase = getDatabase; -exports.logConfiguration = logConfiguration; -exports.getAuthentication = getAuthentication; -exports.getTempPasswordConfig = getTempPasswordConfig; -exports.getCookieSecret = getCookieSecret; -exports.getSessionMaxAgeHours = getSessionMaxAgeHours; -exports.getCommitConfig = getCommitConfig; -exports.getAttestationConfig = getAttestationConfig; -exports.getPrivateOrganizations = getPrivateOrganizations; -exports.getURLShortener = getURLShortener; -exports.getContactEmail = getContactEmail; -exports.getCSRFProtection = getCSRFProtection; -exports.getPlugins = getPlugins; -exports.getSSLKeyPath = getSSLKeyPath; -exports.getSSLCertPath = getSSLCertPath; -exports.getDomains = getDomains; diff --git a/src/config/types.ts b/src/config/types.ts new file mode 100644 index 000000000..7364f6201 --- /dev/null +++ b/src/config/types.ts @@ -0,0 +1,45 @@ +export interface UserSettings { + authorisedList: AuthorisedRepo[]; + sink: Database[]; + authentication: Authentication[]; + tempPassword?: TempPasswordConfig; + proxyUrl: string; + api: Record; + cookieSecret: string; + sessionMaxAgeHours: number; + sslKeyPemPath?: string; // Optional (not in config.schema.json) + sslCertPemPath?: string; // Optional (not in config.schema.json) + plugins: any[]; + commitConfig: Record; + attestationConfig: Record; + privateOrganizations: any[]; + urlShortener: string; + contactEmail: string; + csrfProtection: boolean; + domains: Record; +} + +export interface AuthorisedRepo { + project: string; + name: string; + url: string; +} + +export interface Database { + type: string; + enabled: boolean; + connectionString?: string; + params?: Record; + options?: Record; +} + +export interface Authentication { + type: string; + enabled: boolean; + options?: Record; +} + +export interface TempPasswordConfig { + sendEmail: boolean; + emailConfig: Record; +} From 1c7a6b1b4117d9aef3b0352160d335e6ebe64614 Mon Sep 17 00:00:00 2001 From: Juan Escalada Date: Mon, 3 Mar 2025 14:43:57 +0900 Subject: [PATCH 07/13] refactor(ts): refactor src/config imports --- index.ts | 14 +++++++------- packages/git-proxy-cli/index.js | 4 ++-- src/db/file/repo.ts | 1 - src/proxy/index.js | 4 ++-- src/service/index.js | 2 +- src/service/urls.js | 2 +- tsconfig.json | 3 ++- 7 files changed, 15 insertions(+), 15 deletions(-) diff --git a/index.ts b/index.ts index d52c76a7e..9df49c63e 100755 --- a/index.ts +++ b/index.ts @@ -3,7 +3,7 @@ import yargs from 'yargs'; import { hideBin } from 'yargs/helpers'; import * as fs from 'fs'; -import config from './src/config/file'; +import { configFile, setConfigFile, validate } from './src/config/file'; import proxy from './src/proxy'; import service from './src/service'; @@ -28,22 +28,22 @@ const argv = yargs(hideBin(process.argv)) .strict() .parseSync(); -config.configFile = argv.c ? argv.c : undefined; +setConfigFile(argv.c as string || ""); if (argv.v) { - if (!fs.existsSync(config.configFile as string)) { + if (!fs.existsSync(configFile)) { console.error( - `Config file ${config.configFile} doesn't exist, nothing to validate! Did you forget -c/--config?`, + `Config file ${configFile} doesn't exist, nothing to validate! Did you forget -c/--config?`, ); process.exit(1); } - config.validate(); - console.log(`${config.configFile} is valid`); + validate(); + console.log(`${configFile} is valid`); process.exit(0); } -config.validate(); +validate(); proxy.start(); service.start(); diff --git a/packages/git-proxy-cli/index.js b/packages/git-proxy-cli/index.js index e3c69ce8d..0ec0b788b 100755 --- a/packages/git-proxy-cli/index.js +++ b/packages/git-proxy-cli/index.js @@ -7,8 +7,8 @@ const util = require('util'); const GIT_PROXY_COOKIE_FILE = 'git-proxy-cookie'; // GitProxy UI HOST and PORT (configurable via environment variable) -const { GIT_PROXY_UI_HOST: uiHost = 'http://localhost' } = process.env; -const { GIT_PROXY_UI_PORT: uiPort } = require('@finos/git-proxy/src/config/env').Vars; +const { GIT_PROXY_UI_HOST: uiHost, GIT_PROXY_UI_PORT: uiPort } = + require('@finos/git-proxy/src/config/env').serverConfig; const baseUrl = `${uiHost}:${uiPort}`; axios.defaults.timeout = 30000; diff --git a/src/db/file/repo.ts b/src/db/file/repo.ts index 98efaaa9b..ea0c0cdd2 100644 --- a/src/db/file/repo.ts +++ b/src/db/file/repo.ts @@ -1,6 +1,5 @@ import fs from 'fs'; import Datastore from '@seald-io/nedb' -import { Action } from '../../proxy/actions/Action'; import { Repo } from '../types'; if (!fs.existsSync('./.data')) fs.mkdirSync('./.data'); diff --git a/src/proxy/index.js b/src/proxy/index.js index d4e8e3f93..3f5cb53e9 100644 --- a/src/proxy/index.js +++ b/src/proxy/index.js @@ -9,8 +9,8 @@ const config = require('../config'); const db = require('../db'); const { PluginLoader } = require('../plugin'); const chain = require('./chain'); -const { GIT_PROXY_SERVER_PORT: proxyHttpPort } = require('../config/env').Vars; -const { GIT_PROXY_HTTPS_SERVER_PORT: proxyHttpsPort } = require('../config/env').Vars; +const { GIT_PROXY_SERVER_PORT: proxyHttpPort, GIT_PROXY_HTTPS_SERVER_PORT: proxyHttpsPort } = + require('../config/env').serverConfig; const options = { inflate: true, diff --git a/src/service/index.js b/src/service/index.js index 39126a37c..d384fcd6e 100644 --- a/src/service/index.js +++ b/src/service/index.js @@ -14,7 +14,7 @@ const limiter = rateLimit({ max: 100, // limit each IP to 100 requests per windowMs }); -const { GIT_PROXY_UI_PORT: uiPort } = require('../config/env').Vars; +const { GIT_PROXY_UI_PORT: uiPort } = require('../config/env').serverConfig; const _httpServer = http.createServer(app); diff --git a/src/service/urls.js b/src/service/urls.js index 4e22a4327..2d1a60de9 100644 --- a/src/service/urls.js +++ b/src/service/urls.js @@ -1,5 +1,5 @@ const { GIT_PROXY_SERVER_PORT: PROXY_HTTP_PORT, GIT_PROXY_UI_PORT: UI_PORT } = - require('../config/env').Vars; + require('../config/env').serverConfig; const config = require('../config'); module.exports = { diff --git a/tsconfig.json b/tsconfig.json index 9b7b30543..805153d01 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -12,7 +12,8 @@ "isolatedModules": true, "module": "CommonJS", "esModuleInterop": true, - "allowSyntheticDefaultImports": true + "allowSyntheticDefaultImports": true, + "resolveJsonModule": true }, "include": ["src"] } From 9b6f674d233bc8af788874101ac8fa5e469e50d8 Mon Sep 17 00:00:00 2001 From: Juan Escalada Date: Mon, 3 Mar 2025 15:54:25 +0900 Subject: [PATCH 08/13] refactor(ts): update linter config for ts files --- .eslintrc.json | 11 +- package-lock.json | 331 +++++++++++++++++++++++++++++++++++++++++++++- package.json | 3 + 3 files changed, 339 insertions(+), 6 deletions(-) diff --git a/.eslintrc.json b/.eslintrc.json index f2d9db8eb..3006a8ddc 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -1,5 +1,5 @@ { - "parser": "@babel/eslint-parser", + "parser": "@typescript-eslint/parser", "env": { "node": true, "browser": true, @@ -9,6 +9,7 @@ }, "extends": [ "eslint:recommended", + "plugin:@typescript-eslint/recommended", "plugin:react/recommended", "google", "prettier", @@ -27,11 +28,15 @@ "presets": ["@babel/preset-react"] } }, - "plugins": ["react", "prettier"], + "plugins": ["@typescript-eslint", "react", "prettier"], "rules": { "react/prop-types": "off", "require-jsdoc": "off", - "no-async-promise-executor": "off" + "no-async-promise-executor": "off", + "@typescript-eslint/no-explicit-any": "off", // temporary until TS refactor is complete + "@typescript-eslint/no-unused-vars": "off", // temporary until TS refactor is complete + "@typescript-eslint/no-require-imports": "off", // prevents error on old "require" imports + "@typescript-eslint/no-unused-expressions": "off" // prevents error on test "expect" expressions }, "settings": { "react": { diff --git a/package-lock.json b/package-lock.json index 18b2a6164..8134cb196 100644 --- a/package-lock.json +++ b/package-lock.json @@ -25,6 +25,7 @@ "connect-mongo": "^5.1.0", "cors": "^2.8.5", "diff2html": "^3.4.33", + "eslint-plugin-typescript": "^0.14.0", "express": "^4.18.2", "express-http-proxy": "^2.0.0", "express-rate-limit": "^7.1.5", @@ -66,6 +67,8 @@ "@types/mocha": "^10.0.10", "@types/node": "^22.13.5", "@types/yargs": "^17.0.33", + "@typescript-eslint/eslint-plugin": "^8.25.0", + "@typescript-eslint/parser": "^8.25.0", "@vitejs/plugin-react": "^4.0.2", "chai": "^4.2.0", "chai-http": "^4.3.0", @@ -3732,6 +3735,238 @@ "@types/node": "*" } }, + "node_modules/@typescript-eslint/eslint-plugin": { + "version": "8.25.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.25.0.tgz", + "integrity": "sha512-VM7bpzAe7JO/BFf40pIT1lJqS/z1F8OaSsUB3rpFJucQA4cOSuH2RVVVkFULN+En0Djgr29/jb4EQnedUo95KA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/regexpp": "^4.10.0", + "@typescript-eslint/scope-manager": "8.25.0", + "@typescript-eslint/type-utils": "8.25.0", + "@typescript-eslint/utils": "8.25.0", + "@typescript-eslint/visitor-keys": "8.25.0", + "graphemer": "^1.4.0", + "ignore": "^5.3.1", + "natural-compare": "^1.4.0", + "ts-api-utils": "^2.0.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "@typescript-eslint/parser": "^8.0.0 || ^8.0.0-alpha.0", + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <5.8.0" + } + }, + "node_modules/@typescript-eslint/parser": { + "version": "8.25.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.25.0.tgz", + "integrity": "sha512-4gbs64bnbSzu4FpgMiQ1A+D+urxkoJk/kqlDJ2W//5SygaEiAP2B4GoS7TEdxgwol2el03gckFV9lJ4QOMiiHg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/scope-manager": "8.25.0", + "@typescript-eslint/types": "8.25.0", + "@typescript-eslint/typescript-estree": "8.25.0", + "@typescript-eslint/visitor-keys": "8.25.0", + "debug": "^4.3.4" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <5.8.0" + } + }, + "node_modules/@typescript-eslint/scope-manager": { + "version": "8.25.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.25.0.tgz", + "integrity": "sha512-6PPeiKIGbgStEyt4NNXa2ru5pMzQ8OYKO1hX1z53HMomrmiSB+R5FmChgQAP1ro8jMtNawz+TRQo/cSXrauTpg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.25.0", + "@typescript-eslint/visitor-keys": "8.25.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/type-utils": { + "version": "8.25.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.25.0.tgz", + "integrity": "sha512-d77dHgHWnxmXOPJuDWO4FDWADmGQkN5+tt6SFRZz/RtCWl4pHgFl3+WdYCn16+3teG09DY6XtEpf3gGD0a186g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/typescript-estree": "8.25.0", + "@typescript-eslint/utils": "8.25.0", + "debug": "^4.3.4", + "ts-api-utils": "^2.0.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <5.8.0" + } + }, + "node_modules/@typescript-eslint/types": { + "version": "8.25.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.25.0.tgz", + "integrity": "sha512-+vUe0Zb4tkNgznQwicsvLUJgZIRs6ITeWSCclX1q85pR1iOiaj+4uZJIUp//Z27QWu5Cseiw3O3AR8hVpax7Aw==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/typescript-estree": { + "version": "8.25.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.25.0.tgz", + "integrity": "sha512-ZPaiAKEZ6Blt/TPAx5Ot0EIB/yGtLI2EsGoY6F7XKklfMxYQyvtL+gT/UCqkMzO0BVFHLDlzvFqQzurYahxv9Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.25.0", + "@typescript-eslint/visitor-keys": "8.25.0", + "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": "^2.0.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <5.8.0" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/semver": { + "version": "7.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz", + "integrity": "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@typescript-eslint/utils": { + "version": "8.25.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.25.0.tgz", + "integrity": "sha512-syqRbrEv0J1wywiLsK60XzHnQe/kRViI3zwFALrNEgnntn1l24Ra2KvOAWwWbWZ1lBZxZljPDGOq967dsl6fkA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.4.0", + "@typescript-eslint/scope-manager": "8.25.0", + "@typescript-eslint/types": "8.25.0", + "@typescript-eslint/typescript-estree": "8.25.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <5.8.0" + } + }, + "node_modules/@typescript-eslint/visitor-keys": { + "version": "8.25.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.25.0.tgz", + "integrity": "sha512-kCYXKAum9CecGVHGij7muybDfTS2sD3t0L4bJsEZLkyrXUImiCTq1M3LG2SRtOhiHFwMR9wAFplpT6XHYjTkwQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.25.0", + "eslint-visitor-keys": "^4.2.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/visitor-keys/node_modules/eslint-visitor-keys": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.0.tgz", + "integrity": "sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, "node_modules/@ungap/structured-clone": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz", @@ -6270,6 +6505,19 @@ "eslint": ">=5.0.0" } }, + "node_modules/eslint-plugin-typescript": { + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-typescript/-/eslint-plugin-typescript-0.14.0.tgz", + "integrity": "sha512-2u1WnnDF2mkWWgU1lFQ2RjypUlmRoBEvQN02y9u+IL12mjWlkKFGEBnVsjs9Y8190bfPQCvWly1c2rYYUSOxWw==", + "deprecated": "Deprecated: Use @typescript-eslint/eslint-plugin instead", + "license": "MIT", + "dependencies": { + "requireindex": "~1.1.0" + }, + "engines": { + "node": ">=6" + } + }, "node_modules/eslint-scope": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", @@ -6723,6 +6971,36 @@ "integrity": "sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==", "dev": true }, + "node_modules/fast-glob": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz", + "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==", + "dev": true, + "license": "MIT", + "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.8" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fast-glob/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/fast-json-stable-stringify": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", @@ -7699,9 +7977,10 @@ ] }, "node_modules/ignore": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.0.tgz", - "integrity": "sha512-g7dmpshy+gD7mh88OC9NwSGTKoc3kyLAZQRU1mt53Aw/vnvfXnbC+F/7F7QoYVKbV+KNvJx8wArewKy1vXMtlg==", + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", + "license": "MIT", "engines": { "node": ">= 4" } @@ -9415,6 +9694,16 @@ "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", "dev": true }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, "node_modules/methods": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", @@ -9423,6 +9712,20 @@ "node": ">= 0.6" } }, + "node_modules/micromatch": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", + "dev": true, + "license": "MIT", + "dependencies": { + "braces": "^3.0.3", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, "node_modules/mime": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", @@ -11155,6 +11458,15 @@ "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==", "dev": true }, + "node_modules/requireindex": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/requireindex/-/requireindex-1.1.0.tgz", + "integrity": "sha512-LBnkqsDE7BZKvqylbmn7lTIVdpx4K/QCduRATpO5R+wtPmky/a8pN1bO2D6wXppn1497AJF9mNjqAXr6bdl9jg==", + "license": "MIT", + "engines": { + "node": ">=0.10.5" + } + }, "node_modules/resolve": { "version": "2.0.0-next.5", "resolved": "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.5.tgz", @@ -12364,6 +12676,19 @@ "tree-kill": "cli.js" } }, + "node_modules/ts-api-utils": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.0.1.tgz", + "integrity": "sha512-dnlgjFSVetynI8nzgJ+qF62efpglpWRk8isUEWZGWlJYySCTD6aKvbUDu+zbPeDakk3bg5H4XpitHukgfL1m9w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18.12" + }, + "peerDependencies": { + "typescript": ">=4.8.4" + } + }, "node_modules/ts-node": { "version": "10.9.2", "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz", diff --git a/package.json b/package.json index 5b33d5aa7..3e36841c7 100644 --- a/package.json +++ b/package.json @@ -47,6 +47,7 @@ "connect-mongo": "^5.1.0", "cors": "^2.8.5", "diff2html": "^3.4.33", + "eslint-plugin-typescript": "^0.14.0", "express": "^4.18.2", "express-http-proxy": "^2.0.0", "express-rate-limit": "^7.1.5", @@ -84,6 +85,8 @@ "@types/mocha": "^10.0.10", "@types/node": "^22.13.5", "@types/yargs": "^17.0.33", + "@typescript-eslint/eslint-plugin": "^8.25.0", + "@typescript-eslint/parser": "^8.25.0", "@vitejs/plugin-react": "^4.0.2", "chai": "^4.2.0", "chai-http": "^4.3.0", From fdf3f107ffd685bb74400cc96bbac162c1b1a402 Mon Sep 17 00:00:00 2001 From: Juan Escalada Date: Mon, 3 Mar 2025 15:59:42 +0900 Subject: [PATCH 09/13] chore(ts): add typescript and vite to ignored dependencies --- .github/workflows/unused-dependencies.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/unused-dependencies.yml b/.github/workflows/unused-dependencies.yml index e25beda72..bb0db7a31 100644 --- a/.github/workflows/unused-dependencies.yml +++ b/.github/workflows/unused-dependencies.yml @@ -16,7 +16,7 @@ jobs: node-version: '18.x' - name: 'Run depcheck' run: | - npx depcheck --skip-missing --ignores="@babel/*,@commitlint/*,eslint,eslint-*,husky,mocha,concurrently,nyc,prettier" + npx depcheck --skip-missing --ignores="@babel/*,@commitlint/*,eslint,eslint-*,husky,mocha,concurrently,nyc,prettier,typescript,vite-tsconfig-paths" echo $? if [[ $? == 1 ]]; then echo "Unused dependencies or devDependencies found" From d6f9e0dad0f4786a1f14e545f9f56786bb8448e4 Mon Sep 17 00:00:00 2001 From: Juan Escalada Date: Mon, 3 Mar 2025 17:25:20 +0900 Subject: [PATCH 10/13] chore(ts): bump node version for CI tests --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c71e3c8f7..5eb4c54d2 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -19,7 +19,7 @@ jobs: strategy: matrix: - node-version: [18.x] + node-version: [22.x] mongodb-version: [4.4] steps: From d478edd73b298f5e892903f9f4ff6e2c927b35ee Mon Sep 17 00:00:00 2001 From: Juan Escalada Date: Thu, 6 Mar 2025 00:55:49 +0900 Subject: [PATCH 11/13] chore(ts): attempt to fix failing CLI tests --- packages/git-proxy-cli/index.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/git-proxy-cli/index.js b/packages/git-proxy-cli/index.js index 0ec0b788b..a86ade54f 100755 --- a/packages/git-proxy-cli/index.js +++ b/packages/git-proxy-cli/index.js @@ -7,8 +7,8 @@ const util = require('util'); const GIT_PROXY_COOKIE_FILE = 'git-proxy-cookie'; // GitProxy UI HOST and PORT (configurable via environment variable) -const { GIT_PROXY_UI_HOST: uiHost, GIT_PROXY_UI_PORT: uiPort } = - require('@finos/git-proxy/src/config/env').serverConfig; +const { GIT_PROXY_UI_HOST: uiHost = 'http://localhost', GIT_PROXY_UI_PORT: uiPort = 8080 } = process.env; + const baseUrl = `${uiHost}:${uiPort}`; axios.defaults.timeout = 30000; From 4a07b20cdf1ff4566c2186618594f24599e71682 Mon Sep 17 00:00:00 2001 From: Juan Escalada Date: Wed, 2 Apr 2025 15:15:14 +0900 Subject: [PATCH 12/13] fix(ts): port over import/test fixes from `proxy` refactor PR --- .eslintrc.json | 11 +- .github/workflows/ci.yml | 2 +- .mocharc.json | 8 - package-lock.json | 538 ++++++++++++++++++++++++++++++- package.json | 8 +- test/{ => plugin}/plugin.test.js | 4 +- 6 files changed, 555 insertions(+), 16 deletions(-) delete mode 100644 .mocharc.json rename test/{ => plugin}/plugin.test.js (97%) diff --git a/.eslintrc.json b/.eslintrc.json index 3006a8ddc..fb129879f 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -15,8 +15,17 @@ "prettier", "plugin:json/recommended" ], - "overrides": [], + "overrides": [ + { + "files": ["test/**/*.js", "**/*.json"], + "parser": "espree", + "rules": { + "@typescript-eslint/no-unused-expressions": "off" + } + } + ], "parserOptions": { + "project": "./tsconfig.json", "requireConfigFile": false, "ecmaVersion": 12, "sourceType": "module", diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 35b7aefbf..d5a9ccadd 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -19,7 +19,7 @@ jobs: strategy: matrix: - node-version: [22.x] + node-version: [18.x] mongodb-version: [4.4] steps: diff --git a/.mocharc.json b/.mocharc.json deleted file mode 100644 index 07a8828f6..000000000 --- a/.mocharc.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "require": [ - "ts-node/register" - ], - "loader": "ts-node/esm", - "exit": true, - "experimental-print-required-tla": true -} diff --git a/package-lock.json b/package-lock.json index ec1e4a731..efa633965 100644 --- a/package-lock.json +++ b/package-lock.json @@ -25,7 +25,6 @@ "connect-mongo": "^5.1.0", "cors": "^2.8.5", "diff2html": "^3.4.33", - "eslint-plugin-typescript": "^0.14.0", "express": "^4.18.2", "express-http-proxy": "^2.0.0", "express-rate-limit": "^7.1.5", @@ -81,12 +80,15 @@ "eslint-plugin-prettier": "^5.0.0", "eslint-plugin-react": "^7.21.5", "eslint-plugin-standard": "^5.0.0", + "eslint-plugin-typescript": "^0.14.0", "husky": "^9.0.0", "mocha": "^10.8.2", "nyc": "^17.0.0", "prettier": "^3.0.0", "sinon": "^19.0.2", + "ts-mocha": "^11.1.0", "ts-node": "^10.9.2", + "tsx": "^4.19.3", "typescript": "^5.7.3", "vite": "^4.4.2", "vite-tsconfig-paths": "^5.1.4" @@ -1749,6 +1751,23 @@ "resolved": "https://registry.npmjs.org/@emotion/hash/-/hash-0.8.0.tgz", "integrity": "sha512-kBJtf7PH6aWwZ6fka3zQ0p6SBYzx4fl1LoZXE2RrnYST9Xljm7WfKJrU4g/Xr3Beg72MLrp1AWNUmuYJTL7Cow==" }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.25.2", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.2.tgz", + "integrity": "sha512-wCIboOL2yXZym2cgm6mlA742s9QeJ8DjGVaL39dLN4rRwrOgOyYSnOaFPhKZGLb2ngj4EyfAFjsNJwPXZvseag==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, "node_modules/@esbuild/android-arm": { "version": "0.18.20", "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.18.20.tgz", @@ -2018,6 +2037,23 @@ "node": ">=18" } }, + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.25.2", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.2.tgz", + "integrity": "sha512-talAIBoY5M8vHc6EeI2WW9d/CkiO9MQJ0IOWX8hrLhxGbro/vBXJvaQXefW2cP0z0nQVTdQ/eNyGFV1GSKrxfw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, "node_modules/@esbuild/netbsd-x64": { "version": "0.18.20", "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.18.20.tgz", @@ -2035,6 +2071,23 @@ "node": ">=12" } }, + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.25.2", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.2.tgz", + "integrity": "sha512-dcXYOC6NXOqcykeDlwId9kB6OkPUxOEqU+rkrYVqJbK2hagWOMrsTGsMr8+rW02M+d5Op5NNlgMmjzecaRf7Tg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, "node_modules/@esbuild/openbsd-x64": { "version": "0.18.20", "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.18.20.tgz", @@ -6515,6 +6568,7 @@ "resolved": "https://registry.npmjs.org/eslint-plugin-typescript/-/eslint-plugin-typescript-0.14.0.tgz", "integrity": "sha512-2u1WnnDF2mkWWgU1lFQ2RjypUlmRoBEvQN02y9u+IL12mjWlkKFGEBnVsjs9Y8190bfPQCvWly1c2rYYUSOxWw==", "deprecated": "Deprecated: Use @typescript-eslint/eslint-plugin instead", + "dev": true, "license": "MIT", "dependencies": { "requireindex": "~1.1.0" @@ -7509,6 +7563,19 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/get-tsconfig": { + "version": "4.10.0", + "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.10.0.tgz", + "integrity": "sha512-kGzZ3LWWQcGIAmg6iWvXn0ei6WDtV26wzHRMwDSzmAbcXrTEXxHy6IehI6/4eT6VRKyMP1eF1VqwrVUmE/LR7A==", + "dev": true, + "license": "MIT", + "dependencies": { + "resolve-pkg-maps": "^1.0.0" + }, + "funding": { + "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1" + } + }, "node_modules/getos": { "version": "3.2.1", "resolved": "https://registry.npmjs.org/getos/-/getos-3.2.1.tgz", @@ -11498,6 +11565,7 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/requireindex/-/requireindex-1.1.0.tgz", "integrity": "sha512-LBnkqsDE7BZKvqylbmn7lTIVdpx4K/QCduRATpO5R+wtPmky/a8pN1bO2D6wXppn1497AJF9mNjqAXr6bdl9jg==", + "dev": true, "license": "MIT", "engines": { "node": ">=0.10.5" @@ -11530,6 +11598,16 @@ "node": ">=8" } }, + "node_modules/resolve-pkg-maps": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz", + "integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1" + } + }, "node_modules/restore-cursor": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", @@ -12725,6 +12803,29 @@ "typescript": ">=4.8.4" } }, + "node_modules/ts-mocha": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/ts-mocha/-/ts-mocha-11.1.0.tgz", + "integrity": "sha512-yT7FfzNRCu8ZKkYvAOiH01xNma/vLq6Vit7yINKYFNVP8e5UyrYXSOMIipERTpzVKJQ4Qcos5bQo1tNERNZevQ==", + "dev": true, + "license": "MIT", + "bin": { + "ts-mocha": "bin/ts-mocha" + }, + "engines": { + "node": ">= 6.X.X" + }, + "peerDependencies": { + "mocha": "^3.X.X || ^4.X.X || ^5.X.X || ^6.X.X || ^7.X.X || ^8.X.X || ^9.X.X || ^10.X.X || ^11.X.X", + "ts-node": "^7.X.X || ^8.X.X || ^9.X.X || ^10.X.X", + "tsconfig-paths": "^4.X.X" + }, + "peerDependenciesMeta": { + "tsconfig-paths": { + "optional": true + } + } + }, "node_modules/ts-node": { "version": "10.9.2", "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz", @@ -12813,6 +12914,441 @@ "node": ">=0.6.x" } }, + "node_modules/tsx": { + "version": "4.19.3", + "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.19.3.tgz", + "integrity": "sha512-4H8vUNGNjQ4V2EOoGw005+c+dGuPSnhpPBPHBtsZdGZBk/iJb4kguGlPWaZTZ3q5nMtFOEsY0nRDlh9PJyd6SQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "esbuild": "~0.25.0", + "get-tsconfig": "^4.7.5" + }, + "bin": { + "tsx": "dist/cli.mjs" + }, + "engines": { + "node": ">=18.0.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + } + }, + "node_modules/tsx/node_modules/@esbuild/android-arm": { + "version": "0.25.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.2.tgz", + "integrity": "sha512-NQhH7jFstVY5x8CKbcfa166GoV0EFkaPkCKBQkdPJFvo5u+nGXLEH/ooniLb3QI8Fk58YAx7nsPLozUWfCBOJA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/android-arm64": { + "version": "0.25.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.2.tgz", + "integrity": "sha512-5ZAX5xOmTligeBaeNEPnPaeEuah53Id2tX4c2CVP3JaROTH+j4fnfHCkr1PjXMd78hMst+TlkfKcW/DlTq0i4w==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/android-x64": { + "version": "0.25.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.2.tgz", + "integrity": "sha512-Ffcx+nnma8Sge4jzddPHCZVRvIfQ0kMsUsCMcJRHkGJ1cDmhe4SsrYIjLUKn1xpHZybmOqCWwB0zQvsjdEHtkg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/darwin-arm64": { + "version": "0.25.2", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.2.tgz", + "integrity": "sha512-MpM6LUVTXAzOvN4KbjzU/q5smzryuoNjlriAIx+06RpecwCkL9JpenNzpKd2YMzLJFOdPqBpuub6eVRP5IgiSA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/darwin-x64": { + "version": "0.25.2", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.2.tgz", + "integrity": "sha512-5eRPrTX7wFyuWe8FqEFPG2cU0+butQQVNcT4sVipqjLYQjjh8a8+vUTfgBKM88ObB85ahsnTwF7PSIt6PG+QkA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/freebsd-arm64": { + "version": "0.25.2", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.2.tgz", + "integrity": "sha512-mLwm4vXKiQ2UTSX4+ImyiPdiHjiZhIaE9QvC7sw0tZ6HoNMjYAqQpGyui5VRIi5sGd+uWq940gdCbY3VLvsO1w==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/freebsd-x64": { + "version": "0.25.2", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.2.tgz", + "integrity": "sha512-6qyyn6TjayJSwGpm8J9QYYGQcRgc90nmfdUb0O7pp1s4lTY+9D0H9O02v5JqGApUyiHOtkz6+1hZNvNtEhbwRQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/linux-arm": { + "version": "0.25.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.2.tgz", + "integrity": "sha512-UHBRgJcmjJv5oeQF8EpTRZs/1knq6loLxTsjc3nxO9eXAPDLcWW55flrMVc97qFPbmZP31ta1AZVUKQzKTzb0g==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/linux-arm64": { + "version": "0.25.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.2.tgz", + "integrity": "sha512-gq/sjLsOyMT19I8obBISvhoYiZIAaGF8JpeXu1u8yPv8BE5HlWYobmlsfijFIZ9hIVGYkbdFhEqC0NvM4kNO0g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/linux-ia32": { + "version": "0.25.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.2.tgz", + "integrity": "sha512-bBYCv9obgW2cBP+2ZWfjYTU+f5cxRoGGQ5SeDbYdFCAZpYWrfjjfYwvUpP8MlKbP0nwZ5gyOU/0aUzZ5HWPuvQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/linux-loong64": { + "version": "0.25.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.2.tgz", + "integrity": "sha512-SHNGiKtvnU2dBlM5D8CXRFdd+6etgZ9dXfaPCeJtz+37PIUlixvlIhI23L5khKXs3DIzAn9V8v+qb1TRKrgT5w==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/linux-mips64el": { + "version": "0.25.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.2.tgz", + "integrity": "sha512-hDDRlzE6rPeoj+5fsADqdUZl1OzqDYow4TB4Y/3PlKBD0ph1e6uPHzIQcv2Z65u2K0kpeByIyAjCmjn1hJgG0Q==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/linux-ppc64": { + "version": "0.25.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.2.tgz", + "integrity": "sha512-tsHu2RRSWzipmUi9UBDEzc0nLc4HtpZEI5Ba+Omms5456x5WaNuiG3u7xh5AO6sipnJ9r4cRWQB2tUjPyIkc6g==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/linux-riscv64": { + "version": "0.25.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.2.tgz", + "integrity": "sha512-k4LtpgV7NJQOml/10uPU0s4SAXGnowi5qBSjaLWMojNCUICNu7TshqHLAEbkBdAszL5TabfvQ48kK84hyFzjnw==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/linux-s390x": { + "version": "0.25.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.2.tgz", + "integrity": "sha512-GRa4IshOdvKY7M/rDpRR3gkiTNp34M0eLTaC1a08gNrh4u488aPhuZOCpkF6+2wl3zAN7L7XIpOFBhnaE3/Q8Q==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/linux-x64": { + "version": "0.25.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.2.tgz", + "integrity": "sha512-QInHERlqpTTZ4FRB0fROQWXcYRD64lAoiegezDunLpalZMjcUcld3YzZmVJ2H/Cp0wJRZ8Xtjtj0cEHhYc/uUg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/netbsd-x64": { + "version": "0.25.2", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.2.tgz", + "integrity": "sha512-voZT9Z+tpOxrvfKFyfDYPc4DO4rk06qamv1a/fkuzHpiVBMOhpjK+vBmWM8J1eiB3OLSMFYNaOaBNLXGChf5tg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/openbsd-x64": { + "version": "0.25.2", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.2.tgz", + "integrity": "sha512-t/TkWwahkH0Tsgoq1Ju7QfgGhArkGLkF1uYz8nQS/PPFlXbP5YgRpqQR3ARRiC2iXoLTWFxc6DJMSK10dVXluw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/sunos-x64": { + "version": "0.25.2", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.2.tgz", + "integrity": "sha512-cfZH1co2+imVdWCjd+D1gf9NjkchVhhdpgb1q5y6Hcv9TP6Zi9ZG/beI3ig8TvwT9lH9dlxLq5MQBBgwuj4xvA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/win32-arm64": { + "version": "0.25.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.2.tgz", + "integrity": "sha512-7Loyjh+D/Nx/sOTzV8vfbB3GJuHdOQyrOryFdZvPHLf42Tk9ivBU5Aedi7iyX+x6rbn2Mh68T4qq1SDqJBQO5Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/win32-ia32": { + "version": "0.25.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.2.tgz", + "integrity": "sha512-WRJgsz9un0nqZJ4MfhabxaD9Ft8KioqU3JMinOTvobbX6MOSUigSBlogP8QB3uxpJDsFS6yN+3FDBdqE5lg9kg==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/win32-x64": { + "version": "0.25.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.2.tgz", + "integrity": "sha512-kM3HKb16VIXZyIeVrM1ygYmZBKybX8N4p754bw390wGO3Tf2j4L2/WYL+4suWujpgf6GBYs3jv7TyUivdd05JA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/esbuild": { + "version": "0.25.2", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.2.tgz", + "integrity": "sha512-16854zccKPnC+toMywC+uKNeYSv+/eXkevRAfwRD/G9Cleq66m8XFIrigkbvauLLlCfDL45Q2cWegSg53gGBnQ==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.25.2", + "@esbuild/android-arm": "0.25.2", + "@esbuild/android-arm64": "0.25.2", + "@esbuild/android-x64": "0.25.2", + "@esbuild/darwin-arm64": "0.25.2", + "@esbuild/darwin-x64": "0.25.2", + "@esbuild/freebsd-arm64": "0.25.2", + "@esbuild/freebsd-x64": "0.25.2", + "@esbuild/linux-arm": "0.25.2", + "@esbuild/linux-arm64": "0.25.2", + "@esbuild/linux-ia32": "0.25.2", + "@esbuild/linux-loong64": "0.25.2", + "@esbuild/linux-mips64el": "0.25.2", + "@esbuild/linux-ppc64": "0.25.2", + "@esbuild/linux-riscv64": "0.25.2", + "@esbuild/linux-s390x": "0.25.2", + "@esbuild/linux-x64": "0.25.2", + "@esbuild/netbsd-arm64": "0.25.2", + "@esbuild/netbsd-x64": "0.25.2", + "@esbuild/openbsd-arm64": "0.25.2", + "@esbuild/openbsd-x64": "0.25.2", + "@esbuild/sunos-x64": "0.25.2", + "@esbuild/win32-arm64": "0.25.2", + "@esbuild/win32-ia32": "0.25.2", + "@esbuild/win32-x64": "0.25.2" + } + }, "node_modules/tunnel-agent": { "version": "0.6.0", "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", diff --git a/package.json b/package.json index 53de641c5..219800b46 100644 --- a/package.json +++ b/package.json @@ -6,11 +6,11 @@ "cli": "node ./packages/git-proxy-cli/index.js", "client": "vite --config vite.config.js", "clientinstall": "npm install --prefix client", - "server": "ts-node index.ts", + "server": "tsx index.ts", "start": "concurrently \"npm run server\" \"npm run client\"", "build": "vite build", "build-ts": "tsc", - "test": "NODE_ENV=test mocha --exit", + "test": "NODE_ENV=test ts-mocha './test/*.js' --exit; mocha './test/plugin/*.js' --exit", "test-coverage": "nyc npm run test", "test-coverage-ci": "nyc --reporter=lcovonly --reporter=text npm run test", "prepare": "node ./scripts/prepare.js", @@ -47,7 +47,6 @@ "connect-mongo": "^5.1.0", "cors": "^2.8.5", "diff2html": "^3.4.33", - "eslint-plugin-typescript": "^0.14.0", "express": "^4.18.2", "express-http-proxy": "^2.0.0", "express-rate-limit": "^7.1.5", @@ -99,12 +98,15 @@ "eslint-plugin-prettier": "^5.0.0", "eslint-plugin-react": "^7.21.5", "eslint-plugin-standard": "^5.0.0", + "eslint-plugin-typescript": "^0.14.0", "husky": "^9.0.0", "mocha": "^10.8.2", "nyc": "^17.0.0", "prettier": "^3.0.0", "sinon": "^19.0.2", + "ts-mocha": "^11.1.0", "ts-node": "^10.9.2", + "tsx": "^4.19.3", "typescript": "^5.7.3", "vite": "^4.4.2", "vite-tsconfig-paths": "^5.1.4" diff --git a/test/plugin.test.js b/test/plugin/plugin.test.js similarity index 97% rename from test/plugin.test.js rename to test/plugin/plugin.test.js index cba96fa7a..04c5d5ad9 100644 --- a/test/plugin.test.js +++ b/test/plugin/plugin.test.js @@ -4,7 +4,7 @@ const { PullActionPlugin, PushActionPlugin, PluginLoader, -} = require('../src/plugin'); +} = require('../../src/plugin'); const { spawnSync } = require('child_process'); const { rmSync } = require('fs'); const { join } = require('path'); @@ -13,7 +13,7 @@ chai.should(); const expect = chai.expect; -const testPackagePath = join(__dirname, 'fixtures', 'test-package'); +const testPackagePath = join(__dirname, '../fixtures', 'test-package'); describe('loading plugins from packages', function () { // eslint-disable-next-line no-invalid-this From 707ac3b1fd0ea69076a144669e95448fb8603173 Mon Sep 17 00:00:00 2001 From: Juan Escalada Date: Wed, 2 Apr 2025 15:23:45 +0900 Subject: [PATCH 13/13] fix(ts): fix ci issues --- .github/workflows/unused-dependencies.yml | 2 +- packages/git-proxy-cli/package.json | 2 +- packages/git-proxy-cli/tsconfig.json | 18 ++++++++++++++++++ 3 files changed, 20 insertions(+), 2 deletions(-) create mode 100644 packages/git-proxy-cli/tsconfig.json diff --git a/.github/workflows/unused-dependencies.yml b/.github/workflows/unused-dependencies.yml index b1cbc45df..6afdb62da 100644 --- a/.github/workflows/unused-dependencies.yml +++ b/.github/workflows/unused-dependencies.yml @@ -21,7 +21,7 @@ jobs: node-version: '18.x' - name: 'Run depcheck' run: | - npx depcheck --skip-missing --ignores="@babel/*,@commitlint/*,eslint,eslint-*,husky,mocha,concurrently,nyc,prettier,typescript,vite-tsconfig-paths" + npx depcheck --skip-missing --ignores="@babel/*,@commitlint/*,concurrently,eslint,eslint-*,husky,mocha,nyc,prettier,ts-mocha,ts-node,tsconfig-paths,tsx,typescript,vite-tsconfig-paths" echo $? if [[ $? == 1 ]]; then echo "Unused dependencies or devDependencies found" diff --git a/packages/git-proxy-cli/package.json b/packages/git-proxy-cli/package.json index c2bcf6ef4..baade725c 100644 --- a/packages/git-proxy-cli/package.json +++ b/packages/git-proxy-cli/package.json @@ -13,7 +13,7 @@ }, "scripts": { "lint": "eslint --fix . --ext .js,.jsx", - "test": "NODE_ENV=test mocha --exit --timeout 10000", + "test": "NODE_ENV=test ts-mocha --exit --timeout 10000", "test-coverage": "nyc npm run test", "test-coverage-ci": "nyc --reporter=lcovonly --reporter=text --reporter=html npm run test" }, diff --git a/packages/git-proxy-cli/tsconfig.json b/packages/git-proxy-cli/tsconfig.json new file mode 100644 index 000000000..236bfabc5 --- /dev/null +++ b/packages/git-proxy-cli/tsconfig.json @@ -0,0 +1,18 @@ +{ + "compilerOptions": { + "target": "ES6", + "lib": ["DOM", "ESNext"], + "allowJs": true, + "checkJs": false, + "jsx": "react-jsx", + "moduleResolution": "Node", + "strict": true, + "noEmit": true, + "skipLibCheck": true, + "isolatedModules": true, + "module": "CommonJS", + "esModuleInterop": true, + "allowSyntheticDefaultImports": true + }, + "include": ["index.js", "test", "coverage"] +}