Build: Detect circular dependencies with Madge (#17924)
* feat: adds script to run madge in a CI environment * build: adds check for circular dependencies * build: move actions higher up * build: only print annotation once * build: make script not fail CI until dependencies are fixed
This commit is contained in:
2
.github/workflows/test-backoffice.yml
vendored
2
.github/workflows/test-backoffice.yml
vendored
@@ -40,6 +40,8 @@ jobs:
|
|||||||
cache: npm
|
cache: npm
|
||||||
cache-dependency-path: ./src/Umbraco.Web.UI.Client/package-lock.json
|
cache-dependency-path: ./src/Umbraco.Web.UI.Client/package-lock.json
|
||||||
- run: npm ci --no-audit --no-fund --prefer-offline
|
- run: npm ci --no-audit --no-fund --prefer-offline
|
||||||
|
- name: Check for circular dependencies
|
||||||
|
run: node devops/circular/index.js src
|
||||||
- run: npm run lint:errors
|
- run: npm run lint:errors
|
||||||
- run: npm run build:for:cms
|
- run: npm run build:for:cms
|
||||||
- run: npm run check:paths
|
- run: npm run check:paths
|
||||||
|
|||||||
75
src/Umbraco.Web.UI.Client/devops/circular/index.js
Normal file
75
src/Umbraco.Web.UI.Client/devops/circular/index.js
Normal file
@@ -0,0 +1,75 @@
|
|||||||
|
/**
|
||||||
|
* This module is used to detect circular dependencies in the Umbraco backoffice.
|
||||||
|
* It is used in the build process to ensure that we don't have circular dependencies.
|
||||||
|
* @example node devops/circular/index.js src
|
||||||
|
* @author Umbraco HQ
|
||||||
|
*/
|
||||||
|
|
||||||
|
import madge from 'madge';
|
||||||
|
import { join } from 'path';
|
||||||
|
import { mkdirSync } from 'fs';
|
||||||
|
|
||||||
|
const __dirname = import.meta.dirname;
|
||||||
|
const IS_GITHUB_ACTIONS = process.env.GITHUB_ACTIONS === 'true';
|
||||||
|
const IS_AZURE_PIPELINES = process.env.TF_BUILD === 'true';
|
||||||
|
const baseDir = process.argv[2] || 'src';
|
||||||
|
const specificPaths = (process.argv[3] || '').split(',');
|
||||||
|
|
||||||
|
console.log('Scanning for circular dependencies in:', baseDir);
|
||||||
|
|
||||||
|
const madgeSetup = await madge(specificPaths, {
|
||||||
|
baseDir,
|
||||||
|
fileExtensions: ['ts'],
|
||||||
|
tsConfig: join(baseDir, 'tsconfig.build.json'),
|
||||||
|
detectiveOptions: {
|
||||||
|
ts: {
|
||||||
|
skipTypeImports: true,
|
||||||
|
skipAsyncImports: true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
console.log('-'.repeat(80));
|
||||||
|
|
||||||
|
const circular = madgeSetup.circular();
|
||||||
|
|
||||||
|
if (circular.length) {
|
||||||
|
console.error(circular.length, 'circular dependencies detected:\n');
|
||||||
|
for (let i = 0; i < circular.length; i++) {
|
||||||
|
printCircularDependency(circular[i], i + 1);
|
||||||
|
}
|
||||||
|
console.error('\nPlease fix the circular dependencies before proceeding.\n');
|
||||||
|
|
||||||
|
try {
|
||||||
|
const imagePath = join(__dirname, '../../madge');
|
||||||
|
mkdirSync(imagePath, { recursive: true });
|
||||||
|
const image = await madgeSetup.image(join(imagePath, 'circular.svg'), true);
|
||||||
|
console.log('Circular dependencies graph generated:', image);
|
||||||
|
} catch { console.warn('No image generated. Make sure Graphviz is in your $PATH if you want a visualization'); }
|
||||||
|
|
||||||
|
// TODO: Set this to 1 when we have fixed all circular dependencies
|
||||||
|
process.exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('\nNo circular dependencies detected.\n');
|
||||||
|
process.exit(0);
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param {string[]} circular The circular dependencies.
|
||||||
|
* @param {number} idx The index of the circular dependency.
|
||||||
|
*/
|
||||||
|
function printCircularDependency(circular, idx) {
|
||||||
|
circular = circular.map(file => `${baseDir}/${file}`);
|
||||||
|
const circularPath = circular.join(' -> ');
|
||||||
|
|
||||||
|
if (IS_GITHUB_ACTIONS) {
|
||||||
|
console.error(`::error file=${circular[0]},title=Circular dependency::Circular dependencies detected: ${circularPath}`);
|
||||||
|
}
|
||||||
|
else if (IS_AZURE_PIPELINES) {
|
||||||
|
console.error(`##vso[task.logissue type=error;sourcepath=${circular[0]};]Circular dependencies detected: ${circularPath}`);
|
||||||
|
} else {
|
||||||
|
console.error(idx, '=', circularPath, '\n');
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -158,7 +158,7 @@
|
|||||||
"postbuild": "rollup -c ./src/rollup.config.js && node ./devops/build/global-types.js",
|
"postbuild": "rollup -c ./src/rollup.config.js && node ./devops/build/global-types.js",
|
||||||
"check": "npm run lint:errors && npm run compile && npm run build-storybook && npm run generate:jsonschema:dist",
|
"check": "npm run lint:errors && npm run compile && npm run build-storybook && npm run generate:jsonschema:dist",
|
||||||
"check:paths": "node ./devops/build/check-path-length.js dist-cms 120",
|
"check:paths": "node ./devops/build/check-path-length.js dist-cms 120",
|
||||||
"check:circular": "madge --circular --warning --extensions ts ./src",
|
"check:circular": "node ./devops/circular/index.js src",
|
||||||
"compile": "tsc",
|
"compile": "tsc",
|
||||||
"dev": "vite",
|
"dev": "vite",
|
||||||
"dev:server": "cross-env VITE_UMBRACO_USE_MSW=off vite",
|
"dev:server": "cross-env VITE_UMBRACO_USE_MSW=off vite",
|
||||||
|
|||||||
Reference in New Issue
Block a user