docs(core): powerpack docs (#27904)

-  Activate powerpack recipe
-  Powerpack owners documentation
- [x] Powerpack custom remote cache documentation
- [x] Powerpack conformance documentation

Infrastructure for powerpack docs

- Adds the ability to generate API docs from ocean packages

To generate API documentation for plugins in the ocean repository, run
the `nx documentation` command with the `NX_OCEAN_RELATIVE_PATH`
environment variable set to the relative path to your checked out copy
of the ocean repo.

```
NX_OCEAN_RELATIVE_PATH=../ocean nx documentation
```

This will create generated API documentation in the
`docs/external-generated` folder. This API will be merged into the
normal `docs/generated` documentation when the docs site is built.

Because there are two separate output folders, if someone runs `nx
documentation` without the `NX_OCEAN_RELATIVE_PATH` environment
variable, the ocean documentation will not be overwritten. The ocean
documentation will only be updated or deleted when someone explicitly
chooses to do so.

---------

Co-authored-by: Juri Strumpflohner <juri.strumpflohner@gmail.com>
This commit is contained in:
Isaac Mann 2024-09-25 10:15:47 -04:00 committed by GitHub
parent 5916c608ef
commit 12eb5df469
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
39 changed files with 3203 additions and 88 deletions

View File

@ -417,6 +417,28 @@ Embed an Nx Graph visualization that can be panned by the user.
{% /graph %} {% /graph %}
```` ````
## Generating API Documentation
To generate API documentation for the codebase and update the menu for the docs on nx.dev, you can run:
```
nx documentation
```
This will happen automatically in a `git push` hook, so you'll be reminded if you forget.
### Generate API Documentation for Ocean Plugins
To generate API documentation for plugins in the ocean repository, run the `nx documentation` command with the `NX_OCEAN_RELATIVE_PATH` environment variable set to the relative path to your checked out copy of the ocean repo.
```
NX_OCEAN_RELATIVE_PATH=../ocean nx documentation
```
This will create generated API documentation in the `docs/external-generated` folder. This API will be merged into the normal `docs/generated` documentation when the docs site is built.
Because there are two separate output folders, if someone runs `nx documentation` without the `NX_OCEAN_RELATIVE_PATH` environment variable, the ocean documentation will not be overwritten. The ocean documentation will only be updated or deleted when someone explicitly chooses to do so.
## Publishing Process ## Publishing Process
There are multiple versions of the `nx.dev` site. There are multiple versions of the `nx.dev` site.

View File

@ -0,0 +1,144 @@
[
{
"description": "Not intended for external use",
"documents": [
{
"id": "overview",
"name": "Overview",
"description": "Not intended for external use",
"file": "external-generated/packages/powerpack-conformance/documents/overview",
"itemList": [],
"isExternal": false,
"path": "powerpack-conformance/documents/overview",
"tags": [],
"originalFilePath": "shared/packages/powerpack-conformance/powerpack-conformance-plugin"
}
],
"executors": [],
"generators": [],
"githubRoot": "https://github.com/nrwl/nx/blob/master",
"name": "powerpack-conformance",
"packageName": "@nx/powerpack-conformance",
"root": "/libs/nx-packages/powerpack-conformance",
"source": "/libs/nx-packages/powerpack-conformance/src"
},
{
"description": "Not intended for external use",
"documents": [],
"executors": [],
"generators": [],
"githubRoot": "https://github.com/nrwl/nx/blob/master",
"name": "powerpack-license",
"packageName": "@nx/powerpack-license",
"root": "/libs/nx-packages/powerpack-license",
"source": "/libs/nx-packages/powerpack-license/src"
},
{
"description": "Not intended for external use",
"documents": [
{
"id": "overview",
"name": "Overview",
"description": "Not intended for external use",
"file": "external-generated/packages/powerpack-owners/documents/overview",
"itemList": [],
"isExternal": false,
"path": "powerpack-owners/documents/overview",
"tags": [],
"originalFilePath": "shared/packages/powerpack-owners/powerpack-owners-plugin"
}
],
"executors": [],
"generators": [
{
"description": "Initialize Nx Powerpack Owners config",
"file": "external-generated/packages/powerpack-owners/generators/init.json",
"hidden": false,
"name": "init",
"originalFilePath": "/libs/nx-packages/powerpack-owners/src/generators/init/schema.json",
"path": "powerpack-owners/generators/init",
"type": "generator"
},
{
"description": "Sync Nx Powerpack Owners config to a CODEOWNERS file",
"file": "external-generated/packages/powerpack-owners/generators/sync-codeowners-file.json",
"hidden": false,
"name": "sync-codeowners-file",
"originalFilePath": "/libs/nx-packages/powerpack-owners/src/generators/sync-codeowners-file/schema.json",
"path": "powerpack-owners/generators/sync-codeowners-file",
"type": "generator"
}
],
"githubRoot": "https://github.com/nrwl/nx/blob/master",
"name": "powerpack-owners",
"packageName": "@nx/powerpack-owners",
"root": "/libs/nx-packages/powerpack-owners",
"source": "/libs/nx-packages/powerpack-owners/src"
},
{
"description": "Not intended for external use",
"documents": [
{
"id": "overview",
"name": "Overview",
"description": "Not intended for external use",
"file": "external-generated/packages/powerpack-s3-cache/documents/overview",
"itemList": [],
"isExternal": false,
"path": "powerpack-s3-cache/documents/overview",
"tags": [],
"originalFilePath": "shared/packages/powerpack-s3-cache/powerpack-s3-cache-plugin"
}
],
"executors": [],
"generators": [
{
"description": "Initialize the S3 Cache",
"file": "external-generated/packages/powerpack-s3-cache/generators/init.json",
"hidden": false,
"name": "init",
"originalFilePath": "/libs/nx-packages/powerpack-s3-cache/src/generators/init/schema.json",
"path": "powerpack-s3-cache/generators/init",
"type": "generator"
}
],
"githubRoot": "https://github.com/nrwl/nx/blob/master",
"name": "powerpack-s3-cache",
"packageName": "@nx/powerpack-s3-cache",
"root": "/libs/nx-packages/powerpack-s3-cache",
"source": "/libs/nx-packages/powerpack-s3-cache/src"
},
{
"description": "A Nx Powerpack plugin for an Nx cache which is shared through the filesystem",
"documents": [
{
"id": "overview",
"name": "Overview",
"description": "A Nx Powerpack plugin for an Nx cache which is shared through the filesystem",
"file": "external-generated/packages/powerpack-shared-fs-cache/documents/overview",
"itemList": [],
"isExternal": false,
"path": "powerpack-shared-fs-cache/documents/overview",
"tags": [],
"originalFilePath": "shared/packages/powerpack-shared-fs-cache/powerpack-shared-fs-cache-plugin"
}
],
"executors": [],
"generators": [
{
"description": "Add the shared fs cache",
"file": "external-generated/packages/powerpack-shared-fs-cache/generators/init.json",
"hidden": false,
"name": "init",
"originalFilePath": "/libs/nx-packages/powerpack-shared-fs-cache/src/generators/init/schema.json",
"path": "powerpack-shared-fs-cache/generators/init",
"type": "generator"
}
],
"githubRoot": "https://github.com/nrwl/nx/blob/master",
"name": "powerpack-shared-fs-cache",
"packageName": "@nx/powerpack-shared-fs-cache",
"root": "/libs/nx-packages/powerpack-shared-fs-cache",
"source": "/libs/nx-packages/powerpack-shared-fs-cache/src"
}
]

View File

@ -0,0 +1,217 @@
---
title: Overview of the Nx powerpack-conformance Plugin
description: The Nx Powerpack Conformance plugin provides the ability to write and apply rules for your workspace
---
The `@nx/powerpack-conformance` plugin allows [Nx Powerpack]() users to write and apply rules for your entire workspace that help with **consistency**, **maintainability**, **reliability** and **security**.
The conformance plugin allows you to encode your own organization's standards so that they can be enforced automatically. Conformance rules can also complement linting tools by enforcing that those tools are configured in the recommended way. The rules are written in TypeScript but can be applied to any language in the codebase or focus entirely on configuration files.
The plugin also provides the following pre-written rules:
- [**Enforce Module Boundaries**](#enforce-module-boundaries): Similar to the Nx [ESLint Enforce Module Boundaries rule](/features/enforce-module-boundaries), but enforces the boundaries on every project dependency, not just those created from TypeScript imports or `package.json` dependencies.
- [**Ensure Owners**](#ensure-owners): Require every project to have an owner defined for the [`@nx/powerpack-owners` plugin](/nx-api/powerpack-owners)
{% callout title="This plugin requires an active Nx Powerpack license" %}
In order to use `@nx/powerpack-conformance`, you need to have an active Powerpack license. If you don't have a license or it has expired, the `nx conformance` command will fail.
{% /callout %}
## Setup
1. [Activate Powerpack](/recipes/installation/activate-powerpack) if you haven't already
2. Install the package
```shell
nx add @nx/powerpack-conformance
```
3. Configure Conformance Rules
Configure the `@nx/powerpack-conformance` plugin in the `nx.json` file or in individual project configuration files. Consult the [Conformance Configuration Reference](#conformance-configuration-reference) section for more details.
4. Run the `nx conformance` command in CI
Add `nx conformance` to the beginning of the CI process.
{% tabs %}
{% tab label="Without Nx Cloud" %}
```yaml
- name: Enforce all conformance rules
run: npx nx conformance
```
{% /tab %}
{% tab label="Using Nx Cloud" %}
```yaml
- name: Enforce all conformance rules
run: npx nx-cloud record -- npx nx conformance
```
Use `npx nx-cloud record --` to capture the logs for `nx conformance` in the Nx Cloud dashboard.
{% /tab %}
{% /tabs %}
## Conformance Configuration Reference
```jsonc {% fileName="nx.json" %}
{
"conformance": {
"rules": [{
/**
* Relative path to a local rule implementation or node_module path.
*/
"rule": "@nx/powerpack-conformance/enforce-module-boundaries";
/**
* Rule specific configuration options. (Optional)
*/
"options": {}
/**
* The projects array allows users to opt in or out of violations for specific projects being reported by the current rule.
* The array can contain any valid matchers for findMatchingProjects(), by default the implied value is ["*"]. (Optional)
*/
"projects": ["*"];
}]
}
}
```
## Provided Conformance Rules
The following rules are provided by Nx along with the `@nx/powerpack-conformance` plugin.
### Enforce Module Boundaries
This rule is similar to the Nx [ESLint Enforce Module Boundaries rule](/features/enforce-module-boundaries), but enforces the boundaries on every project dependency, not just those created from TypeScript imports or `package.json` dependencies.
Set the `rule` property to: `@nx/powerpack-conformance/enforce-module-boundaries`
```json {% fileName="nx.json" %}
{
"conformance": {
"rules": [
{
"rule": "@nx/powerpack-conformance/enforce-module-boundaries",
"options": {
// Optional
// Can be a boolean or an object with an array of buildTargetNames
"requireBuildableDependenciesForBuildableProjects": {
// Defaults to ["build"]
"buildTargetNames": ["build", "compile"]
},
// Optional
"ignoredCircularDependencies": [["projectA", "projectB"]],
// Optional
"depConstraints": [
{
// Must define either `sourceTag` or `allSourceTags`
"sourceTag": "string",
"allSourceTags": ["string"],
// Optional
"onlyDependOnLibsWithTags": [],
// Optional
"notDependOnLibsWithTags": []
}
],
// Optional
"checkDynamicDependenciesExceptions": []
}
}
]
}
}
```
#### Options
| Property | Type | Default | Description |
| ------------------------------------------------ | ------------------------- | ------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| ignoredCircularDependencies | _Array<[string, string]>_ | _[]_ | List of project pairs that should be skipped from `Circular dependencies` checks, including the self-circular dependency check. E.g. `['feature-project-a', 'myapp']`. Project name can be replaced by catch all `*` for more generic matches. |
| checkDynamicDependenciesExceptions | _Array<string>_ | _[]_ | List of imports that should be skipped for `Imports of lazy-loaded libraries forbidden` checks. E.g. `['@myorg/lazy-project/component/*', '@myorg/other-project']` |
| requireBuildableDependenciesForBuildableProjects | _boolean_ | _false_ | Enable to restrict the buildable libs from importing non-buildable libraries |
| depConstraints | _Array<object>_ | _[]_ | List of dependency constraints between projects |
#### Dependency constraints
The `depConstraints` is an array of objects representing the constraints defined between source and target projects. A
constraint must include `sourceTag` or `allSourceTags`. The constraints are applied with **AND** logical operation - for
a given `source` project the resulting constraints would be **all** that match its tags.
| Property | Type | Description |
| ------------------------ | --------------- | ---------------------------------------------------------------------------------- |
| sourceTag | _string_ | Tag that source project must contain to match the constraint |
| allSourceTags | _Array<string>_ | List of tags the source project must contain to match the constraint |
| onlyDependOnLibsWithTags | _Array<string>_ | The source **can depend only** on projects that contain at least one of these tags |
| notDependOnLibsWithTags | _Array<string>_ | The source **can not depend** on projects that contain at least one of these tags |
### Ensure Owners
This rule requires every project to have an owner defined for the [`@nx/powerpack-owners` plugin](/nx-api/powerpack-owners)
Set the `rule` property to: `@nx/powerpack-conformance/ensure-owners`
```json {% fileName="nx.json" %}
{
"conformance": {
"rules": [
{
"rule": "@nx/powerpack-conformance/ensure-owners"
}
]
}
}
```
## Custom Conformance Rules
To write your own conformance rule, specify a relative path to a TypeScript or JavaScript file as the rule name:
```json {% fileName="nx.json" %}
{
"conformance": {
"rules": [
{
"rule": "./tools/local-conformance-rule.ts"
}
]
}
}
```
The rule definition file should look like this:
```ts {% fileName="tools/local-conformance-rule.ts" %}
import type {
ConformanceRule,
ConformanceRuleResult,
createConformanceRule,
} from '@nx/powerpack-conformance';
const rule = createConformanceRule({
name: 'local-conformance-rule-example',
category: 'security', // `consistency`, `maintainability`, `reliability` or `security`
reporter: 'project-reporter', // `project-reporter` or `project-files-reporter`
implementation: async (context): Promise<ConformanceRuleResult> => {
const { projectGraph, ruleOptions } = context;
// Your rule logic goes here
return {
severity: 'low', // 'high', 'medium' or 'low'
details: {
violations: [
// Return an empty array if the rule passes
{
sourceProject: 'my-project',
message: 'This is an informative error message.',
},
],
},
};
},
});
export default rule;
```
Note that the severity of the error is defined by the rule author and can be adjusted based on the specific violations that are found.

View File

@ -0,0 +1,326 @@
---
title: Overview of the Nx powerpack-owners Plugin
description: The Nx Powerpack Owners plugin provides the ability to define code ownership based on projects in addition to files
---
The `@nx/powerpack-owners` plugin extends the CODEOWNERS functionality to allow you to define code ownership based on projects in addition to the standard file-based definitions. It leverages the [`nx sync`](/concepts/sync-generators) command to compile `owners` configuration settings from `nx.json` and project configuration files into valid CODEOWNERS files for [GitHub](https://docs.github.com/en/repositories/managing-your-repositorys-settings-and-features/customizing-your-repository/about-code-owners), [Bitbucket](https://support.atlassian.com/bitbucket-cloud/docs/set-up-and-use-code-owners/) or [GitLab](https://docs.gitlab.com/ee/user/project/codeowners/).
With this plugin, you can specify code ownership using the same project matcher syntax as [`nx run-many`](/nx-api/nx/documents/run-many#examples). This allows you to easily define rules for multiple projects that may not be located in the same directory. Also, the CODEOWNERS rules will not need to be revisited if a project location is changed or a new project is added.
{% callout title="This plugin requires an active Nx Powerpack license" %}
In order to use `@nx/powerpack-owners`, you need to have an active Powerpack license. If you don't have a license or it has expired, the syncing process will stop working and you'll need to manually maintain your CODEOWNERS file.
{% /callout %}
## Setup
1. [Activate Powerpack](/recipes/installation/activate-powerpack) if you haven't already
2. Install the package
```shell
nx add @nx/powerpack-owners
```
3. Configure Ownership
Configure the `@nx/powerpack-owners` plugin in the `nx.json` file or in individual project configuration files. Consult the [Owners Configuration Reference](#owners-configuration-reference) section for more details.
4. Configure the [Sync Generator](/concepts/sync-generators) and CI
The `nx add @nx/powerpack-owners` command should have registered the `@nx/powerpack-owners:sync-codeowners-file` generator as a `globalGenerator` in `nx.json`. You can double check to make sure:
```jsonc {% fileName="nx.json" %}
{
"sync": {
"globalGenerators": ["@nx/powerpack-owners:sync-codeowners-file"]
}
}
```
Add `nx sync:check` to the beginning of the CI process.
```yaml
- name: Ensure the workspace configuration is in sync
run: npx nx sync:check
```
It is also often helpful to add `nx sync` as a git push hook or git commit hook.
## Owners Configuration Reference
{% tabs %}
{% tab label="GitHub" %}
```jsonc {% fileName="nx.json" %}
{
// Can be set to true instead of an object to accept all defaults
"owners": {
// Options are `github`, `bitbucket` or `gitlab`. (Optional) Defaults to `github`
"format": "github",
// (Optional) Default changes based on format: `.github/CODEOWNERS`, `.bitbucket/CODEOWNERS`, `.gitlab/CODEOWNERS`
"outputPath": "CODEOWNERS",
// (Optional)
"patterns": [
{
"description": "A description of the rule",
"owners": ["@joelovesrust"],
// specify either projects or files, not both
// Can be any project specifier that could be used in `nx run-many`
// See https://nx.dev/nx-api/nx/documents/run-many
"projects": ["my-rust-app", "rust-*", "tag:rust"],
// File globs
"files": [".github/workflows/**/*"]
}
]
}
}
```
{% /tab %}
{% tab label="Bitbucket" %}
```jsonc {% fileName="nx.json" %}
{
// Can be set to true instead of an object to accept all defaults
"owners": {
// Options are `github`, `bitbucket` or `gitlab`. (Optional) Defaults to `github`
"format": "bitbucket",
// (Optional) Default changes based on format: `.github/CODEOWNERS`, `.bitbucket/CODEOWNERS`, `.gitlab/CODEOWNERS`
"outputPath": "CODEOWNERS",
// (Optional)
"patterns": [
{
"description": "A description of the rule",
"owners": ["@joelovesrust"],
// specify either projects or files, not both
// Can be any project specifier that could be used in `nx run-many`
// See https://nx.dev/nx-api/nx/documents/run-many
"projects": ["my-rust-app", "rust-*", "tag:rust"],
// File globs
"files": [".github/workflows/**/*"]
}
]
}
}
```
{% /tab %}
{% tab label="GitLab" %}
If you are using GitLab, you can specify CODEOWNERS [sections](https://docs.gitlab.com/ee/user/project/codeowners/#organize-code-owners-by-putting-them-into-sections) which give you a little more control over the PR process.
```jsonc {% fileName="nx.json" %}
{
// Can be set to true instead of an object to accept all defaults
"owners": {
// Options are `github`, `bitbucket` or `gitlab`. (Optional) Defaults to `github`
"format": "gitlab",
// (Optional) Default changes based on format: `.github/CODEOWNERS`, `.bitbucket/CODEOWNERS`, `.gitlab/CODEOWNERS`
"outputPath": "CODEOWNERS",
// (Optional)
"patterns": [
{
"description": "A description of the rule",
"owners": ["@joelovesrust"],
// Specify either `projects` or `files`, not both
// Can be any project specifier that could be used in `nx run-many`
// See https://nx.dev/nx-api/nx/documents/run-many
"projects": ["my-rust-app", "rust-*", "tag:rust"],
// File globs
"files": [".github/workflows/**/*"]
}
],
// (Optional)
"sections": [
{
// Labels the section
"name": "My section",
// (Optional) The owners to use if a pattern does not specify a set of owners
"defaultOwners": ["@cheddar"],
// Specify either `numberOfRequiredApprovals` or `optional`, not both
// (Optional) Require more than one person to approve the PR
"numberOfRequiredApprovals": 2,
// (Optional) Do not require any approvals, just notify the owners
"optional": true,
// Same format as the root patterns
"patterns": []
}
]
}
}
```
```jsonc {% fileName="path/to/project/project.json" %}
{
"owners": {
// Keys are file globs relative to the root of the project
// Owners can be listed as a string array
"**/*": ["@ahmed", "@petra"],
// Owners can be listed as an object with a description
"README.md": {
"description": "Jared is very particular about the README file",
"owners": ["@jared"]
}
}
};
```
{% /tab %}
{% /tabs %}
**Examples:**
{% tabs %}
{% tab label="GitHub" %}
```jsonc {% fileName="nx.json" %}
{
"owners": {
// defaults to "github"
"format": "github",
// defaults to ".github/CODEOWNERS"
"outputPath": "CODEOWNERS",
"patterns": [
{
"description": "Joe should double check all changes to rust code",
"projects": ["tag:rust"],
"owners": ["@joelovesrust"]
},
{
"description": "The Finance team owns these projects",
"projects": ["finance-*"],
"owners": ["@finance-team"]
},
{
"description": "Alice, Bob and Cecil work together on these projects",
"projects": ["admin", "booking", "cart"],
"owners": ["@alice", "@bob", "@cecil"]
},
{
"description": "CI Workflows",
"files": [".github/workflows/**/*"],
"owners": ["@devops"]
}
]
}
}
```
```jsonc {% fileName="packages/my-project/project.json" %}
{
"owners": {
"**/*": ["@ahmed", "@petra"],
"package.json": ["@ahmed"],
"README.md": {
"owners": ["@jared"],
"description": "Jared is very particular about the README file"
}
},
};
```
{% /tab %}
{% tab label="Bitbucket" %}
```jsonc {% fileName="nx.json" %}
{
"owners": {
"format": "bitbucket",
// defaults to ".bitbucket/CODEOWNERS"
"outputPath": "CODEOWNERS",
"patterns": [
{
"description": "Joe should double check all changes to rust code",
"projects": ["tag:rust"],
"owners": ["@joelovesrust"]
},
{
"description": "The Finance team owns these projects",
"projects": ["finance-*"],
"owners": ["@finance-team"]
},
{
"description": "Alice, Bob and Cecil work together on these projects",
"projects": ["admin", "booking", "cart"],
"owners": ["@alice", "@bob", "@cecil"]
},
{
"description": "CI Workflows",
"files": [".github/workflows/**/*"],
"owners": ["@devops"]
}
]
}
}
```
```jsonc {% fileName="packages/my-project/project.json" %}
{
"owners": {
"**/*": ["@ahmed", "@petra"],
"package.json": ["@ahmed"],
"README.md": {
"owners": ["@jared"],
"description": "Jared is very particular about the README file"
}
},
};
```
{% /tab %}
{% tab label="GitLab" %}
```jsonc {% fileName="nx.json" %}
{
"owners": {
"format": "gitlab",
// defaults to ".gitlab/CODEOWNERS"
"outputPath": "CODEOWNERS",
"patterns": [
{
"description": "Joe should double check all changes to rust code",
"projects": ["tag:rust"],
"owners": ["@joelovesrust"]
},
{
"description": "CI Workflows",
"files": [".github/workflows/**/*"],
"owners": ["@devops"]
}
],
"sections": [
{
"name": "Finance",
"defaultOwners": ["@finance-team"],
"numberOfRequiredApprovals": 2,
"patterns": [
{
"description": "The Finance team owns these projects",
"projects": ["finance-*"]
},
{
"description": "Alice, Bob and Cecil work together on these projects",
"projects": ["admin", "booking", "cart"],
"owners": ["@alice", "@bob", "@cecil"]
}
]
}
]
}
}
```
```jsonc {% fileName="packages/my-project/project.json" %}
{
"owners": {
"**/*": ["@ahmed", "@petra"],
"package.json": ["@ahmed"],
"README.md": {
"owners": ["@jared"],
"description": "Jared is very particular about the README file"
}
},
};
```
{% /tab %}
{% /tabs %}

View File

@ -0,0 +1,21 @@
{
"name": "init",
"factory": "./src/generators/init/init",
"schema": {
"$schema": "http://json-schema.org/schema",
"id": "NxPowerpackOwnersInit",
"title": "Add Powerpack Owners Configuration to the workspace",
"type": "object",
"cli": "nx",
"properties": {},
"additionalProperties": false,
"required": [],
"presets": []
},
"description": "Initialize Nx Powerpack Owners config",
"implementation": "/libs/nx-packages/powerpack-owners/src/generators/init/init.ts",
"aliases": [],
"hidden": false,
"path": "/libs/nx-packages/powerpack-owners/src/generators/init/schema.json",
"type": "generator"
}

View File

@ -0,0 +1,19 @@
{
"name": "sync-codeowners-file",
"factory": "./src/generators/sync-codeowners-file/generator",
"schema": {
"$schema": "https://json-schema.org/schema",
"$id": "NxPowerpackOwnersSyncCodeownersFileGenerator",
"title": "Nx Powerpack Owners Sync CODEOWNERS File Generator",
"type": "object",
"properties": {},
"required": [],
"presets": []
},
"description": "Sync Nx Powerpack Owners config to a CODEOWNERS file",
"implementation": "/libs/nx-packages/powerpack-owners/src/generators/sync-codeowners-file/generator.ts",
"aliases": [],
"hidden": false,
"path": "/libs/nx-packages/powerpack-owners/src/generators/sync-codeowners-file/schema.json",
"type": "generator"
}

View File

@ -0,0 +1,92 @@
---
title: Overview of the Nx powerpack-s3-cache Plugin
description: The powerpack-s3-cache Nx plugin enables you to use an AWS S3 bucket to host your remote cache instead of Nx Cloud
---
The `@nx/powerpack-s3-cache` plugin enables you to use an AWS S3 bucket instead of Nx Cloud to host your remote cache.
{% callout title="This plugin requires an active Nx Powerpack license" %}
In order to use `@nx/powerpack-s3-cache`, you need to have an active Powerpack license. If you don't have a license or it has expired, your cache will no longer be shared and each machine will use its local cache.
{% /callout %}
## Setup
### 1. Install the Package
1. [Activate Powerpack](/recipes/installation/activate-powerpack) if you haven't already
2. Install the package
```shell
nx add @nx/powerpack-s3-cache
```
### 2. Authenticate with AWS
There are four different ways to authenticate with AWS. They will be attempted in this order:
1. Environment variables
2. INI config files
3. Single sign-on
4. `nx.json` settings
#### Environment Variables
[AWS provides environment variables](https://docs.aws.amazon.com/sdkref/latest/guide/environment-variables.html) that can be used to authenticate:
| **Environment Variable** | **Description** |
| --------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `AWS_ACCESS_KEY_ID` | The access key for your AWS account. |
| `AWS_SECRET_ACCESS_KEY` | The secret key for your AWS account. |
| `AWS_SESSION_TOKEN` | The session key for your AWS account. This is only needed when you are using temporary credentials. |
| `AWS_CREDENTIAL_EXPIRATION` | The expiration time of the credentials contained in the environment variables described above. This value must be in a format compatible with the [ISO-8601 standard](https://en.wikipedia.org/wiki/ISO_8601) and is only needed when you are using temporary credentials. |
Both the `AWS_ACCESS_KEY_ID` and the `AWS_SECRET_ACCESS_KEY` environment variables are required to use the environment variable authentication method.
#### INI Config Files
AWS can read your authentication credentials from [shared INI config files](https://docs.aws.amazon.com/sdkref/latest/guide/file-format.html). The files are located at `~/.aws/credentials` and `~/.aws/config`. Both files are expected to be INI formatted with section names corresponding to profiles. Sections in the credentials file are treated as profile names, whereas profile sections in the config file must have the format of `[profile profile-name]`, except for the default profile. Profiles that appear in both files will not be merged, and the version that appears in the credentials file will be given precedence over the profile found in the config file.
#### Single Sign-On
Nx can read the active access token [created after running `aws sso login`](https://docs.aws.amazon.com/sdkref/latest/guide/understanding-sso.html) then request temporary AWS credentials. You can create the `AwsCredentialIdentityProvider` functions using the inline SSO parameters (`ssoStartUrl`, `ssoAccountId`, `ssoRegion`, `ssoRoleName`) or load them from [AWS SDKs and Tools shared configuration and credentials files](https://docs.aws.amazon.com/credref/latest/refdocs/creds-config-files.html). Profiles in the `credentials` file are given precedence over profiles in the `config` file.
#### Credentials in `nx.json` File
Storing your credentials in the `nx.json` file is the least secure of the 4 authentication options, since anyone with read access to your code base will have access to your AWS credentials.
```jsonc {% fileName="nx.json" %}
{
"s3": {
"ssoProfile": "default",
"accessKeyId": "MYACCESSKEYID",
"secretAccessKey": "MYSECRETACCESSKEY"
}
}
```
| **Property** | **Description** |
| ------------------- | ----------------------------------------------------------------------------- |
| **ssoProfile** | The name of the profile to use from your AWS CLI SSO Configuration (optional) |
| **endpoint** | The AWS endpoint URL (optional) |
| **accessKeyId** | AWS Access Key ID (optional) |
| **secretAccessKey** | AWS secret access key (optional) |
### 3. Configure S3 Cache
Regardless of how you manage your AWS authentication, you need to configure your Nx cache in the `nx.json` file. The `bucket` that you specify needs to already exist - Nx doesn't create it for you.
```jsonc {% fileName="nx.json" %}
{
"s3": {
"region": "us-east-1",
"bucket": "my-bucket",
"encryptionKey": "create-your-own-key"
}
}
```
| **Property** | **Description** |
| ----------------- | --------------------------------------------------------------------------------- |
| **region** | The id of the AWS region to use |
| **bucket** | The name of the AWS bucket to use |
| **encryptionKey** | Nx encryption key used to encrypt and decrypt artifacts from the cache (optional) |

View File

@ -0,0 +1,30 @@
{
"name": "init",
"factory": "./src/generators/init/generator",
"schema": {
"$schema": "https://json-schema.org/schema",
"$id": "Init",
"title": "",
"type": "object",
"properties": {
"region": {
"type": "string",
"description": "The AWS region the bucket is located in",
"x-prompt": "Which AWS region is the bucket located in?"
},
"bucket": {
"type": "string",
"description": "The the name of the S3 Bucket to store the Nx Cache in",
"x-prompt": "What is the name of the S3 Bucket to store the Nx Cache in?"
}
},
"required": ["region", "bucket"],
"presets": []
},
"description": "Initialize the S3 Cache",
"implementation": "/libs/nx-packages/powerpack-s3-cache/src/generators/init/generator.ts",
"aliases": [],
"hidden": false,
"path": "/libs/nx-packages/powerpack-s3-cache/src/generators/init/schema.json",
"type": "generator"
}

View File

@ -0,0 +1,33 @@
---
title: Overview of the Nx powerpack-shared-fs-cache Plugin
description: The powerpack-shared-fs-cache Nx plugin enables you to use an shared file system directory instead of Nx Cloud to host your remote cache
---
The `@nx/powerpack-shared-fs-cache` plugin enables you to use an shared file system directory instead of Nx Cloud to host your remote cache. You are responsible for the sharing mechanism for the directory, but the plugin ensures that Nx correctly associates task metadata with the file artifacts.
{% callout type="warning" title="Potential Cache Poisoning" %}
Using a shared file system folder for the remote cache opens you up to the possibility of [cache poisoning](/troubleshooting/unknown-local-cache). To avoid this, use [Nx Replay](/ci/features/remote-cache) or share your cache with an AWS S3 bucket using [`@nx/powerpack-s3-cache`](/nx-api/powerpack-s3-cache).
{% /callout %}
{% callout title="This plugin requires an active Nx Powerpack license" %}
In order to use `@nx/powerpack-shared-fs-cache`, you need to have an active Powerpack license. If you don't have a license or it has expired, your cache will no longer be shared and each machine will use its local cache.
{% /callout %}
## Setup
### 1. Install the Package
1. [Activate Powerpack](/recipes/installation/activate-powerpack) if you haven't already
2. Install the package
```shell
nx add @nx/powerpack-shared-fs-cache
```
### 2. Configure the Cache Directory
The `@nx/powerpack-shared-fs-cache` plugin treats your local cache directory as if it is also a remote cache directory. The local cache directory can be set using `cacheDirectory` in the `nx.json` file or the `NX_CACHE_DIRECTORY` environment variable. The default local cache directory is `.nx/cache`
### 3. Share the Cache Directory
The `@nx/powerpack-shared-fs-cache` plugin does not actually share the cache directory across your organization. If you want that functionality, use [Nx Replay](/ci/features/remote-cache) instead. Your shared file system directory might be a directory that is saved and restored by a CI provider or it could be a shared network drive.

View File

@ -0,0 +1,19 @@
{
"name": "init",
"factory": "./src/generators/init/generator",
"schema": {
"$schema": "https://json-schema.org/schema",
"$id": "Init",
"title": "",
"type": "object",
"properties": {},
"required": [],
"presets": []
},
"description": "Add the shared fs cache",
"implementation": "/libs/nx-packages/powerpack-shared-fs-cache/src/generators/init/generator.ts",
"aliases": [],
"hidden": false,
"path": "/libs/nx-packages/powerpack-shared-fs-cache/src/generators/init/schema.json",
"type": "generator"
}

View File

@ -323,6 +323,39 @@
"children": [], "children": [],
"disableCollapsible": false "disableCollapsible": false
}, },
{
"name": "Powerpack Features",
"path": "/features/powerpack",
"id": "powerpack",
"isExternal": false,
"children": [
{
"name": "Run Language-Agnostic Conformance Rules",
"path": "/features/powerpack/conformance",
"id": "conformance",
"isExternal": false,
"children": [],
"disableCollapsible": false
},
{
"name": "Define Code Ownership at the Project Level",
"path": "/features/powerpack/owners",
"id": "owners",
"isExternal": false,
"children": [],
"disableCollapsible": false
},
{
"name": "Self-Host the Remote Cache",
"path": "/features/powerpack/custom-caching",
"id": "custom-caching",
"isExternal": false,
"children": [],
"disableCollapsible": false
}
],
"disableCollapsible": false
},
{ {
"name": "CI Features", "name": "CI Features",
"path": "/features/ci-features", "path": "/features/ci-features",
@ -439,6 +472,63 @@
"children": [], "children": [],
"disableCollapsible": false "disableCollapsible": false
}, },
{
"name": "Powerpack Features",
"path": "/features/powerpack",
"id": "powerpack",
"isExternal": false,
"children": [
{
"name": "Run Language-Agnostic Conformance Rules",
"path": "/features/powerpack/conformance",
"id": "conformance",
"isExternal": false,
"children": [],
"disableCollapsible": false
},
{
"name": "Define Code Ownership at the Project Level",
"path": "/features/powerpack/owners",
"id": "owners",
"isExternal": false,
"children": [],
"disableCollapsible": false
},
{
"name": "Self-Host the Remote Cache",
"path": "/features/powerpack/custom-caching",
"id": "custom-caching",
"isExternal": false,
"children": [],
"disableCollapsible": false
}
],
"disableCollapsible": false
},
{
"name": "Run Language-Agnostic Conformance Rules",
"path": "/features/powerpack/conformance",
"id": "conformance",
"isExternal": false,
"children": [],
"disableCollapsible": false
},
{
"name": "Define Code Ownership at the Project Level",
"path": "/features/powerpack/owners",
"id": "owners",
"isExternal": false,
"children": [],
"disableCollapsible": false
},
{
"name": "Self-Host the Remote Cache",
"path": "/features/powerpack/custom-caching",
"id": "custom-caching",
"isExternal": false,
"children": [],
"disableCollapsible": false
},
{ {
"name": "CI Features", "name": "CI Features",
"path": "/features/ci-features", "path": "/features/ci-features",
@ -1081,6 +1171,14 @@
"id": "installation", "id": "installation",
"isExternal": false, "isExternal": false,
"children": [ "children": [
{
"name": "Activate Powerpack",
"path": "/recipes/installation/activate-powerpack",
"id": "activate-powerpack",
"isExternal": false,
"children": [],
"disableCollapsible": false
},
{ {
"name": "Install Nx in a Non-Javascript Repo", "name": "Install Nx in a Non-Javascript Repo",
"path": "/recipes/installation/install-non-javascript", "path": "/recipes/installation/install-non-javascript",
@ -2095,6 +2193,14 @@
"id": "installation", "id": "installation",
"isExternal": false, "isExternal": false,
"children": [ "children": [
{
"name": "Activate Powerpack",
"path": "/recipes/installation/activate-powerpack",
"id": "activate-powerpack",
"isExternal": false,
"children": [],
"disableCollapsible": false
},
{ {
"name": "Install Nx in a Non-Javascript Repo", "name": "Install Nx in a Non-Javascript Repo",
"path": "/recipes/installation/install-non-javascript", "path": "/recipes/installation/install-non-javascript",
@ -2114,6 +2220,14 @@
], ],
"disableCollapsible": false "disableCollapsible": false
}, },
{
"name": "Activate Powerpack",
"path": "/recipes/installation/activate-powerpack",
"id": "activate-powerpack",
"isExternal": false,
"children": [],
"disableCollapsible": false
},
{ {
"name": "Install Nx in a Non-Javascript Repo", "name": "Install Nx in a Non-Javascript Repo",
"path": "/recipes/installation/install-non-javascript", "path": "/recipes/installation/install-non-javascript",
@ -4762,6 +4876,14 @@
"children": [], "children": [],
"disableCollapsible": false "disableCollapsible": false
}, },
{
"name": "Custom Task Runners",
"path": "/deprecated/custom-task-runners",
"id": "custom-task-runners",
"isExternal": false,
"children": [],
"disableCollapsible": false
},
{ {
"name": "Workspace Executors", "name": "Workspace Executors",
"path": "/deprecated/workspace-executors", "path": "/deprecated/workspace-executors",
@ -4861,6 +4983,14 @@
"children": [], "children": [],
"disableCollapsible": false "disableCollapsible": false
}, },
{
"name": "Custom Task Runners",
"path": "/deprecated/custom-task-runners",
"id": "custom-task-runners",
"isExternal": false,
"children": [],
"disableCollapsible": false
},
{ {
"name": "Workspace Executors", "name": "Workspace Executors",
"path": "/deprecated/workspace-executors", "path": "/deprecated/workspace-executors",
@ -10399,6 +10529,177 @@
], ],
"isExternal": false, "isExternal": false,
"disableCollapsible": false "disableCollapsible": false
},
{
"id": "powerpack-conformance",
"path": "/nx-api/powerpack-conformance",
"name": "powerpack-conformance",
"children": [
{
"id": "documents",
"path": "/nx-api/powerpack-conformance/documents",
"name": "documents",
"children": [
{
"name": "Overview",
"path": "/nx-api/powerpack-conformance/documents/overview",
"id": "overview",
"isExternal": false,
"children": [],
"disableCollapsible": false
}
],
"isExternal": false,
"disableCollapsible": false
}
],
"isExternal": false,
"disableCollapsible": false
},
{
"id": "powerpack-license",
"path": "/nx-api/powerpack-license",
"name": "powerpack-license",
"children": [],
"isExternal": false,
"disableCollapsible": false
},
{
"id": "powerpack-owners",
"path": "/nx-api/powerpack-owners",
"name": "powerpack-owners",
"children": [
{
"id": "documents",
"path": "/nx-api/powerpack-owners/documents",
"name": "documents",
"children": [
{
"name": "Overview",
"path": "/nx-api/powerpack-owners/documents/overview",
"id": "overview",
"isExternal": false,
"children": [],
"disableCollapsible": false
}
],
"isExternal": false,
"disableCollapsible": false
},
{
"id": "generators",
"path": "/nx-api/powerpack-owners/generators",
"name": "generators",
"children": [
{
"id": "init",
"path": "/nx-api/powerpack-owners/generators/init",
"name": "init",
"children": [],
"isExternal": false,
"disableCollapsible": false
},
{
"id": "sync-codeowners-file",
"path": "/nx-api/powerpack-owners/generators/sync-codeowners-file",
"name": "sync-codeowners-file",
"children": [],
"isExternal": false,
"disableCollapsible": false
}
],
"isExternal": false,
"disableCollapsible": false
}
],
"isExternal": false,
"disableCollapsible": false
},
{
"id": "powerpack-s3-cache",
"path": "/nx-api/powerpack-s3-cache",
"name": "powerpack-s3-cache",
"children": [
{
"id": "documents",
"path": "/nx-api/powerpack-s3-cache/documents",
"name": "documents",
"children": [
{
"name": "Overview",
"path": "/nx-api/powerpack-s3-cache/documents/overview",
"id": "overview",
"isExternal": false,
"children": [],
"disableCollapsible": false
}
],
"isExternal": false,
"disableCollapsible": false
},
{
"id": "generators",
"path": "/nx-api/powerpack-s3-cache/generators",
"name": "generators",
"children": [
{
"id": "init",
"path": "/nx-api/powerpack-s3-cache/generators/init",
"name": "init",
"children": [],
"isExternal": false,
"disableCollapsible": false
}
],
"isExternal": false,
"disableCollapsible": false
}
],
"isExternal": false,
"disableCollapsible": false
},
{
"id": "powerpack-shared-fs-cache",
"path": "/nx-api/powerpack-shared-fs-cache",
"name": "powerpack-shared-fs-cache",
"children": [
{
"id": "documents",
"path": "/nx-api/powerpack-shared-fs-cache/documents",
"name": "documents",
"children": [
{
"name": "Overview",
"path": "/nx-api/powerpack-shared-fs-cache/documents/overview",
"id": "overview",
"isExternal": false,
"children": [],
"disableCollapsible": false
}
],
"isExternal": false,
"disableCollapsible": false
},
{
"id": "generators",
"path": "/nx-api/powerpack-shared-fs-cache/generators",
"name": "generators",
"children": [
{
"id": "init",
"path": "/nx-api/powerpack-shared-fs-cache/generators/init",
"name": "init",
"children": [],
"isExternal": false,
"disableCollapsible": false
}
],
"isExternal": false,
"disableCollapsible": false
}
],
"isExternal": false,
"disableCollapsible": false
} }
] ]
} }

View File

@ -3490,5 +3490,152 @@
} }
}, },
"path": "/nx-api/workspace" "path": "/nx-api/workspace"
},
"powerpack-conformance": {
"githubRoot": "https://github.com/nrwl/nx/blob/master",
"name": "powerpack-conformance",
"packageName": "@nx/powerpack-conformance",
"description": "Not intended for external use",
"documents": {
"/nx-api/powerpack-conformance/documents/overview": {
"id": "overview",
"name": "Overview",
"description": "Not intended for external use",
"file": "external-generated/packages/powerpack-conformance/documents/overview",
"itemList": [],
"isExternal": false,
"path": "/nx-api/powerpack-conformance/documents/overview",
"tags": [],
"originalFilePath": "shared/packages/powerpack-conformance/powerpack-conformance-plugin"
}
},
"root": "/libs/nx-packages/powerpack-conformance",
"source": "/libs/nx-packages/powerpack-conformance/src",
"executors": {},
"generators": {},
"path": "/nx-api/powerpack-conformance"
},
"powerpack-license": {
"githubRoot": "https://github.com/nrwl/nx/blob/master",
"name": "powerpack-license",
"packageName": "@nx/powerpack-license",
"description": "Not intended for external use",
"documents": {},
"root": "/libs/nx-packages/powerpack-license",
"source": "/libs/nx-packages/powerpack-license/src",
"executors": {},
"generators": {},
"path": "/nx-api/powerpack-license"
},
"powerpack-owners": {
"githubRoot": "https://github.com/nrwl/nx/blob/master",
"name": "powerpack-owners",
"packageName": "@nx/powerpack-owners",
"description": "Not intended for external use",
"documents": {
"/nx-api/powerpack-owners/documents/overview": {
"id": "overview",
"name": "Overview",
"description": "Not intended for external use",
"file": "external-generated/packages/powerpack-owners/documents/overview",
"itemList": [],
"isExternal": false,
"path": "/nx-api/powerpack-owners/documents/overview",
"tags": [],
"originalFilePath": "shared/packages/powerpack-owners/powerpack-owners-plugin"
}
},
"root": "/libs/nx-packages/powerpack-owners",
"source": "/libs/nx-packages/powerpack-owners/src",
"executors": {},
"generators": {
"/nx-api/powerpack-owners/generators/init": {
"description": "Initialize Nx Powerpack Owners config",
"file": "external-generated/packages/powerpack-owners/generators/init.json",
"hidden": false,
"name": "init",
"originalFilePath": "/libs/nx-packages/powerpack-owners/src/generators/init/schema.json",
"path": "/nx-api/powerpack-owners/generators/init",
"type": "generator"
},
"/nx-api/powerpack-owners/generators/sync-codeowners-file": {
"description": "Sync Nx Powerpack Owners config to a CODEOWNERS file",
"file": "external-generated/packages/powerpack-owners/generators/sync-codeowners-file.json",
"hidden": false,
"name": "sync-codeowners-file",
"originalFilePath": "/libs/nx-packages/powerpack-owners/src/generators/sync-codeowners-file/schema.json",
"path": "/nx-api/powerpack-owners/generators/sync-codeowners-file",
"type": "generator"
}
},
"path": "/nx-api/powerpack-owners"
},
"powerpack-s3-cache": {
"githubRoot": "https://github.com/nrwl/nx/blob/master",
"name": "powerpack-s3-cache",
"packageName": "@nx/powerpack-s3-cache",
"description": "Not intended for external use",
"documents": {
"/nx-api/powerpack-s3-cache/documents/overview": {
"id": "overview",
"name": "Overview",
"description": "Not intended for external use",
"file": "external-generated/packages/powerpack-s3-cache/documents/overview",
"itemList": [],
"isExternal": false,
"path": "/nx-api/powerpack-s3-cache/documents/overview",
"tags": [],
"originalFilePath": "shared/packages/powerpack-s3-cache/powerpack-s3-cache-plugin"
}
},
"root": "/libs/nx-packages/powerpack-s3-cache",
"source": "/libs/nx-packages/powerpack-s3-cache/src",
"executors": {},
"generators": {
"/nx-api/powerpack-s3-cache/generators/init": {
"description": "Initialize the S3 Cache",
"file": "external-generated/packages/powerpack-s3-cache/generators/init.json",
"hidden": false,
"name": "init",
"originalFilePath": "/libs/nx-packages/powerpack-s3-cache/src/generators/init/schema.json",
"path": "/nx-api/powerpack-s3-cache/generators/init",
"type": "generator"
}
},
"path": "/nx-api/powerpack-s3-cache"
},
"powerpack-shared-fs-cache": {
"githubRoot": "https://github.com/nrwl/nx/blob/master",
"name": "powerpack-shared-fs-cache",
"packageName": "@nx/powerpack-shared-fs-cache",
"description": "A Nx Powerpack plugin for an Nx cache which is shared through the filesystem",
"documents": {
"/nx-api/powerpack-shared-fs-cache/documents/overview": {
"id": "overview",
"name": "Overview",
"description": "A Nx Powerpack plugin for an Nx cache which is shared through the filesystem",
"file": "external-generated/packages/powerpack-shared-fs-cache/documents/overview",
"itemList": [],
"isExternal": false,
"path": "/nx-api/powerpack-shared-fs-cache/documents/overview",
"tags": [],
"originalFilePath": "shared/packages/powerpack-shared-fs-cache/powerpack-shared-fs-cache-plugin"
}
},
"root": "/libs/nx-packages/powerpack-shared-fs-cache",
"source": "/libs/nx-packages/powerpack-shared-fs-cache/src",
"executors": {},
"generators": {
"/nx-api/powerpack-shared-fs-cache/generators/init": {
"description": "Add the shared fs cache",
"file": "external-generated/packages/powerpack-shared-fs-cache/generators/init.json",
"hidden": false,
"name": "init",
"originalFilePath": "/libs/nx-packages/powerpack-shared-fs-cache/src/generators/init/schema.json",
"path": "/nx-api/powerpack-shared-fs-cache/generators/init",
"type": "generator"
}
},
"path": "/nx-api/powerpack-shared-fs-cache"
} }
} }

View File

@ -438,6 +438,51 @@
"path": "/features/manage-releases", "path": "/features/manage-releases",
"tags": ["nx-release"] "tags": ["nx-release"]
}, },
{
"id": "powerpack",
"name": "Powerpack Features",
"description": "Features of Nx that are available with a powerpack license.",
"mediaImage": "",
"file": "",
"itemList": [
{
"id": "conformance",
"name": "Run Language-Agnostic Conformance Rules",
"description": "Conformance",
"mediaImage": "",
"file": "shared/features/powerpack/conformance",
"itemList": [],
"isExternal": false,
"path": "/features/powerpack/conformance",
"tags": ["conformance"]
},
{
"id": "owners",
"name": "Define Code Ownership at the Project Level",
"description": "Owners",
"mediaImage": "",
"file": "shared/features/powerpack/owners",
"itemList": [],
"isExternal": false,
"path": "/features/powerpack/owners",
"tags": ["owners"]
},
{
"id": "custom-caching",
"name": "Self-Host the Remote Cache",
"description": "Custom Caching",
"mediaImage": "",
"file": "shared/features/powerpack/custom-caching",
"itemList": [],
"isExternal": false,
"path": "/features/powerpack/custom-caching",
"tags": ["custom-caching"]
}
],
"isExternal": false,
"path": "/features/powerpack",
"tags": []
},
{ {
"id": "ci-features", "id": "ci-features",
"name": "CI Features", "name": "CI Features",
@ -598,6 +643,84 @@
"path": "/features/manage-releases", "path": "/features/manage-releases",
"tags": ["nx-release"] "tags": ["nx-release"]
}, },
"/features/powerpack": {
"id": "powerpack",
"name": "Powerpack Features",
"description": "Features of Nx that are available with a powerpack license.",
"mediaImage": "",
"file": "",
"itemList": [
{
"id": "conformance",
"name": "Run Language-Agnostic Conformance Rules",
"description": "Conformance",
"mediaImage": "",
"file": "shared/features/powerpack/conformance",
"itemList": [],
"isExternal": false,
"path": "/features/powerpack/conformance",
"tags": ["conformance"]
},
{
"id": "owners",
"name": "Define Code Ownership at the Project Level",
"description": "Owners",
"mediaImage": "",
"file": "shared/features/powerpack/owners",
"itemList": [],
"isExternal": false,
"path": "/features/powerpack/owners",
"tags": ["owners"]
},
{
"id": "custom-caching",
"name": "Self-Host the Remote Cache",
"description": "Custom Caching",
"mediaImage": "",
"file": "shared/features/powerpack/custom-caching",
"itemList": [],
"isExternal": false,
"path": "/features/powerpack/custom-caching",
"tags": ["custom-caching"]
}
],
"isExternal": false,
"path": "/features/powerpack",
"tags": []
},
"/features/powerpack/conformance": {
"id": "conformance",
"name": "Run Language-Agnostic Conformance Rules",
"description": "Conformance",
"mediaImage": "",
"file": "shared/features/powerpack/conformance",
"itemList": [],
"isExternal": false,
"path": "/features/powerpack/conformance",
"tags": ["conformance"]
},
"/features/powerpack/owners": {
"id": "owners",
"name": "Define Code Ownership at the Project Level",
"description": "Owners",
"mediaImage": "",
"file": "shared/features/powerpack/owners",
"itemList": [],
"isExternal": false,
"path": "/features/powerpack/owners",
"tags": ["owners"]
},
"/features/powerpack/custom-caching": {
"id": "custom-caching",
"name": "Self-Host the Remote Cache",
"description": "Custom Caching",
"mediaImage": "",
"file": "shared/features/powerpack/custom-caching",
"itemList": [],
"isExternal": false,
"path": "/features/powerpack/custom-caching",
"tags": ["custom-caching"]
},
"/features/ci-features": { "/features/ci-features": {
"id": "ci-features", "id": "ci-features",
"name": "CI Features", "name": "CI Features",
@ -1476,6 +1599,17 @@
"mediaImage": "", "mediaImage": "",
"file": "", "file": "",
"itemList": [ "itemList": [
{
"id": "activate-powerpack",
"name": "Activate Powerpack",
"description": "",
"mediaImage": "",
"file": "shared/recipes/installation/activate-powerpack",
"itemList": [],
"isExternal": false,
"path": "/recipes/installation/activate-powerpack",
"tags": ["installation"]
},
{ {
"id": "install-non-javascript", "id": "install-non-javascript",
"name": "Install Nx in a Non-Javascript Repo", "name": "Install Nx in a Non-Javascript Repo",
@ -2864,6 +2998,17 @@
"mediaImage": "", "mediaImage": "",
"file": "", "file": "",
"itemList": [ "itemList": [
{
"id": "activate-powerpack",
"name": "Activate Powerpack",
"description": "",
"mediaImage": "",
"file": "shared/recipes/installation/activate-powerpack",
"itemList": [],
"isExternal": false,
"path": "/recipes/installation/activate-powerpack",
"tags": ["installation"]
},
{ {
"id": "install-non-javascript", "id": "install-non-javascript",
"name": "Install Nx in a Non-Javascript Repo", "name": "Install Nx in a Non-Javascript Repo",
@ -2891,6 +3036,17 @@
"path": "/recipes/installation", "path": "/recipes/installation",
"tags": [] "tags": []
}, },
"/recipes/installation/activate-powerpack": {
"id": "activate-powerpack",
"name": "Activate Powerpack",
"description": "",
"mediaImage": "",
"file": "shared/recipes/installation/activate-powerpack",
"itemList": [],
"isExternal": false,
"path": "/recipes/installation/activate-powerpack",
"tags": ["installation"]
},
"/recipes/installation/install-non-javascript": { "/recipes/installation/install-non-javascript": {
"id": "install-non-javascript", "id": "install-non-javascript",
"name": "Install Nx in a Non-Javascript Repo", "name": "Install Nx in a Non-Javascript Repo",
@ -6521,6 +6677,17 @@
"path": "/deprecated/workspace-generators", "path": "/deprecated/workspace-generators",
"tags": [] "tags": []
}, },
{
"id": "custom-task-runners",
"name": "Custom Task Runners",
"description": "",
"mediaImage": "",
"file": "shared/deprecated/custom-task-runners",
"itemList": [],
"isExternal": false,
"path": "/deprecated/custom-task-runners",
"tags": []
},
{ {
"id": "workspace-executors", "id": "workspace-executors",
"name": "Workspace Executors", "name": "Workspace Executors",
@ -6658,6 +6825,17 @@
"path": "/deprecated/workspace-generators", "path": "/deprecated/workspace-generators",
"tags": [] "tags": []
}, },
"/deprecated/custom-task-runners": {
"id": "custom-task-runners",
"name": "Custom Task Runners",
"description": "",
"mediaImage": "",
"file": "shared/deprecated/custom-task-runners",
"itemList": [],
"isExternal": false,
"path": "/deprecated/custom-task-runners",
"tags": []
},
"/deprecated/workspace-executors": { "/deprecated/workspace-executors": {
"id": "workspace-executors", "id": "workspace-executors",
"name": "Workspace Executors", "name": "Workspace Executors",

View File

@ -575,6 +575,33 @@
"path": "/nx-api/nx/documents/release" "path": "/nx-api/nx/documents/release"
} }
], ],
"conformance": [
{
"description": "Conformance",
"file": "shared/features/powerpack/conformance",
"id": "conformance",
"name": "Run Language-Agnostic Conformance Rules",
"path": "/features/powerpack/conformance"
}
],
"owners": [
{
"description": "Owners",
"file": "shared/features/powerpack/owners",
"id": "owners",
"name": "Define Code Ownership at the Project Level",
"path": "/features/powerpack/owners"
}
],
"custom-caching": [
{
"description": "Custom Caching",
"file": "shared/features/powerpack/custom-caching",
"id": "custom-caching",
"name": "Self-Host the Remote Cache",
"path": "/features/powerpack/custom-caching"
}
],
"intro": [ "intro": [
{ {
"description": "", "description": "",
@ -821,6 +848,13 @@
} }
], ],
"installation": [ "installation": [
{
"description": "",
"file": "shared/recipes/installation/activate-powerpack",
"id": "activate-powerpack",
"name": "Activate Powerpack",
"path": "/recipes/installation/activate-powerpack"
},
{ {
"description": "", "description": "",
"file": "shared/recipes/installation/install-non-javascript", "file": "shared/recipes/installation/install-non-javascript",

View File

@ -131,6 +131,34 @@
"tags": ["nx-release"], "tags": ["nx-release"],
"file": "shared/features/manage-releases" "file": "shared/features/manage-releases"
}, },
{
"name": "Powerpack Features",
"id": "powerpack",
"description": "Features of Nx that are available with a powerpack license.",
"itemList": [
{
"name": "Run Language-Agnostic Conformance Rules",
"description": "Conformance",
"id": "conformance",
"tags": ["conformance"],
"file": "shared/features/powerpack/conformance"
},
{
"name": "Define Code Ownership at the Project Level",
"description": "Owners",
"id": "owners",
"tags": ["owners"],
"file": "shared/features/powerpack/owners"
},
{
"name": "Self-Host the Remote Cache",
"description": "Custom Caching",
"id": "custom-caching",
"tags": ["custom-caching"],
"file": "shared/features/powerpack/custom-caching"
}
]
},
{ {
"name": "CI Features", "name": "CI Features",
"id": "ci-features", "id": "ci-features",
@ -354,6 +382,12 @@
"id": "installation", "id": "installation",
"description": "Installing Nx", "description": "Installing Nx",
"itemList": [ "itemList": [
{
"name": "Activate Powerpack",
"id": "activate-powerpack",
"tags": ["installation"],
"file": "shared/recipes/installation/activate-powerpack"
},
{ {
"name": "Install Nx in a Non-Javascript Repo", "name": "Install Nx in a Non-Javascript Repo",
"id": "install-non-javascript", "id": "install-non-javascript",
@ -1364,6 +1398,11 @@
"id": "workspace-generators", "id": "workspace-generators",
"file": "shared/deprecated/workspace-generators" "file": "shared/deprecated/workspace-generators"
}, },
{
"name": "Custom Task Runners",
"id": "custom-task-runners",
"file": "shared/deprecated/custom-task-runners"
},
{ {
"name": "Workspace Executors", "name": "Workspace Executors",
"id": "workspace-executors", "id": "workspace-executors",
@ -2558,6 +2597,58 @@
} }
] ]
}, },
{
"name": "powerpack-owners",
"id": "powerpack-owners",
"description": "powerpack-owners package.",
"itemList": [
{
"name": "Overview",
"id": "overview",
"path": "/nx-api/powerpack-owners",
"file": "shared/packages/powerpack-owners/powerpack-owners-plugin"
}
]
},
{
"name": "powerpack-conformance",
"id": "powerpack-conformance",
"description": "powerpack-conformance package.",
"itemList": [
{
"name": "Overview",
"id": "overview",
"path": "/nx-api/powerpack-conformance",
"file": "shared/packages/powerpack-conformance/powerpack-conformance-plugin"
}
]
},
{
"name": "powerpack-s3-cache",
"id": "powerpack-s3-cache",
"description": "powerpack-s3-cache package.",
"itemList": [
{
"name": "Overview",
"id": "overview",
"path": "/nx-api/powerpack-s3-cache",
"file": "shared/packages/powerpack-s3-cache/powerpack-s3-cache-plugin"
}
]
},
{
"name": "powerpack-shared-fs-cache",
"id": "powerpack-shared-fs-cache",
"description": "powerpack-shared-fs-cache package.",
"itemList": [
{
"name": "Overview",
"id": "overview",
"path": "/nx-api/powerpack-shared-fs-cache",
"file": "shared/packages/powerpack-shared-fs-cache/powerpack-shared-fs-cache-plugin"
}
]
},
{ {
"name": "gradle", "name": "gradle",
"id": "gradle", "id": "gradle",

View File

@ -46,7 +46,7 @@ In order to guarantee that cache poisoning will never affect your end users, [sk
### Do Not Manually Share Your Local Cache ### Do Not Manually Share Your Local Cache
Nx implicitly trusts the local cache which is stored by default in the `.nx/cache` folder. You can change the location of that folder in the `nx.json` file, so it could be tempting to place it on a network drive and easily share your cache with everyone on the company network. However, by doing this you've voided the guarantee of immutability from your cache. If someone has direct access to the cached files, they could directly poison the cache. Nx will automatically detect if a cache entry has been created in your local cache using a different machine and warn you with an [Unknown Local Cache Error](/troubleshooting/unknown-local-cache). Instead, use Nx Cloud [remote caching](/ci/features/remote-cache). Nx implicitly trusts the local cache which is stored by default in the `.nx/cache` folder. You can change the location of that folder in the `nx.json` file, so it could be tempting to place it on a network drive and easily share your cache with everyone on the company network. However, by doing this you've voided the guarantee of immutability from your cache. If someone has direct access to the cached files, they could directly poison the cache. Nx will automatically detect if a cache entry has been created in your local cache using a different machine and warn you with an [Unknown Local Cache Error](/troubleshooting/unknown-local-cache). Instead, use Nx Cloud [remote caching](/ci/features/remote-cache). If you want share your local cache anyway, you can [activate Nx Powerpack](/recipes/installation/activate-powerpack) and use the [`@nx/powerpack-shared-fs-cache`](/nx-api/powerpack-shared-fs-cache) plugin.
### Configure End to End Encryption ### Configure End to End Encryption

View File

@ -0,0 +1,12 @@
# tasksRunnerOptions
As of Nx 20, the `tasksRunnerOptions` property in `nx.json` is deprecated. This property was used to register custom task runners. `tasksRunnerOptions` and custom task runners will cease to function in Nx 21. In Nx 20, the local cache metadata and project graph are stored in a database, rather than using the file system. (Cache artifacts are still stored on the file system.) This has two benefits:
1. Cache reads and writes are faster.
2. The local cache is more secure since other processes with access to the file system can no longer read or modify the cache.
For most organizations, this feature is a net positive. If you are currently using a custom task runner, you are most likely using it to define your own custom [remote cache](/ci/features/remote-cache) storage location. You have several options moving forward:
1. Use [Nx Cloud](/nx-cloud) for your remote cache
2. Use an [Nx Powerpack]() plugin to store your remote cache on an [AWS S3 bucket](/nx-api/powerpack-s3-cache) or a [network drive](/nx-api/powerpack-shared-fs-cache)
3. Use the deprecated custom task runner feature until Nx 21

View File

@ -0,0 +1,78 @@
# Run Language-Agnostic Conformance Rules
The [`@nx/powerpack-conformance`](/nx-api/powerpack-conformance) plugin allows [Nx Powerpack]() users to write and apply rules for your entire workspace that help with **consistency**, **maintainability**, **reliability** and **security**.
The conformance plugin allows you to **encode your own organization's standards** so that they can be enforced automatically. Conformance rules can also **complement linting tools** by enforcing that those tools are configured in the recommended way. The rules are written in TypeScript but can be **applied to any language in the codebase** or focus entirely on configuration files.
The plugin also provides the following pre-written rules:
- **Enforce Module Boundaries**: Similar to the Nx [ESLint Enforce Module Boundaries rule](/features/enforce-module-boundaries), but enforces the boundaries on every project dependency, not just those created from TypeScript imports or `package.json` dependencies.
- **Ensure Owners**: Require every project to have an owner defined for the [`@nx/powerpack-owners` plugin](/nx-api/powerpack-owners)
## Setup
The `@nx/powerpack-conformance` plugin requires an Nx Powerpack license to function. [Activating Powerpack](/recipes/installation/activate-powerpack) is a simple process.
{% call-to-action title="Buy a Powerpack License" icon="nx" description="Unlock all the features of Nx" url="https://nx.app/powerpack/purchase" /%}
Then, add the Conformance plugin to your workspace.
{% link-card title="Conformance" type="Nx Plugin" url="/nx-api/powerpack-conformance" icon="CheckBadgeIcon" /%}
## Configure Conformance Rules
Conformance rules are configured in the `conformance` property of the `nx.json` file. You can use the pre-defined rules or reference [your own custom rule](/nx-api/powerpack-conformance#custom-conformance-rules). See the [plugin documentation](/nx-api/powerpack-conformance) for more details.
```jsonc {% fileName="nx.json" %}
{
"conformance": {
"rules": [
{
"rule": "@nx/powerpack-conformance/enforce-module-boundaries",
"options": {
"depConstraints": [
{
"sourceTag": "scope:shared",
"onlyDependOnLibsWithTags": ["scope:shared"]
}
]
}
},
{
"rule": "@nx/powerpack-conformance/ensure-owners",
"projects": ["!experimental-app"]
},
{
"rule": "./tools/local-conformance-rule.ts"
}
]
}
}
```
## Enforce Rules with the `nx conformance` Command
The `@nx/powerpack-conformance` plugin enables the `nx conformance` command which checks all the configured rules. This command should be added to the beginning of your CI process so that the conformance rules are enforced for every PR.
{% tabs %}
{% tab label="Without Nx Cloud" %}
```yaml
- name: Enforce all conformance rules
run: npx nx conformance
```
{% /tab %}
{% tab label="Using Nx Cloud" %}
```yaml
- name: Enforce all conformance rules
run: npx nx-cloud record -- npx nx conformance
```
Use `npx nx-cloud record --` to capture the logs for `nx conformance` in the Nx Cloud dashboard.
{% /tab %}
{% /tabs %}
If there is not a valid Powerpack license in the workspace, the `nx conformance` command will fail without checking any rules.

View File

@ -0,0 +1,31 @@
# Self-Host the Remote Cache
The recommended way to enable the [remote cache](/ci/features/remote-cache) is to use Nx Replay and have Nx Cloud share the task cache across your organization. For those organizations that are unable to use Nx Cloud, Nx offers official plugins that are enabled by [Nx Powerpack]() to self-host the remote cache in a fast and secure manner. The recommended ways to host the remote cache are, in order of preference:
1. [Nx Replay](/ci/features/remote-cache): Cache is hosted on Nx Cloud servers or on-premise with an [Nx Enterprise](/enterprise) contract
2. [@nx/powerpack-s3-cache](/nx-api/powerpack-s3-cache): Cache is on a self-hosted, fully secure AWS S3 bucket
3. [@nx/powerpack-shared-fs-cache](/nx-api/powerpack-s3-cache): Cache is self-hosted and self-secured on a shared file system location
The options range from fully opting in to Nx's management of the remote cache to fully managing the configuration and security of your own remote cache.
## Setup
The `@nx/powerpack-s3-cache` and `@nx/powerpack-shared-fs-cache` plugins require an Nx Powerpack license to function. [Activating Powerpack](/recipes/installation/activate-powerpack) is a simple process.
{% call-to-action title="Buy a Powerpack License" icon="nx" description="Unlock all the features of the Nx CLI" url="https://nx.app/powerpack/purchase" /%}
Then, choose the appropriate cache plugin for your situation.
{% cards cols="2" lgCols="2" mdCols="2" smCols="2" %}
{% link-card title="AWS S3 Bucket Remote Cache" type="Nx Plugin" url="/nx-api/powerpack-s3-cache" icon="AwsIcon" /%}
{% link-card title="Shared Network Drive Remote Cache" type="Nx Plugin" url="/nx-api/powerpack-shared-fs-cache" icon="ServerIcon" /%}
{% /cards %}
## Switch to Nx Cloud
These custom remote cache storage solutions only provide the remote cache functionality of Nx Cloud. If you want to leverage [distributed task execution](/ci/features/distribute-task-execution), [re-running flaky tasks](/ci/features/flaky-tasks) or [automatically splitting tasks](/ci/features/split-e2e-tasks), you'll need to [connect to Nx Cloud](/ci/intro/connect-to-nx-cloud) and use Nx Cloud's remote cache solution instead.
{% call-to-action title="Connect to Nx Cloud" icon="nxcloud" description="Enable task distribution and Atomizer" url="/ci/intro/connect-to-nx-cloud" /%}

View File

@ -0,0 +1,87 @@
# Define Code Ownership at the Project Level
This plugin provides the ability to configure and maintain code owners for projects in an Nx workspace.
The atomic unit of code in an Nx workspace is a project. Tasks, module boundaries and the Nx graph all train us to conceptualize the workspace as a collection of projects. The CODEOWNERS file, however, requires you to switch from a project mental model to a more low-level definition based on the folder structure of your workspace. The `@nx/powerpack-owners` plugin enables you to stay in the mental model that your workspace is a collection of projects as you define the ownership rules for your workspace. Nx will take care of compiling the project ownership rules into file-based ownership rules that [GitHub](https://docs.github.com/en/repositories/managing-your-repositorys-settings-and-features/customizing-your-repository/about-code-owners), [Bitbucket](https://support.atlassian.com/bitbucket-cloud/docs/set-up-and-use-code-owners/) or [GitLab](https://docs.gitlab.com/ee/user/project/codeowners/) can understand in the CODEOWNERS file.
## Setup
The `@nx/powerpack-owners` plugin requires an Nx Powerpack license to function. [Activating Powerpack](/recipes/installation/activate-powerpack) is a simple process.
{% call-to-action title="Buy a Powerpack License" icon="nx" description="Unlock all the features of Nx" url="https://nx.app/powerpack/purchase" /%}
Then, add the Owners plugin to your workspace.
{% link-card title="Owners" type="Nx Plugin" url="/nx-api/powerpack-owners" icon="UserGroupIcon" /%}
## Project or File-based Configuration
The ownership configuration is defined in the `nx.json` file or in individual project configuration files. Nx then uses a [sync generator](/concepts/sync-generators) to automatically compile those settings into a valid CODEOWNERS file for GitHub, Bitbucket or GitLab. See the [plugin documentation](/nx-api/powerpack-owners) for more details.
{% cards smCols="2" mdCols="2" lgCols="2" %}
**Define Project Owners**
**Nx Generates the CODEOWNERS file**
```json {% fileName="nx.json" %}
{
"owners": {
"format": "github",
"patterns": [
{
"description": "Joe's Rust projects",
"projects": ["tag:rust"],
"owners": ["@joelovesrust"]
},
{
"description": "Finance projects",
"projects": ["finance-*"],
"owners": ["@finance-team"]
},
{
"description": "Alphabet soup",
"projects": ["admin", "books", "cart"],
"owners": ["@alice", "@bob", "@cecil"]
},
{
"description": "CI Workflows",
"files": [".github/workflows/**/*"],
"owners": ["@devops"]
}
]
}
}
```
```yaml {% fileName=".github/CODEOWNERS" %}
# Joe's Rust projects
/packages/rust-api @joelovesrust
/packages/experimental-rust @joelovesrust
# Finance projects
/packages/finance-ui @finance-team
/packages/finance-data @finance-team
# Alphabet soup
/packages/admin @alice @bob @cecil
/packages/books @alice @bob @cecil
/packages/cart @alice @bob @cecil
# CI Workflows
.github/workflows/**/* @devops
/packages/my-project/ @ahmed @petra
/packages/my-project/package.json @ahmed
```
```json {% fileName="packages/my-project/project.json" %}
{
"owners": {
"**/*": ["@ahmed", "@petra"],
"package.json": ["@ahmed"]
},
};
```
{% /cards %}

View File

@ -46,25 +46,9 @@ access to all the previously created Nx cache artifacts. Hence, it is plausible
single task hash - to be accessed without leaving any trace. This is feasible due to the network drive's capability to single task hash - to be accessed without leaving any trace. This is feasible due to the network drive's capability to
allow overwrites. allow overwrites.
Instead of sharing the network drive, we highly recommend you to implement the `RemoteCache` interface. ## How Nx Replay Makes Sure Sharing Cache is Safe
## Implementing Remote Cache Interface [Nx Replay](/ci/features/remote-cache), the Nx Cloud hosted remote cache, does the following things to make sharing the cache safe:
This is the interface:
```typescript
interface RemoteCache {
retrieve(hash: string, cachePath: string);
store(hash: string, cachePath: string);
}
```
> You will need to wrap the default tasks runner to provide the remote cache implementation.
## How Nx Cloud Makes Sure Sharing Cache is Safe
The Nx Cloud runner provides an implementation of `RemoteCache` which does the following things making sharing the cache safe:
1. **Immutable Artifacts:** Nx Cloud allows you to create and store new artifacts without the ability to override the 1. **Immutable Artifacts:** Nx Cloud allows you to create and store new artifacts without the ability to override the
existing ones. This prevents any possibility of poisoning an existing artifact. This is achieved by managing the existing ones. This prevents any possibility of poisoning an existing artifact. This is achieved by managing the
@ -81,6 +65,15 @@ The Nx Cloud runner provides an implementation of `RemoteCache` which does the f
an access token gets compromised it can be easily removed, in turn deleting all the cache artifacts that were created an access token gets compromised it can be easily removed, in turn deleting all the cache artifacts that were created
using it. using it.
Nx Cloud is not the only remote cache you can use. If you are using a different remote cache or using your Nx Replay is not the only remote cache you can use. If you are using a different remote cache or using your
own implementation, we would highly recommend ensuring that the same safety mechanisms as Nx Cloud have been put in own implementation, we would highly recommend ensuring that the same safety mechanisms as Nx Cloud have been put in
place. place.
## Self-Hosted Remote Cache
If you can't use Nx Replay, Nx provides plugins that enable you to [self-host the remote cache](/features/powerpack/custom-caching). These plugins are available as part of the [Nx Powerpack](), which you can unlock by [activating your license](/recipes/installation/activate-powerpack). There are plugins to self-host your remote cache in the following locations:
- [AWS S3 Bucket](/nx-api/powerpack-s3-cache)
- [Shared File System](/nx-api/powerpack-shared-fs-cache)
These plugins will ensure that the task metadata and project graph information are correctly associated with the file artifacts in your cache.

View File

@ -0,0 +1,217 @@
---
title: Overview of the Nx powerpack-conformance Plugin
description: The Nx Powerpack Conformance plugin provides the ability to write and apply rules for your workspace
---
The `@nx/powerpack-conformance` plugin allows [Nx Powerpack]() users to write and apply rules for your entire workspace that help with **consistency**, **maintainability**, **reliability** and **security**.
The conformance plugin allows you to encode your own organization's standards so that they can be enforced automatically. Conformance rules can also complement linting tools by enforcing that those tools are configured in the recommended way. The rules are written in TypeScript but can be applied to any language in the codebase or focus entirely on configuration files.
The plugin also provides the following pre-written rules:
- [**Enforce Module Boundaries**](#enforce-module-boundaries): Similar to the Nx [ESLint Enforce Module Boundaries rule](/features/enforce-module-boundaries), but enforces the boundaries on every project dependency, not just those created from TypeScript imports or `package.json` dependencies.
- [**Ensure Owners**](#ensure-owners): Require every project to have an owner defined for the [`@nx/powerpack-owners` plugin](/nx-api/powerpack-owners)
{% callout title="This plugin requires an active Nx Powerpack license" %}
In order to use `@nx/powerpack-conformance`, you need to have an active Powerpack license. If you don't have a license or it has expired, the `nx conformance` command will fail.
{% /callout %}
## Setup
1. [Activate Powerpack](/recipes/installation/activate-powerpack) if you haven't already
2. Install the package
```shell
nx add @nx/powerpack-conformance
```
3. Configure Conformance Rules
Configure the `@nx/powerpack-conformance` plugin in the `nx.json` file or in individual project configuration files. Consult the [Conformance Configuration Reference](#conformance-configuration-reference) section for more details.
4. Run the `nx conformance` command in CI
Add `nx conformance` to the beginning of the CI process.
{% tabs %}
{% tab label="Without Nx Cloud" %}
```yaml
- name: Enforce all conformance rules
run: npx nx conformance
```
{% /tab %}
{% tab label="Using Nx Cloud" %}
```yaml
- name: Enforce all conformance rules
run: npx nx-cloud record -- npx nx conformance
```
Use `npx nx-cloud record --` to capture the logs for `nx conformance` in the Nx Cloud dashboard.
{% /tab %}
{% /tabs %}
## Conformance Configuration Reference
```jsonc {% fileName="nx.json" %}
{
"conformance": {
"rules": [{
/**
* Relative path to a local rule implementation or node_module path.
*/
"rule": "@nx/powerpack-conformance/enforce-module-boundaries";
/**
* Rule specific configuration options. (Optional)
*/
"options": {}
/**
* The projects array allows users to opt in or out of violations for specific projects being reported by the current rule.
* The array can contain any valid matchers for findMatchingProjects(), by default the implied value is ["*"]. (Optional)
*/
"projects": ["*"];
}]
}
}
```
## Provided Conformance Rules
The following rules are provided by Nx along with the `@nx/powerpack-conformance` plugin.
### Enforce Module Boundaries
This rule is similar to the Nx [ESLint Enforce Module Boundaries rule](/features/enforce-module-boundaries), but enforces the boundaries on every project dependency, not just those created from TypeScript imports or `package.json` dependencies.
Set the `rule` property to: `@nx/powerpack-conformance/enforce-module-boundaries`
```json {% fileName="nx.json" %}
{
"conformance": {
"rules": [
{
"rule": "@nx/powerpack-conformance/enforce-module-boundaries",
"options": {
// Optional
// Can be a boolean or an object with an array of buildTargetNames
"requireBuildableDependenciesForBuildableProjects": {
// Defaults to ["build"]
"buildTargetNames": ["build", "compile"]
},
// Optional
"ignoredCircularDependencies": [["projectA", "projectB"]],
// Optional
"depConstraints": [
{
// Must define either `sourceTag` or `allSourceTags`
"sourceTag": "string",
"allSourceTags": ["string"],
// Optional
"onlyDependOnLibsWithTags": [],
// Optional
"notDependOnLibsWithTags": []
}
],
// Optional
"checkDynamicDependenciesExceptions": []
}
}
]
}
}
```
#### Options
| Property | Type | Default | Description |
| ------------------------------------------------ | ------------------------- | ------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| ignoredCircularDependencies | _Array<[string, string]>_ | _[]_ | List of project pairs that should be skipped from `Circular dependencies` checks, including the self-circular dependency check. E.g. `['feature-project-a', 'myapp']`. Project name can be replaced by catch all `*` for more generic matches. |
| checkDynamicDependenciesExceptions | _Array<string>_ | _[]_ | List of imports that should be skipped for `Imports of lazy-loaded libraries forbidden` checks. E.g. `['@myorg/lazy-project/component/*', '@myorg/other-project']` |
| requireBuildableDependenciesForBuildableProjects | _boolean_ | _false_ | Enable to restrict the buildable libs from importing non-buildable libraries |
| depConstraints | _Array<object>_ | _[]_ | List of dependency constraints between projects |
#### Dependency constraints
The `depConstraints` is an array of objects representing the constraints defined between source and target projects. A
constraint must include `sourceTag` or `allSourceTags`. The constraints are applied with **AND** logical operation - for
a given `source` project the resulting constraints would be **all** that match its tags.
| Property | Type | Description |
| ------------------------ | --------------- | ---------------------------------------------------------------------------------- |
| sourceTag | _string_ | Tag that source project must contain to match the constraint |
| allSourceTags | _Array<string>_ | List of tags the source project must contain to match the constraint |
| onlyDependOnLibsWithTags | _Array<string>_ | The source **can depend only** on projects that contain at least one of these tags |
| notDependOnLibsWithTags | _Array<string>_ | The source **can not depend** on projects that contain at least one of these tags |
### Ensure Owners
This rule requires every project to have an owner defined for the [`@nx/powerpack-owners` plugin](/nx-api/powerpack-owners)
Set the `rule` property to: `@nx/powerpack-conformance/ensure-owners`
```json {% fileName="nx.json" %}
{
"conformance": {
"rules": [
{
"rule": "@nx/powerpack-conformance/ensure-owners"
}
]
}
}
```
## Custom Conformance Rules
To write your own conformance rule, specify a relative path to a TypeScript or JavaScript file as the rule name:
```json {% fileName="nx.json" %}
{
"conformance": {
"rules": [
{
"rule": "./tools/local-conformance-rule.ts"
}
]
}
}
```
The rule definition file should look like this:
```ts {% fileName="tools/local-conformance-rule.ts" %}
import type {
ConformanceRule,
ConformanceRuleResult,
createConformanceRule,
} from '@nx/powerpack-conformance';
const rule = createConformanceRule({
name: 'local-conformance-rule-example',
category: 'security', // `consistency`, `maintainability`, `reliability` or `security`
reporter: 'project-reporter', // `project-reporter` or `project-files-reporter`
implementation: async (context): Promise<ConformanceRuleResult> => {
const { projectGraph, ruleOptions } = context;
// Your rule logic goes here
return {
severity: 'low', // 'high', 'medium' or 'low'
details: {
violations: [
// Return an empty array if the rule passes
{
sourceProject: 'my-project',
message: 'This is an informative error message.',
},
],
},
};
},
});
export default rule;
```
Note that the severity of the error is defined by the rule author and can be adjusted based on the specific violations that are found.

View File

@ -0,0 +1,326 @@
---
title: Overview of the Nx powerpack-owners Plugin
description: The Nx Powerpack Owners plugin provides the ability to define code ownership based on projects in addition to files
---
The `@nx/powerpack-owners` plugin extends the CODEOWNERS functionality to allow you to define code ownership based on projects in addition to the standard file-based definitions. It leverages the [`nx sync`](/concepts/sync-generators) command to compile `owners` configuration settings from `nx.json` and project configuration files into valid CODEOWNERS files for [GitHub](https://docs.github.com/en/repositories/managing-your-repositorys-settings-and-features/customizing-your-repository/about-code-owners), [Bitbucket](https://support.atlassian.com/bitbucket-cloud/docs/set-up-and-use-code-owners/) or [GitLab](https://docs.gitlab.com/ee/user/project/codeowners/).
With this plugin, you can specify code ownership using the same project matcher syntax as [`nx run-many`](/nx-api/nx/documents/run-many#examples). This allows you to easily define rules for multiple projects that may not be located in the same directory. Also, the CODEOWNERS rules will not need to be revisited if a project location is changed or a new project is added.
{% callout title="This plugin requires an active Nx Powerpack license" %}
In order to use `@nx/powerpack-owners`, you need to have an active Powerpack license. If you don't have a license or it has expired, the syncing process will stop working and you'll need to manually maintain your CODEOWNERS file.
{% /callout %}
## Setup
1. [Activate Powerpack](/recipes/installation/activate-powerpack) if you haven't already
2. Install the package
```shell
nx add @nx/powerpack-owners
```
3. Configure Ownership
Configure the `@nx/powerpack-owners` plugin in the `nx.json` file or in individual project configuration files. Consult the [Owners Configuration Reference](#owners-configuration-reference) section for more details.
4. Configure the [Sync Generator](/concepts/sync-generators) and CI
The `nx add @nx/powerpack-owners` command should have registered the `@nx/powerpack-owners:sync-codeowners-file` generator as a `globalGenerator` in `nx.json`. You can double check to make sure:
```jsonc {% fileName="nx.json" %}
{
"sync": {
"globalGenerators": ["@nx/powerpack-owners:sync-codeowners-file"]
}
}
```
Add `nx sync:check` to the beginning of the CI process.
```yaml
- name: Ensure the workspace configuration is in sync
run: npx nx sync:check
```
It is also often helpful to add `nx sync` as a git push hook or git commit hook.
## Owners Configuration Reference
{% tabs %}
{% tab label="GitHub" %}
```jsonc {% fileName="nx.json" %}
{
// Can be set to true instead of an object to accept all defaults
"owners": {
// Options are `github`, `bitbucket` or `gitlab`. (Optional) Defaults to `github`
"format": "github",
// (Optional) Default changes based on format: `.github/CODEOWNERS`, `.bitbucket/CODEOWNERS`, `.gitlab/CODEOWNERS`
"outputPath": "CODEOWNERS",
// (Optional)
"patterns": [
{
"description": "A description of the rule",
"owners": ["@joelovesrust"],
// specify either projects or files, not both
// Can be any project specifier that could be used in `nx run-many`
// See https://nx.dev/nx-api/nx/documents/run-many
"projects": ["my-rust-app", "rust-*", "tag:rust"],
// File globs
"files": [".github/workflows/**/*"]
}
]
}
}
```
{% /tab %}
{% tab label="Bitbucket" %}
```jsonc {% fileName="nx.json" %}
{
// Can be set to true instead of an object to accept all defaults
"owners": {
// Options are `github`, `bitbucket` or `gitlab`. (Optional) Defaults to `github`
"format": "bitbucket",
// (Optional) Default changes based on format: `.github/CODEOWNERS`, `.bitbucket/CODEOWNERS`, `.gitlab/CODEOWNERS`
"outputPath": "CODEOWNERS",
// (Optional)
"patterns": [
{
"description": "A description of the rule",
"owners": ["@joelovesrust"],
// specify either projects or files, not both
// Can be any project specifier that could be used in `nx run-many`
// See https://nx.dev/nx-api/nx/documents/run-many
"projects": ["my-rust-app", "rust-*", "tag:rust"],
// File globs
"files": [".github/workflows/**/*"]
}
]
}
}
```
{% /tab %}
{% tab label="GitLab" %}
If you are using GitLab, you can specify CODEOWNERS [sections](https://docs.gitlab.com/ee/user/project/codeowners/#organize-code-owners-by-putting-them-into-sections) which give you a little more control over the PR process.
```jsonc {% fileName="nx.json" %}
{
// Can be set to true instead of an object to accept all defaults
"owners": {
// Options are `github`, `bitbucket` or `gitlab`. (Optional) Defaults to `github`
"format": "gitlab",
// (Optional) Default changes based on format: `.github/CODEOWNERS`, `.bitbucket/CODEOWNERS`, `.gitlab/CODEOWNERS`
"outputPath": "CODEOWNERS",
// (Optional)
"patterns": [
{
"description": "A description of the rule",
"owners": ["@joelovesrust"],
// Specify either `projects` or `files`, not both
// Can be any project specifier that could be used in `nx run-many`
// See https://nx.dev/nx-api/nx/documents/run-many
"projects": ["my-rust-app", "rust-*", "tag:rust"],
// File globs
"files": [".github/workflows/**/*"]
}
],
// (Optional)
"sections": [
{
// Labels the section
"name": "My section",
// (Optional) The owners to use if a pattern does not specify a set of owners
"defaultOwners": ["@cheddar"],
// Specify either `numberOfRequiredApprovals` or `optional`, not both
// (Optional) Require more than one person to approve the PR
"numberOfRequiredApprovals": 2,
// (Optional) Do not require any approvals, just notify the owners
"optional": true,
// Same format as the root patterns
"patterns": []
}
]
}
}
```
```jsonc {% fileName="path/to/project/project.json" %}
{
"owners": {
// Keys are file globs relative to the root of the project
// Owners can be listed as a string array
"**/*": ["@ahmed", "@petra"],
// Owners can be listed as an object with a description
"README.md": {
"description": "Jared is very particular about the README file",
"owners": ["@jared"]
}
}
};
```
{% /tab %}
{% /tabs %}
**Examples:**
{% tabs %}
{% tab label="GitHub" %}
```jsonc {% fileName="nx.json" %}
{
"owners": {
// defaults to "github"
"format": "github",
// defaults to ".github/CODEOWNERS"
"outputPath": "CODEOWNERS",
"patterns": [
{
"description": "Joe should double check all changes to rust code",
"projects": ["tag:rust"],
"owners": ["@joelovesrust"]
},
{
"description": "The Finance team owns these projects",
"projects": ["finance-*"],
"owners": ["@finance-team"]
},
{
"description": "Alice, Bob and Cecil work together on these projects",
"projects": ["admin", "booking", "cart"],
"owners": ["@alice", "@bob", "@cecil"]
},
{
"description": "CI Workflows",
"files": [".github/workflows/**/*"],
"owners": ["@devops"]
}
]
}
}
```
```jsonc {% fileName="packages/my-project/project.json" %}
{
"owners": {
"**/*": ["@ahmed", "@petra"],
"package.json": ["@ahmed"],
"README.md": {
"owners": ["@jared"],
"description": "Jared is very particular about the README file"
}
},
};
```
{% /tab %}
{% tab label="Bitbucket" %}
```jsonc {% fileName="nx.json" %}
{
"owners": {
"format": "bitbucket",
// defaults to ".bitbucket/CODEOWNERS"
"outputPath": "CODEOWNERS",
"patterns": [
{
"description": "Joe should double check all changes to rust code",
"projects": ["tag:rust"],
"owners": ["@joelovesrust"]
},
{
"description": "The Finance team owns these projects",
"projects": ["finance-*"],
"owners": ["@finance-team"]
},
{
"description": "Alice, Bob and Cecil work together on these projects",
"projects": ["admin", "booking", "cart"],
"owners": ["@alice", "@bob", "@cecil"]
},
{
"description": "CI Workflows",
"files": [".github/workflows/**/*"],
"owners": ["@devops"]
}
]
}
}
```
```jsonc {% fileName="packages/my-project/project.json" %}
{
"owners": {
"**/*": ["@ahmed", "@petra"],
"package.json": ["@ahmed"],
"README.md": {
"owners": ["@jared"],
"description": "Jared is very particular about the README file"
}
},
};
```
{% /tab %}
{% tab label="GitLab" %}
```jsonc {% fileName="nx.json" %}
{
"owners": {
"format": "gitlab",
// defaults to ".gitlab/CODEOWNERS"
"outputPath": "CODEOWNERS",
"patterns": [
{
"description": "Joe should double check all changes to rust code",
"projects": ["tag:rust"],
"owners": ["@joelovesrust"]
},
{
"description": "CI Workflows",
"files": [".github/workflows/**/*"],
"owners": ["@devops"]
}
],
"sections": [
{
"name": "Finance",
"defaultOwners": ["@finance-team"],
"numberOfRequiredApprovals": 2,
"patterns": [
{
"description": "The Finance team owns these projects",
"projects": ["finance-*"]
},
{
"description": "Alice, Bob and Cecil work together on these projects",
"projects": ["admin", "booking", "cart"],
"owners": ["@alice", "@bob", "@cecil"]
}
]
}
]
}
}
```
```jsonc {% fileName="packages/my-project/project.json" %}
{
"owners": {
"**/*": ["@ahmed", "@petra"],
"package.json": ["@ahmed"],
"README.md": {
"owners": ["@jared"],
"description": "Jared is very particular about the README file"
}
},
};
```
{% /tab %}
{% /tabs %}

View File

@ -0,0 +1,94 @@
---
title: Overview of the Nx powerpack-s3-cache Plugin
description: The powerpack-s3-cache Nx plugin enables you to use an Amazon S3 bucket to host your remote cache instead of Nx Cloud
---
The `@nx/powerpack-s3-cache` plugin enables you to use an [Amazon S3](https://aws.amazon.com/s3) bucket instead of Nx Cloud to host your remote cache.
This plugin will enable the remote cache for your Nx workspace, but does not provide any of the other features of Nx Cloud. If you want to leverage [distributed task execution](/ci/features/distribute-task-execution), [re-running flaky tasks](/ci/features/flaky-tasks) or [automatically splitting tasks](/ci/features/split-e2e-tasks), you'll need to [connect to Nx Cloud](/ci/intro/connect-to-nx-cloud) and use [Nx Replay](/ci/features/remote-cache) instead.
{% callout title="This plugin requires an active Nx Powerpack license" %}
In order to use `@nx/powerpack-s3-cache`, you need to have an active Powerpack license. If you don't have a license or it has expired, your cache will no longer be shared and each machine will use its local cache.
{% /callout %}
## Setup
### 1. Install the Package
1. [Activate Powerpack](/recipes/installation/activate-powerpack) if you haven't already
2. Install the package
```shell
nx add @nx/powerpack-s3-cache
```
### 2. Authenticate with AWS
There are four different ways to authenticate with AWS. They will be attempted in this order:
1. Environment variables
2. INI config files
3. Single sign-on
4. `nx.json` settings
#### Environment Variables
[AWS provides environment variables](https://docs.aws.amazon.com/sdkref/latest/guide/environment-variables.html) that can be used to authenticate:
| **Environment Variable** | **Description** |
| --------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `AWS_ACCESS_KEY_ID` | The access key for your AWS account. |
| `AWS_SECRET_ACCESS_KEY` | The secret key for your AWS account. |
| `AWS_SESSION_TOKEN` | The session key for your AWS account. This is only needed when you are using temporary credentials. |
| `AWS_CREDENTIAL_EXPIRATION` | The expiration time of the credentials contained in the environment variables described above. This value must be in a format compatible with the [ISO-8601 standard](https://en.wikipedia.org/wiki/ISO_8601) and is only needed when you are using temporary credentials. |
Both the `AWS_ACCESS_KEY_ID` and the `AWS_SECRET_ACCESS_KEY` environment variables are required to use the environment variable authentication method.
#### INI Config Files
AWS can read your authentication credentials from [shared INI config files](https://docs.aws.amazon.com/sdkref/latest/guide/file-format.html). The files are located at `~/.aws/credentials` and `~/.aws/config`. Both files are expected to be INI formatted with section names corresponding to profiles. Sections in the credentials file are treated as profile names, whereas profile sections in the config file must have the format of `[profile profile-name]`, except for the default profile. Profiles that appear in both files will not be merged, and the version that appears in the credentials file will be given precedence over the profile found in the config file.
#### Single Sign-On
Nx can read the active access token [created after running `aws sso login`](https://docs.aws.amazon.com/sdkref/latest/guide/understanding-sso.html) then request temporary AWS credentials. You can create the `AwsCredentialIdentityProvider` functions using the inline SSO parameters (`ssoStartUrl`, `ssoAccountId`, `ssoRegion`, `ssoRoleName`) or load them from [AWS SDKs and Tools shared configuration and credentials files](https://docs.aws.amazon.com/credref/latest/refdocs/creds-config-files.html). Profiles in the `credentials` file are given precedence over profiles in the `config` file.
#### Credentials in `nx.json` File
Storing your credentials in the `nx.json` file is the least secure of the 4 authentication options, since anyone with read access to your code base will have access to your AWS credentials.
```jsonc {% fileName="nx.json" %}
{
"s3": {
"ssoProfile": "default",
"accessKeyId": "MYACCESSKEYID",
"secretAccessKey": "MYSECRETACCESSKEY"
}
}
```
| **Property** | **Description** |
| ------------------- | ----------------------------------------------------------------------------- |
| **ssoProfile** | The name of the profile to use from your AWS CLI SSO Configuration (optional) |
| **endpoint** | The AWS endpoint URL (optional) |
| **accessKeyId** | AWS Access Key ID (optional) |
| **secretAccessKey** | AWS secret access key (optional) |
### 3. Configure S3 Cache
Regardless of how you manage your AWS authentication, you need to configure your Nx cache in the `nx.json` file. The `bucket` that you specify needs to already exist - Nx doesn't create it for you.
```jsonc {% fileName="nx.json" %}
{
"s3": {
"region": "us-east-1",
"bucket": "my-bucket",
"encryptionKey": "create-your-own-key"
}
}
```
| **Property** | **Description** |
| ----------------- | --------------------------------------------------------------------------------- |
| **region** | The id of the AWS region to use |
| **bucket** | The name of the AWS bucket to use |
| **encryptionKey** | Nx encryption key used to encrypt and decrypt artifacts from the cache (optional) |

View File

@ -0,0 +1,35 @@
---
title: Overview of the Nx powerpack-shared-fs-cache Plugin
description: The powerpack-shared-fs-cache Nx plugin enables you to use a shared file system directory instead of Nx Cloud to host your remote cache
---
The `@nx/powerpack-shared-fs-cache` plugin enables you to use a shared file system directory instead of Nx Cloud to host your remote cache. You are responsible for the sharing mechanism for the directory, but the plugin ensures that Nx correctly associates task metadata with the file artifacts.
This plugin will enable the remote cache for your Nx workspace, but does not provide any of the other features of Nx Cloud. If you want to leverage [distributed task execution](/ci/features/distribute-task-execution), [re-running flaky tasks](/ci/features/flaky-tasks) or [automatically splitting tasks](/ci/features/split-e2e-tasks), you'll need to [connect to Nx Cloud](/ci/intro/connect-to-nx-cloud) and use [Nx Replay](/ci/features/remote-cache) instead.
{% callout type="warning" title="Potential Cache Poisoning" %}
Using a shared file system folder for the remote cache opens you up to the possibility of [cache poisoning](/troubleshooting/unknown-local-cache). To avoid this, use [Nx Replay](/ci/features/remote-cache) or share your cache with an AWS S3 bucket using [`@nx/powerpack-s3-cache`](/nx-api/powerpack-s3-cache).
{% /callout %}
{% callout title="This plugin requires an active Nx Powerpack license" %}
In order to use `@nx/powerpack-shared-fs-cache`, you need to have an active Powerpack license. If you don't have a license or it has expired, your cache will no longer be shared and each machine will use its local cache.
{% /callout %}
## Setup
### 1. Install the Package
1. [Activate Powerpack](/recipes/installation/activate-powerpack) if you haven't already
2. Install the package
```shell
nx add @nx/powerpack-shared-fs-cache
```
### 2. Configure the Cache Directory
The `@nx/powerpack-shared-fs-cache` plugin treats your local cache directory as if it is also a remote cache directory. The local cache directory can be set using `cacheDirectory` in the `nx.json` file or the `NX_CACHE_DIRECTORY` environment variable. The default local cache directory is `.nx/cache`
### 3. Share the Cache Directory
The `@nx/powerpack-shared-fs-cache` plugin does not actually share the cache directory across your organization. You are responsible for enabling the actual sharing mechanism. If you want Nx to handle the sharing, use [Nx Replay](/ci/features/remote-cache) instead. Your shared file system directory might be a directory that is saved and restored by a CI provider or it could be a shared network drive.

View File

@ -0,0 +1,42 @@
# Activate Powerpack
Nx Powerpack unlocks features of Nx that are particularly useful for larger organizations. The features include the ability to:
- [Run language-agnostic conformance rules](/features/powerpack/conformance)
- [Define code ownership at the project level](/features/powerpack/owners)
- [Change the remote cache storage location](/features/powerpack/custom-caching)
Activating Powerpack is a two step process.
## 1. Purchase a License
You'll need to [purchase a license](https://nx.app/powerpack/purchase) online. The license cost depends on the
{% call-to-action title="Buy a Powerpack License" icon="nx" description="Unlock all the features of Nx" url="https://nx.app/powerpack/purchase" /%}
Once you've completed the purchase, you will receive a license key.
## 2. Register the License Key
{% tabs %}
{% tab label="Closed Source Repository" %}
To register the license key in your repository, run the `nx activate-powerpack` command.
```shell
nx activate-powerpack YOUR_LICENSE_KEY
```
The license will be saved in your repository and should be committed so that every developer has access to the Powerpack features.
{% /tab %}
{% tab label="Open Source Repository" %}
Register the license key as an environment variable that is not committed to the repository.
```{% fileName=".env" %}
NX_POWERPACK_LICENSE=YOUR_LICENSE_KEY
```
{% /tab %}
{% /tabs %}

View File

@ -2,29 +2,8 @@
By default the cache is stored locally in `.nx/cache`. Cache results are stored for a week before they get deleted. You can customize the cache location in the `nx.json` file: By default the cache is stored locally in `.nx/cache`. Cache results are stored for a week before they get deleted. You can customize the cache location in the `nx.json` file:
{% tabs %}
{% tab label="Nx >= 17" %}
```json {% fileName="nx.json"%} ```json {% fileName="nx.json"%}
{ {
"cacheDirectory": "/tmp/mycache" "cacheDirectory": "/tmp/mycache"
} }
``` ```
{% /tab %}
{% tab label="Nx < 17" %}
```json {% fileName="nx.json"%}
{
"tasksRunnerOptions": {
"default": {
"options": {
"cacheDirectory": "/tmp/mycache"
}
}
}
}
```
{% /tab %}
{% /tabs %}

View File

@ -21,6 +21,10 @@
- [Automate Updating Dependencies](/features/automate-updating-dependencies) - [Automate Updating Dependencies](/features/automate-updating-dependencies)
- [Enforce Module Boundaries](/features/enforce-module-boundaries) - [Enforce Module Boundaries](/features/enforce-module-boundaries)
- [Manage Releases](/features/manage-releases) - [Manage Releases](/features/manage-releases)
- [Powerpack Features](/features/powerpack)
- [Run Language-Agnostic Conformance Rules](/features/powerpack/conformance)
- [Define Code Ownership at the Project Level](/features/powerpack/owners)
- [Self-Host the Remote Cache](/features/powerpack/custom-caching)
- [CI Features](/features/ci-features) - [CI Features](/features/ci-features)
- [Concepts](/concepts) - [Concepts](/concepts)
- [Mental Model](/concepts/mental-model) - [Mental Model](/concepts/mental-model)
@ -51,6 +55,7 @@
- [Folder Structure](/concepts/decisions/folder-structure) - [Folder Structure](/concepts/decisions/folder-structure)
- [Recipes](/recipes) - [Recipes](/recipes)
- [Installation](/recipes/installation) - [Installation](/recipes/installation)
- [Activate Powerpack](/recipes/installation/activate-powerpack)
- [Install Nx in a Non-Javascript Repo](/recipes/installation/install-non-javascript) - [Install Nx in a Non-Javascript Repo](/recipes/installation/install-non-javascript)
- [Update Your Global Nx Installation](/recipes/installation/update-global-installation) - [Update Your Global Nx Installation](/recipes/installation/update-global-installation)
- [Tasks & Caching](/recipes/running-tasks) - [Tasks & Caching](/recipes/running-tasks)
@ -219,6 +224,7 @@
- [workspace.json](/deprecated/workspace-json) - [workspace.json](/deprecated/workspace-json)
- [As Provided vs. Derived](/deprecated/as-provided-vs-derived) - [As Provided vs. Derived](/deprecated/as-provided-vs-derived)
- [Workspace Generators](/deprecated/workspace-generators) - [Workspace Generators](/deprecated/workspace-generators)
- [Custom Task Runners](/deprecated/custom-task-runners)
- [Workspace Executors](/deprecated/workspace-executors) - [Workspace Executors](/deprecated/workspace-executors)
- [runtimeCacheInputs](/deprecated/runtime-cache-inputs) - [runtimeCacheInputs](/deprecated/runtime-cache-inputs)
- [cacheableOperations](/deprecated/cacheable-operations) - [cacheableOperations](/deprecated/cacheable-operations)
@ -755,3 +761,23 @@
- [npm-package](/nx-api/workspace/generators/npm-package) - [npm-package](/nx-api/workspace/generators/npm-package)
- [ci-workflow](/nx-api/workspace/generators/ci-workflow) - [ci-workflow](/nx-api/workspace/generators/ci-workflow)
- [infer-targets](/nx-api/workspace/generators/infer-targets) - [infer-targets](/nx-api/workspace/generators/infer-targets)
- [powerpack-conformance](/nx-api/powerpack-conformance)
- [documents](/nx-api/powerpack-conformance/documents)
- [Overview](/nx-api/powerpack-conformance/documents/overview)
- [powerpack-license](/nx-api/powerpack-license)
- [powerpack-owners](/nx-api/powerpack-owners)
- [documents](/nx-api/powerpack-owners/documents)
- [Overview](/nx-api/powerpack-owners/documents/overview)
- [generators](/nx-api/powerpack-owners/generators)
- [init](/nx-api/powerpack-owners/generators/init)
- [sync-codeowners-file](/nx-api/powerpack-owners/generators/sync-codeowners-file)
- [powerpack-s3-cache](/nx-api/powerpack-s3-cache)
- [documents](/nx-api/powerpack-s3-cache/documents)
- [Overview](/nx-api/powerpack-s3-cache/documents/overview)
- [generators](/nx-api/powerpack-s3-cache/generators)
- [init](/nx-api/powerpack-s3-cache/generators/init)
- [powerpack-shared-fs-cache](/nx-api/powerpack-shared-fs-cache)
- [documents](/nx-api/powerpack-shared-fs-cache/documents)
- [Overview](/nx-api/powerpack-shared-fs-cache/documents/overview)
- [generators](/nx-api/powerpack-shared-fs-cache/generators)
- [init](/nx-api/powerpack-shared-fs-cache/generators/init)

View File

@ -77,11 +77,11 @@ export default function Browse(props: BrowseProps): JSX.Element {
return ( return (
<> <>
<NextSeo <NextSeo
title="Nx Plugin Listing" title="Nx Plugin Registry"
description="Nx Plugins enhance the developer experience in you workspace to make your life simpler. Browse the list of available Nx Plugins." description="Nx Plugins enhance the developer experience in you workspace to make your life simpler. Browse the list of available Nx Plugins."
openGraph={{ openGraph={{
url: 'https://nx.dev' + router.asPath, url: 'https://nx.dev' + router.asPath,
title: 'Nx Plugin Listing', title: 'Nx Plugin Registry',
description: description:
'Nx Plugins enhance the developer experience in you workspace to make your life simpler. Browse the list of available Nx Plugins.', 'Nx Plugins enhance the developer experience in you workspace to make your life simpler. Browse the list of available Nx Plugins.',
images: [ images: [
@ -127,7 +127,7 @@ export default function Browse(props: BrowseProps): JSX.Element {
Are you a plugin author? You can{' '} Are you a plugin author? You can{' '}
<a <a
className="underline" className="underline"
href="/extending-nx/tutorials/tooling-plugin#list-your-nx-plugin" href="/extending-nx/recipes/publish-plugin#list-your-nx-plugin"
> >
add your plugin to the registry add your plugin to the registry
</a>{' '} </a>{' '}

View File

@ -0,0 +1,397 @@
import { useRouter } from 'next/router';
import { NextSeo } from 'next-seo';
import { Footer, Header } from '@nx/nx-dev/ui-common';
export function Contact(): JSX.Element {
const router = useRouter();
return (
<>
<NextSeo
title="Contact us"
description="There are many ways you can connect with the open-source Nx community. Let's connect together!"
openGraph={{
url: 'https://nx.dev' + router.asPath,
title: 'Contact us',
description:
"There are many ways you can connect with the open-source Nx community. Let's connect together!",
images: [
{
url: 'https://nx.dev/socials/nx-media.png',
width: 800,
height: 421,
alt: 'Nx: Smart Monorepos · Fast CI',
type: 'image/jpeg',
},
],
siteName: 'NxDev',
type: 'website',
}}
/>
<Header />
<main id="main" role="main" className="py-24 lg:py-32">
<div className="mx-auto max-w-prose">
<h1 className="text-2xl font-bold leading-7 sm:text-3xl sm:tracking-tight">
NX POWERPACK END USER LICENSE AGREEMENT
</h1>
<h2 className="mt-6 text-lg font-medium leading-6">
Last Updated: September 18th, 2024
</h2>
<p className="mt-12">
This Nx End User License Agreement (together with your associated
Order Information, the Agreement) governs your use of our Nx
Powerpack, a suite of paid extensions for Nx (the Software). To
make this Agreement easier to read, the terms Nx, we, and us
refers to Narwhal Technologies, Inc., and the term you refers to
you and any organization that you are acting on behalf of in signing
up for a subscription to the Software. If you are an individual
acting on behalf of an entity, you represent and warrant that you
have the authority to enter into this Agreement on behalf of that
entity and to legally bind that entity. If you do not accept the
terms of this Agreement, then you must not use the Software.
</p>
<div className="prose mt-6 mt-8 text-slate-700 dark:text-slate-400">
<h2 className="mt-6 text-slate-700 dark:text-slate-400">
1. DEFINITIONS.
</h2>
<dl>
<dd>
(a) Licensed Volume means the limits, volume or other
conditions of permitted use for the Software as set forth in the
Order Information, including any limits on the number of
Authorized Users or number of workspaces.
</dd>
<dd>
(b) Nx IP means the Software, algorithms, technology,
databases, tools, know-how or processes used to provide or
deliver the Software or any related services, and its
documentation (Documentation), all improvements, modifications
or derivative works of the foregoing (regardless of authorship),
and all intellectual property rights (IPR) in any of the
foregoing.
</dd>
<dd>
(c) Order Information means (i) certain terms associated with
your subscription to Use the Software, as communicated to you
via our pricing page available at
https://cloud.nx.app/powerpack/purchase (“Pricing Page”) , as
may be updated from time to time or (ii) as otherwise set forth
in a written order form or purchase order signed by you and Nx
(PO).
</dd>
</dl>
<h2 className="mt-6 text-slate-700 dark:text-slate-400">
2. LICENSE.
</h2>
<dl>
<dd>
(a) License. Subject to the terms and conditions of this
Agreement (including receipt of the License Key), Nx hereby
grants you a worldwide, non-exclusive, non-transferable (except
in compliance with Section 12), non-sublicensable license to
download and install the Software on premises owned or
controlled by you, and run the Software solely for your internal
business purposes (the Purpose) during the Term in accordance
with the Documentation and subject to the Licensed Volume. You
have the right to permit your employees or contributors
(Authorized Users) to use the Software on your behalf for the
Purpose in accordance with this Agreement; provided, however,
that you will remain fully and directly liable to Nx for any and
all use of the Software by Authorized Users as if such use was
by you yourself under this Agreement. Nothing in this Agreement
will operate to grant you any right, title or interest, whether
by implication, estoppel or otherwise, in or to the Nx IP, other
than as expressly set forth herein. As between Nx and you, Nx
will exclusively own all right, title and interest in and to the
Nx IP.
</dd>
<dd>
(b) Use Restrictions. You will not at any time, directly or
indirectly, and will not permit any person or entity
(collectively, Person) (including, without limitation, your
Authorized Users) to: (i) copy, modify or create derivative
works of the Software or Documentation, in whole or in part;
(ii) reverse engineer, disassemble, decompile, decode or
otherwise attempt to derive or gain improper access to any
software component of the Software, in whole or in part; (iii)
frame, mirror, sell, resell, rent or lease the use of the
Software, License Key or Documentation to any other Person, or
otherwise use or allow any Person to use the Software, License
Key or Documentation for any purpose other than for your benefit
for the Purpose in accordance with this Agreement; (iv) create
any script or other automated tool that attempts to create
multiple License Keys; (v) use the Software or License Key in
any infringing or unlawful manner; or (vi) use the Software,
Documentation or any other Confidential Information of Nx for
competitive analysis or benchmarking purposes, or to otherwise
develop, commercialize, license or sell any product, service or
technology that could, directly or indirectly, compete with the
Nx IP.
</dd>
<dd>
(c) Authorized Equipment. You will bear the sole responsibility
for obtaining and maintaining the hardware and any computer
systems, networks, telecommunications systems, Internet access,
third party services or any other materials required to meet the
minimum technical and operational requirements required to
operate the Software.
</dd>
</dl>
<h2 className="mt-6 text-slate-700 dark:text-slate-400">
3. LICENSE KEY; FEES AND PAYMENT.
</h2>
To use the Software, you are required to purchase a license key via
the Pricing Page or PO (License Key). You are liable for any
actions or inactions performed under your License Key. You will pay
Nx all fees set forth in your Order Information (Fees) on the
payment dates specified in your Order Information. All Fees are
non-refundable. Nx reserves the right to change the Fees and
Licensed Volume and to institute new Fees and revised limits of the
Licensed Volume upon 30 days prior notice to you. Unless otherwise
specified in the Order Information, Fees will be paid by the
approved credit card that you designate when you sign up to use the
Software. You hereby authorize us to initiate all payment
transactions for Fees from your approved credit card when such Fees
are due, if applicable. Any and all Fees that are not paid to Nx
when due will accrue interest at a rate of 1.5% per month, or the
maximum rate permitted by law, whichever is greater. In the event of
a conflict between this Agreement and the Order Information, the
Order Information will control and govern. All Fees do not include
any sales, use, value added or other applicable taxes, payment of
which will be your sole responsibility (excluding any taxes based on
Nxs net income).
<h2 className="mt-6 text-slate-700 dark:text-slate-400">
4. CONFIDENTIAL INFORMATION.
</h2>
Confidential Information means any information that one party (the
Disclosing Party) provides to the other party (the Receiving
Party) in connection with this Agreement, whether orally or in
writing, that is designated as confidential or that reasonably
should be considered to be confidential given the nature of the
information and/or the circumstances of disclosure. Confidential
Information will not include any information that: (i) is or becomes
generally known to the public through no fault or breach of this
Agreement by the Receiving Party; (ii) is rightfully known by the
Receiving Party at the time of disclosure without an obligation of
confidentiality; (iii) is independently developed by the Receiving
Party without access to or use of any Confidential Information of
the Disclosing Party that can be evidenced in writing; or (iv) is
rightfully obtained by the Receiving Party from a third-party
without restriction on use or disclosure. For clarity, the Software
and the Documentation will be deemed Confidential Information of Nx.
The Receiving Party will not use or disclose any Confidential
Information of the Disclosing Party except as necessary to perform
its obligations or exercise its rights under this Agreement. The
Receiving Party may disclose Confidential Information of the
Disclosing Party only: (A) to those of its employees, contractors,
agents and advisors who have a bona fide need to know such
Confidential Information to perform under this Agreement and who are
bound by written agreements with use and nondisclosure restrictions
at least as protective of the Confidential Information as those set
forth in this Agreement, or (B) as such disclosure may be required
by the order or requirement of a court, administrative agency or
other governmental body, subject to the Receiving Party providing to
the Disclosing Party reasonable written notice to allow the
Disclosing Party to seek a protective order or otherwise contest the
disclosure.
<h2 className="mt-6 text-slate-700 dark:text-slate-400">
5. POLICIES; SUPPORT.
</h2>
You hereby acknowledge that you have reviewed and agreed to the Nx
Privacy Policy at https://cloud.nx.app/privacy. Such policy is
hereby incorporated into and is hereby deemed a part of this
Agreement, binding upon you and you Authorized Users with respect to
your and their use of the Software in connection with this
Agreement. As part of your subscription to the Software, Nx will
provide reasonable support in connection with the Software in
accordance with the support terms set forth in your Order
Information.
<h2 className="mt-6 text-slate-700 dark:text-slate-400">
6. FEEDBACK.
</h2>
From time-to-time you or your Authorized Users may provide Nx with
feedback with regard to the Software. You, on behalf of yourself and
your Authorized Users, hereby grant Nx a perpetual, irrevocable,
royalty-free and fully-paid up license to use and exploit all such
feedback in connection with Nxs business purposes.
<h2 className="mt-6 text-slate-700 dark:text-slate-400">
7. INDEMNIFICATION.
</h2>
<dl>
<dd>
(a) Nx Indemnification. Nx will defend and pay all damages
finally awarded against you pursuant to a final, valid and
binding judgment or order, or a final settlement agreement with
respect to any claim, suit or proceeding brought by a third
party against you arising from the Softwares infringement of
such third-partys IPR. The foregoing obligation will not apply
if the underlying third-party claim arises from (i) your breach
of this Agreement, negligence, willful misconduct or fraud; (ii)
modifications to the Software by anyone other than Nx; or (iii)
combinations of the Software of with software, data or materials
not provided by Nx. If Nx reasonably believes the Software (or
any component) could infringe any third partys IPR, Nx may, at
its sole option and expense: (A) procure the right for you to
continue using the Software (or any infringing component) to
make it non-infringing without materially reducing its
functionality; or (B) replace the Software (or any infringing
component) with a non-infringing alternative that is
functionally equivalent in all material respects. If the
foregoing remedies are not available to Nx on commercially
reasonable terms, then Nx may terminate your use of the Software
upon notice to you.
</dd>
<dd>
(b) Your Indemnification. You will defend and pay all damages
finally awarded against Nx pursuant to a final, valid and
binding judgment or order or a final settlement agreement with
respect to any claim, suit or proceeding brought by a third
party against Nx arising from any breach of the restrictions set
forth in Section 2(b).
</dd>
<dd>
(c) Indemnification Procedures. The party seeking defense and
indemnity (the Indemnified Party) will promptly notify the
other party (the Indemnifying Party) of any and all such
claims and will reasonably cooperate with the Indemnifying Party
with the defense and/or settlement thereof. The Indemnifying
Party will have the sole right to conduct the defense of any
claim for which the Indemnifying Party is responsible hereunder
(provided that the Indemnifying Party may not settle any claim
without the Indemnified Partys prior written approval unless
the settlement unconditionally releases the Indemnified Party
from all liability, does not require any admission by the
Indemnified Party, and does not place restrictions upon the
Indemnified Partys business). The Indemnified Party may
participate in the defense or settlement of any such claim at
its own expense and with its own choice of counsel or, if the
Indemnifying Party refuses to fulfill its obligation of defense,
the Indemnified Party may defend itself and seek reimbursement
from the Indemnifying Party.
</dd>
</dl>
<h2 className="mt-6 text-slate-700 dark:text-slate-400">
8. DISCLAIMERS.
</h2>
THE SOFTWARE IS PROVIDED ON AN AS IS BASIS, AND NX MAKES NO
WARRANTIES OR REPRESENTATIONS TO YOU, YOUR AUTHORIZED USERS OR TO
ANY OTHER PERSON REGARDING THE SOFTWARE. TO THE MAXIMUM EXTENT
PERMITTED BY APPLICABLE LAW, NX HEREBY DISCLAIMS (a) ALL WARRANTIES
AND REPRESENTATIONS, WHETHER EXPRESS OR IMPLIED AND (b) ANY WARRANTY
THAT USE OF THE SOFTWARE WILL BE ERROR-FREE.
<h2 className="mt-6 text-slate-700 dark:text-slate-400">
9. LIMITATIONS OF LIABILITY.
</h2>
EXCEPT FOR A PARTYS GROSS NEGLIGENCE, WILLFUL MISCONDUCT OR FRAUD,
IN NO EVENT WILL (a) EITHER PARTY BE LIABLE TO THE OTHER PARTY FOR
ANY INCIDENTAL, SPECIAL, EXEMPLARY, PUNITIVE OR CONSEQUENTIAL
DAMAGES, LOSS OF INCOME, DATA, PROFITS, REVENUE OR BUSINESS
INTERRUPTION, OR THE COST OF SUBSTITUTE SERVICES OR OTHER ECONOMIC
LOSS, ARISING OUT OF OR IN CONNECTION WITH THIS AGREEMENT, WHETHER
SUCH LIABILITY ARISES FROM ANY CLAIM BASED ON CONTRACT, WARRANTY,
TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, AND
WHETHER OR NOT SUCH PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
SUCH LOSS OR DAMAGE AND (b) NXS TOTAL LIABILITY TO YOU, YOUR
AUTHORIZED USERS OR ANY OTHER PERSON IN CONNECTION WITH THIS
AGREEMENT OR THE PROVISION OF THE SOFTWARE EXCEED THE FEES ACTUALLY
PAID BY YOU TO NX IN THE 12 MONTH PERIOD PRECEDING THE ACTION GIVING
RISE TO SUCH LIABILITY.
<h2 className="mt-6 text-slate-700 dark:text-slate-400">
10. TERM AND TERMINATION.
</h2>
<dl>
<dd>
(a) Term; Termination. The term of this Agreement will begin on
the effective date in the Order Information, and will expire at
the end of the initial term specified in the Order Information
(the Initial Term). Following the Initial Term, this Agreement
will automatically renew for successive one-month terms (the
Initial Term, together with any renewal term, the Term),
unless Nx or you provides the other with at least twenty (20)
days written notice of its intent not to renew prior to the end
of the then-current term. Either party may terminate this
Agreement, effective on written notice to the other party, if
the other party materially breaches this Agreement, and such
breach: (A) is incapable of cure; or (B) being capable of cure,
remains uncured thirty (30) days after the non-breaching party
provides the breaching party with written notice of such breach.
</dd>
<dd>
(b) Effect of Termination; Survival. Upon termination of this
Agreement, your right to use the Software will immediately
terminate and you shall cease using the Software, including for
example, by permanently removing the Software dependency. This
Section 10(b) and Sections 2(b), 3, 4, 5 (first sentence), 6 9
and 12 survive any termination of this Agreement.
</dd>
</dl>
<h2 className="mt-6 text-slate-700 dark:text-slate-400">
11. TRADEMARKS.
</h2>
You hereby grant Nx a limited, non-exclusive, royalty-free license
to use and display your name, designated trademarks and associated
logos (Your Marks) during the Term in connection with Nxs
marketing and promotional efforts for its products and services,
including by publicly naming you as a customer of Nx. Nx will
conform to and observe the trademark standards as you prescribe from
time to time. All goodwill generated by Nxs use of Your Marks
inures to your benefit.
<h2 className="my-6 text-slate-700 dark:text-slate-400">
12. MISCELLANEOUS.
</h2>
This Agreement, together with the Order Information, is the complete
and exclusive agreement between the parties with respect to its
subject matter and supersedes all prior or contemporaneous
agreements, communications and understandings, both written and
oral, with respect to its subject matter, including any prior terms.
This Agreement may be amended or modified only by a written document
assented by duly authorized representatives of the parties. Nx may
perform an audit of your use of the Software once per year in
connection with your compliance with this Agreement, including if
you are exceeding the Licensed Volume. Nx may provide notices to you
by posting them on our website, by providing electronic notification
via the Software, or by email to the address associated with your
account. You may provide notices to us via email at
powerpack-support@nrwl.io. All notices are effective upon posting or
when delivered. Except as otherwise set forth herein, either partys
failure to enforce any provision of this Agreement will not
constitute a waiver of future enforcement of that or any other
provision. No waiver of any provision of this Agreement will be
effective unless it is in writing and signed by the party granting
the waiver. If any provision of this Agreement is held invalid,
illegal or unenforceable, that provision will be enforced to the
maximum extent permitted by law, and the remaining provisions of
this Agreement will remain in full force and effect. This Agreement
will be governed by and construed in accordance with the laws of the
State of California without giving effect to any principles of
conflict of laws that would lead to the application of the laws of
another jurisdiction. Any legal action or proceeding arising under
this Agreement will be brought exclusively in the federal or state
courts located in the Northern District of California and the
parties irrevocably consent to the personal jurisdiction and venue
therein. Nx may freely assign its rights and obligations under this
Agreement. You may not assign or transfer this Agreement, by
operation of law or otherwise, without Nxs prior written consent;
provided, however, that you may assign your rights or delegate your
obligations, in whole or in part, without such consent, to (i) one
or more of your affiliates, or (ii) a third party that succeeds to
all or substantially all of your business and assets relating to the
subject matter of this Agreement, whether by sale, merger, operation
of law or otherwise. Any attempt to assign or transfer this
Agreement without such consent will be void. Subject to the
foregoing, this Agreement is binding upon and will inure to the
benefit of each of the parties and their respective successors and
permitted assigns. Unless otherwise expressly provided, no
provisions of this Agreement are intended or will be construed to
confer upon or give to any person or entity, other than the parties,
any rights, remedies or other benefits under or by reason of this
Agreement.
</div>
</div>
</main>
<Footer />
</>
);
}
export default Contact;

View File

@ -15,6 +15,7 @@ import {
GlobeAltIcon, GlobeAltIcon,
MicrophoneIcon, MicrophoneIcon,
VideoCameraIcon, VideoCameraIcon,
CheckBadgeIcon,
} from '@heroicons/react/24/outline'; } from '@heroicons/react/24/outline';
import { FC, SVGProps } from 'react'; import { FC, SVGProps } from 'react';
import { DiscordIcon } from '../discord-icon'; import { DiscordIcon } from '../discord-icon';
@ -85,6 +86,22 @@ export const featuresItems: MenuItem[] = [
isNew: false, isNew: false,
isHighlight: false, isHighlight: false,
}, },
{
name: 'Run Conformance Rules',
description: null,
href: '/features/powerpack/conformance',
icon: CheckBadgeIcon,
isNew: false,
isHighlight: false,
},
{
name: 'Define Project Owners',
description: null,
href: '/features/powerpack/owners',
icon: UserGroupIcon,
isNew: false,
isHighlight: false,
},
{ {
name: 'Use Remote Caching (Nx Replay)', name: 'Use Remote Caching (Nx Replay)',
description: 'Zero-config, fast & secure remote cache solution.', description: 'Zero-config, fast & secure remote cache solution.',

View File

@ -7,7 +7,8 @@ import {
} from '@heroicons/react/24/outline'; } from '@heroicons/react/24/outline';
import { MagnifyingGlassIcon } from '@heroicons/react/24/solid'; import { MagnifyingGlassIcon } from '@heroicons/react/24/solid';
import { PluginCard, SectionHeading } from '@nx/nx-dev/ui-common'; import { PluginCard, SectionHeading } from '@nx/nx-dev/ui-common';
import { useState } from 'react'; import { useParams } from 'next/navigation';
import { useEffect, useState, useRef, ElementRef } from 'react';
interface Plugin { interface Plugin {
description: string; description: string;
@ -36,11 +37,38 @@ interface Modifiers {
orderDirection: 'ASC' | 'DESC'; orderDirection: 'ASC' | 'DESC';
} }
const useUrlHash = (initialValue: string) => {
const [hash, setHash] = useState(initialValue);
const updateHash = (str: string) => {
if (!str) return;
setHash(str.split('#')[1]);
};
const params = useParams();
useEffect(() => {
updateHash(window.location.hash);
}, [params]);
return hash;
};
export function PluginDirectory({ export function PluginDirectory({
pluginList, pluginList,
}: { }: {
pluginList: Plugin[]; pluginList: Plugin[];
}): JSX.Element { }): JSX.Element {
const hash = decodeURIComponent(useUrlHash(''));
const searchRef = useRef<ElementRef<'input'>>(null);
useEffect(() => {
if (searchRef.current) {
// Set input value and trigger the onChange event
searchRef.current.setAttribute('value', hash);
const event = new Event('input', { bubbles: true });
searchRef.current.dispatchEvent(event);
}
}, [searchRef, hash]);
const [modifiers, setModifiers] = useState<Modifiers>({ const [modifiers, setModifiers] = useState<Modifiers>({
term: '', term: '',
officialStatus: undefined, officialStatus: undefined,
@ -79,6 +107,7 @@ export function PluginDirectory({
</div> </div>
<input <input
id="search" id="search"
ref={searchRef}
name="search" name="search"
className="block w-full rounded-md border border-slate-300 bg-white py-2 pl-10 pr-3 text-sm placeholder-slate-500 transition focus:placeholder-slate-400 dark:border-slate-900 dark:bg-slate-700" className="block w-full rounded-md border border-slate-300 bg-white py-2 pl-10 pr-3 text-sm placeholder-slate-500 transition focus:placeholder-slate-400 dark:border-slate-900 dark:bg-slate-700"
placeholder="Quick search" placeholder="Quick search"

View File

@ -5,6 +5,8 @@ import {
PlayCircleIcon, PlayCircleIcon,
} from '@heroicons/react/24/outline'; } from '@heroicons/react/24/outline';
import { Framework, frameworkIcons } from '@nx/graph/ui-icons'; import { Framework, frameworkIcons } from '@nx/graph/ui-icons';
import * as nxDevIcons from '@nx/nx-dev/ui-icons';
import * as heroIcons from '@heroicons/react/24/outline';
import { cx } from '@nx/nx-dev/ui-primitives'; import { cx } from '@nx/nx-dev/ui-primitives';
import { ReactNode } from 'react'; import { ReactNode } from 'react';
@ -99,6 +101,13 @@ export function Cards({
); );
} }
function callIfFunction(fn: any) {
if (typeof fn === 'function') {
return fn({});
}
return fn;
}
export function LinkCard({ export function LinkCard({
title, title,
type, type,
@ -116,7 +125,7 @@ export function LinkCard({
<Link <Link
key={title} key={title}
href={url} href={url}
className="no-prose relative col-span-1 flex flex-col items-center rounded-md border border-slate-200 bg-slate-50/40 p-4 text-center font-semibold shadow-sm transition focus-within:ring-2 focus-within:ring-blue-500 focus-within:ring-offset-2 hover:bg-slate-100 dark:border-slate-800/40 dark:bg-slate-800/60 dark:hover:bg-slate-800" className="no-prose relative col-span-1 mx-auto flex w-full max-w-md flex-col items-center rounded-md border border-slate-200 bg-slate-50/40 p-4 text-center font-semibold shadow-sm transition focus-within:ring-2 focus-within:ring-blue-500 focus-within:ring-offset-2 hover:bg-slate-100 dark:border-slate-800/40 dark:bg-slate-800/60 dark:hover:bg-slate-800"
style={{ textDecorationLine: 'none' }} style={{ textDecorationLine: 'none' }}
prefetch={false} prefetch={false}
> >
@ -129,7 +138,12 @@ export function LinkCard({
} }
)} )}
> >
{icon && frameworkIcons[icon as Framework]?.image} {icon &&
(frameworkIcons[icon as Framework]?.image ||
callIfFunction(nxDevIcons[icon as keyof typeof nxDevIcons]) ||
callIfFunction(
(heroIcons[icon as keyof typeof heroIcons] as any)?.render
))}
</div> </div>
)} )}
<div <div

View File

@ -396,6 +396,7 @@
"{workspaceRoot}/packages/**", "{workspaceRoot}/packages/**",
"{workspaceRoot}/docs/**", "{workspaceRoot}/docs/**",
"{workspaceRoot}/scripts/documentation/**", "{workspaceRoot}/scripts/documentation/**",
"!{workspaceRoot}/docs/external-generated",
"!{workspaceRoot}/docs/generated", "!{workspaceRoot}/docs/generated",
"!{workspaceRoot}/packages/**/*.spec.ts", "!{workspaceRoot}/packages/**/*.spec.ts",
"!{workspaceRoot}/packages/**/project.json", "!{workspaceRoot}/packages/**/project.json",
@ -407,6 +408,7 @@
] ]
}, },
"outputs": [ "outputs": [
"{workspaceRoot}/docs/external-generated",
"{workspaceRoot}/docs/generated" "{workspaceRoot}/docs/generated"
] ]
} }

View File

@ -43,6 +43,10 @@ export function generateManifests(workspace: string): Promise<void[]> {
console.log(`${chalk.blue('i')} Generating Manifests`); console.log(`${chalk.blue('i')} Generating Manifests`);
const documentationPath = resolve(workspace, 'docs'); const documentationPath = resolve(workspace, 'docs');
const generatedDocumentationPath = resolve(documentationPath, 'generated'); const generatedDocumentationPath = resolve(documentationPath, 'generated');
const generatedExternalDocumentationPath = resolve(
documentationPath,
'external-generated'
);
const targetFolder: string = resolve(generatedDocumentationPath, 'manifests'); const targetFolder: string = resolve(generatedDocumentationPath, 'manifests');
const documents: Partial<DocumentMetadata>[] = readJsonSync( const documents: Partial<DocumentMetadata>[] = readJsonSync(
`${documentationPath}/map.json`, `${documentationPath}/map.json`,
@ -50,12 +54,17 @@ export function generateManifests(workspace: string): Promise<void[]> {
encoding: 'utf8', encoding: 'utf8',
} }
).content; ).content;
const packages: PackageMetadata[] = readJsonSync( const packages: PackageMetadata[] = [
`${generatedDocumentationPath}/packages-metadata.json`, ...readJsonSync(`${generatedDocumentationPath}/packages-metadata.json`, {
{
encoding: 'utf8', encoding: 'utf8',
} }),
); ...readJsonSync(
`${generatedExternalDocumentationPath}/packages-metadata.json`,
{
encoding: 'utf8',
}
),
];
/** /**
* We are starting by selecting what section of the map.json we want to work with. * We are starting by selecting what section of the map.json we want to work with.

View File

@ -2,7 +2,11 @@ import * as chalk from 'chalk';
import { execSync } from 'child_process'; import { execSync } from 'child_process';
import { removeSync } from 'fs-extra'; import { removeSync } from 'fs-extra';
import { join, resolve } from 'path'; import { join, resolve } from 'path';
import { generatePackageSchemas } from '../package-schemas/generatePackageSchemas'; import {
generateExternalPackageSchemas,
generateLocalPackageSchemas,
generatePackageSchemas,
} from '../package-schemas/generatePackageSchemas';
import { generateCliDocumentation } from './generate-cli-data'; import { generateCliDocumentation } from './generate-cli-data';
import { generateCnwDocumentation } from './generate-cnw-documentation'; import { generateCnwDocumentation } from './generate-cnw-documentation';
import { generateDevkitDocumentation } from './generate-devkit-documentation'; import { generateDevkitDocumentation } from './generate-devkit-documentation';
@ -26,7 +30,8 @@ async function generate() {
await generateCliDocumentation(commandsOutputDirectory); await generateCliDocumentation(commandsOutputDirectory);
await generateDevkitDocumentation(); await generateDevkitDocumentation();
await generatePackageSchemas(); await generateLocalPackageSchemas();
await generateExternalPackageSchemas();
await generateManifests(workspaceRoot); await generateManifests(workspaceRoot);

View File

@ -32,9 +32,18 @@ const documents: any[] = [
}), }),
].filter(Boolean); ].filter(Boolean);
const packages: PackageMetadata[] = readJSONSync( const packages: PackageMetadata[] = [
resolve(__dirname, '../../../', `./docs/generated/packages-metadata.json`) ...readJSONSync(
); resolve(__dirname, '../../../', `./docs/generated/packages-metadata.json`)
),
...readJSONSync(
resolve(
__dirname,
'../../../',
`./docs/external-generated/packages-metadata.json`
)
),
];
const targetFolder: string = resolve( const targetFolder: string = resolve(
__dirname, __dirname,
'../../../', '../../../',

View File

@ -33,41 +33,77 @@ function pathResolver(root: string): (path: string) => string {
return (path) => join(root, path.replace('schema.json', '')); return (path) => join(root, path.replace('schema.json', ''));
} }
export function generatePackageSchemas(): Promise<void[]> { export function generateLocalPackageSchemas(): Promise<void[]> {
return generatePackageSchemas();
}
export function generateExternalPackageSchemas(): Promise<any> {
const sourceRepositoryRelativePath = process.env.NX_OCEAN_RELATIVE_PATH;
if (!sourceRepositoryRelativePath) {
return Promise.all([]);
}
const sourcePackagesDirectory = 'libs/nx-packages';
const sourcePackagesNamePrefix = 'powerpack-';
return generatePackageSchemas(
sourceRepositoryRelativePath,
sourcePackagesDirectory,
sourcePackagesNamePrefix
);
}
export function generatePackageSchemas(
sourceRepositoryRelativePath = '',
sourcePackagesDirectory = 'packages',
sourcePackagesNamePrefix = ''
): Promise<void[]> {
console.log(`${chalk.blue('i')} Generating Package Schemas`); console.log(`${chalk.blue('i')} Generating Package Schemas`);
const absoluteRoot = resolve(join(__dirname, '../../../')); const absoluteRoot = resolve(join(__dirname, '../../../'));
const sourceRepositoryRoot = resolve(
const packages = findPackageMetadataList(absoluteRoot, 'packages').map( join(__dirname, '../../../', sourceRepositoryRelativePath)
(packageMetadata) => {
const getCurrentSchemaPath = pathResolver(absoluteRoot);
if (!!packageMetadata.executors.length) {
packageMetadata.executors = packageMetadata.executors.map((item) => ({
...item,
schema: processSchemaData(
item.schema as NxSchema,
getCurrentSchemaPath(item['path'].replace('schema.json', ''))
),
}));
}
if (!!packageMetadata.generators.length) {
packageMetadata.generators = packageMetadata.generators.map((item) => ({
...item,
schema: processSchemaData(
item.schema as NxSchema,
getCurrentSchemaPath(item['path'].replace('schema.json', ''))
),
}));
}
return packageMetadata;
}
); );
const generatedFolderName = sourceRepositoryRelativePath
? 'external-generated'
: 'generated';
const packages = findPackageMetadataList(
sourceRepositoryRoot,
sourcePackagesDirectory,
sourcePackagesNamePrefix
).map((packageMetadata) => {
const getCurrentSchemaPath = pathResolver(absoluteRoot);
if (!!packageMetadata.executors.length) {
packageMetadata.executors = packageMetadata.executors.map((item) => ({
...item,
schema: processSchemaData(
item.schema as NxSchema,
getCurrentSchemaPath(item['path'].replace('schema.json', ''))
),
}));
}
if (!!packageMetadata.generators.length) {
packageMetadata.generators = packageMetadata.generators.map((item) => ({
...item,
schema: processSchemaData(
item.schema as NxSchema,
getCurrentSchemaPath(item['path'].replace('schema.json', ''))
),
}));
}
return packageMetadata;
});
const packagesMetadata = packages.map( const packagesMetadata = packages.map(
(p): PackageMetadata => ({ (p): PackageMetadata => ({
description: p.description, description: p.description,
documents: p.documents.map((d) => ({ documents: p.documents.map((d) => ({
...createDocumentMetadata({ ...createDocumentMetadata({
description: d.description || p.description, description: d.description || p.description,
file: ['generated', 'packages', p.name, 'documents', d.id].join('/'), file: [
generatedFolderName,
'packages',
p.name,
'documents',
d.id,
].join('/'),
id: d.id, id: d.id,
itemList: d.itemList, itemList: d.itemList,
name: d.name, name: d.name,
@ -79,7 +115,7 @@ export function generatePackageSchemas(): Promise<void[]> {
executors: p.executors.map((e) => ({ executors: p.executors.map((e) => ({
description: e.description, description: e.description,
file: [ file: [
'generated', generatedFolderName,
'packages', 'packages',
p.name, p.name,
'executors', 'executors',
@ -94,7 +130,7 @@ export function generatePackageSchemas(): Promise<void[]> {
generators: p.generators.map((g) => ({ generators: p.generators.map((g) => ({
description: g.description, description: g.description,
file: [ file: [
'generated', generatedFolderName,
'packages', 'packages',
p.name, p.name,
'generators', 'generators',
@ -114,7 +150,7 @@ export function generatePackageSchemas(): Promise<void[]> {
}) })
); );
const outputPath: string = join(absoluteRoot, 'docs', 'generated'); const outputPath: string = join(absoluteRoot, 'docs', generatedFolderName);
const outputPackagesPath: string = join(outputPath, 'packages'); const outputPackagesPath: string = join(outputPath, 'packages');
const fileGenerationPromises: Promise<void>[] = []; const fileGenerationPromises: Promise<void>[] = [];

View File

@ -105,7 +105,8 @@ function getSchemaList(
*/ */
export function findPackageMetadataList( export function findPackageMetadataList(
absoluteRoot: string, absoluteRoot: string,
packagesDirectory: string = 'packages' packagesDirectory: string = 'packages',
prefix = ''
): PackageData[] { ): PackageData[] {
const packagesDir = resolve(join(absoluteRoot, packagesDirectory)); const packagesDir = resolve(join(absoluteRoot, packagesDirectory));
@ -117,7 +118,9 @@ export function findPackageMetadataList(
.itemList.map((item) => convertToDocumentMetadata(item)); .itemList.map((item) => convertToDocumentMetadata(item));
// Do not use map.json, but add a documentation property on the package.json directly that can be easily resolved // Do not use map.json, but add a documentation property on the package.json directly that can be easily resolved
return sync(`${packagesDir}/*`, { ignore: [`${packagesDir}/cli`] }) return sync(`${packagesDir}/${prefix}*`, {
ignore: [`${packagesDir}/cli`, `${packagesDir}/*-e2e`],
})
.map((folderPath: string): PackageData => { .map((folderPath: string): PackageData => {
const folderName = folderPath.substring(packagesDir.length + 1); const folderName = folderPath.substring(packagesDir.length + 1);