diff --git a/.gitignore b/.gitignore index 633a849347276..b31b96ae6443b 100644 --- a/.gitignore +++ b/.gitignore @@ -40,14 +40,13 @@ out # Local dev files .env.local .bashrc -.nx *.node # Fix for issue when working on the repo in a dev container .pnpm-store -.nx/cache -.nx/workspace-data +.nx +!.nx/workflows .cargo/.package-cache .cargo/bin/ @@ -61,4 +60,4 @@ target *.wasm /wasi-sdk* -vite.config.*.timestamp* \ No newline at end of file +vite.config.*.timestamp* diff --git a/.nx/workflows/agents.yaml b/.nx/workflows/agents.yaml index 4b136c16b6ae6..2b00aa184b2bc 100644 --- a/.nx/workflows/agents.yaml +++ b/.nx/workflows/agents.yaml @@ -38,7 +38,7 @@ launch-templates: - name: Install Browsers script: | pnpm exec cypress install - pnpm exec playwright install + pnpm exec playwright install --with-deps - name: Install Rust script: | @@ -95,7 +95,7 @@ launch-templates: - name: Install Browsers script: | pnpm exec cypress install - pnpm exec playwright install + pnpm exec playwright install --with-deps - name: Install Rust script: | diff --git a/community/approved-plugins.json b/community/approved-plugins.json index c978f8d561fa4..56417001c4413 100644 --- a/community/approved-plugins.json +++ b/community/approved-plugins.json @@ -503,5 +503,10 @@ "name": "nx-solhint", "description": "Solhint generators and inferred tasks for Nx", "url": "https://github.com/juliangsibecas/nx-solhint" + }, + { + "name": "nx-foundry", + "description": "Foundry generators and inferred tasks for Nx", + "url": "https://github.com/juliangsibecas/nx-foundry" } ] diff --git a/docs/blog/2024-02-09-versioning-and-releasing-packages.md b/docs/blog/2024-02-09-versioning-and-releasing-packages.md index c6ccb756d6eb5..61d3c5a670e8e 100644 --- a/docs/blog/2024-02-09-versioning-and-releasing-packages.md +++ b/docs/blog/2024-02-09-versioning-and-releasing-packages.md @@ -188,7 +188,7 @@ It also generates a nice `CHANGELOG.md` for us: - **buttons:** add new background shadow -### ❤️ Thank You +### ❤️ Thank You - Juri diff --git a/docs/blog/2024-11-19-ci-affected-graph.md b/docs/blog/2024-11-19-ci-affected-graph.md new file mode 100644 index 0000000000000..fdc14968fb38a --- /dev/null +++ b/docs/blog/2024-11-19-ci-affected-graph.md @@ -0,0 +1,54 @@ +--- +title: See your affected project graph in Nx Cloud +slug: ci-affected-graph +authors: ['Philip Fulcher'] +tags: [nx-cloud] +cover_image: /blog/images/2024-11-19/header.avif +youtubeUrl: https://youtu.be/TS-Fp2iSlVM +--- + +As monorepos grow in size and complexity, it can be difficult to understand the relationships between different parts of +your codebase. That's why Nx has the [graph visualization](/features/explore-graph) that helps you see the different +connections between projects and tasks in your workspace. But that runs locally, and sometimes you need to see that same graph from your CI's perspective. Now you can do that with the affected project graph in Nx Cloud. + +## More insight into CI tasks + +The CLI project graph visualization can give you some information about what projects or tasks are affected by your changes. But +CI may run different tasks than you do locally, or compare to different branches for affected calculations. So you often +feel like you're passing your work off to a black box with no insight into why a project is marked as affected on CI. + +What do we mean by "marked as affected?" In a monorepo, running all your tasks, all the time, quickly becomes untenable. You'll either be wasting time waiting for tasks to finish, or spending a fortune on runners powerful enough to run in a timely manner. Instead, Nx analyzes the structure of your workspace and understands the relationship between different projects. When you run [`affected`](/ci/features/affected) tasks, it traces the projects that are actually affected by the change. For example, if you've made changes to a single app, Nx only marks that app as affected and doesn't run tasks for any other app. + +## How do I use it? + +The affected project graph is available on all CI Pipeline Executions (CIPEs) in Nx Cloud. Click the new "Affected Project Graph" link at the top of your CIPE view. + +![Screenshot of CI affected project graph on Nx Cloud](/blog/images/2024-11-19/screenshot.avif) + +The affected project graph uses the new [Composite Graph](/features/explore-graph#focusing-on-valuable-projects) introduced in Nx 20. +Groups of projects are collapsed into a single node on the graph based on directories. You can expand those nodes to see +inside by double-clicking them, or by clicking on the node and then clicking "Expand". + +You can explore affected project graphs on your own on the +public [Nx OSS workspace](https://staging.nx.app/orgs/62d013d4d26f260059f7765e/workspaces/62d013ea0852fe0a2df74438/overview). + +We've put together an example of one problem you can solve using this new view: [reducing the number of affected projects on CI](/ci/recipes/other/cipe-affected-project-graph). + +## Get started with Nx Cloud + +Not an Nx Cloud user? You can get started today, for free! + +{% call-to-action title="Get started with Nx Cloud" url="/nx-cloud" icon="nxcloud" description="Try Nx Cloud for Free" %} +Get started with Nx Cloud +{% /call-to-action %} + +## Learn more + +- [Recipe: Reduce the Number of Affected Projects in a CI Pipeline Execution](/ci/recipes/other/cipe-affected-project-graph) +- [Nx Docs](/getting-started/intro) +- [X/Twitter](https://twitter.com/nxdevtools) +- [LinkedIn](https://www.linkedin.com/company/nrwl/) +- [Nx GitHub](https://github.com/nrwl/nx) +- [Nx Official Discord Server](https://go.nx.dev/community) +- [Nx Youtube Channel](https://www.youtube.com/@nxdevtools) +- [Speed up your CI](/nx-cloud) diff --git a/docs/blog/images/2024-11-19/header.avif b/docs/blog/images/2024-11-19/header.avif new file mode 100644 index 0000000000000..4badd86b4b639 Binary files /dev/null and b/docs/blog/images/2024-11-19/header.avif differ diff --git a/docs/blog/images/2024-11-19/header.png b/docs/blog/images/2024-11-19/header.png new file mode 100644 index 0000000000000..511727f362856 Binary files /dev/null and b/docs/blog/images/2024-11-19/header.png differ diff --git a/docs/blog/images/2024-11-19/screenshot.avif b/docs/blog/images/2024-11-19/screenshot.avif new file mode 100644 index 0000000000000..ec28520b3d9dd Binary files /dev/null and b/docs/blog/images/2024-11-19/screenshot.avif differ diff --git a/docs/external-generated/packages-metadata.json b/docs/external-generated/packages-metadata.json index ff64b85ac8027..9b050f6234940 100644 --- a/docs/external-generated/packages-metadata.json +++ b/docs/external-generated/packages-metadata.json @@ -39,12 +39,12 @@ ], "executors": [ { - "description": "Compile and bundle an Nx Conformance Rule", - "file": "external-generated/packages/powerpack-conformance/executors/bundle-rule.json", + "description": "Compile and bundle one or more Nx Conformance Rules", + "file": "external-generated/packages/powerpack-conformance/executors/bundle-rules.json", "hidden": false, - "name": "bundle-rule", - "originalFilePath": "/libs/nx-packages/powerpack-conformance/src/executors/bundle-rule/schema.json", - "path": "powerpack-conformance/executors/bundle-rule", + "name": "bundle-rules", + "originalFilePath": "/libs/nx-packages/powerpack-conformance/src/executors/bundle-rules/schema.json", + "path": "powerpack-conformance/executors/bundle-rules", "type": "executor" } ], diff --git a/docs/external-generated/packages/powerpack-conformance/executors/bundle-rules.json b/docs/external-generated/packages/powerpack-conformance/executors/bundle-rules.json new file mode 100644 index 0000000000000..58aede4eaba70 --- /dev/null +++ b/docs/external-generated/packages/powerpack-conformance/executors/bundle-rules.json @@ -0,0 +1,24 @@ +{ + "name": "bundle-rules", + "implementation": "/libs/nx-packages/powerpack-conformance/src/executors/bundle-rules/executor.ts", + "schema": { + "$schema": "https://json-schema.org/schema", + "version": 2, + "title": "BundleNxConformanceRules", + "description": "Compile and bundle one or more Nx Conformance Rules", + "type": "object", + "properties": { + "outputPath": { + "type": "string", + "description": "The output path for the bundled rules to be written to" + } + }, + "required": ["outputPath"], + "presets": [] + }, + "description": "Compile and bundle one or more Nx Conformance Rules", + "aliases": [], + "hidden": false, + "path": "/libs/nx-packages/powerpack-conformance/src/executors/bundle-rules/schema.json", + "type": "executor" +} diff --git a/docs/generated/manifests/ci.json b/docs/generated/manifests/ci.json index 6a04727ea49dc..87360ecb883a9 100644 --- a/docs/generated/manifests/ci.json +++ b/docs/generated/manifests/ci.json @@ -847,6 +847,40 @@ "isExternal": false, "path": "/ci/recipes/enterprise/dte", "tags": [] + }, + { + "id": "conformance", + "name": "Conformance", + "description": "Conformance features that are available to Nx Cloud Enterprise customers", + "mediaImage": "", + "file": "", + "itemList": [ + { + "id": "configure-conformance-rules-in-nx-cloud", + "name": "Configure Conformance Rules in Nx Cloud", + "description": "", + "mediaImage": "", + "file": "nx-cloud/enterprise/conformance/configure-conformance-rules-in-nx-cloud", + "itemList": [], + "isExternal": false, + "path": "/ci/recipes/enterprise/conformance/configure-conformance-rules-in-nx-cloud", + "tags": ["conformance"] + }, + { + "id": "publish-conformance-rules-to-nx-cloud", + "name": "Publish Conformance Rules to Nx Cloud", + "description": "", + "mediaImage": "", + "file": "nx-cloud/enterprise/conformance/publish-conformance-rules-to-nx-cloud", + "itemList": [], + "isExternal": false, + "path": "/ci/recipes/enterprise/conformance/publish-conformance-rules-to-nx-cloud", + "tags": ["conformance"] + } + ], + "isExternal": false, + "path": "/ci/recipes/enterprise/conformance", + "tags": [] } ], "isExternal": false, @@ -1420,6 +1454,40 @@ "isExternal": false, "path": "/ci/recipes/enterprise/dte", "tags": [] + }, + { + "id": "conformance", + "name": "Conformance", + "description": "Conformance features that are available to Nx Cloud Enterprise customers", + "mediaImage": "", + "file": "", + "itemList": [ + { + "id": "configure-conformance-rules-in-nx-cloud", + "name": "Configure Conformance Rules in Nx Cloud", + "description": "", + "mediaImage": "", + "file": "nx-cloud/enterprise/conformance/configure-conformance-rules-in-nx-cloud", + "itemList": [], + "isExternal": false, + "path": "/ci/recipes/enterprise/conformance/configure-conformance-rules-in-nx-cloud", + "tags": ["conformance"] + }, + { + "id": "publish-conformance-rules-to-nx-cloud", + "name": "Publish Conformance Rules to Nx Cloud", + "description": "", + "mediaImage": "", + "file": "nx-cloud/enterprise/conformance/publish-conformance-rules-to-nx-cloud", + "itemList": [], + "isExternal": false, + "path": "/ci/recipes/enterprise/conformance/publish-conformance-rules-to-nx-cloud", + "tags": ["conformance"] + } + ], + "isExternal": false, + "path": "/ci/recipes/enterprise/conformance", + "tags": [] } ], "isExternal": false, @@ -1736,6 +1804,62 @@ "path": "/ci/recipes/enterprise/dte/jenkins-dte", "tags": [] }, + "/ci/recipes/enterprise/conformance": { + "id": "conformance", + "name": "Conformance", + "description": "Conformance features that are available to Nx Cloud Enterprise customers", + "mediaImage": "", + "file": "", + "itemList": [ + { + "id": "configure-conformance-rules-in-nx-cloud", + "name": "Configure Conformance Rules in Nx Cloud", + "description": "", + "mediaImage": "", + "file": "nx-cloud/enterprise/conformance/configure-conformance-rules-in-nx-cloud", + "itemList": [], + "isExternal": false, + "path": "/ci/recipes/enterprise/conformance/configure-conformance-rules-in-nx-cloud", + "tags": ["conformance"] + }, + { + "id": "publish-conformance-rules-to-nx-cloud", + "name": "Publish Conformance Rules to Nx Cloud", + "description": "", + "mediaImage": "", + "file": "nx-cloud/enterprise/conformance/publish-conformance-rules-to-nx-cloud", + "itemList": [], + "isExternal": false, + "path": "/ci/recipes/enterprise/conformance/publish-conformance-rules-to-nx-cloud", + "tags": ["conformance"] + } + ], + "isExternal": false, + "path": "/ci/recipes/enterprise/conformance", + "tags": [] + }, + "/ci/recipes/enterprise/conformance/configure-conformance-rules-in-nx-cloud": { + "id": "configure-conformance-rules-in-nx-cloud", + "name": "Configure Conformance Rules in Nx Cloud", + "description": "", + "mediaImage": "", + "file": "nx-cloud/enterprise/conformance/configure-conformance-rules-in-nx-cloud", + "itemList": [], + "isExternal": false, + "path": "/ci/recipes/enterprise/conformance/configure-conformance-rules-in-nx-cloud", + "tags": ["conformance"] + }, + "/ci/recipes/enterprise/conformance/publish-conformance-rules-to-nx-cloud": { + "id": "publish-conformance-rules-to-nx-cloud", + "name": "Publish Conformance Rules to Nx Cloud", + "description": "", + "mediaImage": "", + "file": "nx-cloud/enterprise/conformance/publish-conformance-rules-to-nx-cloud", + "itemList": [], + "isExternal": false, + "path": "/ci/recipes/enterprise/conformance/publish-conformance-rules-to-nx-cloud", + "tags": ["conformance"] + }, "/ci/recipes/other": { "id": "other", "name": "Other", @@ -1854,6 +1978,17 @@ "path": "/ci/reference/launch-templates", "tags": [] }, + { + "id": "assignment-rules", + "name": "Assignment Rules", + "description": "", + "mediaImage": "", + "file": "nx-cloud/reference/assignment-rules", + "itemList": [], + "isExternal": false, + "path": "/ci/reference/assignment-rules", + "tags": [] + }, { "id": "custom-steps", "name": "Custom Steps", @@ -1925,6 +2060,17 @@ "path": "/ci/reference/launch-templates", "tags": [] }, + "/ci/reference/assignment-rules": { + "id": "assignment-rules", + "name": "Assignment Rules", + "description": "", + "mediaImage": "", + "file": "nx-cloud/reference/assignment-rules", + "itemList": [], + "isExternal": false, + "path": "/ci/reference/assignment-rules", + "tags": [] + }, "/ci/reference/custom-steps": { "id": "custom-steps", "name": "Custom Steps", diff --git a/docs/generated/manifests/menus.json b/docs/generated/manifests/menus.json index df37cdf4f03af..ad41be5c64eee 100644 --- a/docs/generated/manifests/menus.json +++ b/docs/generated/manifests/menus.json @@ -6041,6 +6041,31 @@ } ], "disableCollapsible": false + }, + { + "name": "Conformance", + "path": "/ci/recipes/enterprise/conformance", + "id": "conformance", + "isExternal": false, + "children": [ + { + "name": "Configure Conformance Rules in Nx Cloud", + "path": "/ci/recipes/enterprise/conformance/configure-conformance-rules-in-nx-cloud", + "id": "configure-conformance-rules-in-nx-cloud", + "isExternal": false, + "children": [], + "disableCollapsible": false + }, + { + "name": "Publish Conformance Rules to Nx Cloud", + "path": "/ci/recipes/enterprise/conformance/publish-conformance-rules-to-nx-cloud", + "id": "publish-conformance-rules-to-nx-cloud", + "isExternal": false, + "children": [], + "disableCollapsible": false + } + ], + "disableCollapsible": false } ], "disableCollapsible": false @@ -6459,6 +6484,31 @@ } ], "disableCollapsible": false + }, + { + "name": "Conformance", + "path": "/ci/recipes/enterprise/conformance", + "id": "conformance", + "isExternal": false, + "children": [ + { + "name": "Configure Conformance Rules in Nx Cloud", + "path": "/ci/recipes/enterprise/conformance/configure-conformance-rules-in-nx-cloud", + "id": "configure-conformance-rules-in-nx-cloud", + "isExternal": false, + "children": [], + "disableCollapsible": false + }, + { + "name": "Publish Conformance Rules to Nx Cloud", + "path": "/ci/recipes/enterprise/conformance/publish-conformance-rules-to-nx-cloud", + "id": "publish-conformance-rules-to-nx-cloud", + "isExternal": false, + "children": [], + "disableCollapsible": false + } + ], + "disableCollapsible": false } ], "disableCollapsible": false @@ -6689,6 +6739,47 @@ "children": [], "disableCollapsible": false }, + { + "name": "Conformance", + "path": "/ci/recipes/enterprise/conformance", + "id": "conformance", + "isExternal": false, + "children": [ + { + "name": "Configure Conformance Rules in Nx Cloud", + "path": "/ci/recipes/enterprise/conformance/configure-conformance-rules-in-nx-cloud", + "id": "configure-conformance-rules-in-nx-cloud", + "isExternal": false, + "children": [], + "disableCollapsible": false + }, + { + "name": "Publish Conformance Rules to Nx Cloud", + "path": "/ci/recipes/enterprise/conformance/publish-conformance-rules-to-nx-cloud", + "id": "publish-conformance-rules-to-nx-cloud", + "isExternal": false, + "children": [], + "disableCollapsible": false + } + ], + "disableCollapsible": false + }, + { + "name": "Configure Conformance Rules in Nx Cloud", + "path": "/ci/recipes/enterprise/conformance/configure-conformance-rules-in-nx-cloud", + "id": "configure-conformance-rules-in-nx-cloud", + "isExternal": false, + "children": [], + "disableCollapsible": false + }, + { + "name": "Publish Conformance Rules to Nx Cloud", + "path": "/ci/recipes/enterprise/conformance/publish-conformance-rules-to-nx-cloud", + "id": "publish-conformance-rules-to-nx-cloud", + "isExternal": false, + "children": [], + "disableCollapsible": false + }, { "name": "Other", "path": "/ci/recipes/other", @@ -6776,6 +6867,14 @@ "children": [], "disableCollapsible": false }, + { + "name": "Assignment Rules", + "path": "/ci/reference/assignment-rules", + "id": "assignment-rules", + "isExternal": false, + "children": [], + "disableCollapsible": false + }, { "name": "Custom Steps", "path": "/ci/reference/custom-steps", @@ -6827,6 +6926,14 @@ "children": [], "disableCollapsible": false }, + { + "name": "Assignment Rules", + "path": "/ci/reference/assignment-rules", + "id": "assignment-rules", + "isExternal": false, + "children": [], + "disableCollapsible": false + }, { "name": "Custom Steps", "path": "/ci/reference/custom-steps", @@ -9901,6 +10008,22 @@ "children": [], "isExternal": false, "disableCollapsible": false + }, + { + "id": "convert-config-to-rspack-plugin", + "path": "/nx-api/rspack/generators/convert-config-to-rspack-plugin", + "name": "convert-config-to-rspack-plugin", + "children": [], + "isExternal": false, + "disableCollapsible": false + }, + { + "id": "convert-to-inferred", + "path": "/nx-api/rspack/generators/convert-to-inferred", + "name": "convert-to-inferred", + "children": [], + "isExternal": false, + "disableCollapsible": false } ], "isExternal": false, @@ -10611,9 +10734,9 @@ "name": "executors", "children": [ { - "id": "bundle-rule", - "path": "/nx-api/powerpack-conformance/executors/bundle-rule", - "name": "bundle-rule", + "id": "bundle-rules", + "path": "/nx-api/powerpack-conformance/executors/bundle-rules", + "name": "bundle-rules", "children": [], "isExternal": false, "disableCollapsible": false diff --git a/docs/generated/manifests/nx-api.json b/docs/generated/manifests/nx-api.json index c6fe5ba432b51..75e17d7962523 100644 --- a/docs/generated/manifests/nx-api.json +++ b/docs/generated/manifests/nx-api.json @@ -3012,6 +3012,24 @@ "originalFilePath": "/packages/rspack/src/generators/convert-webpack/schema.json", "path": "/nx-api/rspack/generators/convert-webpack", "type": "generator" + }, + "/nx-api/rspack/generators/convert-config-to-rspack-plugin": { + "description": "Convert the project to use the `NxAppRspackPlugin` and `NxReactRspackPlugin`.", + "file": "generated/packages/rspack/generators/convert-config-to-rspack-plugin.json", + "hidden": false, + "name": "convert-config-to-rspack-plugin", + "originalFilePath": "/packages/rspack/src/generators/convert-config-to-rspack-plugin/schema.json", + "path": "/nx-api/rspack/generators/convert-config-to-rspack-plugin", + "type": "generator" + }, + "/nx-api/rspack/generators/convert-to-inferred": { + "description": "Convert existing Rspack project(s) using `@nx/rspack:rspack` executor to use `@nx/rspack/plugin`.", + "file": "generated/packages/rspack/generators/convert-to-inferred.json", + "hidden": false, + "name": "convert-to-inferred", + "originalFilePath": "/packages/rspack/src/generators/convert-to-inferred/schema.json", + "path": "/nx-api/rspack/generators/convert-to-inferred", + "type": "generator" } }, "path": "/nx-api/rspack" @@ -3663,13 +3681,13 @@ "root": "/libs/nx-packages/powerpack-conformance", "source": "/libs/nx-packages/powerpack-conformance/src", "executors": { - "/nx-api/powerpack-conformance/executors/bundle-rule": { - "description": "Compile and bundle an Nx Conformance Rule", - "file": "external-generated/packages/powerpack-conformance/executors/bundle-rule.json", + "/nx-api/powerpack-conformance/executors/bundle-rules": { + "description": "Compile and bundle one or more Nx Conformance Rules", + "file": "external-generated/packages/powerpack-conformance/executors/bundle-rules.json", "hidden": false, - "name": "bundle-rule", - "originalFilePath": "/libs/nx-packages/powerpack-conformance/src/executors/bundle-rule/schema.json", - "path": "/nx-api/powerpack-conformance/executors/bundle-rule", + "name": "bundle-rules", + "originalFilePath": "/libs/nx-packages/powerpack-conformance/src/executors/bundle-rules/schema.json", + "path": "/nx-api/powerpack-conformance/executors/bundle-rules", "type": "executor" } }, diff --git a/docs/generated/manifests/tags.json b/docs/generated/manifests/tags.json index 039e6774a8f27..4206be6c90db3 100644 --- a/docs/generated/manifests/tags.json +++ b/docs/generated/manifests/tags.json @@ -1235,6 +1235,20 @@ "id": "conformance", "name": "Run Language-Agnostic Conformance Rules", "path": "/nx-enterprise/powerpack/conformance" + }, + { + "description": "", + "file": "nx-cloud/enterprise/conformance/configure-conformance-rules-in-nx-cloud", + "id": "configure-conformance-rules-in-nx-cloud", + "name": "Configure Conformance Rules in Nx Cloud", + "path": "/ci/recipes/enterprise/conformance/configure-conformance-rules-in-nx-cloud" + }, + { + "description": "", + "file": "nx-cloud/enterprise/conformance/publish-conformance-rules-to-nx-cloud", + "id": "publish-conformance-rules-to-nx-cloud", + "name": "Publish Conformance Rules to Nx Cloud", + "path": "/ci/recipes/enterprise/conformance/publish-conformance-rules-to-nx-cloud" } ], "owners": [ diff --git a/docs/generated/packages-metadata.json b/docs/generated/packages-metadata.json index 0f8d2dceca38b..04e75a49bb135 100644 --- a/docs/generated/packages-metadata.json +++ b/docs/generated/packages-metadata.json @@ -2981,6 +2981,24 @@ "originalFilePath": "/packages/rspack/src/generators/convert-webpack/schema.json", "path": "rspack/generators/convert-webpack", "type": "generator" + }, + { + "description": "Convert the project to use the `NxAppRspackPlugin` and `NxReactRspackPlugin`.", + "file": "generated/packages/rspack/generators/convert-config-to-rspack-plugin.json", + "hidden": false, + "name": "convert-config-to-rspack-plugin", + "originalFilePath": "/packages/rspack/src/generators/convert-config-to-rspack-plugin/schema.json", + "path": "rspack/generators/convert-config-to-rspack-plugin", + "type": "generator" + }, + { + "description": "Convert existing Rspack project(s) using `@nx/rspack:rspack` executor to use `@nx/rspack/plugin`.", + "file": "generated/packages/rspack/generators/convert-to-inferred.json", + "hidden": false, + "name": "convert-to-inferred", + "originalFilePath": "/packages/rspack/src/generators/convert-to-inferred/schema.json", + "path": "rspack/generators/convert-to-inferred", + "type": "generator" } ], "githubRoot": "https://github.com/nrwl/nx/blob/master", diff --git a/docs/generated/packages/rspack/generators/convert-config-to-rspack-plugin.json b/docs/generated/packages/rspack/generators/convert-config-to-rspack-plugin.json new file mode 100644 index 0000000000000..3e3b596fce8e9 --- /dev/null +++ b/docs/generated/packages/rspack/generators/convert-config-to-rspack-plugin.json @@ -0,0 +1,30 @@ +{ + "name": "convert-config-to-rspack-plugin", + "factory": "./src/generators/convert-config-to-rspack-plugin/convert-config-to-rspack-plugin", + "schema": { + "$schema": "https://json-schema.org/schema", + "$id": "NxRspackConvertConfigToRspackPlugin", + "description": "Convert existing Rspack project(s) using `@nx/rspack:rspack` executor that uses `withNx` to use `NxAppRspackPlugin`. Defaults to migrating all projects. Pass '--project' to migrate only one target.", + "title": "Convert Rspack project using withNx to NxAppRspackPlugin", + "type": "object", + "properties": { + "project": { + "type": "string", + "description": "The project to convert from using the `@nx/rspack:rspack` executor and `withNx` plugin to use `NxAppRspackPlugin`.", + "x-priority": "important" + }, + "skipFormat": { + "type": "boolean", + "description": "Whether to format files at the end of the migration.", + "default": false + } + }, + "presets": [] + }, + "description": "Convert the project to use the `NxAppRspackPlugin` and `NxReactRspackPlugin`.", + "implementation": "/packages/rspack/src/generators/convert-config-to-rspack-plugin/convert-config-to-rspack-plugin.ts", + "aliases": [], + "hidden": false, + "path": "/packages/rspack/src/generators/convert-config-to-rspack-plugin/schema.json", + "type": "generator" +} diff --git a/docs/generated/packages/rspack/generators/convert-to-inferred.json b/docs/generated/packages/rspack/generators/convert-to-inferred.json new file mode 100644 index 0000000000000..d31da11e09c84 --- /dev/null +++ b/docs/generated/packages/rspack/generators/convert-to-inferred.json @@ -0,0 +1,30 @@ +{ + "name": "convert-to-inferred", + "factory": "./src/generators/convert-to-inferred/convert-to-inferred#convertToInferred", + "schema": { + "$schema": "https://json-schema.org/schema", + "$id": "NxWebpackConvertToInferred", + "description": "Convert existing Webpack project(s) using `@nx/webpack:wepack` executor to use `@nx/webpack/plugin`.", + "title": "Convert a Webpack project from executor to plugin", + "type": "object", + "properties": { + "project": { + "type": "string", + "description": "The project to convert from using the `@nx/webpack:webpack` executor to use `@nx/webpack/plugin`. If not provided, all projects using the `@nx/webpack:webpack` executor will be converted.", + "x-priority": "important" + }, + "skipFormat": { + "type": "boolean", + "description": "Whether to format files.", + "default": false + } + }, + "presets": [] + }, + "description": "Convert existing Rspack project(s) using `@nx/rspack:rspack` executor to use `@nx/rspack/plugin`.", + "implementation": "/packages/rspack/src/generators/convert-to-inferred/convert-to-inferred#convertToInferred.ts", + "aliases": [], + "hidden": false, + "path": "/packages/rspack/src/generators/convert-to-inferred/schema.json", + "type": "generator" +} diff --git a/docs/map.json b/docs/map.json index a4beba3fd5299..ed5ef3cc3307f 100644 --- a/docs/map.json +++ b/docs/map.json @@ -1953,6 +1953,25 @@ "file": "nx-cloud/enterprise/dte/jenkins-dte" } ] + }, + { + "name": "Conformance", + "id": "conformance", + "description": "Conformance features that are available to Nx Cloud Enterprise customers", + "itemList": [ + { + "name": "Configure Conformance Rules in Nx Cloud", + "id": "configure-conformance-rules-in-nx-cloud", + "tags": ["conformance"], + "file": "nx-cloud/enterprise/conformance/configure-conformance-rules-in-nx-cloud" + }, + { + "name": "Publish Conformance Rules to Nx Cloud", + "id": "publish-conformance-rules-to-nx-cloud", + "tags": ["conformance"], + "file": "nx-cloud/enterprise/conformance/publish-conformance-rules-to-nx-cloud" + } + ] } ] }, @@ -2001,6 +2020,11 @@ "id": "launch-templates", "file": "nx-cloud/reference/launch-templates" }, + { + "name": "Assignment Rules", + "id": "assignment-rules", + "file": "nx-cloud/reference/assignment-rules" + }, { "name": "Custom Steps", "id": "custom-steps", diff --git a/docs/nx-cloud/enterprise/conformance/configure-conformance-rules-in-nx-cloud.md b/docs/nx-cloud/enterprise/conformance/configure-conformance-rules-in-nx-cloud.md new file mode 100644 index 0000000000000..bb2758f1c7708 --- /dev/null +++ b/docs/nx-cloud/enterprise/conformance/configure-conformance-rules-in-nx-cloud.md @@ -0,0 +1,56 @@ +# Configure Conformance Rules in Nx Cloud + +[Nx Cloud Enterprise](/enterprise) allows you to publish your organization's [Nx Conformance](/nx-enterprise/powerpack/conformance) rules to your Nx Cloud Organization, and consume them in any of your other Nx Workspaces without having to deal with the complexity and friction of dealing with a private NPM registry or similar. Authentication is handled automatically through your Nx Cloud connection and rules are downloaded and applied based on your preferences configured in the Nx Cloud UI. + +To learn about how to create and publish custom rules to your Nx Cloud Organization, please refer to the [Publish Conformance Rules to Nx Cloud](/ci/recipes/enterprise/conformance/publish-conformance-rules-to-nx-cloud) recipe. + +Once you have one or more rules published to your Nx Cloud Organization, you can configure your Nx Cloud Organization to use them in the Nx Cloud UI by visiting: + +https://nx.app/go/organization/conformance-rules + +## Choose the Scope of Configured Rules + +The value in the dropdown will determine what workspace(s) the rules will be applied to. By default, "All Workspaces" is the selected value, but you can change this to focus on a specific workspace instead. + +## Configure a Rule for the Chosen Workspace Scope + +After choosing the target workspace(s), click on the "Configure rule" to open the rule configuration dialog. + +Here you will choose which of the rules published to your Nx Cloud Organization should be applied to the chosen workspace(s), and configure any options that the chosen rule supports. + +### Rule Options + +{% callout title="Rule Options UI" %} +The rule options are currently provided via JSON, but in the near future we will dynamically generate a UI for configuring the options of each rule. +{% /callout %} + +The rule options will be validated against the rule's JSON schema definition before being saved, and you will be notified of any validation errors. + +### Rule Status + +Here you will choose whether or not the rule should be: + +- **Enabled** + - The rule will be executed in the chosen workspace(s) when `nx-cloud conformance`/`nx-cloud conformance:check` is run and any violations will cause the process to fail (exit with a non-zero exit code). +- **Evaluated** + - The rule will be executed in the chosen workspace(s) when `nx-cloud conformance`/`nx-cloud conformance:check` is run, but any violations will not cause the process to fail (i.e. the process will exit with a zero exit code). + - This status is useful for exposing violations to allow them to be addressed but without blocking the CI process in the meantime. + - You can combine this with the [Scheduled Status](#scheduled-status) feature to set a deadline for the chosen workspace(s) to become compliant with the rule. +- **Disabled** + - The rule will not be executed at all in the chosen workspace(s) and violations will therefore not be reported. + +### Scheduled Status + +By toggling on the "Schedule configuration", you can choose to set a future date on which the rule should be automatically transitioned to an alternate status. + +Most commonly this would be used to transition a rule from **Evaluated** to **Enabled** after a grace period, to allow contributors to address the violations before enforcement begins, but any combination of current and scheduled statuses is supported. + +## Notes on the Application of Rules at Runtime + +When `nx-cloud conformance` or `nx-cloud conformance:check` are run, any configured rules for the current workspace will be dynamically downloaded from your Nx Cloud Organization and applied to the resolved conformance configuration. This means that the conformance configuration itself is completely optional when using it with Nx Cloud, but it can still be useful if the workspace wants to combine cloud rules with other locally-defined rules. + +{% callout title="Organization Rules Override Local Rules" %} +By design, the workspace cannot choose to disable the rules configured in Nx Cloud - any conflict between local and cloud rules will result in the local configuration being overridden by the cloud configuration. +{% /callout %} + +If the cloud rules were written to depend on a different version of Nx or Nx Powerpack than is installed within the current workspace, Nx Cloud will handle installing applicable versions dynamically at runtime. diff --git a/docs/nx-cloud/enterprise/conformance/publish-conformance-rules-to-nx-cloud.md b/docs/nx-cloud/enterprise/conformance/publish-conformance-rules-to-nx-cloud.md new file mode 100644 index 0000000000000..4980ad103cc0a --- /dev/null +++ b/docs/nx-cloud/enterprise/conformance/publish-conformance-rules-to-nx-cloud.md @@ -0,0 +1,104 @@ +# Publish Conformance Rules to Nx Cloud + +[Nx Cloud Enterprise](/enterprise) allows you to publish your organization's [Nx Conformance](/nx-enterprise/powerpack/conformance) rules to your Nx Cloud Organization, and consume them in any of your other Nx Workspaces without having to deal with the complexity and friction of dealing with a private NPM registry or similar. Authentication is handled automatically through your Nx Cloud connection and rules are downloaded and applied based on your preferences configured in the Nx Cloud UI. + +Let's create a custom rule which we can then publish to Nx Cloud. We will first create a new library project to contain our rule (and any others we might create in the future): + +```shell +nx generate @nx/js:library cloud-conformance-rules +``` + +The Nx Cloud distribution mechanism expects each rule to be created in a named subdirectory in the `src/` directory of our new project, and each rule directory to contain an `index.ts` and a `schema.json` file. + +E.g. + +``` +cloud-conformance-rules/ +├── src/ +│ ├── test-cloud-rule/ +│ │ ├── index.ts // Our rule implementation +│ │ └── schema.json // The schema definition for the options supported by our rule +``` + +Our simple rule implementation in `test-cloud-rule/index.ts`, that will currently not report any violations, might look like this: + +```ts +import { createConformanceRule } from '@nx/powerpack-conformance'; + +export default createConformanceRule({ + name: 'test-cloud-rule', + category: 'reliability', + description: 'A test cloud rule', + reporter: 'non-project-files-reporter', + implementation: async () => { + return { + severity: 'low', + details: { + violations: [], + }, + }; + }, +}); +``` + +And because we do not yet have any options that we want to support for our rule, our `schema.json` file will looks like this (using the [JSON Schema](https://json-schema.org/) format): + +```json +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "type": "object", + "properties": {}, + "additionalProperties": false +} +``` + +We now have a valid implementation of a rule and we are ready to build it and publish it to Nx Cloud. The [`@nx/powerpack-conformance` plugin](/nx-api/powerpack-conformance) provides a [dedicated executor called `bundle-rules`](/nx-api/powerpack-conformance/executors/bundle-rules) for creating appropriate build artifacts for this purpose, so we will wire that executor up to a new build target in our `cloud-conformance-rules` project's `project.json` file: + +```jsonc {% fileName="cloud-conformance-rules/project.json" %} +{ + // ...any existing project.json content + "targets": { + // ...any existing targets + "build": { + "executor": "@nx/powerpack-conformance:bundle-rules", + "outputs": ["{options.outputPath}"], + "options": { + "outputPath": "{projectRoot}/dist" + } + } + } +} +``` + +We can now run `nx build cloud-conformance-rules` to build our rule and create the build artifacts in the `cloud-conformance-rules/dist` directory (or wherever you prefer to configure that `outputPath` location). If we take a look at the output path location we will see the same structure of one named subdirectory per rule, now containing the (bundled) `index.js` and `schema.json` files. + +Our final step is to publish the rule artifacts to Nx Cloud. We achieve this by running the `publish-conformance-rules` command on the `nx-cloud` CLI, passing the output path location as the first positional argument: + +```shell +nx-cloud publish-conformance-rules cloud-conformance-rules/dist +``` + +Subsequent calls to this command will overwrite the previously published rule artifacts for that rule, including implementation and schema changes. Effectively, the rules are always "at HEAD" and do not therefore have explicit versioning. If you need to support different versions of various setups, you should write the rule implementation to handle it at runtime. This approach helps reduce a lot of complexity and friction when managing Nx Conformance configurations across your organization. + +Because publishing the rules is a relatively common operation, you can also wire up a target in your `cloud-conformance-rules` project to wrap the CLI command. Therefore, including our build target from before, our `project.json` file now looks like this: + +```jsonc {% fileName="cloud-conformance-rules/project.json" %} +{ + // ...any existing project.json content + "targets": { + "build": { + "executor": "@nx/powerpack-conformance:bundle-rules", + "outputs": ["{options.outputPath}"], + "options": { + "outputPath": "{projectRoot}/dist" + } + }, + "publish": { + "dependsOn": ["build"], + "command": "npx nx-cloud publish-conformance-rules {projectRoot}/dist" + } + } +} +``` + +We can now run `nx publish cloud-conformance-rules` to both build and publish our rule (and any future rules in this project) to Nx Cloud. diff --git a/docs/nx-cloud/features/dynamic-agents.md b/docs/nx-cloud/features/dynamic-agents.md index 7ad91cd95f401..43ee22a0b1cd9 100644 --- a/docs/nx-cloud/features/dynamic-agents.md +++ b/docs/nx-cloud/features/dynamic-agents.md @@ -18,26 +18,51 @@ jobs: - ... ``` -This works great but may not be the most cost-effective way to run your tasks. The goal is to **balance cost and speed**. For example, you might want to run a small PR on a few agents to save costs, but use many agents for a large PR to get the fastest possible build time. +This works great, but may not be the most cost-effective way to run your tasks. The goal is to **balance cost and speed**. For example, you might want to run a small PR on a few agents to save costs, but use many agents for a large PR to get the fastest possible build time. ## Configure Dynamic Agents based on PR size -Instead of using a static configuration of agents (like the one shown above), you can also configure to use a different number and type of agents based on the size of your PR. +You can configure Nx Cloud to execute a different number of agents based on the size of your PR's affected changes. Define any number of **changesets** (the number of agents and types of agents) to use for different sized PRs and pass them in a configuration file to your `start-ci-run` command. -Create a file called `dynamic-changesets.yaml` in the `.nx/workflows` directory of your repo. +Start by creating a file called `distribution-config.yaml` in the `.nx/workflows` directory of your repo. This file will contain a `distribute-on` property that will be used to define the changesets to use for your PR. You can name your changesets anything you want. -```yaml {% fileName=".nx/workflows/dynamic-changesets.yaml" %} +{% callout type="warning" title="The order of your changesets matters!" %} +Define your changesets in order of increasing size (i.e. smallest changesets are defined before larger changesets). Nx Cloud uses the position of your changesets as part of its calculations to dynamically determine the correct changeset to use for your PR. +{% /callout %} + +```yaml {% fileName=".nx/workflows/distribution-config.yaml" %} distribute-on: small-changeset: 3 linux-medium-js medium-changeset: 6 linux-medium-js large-changeset: 10 linux-medium-js ``` +You can also specify a `default` changeset if you only want one changeset to be used for all PRs. Note that `default` is a reserved keyword so do not use it if you would like to define multiple changesets. + +```yaml {% fileName=".nx/workflows/distribution-config.yaml" %} +distribute-on: + default: 3 linux-medium-js +``` + +You can have as many changesets as you want. Based on the number of changesets specified, each changeset is assigned an equal percentage out of 100. Nx Cloud can determine the percentage of affected projects in your PR and use that value to evaluate which changeset to use. + {% callout type="deepdive" title="How is the size of the PR determined?" %} -To determine the size of the PR, Nx Cloud calculates the relationship between the number of [affected projects](/ci/features/affected) and the total number of projects in the workspace. It then assigns it to one of the three categories: small, medium, or large. +Nx Cloud calculates the relationship between the number of [affected projects](/ci/features/affected) and the total number of projects in the workspace to determine the size of a PR. {% /callout %} -You can then reference it in your CI pipeline configuration: +## Setting up Dynamic Agents in your CI Pipeline + +In the example below, each changeset would be assigned an equal percentage range out of 100%. If Nx Cloud determines that 30% of your projects have been affected, then it will use the medium changeset to distribute the workload on. If Nx Cloud determines that 55% of your projects have been affected, it will use the large changeset. + +```yaml {% fileName=".nx/workflows/distribution-config.yaml" %} +distribute-on: + small-changeset: 3 linux-medium-js # Distribute on small if 1-25% of projects affected in PR + medium-changeset: 6 linux-medium-js # Distribute on medium if 26-50% of projects affected in PR + large-changeset: 10 linux-medium-js # Distribute on large if 51-75% of projects affected in PR + extra-large-changeset: 15 linux-medium-js # Distribute on extra-large if 76-100% of projects affected in PR +``` + +You can then reference your distribution configuration in your CI pipeline configuration: ```yaml {% fileName=".github/workflows/main.yaml" highlightLines=[8] %} ... @@ -47,8 +72,9 @@ jobs: ... steps: ... - - run: npx nx-cloud start-ci-run --distribute-on=".nx/workflows/dynamic-changesets.yaml" --stop-agents-after="e2e-ci" + - run: npx nx-cloud start-ci-run --distribute-on=".nx/workflows/distribution-config.yaml" --stop-agents-after="e2e-ci" - ... ``` -Now, PRs that affect a small percentage of the repo will run on 3 agents, mid-size PRs will use 6 agents, and large PRs will use 10 agents. This feature helps save costs on smaller PRs while maintaining the high performance necessary for large PRs. +Now your agents will distribute your tasks dynamically—scaling and adapting to your PR sizes. +This feature helps save costs on smaller PRs while maintaining the high performance necessary for large PRs. diff --git a/docs/nx-cloud/intro/ci-with-nx.md b/docs/nx-cloud/intro/ci-with-nx.md index 3cde827454319..a6c78a5807b35 100644 --- a/docs/nx-cloud/intro/ci-with-nx.md +++ b/docs/nx-cloud/intro/ci-with-nx.md @@ -58,6 +58,7 @@ npx nx g ci-workflow Connect on our channels and with the Nx Community to ask questions, get help and keep up to date with the latest news. - Reach out for [Enterprise Support](/enterprise) +- ⭐️ [Star us on GitHub](https://github.com/nrwl/nx) to show your support and stay updated on new releases! - Join our [Discord Community](https://go.nx.dev/community) - Subscribe to our [Youtube Channel](https://www.youtube.com/@nxdevtools) - Follow us on [Twitter](https://twitter.com/nxdevtools) diff --git a/docs/nx-cloud/reference/assignment-rules.md b/docs/nx-cloud/reference/assignment-rules.md new file mode 100644 index 0000000000000..5d96816ecae8a --- /dev/null +++ b/docs/nx-cloud/reference/assignment-rules.md @@ -0,0 +1,164 @@ +# Assignment Rules (beta) + +Assignment rules allow you to control which tasks can run on which agents. Save on agent costs by provisioning different sizes of agents all with the confidence that your tasks will be run on the agents that are best suited for them. You can ensure resource intensive targets like `e2e-ci` and `build` have what they need by using larger agents. Lighter tasks like `lint` and `test` can run on smaller agents. + +Assignment rules are defined in your workspaces `distribution-config.yaml` file. This file should be created in the `.nx/workflows` directory of your repository. Note that this means that you must have [dynamic agents](/ci/features/dynamic-agents) also configured in your `distribution-config.yaml` file. + +## How to Define an Assignment Rule + +Each assignment rule has one of the following properties that it matches against tasks: `project`, `target`, and/or `configuration`. It also has a list of possible [agent types](/ci/reference/launch-templates) that tasks with the matching properties can run on. Rules are defined in yaml like the following: + +```yaml {% fileName=".nx/workflows/distribution-config.yaml" %} +distribute-on: + default: 3 linux-small-js, 2 linux-medium-js, 1 linux-large-js + +assignment-rules: + - project: app1 + target: build + configuration: production + runs-on: + - linux-large-js + - linux-medium-js +``` + +The above rule will match any task that has a project named `app1`, a target named `build`, and a configuration named `production`. Any tasks that match this rule will only be allowed to run on agents with the `linux-large-js` and `linux-medium-js` launch templates. + +You can mix and match any of the criteria in an assignment rule provided that you follow the constraints: + +- At least one of the following properties is defined: `project`, `target`, `configuration`. +- There is at least one [agent type](/ci/reference/launch-templates) specified in the `run-on` field. +- Every changeset in your `distribute-on` field must include at **least one agent** that matches each agent type specified in the run-on field across all assignment rules. For example, if your rules distribute tasks on `linux-small-js`, `linux-medium-js`, and `linux-large-js`, then at least one agent of each type must be available; otherwise, tasks associated with those rules cannot be executed. + +### Invalid Assignment Rules Example + +```yaml {% fileName=".nx/workflows/distribution-config.yaml" %} +distribute-on: + # Invalid changeset that is missing `linux-large-js`. Tasks assigned to large agents won't be able to execute. + small-changeset: 1 linux-small-js, 2 linux-medium-js + medium-changeset: 2 linux-small-js, 2 linux-medium-js, 3 linux-large-js + large-changeset: 3 linux-small-js, 3 linux-medium-js, 4 linux-large-js + +assignment-rules: + # Missing one of `project`, `target`, `configuration` + - runs-on: + - linux-medium-js + - linux-large-js + + # Missing `runs-on` + - target: lint + configuration: production + + # Agent type not found in any of the `distribute-on` changesets + - project: lib1 + target: test + runs-on: + - linux-extra-large-js +``` + +### Valid Assignment Rules Example + +```yaml {% fileName=".nx/workflows/distribution-config.yaml" %} +distribute-on: + default: 3 linux-small-js, 2 linux-medium-js, 1 linux-large-js + +# All rules below are valid assignment rules +assignment-rules: + - project: app1 + runs-on: + - linux-medium-js + - linux-large-js + + - target: lint + configuration: production + runs-on: + - linux-large-js + + - project: lib1 + target: test + runs-on: + - linux-medium-js +``` + +## Assignment Rule Precedence + +Having multiple assignment rules means that often rules may overlap or apply to the same tasks. To determine which rule take priority, a rule of thumb is that **more specific rules take precedence over more general rules**. You can consult our precedence chart for a full list of rule priorities. A checkmark indicates that a rule has a particular property defined. + +| Priority | Configuration | Target | Project | +| :------: | :-----------: | :----: | :-----: | +| 1 | ✅︎ | ✅︎ | ✅︎ | +| 2 | ✅︎ | ✅︎ | | +| 3 | ✅︎ | | ✅︎ | +| 4 | | ✅︎ | ✅︎ | +| 5 | ✅︎ | | | +| 6 | | ✅︎ | | +| 7 | | | ✅ | + +### Rule Precedence Example + +In this example, the task defined below can match multiple assignment rules. However, since the second rule specifies all three properties (`project`, `target`, and `configuration`) rather than just two (`project` and `target`), it takes precedence, and we apply the second rule when distributing the task. + +```json {% fileName="A task from your workspace" %} +{ + "project": "app1", + "target": "build", + "configuration": "production" +} +``` + +```yaml {% fileName=".nx/workflows/distribution-config.yaml" %} +distribute-on: + default: 10 linux-medium-js, 8 linux-large-js + +assignment-rules: + - project: app1 + target: build + configuration: production + runs-on: + - linux-medium-js + + - project: app1 + target: build + runs-on: + - linux-large-js +``` + +## Using Assignment Rules in your CI Pipeline + +A typical `distribution-config.yaml` file might look like this: + +```yaml {% fileName=".nx/workflows/distribution-config.yaml" %} +distribute-on: + small-changeset: 3 linux-medium-js, 2 linux-large-js + medium-changeset: 6 linux-medium-js, 4 linux-large-js + large-changeset: 10 linux-medium-js, 8 linux-large-js + +assignment-rules: + - project: app1 + target: build + configuration: production + runs-on: + - linux-large-js + + - target: lint + runs-on: + - linux-medium-js + + - configuration: development + runs-on: + - linux-medium-js + - linux-large-js +``` + +You can then reference your distribution configuration in your CI pipeline configuration: + +```yaml {% fileName=".github/workflows/main.yaml" highlightLines=[8] %} +... +jobs: + - job: main + displayName: Main Job + ... + steps: + ... + - run: npx nx-cloud start-ci-run --distribute-on=".nx/workflows/distribution-config.yaml" --stop-agents-after="e2e-ci" + - .. +``` diff --git a/docs/nx-cloud/reference/nx-cloud-cli.md b/docs/nx-cloud/reference/nx-cloud-cli.md index 8d5dd955a363d..ce7077b6fa3e5 100644 --- a/docs/nx-cloud/reference/nx-cloud-cli.md +++ b/docs/nx-cloud/reference/nx-cloud-cli.md @@ -105,9 +105,18 @@ Nx Cloud side. You can disable this by passing `--require-explicit-completion`. ### --stop-agents-after You can tell Nx Cloud to terminate agents after it sees a certain -target: `npx nx-cloud start-ci-run --stop-agents-after=e2e`. +target or group of targets: `npx nx-cloud start-ci-run --stop-agents-after=build,test,e2e`. -The target name for `--stop-agents-after` should be the last target run within your pipeline. If not, Nx Cloud will end the CI pipeline execution, preventing the subsequent commands from running. +{% callout type="note" title="Tip: Be as specific as possible when listing targets" %} +For the best results, always tell Nx Cloud about all targets that should be expected during your pipeline. This will +prevent your CI Pipeline Execution from ending prematurely, cutting off any unfinished work. +{% /callout %} + +Whether you are running commands serially or in parallel (through use of the `&` operand or discrete jobs), you should +include one or more targets from each command. + +{% tabs %} +{% tab label="Serial command execution" %} #### Incorrect example: @@ -118,17 +127,66 @@ The target name for `--stop-agents-after` should be the last target run within y - run: nx affected -t test ``` -If build tasks are all cached, then all build tasks will complete immediately causing lint and test tasks to fail with an error saying the CI pipeline execution has already been completed. Instead you should re-order your targets to make sure the build target is last. +Nx Cloud will only look for the presence of a `build` target before determining your pipeline can be shut down. Since +both `lint` and `test` will only run after `build` is complete, your pipeline would end before all intended work is +executed. #### Corrected example: ```yaml -- run: npx nx-cloud start-ci-run --stop-agents-after=build +- run: npx nx-cloud start-ci-run --stop-agents-after=lint,test,build - run: nx affected -t lint - run: nx affected -t test - run: nx affected -t build ``` +{% /tab %} +{% tab label="Parallel command execution" %} + +#### Incorrect example: + +```yaml +- run: npx nx-cloud start-ci-run --stop-agents-after=test +- run: nx affected -t build & nx affected -t lint & nx affected -t test +``` + +At first glance, this example may appear correct. However, since all the commands are executed in parallel, it could +be possible that your `test` command results in full cache hits and finishes faster than the `build` and `lint` commands. +In this case, Nx Cloud will stop your pipeline, leaving work incomplete for both the `build` and `lint` commands. + +#### Corrected example: + +```yaml +- run: npx nx-cloud start-ci-run --stop-agents-after=lint,test,build +- run: nx affected -t build & nx affected -t lint & nx affected -t test +``` + +{% /tab %} +{% /tabs %} + +#### Advanced shutdown targeting + +In advanced pipeline setups, it is possible that you want to run multiple commands with the same target, but with +distinct configurations. An example of this may be doing static translations for different locales during your builds. + +```yaml +- run: npx nx-cloud start-ci-run --stop-agents-after=build +- run: nx affected -t build --configuration=locale-en +- run: nx affected -t build --configuration=locale-es +``` + +In this case, the `build` target will be executed twice, once with the `locale-en` configuration and once with the +`locale-es` configuration. However, Nx Cloud is only looking for the `build` target to assess whether the CI Pipeline +Execution can be marked complete. + +To address this, you can pass an optional `configuration` to make your `target`s more specific. + +```yaml +- run: npx nx-cloud start-ci-run --stop-agents-after=build:locale-en,build:locale-es +- run: nx affected -t build --configuration=locale-en +- run: nx affected -t build --configuration=locale-es +``` + ### --stop-agents-on-failure By default, a failure in one of the commands is going to terminate the whole CI run and will stop all the diff --git a/docs/shared/getting-started/installation.md b/docs/shared/getting-started/installation.md index 20aec18262178..a3d84817d27e2 100644 --- a/docs/shared/getting-started/installation.md +++ b/docs/shared/getting-started/installation.md @@ -79,7 +79,7 @@ npm add --global nx@latest ``` {% /tab %} -{% tab label="yarn" %} +{% tab label="yarn (v1 only)" %} ```shell yarn global add nx@latest diff --git a/docs/shared/getting-started/intro.md b/docs/shared/getting-started/intro.md index aece323ba65e7..4cbb3ff4a6352 100644 --- a/docs/shared/getting-started/intro.md +++ b/docs/shared/getting-started/intro.md @@ -116,6 +116,7 @@ Also, here are some recipes that give you more details based on the technology s Connect on our channels and with the Nx Community to ask questions, get help and keep up to date with the latest news. +- ⭐️ [Star us on GitHub](https://github.com/nrwl/nx) to show your support and stay updated on new releases! - Join our [Discord Community](https://go.nx.dev/community) - Subscribe to our [Youtube Channel](https://www.youtube.com/@nxdevtools) - Follow us on [Twitter](https://twitter.com/nxdevtools) diff --git a/docs/shared/migration/preserving-git-histories.md b/docs/shared/migration/preserving-git-histories.md index 621460d0ddc0c..fe9a65c6168a0 100644 --- a/docs/shared/migration/preserving-git-histories.md +++ b/docs/shared/migration/preserving-git-histories.md @@ -22,12 +22,19 @@ In order to avoid merge conflicts later, it's best to first do the folder reorga ```shell cd my-standalone-app +git checkout main git fetch -git checkout -b monorepo-migration origin/master +git checkout -b monorepo-migration main mkdir -p apps/my-standalone-app git ls-files | sed 's!/.*!!'| uniq | xargs -i git mv {} apps/my-standalone-app +``` + +Check if you need to move back the `.gitignore` file to the root and/or update any paths so you don't commit previously ignored files/folders. +If all is well proceed with the commit and push. + +```shell git commit -m "Move files in preparation for monorepo migration" -git push -u +git push --set-upstream origin monorepo-migration ``` Next, in your monorepo, we'll add a remote repository url for where the standalone app is located: diff --git a/docs/shared/plugins/intro.md b/docs/shared/plugins/intro.md index 76cac0a1452e8..95a09f7849030 100644 --- a/docs/shared/plugins/intro.md +++ b/docs/shared/plugins/intro.md @@ -37,8 +37,8 @@ You can follow along with one of the step by step tutorials below that is focuse {% cards cols="2" %} -{% link-card title="Enforce Best Practices in Your Repository" type="tutorial" url="/extending-nx/tutorials/organization-specific-plugin" icon="office" /%} -{% link-card title="Integrate a Tool Into an Nx Repository" type="tutorial" url="/extending-nx/tutorials/tooling-plugin" icon="tool" /%} +{% link-card title="Enforce Best Practices in Your Repository" type="tutorial" url="/extending-nx/tutorials/organization-specific-plugin" icon="BuildingOfficeIcon" /%} +{% link-card title="Integrate a Tool Into an Nx Repository" type="tutorial" url="/extending-nx/tutorials/tooling-plugin" icon="WrenchScrewdriverIcon" /%} {% /cards %} diff --git a/docs/shared/recipes/module-federation/creating-a-host.md b/docs/shared/recipes/module-federation/creating-a-host.md index 699f88ee005c3..ae75c4bb0aa8e 100644 --- a/docs/shared/recipes/module-federation/creating-a-host.md +++ b/docs/shared/recipes/module-federation/creating-a-host.md @@ -269,6 +269,6 @@ To support [Independent Deployability](/concepts/module-federation/module-federa ```json { ..., - "implicitDependencies": ["remote-one", "remote-two"] + "implicitDependencies": ["remote1", "remote2"] } ``` diff --git a/docs/shared/reference/sitemap.md b/docs/shared/reference/sitemap.md index 48b8c9aa5823e..54e8c777bb362 100644 --- a/docs/shared/reference/sitemap.md +++ b/docs/shared/reference/sitemap.md @@ -314,6 +314,9 @@ - [Bitbucket Pipelines Custom DTE](/ci/recipes/enterprise/dte/bitbucket-dte) - [GitLab Custom DTE](/ci/recipes/enterprise/dte/gitlab-dte) - [Jenkins Custom DTE](/ci/recipes/enterprise/dte/jenkins-dte) + - [Conformance](/ci/recipes/enterprise/conformance) + - [Configure Conformance Rules in Nx Cloud](/ci/recipes/enterprise/conformance/configure-conformance-rules-in-nx-cloud) + - [Publish Conformance Rules to Nx Cloud](/ci/recipes/enterprise/conformance/publish-conformance-rules-to-nx-cloud) - [Other](/ci/recipes/other) - [Record Non-Nx Commands](/ci/recipes/other/record-commands) - [Prepare applications for deployment via CI](/ci/recipes/other/ci-deployment) @@ -322,6 +325,7 @@ - [Configuration Options](/ci/reference/config) - [nx-cloud CLI](/ci/reference/nx-cloud-cli) - [Launch Templates](/ci/reference/launch-templates) + - [Assignment Rules](/ci/reference/assignment-rules) - [Custom Steps](/ci/reference/custom-steps) - [Environment Variables](/ci/reference/env-vars) - [Release Notes](/ci/reference/release-notes) @@ -697,6 +701,8 @@ - [preset](/nx-api/rspack/generators/preset) - [application](/nx-api/rspack/generators/application) - [convert-webpack](/nx-api/rspack/generators/convert-webpack) + - [convert-config-to-rspack-plugin](/nx-api/rspack/generators/convert-config-to-rspack-plugin) + - [convert-to-inferred](/nx-api/rspack/generators/convert-to-inferred) - [storybook](/nx-api/storybook) - [documents](/nx-api/storybook/documents) - [Overview](/nx-api/storybook/documents/overview) @@ -782,7 +788,7 @@ - [documents](/nx-api/powerpack-conformance/documents) - [Overview](/nx-api/powerpack-conformance/documents/overview) - [executors](/nx-api/powerpack-conformance/executors) - - [bundle-rule](/nx-api/powerpack-conformance/executors/bundle-rule) + - [bundle-rules](/nx-api/powerpack-conformance/executors/bundle-rules) - [powerpack-enterprise-cloud](/nx-api/powerpack-enterprise-cloud) - [generators](/nx-api/powerpack-enterprise-cloud/generators) - [init](/nx-api/powerpack-enterprise-cloud/generators/init) diff --git a/docs/shared/tutorials/angular-monorepo.md b/docs/shared/tutorials/angular-monorepo.md index 9489c6cd747d5..190ca91e4dd52 100644 --- a/docs/shared/tutorials/angular-monorepo.md +++ b/docs/shared/tutorials/angular-monorepo.md @@ -1345,6 +1345,7 @@ Here's some things you can dive into next: Also, make sure you +- ⭐️ [Star us on GitHub](https://github.com/nrwl/nx) to show your support and stay updated on new releases! - [Join the Official Nx Discord Server](https://go.nx.dev/community) to ask questions and find out the latest news about Nx. - [Follow Nx on Twitter](https://twitter.com/nxdevtools) to stay up to date with Nx news - [Read our Nx blog](/blog) diff --git a/docs/shared/tutorials/angular-standalone.md b/docs/shared/tutorials/angular-standalone.md index 8e344b882104f..b4f4be03773e0 100644 --- a/docs/shared/tutorials/angular-standalone.md +++ b/docs/shared/tutorials/angular-standalone.md @@ -1144,6 +1144,7 @@ Here's some things you can dive into next: Also, make sure you +- ⭐️ [Star us on GitHub](https://github.com/nrwl/nx) to show your support and stay updated on new releases! - [Join the Official Nx Discord Server](https://go.nx.dev/community) to ask questions and find out the latest news about Nx. - [Follow Nx on Twitter](https://twitter.com/nxdevtools) to stay up to date with Nx news - [Read our Nx blog](/blog) diff --git a/docs/shared/tutorials/gradle.md b/docs/shared/tutorials/gradle.md index b0726592a69ce..bda706e819dd0 100644 --- a/docs/shared/tutorials/gradle.md +++ b/docs/shared/tutorials/gradle.md @@ -411,6 +411,7 @@ organization: Connect with the rest of the Nx community with these resources: +- ⭐️ [Star us on GitHub](https://github.com/nrwl/nx) to show your support and stay updated on new releases! - [Join the Official Nx Discord Server](https://go.nx.dev/community) to ask questions and find out the latest news about Nx. - [Follow Nx on Twitter](https://twitter.com/nxdevtools) to stay up to date with Nx news diff --git a/docs/shared/tutorials/npm-workspaces.md b/docs/shared/tutorials/npm-workspaces.md index cb00f9c9dd039..c98da9fee6c49 100644 --- a/docs/shared/tutorials/npm-workspaces.md +++ b/docs/shared/tutorials/npm-workspaces.md @@ -497,6 +497,7 @@ For more information about how Nx can improve your CI pipeline, check out one of Connect with the rest of the Nx community with these resources: +- ⭐️ [Star us on GitHub](https://github.com/nrwl/nx) to show your support and stay updated on new releases! - [Join the Official Nx Discord Server](https://go.nx.dev/community) to ask questions and find out the latest news about Nx. - [Follow Nx on Twitter](https://twitter.com/nxdevtools) to stay up to date with Nx news - [Read our Nx blog](/blog) diff --git a/docs/shared/tutorials/react-monorepo.md b/docs/shared/tutorials/react-monorepo.md index 064fde5f65e1b..fc1513587d352 100644 --- a/docs/shared/tutorials/react-monorepo.md +++ b/docs/shared/tutorials/react-monorepo.md @@ -1147,6 +1147,7 @@ Here's some things you can dive into next: Also, make sure you +- ⭐️ [Star us on GitHub](https://github.com/nrwl/nx) to show your support and stay updated on new releases! - [Join the Official Nx Discord Server](https://go.nx.dev/community) to ask questions and find out the latest news about Nx. - [Follow Nx on Twitter](https://twitter.com/nxdevtools) to stay up to date with Nx news - [Read our Nx blog](/blog) diff --git a/docs/shared/tutorials/react-standalone.md b/docs/shared/tutorials/react-standalone.md index 3c20f700d888c..c3044b90c47db 100644 --- a/docs/shared/tutorials/react-standalone.md +++ b/docs/shared/tutorials/react-standalone.md @@ -1096,6 +1096,7 @@ Here's some things you can dive into next: Also, make sure you +- ⭐️ [Star us on GitHub](https://github.com/nrwl/nx) to show your support and stay updated on new releases! - [Join the Official Nx Discord Server](https://go.nx.dev/community) to ask questions and find out the latest news about Nx. - [Follow Nx on Twitter](https://twitter.com/nxdevtools) to stay up to date with Nx news - [Read our Nx blog](/blog) diff --git a/docs/shared/tutorials/vue-standalone.md b/docs/shared/tutorials/vue-standalone.md index 9cd267562fe49..1f5a232def46a 100644 --- a/docs/shared/tutorials/vue-standalone.md +++ b/docs/shared/tutorials/vue-standalone.md @@ -1138,6 +1138,7 @@ For more information about how Nx can improve your CI pipeline, check out one of Connect with the rest of the Nx community with these resources: +- ⭐️ [Star us on GitHub](https://github.com/nrwl/nx) to show your support and stay updated on new releases! - [Join the Official Nx Discord Server](https://go.nx.dev/community) to ask questions and find out the latest news about Nx. - [Follow Nx on Twitter](https://twitter.com/nxdevtools) to stay up to date with Nx news - [Read our Nx blog](/blog) diff --git a/e2e/next/src/next-playwright.test.ts b/e2e/next/src/next-playwright.test.ts index 833012b77d2f9..7d5131a3a0d8a 100644 --- a/e2e/next/src/next-playwright.test.ts +++ b/e2e/next/src/next-playwright.test.ts @@ -25,7 +25,7 @@ describe('Next Playwright e2e tests', () => { afterAll(() => cleanupProject()); it('should execute e2e tests using playwright', () => { - if (runE2ETests()) { + if (runE2ETests('playwright')) { const result = runCLI(`e2e ${appName}-e2e --verbose`); expect(result).toContain( `Successfully ran target e2e for project ${appName}-e2e` @@ -53,7 +53,7 @@ describe('Next Playwright e2e tests', () => { ` ); - if (runE2ETests()) { + if (runE2ETests('playwright')) { const result = runCLI(`e2e ${appName}-e2e --verbose`); expect(result).toContain( `Successfully ran target e2e for project ${appName}-e2e` diff --git a/e2e/next/src/next.test.ts b/e2e/next/src/next.test.ts index 695c109ca0173..5cc90aeaa6a85 100644 --- a/e2e/next/src/next.test.ts +++ b/e2e/next/src/next.test.ts @@ -184,7 +184,7 @@ describe('Next.js Applications', () => { runCLI(`generate @nx/next:app ${appName} --no-interactive --style=css`); - if (runE2ETests('cypress')) { + if (runE2ETests('playwright')) { const e2eResults = runCLI(`e2e-ci ${appName}-e2e --verbose`, { verbose: true, env: { diff --git a/e2e/release/src/release.test.ts b/e2e/release/src/release.test.ts index 80ec1cc7fd157..8cb139a05d848 100644 --- a/e2e/release/src/release.test.ts +++ b/e2e/release/src/release.test.ts @@ -133,7 +133,7 @@ describe('nx release', () => { + + - an awesome new feature ([{COMMIT_SHA}](https://github.com/nrwl/fake-repo/commit/{COMMIT_SHA})) + - + ### ❤️ Thank You + + ### ❤️ Thank You + + - Test @{COMMIT_AUTHOR} @@ -153,7 +153,7 @@ describe('nx release', () => { - an awesome new feature ([{COMMIT_SHA}](https://github.com/nrwl/fake-repo/commit/{COMMIT_SHA})) - ### ❤️ Thank You + ### ❤️ Thank You - Test @{COMMIT_AUTHOR} `); diff --git a/e2e/release/src/version-plans.test.ts b/e2e/release/src/version-plans.test.ts index 5a533c5da1d83..02741c9188ab1 100644 --- a/e2e/release/src/version-plans.test.ts +++ b/e2e/release/src/version-plans.test.ts @@ -178,7 +178,7 @@ Here is another line in the message. + + - Update the fixed packages with a minor release. + -+ ### ❤️ Thank You ++ ### ❤️ Thank You + + - Test` ); @@ -192,7 +192,7 @@ Here is another line in the message. + + - Update the fixed packages with a minor release. + -+ ### ❤️ Thank You ++ ### ❤️ Thank You + + - Test` ); @@ -208,7 +208,7 @@ Here is another line in the message. + + Here is another line in the message. + -+ ### ❤️ Thank You ++ ### ❤️ Thank You + + - Test` ); @@ -225,7 +225,7 @@ Here is another line in the message. + + Here is another line in the message. + -+ ### ❤️ Thank You ++ ### ❤️ Thank You + + - Test` ); @@ -242,7 +242,7 @@ Here is another line in the message. + + Here is another line in the message. + -+ ### ❤️ Thank You ++ ### ❤️ Thank You + + - Test` ); @@ -321,7 +321,7 @@ Update packages in both groups with a mix #2 + + - Update packages in both groups with a mix #2 + -+ ### ❤️ Thank You ++ ### ❤️ Thank You + + - Test` ); @@ -336,7 +336,7 @@ Update packages in both groups with a mix #2 + + - Update packages in both groups with a mix #2 + -+ ### ❤️ Thank You ++ ### ❤️ Thank You + + - Test ` @@ -352,7 +352,7 @@ Update packages in both groups with a mix #2 + + - Update packages in both groups with a mix #1 + -+ ### ❤️ Thank You ++ ### ❤️ Thank You + + - Test` ); @@ -368,7 +368,7 @@ Update packages in both groups with a mix #2 + + - Update packages in both groups with a mix #2 + -+ ### ❤️ Thank You ++ ### ❤️ Thank You + + - Test` ); @@ -384,7 +384,7 @@ Update packages in both groups with a mix #2 + + - Update packages in both groups with a mix #2 + -+ ### ❤️ Thank You ++ ### ❤️ Thank You + + - Test` ); @@ -549,7 +549,7 @@ const yargs = require('yargs'); + + - Update the fixed packages with a minor release. + -+ ### ❤️ Thank You ++ ### ❤️ Thank You + + - Test` ); @@ -563,7 +563,7 @@ const yargs = require('yargs'); + + - Update the fixed packages with a minor release. + -+ ### ❤️ Thank You ++ ### ❤️ Thank You + + - Test` ); @@ -577,7 +577,7 @@ const yargs = require('yargs'); + + - Update the independent packages with a patch, preminor, and prerelease. + -+ ### ❤️ Thank You ++ ### ❤️ Thank You + + - Test` ); @@ -592,7 +592,7 @@ const yargs = require('yargs'); + + - Update the independent packages with a patch, preminor, and prerelease. + -+ ### ❤️ Thank You ++ ### ❤️ Thank You + + - Test` ); @@ -607,7 +607,7 @@ const yargs = require('yargs'); + + - Update the independent packages with a patch, preminor, and prerelease. + -+ ### ❤️ Thank You ++ ### ❤️ Thank You + + - Test` ); @@ -689,7 +689,7 @@ Update packages in both groups with a mix #2 + + - Update packages in both groups with a mix #2 + -+ ### ❤️ Thank You ++ ### ❤️ Thank You + + - Test` ); @@ -704,7 +704,7 @@ Update packages in both groups with a mix #2 + + - Update packages in both groups with a mix #2 + -+ ### ❤️ Thank You ++ ### ❤️ Thank You + + - Test ` @@ -720,7 +720,7 @@ Update packages in both groups with a mix #2 + + - Update packages in both groups with a mix #1 + -+ ### ❤️ Thank You ++ ### ❤️ Thank You + + - Test` ); @@ -736,7 +736,7 @@ Update packages in both groups with a mix #2 + + - Update packages in both groups with a mix #2 + -+ ### ❤️ Thank You ++ ### ❤️ Thank You + + - Test` ); @@ -752,7 +752,7 @@ Update packages in both groups with a mix #2 + + - Update packages in both groups with a mix #2 + -+ ### ❤️ Thank You ++ ### ❤️ Thank You + + - Test` ); diff --git a/nx-dev/data-access-documents/src/lib/documents.api.ts b/nx-dev/data-access-documents/src/lib/documents.api.ts index 5b8c6f5c60d00..5cd441d4e76a5 100644 --- a/nx-dev/data-access-documents/src/lib/documents.api.ts +++ b/nx-dev/data-access-documents/src/lib/documents.api.ts @@ -97,6 +97,27 @@ export class DocumentsApi { name: document.name, mediaImage: document.mediaImage || '', relatedDocuments: this.getRelatedDocuments(document.tags), + parentDocuments: path.map((segment, index): RelatedDocument => { + const parentPath = path.slice(0, index + 1).join('/'); + const parentDocument = + this.manifest[this.getManifestKey(parentPath)] || null; + if (!parentDocument) { + return { + id: segment, + name: '', + description: '', + file: '', + path: '/' + path.slice(0, index + 1).join('/'), + }; + } + return { + id: parentDocument.id, + name: parentDocument.name, + description: parentDocument.description, + file: parentDocument.file, + path: parentDocument.path, + }; + }), tags: document.tags, }; } diff --git a/nx-dev/feature-doc-viewer/src/lib/doc-viewer.tsx b/nx-dev/feature-doc-viewer/src/lib/doc-viewer.tsx index b382caaffce97..97d7275cfcabb 100644 --- a/nx-dev/feature-doc-viewer/src/lib/doc-viewer.tsx +++ b/nx-dev/feature-doc-viewer/src/lib/doc-viewer.tsx @@ -101,7 +101,7 @@ export function DocViewer({
- +
{/*MAIN CONTENT*/} diff --git a/nx-dev/models-document/src/lib/documents.models.ts b/nx-dev/models-document/src/lib/documents.models.ts index 6961a22eb4f06..cb6433d9cd98f 100644 --- a/nx-dev/models-document/src/lib/documents.models.ts +++ b/nx-dev/models-document/src/lib/documents.models.ts @@ -29,6 +29,7 @@ export interface ProcessedDocument { id: string; name: string; relatedDocuments: Record; + parentDocuments?: RelatedDocument[]; tags: string[]; } diff --git a/nx-dev/ui-common/src/lib/breadcrumbs.tsx b/nx-dev/ui-common/src/lib/breadcrumbs.tsx index 54b10e84f3acc..71aef1949f318 100644 --- a/nx-dev/ui-common/src/lib/breadcrumbs.tsx +++ b/nx-dev/ui-common/src/lib/breadcrumbs.tsx @@ -1,25 +1,71 @@ import { ChevronRightIcon } from '@heroicons/react/24/solid'; +import { ProcessedDocument } from '@nx/nx-dev/models-document'; import classNames from 'classnames'; -export function Breadcrumbs({ path }: { path: string }): JSX.Element { - const cleanedPath = path.includes('?') - ? path.slice(0, path.indexOf('?')) - : path; - const pages = [ - ...cleanedPath - .split('/') - .filter(Boolean) - .map((segment, index, segments) => ({ - name: segment.includes('#') - ? segment.slice(0, segment.indexOf('#')) - : segment, - // We do not have dedicated page view for executors & generators - href: '/' + segments.slice(0, index + 1).join('/'), - current: '/' + segments.slice(0, index + 1).join('/') === cleanedPath, - })), - ]; - - if (pages.length === 1) { +interface Crumb { + id: string; + name: string; + href: string; + current: boolean; +} + +const sectionNames: Record = { + ci: 'CI', + 'extending-nx': 'Extending Nx', + 'nx-api': 'Nx API', +}; + +const capitalize = (s: string) => s.charAt(0).toUpperCase() + s.slice(1); + +export function Breadcrumbs({ + document, + path, +}: { + document?: ProcessedDocument; + path?: string; +}): JSX.Element { + let crumbs: Crumb[] = []; + + if (path) { + const cleanedPath = path.includes('?') + ? path.slice(0, path.indexOf('?')) + : path; + crumbs = [ + ...cleanedPath + .split('/') + .filter(Boolean) + .map((segment, index, segments) => { + const strippedName = segment.includes('#') + ? segment.slice(0, segment.indexOf('#')) + : segment; + const name = + sectionNames[strippedName] || + strippedName.split('-').map(capitalize).join(' '); + return { + id: segment, + name, + // We do not have dedicated page view for executors & generators + href: '/' + segments.slice(0, index + 1).join('/'), + current: + '/' + segments.slice(0, index + 1).join('/') === cleanedPath, + }; + }), + ]; + } + + if (document && document.parentDocuments) { + crumbs = document.parentDocuments.map((parentDocument, index) => ({ + id: parentDocument.id, + name: + parentDocument.name || + sectionNames[parentDocument.id] || + parentDocument.id.split('-').map(capitalize).join(' '), + href: parentDocument.path, + current: index + 1 === document.parentDocuments?.length, + })); + } + + if (crumbs.length < 2) { return <>; } @@ -27,8 +73,8 @@ export function Breadcrumbs({ path }: { path: string }): JSX.Element {