-
Notifications
You must be signed in to change notification settings - Fork 465
feat(nx-plugin): enforce module boundaries on new arch #16803
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from 3 commits
Commits
Show all changes
6 commits
Select commit
Hold shift + click to select a range
ed40779
feat(nx-plugin): infer boundary tags for new-arch packages
ysitbon cff540c
feat(nx-plugin): enforce module boundaries via project graph
ysitbon 43683f1
chore: address PR review — de-dup tag inference, dedicated boundary c…
ysitbon a61c52f
fix(nx-plugin): dedupe boundary violations per source/target edge
ysitbon 2e4ad31
chore: restore workflow pin version to develop
ysitbon 7c4b507
chore: delete unecessary changeset
ysitbon File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Some comments aren't visible on the classic Files Changed page.
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,12 @@ | ||
| --- | ||
| "@domain/entity-currency": minor | ||
| "@domain/entity-currency-crypto": minor | ||
| "@domain/entity-currency-fiat": minor | ||
| "@domain/entity-currency-token": minor | ||
| "@domain/entity-currency-unit": minor | ||
| "@shared/feature-flags": minor | ||
| "@shared/schema-primitives": minor | ||
| "@features/market-banner": minor | ||
| --- | ||
|
|
||
| Enforce module boundaries on the new architecture (`domain/`, `shared/`, `features/`) via a pure Nx project-graph validator (LIVE-29780). The project-tags plugin now infers `scope:domain`, `scope:shared`, `type:domain-entity`, and `type:domain-api`; a cacheable `lint:boundaries` Nx target walks the graph and fails CI on any workspace→workspace edge that violates the layered rules (shared leaf, domain depends on shared, features depend on domain+shared, entities cannot import APIs). No ESLint involvement — stays aligned with the ongoing oxlint migration; config ports verbatim to `.oxlintrc.json` when `@nx/oxlint` publishes stable. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,49 @@ | ||
| name: "[Module Boundaries] - Test - Called" | ||
|
|
||
| on: | ||
| workflow_call: | ||
| workflow_dispatch: | ||
| inputs: | ||
| ref: | ||
| description: | | ||
| If you run this manually, and want to run on a PR, the correct ref should be refs/pull/{PR_NUMBER}/merge to | ||
| have the "normal" scenario involving checking out a merge commit between your branch and the base branch. | ||
| If you want to run only on a branch or specific commit, you can use either the sha or the branch name instead (prefer the first version for PRs). | ||
| required: false | ||
|
|
||
| permissions: | ||
| id-token: write | ||
| contents: read | ||
|
|
||
| jobs: | ||
| enforce-boundaries: | ||
| name: Enforce Module Boundaries | ||
| runs-on: ubuntu-22.04 | ||
| timeout-minutes: 10 | ||
| env: | ||
| NODE_OPTIONS: "--max-old-space-size=4096" | ||
| CI_OS: ubuntu-22.04 | ||
| steps: | ||
| - name: Checkout | ||
| uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 | ||
| with: | ||
| ref: ${{ inputs.ref || github.sha }} | ||
|
|
||
| - name: Setup the caches | ||
| uses: LedgerHQ/ledger-live/tools/actions/composites/setup-caches@develop | ||
| id: setup-caches | ||
| with: | ||
| use-mise: true | ||
| gh-token: ${{ secrets.GITHUB_TOKEN }} | ||
| cache-develop-role-arn: ${{ secrets.AWS_CACHE_OIDC_ROLE_ARN_DEVELOP }} | ||
| cache-branch-role-arn: ${{ secrets.AWS_CACHE_OIDC_ROLE_ARN_BRANCH }} | ||
| nx-key: ${{ secrets.NX_KEY }} | ||
| accountId: ${{ secrets.AWS_ACCOUNT_ID_PROD }} | ||
| roleName: ${{ secrets.AWS_CACHE_ROLE_NAME }} | ||
| region: ${{ secrets.AWS_CACHE_REGION }} | ||
|
|
||
| - name: Install dependencies | ||
| run: pnpm i | ||
|
|
||
| - name: Enforce module boundaries | ||
| run: pnpm exec nx run enforce-boundaries:lint:boundaries | ||
|
ysitbon marked this conversation as resolved.
|
||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,30 @@ | ||
| "use strict"; | ||
|
|
||
| /** | ||
| * Module-boundary dependency constraints for the new architecture | ||
| * (domain/, shared/, features/). Shape mirrors @nx/enforce-module-boundaries | ||
| * depConstraints so this config ports verbatim to .oxlintrc.json when | ||
| * @nx/oxlint publishes stable. | ||
| * | ||
| * A rule fires only when the source package has the sourceTag. Legacy | ||
| * packages without matching tags (libs/, apps/, e2e/, tools/) are | ||
| * unconstrained on purpose. | ||
| */ | ||
| const DEP_CONSTRAINTS = [ | ||
| { sourceTag: "scope:shared", onlyDependOnLibsWithTags: ["scope:shared"] }, | ||
| { sourceTag: "scope:domain", onlyDependOnLibsWithTags: ["scope:domain", "scope:shared"] }, | ||
| { | ||
| sourceTag: "scope:features", | ||
| onlyDependOnLibsWithTags: ["scope:features", "scope:domain", "scope:shared"], | ||
| }, | ||
| { | ||
| sourceTag: "type:domain-entity", | ||
| onlyDependOnLibsWithTags: ["type:domain-entity", "scope:shared"], | ||
| }, | ||
| { | ||
| sourceTag: "type:domain-api", | ||
| onlyDependOnLibsWithTags: ["type:domain-entity", "type:domain-api", "scope:shared"], | ||
|
ysitbon marked this conversation as resolved.
|
||
| }, | ||
| ]; | ||
|
|
||
| module.exports = { DEP_CONSTRAINTS }; | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,26 @@ | ||
| { | ||
| "$schema": "../../../node_modules/nx/schemas/project-schema.json", | ||
| "name": "enforce-boundaries", | ||
| "projectType": "library", | ||
| "targets": { | ||
| "lint:boundaries": { | ||
| "executor": "nx:run-commands", | ||
| "cache": true, | ||
| "inputs": [ | ||
| "{workspaceRoot}/tools/nx-plugins/enforce-boundaries/**/*", | ||
| "{workspaceRoot}/tools/nx-plugins/project-tags/plugin.js", | ||
| "{workspaceRoot}/domain/**/package.json", | ||
| "{workspaceRoot}/shared/**/package.json", | ||
| "{workspaceRoot}/features/**/package.json", | ||
| "{workspaceRoot}/apps/**/package.json", | ||
| "{workspaceRoot}/libs/**/package.json", | ||
| "{workspaceRoot}/pnpm-workspace.yaml", | ||
|
ysitbon marked this conversation as resolved.
|
||
| "{workspaceRoot}/nx.cache-config.json" | ||
| ], | ||
| "options": { | ||
| "cwd": "{workspaceRoot}", | ||
| "command": "node tools/nx-plugins/enforce-boundaries/validate.js" | ||
| } | ||
| } | ||
| } | ||
| } | ||
|
LL782 marked this conversation as resolved.
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,72 @@ | ||
| "use strict"; | ||
|
|
||
| const { createProjectGraphAsync } = require("@nx/devkit"); | ||
| const { DEP_CONSTRAINTS } = require("./constraints"); | ||
|
|
||
| /** | ||
| * @typedef {{ data?: { tags?: string[] } }} GraphNode | ||
| * @typedef {{ target: string }} GraphEdge | ||
| * @typedef {{ nodes: Record<string, GraphNode>, dependencies: Record<string, GraphEdge[]> }} ProjectGraphLike | ||
| * @typedef {{ sourceName: string, sourceTag: string, target: string, targetTags: string[] }} Violation | ||
| */ | ||
|
|
||
| /** | ||
| * Walk the Nx project graph and collect every edge that violates the | ||
| * DEP_CONSTRAINTS rules. Exported for unit testing against a synthetic graph. | ||
| * | ||
| * @param {ProjectGraphLike} graph | ||
| * @returns {Violation[]} | ||
| */ | ||
| function findViolations(graph) { | ||
| const violations = []; | ||
|
|
||
| for (const [sourceName, edges] of Object.entries(graph.dependencies)) { | ||
| const sourceNode = graph.nodes[sourceName]; | ||
| if (!sourceNode) continue; | ||
| const sourceTags = sourceNode.data?.tags ?? []; | ||
|
|
||
| for (const edge of edges) { | ||
| const targetNode = graph.nodes[edge.target]; | ||
| if (!targetNode) continue; // external / npm targets carry no tags; skip | ||
| const targetTags = targetNode.data?.tags ?? []; | ||
|
|
||
| for (const { sourceTag, onlyDependOnLibsWithTags } of DEP_CONSTRAINTS) { | ||
| if (!sourceTags.includes(sourceTag)) continue; | ||
| const allowed = targetTags.some(t => onlyDependOnLibsWithTags.includes(t)); | ||
| if (!allowed) { | ||
| violations.push({ sourceName, sourceTag, target: edge.target, targetTags }); | ||
| } | ||
|
ysitbon marked this conversation as resolved.
|
||
| } | ||
| } | ||
| } | ||
|
|
||
| return violations; | ||
| } | ||
|
|
||
| async function main() { | ||
| const graph = await createProjectGraphAsync({ exitOnError: true }); | ||
| const violations = findViolations(graph); | ||
|
|
||
| if (violations.length > 0) { | ||
| console.error(`\n✗ ${violations.length} module-boundary violation(s):\n`); | ||
| for (const v of violations) { | ||
| const tgtTags = v.targetTags.length > 0 ? v.targetTags.join(", ") : "untagged"; | ||
| console.error(` ${v.sourceName} [${v.sourceTag}] → ${v.target} [${tgtTags}]`); | ||
| } | ||
| console.error( | ||
| "\nAllowed edges are defined in tools/nx-plugins/enforce-boundaries/constraints.js\n", | ||
| ); | ||
| process.exit(1); | ||
| } | ||
|
|
||
| console.log("✓ module boundaries ok"); | ||
| } | ||
|
|
||
| module.exports = { findViolations }; | ||
|
|
||
| if (require.main === module) { | ||
| main().catch(err => { | ||
| console.error(err); | ||
| process.exit(1); | ||
| }); | ||
| } | ||
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.