diff --git a/CHANGELOG.md b/CHANGELOG.md index 6fe4153ba..5a2ae82e9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,26 @@ +## 0.65.0 (2025-03-05) + +### πŸš€ Features + +- **utils:** add score filter to md report generation ([#956](https://github.com/code-pushup/cli/pull/956)) + +### ❀️ Thank You + +- Michael Hladky @BioPhoton + +## 0.64.2 (2025-03-05) + +### 🩹 Fixes + +- update nx-verdaccio pkg ([#954](https://github.com/code-pushup/cli/pull/954)) +- **plugin-js-packages:** ignore non-empty stderr ([7936a00c](https://github.com/code-pushup/cli/commit/7936a00c)) +- **utils:** ignore non-json lines in fromJsonLines utility ([7886c572](https://github.com/code-pushup/cli/commit/7886c572)) + +### ❀️ Thank You + +- MatΔ›j Chalk +- Michael Hladky @BioPhoton + ## 0.64.1 (2025-03-04) ### 🩹 Fixes diff --git a/nx.json b/nx.json index 84fbf0790..0c1cd400d 100644 --- a/nx.json +++ b/nx.json @@ -94,6 +94,9 @@ "filterByTags": ["publishable"] } } + }, + { + "plugin": "./packages/nx-plugin/src/plugin/plugin.ts" } ] } diff --git a/package-lock.json b/package-lock.json index 7094c8ac4..8a43b0e37 100644 --- a/package-lock.json +++ b/package-lock.json @@ -50,7 +50,7 @@ "@nx/react": "19.8.13", "@nx/vite": "19.8.13", "@nx/workspace": "19.8.13", - "@push-based/nx-verdaccio": "0.0.0-alpha.26", + "@push-based/nx-verdaccio": "0.0.0-alpha.30", "@swc-node/register": "1.9.2", "@swc/cli": "0.3.14", "@swc/core": "1.5.7", @@ -5769,15 +5769,53 @@ } }, "node_modules/@push-based/nx-verdaccio": { - "version": "0.0.0-alpha.26", - "resolved": "https://registry.npmjs.org/@push-based/nx-verdaccio/-/nx-verdaccio-0.0.0-alpha.26.tgz", - "integrity": "sha512-Go11Dg+w5Ntl5Ig8YNzVVPbpOG85aVszjyBIK0FvVBX+/QllQY1F4fP8K8fYnMJnO9v5Tao3cryGFY5Zo9i+/g==", + "version": "0.0.0-alpha.30", + "resolved": "https://registry.npmjs.org/@push-based/nx-verdaccio/-/nx-verdaccio-0.0.0-alpha.30.tgz", + "integrity": "sha512-PB/WpfcqmyypyXkWKJBVinIgvOgYJV3ckXdQXKBHJuEKyUnfiUObmgnGqmlQqCgFlv5tvPkNGEFXDPTGL9JyGw==", "dev": true, "dependencies": { "@nx/devkit": "19.8.0", + "@nx/vite": "19.8.0", "ansis": "^3.3.2", "simple-git": "^3.27.0", - "tslib": "^2.3.0" + "tslib": "^2.3.0", + "vite": "~5.0.0", + "vitest": "^1.3.1" + } + }, + "node_modules/@push-based/nx-verdaccio/node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@push-based/nx-verdaccio/node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@push-based/nx-verdaccio/node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" } }, "node_modules/@push-based/nx-verdaccio/node_modules/@nrwl/devkit": { @@ -5789,6 +5827,46 @@ "@nx/devkit": "19.8.0" } }, + "node_modules/@push-based/nx-verdaccio/node_modules/@nrwl/js": { + "version": "19.8.0", + "resolved": "https://registry.npmjs.org/@nrwl/js/-/js-19.8.0.tgz", + "integrity": "sha512-agmIwKD6zK0l+aIEhDv3VuPW10rn5fhHeif3k5q9EgT47QL2gCNzU54oYpuXoKeenJCsDMzOEkJb1IsglVas6g==", + "dev": true, + "dependencies": { + "@nx/js": "19.8.0" + } + }, + "node_modules/@push-based/nx-verdaccio/node_modules/@nrwl/tao": { + "version": "19.8.0", + "resolved": "https://registry.npmjs.org/@nrwl/tao/-/tao-19.8.0.tgz", + "integrity": "sha512-tybyYdhHNfyBRb8SOc/SasT1iwjYkp/QibS8L3ayTvpvvzJpNr8BpuTznQWIkaIjilflmcdHl+rMiQDqwABqpg==", + "dev": true, + "dependencies": { + "nx": "19.8.0", + "tslib": "^2.3.0" + }, + "bin": { + "tao": "index.js" + } + }, + "node_modules/@push-based/nx-verdaccio/node_modules/@nrwl/vite": { + "version": "19.8.0", + "resolved": "https://registry.npmjs.org/@nrwl/vite/-/vite-19.8.0.tgz", + "integrity": "sha512-Nux7PN5HYFnSbVj0lVIhgMRkfJ7AYRBr8lXDsJBFboxUtmnPGpG5aV6o/9Fu2XD/eiLBsHCmMcusqkD0+jCvMA==", + "dev": true, + "dependencies": { + "@nx/vite": "19.8.0" + } + }, + "node_modules/@push-based/nx-verdaccio/node_modules/@nrwl/workspace": { + "version": "19.8.0", + "resolved": "https://registry.npmjs.org/@nrwl/workspace/-/workspace-19.8.0.tgz", + "integrity": "sha512-HSN0GML7RaVUSRD3lOc07atCjs4Vzs3Jgs9/7+zFtldKsmsY4GzYIWpJ4G6IDl9u3YJwTKtRmuj5BVI7G+ZGmw==", + "dev": true, + "dependencies": { + "@nx/workspace": "19.8.0" + } + }, "node_modules/@push-based/nx-verdaccio/node_modules/@nx/devkit": { "version": "19.8.0", "resolved": "https://registry.npmjs.org/@nx/devkit/-/devkit-19.8.0.tgz", @@ -5809,19 +5887,580 @@ "nx": ">= 17 <= 20" } }, - "node_modules/@push-based/nx-verdaccio/node_modules/minimatch": { - "version": "9.0.3", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", - "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", + "node_modules/@push-based/nx-verdaccio/node_modules/@nx/js": { + "version": "19.8.0", + "resolved": "https://registry.npmjs.org/@nx/js/-/js-19.8.0.tgz", + "integrity": "sha512-gexu1nYN3Hl3+yNuowgfd3sW5uooMKx9Dg6FPWWn/27+eJlTny5A2nQ3YR85yKRiJbNEP23am4le788pyVq2MQ==", "dev": true, "dependencies": { - "brace-expansion": "^2.0.1" + "@babel/core": "^7.23.2", + "@babel/plugin-proposal-decorators": "^7.22.7", + "@babel/plugin-transform-class-properties": "^7.22.5", + "@babel/plugin-transform-runtime": "^7.23.2", + "@babel/preset-env": "^7.23.2", + "@babel/preset-typescript": "^7.22.5", + "@babel/runtime": "^7.22.6", + "@nrwl/js": "19.8.0", + "@nx/devkit": "19.8.0", + "@nx/workspace": "19.8.0", + "babel-plugin-const-enum": "^1.0.1", + "babel-plugin-macros": "^2.8.0", + "babel-plugin-transform-typescript-metadata": "^0.3.1", + "chalk": "^4.1.0", + "columnify": "^1.6.0", + "detect-port": "^1.5.1", + "fast-glob": "3.2.7", + "ignore": "^5.0.4", + "js-tokens": "^4.0.0", + "jsonc-parser": "3.2.0", + "minimatch": "9.0.3", + "npm-package-arg": "11.0.1", + "npm-run-path": "^4.0.1", + "ora": "5.3.0", + "semver": "^7.5.3", + "source-map-support": "0.5.19", + "ts-node": "10.9.1", + "tsconfig-paths": "^4.1.2", + "tslib": "^2.3.0" + }, + "peerDependencies": { + "verdaccio": "^5.0.4" }, + "peerDependenciesMeta": { + "verdaccio": { + "optional": true + } + } + }, + "node_modules/@push-based/nx-verdaccio/node_modules/@nx/nx-darwin-arm64": { + "version": "19.8.0", + "resolved": "https://registry.npmjs.org/@nx/nx-darwin-arm64/-/nx-darwin-arm64-19.8.0.tgz", + "integrity": "sha512-JWtBb6ndCdGE+RBIwKN85BZnX41lFGsFxnsmot71GeAj/g7Cb0PM2qcmxawoy8yLPTBGZhb+eHER3z3nDIqRog==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], "engines": { - "node": ">=16 || 14 >=14.17" + "node": ">= 10" + } + }, + "node_modules/@push-based/nx-verdaccio/node_modules/@nx/nx-darwin-x64": { + "version": "19.8.0", + "resolved": "https://registry.npmjs.org/@nx/nx-darwin-x64/-/nx-darwin-x64-19.8.0.tgz", + "integrity": "sha512-NcNaqbbStBkyahLaoKFtW6nEdjCjYT5ZOmGjc6UpAx1Y3pkk/FcIOYJRCBxwuOsRRsEAyeVcHPdYrouZmV+6Yw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@push-based/nx-verdaccio/node_modules/@nx/nx-freebsd-x64": { + "version": "19.8.0", + "resolved": "https://registry.npmjs.org/@nx/nx-freebsd-x64/-/nx-freebsd-x64-19.8.0.tgz", + "integrity": "sha512-QXHRnMW5LrpYvtmdFRL2CRgX9CWDccrs2xhQNNzcgsLgL87Wte5kjDoJJN4GQjtrmjD3Q93w67CE9lhqnpXBvQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@push-based/nx-verdaccio/node_modules/@nx/nx-linux-arm-gnueabihf": { + "version": "19.8.0", + "resolved": "https://registry.npmjs.org/@nx/nx-linux-arm-gnueabihf/-/nx-linux-arm-gnueabihf-19.8.0.tgz", + "integrity": "sha512-VjZOLMxz0gT+0AdDygxQS0Vvi3AcEzO3y9o9WdGKKaDVUDycrFn72X+ZbvFoio1dF7S1s2TbmOlR09Bu1yTgGg==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@push-based/nx-verdaccio/node_modules/@nx/nx-linux-arm64-gnu": { + "version": "19.8.0", + "resolved": "https://registry.npmjs.org/@nx/nx-linux-arm64-gnu/-/nx-linux-arm64-gnu-19.8.0.tgz", + "integrity": "sha512-sCSrXkSmEfDUDGLESXB3eHXECAIYz9nosFZpCggyUP1vgF/QcV40fHnV38nrFbKaVHuoaxy43RgnD+I3o6sDSw==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@push-based/nx-verdaccio/node_modules/@nx/nx-linux-arm64-musl": { + "version": "19.8.0", + "resolved": "https://registry.npmjs.org/@nx/nx-linux-arm64-musl/-/nx-linux-arm64-musl-19.8.0.tgz", + "integrity": "sha512-F3xEe7NGjsVKZTVlvUiUOTmCzxteRsQH2SSsYXyAfgJ42P3eZPc9HgeLx6RByjC/NBCwc7XEECMP1FjQgQXHVw==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@push-based/nx-verdaccio/node_modules/@nx/nx-linux-x64-gnu": { + "version": "19.8.0", + "resolved": "https://registry.npmjs.org/@nx/nx-linux-x64-gnu/-/nx-linux-x64-gnu-19.8.0.tgz", + "integrity": "sha512-4uYuE+LvxOFXvi9z9ueJSVrME5D383SHNCjs6jYwc9KovCsmL5oPVXRieoE4/hYI4lrjly+CrAnPZU1P7ocBiw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@push-based/nx-verdaccio/node_modules/@nx/nx-linux-x64-musl": { + "version": "19.8.0", + "resolved": "https://registry.npmjs.org/@nx/nx-linux-x64-musl/-/nx-linux-x64-musl-19.8.0.tgz", + "integrity": "sha512-9UDEGjOvNt+m+kMBCAB7CGisSwv05Xvaq8K3NJ+xM5GPG74EkQel24mSoIJfm/6zmDkdZCiRzNN9VRjOjzOz6Q==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@push-based/nx-verdaccio/node_modules/@nx/nx-win32-arm64-msvc": { + "version": "19.8.0", + "resolved": "https://registry.npmjs.org/@nx/nx-win32-arm64-msvc/-/nx-win32-arm64-msvc-19.8.0.tgz", + "integrity": "sha512-JVzm0KjyLZY5ponBukZ/b35wttW0b3LB0nqaiiHY7WKwSzo+m0UGEYHD/Yk6rKA0RRZN2wQVeIzLeWfYcZYrhA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@push-based/nx-verdaccio/node_modules/@nx/nx-win32-x64-msvc": { + "version": "19.8.0", + "resolved": "https://registry.npmjs.org/@nx/nx-win32-x64-msvc/-/nx-win32-x64-msvc-19.8.0.tgz", + "integrity": "sha512-IRLhMZIInvp9okLsjnj76zaz8iaMovtLr6MHIFOOPIMsZYRhqQTArF5Os/NqEezeYYxvX6YZ5hKYe0xQO7A5LA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@push-based/nx-verdaccio/node_modules/@nx/vite": { + "version": "19.8.0", + "resolved": "https://registry.npmjs.org/@nx/vite/-/vite-19.8.0.tgz", + "integrity": "sha512-Krok+zalc6as1w+V+D/mmY+vh5qKdkvz4omMds2k3d+RQNxIb7Mh78ueGVQr5zRtR9CKSSPvDMtUklnjDlp1SQ==", + "dev": true, + "dependencies": { + "@nrwl/vite": "19.8.0", + "@nx/devkit": "19.8.0", + "@nx/js": "19.8.0", + "@phenomnomnominal/tsquery": "~5.0.1", + "@swc/helpers": "~0.5.0", + "enquirer": "~2.3.6", + "minimatch": "9.0.3", + "tsconfig-paths": "^4.1.2" }, - "funding": { - "url": "https://github.com/sponsors/isaacs" + "peerDependencies": { + "vite": "^5.0.0", + "vitest": "^1.3.1 || ^2.0.0" + } + }, + "node_modules/@push-based/nx-verdaccio/node_modules/@nx/workspace": { + "version": "19.8.0", + "resolved": "https://registry.npmjs.org/@nx/workspace/-/workspace-19.8.0.tgz", + "integrity": "sha512-8/NHRuJAqurNaFIUuSZdV8qNqiFykXlHjPp6E4raNmB8seIKYJVeYZgw9D7d5piOuLHA3o0JWSKJQ3nBElfCBw==", + "dev": true, + "dependencies": { + "@nrwl/workspace": "19.8.0", + "@nx/devkit": "19.8.0", + "chalk": "^4.1.0", + "enquirer": "~2.3.6", + "nx": "19.8.0", + "tslib": "^2.3.0", + "yargs-parser": "21.1.1" + } + }, + "node_modules/@push-based/nx-verdaccio/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@push-based/nx-verdaccio/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/@push-based/nx-verdaccio/node_modules/cli-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", + "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==", + "dev": true, + "dependencies": { + "restore-cursor": "^3.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@push-based/nx-verdaccio/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/@push-based/nx-verdaccio/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/@push-based/nx-verdaccio/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "node_modules/@push-based/nx-verdaccio/node_modules/fast-glob": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.7.tgz", + "integrity": "sha512-rYGMRwip6lUMvYD3BTScMwT1HtAs2d71SMv66Vrxs0IekGZEjhM0pcMfjQPnknBt2zeCwQMEupiN02ZP4DiT1Q==", + "dev": true, + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.4" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@push-based/nx-verdaccio/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, + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/@push-based/nx-verdaccio/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/@push-based/nx-verdaccio/node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/@push-based/nx-verdaccio/node_modules/mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/@push-based/nx-verdaccio/node_modules/minimatch": { + "version": "9.0.3", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", + "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@push-based/nx-verdaccio/node_modules/nx": { + "version": "19.8.0", + "resolved": "https://registry.npmjs.org/nx/-/nx-19.8.0.tgz", + "integrity": "sha512-zD1ZvkfxECrd9QnvUyAUVLESmjl0bpIhB1gLcYN2BqsCkB1vkngbxIvXDorI98keOVEfHzeuwNSkufQNls1hug==", + "dev": true, + "hasInstallScript": true, + "dependencies": { + "@napi-rs/wasm-runtime": "0.2.4", + "@nrwl/tao": "19.8.0", + "@yarnpkg/lockfile": "^1.1.0", + "@yarnpkg/parsers": "3.0.0-rc.46", + "@zkochan/js-yaml": "0.0.7", + "axios": "^1.7.4", + "chalk": "^4.1.0", + "cli-cursor": "3.1.0", + "cli-spinners": "2.6.1", + "cliui": "^8.0.1", + "dotenv": "~16.4.5", + "dotenv-expand": "~11.0.6", + "enquirer": "~2.3.6", + "figures": "3.2.0", + "flat": "^5.0.2", + "front-matter": "^4.0.2", + "fs-extra": "^11.1.0", + "ignore": "^5.0.4", + "jest-diff": "^29.4.1", + "jsonc-parser": "3.2.0", + "lines-and-columns": "2.0.3", + "minimatch": "9.0.3", + "node-machine-id": "1.1.12", + "npm-run-path": "^4.0.1", + "open": "^8.4.0", + "ora": "5.3.0", + "semver": "^7.5.3", + "string-width": "^4.2.3", + "strong-log-transformer": "^2.1.0", + "tar-stream": "~2.2.0", + "tmp": "~0.2.1", + "tsconfig-paths": "^4.1.2", + "tslib": "^2.3.0", + "yargs": "^17.6.2", + "yargs-parser": "21.1.1" + }, + "bin": { + "nx": "bin/nx.js", + "nx-cloud": "bin/nx-cloud.js" + }, + "optionalDependencies": { + "@nx/nx-darwin-arm64": "19.8.0", + "@nx/nx-darwin-x64": "19.8.0", + "@nx/nx-freebsd-x64": "19.8.0", + "@nx/nx-linux-arm-gnueabihf": "19.8.0", + "@nx/nx-linux-arm64-gnu": "19.8.0", + "@nx/nx-linux-arm64-musl": "19.8.0", + "@nx/nx-linux-x64-gnu": "19.8.0", + "@nx/nx-linux-x64-musl": "19.8.0", + "@nx/nx-win32-arm64-msvc": "19.8.0", + "@nx/nx-win32-x64-msvc": "19.8.0" + }, + "peerDependencies": { + "@swc-node/register": "^1.8.0", + "@swc/core": "^1.3.85" + }, + "peerDependenciesMeta": { + "@swc-node/register": { + "optional": true + }, + "@swc/core": { + "optional": true + } + } + }, + "node_modules/@push-based/nx-verdaccio/node_modules/onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "dev": true, + "dependencies": { + "mimic-fn": "^2.1.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@push-based/nx-verdaccio/node_modules/restore-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", + "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==", + "dev": true, + "dependencies": { + "onetime": "^5.1.0", + "signal-exit": "^3.0.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@push-based/nx-verdaccio/node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "dev": true + }, + "node_modules/@push-based/nx-verdaccio/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@push-based/nx-verdaccio/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@push-based/nx-verdaccio/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@push-based/nx-verdaccio/node_modules/vite": { + "version": "5.0.13", + "resolved": "https://registry.npmjs.org/vite/-/vite-5.0.13.tgz", + "integrity": "sha512-/9ovhv2M2dGTuA+dY93B9trfyWMDRQw2jdVBhHNP6wr0oF34wG2i/N55801iZIpgUpnHDm4F/FabGQLyc+eOgg==", + "dev": true, + "dependencies": { + "esbuild": "^0.19.3", + "postcss": "^8.4.32", + "rollup": "^4.2.0" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^18.0.0 || >=20.0.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^18.0.0 || >=20.0.0", + "less": "*", + "lightningcss": "^1.21.0", + "sass": "*", + "stylus": "*", + "sugarss": "*", + "terser": "^5.4.0" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "less": { + "optional": true + }, + "lightningcss": { + "optional": true + }, + "sass": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + } } }, "node_modules/@rollup/rollup-android-arm-eabi": { diff --git a/package.json b/package.json index 4313d674d..66b0db8fb 100644 --- a/package.json +++ b/package.json @@ -63,7 +63,7 @@ "@nx/react": "19.8.13", "@nx/vite": "19.8.13", "@nx/workspace": "19.8.13", - "@push-based/nx-verdaccio": "0.0.0-alpha.26", + "@push-based/nx-verdaccio": "0.0.0-alpha.30", "@swc-node/register": "1.9.2", "@swc/cli": "0.3.14", "@swc/core": "1.5.7", diff --git a/packages/ci/package.json b/packages/ci/package.json index fb9846487..a0d8d4200 100644 --- a/packages/ci/package.json +++ b/packages/ci/package.json @@ -1,6 +1,6 @@ { "name": "@code-pushup/ci", - "version": "0.64.1", + "version": "0.65.0", "description": "CI automation logic for Code PushUp (provider-agnostic)", "license": "MIT", "homepage": "https://github.com/code-pushup/cli/tree/main/packages/ci#readme", @@ -26,8 +26,8 @@ }, "type": "module", "dependencies": { - "@code-pushup/models": "0.64.1", - "@code-pushup/utils": "0.64.1", + "@code-pushup/models": "0.65.0", + "@code-pushup/utils": "0.65.0", "glob": "^10.4.5", "simple-git": "^3.20.0", "yaml": "^2.5.1", diff --git a/packages/cli/package.json b/packages/cli/package.json index b4df8398c..aa65ece68 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -1,6 +1,6 @@ { "name": "@code-pushup/cli", - "version": "0.64.1", + "version": "0.65.0", "license": "MIT", "description": "A CLI to run all kinds of code quality measurements to align your team with company goals", "homepage": "https://code-pushup.dev", @@ -42,9 +42,9 @@ "code-pushup": "./src/index.js" }, "dependencies": { - "@code-pushup/models": "0.64.1", - "@code-pushup/core": "0.64.1", - "@code-pushup/utils": "0.64.1", + "@code-pushup/models": "0.65.0", + "@code-pushup/core": "0.65.0", + "@code-pushup/utils": "0.65.0", "yargs": "^17.7.2", "ansis": "^3.3.0", "simple-git": "^3.20.0" diff --git a/packages/core/package.json b/packages/core/package.json index 18ea97021..88bc879bd 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -1,6 +1,6 @@ { "name": "@code-pushup/core", - "version": "0.64.1", + "version": "0.65.0", "license": "MIT", "description": "Core business logic for the used by the Code PushUp CLI", "homepage": "https://github.com/code-pushup/cli/tree/main/packages/core#readme", @@ -39,8 +39,8 @@ }, "type": "module", "dependencies": { - "@code-pushup/models": "0.64.1", - "@code-pushup/utils": "0.64.1", + "@code-pushup/models": "0.65.0", + "@code-pushup/utils": "0.65.0", "ansis": "^3.3.0" }, "peerDependencies": { diff --git a/packages/create-cli/package.json b/packages/create-cli/package.json index 24b144d7a..812de33b3 100644 --- a/packages/create-cli/package.json +++ b/packages/create-cli/package.json @@ -1,6 +1,6 @@ { "name": "@code-pushup/create-cli", - "version": "0.64.1", + "version": "0.65.0", "license": "MIT", "bin": "index.js", "homepage": "https://github.com/code-pushup/cli/tree/main/packages/create-cli#readme", @@ -26,7 +26,7 @@ }, "type": "module", "dependencies": { - "@code-pushup/nx-plugin": "0.64.1", - "@code-pushup/utils": "0.64.1" + "@code-pushup/nx-plugin": "0.65.0", + "@code-pushup/utils": "0.65.0" } } diff --git a/packages/example-plugin/plugin.ts b/packages/example-plugin/plugin.ts new file mode 100644 index 000000000..357d362af --- /dev/null +++ b/packages/example-plugin/plugin.ts @@ -0,0 +1,70 @@ +import { + type CreateNodesV2, + type ProjectConfiguration, + createNodesFromFiles, +} from '@nx/devkit'; +import { readFile } from 'node:fs/promises'; +import { dirname, join } from 'node:path'; +import { combineGlobPatterns } from 'nx/src/utils/globs'; +import { getProjectConfig } from './project-config'; + +const PROJECT_JSON_FILE_GLOB = '**/project.json'; +const PACKAGE_JSON_FILE_GLOB = '**/package.json'; +const GLOB_PATTERN = combineGlobPatterns( + PROJECT_JSON_FILE_GLOB, + PACKAGE_JSON_FILE_GLOB, +); + +export const createNodesV2: CreateNodesV2 = [ + GLOB_PATTERN, + async (configFiles, options, context) => { + console.log('hello'); + return await createNodesFromFiles( + async (globMatchingFile, internalOptions) => { + // Unexpected token 'g', "getProject"... is not valid JSON + // Project lib-a-e2e is an environment project but has no implicit dependencies. + const projectConfiguration: ProjectConfiguration = await readFile( + join(process.cwd(), globMatchingFile), + 'utf8', + ).then(JSON.parse); + console.log( + 'getProjectConfig', + await getProjectConfig(globMatchingFile), + ); + console.log('projectConfiguration', projectConfiguration); + if ( + !('name' in projectConfiguration) || + typeof projectConfiguration.name !== 'string' + ) { + throw new Error('Project name is required'); + } + + const projectRoot = dirname(globMatchingFile); + if (projectRoot.includes('dummy')) { + console.log('dummy'); + } + const { targets, namedInputs = {} } = { + targets: { + 'code-pushup': { + command: "node echo 'hello'", + options: { + 'persist.filename': 'code-pushup.json', + }, + }, + }, + }; + return { + projects: { + [projectRoot]: { + namedInputs, + targets, + }, + }, + }; + }, + configFiles, + options, + context, + ); + }, +]; diff --git a/packages/example-plugin/project-config.ts b/packages/example-plugin/project-config.ts new file mode 100644 index 000000000..a591b626e --- /dev/null +++ b/packages/example-plugin/project-config.ts @@ -0,0 +1,40 @@ +import type { ProjectConfiguration } from '@nx/devkit'; +import { readFile } from 'node:fs/promises'; +import { dirname, join } from 'node:path'; + +/** + * Project Config is created by reading files and combining the results + * + * @param matchingFilePath + * + * @catch error when the file is not present + * + * @returns Combined PackageNxConfig and ProjectConfiguration fields, and unified targets + */ + +// Project lib-a-e2e is an environment project but has no implicit dependencies. +export async function getProjectConfig(matchingFilePath: string) { + const dirName = dirname(matchingFilePath); + + const projectJson: ProjectConfiguration = await readFile( + join(dirName, 'project.json'), + 'utf8', + ) + .catch(() => '{}') + .then(JSON.parse); + const { nx: pkgProjectJson }: { nx: ProjectConfiguration } = await readFile( + join(dirName, 'package.json'), + 'utf8', + ) + .catch(() => '{}') + .then(JSON.parse); + + return { + ...projectJson, + ...pkgProjectJson, + targets: { + ...projectJson.targets, + ...pkgProjectJson?.targets, + }, + } satisfies ProjectConfiguration; +} diff --git a/packages/models/package.json b/packages/models/package.json index e764d76d5..35e5cfd92 100644 --- a/packages/models/package.json +++ b/packages/models/package.json @@ -1,6 +1,6 @@ { "name": "@code-pushup/models", - "version": "0.64.1", + "version": "0.65.0", "license": "MIT", "description": "Model definitions and validators for the Code PushUp CLI", "homepage": "https://github.com/code-pushup/cli/tree/main/packages/models#readme", diff --git a/packages/nx-plugin/package.json b/packages/nx-plugin/package.json index e616c78c0..27b9aec84 100644 --- a/packages/nx-plugin/package.json +++ b/packages/nx-plugin/package.json @@ -1,6 +1,6 @@ { "name": "@code-pushup/nx-plugin", - "version": "0.64.1", + "version": "0.65.0", "license": "MIT", "description": "Nx plugin to integrate the Code PushUp CLI into your workspace πŸ› οΈ", "publishConfig": { @@ -32,8 +32,8 @@ "generators": "./generators.json", "executors": "./executors.json", "dependencies": { - "@code-pushup/models": "0.64.1", - "@code-pushup/utils": "0.64.1", + "@code-pushup/models": "0.65.0", + "@code-pushup/utils": "0.65.0", "@nx/devkit": "^17.0.0 || ^18.0.0 || ^19.0.0", "ansis": "^3.3.0", "nx": "^17.0.0 || ^18.0.0 || ^19.0.0", diff --git a/packages/nx-plugin/src/plugin/index.ts b/packages/nx-plugin/src/plugin/index.ts index 648d0b4aa..6af7c1076 100644 --- a/packages/nx-plugin/src/plugin/index.ts +++ b/packages/nx-plugin/src/plugin/index.ts @@ -1,2 +1,2 @@ -export { createNodes } from './plugin.js'; +export { createNodes, createNodesV2 } from './plugin.js'; export type { CreateNodesOptions } from './types.js'; diff --git a/packages/nx-plugin/src/plugin/plugin.ts b/packages/nx-plugin/src/plugin/plugin.ts index bb0f09846..57473e92d 100644 --- a/packages/nx-plugin/src/plugin/plugin.ts +++ b/packages/nx-plugin/src/plugin/plugin.ts @@ -1,38 +1,104 @@ -import type { - CreateNodes, - CreateNodesContext, - CreateNodesResult, +import { + type CreateNodesV2, + type ProjectConfiguration, + createNodesFromFiles, } from '@nx/devkit'; -import { normalizeCreateNodesOptions } from '@push-based/nx-verdaccio/src/plugin/normalize-create-nodes-options'; -import { createProjectConfiguration } from '@push-based/nx-verdaccio/src/plugin/targets/create-targets'; +import { readFile } from 'node:fs/promises'; +import { dirname, join } from 'node:path'; +import { combineGlobPatterns } from 'nx/src/utils/globs'; import { PROJECT_JSON_FILE_NAME } from '../internal/constants'; +import { getProjectConfig } from './project-config'; +import { createProjectConfiguration } from './utils'; type FileMatcher = `${string}${typeof PROJECT_JSON_FILE_NAME}`; -const PROJECT_JSON_FILE_GLOB = `**/${PROJECT_JSON_FILE_NAME}` as FileMatcher; +// const PROJECT_JSON_FILE_GLOB = `**/${PROJECT_JSON_FILE_NAME}` as FileMatcher; -// name has to be "createNodes" to get picked up by Nx -export const createNodes = [ +// // name has to be "createNodes" to get picked up by Nx +// export const createNodes = [ +// PROJECT_JSON_FILE_GLOB, +// createNodesV1Fn, +// ] satisfies CreateNodes; + +// export async function createNodesV1Fn( +// projectConfigurationFile: string, +// createNodesOptions: unknown, +// _: CreateNodesContext, +// ): Promise { +// const projectJson = await loadProjectConfiguration(projectConfigurationFile); +// const createOptions = normalizeCreateNodesOptions(createNodesOptions); + +// const { targets } = await createProjectConfiguration( +// projectJson, +// createOptions, +// ); +// return { +// projects: { +// [projectJson.root]: { +// targets, +// }, +// }, +// }; +// } + +const PROJECT_JSON_FILE_GLOB = '**/project.json'; +const PACKAGE_JSON_FILE_GLOB = '**/package.json'; +const GLOB_PATTERN = combineGlobPatterns( PROJECT_JSON_FILE_GLOB, - createNodesV1Fn, -] satisfies CreateNodes; + PACKAGE_JSON_FILE_GLOB, +); -export async function createNodesV1Fn( - projectConfigurationFile: string, - createNodesOptions: unknown, - _: CreateNodesContext, -): Promise { - const projectJson = await loadProjectConfiguration(projectConfigurationFile); - const createOptions = normalizeCreateNodesOptions(createNodesOptions); +export const createNodesV2: CreateNodesV2 = [ + GLOB_PATTERN, + async (configFiles, options, context) => { + console.log('hello'); + return await createNodesFromFiles( + async (globMatchingFile, internalOptions) => { + // Unexpected token 'g', "getProject"... is not valid JSON + // Project lib-a-e2e is an environment project but has no implicit dependencies. + const projectConfiguration: ProjectConfiguration = await readFile( + join(process.cwd(), globMatchingFile), + 'utf8', + ).then(JSON.parse); + console.log( + 'getProjectConfig', + await getProjectConfig(globMatchingFile), + ); + console.log('projectConfiguration', projectConfiguration); + if ( + !('name' in projectConfiguration) || + typeof projectConfiguration.name !== 'string' + ) { + throw new Error('Project name is required'); + } - const { targets } = await createProjectConfiguration( - projectJson, - createOptions, - ); - return { - projects: { - [projectJson.root]: { - targets, + const projectRoot = dirname(globMatchingFile); + const { targets } = await createProjectConfiguration( + projectConfiguration, + options, + ); + // const codePushupConfigPath = join(projectRoot, 'code-pushup.config.ts'); + // const codePushupConfig = await readFile(codePushupConfigPath, 'utf8'); + console.log('targets', targets); + return { + projects: { + [projectRoot]: { + namedInputs: {}, + targets: { + ...targets, + 'code-pushup': { + command: "node echo 'hello'", + options: { + 'persist.filename': 'code-pushup.json', + }, + }, + }, + }, + }, + }; }, - }, - }; -} + configFiles, + options, + context, + ); + }, +]; diff --git a/packages/nx-plugin/src/plugin/project-config.ts b/packages/nx-plugin/src/plugin/project-config.ts new file mode 100644 index 000000000..a591b626e --- /dev/null +++ b/packages/nx-plugin/src/plugin/project-config.ts @@ -0,0 +1,40 @@ +import type { ProjectConfiguration } from '@nx/devkit'; +import { readFile } from 'node:fs/promises'; +import { dirname, join } from 'node:path'; + +/** + * Project Config is created by reading files and combining the results + * + * @param matchingFilePath + * + * @catch error when the file is not present + * + * @returns Combined PackageNxConfig and ProjectConfiguration fields, and unified targets + */ + +// Project lib-a-e2e is an environment project but has no implicit dependencies. +export async function getProjectConfig(matchingFilePath: string) { + const dirName = dirname(matchingFilePath); + + const projectJson: ProjectConfiguration = await readFile( + join(dirName, 'project.json'), + 'utf8', + ) + .catch(() => '{}') + .then(JSON.parse); + const { nx: pkgProjectJson }: { nx: ProjectConfiguration } = await readFile( + join(dirName, 'package.json'), + 'utf8', + ) + .catch(() => '{}') + .then(JSON.parse); + + return { + ...projectJson, + ...pkgProjectJson, + targets: { + ...projectJson.targets, + ...pkgProjectJson?.targets, + }, + } satisfies ProjectConfiguration; +} diff --git a/packages/nx-plugin/src/plugin/utils.ts b/packages/nx-plugin/src/plugin/utils.ts index 845ed3ad4..eb9f474ab 100644 --- a/packages/nx-plugin/src/plugin/utils.ts +++ b/packages/nx-plugin/src/plugin/utils.ts @@ -1,18 +1,18 @@ -import type {ProjectConfiguration} from '@nx/devkit'; -import {readFile} from 'node:fs/promises'; +import type { CreateNodesContext, ProjectConfiguration } from '@nx/devkit'; +import { readFile } from 'node:fs/promises'; import * as path from 'node:path'; -import {dirname, join} from 'node:path'; -import {createTargets} from './target/targets'; -import type {CreateNodesOptions, NormalizedCreateNodesOptions} from './types'; -import {CP_TARGET_NAME} from './constants.js'; -import type {CreateNodesOptions, NormalizedCreateNodesContext,} from './types.js'; +import { dirname, join } from 'node:path'; +import { CP_TARGET_NAME } from './constants'; +import { createTargets } from './target/targets'; +import type { CreateNodesOptions, NormalizedCreateNodesOptions } from './types'; export async function normalizedCreateNodesContext( context: CreateNodesContext, projectConfigurationFile: string, createOptions: CreateNodesOptions = {}, -): Promise { +) { const projectRoot = path.dirname(projectConfigurationFile); +} export function normalizeCreateNodesOptions( options: unknown = {}, diff --git a/packages/plugin-coverage/package.json b/packages/plugin-coverage/package.json index b2f96ca8e..a95dfcdec 100644 --- a/packages/plugin-coverage/package.json +++ b/packages/plugin-coverage/package.json @@ -1,6 +1,6 @@ { "name": "@code-pushup/coverage-plugin", - "version": "0.64.1", + "version": "0.65.0", "description": "Code PushUp plugin for tracking code coverage β˜‚", "license": "MIT", "homepage": "https://github.com/code-pushup/cli/tree/main/packages/plugin-coverage#readme", @@ -34,8 +34,8 @@ }, "type": "module", "dependencies": { - "@code-pushup/models": "0.64.1", - "@code-pushup/utils": "0.64.1", + "@code-pushup/models": "0.65.0", + "@code-pushup/utils": "0.65.0", "ansis": "^3.3.0", "parse-lcov": "^1.0.4", "yargs": "^17.7.2", diff --git a/packages/plugin-eslint/package.json b/packages/plugin-eslint/package.json index 0f2fbe61d..d48972c10 100644 --- a/packages/plugin-eslint/package.json +++ b/packages/plugin-eslint/package.json @@ -1,6 +1,6 @@ { "name": "@code-pushup/eslint-plugin", - "version": "0.64.1", + "version": "0.65.0", "license": "MIT", "description": "Code PushUp plugin for detecting problems in source code using ESLint.πŸ“‹", "homepage": "https://github.com/code-pushup/cli/tree/main/packages/plugin-eslint#readme", @@ -38,8 +38,8 @@ }, "type": "module", "dependencies": { - "@code-pushup/utils": "0.64.1", - "@code-pushup/models": "0.64.1", + "@code-pushup/utils": "0.65.0", + "@code-pushup/models": "0.65.0", "yargs": "^17.7.2", "zod": "^3.22.4" }, diff --git a/packages/plugin-js-packages/package.json b/packages/plugin-js-packages/package.json index c12db1999..f16262f85 100644 --- a/packages/plugin-js-packages/package.json +++ b/packages/plugin-js-packages/package.json @@ -1,6 +1,6 @@ { "name": "@code-pushup/js-packages-plugin", - "version": "0.64.1", + "version": "0.65.0", "description": "Code PushUp plugin for JavaScript packages πŸ›‘οΈ", "license": "MIT", "homepage": "https://github.com/code-pushup/cli/tree/main/packages/plugin-js-packages#readme", @@ -37,8 +37,8 @@ }, "type": "module", "dependencies": { - "@code-pushup/models": "0.64.1", - "@code-pushup/utils": "0.64.1", + "@code-pushup/models": "0.65.0", + "@code-pushup/utils": "0.65.0", "build-md": "^0.4.1", "semver": "^7.6.0", "yargs": "^17.7.2", diff --git a/packages/plugin-js-packages/src/lib/runner/index.ts b/packages/plugin-js-packages/src/lib/runner/index.ts index e2784e30e..f8bca562d 100644 --- a/packages/plugin-js-packages/src/lib/runner/index.ts +++ b/packages/plugin-js-packages/src/lib/runner/index.ts @@ -78,18 +78,13 @@ async function processOutdated( packageJsonPaths: PackageJsonPaths, ) { const pm = packageManagers[id]; - const { stdout, stderr } = await executeProcess({ + const { stdout } = await executeProcess({ command: pm.command, args: pm.outdated.commandArgs, cwd: process.cwd(), ignoreExitCode: true, // outdated returns exit code 1 when outdated dependencies are found }); - // Successful outdated check has empty stderr - if (stderr) { - throw new Error(`JS packages plugin: outdated error: ${stderr}`); - } - // Locate all package.json files in the repository if not provided const finalPaths = Array.isArray(packageJsonPaths) ? packageJsonPaths @@ -122,16 +117,12 @@ async function processAudit( const auditResults = await Promise.allSettled( compatibleAuditDepGroups.map( async (depGroup): Promise<[DependencyGroup, AuditResult]> => { - const { stdout, stderr } = await executeProcess({ + const { stdout } = await executeProcess({ command: pm.command, args: pm.audit.getCommandArgs(depGroup), cwd: process.cwd(), ignoreExitCode: pm.audit.ignoreExitCode, }); - // Successful audit check has empty stderr - if (stderr) { - throw new Error(`JS packages plugin: audit error: ${stderr}`); - } return [depGroup, pm.audit.unifyResult(stdout)]; }, ), diff --git a/packages/plugin-jsdocs/package.json b/packages/plugin-jsdocs/package.json index 6c1d54e21..49ca6ec48 100644 --- a/packages/plugin-jsdocs/package.json +++ b/packages/plugin-jsdocs/package.json @@ -1,6 +1,6 @@ { "name": "@code-pushup/jsdocs-plugin", - "version": "0.64.1", + "version": "0.65.0", "description": "Code PushUp plugin for tracking documentation coverage πŸ“š", "license": "MIT", "homepage": "https://github.com/code-pushup/cli/tree/main/packages/plugin-jsdocs#readme", @@ -35,8 +35,8 @@ }, "type": "module", "dependencies": { - "@code-pushup/models": "0.64.1", - "@code-pushup/utils": "0.64.1", + "@code-pushup/models": "0.65.0", + "@code-pushup/utils": "0.65.0", "zod": "^3.22.4", "ts-morph": "^24.0.0" } diff --git a/packages/plugin-lighthouse/package.json b/packages/plugin-lighthouse/package.json index 495c905fe..c7884ca25 100644 --- a/packages/plugin-lighthouse/package.json +++ b/packages/plugin-lighthouse/package.json @@ -1,6 +1,6 @@ { "name": "@code-pushup/lighthouse-plugin", - "version": "0.64.1", + "version": "0.65.0", "license": "MIT", "description": "Code PushUp plugin for measuring web performance and quality with Lighthouse πŸ”₯", "homepage": "https://github.com/code-pushup/cli/tree/main/packages/plugin-lighthouse#readme", @@ -36,8 +36,8 @@ }, "type": "module", "dependencies": { - "@code-pushup/models": "0.64.1", - "@code-pushup/utils": "0.64.1", + "@code-pushup/models": "0.65.0", + "@code-pushup/utils": "0.65.0", "ansis": "^3.3.0", "chrome-launcher": "^1.1.1", "lighthouse": "^12.0.0", diff --git a/packages/utils/package.json b/packages/utils/package.json index 7df5dfbee..3b1d8ed24 100644 --- a/packages/utils/package.json +++ b/packages/utils/package.json @@ -1,6 +1,6 @@ { "name": "@code-pushup/utils", - "version": "0.64.1", + "version": "0.65.0", "description": "Low-level utilities (helper functions, etc.) used by Code PushUp CLI", "license": "MIT", "homepage": "https://github.com/code-pushup/cli/tree/main/packages/utils#readme", @@ -27,7 +27,7 @@ "node": ">=17.0.0" }, "dependencies": { - "@code-pushup/models": "0.64.1", + "@code-pushup/models": "0.65.0", "@isaacs/cliui": "^8.0.2", "@poppinss/cliui": "^6.4.0", "ansis": "^3.3.0", diff --git a/packages/utils/src/lib/reports/__snapshots__/generate-md-report-category-section.unit.test.ts.snap b/packages/utils/src/lib/reports/__snapshots__/generate-md-report-category-section.unit.test.ts.snap index d8b4fde36..191eaf9ab 100644 --- a/packages/utils/src/lib/reports/__snapshots__/generate-md-report-category-section.unit.test.ts.snap +++ b/packages/utils/src/lib/reports/__snapshots__/generate-md-report-category-section.unit.test.ts.snap @@ -45,6 +45,17 @@ exports[`categoriesDetailsSection > should render complete categories details 1` " `; +exports[`categoriesDetailsSection > should render filtered categories details > filtered 1`] = ` +"## 🏷 Categories + +### Bug Prevention + +🟒 Score: **100** βœ… + +- 🟩 [No let](#no-let-eslint) (_Eslint_) - **0** +" +`; + exports[`categoriesOverviewSection > should render complete categories table 1`] = ` "| 🏷 Category | ⭐ Score | πŸ›‘ Audits | | :-------------------------------- | :-------: | :-------: | @@ -54,6 +65,13 @@ exports[`categoriesOverviewSection > should render complete categories table 1`] " `; +exports[`categoriesOverviewSection > should render filtered categories table 1`] = ` +"| 🏷 Category | ⭐ Score | πŸ›‘ Audits | +| :-------------------------------- | :--------: | :-------: | +| [Bug Prevention](#bug-prevention) | 🟒 **100** | 1 | +" +`; + exports[`categoriesOverviewSection > should render targetScore icon "❌" if score fails 1`] = ` "| 🏷 Category | ⭐ Score | πŸ›‘ Audits | | :-------------------------------- | :---------: | :-------: | diff --git a/packages/utils/src/lib/reports/generate-md-report-categoy-section.ts b/packages/utils/src/lib/reports/generate-md-report-category-section.ts similarity index 78% rename from packages/utils/src/lib/reports/generate-md-report-categoy-section.ts rename to packages/utils/src/lib/reports/generate-md-report-category-section.ts index 063bc30e3..5cac4a477 100644 --- a/packages/utils/src/lib/reports/generate-md-report-categoy-section.ts +++ b/packages/utils/src/lib/reports/generate-md-report-category-section.ts @@ -4,17 +4,19 @@ import { slugify } from '../formatting.js'; import { HIERARCHY } from '../text-formats/index.js'; import { metaDescription } from './formatting.js'; import { getSortableAuditByRef, getSortableGroupByRef } from './sorting.js'; -import type { ScoredGroup, ScoredReport } from './types.js'; +import type { ScoreFilter, ScoredGroup, ScoredReport } from './types.js'; import { countCategoryAudits, formatReportScore, getPluginNameFromSlug, + scoreFilter, scoreMarker, targetScoreIcon, } from './utils.js'; export function categoriesOverviewSection( report: Required>, + options?: ScoreFilter, ): MarkdownDocument { const { categories, plugins } = report; return new MarkdownDocument().table( @@ -23,26 +25,29 @@ export function categoriesOverviewSection( { heading: '⭐ Score', alignment: 'center' }, { heading: 'πŸ›‘ Audits', alignment: 'center' }, ], - categories.map(({ title, refs, score, isBinary }) => [ - // @TODO refactor `isBinary: boolean` to `targetScore: number` #713 - // The heading "ID" is inferred from the heading text in Markdown. - md.link(`#${slugify(title)}`, title), - md`${scoreMarker(score)} ${md.bold( - formatReportScore(score), - )}${binaryIconSuffix(score, isBinary)}`, - countCategoryAudits(refs, plugins).toString(), - ]), + categories + .filter(scoreFilter(options)) + .map(({ title, refs, score, isBinary }) => [ + // @TODO refactor `isBinary: boolean` to `targetScore: number` #713 + // The heading "ID" is inferred from the heading text in Markdown. + md.link(`#${slugify(title)}`, title), + md`${scoreMarker(score)} ${md.bold( + formatReportScore(score), + )}${binaryIconSuffix(score, isBinary)}`, + countCategoryAudits(refs, plugins).toString(), + ]), ); } export function categoriesDetailsSection( report: Required>, + options?: ScoreFilter, ): MarkdownDocument { const { categories, plugins } = report; - + const isScoreDisplayed = scoreFilter(options); return new MarkdownDocument() .heading(HIERARCHY.level_2, '🏷 Categories') - .$foreach(categories, (doc, category) => + .$foreach(categories.filter(isScoreDisplayed), (doc, category) => doc .heading(HIERARCHY.level_3, category.title) .paragraph(metaDescription(category)) @@ -63,13 +68,17 @@ export function categoriesDetailsSection( ), ); const pluginTitle = getPluginNameFromSlug(ref.plugin, plugins); - return categoryGroupItem(group, groupAudits, pluginTitle); + return isScoreDisplayed(group) + ? categoryGroupItem(group, groupAudits, pluginTitle) + : ''; } // Add audit details else { const audit = getSortableAuditByRef(ref, plugins); const pluginTitle = getPluginNameFromSlug(ref.plugin, plugins); - return categoryRef(audit, pluginTitle); + return isScoreDisplayed(audit) + ? categoryRef(audit, pluginTitle) + : ''; } }), ), diff --git a/packages/utils/src/lib/reports/generate-md-report-category-section.unit.test.ts b/packages/utils/src/lib/reports/generate-md-report-category-section.unit.test.ts index 6afaca2f2..01b00876e 100644 --- a/packages/utils/src/lib/reports/generate-md-report-category-section.unit.test.ts +++ b/packages/utils/src/lib/reports/generate-md-report-category-section.unit.test.ts @@ -6,7 +6,7 @@ import { categoriesOverviewSection, categoryGroupItem, categoryRef, -} from './generate-md-report-categoy-section.js'; +} from './generate-md-report-category-section.js'; import type { ScoredGroup, ScoredReport } from './types.js'; // === Categories Overview Section @@ -49,6 +49,48 @@ describe('categoriesOverviewSection', () => { ).toMatchSnapshot(); }); + it('should render filtered categories table', () => { + expect( + categoriesOverviewSection( + { + plugins: [ + { + slug: 'eslint', + title: 'Eslint', + }, + { + slug: 'lighthouse', + title: 'Lighthouse', + }, + ], + categories: [ + { + slug: 'bug-prevention', + title: 'Bug Prevention', + score: 1, + refs: [{ slug: 'no-let', type: 'audit' }], + }, + { + slug: 'performance', + title: 'Performance', + score: 0.74, + refs: [{ slug: 'largest-contentful-paint', type: 'audit' }], + }, + { + slug: 'typescript', + title: 'Typescript', + score: 0.14, + refs: [{ slug: 'no-any', type: 'audit' }], + }, + ], + } as Required>, + { + isScoreListed: score => score === 1, + }, + ).toString(), + ).toMatchSnapshot(); + }); + it('should render targetScore icon "❌" if score fails', () => { expect( categoriesOverviewSection({ @@ -215,6 +257,68 @@ describe('categoriesDetailsSection', () => { ).toMatchSnapshot(); }); + it('should render filtered categories details', () => { + expect( + categoriesDetailsSection( + { + plugins: [ + { + slug: 'eslint', + title: 'Eslint', + audits: [ + { slug: 'no-let', title: 'No let', score: 1, value: 0 }, + { slug: 'no-any', title: 'No any', score: 0, value: 5 }, + ], + }, + { + slug: 'lighthouse', + title: 'Lighthouse', + audits: [ + { + slug: 'largest-contentful-paint', + title: 'Largest Contentful Paint', + score: 0.7, + value: 2905, + }, + ], + }, + ], + categories: [ + { + slug: 'bug-prevention', + title: 'Bug Prevention', + score: 1, + isBinary: true, + refs: [{ slug: 'no-let', type: 'audit', plugin: 'eslint' }], + }, + { + slug: 'performance', + title: 'Performance', + score: 0.74, + refs: [ + { + slug: 'largest-contentful-paint', + type: 'audit', + plugin: 'lighthouse', + }, + ], + }, + { + slug: 'typescript', + title: 'Typescript', + score: 0.14, + isBinary: true, + refs: [{ slug: 'no-any', type: 'audit', plugin: 'eslint' }], + }, + ], + } as Required>, + { + isScoreListed: score => score === 1, + }, + ).toString(), + ).toMatchSnapshot('filtered'); + }); + it('should render categories details and add "❌" when isBinary is failing', () => { expect( categoriesDetailsSection({ diff --git a/packages/utils/src/lib/reports/generate-md-report.ts b/packages/utils/src/lib/reports/generate-md-report.ts index 3ae8b1c7d..c452b22f6 100644 --- a/packages/utils/src/lib/reports/generate-md-report.ts +++ b/packages/utils/src/lib/reports/generate-md-report.ts @@ -16,9 +16,14 @@ import { import { categoriesDetailsSection, categoriesOverviewSection, -} from './generate-md-report-categoy-section.js'; +} from './generate-md-report-category-section.js'; import type { MdReportOptions, ScoredReport } from './types.js'; -import { formatReportScore, scoreMarker, severityMarker } from './utils.js'; +import { + formatReportScore, + scoreFilter, + scoreMarker, + severityMarker, +} from './utils.js'; export function auditDetailsAuditValue({ score, @@ -30,6 +35,10 @@ export function auditDetailsAuditValue({ )} (score: ${formatReportScore(score)})`; } +/** + * Check if the report has categories. + * @param report + */ function hasCategories( report: ScoredReport, ): report is ScoredReport & Required> { @@ -44,7 +53,10 @@ export function generateMdReport( .heading(HIERARCHY.level_1, REPORT_HEADLINE_TEXT) .$concat( ...(hasCategories(report) - ? [categoriesOverviewSection(report), categoriesDetailsSection(report)] + ? [ + categoriesOverviewSection(report, options), + categoriesDetailsSection(report, options), + ] : []), auditsSection(report, options), aboutSection(report), @@ -110,11 +122,14 @@ export function auditsSection( { plugins }: Pick, options?: MdReportOptions, ): MarkdownDocument { + const isScoreDisplayed = scoreFilter(options); return new MarkdownDocument() .heading(HIERARCHY.level_2, 'πŸ›‘οΈ Audits') .$foreach( plugins.flatMap(plugin => - plugin.audits.map(audit => ({ ...audit, plugin })), + plugin.audits + .filter(isScoreDisplayed) + .map(audit => ({ ...audit, plugin })), ), (doc, { plugin, ...audit }) => { const auditTitle = `${audit.title} (${plugin.title})`; diff --git a/packages/utils/src/lib/reports/generate-md-report.unit.test.ts b/packages/utils/src/lib/reports/generate-md-report.unit.test.ts index bc870837f..671f6b4b8 100644 --- a/packages/utils/src/lib/reports/generate-md-report.unit.test.ts +++ b/packages/utils/src/lib/reports/generate-md-report.unit.test.ts @@ -47,6 +47,54 @@ const baseScoredReport = { ], } as ScoredReport; +const baseScoredReport2 = { + date: '2025.01.01', + duration: 4200, + version: 'v1.0.0', + commit: { + message: 'ci: update action', + author: 'Michael ', + date: new Date('2025.01.01'), + hash: '535b8e9e557336618a764f3fa45609d224a62837', + }, + plugins: [ + { + slug: 'lighthouse', + version: '1.0.1', + duration: 15_365, + title: 'Lighthouse', + audits: [ + { + slug: 'largest-contentful-paint', + title: 'Largest Contentful Paint', + score: 0.6, + value: 2700, + }, + { + slug: 'cumulative-layout-shift', + title: 'Cumulative Layout Shift', + score: 1, + value: 0, + }, + ], + }, + ], + categories: [ + { + title: 'Speed', + slug: 'speed', + score: 0.93, + refs: [{ slug: 'largest-contentful-paint', plugin: 'lighthouse' }], + }, + { + title: 'Visual Stability', + slug: 'visual-stability', + score: 1, + refs: [{ slug: 'cumulative-layout-shift', plugin: 'lighthouse' }], + }, + ], +} as ScoredReport; + // === Audit Details describe('auditDetailsAuditValue', () => { @@ -359,6 +407,22 @@ describe('auditsSection', () => { ).toMatch('🟩 **0** (score: 100)'); }); + it('should render filtered result', () => { + const auditSection = auditsSection( + { + plugins: [ + { audits: [{ score: 1, value: 0 }] }, + { audits: [{ score: 0, value: 1 }] }, + ], + } as ScoredReport, + { + isScoreListed: (score: number) => score === 1, + }, + ).toString(); + expect(auditSection).toMatch('(score: 100)'); + expect(auditSection).not.toMatch('(score: 0)'); + }); + it('should render audit details', () => { const md = auditsSection({ plugins: [ @@ -580,6 +644,18 @@ describe('generateMdReport', () => { expect(md).toMatch('Made with ❀ by [Code PushUp]'); }); + it('should render sections filtered by isScoreListed of the report', () => { + const md = generateMdReport(baseScoredReport2, { + isScoreListed: (score: number) => score === 1, + }); + + expect(md).toMatch('Visual Stability'); + expect(md).toMatch('Cumulative Layout Shift'); + + expect(md).not.toMatch('Speed'); + expect(md).not.toMatch('Largest Contentful Paint'); + }); + it('should skip categories section when categories are missing', () => { const md = generateMdReport({ ...baseScoredReport, categories: undefined }); expect(md).not.toMatch('## 🏷 Categories'); diff --git a/packages/utils/src/lib/reports/types.ts b/packages/utils/src/lib/reports/types.ts index 1c89d5986..a79059db0 100644 --- a/packages/utils/src/lib/reports/types.ts +++ b/packages/utils/src/lib/reports/types.ts @@ -32,7 +32,11 @@ export type SortableAuditReport = AuditReport & { export type DiffOutcome = 'positive' | 'negative' | 'mixed' | 'unchanged'; -export type MdReportOptions = Pick; +export type ScoreFilter = { + isScoreListed?: (score: number) => boolean; +}; + +export type MdReportOptions = Pick & ScoreFilter; export const SUPPORTED_ENVIRONMENTS = [ 'vscode', diff --git a/packages/utils/src/lib/reports/utils.ts b/packages/utils/src/lib/reports/utils.ts index 7dfaba833..fbb0aec0f 100644 --- a/packages/utils/src/lib/reports/utils.ts +++ b/packages/utils/src/lib/reports/utils.ts @@ -10,11 +10,19 @@ import type { } from '@code-pushup/models'; import { SCORE_COLOR_RANGE } from './constants.js'; import type { + ScoreFilter, ScoredReport, SortableAuditReport, SortableGroup, } from './types.js'; +export function scoreFilter( + options?: ScoreFilter, +) { + const { isScoreListed = () => true } = options ?? {}; + return ({ score }: T) => isScoreListed(score); +} + export function formatReportScore(score: number): string { const scaledScore = score * 100; const roundedScore = Math.round(scaledScore); diff --git a/packages/utils/src/lib/reports/utils.unit.test.ts b/packages/utils/src/lib/reports/utils.unit.test.ts index 965807a35..087edb82a 100644 --- a/packages/utils/src/lib/reports/utils.unit.test.ts +++ b/packages/utils/src/lib/reports/utils.unit.test.ts @@ -26,11 +26,24 @@ import { formatValueChange, getPluginNameFromSlug, roundValue, + scoreFilter, scoreMarker, severityMarker, targetScoreIcon, } from './utils.js'; +describe('scoreFilter', () => { + it('should not filter by score if no options are passed', () => { + expect(scoreFilter()({ score: 0 })).toBe(true); + }); + + it('should filter by score if options are passed', () => { + expect( + scoreFilter({ isScoreListed: score => score === 0.5 })({ score: 0 }), + ).toBe(false); + }); +}); + describe('formatReportScore', () => { it.each([ [0, '0'], diff --git a/packages/utils/src/lib/transform.ts b/packages/utils/src/lib/transform.ts index f33aaa40e..86caf9aef 100644 --- a/packages/utils/src/lib/transform.ts +++ b/packages/utils/src/lib/transform.ts @@ -114,9 +114,19 @@ export function toUnixNewlines(text: string): string { return platform() === 'win32' ? text.replace(/\r\n/g, '\n') : text; } -export function fromJsonLines(jsonLines: string) { +export function fromJsonLines(jsonLines: string) { const unifiedNewLines = toUnixNewlines(jsonLines).trim(); - return JSON.parse(`[${unifiedNewLines.split('\n').join(',')}]`) as T; + const invalid = Symbol('invalid json'); + return unifiedNewLines + .split('\n') + .map(line => { + try { + return JSON.parse(line); + } catch { + return invalid; + } + }) + .filter(line => line !== invalid) as T; } export function toJsonLines(json: T[]) { diff --git a/packages/utils/src/lib/transform.unit.test.ts b/packages/utils/src/lib/transform.unit.test.ts index d4ad2cfcf..b72982e3d 100644 --- a/packages/utils/src/lib/transform.unit.test.ts +++ b/packages/utils/src/lib/transform.unit.test.ts @@ -258,6 +258,17 @@ describe('JSON lines format', () => { expect(fromJsonLines(jsonLines)).toEqual([head, body]); }); + + it('should ignore non-JSON lines', () => { + const jsonLines = [ + '(node:346640) [DEP0040] DeprecationWarning: The `punycode` module is deprecated. Please use a userland alternative instead.', + '(Use `node --trace-deprecation ...` to show where the warning was created)', + JSON.stringify(head), + JSON.stringify(body), + ].join('\n'); + + expect(fromJsonLines(jsonLines)).toEqual([head, body]); + }); }); describe('toJsonLines', () => {