Compare commits
9 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| b9778ab41a | |||
| 02a4784ef4 | |||
| 227d12e9b4 | |||
| 3eabe2dfd9 | |||
| 1fcf0fc9ee | |||
| cd13ab9adc | |||
| e8b73a59b4 | |||
| f425326af6 | |||
| ce57fc56e4 |
@@ -1,12 +0,0 @@
|
||||
[build]
|
||||
target-dir = 'build/target'
|
||||
|
||||
[target.x86_64-unknown-linux-musl]
|
||||
rustflags = [
|
||||
"-C",
|
||||
"target-feature=-crt-static",
|
||||
]
|
||||
|
||||
[target.aarch64-unknown-linux-musl]
|
||||
linker = "aarch64-linux-musl-gcc"
|
||||
rustflags = ["-C", "target-feature=-crt-static"]
|
||||
+154
-144
@@ -1,184 +1,194 @@
|
||||
version: 2.1
|
||||
|
||||
# -------------------------
|
||||
# ORBS
|
||||
# -------------------------
|
||||
orbs:
|
||||
nx: nrwl/nx@1.6.1
|
||||
rust: circleci/rust@1.6.0
|
||||
browser-tools: circleci/browser-tools@1.4.6
|
||||
|
||||
# -------------------------
|
||||
# EXECUTORS
|
||||
# -------------------------
|
||||
|
||||
defaults: &defaults
|
||||
working_directory: ~/repo
|
||||
# Variables
|
||||
var_1: &working_directory ~/repo
|
||||
|
||||
executors:
|
||||
linux:
|
||||
<<: *defaults
|
||||
working_directory: *working_directory
|
||||
docker:
|
||||
- image: cimg/rust:1.73.0-browsers
|
||||
resource_class: medium+
|
||||
- image: cimg/node:12.20-browsers
|
||||
|
||||
macos:
|
||||
<<: *defaults
|
||||
resource_class: macos.m1.medium.gen1
|
||||
macos:
|
||||
xcode: '14.2.0'
|
||||
windows:
|
||||
working_directory: *working_directory
|
||||
resource_class: windows.medium
|
||||
machine:
|
||||
image: windows-server-2019-vs2019:stable
|
||||
shell: cmd.exe
|
||||
|
||||
# -------------------------
|
||||
# COMMANDS
|
||||
# -------------------------
|
||||
commands:
|
||||
run-pnpm-install:
|
||||
setup:
|
||||
parameters:
|
||||
os:
|
||||
type: string
|
||||
steps:
|
||||
- checkout
|
||||
- when:
|
||||
condition:
|
||||
equal: [<< parameters.os >>, windows]
|
||||
steps:
|
||||
- run: nvm install 12.20
|
||||
- run: nvm use 12.20
|
||||
- run: npm install -g yarn@1.19.0
|
||||
- restore_cache:
|
||||
name: Restore pnpm Package Cache
|
||||
name: Restore Yarn Package Cache
|
||||
keys:
|
||||
- node-deps-{{ arch }}-v3-{{ checksum "pnpm-lock.yaml" }}
|
||||
- nrwl-nx-yarn-packages-<< parameters.os >>-{{ checksum "yarn.lock" }}
|
||||
- run:
|
||||
name: Install dependencies
|
||||
command: yarn install --frozen-lockfile --non-interactive --cache-folder ~/.cache/yarn
|
||||
- save_cache:
|
||||
name: Save Yarn Package Cache
|
||||
# Windows needs its own cache key because binaries in node_modules are different.
|
||||
key: nrwl-nx-yarn-packages-<< parameters.os >>-{{ checksum "yarn.lock" }}
|
||||
paths:
|
||||
- ~/.cache/yarn
|
||||
|
||||
- when:
|
||||
condition:
|
||||
equal: [<< parameters.os >>, linux]
|
||||
steps:
|
||||
- run:
|
||||
name: Install pnpm package manager (linux)
|
||||
command: |
|
||||
npm install --prefix=$HOME/.local -g @pnpm/exe@8.7.4
|
||||
name: Install PNPM
|
||||
command: npm install --prefix=$HOME/.local -g pnpm@5.18.9
|
||||
- when:
|
||||
condition:
|
||||
equal: [<< parameters.os >>, macos]
|
||||
equal: [<< parameters.os >>, windows]
|
||||
steps:
|
||||
- run:
|
||||
name: Install pnpm package manager (macos)
|
||||
command: |
|
||||
npm install -g @pnpm/exe@8.7.4
|
||||
- run:
|
||||
name: Install Dependencies
|
||||
command: |
|
||||
pnpm install --frozen-lockfile
|
||||
pnpm playwright install --with-deps firefox webkit chrome
|
||||
- save_cache:
|
||||
name: Save pnpm Package Cache
|
||||
key: node-deps-{{ arch }}-v3-{{ checksum "pnpm-lock.yaml" }}
|
||||
paths:
|
||||
- ~/.pnpm-store
|
||||
- ~/.cache/Cypress
|
||||
- node_modules
|
||||
# -------------------------
|
||||
# JOBS
|
||||
# -------------------------
|
||||
name: Install PNPM
|
||||
command: npm install -g pnpm@5.18.9
|
||||
|
||||
jobs:
|
||||
# -------------------------
|
||||
# JOBS: Main Linux
|
||||
# -------------------------
|
||||
main-linux:
|
||||
executor: linux
|
||||
agent:
|
||||
parameters:
|
||||
os:
|
||||
type: string
|
||||
default: 'linux'
|
||||
cli:
|
||||
type: string
|
||||
default: ''
|
||||
pm:
|
||||
type: string
|
||||
default: pnpm
|
||||
executor: << parameters.os >>
|
||||
environment:
|
||||
NX_E2E_CI_CACHE_KEY: e2e-circleci-linux
|
||||
NX_VERBOSE_LOGGING: 'true'
|
||||
NX_DAEMON: 'true'
|
||||
NX_PERF_LOGGING: 'false'
|
||||
NX_NATIVE_LOGGING: 'false'
|
||||
NX_E2E_RUN_E2E: 'true'
|
||||
NX_CI_EXECUTION_ENV: 'linux'
|
||||
GIT_AUTHOR_NAME: test@test.com
|
||||
GIT_AUTHOR_EMAIL: Test
|
||||
GIT_COMMITTER_EMAIL: test@test.com
|
||||
GIT_COMMITTER_NAME: Test
|
||||
NX_E2E_CI_CACHE_KEY: e2e-circleci-<< parameters.os >>-<< parameters.pm >>
|
||||
SELECTED_PM: << parameters.pm >>
|
||||
SELECTED_CLI: << parameters.cli >>
|
||||
steps:
|
||||
- run: lscpu
|
||||
- checkout
|
||||
- run: npx nx-cloud@next start-ci-run --distributes-on="8 linux-medium" --stop-agents-after="e2e"
|
||||
- setup:
|
||||
os: << parameters.os >>
|
||||
- run:
|
||||
command: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y ca-certificates lsof
|
||||
- browser-tools/install-chrome
|
||||
- browser-tools/install-chromedriver
|
||||
- run-pnpm-install:
|
||||
os: linux
|
||||
- nx/set-shas:
|
||||
main-branch-name: 'master'
|
||||
- run:
|
||||
name: Benchmark
|
||||
command: node tools/benchmark/benchmark.js
|
||||
name: Agent
|
||||
command: npx nx-cloud start-agent
|
||||
no_output_timeout: 60m
|
||||
pr-main:
|
||||
parameters:
|
||||
os:
|
||||
type: string
|
||||
default: 'linux'
|
||||
cli:
|
||||
type: string
|
||||
default: ''
|
||||
pm:
|
||||
type: string
|
||||
default: pnpm
|
||||
executor: << parameters.os >>
|
||||
environment:
|
||||
NX_CLOUD_DISTRIBUTED_EXECUTION: 'true'
|
||||
SELECTED_CLI: << parameters.cli >>
|
||||
NX_E2E_CI_CACHE_KEY: e2e-circleci-<< parameters.os >>-<< parameters.pm >>
|
||||
steps:
|
||||
- setup:
|
||||
os: << parameters.os >>
|
||||
- run:
|
||||
name: Check Documentation
|
||||
command: pnpm nx documentation --no-dte
|
||||
no_output_timeout: 20m
|
||||
command: yarn documentation
|
||||
- run:
|
||||
name: Run Checks/Lint/Test/Build
|
||||
no_output_timeout: 60m
|
||||
command: |
|
||||
pids=()
|
||||
|
||||
pnpm nx-cloud record -- nx format:check --base=$NX_BASE --head=$NX_HEAD &
|
||||
pids+=($!)
|
||||
|
||||
pnpm nx run-many -t check-imports check-commit check-lock-files check-codeowners documentation --parallel=1 --no-dte &
|
||||
pids+=($!)
|
||||
|
||||
(pnpm nx affected --targets=lint,test,build --base=$NX_BASE --head=$NX_HEAD --parallel=3 &&
|
||||
pnpm nx affected --target=e2e --base=$NX_BASE --head=$NX_HEAD --parallel=1) &
|
||||
pids+=($!)
|
||||
|
||||
for pid in "${pids[@]}"; do
|
||||
wait "$pid"
|
||||
done
|
||||
# -------------------------
|
||||
# JOBS: Main-MacOS
|
||||
# -------------------------
|
||||
mainmacos:
|
||||
executor: macos
|
||||
name: Check Imports
|
||||
command: yarn check-imports
|
||||
- run:
|
||||
name: Check Formatting
|
||||
command: yarn check-format
|
||||
- run:
|
||||
name: Check Package dependencies
|
||||
command: yarn depcheck
|
||||
- run:
|
||||
name: Run Builds
|
||||
command: npx nx affected --target=build --parallel --max-parallel=3
|
||||
- run:
|
||||
name: Run Unit Tests
|
||||
command: npx nx affected --target=test --parallel --max-parallel=2
|
||||
- run:
|
||||
name: Run Linting
|
||||
command: npx nx affected --target=lint --parallel --max-parallel=4
|
||||
- run:
|
||||
name: Run E2E Tests
|
||||
command: npx nx affected --target=e2e
|
||||
no_output_timeout: 45m
|
||||
- run:
|
||||
name: Stop All Running Agents for This CI Run
|
||||
command: npx nx-cloud stop-all-agents
|
||||
trunk-main:
|
||||
parameters:
|
||||
os:
|
||||
type: string
|
||||
default: 'linux'
|
||||
cli:
|
||||
type: string
|
||||
default: ''
|
||||
pm:
|
||||
type: string
|
||||
default: pnpm
|
||||
executor: << parameters.os >>
|
||||
environment:
|
||||
NX_E2E_CI_CACHE_KEY: e2e-circleci-macos
|
||||
NX_PERF_LOGGING: 'false'
|
||||
NX_CI_EXECUTION_ENV: 'macos'
|
||||
SELECTED_PM: 'npm' # explicitly define npm for macOS tests
|
||||
NX_CLOUD_DISTRIBUTED_EXECUTION: 'true'
|
||||
SELECTED_CLI: << parameters.cli >>
|
||||
NX_E2E_CI_CACHE_KEY: e2e-circleci-<< parameters.os >>-<< parameters.pm >>
|
||||
steps:
|
||||
- checkout
|
||||
- restore_cache:
|
||||
name: Restore Homebrew packages
|
||||
keys:
|
||||
- nrwl-nx-homebrew-packages
|
||||
- setup:
|
||||
os: << parameters.os >>
|
||||
- run:
|
||||
name: Configure Detox Environment, Install applesimutils
|
||||
command: |
|
||||
HOMEBREW_NO_AUTO_UPDATE=1 brew tap wix/brew >/dev/null
|
||||
HOMEBREW_NO_AUTO_UPDATE=1 brew install applesimutils >/dev/null
|
||||
xcrun simctl shutdown all && xcrun simctl erase all
|
||||
no_output_timeout: 20m
|
||||
- save_cache:
|
||||
name: Save Homebrew Cache
|
||||
key: nrwl-nx-homebrew-packages
|
||||
paths:
|
||||
- /usr/local/Homebrew
|
||||
- ~/Library/Caches/Homebrew
|
||||
- run-pnpm-install:
|
||||
os: macos
|
||||
- rust/install
|
||||
- nx/set-shas:
|
||||
main-branch-name: 'master'
|
||||
name: Run Builds
|
||||
command: npx nx affected --target=build --base=HEAD~1 --parallel --max-parallel=3
|
||||
- run:
|
||||
name: Run E2E Tests for macOS
|
||||
command: |
|
||||
pnpm nx affected -t e2e-macos --parallel=1 --base=$NX_BASE --head=$NX_HEAD
|
||||
name: Run Unit Tests
|
||||
command: npx nx affected --target=test --base=HEAD~1 --parallel --max-parallel=2
|
||||
- run:
|
||||
name: Run Linting
|
||||
command: npx nx affected --target=lint --base=HEAD~1 --parallel --max-parallel=4
|
||||
- run:
|
||||
name: Run E2E Tests
|
||||
command: npx nx affected --target=e2e --base=HEAD~1
|
||||
no_output_timeout: 45m
|
||||
- run:
|
||||
name: Close CI group
|
||||
command: |
|
||||
pnpm nx-cloud stop-all-agents
|
||||
no_output_timeout: 45m
|
||||
|
||||
# -------------------------
|
||||
# WORKFLOWS(JOBS)
|
||||
# -------------------------
|
||||
name: Stop All Running Agents for This CI Run
|
||||
command: npx nx-cloud stop-all-agents
|
||||
workflows:
|
||||
version: 2
|
||||
|
||||
build:
|
||||
jobs:
|
||||
- main-linux
|
||||
- mainmacos:
|
||||
name: main-macos-e2e
|
||||
- agent:
|
||||
name: 'agent1'
|
||||
- agent:
|
||||
name: 'agent2'
|
||||
- agent:
|
||||
name: 'agent3'
|
||||
- agent:
|
||||
name: 'agent4'
|
||||
- agent:
|
||||
name: 'agent5'
|
||||
- agent:
|
||||
name: 'agent6'
|
||||
- trunk-main:
|
||||
filters:
|
||||
branches:
|
||||
only: master
|
||||
- pr-main:
|
||||
filters:
|
||||
branches:
|
||||
ignore: master
|
||||
|
||||
@@ -0,0 +1,85 @@
|
||||
module.exports = {
|
||||
types: [
|
||||
{ value: 'feat', name: 'feat: A new feature' },
|
||||
{ value: 'fix', name: 'fix: A bug fix' },
|
||||
{ value: 'docs', name: 'docs: Documentation only changes' },
|
||||
{
|
||||
value: 'cleanup',
|
||||
name:
|
||||
'cleanup: A code change that neither fixes a bug nor adds a feature',
|
||||
},
|
||||
{
|
||||
value: 'chore',
|
||||
name: "chore: Other changes that don't modify src or test files",
|
||||
},
|
||||
],
|
||||
|
||||
scopes: [
|
||||
{ name: 'angular', description: 'anything Angular specific' },
|
||||
{ name: 'core', description: 'anything Nx core specific' },
|
||||
{ name: 'nxdev', description: 'anything related to docs infrastructure' },
|
||||
{ name: 'nextjs', description: 'anything Next specific' },
|
||||
{ name: 'gatsby', description: 'anything Gatsby specific' },
|
||||
{ name: 'nest', description: 'anything Nest specific' },
|
||||
{ name: 'node', description: 'anything Node specific' },
|
||||
{ name: 'express', description: 'anything Express specific' },
|
||||
{ name: 'nx-plugin', description: 'anything Nx Plugin specific' },
|
||||
{ name: 'react', description: 'anything React specific' },
|
||||
{ name: 'web', description: 'anything Web specific' },
|
||||
{ name: 'linter', description: 'anything Linter specific' },
|
||||
{ name: 'storybook', description: 'anything Storybook specific' },
|
||||
{
|
||||
name: 'testing',
|
||||
description: 'anything testing specific (e.g., jest or cypress)',
|
||||
},
|
||||
{
|
||||
name: 'repo',
|
||||
description: 'anything related to managing the repo itself',
|
||||
},
|
||||
{ name: 'misc', description: 'misc stuff' },
|
||||
{ name: 'devkit', description: 'devkit-related changes' },
|
||||
],
|
||||
|
||||
allowTicketNumber: true,
|
||||
isTicketNumberRequired: false,
|
||||
ticketNumberPrefix: 'TICKET-',
|
||||
ticketNumberRegExp: '\\d{1,5}',
|
||||
|
||||
// it needs to match the value for field type. Eg.: 'fix'
|
||||
/*
|
||||
scopeOverrides: {
|
||||
fix: [
|
||||
{name: 'merge'},
|
||||
{name: 'style'},
|
||||
{name: 'e2eTest'},
|
||||
{name: 'unitTest'}
|
||||
]
|
||||
},
|
||||
*/
|
||||
// override the messages, defaults are as follows
|
||||
messages: {
|
||||
type: "Select the type of change that you're committing:",
|
||||
scope: '\nDenote the SCOPE of this change (optional):',
|
||||
// used if allowCustomScopes is true
|
||||
customScope: 'Denote the SCOPE of this change:',
|
||||
subject:
|
||||
'Write a SHORT, IMPERATIVE (lowercase) description of the change:\n',
|
||||
body:
|
||||
'Provide a LONGER description of the change (optional). Use "|" to break new line:\n',
|
||||
breaking: 'List any BREAKING CHANGES (optional):\n',
|
||||
footer:
|
||||
'List any ISSUES CLOSED by this change (optional). E.g.: #31, #34:\n',
|
||||
confirmCommit: 'Are you sure you want to proceed with the commit above?',
|
||||
},
|
||||
|
||||
allowCustomScopes: false,
|
||||
allowBreakingChanges: ['feat', 'fix'],
|
||||
// skip any questions you want
|
||||
skipQuestions: ['ticketNumber'],
|
||||
|
||||
// limit subject length
|
||||
subjectLimit: 100,
|
||||
// breaklineChar: '|', // It is supported for fields body and footer.
|
||||
// footerPrefix : 'ISSUES CLOSED:'
|
||||
// askForBreakingChangeFirst : true, // default is false
|
||||
};
|
||||
@@ -1,30 +0,0 @@
|
||||
// For format details, see https://aka.ms/devcontainer.json. For config options, see the
|
||||
// README at: https://github.com/devcontainers/templates/tree/main/src/typescript-node
|
||||
{
|
||||
"name": "NxDevContainer",
|
||||
// Or use a Dockerfile or Docker Compose file. More info: https://containers.dev/guide/dockerfile
|
||||
"image": "mcr.microsoft.com/devcontainers/typescript-node:20-bullseye",
|
||||
"features": {
|
||||
"ghcr.io/devcontainers/features/rust:1": {}
|
||||
},
|
||||
// Use 'forwardPorts' to make a list of ports inside the container available locally.
|
||||
// 4211 = nx graph port
|
||||
"forwardPorts": [4211],
|
||||
// Use 'postCreateCommand' to run commands after the container is created.
|
||||
"postCreateCommand": "./.devcontainer/postCreateCommand.sh",
|
||||
// Configure tool-specific properties.
|
||||
"customizations": {
|
||||
"vscode": {
|
||||
"extensions": [
|
||||
"nrwl.angular-console",
|
||||
"firsttris.vscode-jest-runner",
|
||||
"eamodio.gitlens"
|
||||
],
|
||||
"settings": {
|
||||
"debug.javascript.autoAttachFilter": "onlyWithFlag" // workaround for that issue: https://github.com/microsoft/vscode-js-debug/issues/374#issuecomment-622239998
|
||||
}
|
||||
}
|
||||
}
|
||||
// Uncomment to connect as root instead. More info: https://aka.ms/dev-containers-non-root.
|
||||
// "remoteUser": "root"
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
# Update the underlying (Debian) OS, to make sure we have the latest security patches and libraries like 'GLIBC'
|
||||
sudo apt-get update && sudo apt-get -y upgrade
|
||||
|
||||
# Update pnpm
|
||||
#npm install -g pnpm
|
||||
|
||||
# Install dependencies
|
||||
pnpm install --frozen-lockfile
|
||||
|
||||
@@ -1,18 +0,0 @@
|
||||
# EditorConfig is awesome: https://EditorConfig.org
|
||||
|
||||
# top-most EditorConfig file
|
||||
root = true
|
||||
|
||||
# Unix-style newlines with a newline ending every file
|
||||
[*]
|
||||
end_of_line = lf
|
||||
insert_final_newline = true
|
||||
|
||||
# 4 space indentation
|
||||
[*.{js,ts,jsx,tsx}]
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
|
||||
[package.json]
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
@@ -1 +0,0 @@
|
||||
node_modules
|
||||
+7
-53
@@ -1,63 +1,17 @@
|
||||
{
|
||||
"root": true,
|
||||
"parser": "@typescript-eslint/parser",
|
||||
"parserOptions": {
|
||||
"project": "./tsconfig.*?.json"
|
||||
},
|
||||
"env": {
|
||||
"node": true
|
||||
},
|
||||
"ignorePatterns": ["**/*.ts"],
|
||||
"plugins": ["@typescript-eslint", "@nx"],
|
||||
"extends": ["plugin:storybook/recommended"],
|
||||
"plugins": ["@typescript-eslint"],
|
||||
"extends": [],
|
||||
"rules": {
|
||||
"@typescript-eslint/explicit-module-boundary-types": "off",
|
||||
"no-restricted-imports": ["error", "create-nx-workspace"],
|
||||
"@typescript-eslint/no-restricted-imports": [
|
||||
"error",
|
||||
{
|
||||
"patterns": [
|
||||
{
|
||||
"group": ["nx/src/plugins/js*"],
|
||||
"message": "Imports from 'nx/src/plugins/js' are not allowed. Use '@nx/js' instead"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"storybook/no-uninstalled-addons": [
|
||||
"error",
|
||||
{
|
||||
"ignore": ["@nx/react/plugins/storybook"]
|
||||
}
|
||||
]
|
||||
"@typescript-eslint/explicit-module-boundary-types": "off"
|
||||
},
|
||||
"overrides": [
|
||||
{
|
||||
"files": ["*.json"],
|
||||
"parser": "jsonc-eslint-parser",
|
||||
"rules": {}
|
||||
},
|
||||
{
|
||||
"files": ["**/executors/**/schema.json", "**/generators/**/schema.json"],
|
||||
"rules": {
|
||||
"@nx/workspace/valid-schema-description": "error"
|
||||
}
|
||||
},
|
||||
{
|
||||
"files": ["*.ts", "*.tsx", "*.js", "*.jsx"],
|
||||
"rules": {
|
||||
"@nx/enforce-module-boundaries": [
|
||||
"error",
|
||||
{
|
||||
"enforceBuildableLibDependency": true,
|
||||
"checkDynamicDependenciesExceptions": [".*"],
|
||||
"allow": [],
|
||||
"depConstraints": [
|
||||
{
|
||||
"sourceTag": "*",
|
||||
"onlyDependOnLibsWithTags": ["*"]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
"overrides": []
|
||||
}
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
---
|
||||
name: "🐞 Bug Report"
|
||||
about: Report a bug
|
||||
labels: "type: bug"
|
||||
|
||||
---
|
||||
|
||||
<!-- Please do your best to fill out all of the sections below! -->
|
||||
|
||||
## Current Behavior
|
||||
<!-- What is the behavior that currently you experience? -->
|
||||
|
||||
## Expected Behavior
|
||||
<!-- What is the behavior that you expect to happen? -->
|
||||
<!-- Is this a regression? .i.e Did this used to be the behavior at one point? -->
|
||||
|
||||
## Steps to Reproduce
|
||||
<!-- Help us help you by making it easy for us to reproduce your issue! -->
|
||||
|
||||
<!-- Can you reproduce this on https://github.com/nrwl/nx-examples? -->
|
||||
<!-- If so, open a PR with your changes and link it below. -->
|
||||
<!-- If not, please provide a minimal Github repo -->
|
||||
<!-- At the very least, provide as much detail as possible to help us reproduce the issue -->
|
||||
|
||||
<!-- Remove this line -->
|
||||
This issue may not be prioritized if details are not provided to help us reproduce the issue.
|
||||
|
||||
### Failure Logs
|
||||
<!-- Please include any relevant log snippets or files here. -->
|
||||
|
||||
### Environment
|
||||
<!-- It's important for us to know the context in which you experience this behavior! -->
|
||||
<!-- Please paste the result of `nx report` below! -->
|
||||
@@ -1,82 +0,0 @@
|
||||
name: 🐞 Bug Report
|
||||
description: This form is to report unexpected behavior in Nx.
|
||||
labels: ["type: bug"]
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
Thank you for taking your precious time to file an issue! 🙏 We are sorry for the inconvenience this issue has caused you and want to resolve it as soon as possible.
|
||||
|
||||
Help us help you! We know that your time is precious and hate to ask for any more of it, but the first step in fixing this issue is to understand the issue. Taking some extra time to ensure that we are able to reproduce the issue will help us significantly in resolving the issue.
|
||||
- type: textarea
|
||||
id: current-behavior
|
||||
attributes:
|
||||
label: Current Behavior
|
||||
description: What is the behavior that currently you experience?
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: expected-behavior
|
||||
attributes:
|
||||
label: Expected Behavior
|
||||
description: What is the behavior that you expect to happen?
|
||||
validations:
|
||||
required: true
|
||||
- type: input
|
||||
id: repo
|
||||
attributes:
|
||||
label: GitHub Repo
|
||||
description: |
|
||||
This is extremely important! If this issue is reproduce-able on https://github.com/nrwl/nx-examples, you may use that as the repo.
|
||||
If not, please do take a few minutes of your time to create a repo to help us reproduce the issue.
|
||||
This is the best way to help us reproduce the issue and fix it as soon as possible.
|
||||
- type: textarea
|
||||
id: reproduction
|
||||
attributes:
|
||||
label: Steps to Reproduce
|
||||
description: Please provide some instructions to reproduce the issue in the repo provided above. Be as detailed as possible.
|
||||
value: |
|
||||
1.
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: nx-report
|
||||
attributes:
|
||||
label: Nx Report
|
||||
description: Please paste the contents shown by `nx report`. This will be automatically formatted into code, so no need for backticks.
|
||||
render: shell
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: logs
|
||||
attributes:
|
||||
label: Failure Logs
|
||||
description: Please include any relevant log snippets or files here. This will be automatically formatted into code, so no need for backticks.
|
||||
render: shell
|
||||
- type: input
|
||||
id: pm
|
||||
attributes:
|
||||
label: Package Manager Version
|
||||
description: |
|
||||
If `nx report` doesn't work, please provide the name and the version of your package manager.
|
||||
You can get version information by running `yarn --version`, `pnpm --version` or `npm --version`, depending on the package manager used.
|
||||
- type: checkboxes
|
||||
id: os
|
||||
attributes:
|
||||
label: Operating System
|
||||
description: What Operating System are you using?
|
||||
options:
|
||||
- label: macOS
|
||||
- label: Linux
|
||||
- label: Windows
|
||||
- label: Other (Please specify)
|
||||
- type: textarea
|
||||
id: additional
|
||||
attributes:
|
||||
label: Additional Information
|
||||
description: Is there any additional information that you can provide?
|
||||
- type: markdown
|
||||
id: disclaimer
|
||||
attributes:
|
||||
value: |
|
||||
> If we are not able to reproduce the issue, we will likely prioritize fixing other issues we can reproduce. Please do your best to fill out all of the sections above.
|
||||
@@ -7,9 +7,6 @@ labels: "type: feature"
|
||||
<!-- Please do your best to fill out all of the sections below! -->
|
||||
<!-- Use this issue type for concrete suggestions, otherwise, open a discussion type issue instead. -->
|
||||
|
||||
- [ ] I'd be willing to implement this feature ([contributing guide](https://github.com/nrwl/nx/blob/master/CONTRIBUTING.md))
|
||||
|
||||
|
||||
## Description
|
||||
<!-- What is the behavior that you would like to see introduced? -->
|
||||
|
||||
|
||||
@@ -1,26 +0,0 @@
|
||||
---
|
||||
name: "📖 Documentation issue"
|
||||
about: Help improve our docs.
|
||||
labels: "type: docs"
|
||||
---
|
||||
### Documentation issue
|
||||
|
||||
<!-- (Update "[ ]" to "[x]" to check a box) -->
|
||||
|
||||
- [ ] Reporting a typo
|
||||
- [ ] Reporting a documentation bug
|
||||
- [ ] Documentation improvement
|
||||
- [ ] Documentation feedback
|
||||
|
||||
<!--
|
||||
If your issue is not regarding the documentation, please choose an issue type:
|
||||
https://github.com/nrwl/nx/issues/new/choose
|
||||
-->
|
||||
|
||||
### Is there a specific documentation page you are reporting?
|
||||
|
||||
Enter the URL or documentation section here.
|
||||
|
||||
### Additional context or description
|
||||
|
||||
Provide any additional details here as needed.
|
||||
@@ -7,8 +7,8 @@ contact_links:
|
||||
about: "Want to start a thread to discuss an idea? Use the discussions feature provided by GitHub."
|
||||
url: https://github.com/nrwl/nx/discussions
|
||||
- name: Have a question?
|
||||
url: https://go.nx.dev/community
|
||||
about: "The Nx Official Discord Server is a great place for questions to be asked and answered. Please use the #forum if you need help with your workspace!"
|
||||
url: http://go.nrwl.io/join-slack
|
||||
about: "The Community Slack is a great place for questions to be asked and answered. Please use the #support channel if you need help with your workspace!"
|
||||
- name: Are you looking for integration with a new tool?
|
||||
url: https://nx.dev/community
|
||||
url: https://nx.dev/nx-community
|
||||
about: "There are a lot of awesome Plugins for Nx provided by the community! Check here to see if there is a community plugin to integrate your tool."
|
||||
|
||||
@@ -1,31 +1,9 @@
|
||||
<!--
|
||||
_[Please make sure you have read the submission guidelines before posting an PR](https://github.com/nrwl/nx/blob/master/CONTRIBUTING.md#submit-pr)_
|
||||
|
||||
# Community Plugin Submission
|
||||
|
||||
Thanks for submitting your Nx Plugin to our community plugins list. Make sure to follow these steps to ensure that your PR is approved in a timely manner.
|
||||
|
||||
## Plugin Requirements
|
||||
|
||||
Before you submit your plugin to be listed in our registry, it needs to meet the following requirements:
|
||||
- Run some kind of automated e2e tests in your repository
|
||||
- Include `@nx/devkit` as a `dependency` in the plugin's `package.json`
|
||||
- List a `repository.url` in the plugin's `package.json`
|
||||
|
||||
i.e.
|
||||
|
||||
```
|
||||
{
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/nrwl/nx.git",
|
||||
"directory": "packages/web"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Note: We reserve the right to remove unmaintained plugins from the registry. If the plugins become maintained again, they can be resubmitted to the registry.
|
||||
|
||||
## Steps to Submit Your Plugin
|
||||
- Use the following commit message template: `chore(core): nx plugin submission [PLUGIN_NAME]`
|
||||
- Update the `community/approved-plugins.json` file with a new entry for your plugin that includes `name`, `url`, `description`:
|
||||
@@ -42,15 +20,4 @@ Example:
|
||||
}]
|
||||
```
|
||||
|
||||
Once merged, your plugin will be available when running the `nx list` command, and will also be available in the Plugin Registry on [nx.dev](https://nx.dev/plugin-registry)
|
||||
-->
|
||||
|
||||
# Community Plugin Submission
|
||||
|
||||
## {replace with plugin's name}
|
||||
|
||||
<!--
|
||||
Describe what your plugin is and what is its goal or issues it addresses. If you don't provide a description, we will not merge your PR.
|
||||
Is it focused on a technology, tooling or behaviour? Does the plugin provide generators, executors or graph support?
|
||||
Do you know who is already using the plugin? Mention who is the author of the plugin.
|
||||
-->
|
||||
Once merged, your will plugin will be available when running the `nx list` command, and will also be available in the Plugin browser on [nx.dev](https://nx.dev)
|
||||
|
||||
@@ -1,21 +0,0 @@
|
||||
name: Unmergeable Labels Check
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
types: [synchronize, opened, reopened, labeled, unlabeled]
|
||||
|
||||
jobs:
|
||||
do-not-merge:
|
||||
if: ${{ github.repository_owner == 'nrwl' }}
|
||||
name: Prevent Merging
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Check for label
|
||||
run: |
|
||||
echo "${{ toJSON(github.event.*.labels.*.name) }}"
|
||||
node -e 'const forbidden = ["target: next major version", "pr status: needs tests", "pr status: in-progress", "blocked: needs rebase", "pr status: do not merge"];
|
||||
const match = ${{ toJSON(github.event.*.labels.*.name) }}.find(l => forbidden.includes(l.toLowerCase()));
|
||||
if (match) {
|
||||
console.log("Cannot merge PRs that are labeled with " + match);
|
||||
process.exit(1)
|
||||
}'
|
||||
@@ -2,666 +2,58 @@ name: E2E matrix
|
||||
|
||||
on:
|
||||
schedule:
|
||||
- cron: "0 5 * * *"
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
debug_enabled:
|
||||
type: boolean
|
||||
description: 'Run the build with tmate debugging enabled (https://github.com/marketplace/actions/debugging-with-tmate)'
|
||||
required: false
|
||||
default: false
|
||||
- cron: "0 0 * * *"
|
||||
|
||||
env:
|
||||
CYPRESS_CACHE_FOLDER: ${{ github.workspace }}/.cypress
|
||||
|
||||
permissions: {}
|
||||
jobs:
|
||||
preinstall:
|
||||
runs-on: ${{ matrix.os }}
|
||||
strategy:
|
||||
matrix:
|
||||
os:
|
||||
- ubuntu-latest
|
||||
- macos-latest
|
||||
node_version:
|
||||
- 20
|
||||
- 18
|
||||
- 16
|
||||
exclude:
|
||||
# run just node v18 on macos
|
||||
- os: macos-latest
|
||||
node_version: 20
|
||||
- os: macos-latest
|
||||
node_version: 16
|
||||
|
||||
name: Cache install (${{ matrix.os }}, node v${{ matrix.node_version }})
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Install PNPM
|
||||
run: |
|
||||
npm install -g @pnpm/exe@8.7.4
|
||||
|
||||
- name: Set node
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: ${{ matrix.node_version }}
|
||||
cache: 'pnpm'
|
||||
|
||||
- name: Cache node_modules
|
||||
id: cache-modules
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
lookup-only: true
|
||||
path: '**/node_modules'
|
||||
key: ${{ runner.os }}-modules-${{ matrix.node_version }}-${{ github.run_id }}
|
||||
|
||||
- name: Install packages
|
||||
if: steps.cache-modules.outputs.cache-hit != 'true'
|
||||
run: pnpm install --frozen-lockfile
|
||||
|
||||
- name: Homebrew cache directory path
|
||||
if: ${{ matrix.os == 'macos-latest' }}
|
||||
id: homebrew-cache-dir-path
|
||||
run: echo "dir=$(brew --cache)" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Cache Homebrew
|
||||
if: ${{ matrix.os == 'macos-latest' }}
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
lookup-only: true
|
||||
path: ${{ steps.homebrew-cache-dir-path.outputs.dir }}
|
||||
key: brew-${{ matrix.node_version }}
|
||||
restore-keys: |
|
||||
brew-
|
||||
|
||||
- name: Cache Cypress
|
||||
id: cache-cypress
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
lookup-only: true
|
||||
path: '${{ github.workspace }}/.cypress'
|
||||
key: ${{ runner.os }}-cypress
|
||||
|
||||
- name: Install Cypress
|
||||
if: steps.cache-cypress.outputs.cache-hit != 'true'
|
||||
run: npx cypress install
|
||||
|
||||
e2e:
|
||||
needs: preinstall
|
||||
permissions:
|
||||
contents: read
|
||||
runs-on: ${{ matrix.os }}
|
||||
timeout-minutes: 90
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
os:
|
||||
- ubuntu-latest
|
||||
- macos-latest
|
||||
node_version:
|
||||
- 20
|
||||
- 18
|
||||
- 16
|
||||
# - 12.x
|
||||
- 14.x
|
||||
- 15.x
|
||||
package_manager:
|
||||
- npm
|
||||
- yarn
|
||||
- pnpm
|
||||
project:
|
||||
- e2e-angular-core
|
||||
- e2e-angular-extensions
|
||||
- e2e-cypress
|
||||
- e2e-detox
|
||||
- e2e-esbuild
|
||||
- e2e-expo
|
||||
- e2e-jest
|
||||
- e2e-js
|
||||
- e2e-lerna-smoke-tests
|
||||
- e2e-eslint
|
||||
packages:
|
||||
- e2e-workspace
|
||||
- e2e-cli,e2e-nx-plugin,dep-graph-dep-graph-e2e
|
||||
- e2e-cypress,e2e-jest
|
||||
- e2e-react
|
||||
- e2e-next
|
||||
- e2e-node
|
||||
- e2e-nx-init
|
||||
- e2e-nx-misc
|
||||
- e2e-nx-plugin
|
||||
- e2e-nx-run
|
||||
- e2e-react-core
|
||||
- e2e-react-extensions
|
||||
- e2e-react-native
|
||||
- e2e-web
|
||||
- e2e-rollup
|
||||
- e2e-storybook
|
||||
- e2e-storybook-angular
|
||||
- e2e-vite
|
||||
- e2e-webpack
|
||||
- e2e-workspace-create
|
||||
- e2e-workspace-create-npm
|
||||
include:
|
||||
# os short names
|
||||
- os: ubuntu-latest
|
||||
os_name: 'Linux'
|
||||
- os: macos-latest
|
||||
os_name: 'MacOS'
|
||||
# test timeouts
|
||||
- os: ubuntu-latest
|
||||
os_timeout: 60
|
||||
- os: macos-latest
|
||||
os_timeout: 90
|
||||
# codeowner groups
|
||||
- project: e2e-angular-core
|
||||
codeowners: 'S04SS457V38'
|
||||
- project: e2e-angular-extensions
|
||||
codeowners: 'S04SS457V38'
|
||||
- project: e2e-cypress
|
||||
codeowners: 'S04T16BTJJY'
|
||||
- project: e2e-detox
|
||||
codeowners: 'S04TNCNJG5N'
|
||||
- project: e2e-esbuild
|
||||
codeowners: 'S04SJ6HHP0X'
|
||||
- project: e2e-expo
|
||||
codeowners: 'S04TNCNJG5N'
|
||||
- project: e2e-jest
|
||||
codeowners: 'S04T16BTJJY'
|
||||
- project: e2e-js
|
||||
codeowners: 'S04SJ6HHP0X'
|
||||
- project: e2e-lerna-smoke-tests
|
||||
codeowners: 'S04TNCVEETS'
|
||||
- project: e2e-eslint
|
||||
codeowners: 'S04SYJGKSCT'
|
||||
- project: e2e-next
|
||||
codeowners: 'S04TNCNJG5N'
|
||||
- project: e2e-node
|
||||
codeowners: 'S04SJ6HHP0X'
|
||||
- project: e2e-nx-init
|
||||
codeowners: 'S04SYHYKGNP'
|
||||
- project: e2e-nx-misc
|
||||
codeowners: 'S04SYHYKGNP'
|
||||
- project: e2e-nx-plugin
|
||||
codeowners: 'S04SYHYKGNP'
|
||||
- project: e2e-nx-run
|
||||
codeowners: 'S04SYHYKGNP'
|
||||
- project: e2e-react-core
|
||||
codeowners: 'S04TNCNJG5N'
|
||||
- project: e2e-react-extensions
|
||||
codeowners: 'S04TNCNJG5N'
|
||||
- project: e2e-react-native
|
||||
codeowners: 'S04TNCNJG5N'
|
||||
- project: e2e-web
|
||||
codeowners: 'S04SJ6PL98X'
|
||||
- project: e2e-rollup
|
||||
codeowners: 'S04SJ6PL98X'
|
||||
- project: e2e-storybook
|
||||
codeowners: 'S04SVQ8H0G5'
|
||||
- project: e2e-storybook-angular
|
||||
codeowners: 'S04SVQ8H0G5'
|
||||
- project: e2e-vite
|
||||
codeowners: 'S04SJ6PL98X'
|
||||
- project: e2e-webpack
|
||||
codeowners: 'S04SJ6PL98X'
|
||||
- project: e2e-workspace-create
|
||||
codeowners: 'S04SYHYKGNP'
|
||||
- project: e2e-workspace-create-npm
|
||||
codeowners: 'S04SYHYKGNP'
|
||||
exclude:
|
||||
# exclude react-native tests from ubuntu
|
||||
- os: ubuntu-latest
|
||||
project: e2e-react-native
|
||||
- os: ubuntu-latest
|
||||
project: e2e-detox
|
||||
- os: ubuntu-latest
|
||||
project: e2e-expo
|
||||
# exclude non-CNW/Lerna tests from non-LTS node versions
|
||||
- node_version: 16
|
||||
project: e2e-angular-core
|
||||
- node_version: 16
|
||||
project: e2e-angular-extensions
|
||||
- node_version: 16
|
||||
project: e2e-cypress
|
||||
- node_version: 16
|
||||
project: e2e-detox
|
||||
- node_version: 16
|
||||
project: e2e-esbuild
|
||||
- node_version: 16
|
||||
project: e2e-expo
|
||||
- node_version: 16
|
||||
project: e2e-jest
|
||||
- node_version: 16
|
||||
project: e2e-js
|
||||
- node_version: 16
|
||||
project: e2e-eslint
|
||||
- node_version: 16
|
||||
project: e2e-next
|
||||
- node_version: 16
|
||||
project: e2e-node
|
||||
- node_version: 16
|
||||
project: e2e-nx-init
|
||||
- node_version: 16
|
||||
project: e2e-nx-misc
|
||||
- node_version: 16
|
||||
project: e2e-nx-plugin
|
||||
- node_version: 16
|
||||
project: e2e-lerna-smoke-tests
|
||||
- node_version: 16
|
||||
project: e2e-react-core
|
||||
- node_version: 16
|
||||
project: e2e-react-extensions
|
||||
- node_version: 16
|
||||
project: e2e-react-native
|
||||
- node_version: 16
|
||||
project: e2e-web
|
||||
- node_version: 16
|
||||
project: e2e-rollup
|
||||
- node_version: 16
|
||||
project: e2e-storybook
|
||||
- node_version: 16
|
||||
project: e2e-storybook-angular
|
||||
- node_version: 16
|
||||
project: e2e-vite
|
||||
- node_version: 16
|
||||
project: e2e-webpack
|
||||
- node_version: 20
|
||||
project: e2e-angular-core
|
||||
- node_version: 20
|
||||
project: e2e-angular-extensions
|
||||
- node_version: 20
|
||||
project: e2e-cypress
|
||||
- node_version: 20
|
||||
project: e2e-detox
|
||||
- node_version: 20
|
||||
project: e2e-esbuild
|
||||
- node_version: 20
|
||||
project: e2e-expo
|
||||
- node_version: 20
|
||||
project: e2e-jest
|
||||
- node_version: 20
|
||||
project: e2e-js
|
||||
- node_version: 20
|
||||
project: e2e-eslint
|
||||
- node_version: 20
|
||||
project: e2e-next
|
||||
- node_version: 20
|
||||
project: e2e-node
|
||||
- node_version: 20
|
||||
project: e2e-nx-init
|
||||
- node_version: 20
|
||||
project: e2e-nx-misc
|
||||
- node_version: 20
|
||||
project: e2e-nx-plugin
|
||||
- node_version: 20
|
||||
project: e2e-lerna-smoke-tests
|
||||
- node_version: 20
|
||||
project: e2e-react-core
|
||||
- node_version: 20
|
||||
project: e2e-react-extensions
|
||||
- node_version: 20
|
||||
project: e2e-react-native
|
||||
- node_version: 20
|
||||
project: e2e-web
|
||||
- node_version: 20
|
||||
project: e2e-rollup
|
||||
- node_version: 20
|
||||
project: e2e-storybook
|
||||
- node_version: 20
|
||||
project: e2e-storybook-angular
|
||||
- node_version: 20
|
||||
project: e2e-vite
|
||||
- node_version: 20
|
||||
project: e2e-webpack
|
||||
# run just npm v18 on macos
|
||||
- os: macos-latest
|
||||
package_manager: yarn
|
||||
- os: macos-latest
|
||||
package_manager: pnpm
|
||||
- os: macos-latest
|
||||
node_version: 16
|
||||
- os: macos-latest
|
||||
node_version: 20
|
||||
- e2e-web,e2e-linter,e2e-storybook
|
||||
- e2e-angular
|
||||
fail-fast: false
|
||||
|
||||
name: ${{ matrix.os_name }}/${{ matrix.package_manager }}/${{ matrix.node_version }} ${{ join(matrix.project) }}
|
||||
name: Node v${{ matrix.node_version }} (${{ matrix.package_manager }}) - ${{ matrix.packages }}
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v2
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Prepare dir for output
|
||||
run: mkdir -p outputs
|
||||
- name: Install dependencies
|
||||
uses: actions/setup-node@v2
|
||||
with:
|
||||
node-version: ${{ matrix.node_version }}
|
||||
- run: yarn install
|
||||
|
||||
- name: Install PNPM
|
||||
run: |
|
||||
npm install -g @pnpm/exe@8.7.4
|
||||
- name: Install PNPM
|
||||
if: ${{ matrix.package_manager == 'pnpm' }}
|
||||
uses: pnpm/action-setup@v1.2.1
|
||||
with:
|
||||
version: 5.18.9
|
||||
|
||||
- name: Use Node.js ${{ matrix.node_version }}
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: ${{ matrix.node_version }}
|
||||
cache: 'pnpm'
|
||||
|
||||
- name: Cache node_modules
|
||||
id: cache-modules
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: '**/node_modules'
|
||||
key: ${{ runner.os }}-modules-${{ matrix.node_version }}-${{ github.run_id }}
|
||||
|
||||
- name: Install packages
|
||||
run: pnpm install --frozen-lockfile
|
||||
|
||||
- name: Cleanup
|
||||
if: ${{ matrix.os == 'ubuntu-latest' }}
|
||||
run: |
|
||||
# Workaround to provide additional free space for testing.
|
||||
# https://github.com/actions/virtual-environments/issues/2840
|
||||
sudo rm -rf /usr/share/dotnet
|
||||
sudo rm -rf /opt/ghc
|
||||
sudo rm -rf "/usr/local/share/boost"
|
||||
sudo rm -rf "$AGENT_TOOLSDIRECTORY"
|
||||
sudo apt-get install lsof
|
||||
echo fs.inotify.max_user_watches=524288 | sudo tee -a /etc/sysctl.conf && sudo sysctl -p
|
||||
|
||||
- name: Homebrew cache directory path
|
||||
if: ${{ matrix.os == 'macos-latest' }}
|
||||
id: homebrew-cache-dir-path
|
||||
run: echo "dir=$(brew --cache)" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Cache Homebrew
|
||||
if: ${{ matrix.os == 'macos-latest' }}
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: ${{ steps.homebrew-cache-dir-path.outputs.dir }}
|
||||
key: brew-${{ matrix.node_version }}
|
||||
restore-keys: |
|
||||
brew-
|
||||
|
||||
- name: Cache Cypress
|
||||
id: cache-cypress
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: '${{ github.workspace }}/.cypress'
|
||||
key: ${{ runner.os }}-cypress
|
||||
|
||||
- name: Install Cypress
|
||||
if: steps.cache-cypress.outputs.cache-hit != 'true'
|
||||
run: npx cypress install
|
||||
|
||||
- name: Install applesimutils, reset ios simulators
|
||||
if: ${{ matrix.os == 'macos-latest' }}
|
||||
run: |
|
||||
HOMEBREW_NO_AUTO_UPDATE=1 brew tap wix/brew >/dev/null
|
||||
HOMEBREW_NO_AUTO_UPDATE=1 brew install applesimutils >/dev/null
|
||||
xcrun simctl shutdown all && xcrun simctl erase all
|
||||
|
||||
- name: Configure git metadata (needed for lerna smoke tests)
|
||||
run: |
|
||||
git config --global user.email test@test.com
|
||||
git config --global user.name "Test Test"
|
||||
|
||||
- name: Set starting timestamp
|
||||
id: before-e2e
|
||||
run: |
|
||||
echo "timestamp=$(date +%s)" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Run e2e tests
|
||||
id: e2e-run
|
||||
run: pnpm nx run-many -t e2e,e2e-macos -p ${{ matrix.project }}
|
||||
timeout-minutes: ${{ matrix.os_timeout }}
|
||||
env:
|
||||
GIT_AUTHOR_EMAIL: test@test.com
|
||||
GIT_AUTHOR_NAME: Test
|
||||
GIT_COMMITTER_EMAIL: test@test.com
|
||||
GIT_COMMITTER_NAME: Test
|
||||
NX_E2E_CI_CACHE_KEY: e2e-gha-${{ matrix.os }}-${{ matrix.node_version }}-${{ matrix.package_manager }}
|
||||
NODE_OPTIONS: --max_old_space_size=8192
|
||||
SELECTED_PM: ${{ matrix.package_manager }}
|
||||
npm_config_registry: http://localhost:4872
|
||||
YARN_REGISTRY: http://localhost:4872
|
||||
NX_CACHE_DIRECTORY: 'tmp'
|
||||
NX_E2E_SKIP_CLEANUP: 'true'
|
||||
NX_E2E_RUN_E2E: 'true'
|
||||
NX_E2E_VERBOSE_LOGGING: 'true'
|
||||
NX_PERF_LOGGING: 'false'
|
||||
NX_DAEMON: 'true'
|
||||
|
||||
- name: Save matrix config in file
|
||||
if: ${{ always() }}
|
||||
id: save-matrix
|
||||
shell: bash
|
||||
run: |
|
||||
before=${{ steps.before-e2e.outputs.timestamp }}
|
||||
now=$(date +%s)
|
||||
delta=$(($now - $before))
|
||||
matrix=$((
|
||||
echo '${{ toJSON(matrix) }}'
|
||||
) | jq --argjson delta $delta -c '. + { "status": "${{ steps.e2e-run.outcome}}", "duration": $delta }')
|
||||
echo "$matrix" > matrix
|
||||
path=outputs/${{ matrix.os_name}}-${{ matrix.node_version}}-${{ matrix.package_manager}}-${{ matrix.project }}
|
||||
echo "path=$path" >> $GITHUB_OUTPUT
|
||||
echo "$matrix" > $path
|
||||
|
||||
- name: Upload matrix config
|
||||
uses: actions/upload-artifact@v3
|
||||
if: ${{ always() }}
|
||||
with:
|
||||
name: outputs
|
||||
path: ${{ steps.save-matrix.outputs.path }}
|
||||
|
||||
- name: Setup tmate session
|
||||
if: ${{ github.event_name == 'workflow_dispatch' && inputs.debug_enabled && failure() }}
|
||||
uses: mxschmitt/action-tmate@v3.8
|
||||
timeout-minutes: 15
|
||||
|
||||
process-result:
|
||||
if: ${{ always() }}
|
||||
runs-on: ubuntu-latest
|
||||
needs: e2e
|
||||
outputs:
|
||||
message: ${{ steps.process-json.outputs.SLACK_MESSAGE }}
|
||||
proj-duration: ${{ steps.process-json.outputs.SLACK_PROJ_DURATION }}
|
||||
pm-duration: ${{ steps.process-json.outputs.SLACK_PM_DURATION }}
|
||||
codeowners: ${{ steps.process-json.outputs.CODEOWNERS }}
|
||||
steps:
|
||||
- name: Load outputs
|
||||
uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: outputs
|
||||
path: outputs
|
||||
|
||||
- name: Join and stringify matrix configs
|
||||
id: combine-json
|
||||
run: |
|
||||
combined=$((jq -s . outputs/*) | jq tostring)
|
||||
echo "combined=$combined" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Make slack outputs
|
||||
id: process-json
|
||||
uses: actions/github-script@v6
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ github.token }}
|
||||
with:
|
||||
script: |
|
||||
const combined = JSON.parse(${{ steps.combine-json.outputs.combined }});
|
||||
const failedProjects = combined.filter(c => c.status === 'failure').sort((a, b) => a.project.localeCompare(b.project));
|
||||
|
||||
// codeowners
|
||||
const codeowners = new Set();
|
||||
failedProjects.forEach(c => {
|
||||
codeowners.add(c.codeowners);
|
||||
});
|
||||
core.setOutput('CODEOWNERS', Array.from(codeowners).join(','));
|
||||
|
||||
function trimSpace(res) {
|
||||
return res.split('\n').map((l) => l.trim()).join('\n');
|
||||
}
|
||||
|
||||
// failed message
|
||||
let lastProject;
|
||||
let result = `
|
||||
\`\`\`
|
||||
| Failed project | PM | OS | Node |
|
||||
|--------------------------------|------|-------|------|`;
|
||||
failedProjects.forEach(matrix => {
|
||||
const project = matrix.project !== lastProject ? matrix.project : '...';
|
||||
result += `\n| ${project.padEnd(30)} | ${matrix.package_manager.padEnd(4)} | ${matrix.os_name} | v${matrix.node_version.toString().padEnd(3)} |`
|
||||
lastProject = matrix.project;
|
||||
});
|
||||
result += `\`\`\``;
|
||||
core.setOutput('SLACK_MESSAGE', trimSpace(result));
|
||||
|
||||
function humanizeDuration(num) {
|
||||
let res = '';
|
||||
const hours = Math.floor(num / 3600);
|
||||
if (hours) {
|
||||
res += `${hours}h `;
|
||||
}
|
||||
const mins = Math.floor((num % 3600) / 60);
|
||||
if (mins) {
|
||||
res += `${mins}m `;
|
||||
}
|
||||
const sec = num % 60;
|
||||
if (sec) {
|
||||
res += `${sec}s`
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
// duration message
|
||||
const timeReport = {};
|
||||
const pmReport = {
|
||||
npm: 0,
|
||||
yarn: 0,
|
||||
pnpm: 0
|
||||
};
|
||||
const macosProjects = ['e2e-detox', 'e2e-expo', 'e2e-react-native'];
|
||||
combined.forEach((matrix) => {
|
||||
if (matrix.os_name === 'Linux' && matrix.node_version === 18) {
|
||||
pmReport[matrix.package_manager] += matrix.duration;
|
||||
}
|
||||
if (matrix.os_name === 'Linux' || macosProjects.includes(matrix.project)) {
|
||||
if (timeReport[matrix.project]) {
|
||||
if (matrix.duration > timeReport[matrix.project].max) {
|
||||
timeReport[matrix.project].max = matrix.duration;
|
||||
timeReport[
|
||||
matrix.project
|
||||
].maxEnv = `${matrix.os_name}, ${matrix.package_manager}`;
|
||||
}
|
||||
if (matrix.duration < timeReport[matrix.project].min) {
|
||||
timeReport[matrix.project].min = matrix.duration;
|
||||
timeReport[
|
||||
matrix.project
|
||||
].minEnv = `${matrix.os_name}, ${matrix.package_manager}`;
|
||||
}
|
||||
} else {
|
||||
timeReport[matrix.project] = {
|
||||
min: matrix.duration,
|
||||
max: matrix.duration,
|
||||
minEnv: `${matrix.os_name}, ${matrix.package_manager}`,
|
||||
maxEnv: `${matrix.os_name}, ${matrix.package_manager}`,
|
||||
};
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// project time report
|
||||
let resultPkg = `
|
||||
\`\`\`
|
||||
| Project | Time |
|
||||
|--------------------------------|---------------------------|`;
|
||||
function mapProjectTime(proj, section) {
|
||||
let res = '';
|
||||
res += `${humanizeDuration(timeReport[proj][section])}`;
|
||||
res += ` (${timeReport[proj][section + 'Env']})`
|
||||
return res;
|
||||
}
|
||||
function durationIcon(proj, section) {
|
||||
if (timeReport[proj][section] < 12 * 60) {
|
||||
return `${section} ✅`;
|
||||
}
|
||||
if (timeReport[proj][section] < 15 * 60) {
|
||||
return `${section} ❗`;
|
||||
}
|
||||
return `${section} ❌`;
|
||||
}
|
||||
Object.keys(timeReport).forEach(proj => {
|
||||
resultPkg += `\n| ${proj.padEnd(30)} | |`;
|
||||
resultPkg += `\n| ${durationIcon(proj, 'min').padStart(29)} | ${mapProjectTime(proj, 'min').padEnd(25)} |`;
|
||||
resultPkg += `\n| ${durationIcon(proj, 'max').padStart(29)} | ${mapProjectTime(proj, 'max').padEnd(25)} |`;
|
||||
});
|
||||
resultPkg += `\`\`\``;
|
||||
core.setOutput('SLACK_PROJ_DURATION', trimSpace(resultPkg));
|
||||
|
||||
// Print project duration report inline to allow reviewing on manual runs (when no slack message will be sent)
|
||||
console.log(trimSpace(resultPkg));
|
||||
|
||||
let resultPm = `
|
||||
\`\`\`
|
||||
| PM | Total time |
|
||||
|------|-------------|`;
|
||||
Object.keys(pmReport).forEach(pm => {
|
||||
resultPm += `\n| ${pm.padEnd(4)} | ${humanizeDuration(pmReport[pm]).padEnd(11)} |`
|
||||
});
|
||||
resultPm += `\`\`\``;
|
||||
core.setOutput('SLACK_PM_DURATION', trimSpace(resultPm));
|
||||
|
||||
// Print package manager duration report inline to allow reviewing on manual runs (when no slack message will be sent)
|
||||
console.log(trimSpace(resultPm));
|
||||
|
||||
report-failure:
|
||||
if: ${{ failure() && github.repository_owner == 'nrwl' && github.event_name != 'workflow_dispatch' }}
|
||||
needs: process-result
|
||||
runs-on: ubuntu-latest
|
||||
name: Report failure
|
||||
steps:
|
||||
- name: Send notification
|
||||
uses: ravsamhq/notify-slack-action@v2
|
||||
with:
|
||||
status: 'failure'
|
||||
message_format: '{emoji} Workflow has {status_message} ${{ needs.process-result.outputs.message }}'
|
||||
notification_title: '{workflow}'
|
||||
footer: '<{run_url}|View Run> / Last commit <{commit_url}|{commit_sha}>'
|
||||
mention_groups: ${{ needs.process-result.outputs.codeowners }}
|
||||
env:
|
||||
SLACK_WEBHOOK_URL: ${{ secrets.ACTION_MONITORING_SLACK }}
|
||||
|
||||
report-success:
|
||||
if: ${{ success() && github.repository_owner == 'nrwl' && github.event_name != 'workflow_dispatch' }}
|
||||
needs: e2e
|
||||
runs-on: ubuntu-latest
|
||||
name: Report status
|
||||
steps:
|
||||
- name: Send notification
|
||||
uses: ravsamhq/notify-slack-action@v2
|
||||
with:
|
||||
status: ${{ needs.e2e.result }}
|
||||
message_format: '{emoji} Workflow has {status_message}'
|
||||
notification_title: '{workflow}'
|
||||
footer: '<{run_url}|View Run> / Last commit <{commit_url}|{commit_sha}>'
|
||||
env:
|
||||
SLACK_WEBHOOK_URL: ${{ secrets.ACTION_MONITORING_SLACK }}
|
||||
|
||||
report-pm-time:
|
||||
if: ${{ always() && github.repository_owner == 'nrwl' && github.event_name != 'workflow_dispatch' }}
|
||||
needs: process-result
|
||||
runs-on: ubuntu-latest
|
||||
name: Report duration per package manager
|
||||
steps:
|
||||
- name: Send notification
|
||||
uses: ravsamhq/notify-slack-action@v2
|
||||
with:
|
||||
status: 'skipped'
|
||||
message_format: '${{ needs.process-result.outputs.pm-duration }}'
|
||||
notification_title: 'Total duration per package manager (ubuntu only)'
|
||||
env:
|
||||
SLACK_WEBHOOK_URL: ${{ secrets.ACTION_MONITORING_SLACK }}
|
||||
|
||||
report-proj-time:
|
||||
if: ${{ always() && github.repository_owner == 'nrwl' && github.event_name != 'workflow_dispatch' }}
|
||||
needs: process-result
|
||||
runs-on: ubuntu-latest
|
||||
name: Report duration per package manager
|
||||
steps:
|
||||
- name: Send notification
|
||||
uses: ravsamhq/notify-slack-action@v2
|
||||
with:
|
||||
status: 'skipped'
|
||||
message_format: '${{ needs.process-result.outputs.proj-duration }}'
|
||||
notification_title: 'E2E Project duration stats'
|
||||
env:
|
||||
SLACK_WEBHOOK_URL: ${{ secrets.ACTION_MONITORING_SLACK }}
|
||||
- name: Run e2e tests
|
||||
run: yarn e2e ${{ matrix.packages }} affected
|
||||
env:
|
||||
GIT_AUTHOR_NAME: test@test.com
|
||||
GIT_AUTHOR_EMAIL: Test
|
||||
GIT_COMMITTER_EMAIL: test@test.com
|
||||
GIT_COMMITTER_NAME: Test
|
||||
NX_E2E_CI_CACHE_KEY: e2e-gha-${{ matrix.node_version }}-${{ matrix.package_manager }}
|
||||
NODE_OPTIONS: --max_old_space_size=8192
|
||||
SELECTED_PM: ${{ matrix.package_manager }}
|
||||
SELECTED_CLI: ${{ matrix.packages == 'e2e-angular' && 'angular' || 'nx' }}
|
||||
|
||||
@@ -1,421 +0,0 @@
|
||||
name: E2E matrix (Windows)
|
||||
|
||||
on:
|
||||
schedule:
|
||||
- cron: "0 5 * * *"
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
debug_enabled:
|
||||
type: boolean
|
||||
description: 'Run the build with tmate debugging enabled (https://github.com/marketplace/actions/debugging-with-tmate)'
|
||||
required: false
|
||||
default: false
|
||||
|
||||
env:
|
||||
CYPRESS_CACHE_FOLDER: ${{ github.workspace }}/.cypress
|
||||
|
||||
permissions: {}
|
||||
jobs:
|
||||
preinstall:
|
||||
runs-on: windows-latest
|
||||
strategy:
|
||||
matrix:
|
||||
node_version:
|
||||
- 20
|
||||
- 18
|
||||
- 16
|
||||
|
||||
name: Cache install (node v${{ matrix.node_version }})
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- uses: pnpm/action-setup@v2
|
||||
name: Install pnpm
|
||||
with:
|
||||
version: 8.7.4
|
||||
run_install: false
|
||||
|
||||
- name: Set node
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: ${{ matrix.node_version }}
|
||||
cache: 'pnpm'
|
||||
|
||||
- name: Cache node_modules
|
||||
id: cache-modules
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
lookup-only: true
|
||||
path: '**/node_modules'
|
||||
key: ${{ runner.os }}-modules-${{ matrix.node_version }}-${{ github.run_id }}
|
||||
|
||||
- name: Install packages
|
||||
run: pnpm install --frozen-lockfile
|
||||
|
||||
- name: Cache Cypress
|
||||
id: cache-cypress
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
lookup-only: true
|
||||
path: '${{ github.workspace }}/.cypress'
|
||||
key: windows-cypress
|
||||
|
||||
- name: Install Cypress
|
||||
if: steps.cache-cypress.outputs.cache-hit != 'true'
|
||||
run: npx cypress install
|
||||
|
||||
e2e:
|
||||
needs: preinstall
|
||||
permissions:
|
||||
contents: read
|
||||
runs-on: windows-latest
|
||||
strategy:
|
||||
matrix:
|
||||
node_version:
|
||||
- 20
|
||||
- 18
|
||||
- 16
|
||||
package_manager:
|
||||
- npm
|
||||
project:
|
||||
- e2e-angular-core
|
||||
- e2e-angular-extensions
|
||||
- e2e-cypress
|
||||
- e2e-esbuild
|
||||
- e2e-jest
|
||||
- e2e-js
|
||||
- e2e-lerna-smoke-tests
|
||||
- e2e-eslint
|
||||
- e2e-next
|
||||
- e2e-node
|
||||
- e2e-nx-init
|
||||
- e2e-nx-misc
|
||||
- e2e-plugin
|
||||
- e2e-nx-run
|
||||
- e2e-react-core
|
||||
- e2e-react-extensions
|
||||
- e2e-web
|
||||
- e2e-rollup
|
||||
- e2e-storybook
|
||||
- e2e-storybook-angular
|
||||
- e2e-vite
|
||||
- e2e-webpack
|
||||
- e2e-workspace-create
|
||||
- e2e-workspace-create-npm
|
||||
include:
|
||||
# codeowner groups
|
||||
- project: e2e-angular-core
|
||||
codeowners: 'S04SS457V38'
|
||||
- project: e2e-angular-extensions
|
||||
codeowners: 'S04SS457V38'
|
||||
- project: e2e-cypress
|
||||
codeowners: 'S04T16BTJJY'
|
||||
- project: e2e-esbuild
|
||||
codeowners: 'S04SJ6HHP0X'
|
||||
- project: e2e-jest
|
||||
codeowners: 'S04T16BTJJY'
|
||||
- project: e2e-js
|
||||
codeowners: 'S04SJ6HHP0X'
|
||||
- project: e2e-lerna-smoke-tests
|
||||
codeowners: 'S04TNCVEETS'
|
||||
- project: e2e-eslint
|
||||
codeowners: 'S04SYJGKSCT'
|
||||
- project: e2e-next
|
||||
codeowners: 'S04TNCNJG5N'
|
||||
- project: e2e-node
|
||||
codeowners: 'S04SJ6HHP0X'
|
||||
- project: e2e-nx-init
|
||||
codeowners: 'S04SYHYKGNP'
|
||||
- project: e2e-nx-misc
|
||||
codeowners: 'S04SYHYKGNP'
|
||||
- project: e2e-plugin
|
||||
codeowners: 'S04SYHYKGNP'
|
||||
- project: e2e-nx-run
|
||||
codeowners: 'S04SYHYKGNP'
|
||||
- project: e2e-react-core
|
||||
codeowners: 'S04TNCNJG5N'
|
||||
- project: e2e-react-extensions
|
||||
codeowners: 'S04TNCNJG5N'
|
||||
- project: e2e-web
|
||||
codeowners: 'S04SJ6PL98X'
|
||||
- project: e2e-rollup
|
||||
codeowners: 'S04SJ6PL98X'
|
||||
- project: e2e-storybook
|
||||
codeowners: 'S04SVQ8H0G5'
|
||||
- project: e2e-storybook-angular
|
||||
codeowners: 'S04SVQ8H0G5'
|
||||
- project: e2e-vite
|
||||
codeowners: 'S04SJ6PL98X'
|
||||
- project: e2e-webpack
|
||||
codeowners: 'S04SJ6PL98X'
|
||||
- project: e2e-workspace-create
|
||||
codeowners: 'S04SYHYKGNP'
|
||||
- project: e2e-workspace-create-npm
|
||||
codeowners: 'S04SYHYKGNP'
|
||||
exclude:
|
||||
# exclude non-CNW/Lerna tests from non-LTS node versions
|
||||
- node_version: 16
|
||||
project: e2e-angular-core
|
||||
- node_version: 16
|
||||
project: e2e-angular-extensions
|
||||
- node_version: 16
|
||||
project: e2e-cypress
|
||||
- node_version: 16
|
||||
project: e2e-esbuild
|
||||
- node_version: 16
|
||||
project: e2e-jest
|
||||
- node_version: 16
|
||||
project: e2e-js
|
||||
- node_version: 16
|
||||
project: e2e-eslint
|
||||
- node_version: 16
|
||||
project: e2e-next
|
||||
- node_version: 16
|
||||
project: e2e-node
|
||||
- node_version: 16
|
||||
project: e2e-nx-init
|
||||
- node_version: 16
|
||||
project: e2e-nx-misc
|
||||
- node_version: 16
|
||||
project: e2e-plugin
|
||||
- node_version: 16
|
||||
project: e2e-lerna-smoke-tests
|
||||
- node_version: 16
|
||||
project: e2e-react-core
|
||||
- node_version: 16
|
||||
project: e2e-react-extensions
|
||||
- node_version: 16
|
||||
project: e2e-web
|
||||
- node_version: 16
|
||||
project: e2e-rollup
|
||||
- node_version: 16
|
||||
project: e2e-storybook
|
||||
- node_version: 16
|
||||
project: e2e-storybook-angular
|
||||
- node_version: 16
|
||||
project: e2e-vite
|
||||
- node_version: 16
|
||||
project: e2e-webpack
|
||||
- node_version: 20
|
||||
project: e2e-angular-core
|
||||
- node_version: 20
|
||||
project: e2e-angular-extensions
|
||||
- node_version: 20
|
||||
project: e2e-cypress
|
||||
- node_version: 20
|
||||
project: e2e-esbuild
|
||||
- node_version: 20
|
||||
project: e2e-jest
|
||||
- node_version: 20
|
||||
project: e2e-js
|
||||
- node_version: 20
|
||||
project: e2e-eslint
|
||||
- node_version: 20
|
||||
project: e2e-next
|
||||
- node_version: 20
|
||||
project: e2e-node
|
||||
- node_version: 20
|
||||
project: e2e-nx-init
|
||||
- node_version: 20
|
||||
project: e2e-nx-misc
|
||||
- node_version: 20
|
||||
project: e2e-plugin
|
||||
- node_version: 20
|
||||
project: e2e-lerna-smoke-tests
|
||||
- node_version: 20
|
||||
project: e2e-react-core
|
||||
- node_version: 20
|
||||
project: e2e-react-extensions
|
||||
- node_version: 20
|
||||
project: e2e-web
|
||||
- node_version: 20
|
||||
project: e2e-rollup
|
||||
- node_version: 20
|
||||
project: e2e-storybook
|
||||
- node_version: 20
|
||||
project: e2e-storybook-angular
|
||||
- node_version: 20
|
||||
project: e2e-vite
|
||||
- node_version: 20
|
||||
project: e2e-webpack
|
||||
fail-fast: false
|
||||
|
||||
name: ${{ matrix.project }} (v${{ matrix.node_version }})
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Prepare dir for output
|
||||
run: mkdir -p outputs
|
||||
|
||||
- uses: pnpm/action-setup@v2
|
||||
name: Install pnpm
|
||||
with:
|
||||
version: 8.7.4
|
||||
run_install: false
|
||||
|
||||
- name: Use Node.js ${{ matrix.node_version }}
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: ${{ matrix.node_version }}
|
||||
cache: 'pnpm'
|
||||
|
||||
- name: Cache node_modules
|
||||
id: cache-modules
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: '**/node_modules'
|
||||
key: ${{ runner.os }}-modules-${{ matrix.node_version }}-${{ github.run_id }}
|
||||
|
||||
- name: Install packages
|
||||
run: pnpm install --frozen-lockfile
|
||||
|
||||
- name: Cache Cypress
|
||||
id: cache-cypress
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: '${{ github.workspace }}/.cypress'
|
||||
key: ${{ runner.os }}-cypress
|
||||
|
||||
- name: Install Cypress
|
||||
if: steps.cache-cypress.outputs.cache-hit != 'true'
|
||||
run: npx cypress install
|
||||
|
||||
- name: Configure git metadata (needed for lerna smoke tests)
|
||||
run: |
|
||||
git config --global user.email test@test.com
|
||||
git config --global user.name "Test Test"
|
||||
|
||||
- name: Run e2e tests
|
||||
id: e2e-run
|
||||
run: pnpm nx run ${{ matrix.project }}:e2e
|
||||
shell: bash
|
||||
timeout-minutes: 120
|
||||
env:
|
||||
GIT_AUTHOR_EMAIL: test@test.com
|
||||
GIT_AUTHOR_NAME: Test
|
||||
GIT_COMMITTER_EMAIL: test@test.com
|
||||
GIT_COMMITTER_NAME: Test
|
||||
NX_E2E_CI_CACHE_KEY: e2e-gha-windows-${{ matrix.node_version }}-${{ matrix.package_manager }}
|
||||
NODE_OPTIONS: --max_old_space_size=8192
|
||||
SELECTED_PM: ${{ matrix.package_manager }}
|
||||
npm_config_registry: http://localhost:4872
|
||||
NX_CACHE_DIRECTORY: 'tmp'
|
||||
NX_E2E_SKIP_CLEANUP: 'true'
|
||||
NX_E2E_RUN_E2E: 'true'
|
||||
NX_E2E_VERBOSE_LOGGING: 'true'
|
||||
NX_PERF_LOGGING: 'false'
|
||||
NX_DAEMON: 'true'
|
||||
|
||||
- name: Save matrix config in file
|
||||
if: ${{ always() }}
|
||||
id: save-matrix
|
||||
shell: bash
|
||||
run: |
|
||||
matrix=$((
|
||||
echo '${{ toJSON(matrix) }}'
|
||||
) | jq -c '. + { "status": "${{ steps.e2e-run.outcome}}" }')
|
||||
echo "$matrix" > matrix
|
||||
path=outputs/windows-${{ matrix.node_version}}-${{ matrix.package_manager}}-${{ matrix.project }}
|
||||
echo "path=$path" >> $GITHUB_OUTPUT
|
||||
echo "$matrix" > $path
|
||||
|
||||
- name: Upload matrix config
|
||||
uses: actions/upload-artifact@v3
|
||||
if: ${{ always() }}
|
||||
with:
|
||||
name: outputs
|
||||
path: ${{ steps.save-matrix.outputs.path }}
|
||||
|
||||
- name: Setup tmate session
|
||||
if: ${{ github.event_name == 'workflow_dispatch' && inputs.debug_enabled && failure() }}
|
||||
uses: mxschmitt/action-tmate@v3.8
|
||||
timeout-minutes: 15
|
||||
with:
|
||||
sudo: false # disable sudo for windows debugging
|
||||
|
||||
process-result:
|
||||
if: ${{ always() }}
|
||||
runs-on: ubuntu-latest
|
||||
needs: e2e
|
||||
outputs:
|
||||
message: ${{ steps.process-json.outputs.SLACK_MESSAGE }}
|
||||
codeowners: ${{ steps.process-json.outputs.CODEOWNERS }}
|
||||
steps:
|
||||
- name: Load outputs
|
||||
uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: outputs
|
||||
path: outputs
|
||||
|
||||
- name: Join and stringify matrix configs
|
||||
id: combine-json
|
||||
shell: bash
|
||||
run: |
|
||||
combined=$((jq -s . outputs/*) | jq tostring)
|
||||
echo "combined=$combined" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Make slack outputs
|
||||
id: process-json
|
||||
uses: actions/github-script@v6
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ github.token }}
|
||||
with:
|
||||
script: |
|
||||
const combined = JSON.parse(${{ steps.combine-json.outputs.combined }});
|
||||
const failedProjects = combined.filter(c => c.status === 'failure').sort((a, b) => a.project.localeCompare(b.project));
|
||||
|
||||
// codeowners
|
||||
const codeowners = new Set();
|
||||
failedProjects.forEach(c => {
|
||||
codeowners.add(c.codeowners);
|
||||
});
|
||||
core.setOutput('CODEOWNERS', Array.from(codeowners).join(','));
|
||||
|
||||
// message
|
||||
let result = `
|
||||
*OS* Windows
|
||||
*Package manager* npm
|
||||
\`\`\`
|
||||
| Failed project | Node |
|
||||
|--------------------------------|------|`;
|
||||
failedProjects.forEach(matrix => {
|
||||
result += `\n| ${matrix.project.padEnd(30)} | v${matrix.node_version.toString().padEnd(3)} |`
|
||||
});
|
||||
result += `\`\`\``;
|
||||
const message = result.split('\n').map(l => l.trim()).join('\n');
|
||||
core.setOutput('SLACK_MESSAGE', message);
|
||||
|
||||
report-failure:
|
||||
if: ${{ failure() && github.repository_owner == 'nrwl' && github.event_name != 'workflow_dispatch' }}
|
||||
needs: process-result
|
||||
runs-on: ubuntu-latest
|
||||
name: Report failure
|
||||
steps:
|
||||
- name: Send notification
|
||||
uses: ravsamhq/notify-slack-action@v2
|
||||
with:
|
||||
status: 'failure'
|
||||
message_format: '{emoji} Workflow has {status_message} ${{ needs.process-result.outputs.message }}'
|
||||
notification_title: '{workflow}'
|
||||
footer: '<{run_url}|View Run> / Last commit <{commit_url}|{commit_sha}>'
|
||||
mention_groups: ${{ needs.process-result.outputs.codeowners }}
|
||||
env:
|
||||
SLACK_WEBHOOK_URL: ${{ secrets.ACTION_MONITORING_SLACK }}
|
||||
|
||||
report-success:
|
||||
if: ${{ success() && github.repository_owner == 'nrwl' && github.event_name != 'workflow_dispatch' }}
|
||||
needs: e2e
|
||||
runs-on: ubuntu-latest
|
||||
name: Report success
|
||||
steps:
|
||||
- name: Send notification
|
||||
uses: ravsamhq/notify-slack-action@v2
|
||||
with:
|
||||
status: ${{ needs.e2e.result }}
|
||||
message_format: '{emoji} Workflow has {status_message}'
|
||||
notification_title: '{workflow}'
|
||||
footer: '<{run_url}|View Run> / Last commit <{commit_url}|{commit_sha}>'
|
||||
env:
|
||||
SLACK_WEBHOOK_URL: ${{ secrets.ACTION_MONITORING_SLACK }}
|
||||
@@ -1,53 +0,0 @@
|
||||
name: Generate embeddings
|
||||
|
||||
on:
|
||||
schedule:
|
||||
- cron: "0 5 * * 0,4" # sunday, thursday 5AM
|
||||
workflow_dispatch:
|
||||
jobs:
|
||||
cache-and-install:
|
||||
if: github.repository == 'nrwl/nx'
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
node-version: [18]
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Install Node.js
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 18
|
||||
|
||||
- name: Install pnpm
|
||||
uses: pnpm/action-setup@v2
|
||||
id: pnpm-install
|
||||
with:
|
||||
version: 7
|
||||
run_install: false
|
||||
|
||||
- name: Get pnpm store directory
|
||||
id: pnpm-cache
|
||||
shell: bash
|
||||
run: |
|
||||
echo "STORE_PATH=$(pnpm store path)" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Setup pnpm cache
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: ${{ steps.pnpm-cache.outputs.STORE_PATH }}
|
||||
key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-pnpm-store-
|
||||
|
||||
- name: Install dependencies
|
||||
run: pnpm install --no-frozen-lockfile
|
||||
|
||||
- name: Run embeddings script
|
||||
run: pnpm exec nx run tools-documentation-create-embeddings:run-node
|
||||
env:
|
||||
NX_NEXT_PUBLIC_SUPABASE_URL: ${{ secrets.NX_NEXT_PUBLIC_SUPABASE_URL }}
|
||||
NX_SUPABASE_SERVICE_ROLE_KEY: ${{ secrets.NX_SUPABASE_SERVICE_ROLE_KEY }}
|
||||
NX_OPENAI_KEY: ${{ secrets.NX_OPENAI_KEY }}
|
||||
@@ -1,69 +0,0 @@
|
||||
name: Issue Statistics
|
||||
|
||||
on:
|
||||
schedule:
|
||||
- cron: "0 0 * * 0"
|
||||
workflow_dispatch:
|
||||
|
||||
permissions:
|
||||
issues: read
|
||||
pull-requests: read
|
||||
|
||||
jobs:
|
||||
issues-report:
|
||||
if: ${{ github.repository_owner == 'nrwl' }}
|
||||
runs-on: ubuntu-latest
|
||||
name: Report status
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- uses: pnpm/action-setup@v2
|
||||
with:
|
||||
version: 8.2
|
||||
|
||||
- name: Use Node.js ${{ matrix.node_version }}
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: '18'
|
||||
cache: 'pnpm'
|
||||
|
||||
- name: Cache node_modules
|
||||
id: cache-modules
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
lookup-only: true
|
||||
path: '**/node_modules'
|
||||
key: pnpm-${{ hashFiles('pnpm-lock.yaml') }}
|
||||
|
||||
- name: Install packages
|
||||
run: pnpm install --frozen-lockfile
|
||||
|
||||
- name: Download artifact
|
||||
id: download-artifact
|
||||
uses: dawidd6/action-download-artifact@v2 # Needed since we are downloading artifact from a different workflow run, official actions/download-artifact doesn't support this.
|
||||
with:
|
||||
name: cached-issue-data
|
||||
path: ${{ github.workspace }}/scripts/issues-scraper/cached
|
||||
search_artifacts: true
|
||||
continue-on-error: true
|
||||
|
||||
- name: Collect Issue Data
|
||||
id: collect
|
||||
run: npx ts-node ./scripts/issues-scraper/index.ts
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ github.token }}
|
||||
|
||||
- uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: cached-issue-data
|
||||
path: ./scripts/issues-scraper/cached/data.json
|
||||
|
||||
- name: Send GitHub Action trigger data to Slack workflow
|
||||
id: slack
|
||||
uses: slackapi/slack-github-action@v1.23.0
|
||||
with:
|
||||
payload: ${{ steps.collect.outputs.SLACK_MESSAGE }}
|
||||
env:
|
||||
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_ISSUES_REPORT_URL }}
|
||||
SLACK_WEBHOOK_TYPE: INCOMING_WEBHOOK
|
||||
@@ -1,30 +0,0 @@
|
||||
name: "Lock Threads"
|
||||
|
||||
on:
|
||||
schedule:
|
||||
- cron: "0 0 * * *" # Once a day, at midnight UTC
|
||||
workflow_dispatch:
|
||||
|
||||
permissions:
|
||||
issues: write
|
||||
pull-requests: write
|
||||
|
||||
concurrency:
|
||||
group: lock
|
||||
|
||||
jobs:
|
||||
action:
|
||||
if: ${{ github.repository_owner == 'nrwl' }}
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: dessant/lock-threads@v4
|
||||
id: lockthreads
|
||||
with:
|
||||
github-token: ${{ github.token }}
|
||||
issue-inactive-days: "30" # Lock issues after 30 days of being closed
|
||||
pr-inactive-days: "5" # Lock closed PRs after 5 days. This ensures that issues that stem from a PR are opened as issues, rather than comments on the recently merged PR.
|
||||
add-issue-labels: "outdated"
|
||||
issue-comment: >
|
||||
This issue has been closed for more than 30 days. If this issue is still occuring, please open a new issue with more recent context.
|
||||
pr-comment: >
|
||||
This pull request has already been merged/closed. If you experience issues related to these changes, please open a new issue referencing this pull request.
|
||||
@@ -2,45 +2,14 @@ name: NPM Audit
|
||||
|
||||
on:
|
||||
schedule:
|
||||
- cron: "0 0 * * *"
|
||||
workflow_dispatch:
|
||||
- cron: "0 0 * * *"
|
||||
|
||||
permissions: {}
|
||||
jobs:
|
||||
audit:
|
||||
permissions:
|
||||
contents: read # to fetch code (actions/checkout)
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v2
|
||||
|
||||
- name: Install PNPM
|
||||
run: |
|
||||
npm install -g @pnpm/exe@8.3.1
|
||||
|
||||
- name: Run a security audit
|
||||
run: pnpm dlx audit-ci --critical --report-type summary
|
||||
|
||||
# - name: Run Dependency confusion supply chain check
|
||||
# run: npx snync -d .
|
||||
|
||||
report:
|
||||
if: ${{ always() && github.repository_owner == 'nrwl' && github.event_name != 'workflow_dispatch' }}
|
||||
needs: audit
|
||||
runs-on: ubuntu-latest
|
||||
name: Report status
|
||||
steps:
|
||||
- name: Send notification
|
||||
uses: ravsamhq/notify-slack-action@v2
|
||||
with:
|
||||
status: ${{ needs.audit.result }}
|
||||
message_format: '{emoji} Audit has {status_message}'
|
||||
notification_title: '{workflow}'
|
||||
footer: '<{run_url}|View Run> / Last commit <{commit_url}|{commit_sha}>'
|
||||
mention_users: 'U01UELKLYF2,U9NPA6C90'
|
||||
mention_users_when: 'failure,warnings'
|
||||
env:
|
||||
SLACK_WEBHOOK_URL: ${{ secrets.ACTION_MONITORING_SLACK }}
|
||||
- name: Run a security audit
|
||||
run: npx audit-ci --critical --report-type summary
|
||||
|
||||
@@ -1,257 +0,0 @@
|
||||
name: publish
|
||||
env:
|
||||
DEBUG: napi:*
|
||||
NX_RUN_GROUP: ${{ github.run_id }}-${{ github.run_attempt }}
|
||||
NPM_CONFIG_PROVENANCE: true
|
||||
on:
|
||||
workflow_dispatch:
|
||||
release:
|
||||
types: [published]
|
||||
jobs:
|
||||
build:
|
||||
if: "!contains(github.event.head_commit.message, 'skip ci')"
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
settings:
|
||||
- host: macos-latest
|
||||
target: x86_64-apple-darwin
|
||||
build: |
|
||||
pnpm nx run-many --target=build-native -- --target=x86_64-apple-darwin
|
||||
- host: windows-latest
|
||||
build: pnpm nx run-many --target=build-native -- --target=x86_64-pc-windows-msvc
|
||||
target: x86_64-pc-windows-msvc
|
||||
# Windows 32bit (not needed)
|
||||
# - host: windows-latest
|
||||
# build: |
|
||||
# yarn nx -- run-many --target=build-native -- --target=i686-pc-windows-msvc
|
||||
# target: i686-pc-windows-msvc
|
||||
- host: ubuntu-latest
|
||||
target: x86_64-unknown-linux-gnu
|
||||
docker: ghcr.io/napi-rs/napi-rs/nodejs-rust:lts-debian
|
||||
build: |-
|
||||
set -e &&
|
||||
pnpm --version &&
|
||||
pnpm nx run-many --target=build-native -- --target=x86_64-unknown-linux-gnu
|
||||
- host: ubuntu-latest
|
||||
target: x86_64-unknown-linux-musl
|
||||
docker: ghcr.io/napi-rs/napi-rs/nodejs-rust:lts-alpine
|
||||
build: set -e && pnpm nx run-many --target=build-native -- --target=x86_64-unknown-linux-musl
|
||||
- host: macos-latest
|
||||
target: aarch64-apple-darwin
|
||||
build: |
|
||||
sudo rm -Rf /Library/Developer/CommandLineTools/SDKs/*;
|
||||
export CC=$(xcrun -f clang);
|
||||
export CXX=$(xcrun -f clang++);
|
||||
SYSROOT=$(xcrun --sdk macosx --show-sdk-path);
|
||||
export CFLAGS="-isysroot $SYSROOT -isystem $SYSROOT";
|
||||
pnpm nx run-many --target=build-native -- --target=aarch64-apple-darwin
|
||||
- host: ubuntu-latest
|
||||
target: aarch64-unknown-linux-gnu
|
||||
docker: ghcr.io/napi-rs/napi-rs/nodejs-rust:lts-debian-aarch64
|
||||
build: |-
|
||||
set -e &&
|
||||
pnpm --version &&
|
||||
pnpm nx run-many --target=build-native -- --target=aarch64-unknown-linux-gnu
|
||||
- host: ubuntu-latest
|
||||
target: armv7-unknown-linux-gnueabihf
|
||||
setup: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install gcc-arm-linux-gnueabihf -y
|
||||
build: |
|
||||
pnpm nx run-many --target=build-native -- --target=armv7-unknown-linux-gnueabihf
|
||||
# Android (not needed)
|
||||
# - host: ubuntu-latest
|
||||
# target: aarch64-linux-android
|
||||
# build: |
|
||||
# pnpm nx run-many --target=build-native -- --target=aarch64-linux-android
|
||||
# - host: ubuntu-latest
|
||||
# target: armv7-linux-androideabi
|
||||
# build: |
|
||||
# pnpm nx run-many --target=build-native -- --target=armv7-linux-androideabi
|
||||
- host: ubuntu-latest
|
||||
target: aarch64-unknown-linux-musl
|
||||
docker: ghcr.io/napi-rs/napi-rs/nodejs-rust:lts-alpine
|
||||
build: |-
|
||||
set -e &&
|
||||
rustup target add aarch64-unknown-linux-musl &&
|
||||
pnpm nx run-many --target=build-native -- --target=aarch64-unknown-linux-musl
|
||||
- host: windows-latest
|
||||
target: aarch64-pc-windows-msvc
|
||||
build: pnpm nx run-many --target=build-native -- --target=aarch64-pc-windows-msvc
|
||||
name: stable - ${{ matrix.settings.target }} - node@18
|
||||
runs-on: ${{ matrix.settings.host }}
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- uses: pnpm/action-setup@v2
|
||||
with:
|
||||
version: 8.2
|
||||
|
||||
- name: Setup node
|
||||
uses: actions/setup-node@v3
|
||||
if: ${{ !matrix.settings.docker }}
|
||||
with:
|
||||
node-version: 18
|
||||
check-latest: true
|
||||
cache: 'pnpm'
|
||||
|
||||
- name: Install
|
||||
uses: dtolnay/rust-toolchain@stable
|
||||
if: ${{ !matrix.settings.docker }}
|
||||
with:
|
||||
targets: ${{ matrix.settings.target }}
|
||||
|
||||
- name: Cache cargo
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: |
|
||||
~/.cargo/registry/index/
|
||||
~/.cargo/registry/cache/
|
||||
~/.cargo/git/db/
|
||||
.cargo-cache
|
||||
target/
|
||||
key: ${{ matrix.settings.target }}-cargo-registry
|
||||
- uses: goto-bus-stop/setup-zig@v2
|
||||
if: ${{ matrix.settings.target == 'armv7-unknown-linux-gnueabihf' }}
|
||||
with:
|
||||
version: 0.10.0
|
||||
- name: Setup toolchain
|
||||
run: ${{ matrix.settings.setup }}
|
||||
if: ${{ matrix.settings.setup }}
|
||||
shell: bash
|
||||
- name: Setup node x86
|
||||
if: matrix.settings.target == 'i686-pc-windows-msvc'
|
||||
run: yarn config set supportedArchitectures.cpu "ia32"
|
||||
shell: bash
|
||||
- name: Install dependencies
|
||||
run: pnpm install --frozen-lockfile
|
||||
timeout-minutes: 30
|
||||
- name: Setup node x86
|
||||
uses: actions/setup-node@v3
|
||||
if: matrix.settings.target == 'i686-pc-windows-msvc'
|
||||
with:
|
||||
node-version: 18
|
||||
check-latest: true
|
||||
cache: pnpm
|
||||
architecture: x86
|
||||
- name: Build in docker
|
||||
uses: addnab/docker-run-action@v3
|
||||
if: ${{ matrix.settings.docker }}
|
||||
with:
|
||||
image: ${{ matrix.settings.docker }}
|
||||
options: --user 0:0 -v ${{ github.workspace }}/.cargo-cache/git/db:/usr/local/cargo/git/db -v ${{ github.workspace }}/.cargo/registry/cache:/usr/local/cargo/registry/cache -v ${{ github.workspace }}/.cargo/registry/index:/usr/local/cargo/registry/index -v ${{ github.workspace }}:/build -w /build
|
||||
run: ${{ matrix.settings.build }}
|
||||
- name: Build
|
||||
run: ${{ matrix.settings.build }}
|
||||
if: ${{ !matrix.settings.docker }}
|
||||
shell: bash
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: bindings-${{ matrix.settings.target }}
|
||||
path: packages/**/*.node
|
||||
if-no-files-found: error
|
||||
build-freebsd:
|
||||
runs-on: macos-12
|
||||
name: Build FreeBSD
|
||||
timeout-minutes: 45
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
if: ${{ !contains(github.ref, '-') }}
|
||||
- name: Build
|
||||
id: build
|
||||
if: ${{ !contains(github.ref, '-') }}
|
||||
uses: cross-platform-actions/action@v0.21.1
|
||||
env:
|
||||
DEBUG: napi:*
|
||||
RUSTUP_IO_THREADS: 1
|
||||
with:
|
||||
operating_system: freebsd
|
||||
version: '13.2'
|
||||
architecture: x86-64
|
||||
environment_variables: DEBUG RUSTUP_IO_THREADS CI
|
||||
shell: bash
|
||||
run: |
|
||||
env
|
||||
whoami
|
||||
sudo pkg install -y -f node libnghttp2 npm git
|
||||
sudo npm install --location=global --ignore-scripts pnpm
|
||||
curl https://sh.rustup.rs -sSf --output rustup.sh
|
||||
sh rustup.sh -y --profile minimal --default-toolchain stable
|
||||
source "$HOME/.cargo/env"
|
||||
echo "~~~~ rustc --version ~~~~"
|
||||
rustc --version
|
||||
echo "~~~~ node -v ~~~~"
|
||||
node -v
|
||||
echo "~~~~ pnpm --version ~~~~"
|
||||
pnpm --version
|
||||
pwd
|
||||
ls -lah
|
||||
whoami
|
||||
env
|
||||
freebsd-version
|
||||
mkdir -p /Users/runner/work/_temp/_github_workflow
|
||||
echo "{}" > /Users/runner/work/_temp/_github_workflow/event.json
|
||||
pnpm install --frozen-lockfile --ignore-scripts
|
||||
pnpm nx run-many --outputStyle stream --target=build-native -- --target=x86_64-unknown-freebsd
|
||||
pnpm nx reset
|
||||
rm -rf node_modules
|
||||
rm -rf dist
|
||||
echo "KILL ALL NODE PROCESSES"
|
||||
killall node || true
|
||||
echo "COMPLETE"
|
||||
- name: Upload artifact
|
||||
if: ${{ !contains(github.ref, '-') }}
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: bindings-freebsd
|
||||
path: packages/**/*.node
|
||||
if-no-files-found: error
|
||||
publish:
|
||||
if: ${{ github.event_name == 'release' && github.repository_owner == 'nrwl' }}
|
||||
name: Publish
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
id-token: write
|
||||
needs:
|
||||
- build-freebsd
|
||||
- build
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: pnpm/action-setup@v2
|
||||
with:
|
||||
version: 8.2
|
||||
- name: Setup node
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 18
|
||||
check-latest: true
|
||||
cache: 'pnpm'
|
||||
- name: Install dependencies
|
||||
run: pnpm install --frozen-lockfile
|
||||
- name: Download all artifacts
|
||||
uses: actions/download-artifact@v3
|
||||
with:
|
||||
path: artifacts
|
||||
- name: List artifacts
|
||||
run: ls -R artifacts
|
||||
shell: bash
|
||||
- name: Publish
|
||||
run: |
|
||||
git checkout -b publish/$GITHUB_REF_NAME
|
||||
npm config set //registry.npmjs.org/:_authToken=$NPM_TOKEN
|
||||
pnpm nx-release --local=false $GITHUB_REF_NAME
|
||||
- name: Trigger Docs Release
|
||||
# Publish docs only on a full release
|
||||
if: ${{ !github.event.release.prerelease }}
|
||||
run: |
|
||||
# Publish docs only when publishing the latest version
|
||||
if [ "$(git describe --tags `git rev-list --tags --max-count=1`)" = "$GITHUB_REF_NAME" ]; then
|
||||
# We force recreate the branch in order to always be up to date and avoid merge conflicts within the automated workflow
|
||||
git branch -f website
|
||||
git push -f origin website
|
||||
fi
|
||||
env:
|
||||
GH_TOKEN: ${{ github.token }}
|
||||
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
|
||||
@@ -1,18 +1,9 @@
|
||||
on:
|
||||
schedule:
|
||||
- cron: "0 0 * * *"
|
||||
|
||||
- cron: "* 0 * * *"
|
||||
name: Stale Bot workflow
|
||||
|
||||
permissions: {}
|
||||
|
||||
jobs:
|
||||
build:
|
||||
if: ${{ github.repository_owner == 'nrwl' }}
|
||||
permissions:
|
||||
issues: write # to close stale issues (actions/stale)
|
||||
pull-requests: write # to close stale PRs (actions/stale)
|
||||
|
||||
name: stale
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
|
||||
+2
-44
@@ -1,55 +1,13 @@
|
||||
node_modules
|
||||
/.idea
|
||||
/.fleet
|
||||
.idea
|
||||
/.vscode
|
||||
dist
|
||||
/build
|
||||
/coverage
|
||||
./test
|
||||
test
|
||||
.DS_Store
|
||||
tmp
|
||||
*.log
|
||||
jest.debug.config.js
|
||||
.tool-versions
|
||||
/.nx-cache
|
||||
/.nx
|
||||
/.verdaccio/build/local-registry
|
||||
/graph/client/src/assets/environment.js
|
||||
/graph/client/src/assets/dev/environment.js
|
||||
/graph/client/src/assets/generated-project-graphs
|
||||
/graph/client/src/assets/generated-task-graphs
|
||||
/graph/client/src/assets/generated-task-inputs
|
||||
/nx-dev/nx-dev/public/documentation
|
||||
/nx-dev/nx-dev/public/images/open-graph
|
||||
|
||||
# Issues scraper creates these files, stored by github's cache
|
||||
/scripts/issues-scraper/cached
|
||||
|
||||
# We don't commit a CHANELGELOG.md file to the repo, we only create Github releases
|
||||
CHANGELOG.md
|
||||
|
||||
# Next.js
|
||||
.next
|
||||
|
||||
# Angular Cache
|
||||
.angular
|
||||
|
||||
# Local dev files
|
||||
.env
|
||||
.bashrc
|
||||
.nx
|
||||
|
||||
*.node
|
||||
|
||||
# Fix for issue when working on the repo in a dev container
|
||||
.pnpm-store
|
||||
.nx/cache
|
||||
|
||||
.cargo/.package-cache
|
||||
.cargo/bin/
|
||||
.cargo/env
|
||||
.cargo/registry/
|
||||
.local/
|
||||
.npm/
|
||||
.profile
|
||||
.rustup/
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
_
|
||||
@@ -1,3 +0,0 @@
|
||||
#!/bin/sh
|
||||
changedFiles="$(git diff-tree -r --name-only --no-commit-id $1 $2)"
|
||||
node ./scripts/notify-lockfile-changes.js $changedFiles
|
||||
@@ -1,3 +0,0 @@
|
||||
#!/bin/sh
|
||||
changedFiles="$(git diff-tree -r --name-only --no-commit-id ORIG_HEAD HEAD)"
|
||||
node ./scripts/notify-lockfile-changes.js $changedFiles
|
||||
+5
-5
@@ -1,6 +1,6 @@
|
||||
#!/usr/bin/env sh
|
||||
#!/bin/sh
|
||||
. "$(dirname "$0")/_/husky.sh"
|
||||
|
||||
pnpm check-lock-files &&
|
||||
pnpm check-commit &&
|
||||
pnpm documentation &&
|
||||
pnpm pretty-quick --check
|
||||
yarn check-commit
|
||||
yarn documentation
|
||||
yarn pretty-quick --check
|
||||
|
||||
@@ -1,61 +0,0 @@
|
||||
launch-templates:
|
||||
linux-medium:
|
||||
resource-class: 'docker_linux_amd64/medium+'
|
||||
env:
|
||||
CI: 'true'
|
||||
GIT_AUTHOR_EMAIL: test@test.com
|
||||
GIT_AUTHOR_NAME: Test
|
||||
GIT_COMMITTER_EMAIL: test@test.com
|
||||
GIT_COMMITTER_NAME: Test
|
||||
NX_E2E_CI_CACHE_KEY: e2e-circleci-linux
|
||||
NX_VERBOSE_LOGGING: 'true'
|
||||
NX_PERF_LOGGING: 'false'
|
||||
NX_NATIVE_LOGGING: 'false'
|
||||
SELECTED_PM: 'pnpm'
|
||||
NX_E2E_RUN_E2E: 'true'
|
||||
NPM_CONFIG_PREFIX: '/home/workflows/.npm-global'
|
||||
NX_CLOUD_ACCESS_TOKEN: '{{secrets.NX_CLOUD_ACCESS_TOKEN}}'
|
||||
init-steps:
|
||||
- name: LSCPU
|
||||
script: |
|
||||
lscpu
|
||||
- name: Checkout
|
||||
uses: 'nrwl/nx-cloud-workflows/v1.1/workflow-steps/checkout/main.yaml'
|
||||
|
||||
- name: Cache restore
|
||||
uses: 'nrwl/nx-cloud-workflows/v1.1/workflow-steps/cache/main.yaml'
|
||||
env:
|
||||
KEY: 'pnpm-lock.yaml'
|
||||
PATHS: |
|
||||
node_modules
|
||||
~/.cache/Cypress
|
||||
~/.pnpm-store
|
||||
BASE_BRANCH: 'master'
|
||||
|
||||
- name: Install Pnpm
|
||||
script: |
|
||||
npm install -g @pnpm/exe@8.7.4
|
||||
|
||||
- name: Pnpm Install
|
||||
script: |
|
||||
pnpm install --frozen-lockfile
|
||||
|
||||
- name: Install Cypress
|
||||
script: pnpm exec cypress install
|
||||
|
||||
- name: Install Rust
|
||||
script: |
|
||||
curl --proto '=https' --tlsv1.3 https://sh.rustup.rs -sSf | sh -s -- -y
|
||||
source "$HOME/.cargo/env"
|
||||
rustup toolchain install 1.70.0
|
||||
|
||||
- name: Configure git metadata (needed for lerna smoke tests)
|
||||
script: |
|
||||
git config --global user.email test@test.com
|
||||
git config --global user.name "Test Test"
|
||||
|
||||
- name: Load Cargo Env
|
||||
script: echo "PATH=$HOME/.cargo/bin:$PATH" >> $NX_CLOUD_ENV
|
||||
|
||||
- name: Benchmark
|
||||
script: node tools/benchmark/benchmark.js
|
||||
+24
-40
@@ -1,40 +1,24 @@
|
||||
tmp
|
||||
/test
|
||||
/build
|
||||
node_modules
|
||||
/package.json
|
||||
/pnpm-lock.yaml
|
||||
packages/workspace/src/generators/**/files/**/*.json
|
||||
packages/angular/src/schematics/**/files/**/*.json
|
||||
packages/angular/src/migrations/**/files/**/*.json
|
||||
packages/web/src/generators/**/files/**/*.json
|
||||
packages/node/src/schematics/**/files/**/*.json
|
||||
packages/express/src/schematics/**/files/**/*.json
|
||||
packages/nest/src/schematics/**/files/**/*.json
|
||||
packages/react/src/schematics/**/files/**/*.json
|
||||
packages/jest/src/schematics/**/files/**/*.json
|
||||
packages/nx/src/plugins/js/lock-file/__fixtures__/**/*.*
|
||||
packages/**/schematics/**/files/**/*.html
|
||||
packages/**/generators/**/files/**/*.html
|
||||
packages/nx/src/native/
|
||||
nx-dev/nx-dev/.next/
|
||||
nx-dev/nx-dev/public/documentation
|
||||
graph/client/src/assets/environment.js
|
||||
graph/client/src/assets/dev/environment.js
|
||||
graph/client/src/assets/generated-graphs
|
||||
graph/client/src/assets/generated-project-graphs
|
||||
graph/client/src/assets/generated-task-graphs
|
||||
/.vscode
|
||||
/.idea
|
||||
/.fleet
|
||||
/.github
|
||||
/coverage
|
||||
/.yarn
|
||||
/.verdaccio/build/local-registry
|
||||
/dist
|
||||
/.env
|
||||
CODEOWNERS
|
||||
|
||||
/.nx/cache
|
||||
|
||||
.pnpm-store
|
||||
tmp
|
||||
/test
|
||||
/build
|
||||
node_modules
|
||||
/package.json
|
||||
packages/workspace/src/generators/**/files/**/*.json
|
||||
packages/workspace/src/core/dep-graph/vendor.js
|
||||
packages/angular/src/schematics/**/files/**/*.json
|
||||
packages/angular/src/migrations/**/files/**/*.json
|
||||
packages/web/src/generators/**/files/**/*.json
|
||||
packages/node/src/schematics/**/files/**/*.json
|
||||
packages/express/src/schematics/**/files/**/*.json
|
||||
packages/nest/src/schematics/**/files/**/*.json
|
||||
packages/react/src/schematics/**/files/**/*.json
|
||||
packages/jest/src/schematics/**/files/**/*.json
|
||||
packages/**/schematics/**/files/**/*.html
|
||||
packages/**/generators/**/files/**/*.html
|
||||
/.vscode
|
||||
/.idea
|
||||
/.github
|
||||
/coverage
|
||||
/.yarn
|
||||
/.verdaccio/build/local-registry
|
||||
/dist
|
||||
|
||||
+3
-12
@@ -9,14 +9,10 @@ auth:
|
||||
uplinks:
|
||||
npmjs:
|
||||
url: https://registry.npmjs.org/
|
||||
maxage: 60m
|
||||
max_fails: 20
|
||||
fail_timeout: 2m
|
||||
cache: true
|
||||
yarn:
|
||||
url: https://registry.yarnpkg.com
|
||||
maxage: 60m
|
||||
max_fails: 20
|
||||
fail_timeout: 2m
|
||||
cache: true
|
||||
|
||||
packages:
|
||||
'@*/*':
|
||||
@@ -40,9 +36,4 @@ packages:
|
||||
|
||||
# log settings
|
||||
logs:
|
||||
type: stdout
|
||||
format: pretty
|
||||
level: warn
|
||||
|
||||
publish:
|
||||
allow_offline: true # set offline to true to allow publish offline
|
||||
- { type: stdout, format: pretty, level: http }
|
||||
|
||||
+147392
File diff suppressed because one or more lines are too long
@@ -0,0 +1 @@
|
||||
yarnPath: .yarn/releases/yarn-1.22.10.cjs
|
||||
-187
@@ -1,187 +0,0 @@
|
||||
# Any file not covered by a rule below, will default to Jason + Victor and a few select others.
|
||||
* @FrozenPandaz @vsavkin
|
||||
/packages/**/* @FrozenPandaz @vsavkin @AgentEnder @jaysoo @JamesHenry
|
||||
/e2e/**/* @FrozenPandaz @vsavkin @AgentEnder @jaysoo @JamesHenry
|
||||
/scripts/**/* @FrozenPandaz @vsavkin @AgentEnder @jaysoo @JamesHenry
|
||||
/tools/**/* @FrozenPandaz @vsavkin @AgentEnder @jaysoo @JamesHenry
|
||||
package.json @nrwl/nx-core-reviewers
|
||||
pnpm-lock.yaml @nrwl/nx-core-reviewers
|
||||
rust-toolchain @nrwl/nx-native-reviewers
|
||||
|
||||
# Docs Site + Graph
|
||||
/docs @nrwl/nx-docs-reviewers
|
||||
/docs/nx-cloud @StalkAltan @rarmatei @nrwl/nx-docs-reviewers
|
||||
/graph/** @philipjfulcher @FrozenPandaz @bcabanes
|
||||
/images @nrwl/nx-docs-reviewers
|
||||
/nx-dev/** @nrwl/nx-docs-reviewers
|
||||
/typedoc-theme @nrwl/nx-docs-reviewers
|
||||
|
||||
# Plugin Verticals
|
||||
|
||||
## Angular
|
||||
/docs/generated/packages/angular/** @nrwl/nx-angular-reviewers @nrwl/nx-docs-reviewers
|
||||
/docs/shared/packages/angular/** @nrwl/nx-angular-reviewers @nrwl/nx-docs-reviewers
|
||||
/packages/angular/** @nrwl/nx-angular-reviewers
|
||||
/e2e/angular-core/** @nrwl/nx-angular-reviewers
|
||||
/e2e/angular-extensions/** @nrwl/nx-angular-reviewers
|
||||
/packages/angular/plugins/component-testing.ts @nrwl/nx-angular-reviewers @nrwl/nx-testing-tools-reviewers
|
||||
/packages/angular/src/generators/cypress-component-configuration/** @nrwl/nx-angular-reviewers @nrwl/nx-testing-tools-reviewers
|
||||
/packages/angular/src/generators/component-test/** @nrwl/nx-angular-reviewers @nrwl/nx-testing-tools-reviewers
|
||||
|
||||
## React
|
||||
/docs/generated/packages/react/** @nrwl/nx-react-reviewers @nrwl/nx-docs-reviewers
|
||||
/docs/generated/packages/next/** @nrwl/nx-react-reviewers @nrwl/nx-docs-reviewers
|
||||
/docs/shared/packages/react/** @nrwl/nx-react-reviewers @nrwl/nx-docs-reviewers
|
||||
/docs/shared/packages/next/** @nrwl/nx-react-reviewers @nrwl/nx-docs-reviewers
|
||||
/packages/react/** @nrwl/nx-react-reviewers
|
||||
/e2e/react-core/** @nrwl/nx-react-reviewers
|
||||
/e2e/react-extensions/** @nrwl/nx-react-reviewers
|
||||
/packages/next/** @nrwl/nx-react-reviewers
|
||||
/e2e/next-core/** @nrwl/nx-react-reviewers
|
||||
/e2e/next-extensions/** @nrwl/nx-react-reviewers
|
||||
/packages/react/plugins/component-testing/** @nrwl/nx-react-reviewers @nrwl/nx-testing-tools-reviewers
|
||||
/packages/react/src/generators/cypress-component-configuration/** @nrwl/nx-react-reviewers @nrwl/nx-testing-tools-reviewers
|
||||
/packages/react/src/generators/component-test/** @nrwl/nx-react-reviewers @nrwl/nx-testing-tools-reviewers
|
||||
|
||||
# React Native
|
||||
/docs/generated/packages/detox/** @nrwl/nx-react-reviewers @nrwl/nx-docs-reviewers
|
||||
/docs/generated/packages/expo/** @nrwl/nx-react-reviewers @nrwl/nx-docs-reviewers
|
||||
/docs/generated/packages/react-native/** @nrwl/nx-react-reviewers @nrwl/nx-docs-reviewers
|
||||
/docs/shared/packages/react-native/** @nrwl/nx-react-reviewers @nrwl/nx-docs-reviewers
|
||||
/packages/detox/** @nrwl/nx-react-reviewers
|
||||
/e2e/detox/** @nrwl/nx-react-reviewers
|
||||
/packages/expo/** @nrwl/nx-react-reviewers
|
||||
/e2e/expo/** @nrwl/nx-react-reviewers
|
||||
/packages/react-native/** @nrwl/nx-react-reviewers
|
||||
/e2e/react-native/** @nrwl/nx-react-reviewers
|
||||
|
||||
# Vue
|
||||
/packages/vue/** @nrwl/nx-vue-reviewers
|
||||
/e2e/vue/** @nrwl/nx-vue-reviewers
|
||||
/packages/nuxt/** @nrwl/nx-vue-reviewers
|
||||
/e2e/nuxt/** @nrwl/nx-vue-reviewers
|
||||
|
||||
## Node
|
||||
/docs/generated/packages/node/** @nrwl/nx-node-reviewers @nrwl/nx-docs-reviewers
|
||||
/docs/generated/packages/nest/** @nrwl/nx-node-reviewers @nrwl/nx-docs-reviewers
|
||||
/docs/generated/packages/express/** @nrwl/nx-node-reviewers @nrwl/nx-docs-reviewers
|
||||
/docs/shared/packages/node/** @nrwl/nx-node-reviewers @nrwl/nx-docs-reviewers
|
||||
/docs/shared/packages/express/** @nrwl/nx-node-reviewers @nrwl/nx-docs-reviewers
|
||||
/docs/shared/packages/nest/** @nrwl/nx-node-reviewers @FrozenPandaz @nrwl/nx-docs-reviewers
|
||||
/packages/node/** @nrwl/nx-node-reviewers
|
||||
/packages/express/** @nrwl/nx-node-reviewers
|
||||
/packages/nest/** @nrwl/nx-node-reviewers
|
||||
/e2e/node/** @nrwl/nx-node-reviewers
|
||||
|
||||
## JS
|
||||
/docs/generated/packages/js/** @nrwl/nx-js-reviewers @nrwl/nx-docs-reviewers
|
||||
/docs/generated/packages/web/** @nrwl/nx-js-reviewers @nrwl/nx-docs-reviewers
|
||||
/docs/generated/packages/webpack/** @nrwl/nx-js-reviewers @nrwl/nx-docs-reviewers
|
||||
/docs/generated/packages/esbuild/** @nrwl/nx-js-reviewers @nrwl/nx-docs-reviewers
|
||||
/docs/generated/packages/rollup/** @nrwl/nx-js-reviewers @nrwl/nx-docs-reviewers
|
||||
/docs/generated/packages/vite/** @nrwl/nx-js-reviewers @nrwl/nx-docs-reviewers
|
||||
/docs/shared/packages/js/** @nrwl/nx-js-reviewers @nrwl/nx-docs-reviewers
|
||||
/docs/shared/packages/web/** @nrwl/nx-js-reviewers @nrwl/nx-docs-reviewers
|
||||
/docs/shared/packages/webpack/** @nrwl/nx-js-reviewers @nrwl/nx-docs-reviewers
|
||||
/docs/shared/packages/esbuild/** @nrwl/nx-js-reviewers @nrwl/nx-docs-reviewers
|
||||
/docs/shared/packages/vite/** @nrwl/nx-js-reviewers @nrwl/nx-docs-reviewers
|
||||
/packages/js/** @nrwl/nx-js-reviewers
|
||||
/e2e/js/** @nrwl/nx-js-reviewers
|
||||
/packages/web/** @nrwl/nx-js-reviewers
|
||||
/e2e/web/** @nrwl/nx-js-reviewers
|
||||
/packages/webpack/** @nrwl/nx-js-reviewers
|
||||
/packages/webpack/src/utils/module-federation @jaysoo @Coly010
|
||||
/e2e/webpack/** @nrwl/nx-js-reviewers
|
||||
/packages/esbuild/** @nrwl/nx-js-reviewers
|
||||
/e2e/esbuild/** @nrwl/nx-js-reviewers
|
||||
/packages/rollup/** @nrwl/nx-js-reviewers
|
||||
/e2e/rollup/** @nrwl/nx-js-reviewers
|
||||
/packages/vite/** @nrwl/nx-js-reviewers
|
||||
/e2e/vite/** @nrwl/nx-js-reviewers
|
||||
|
||||
## Tools
|
||||
/docs/generated/packages/cypress/** @nrwl/nx-testing-tools-reviewers @nrwl/nx-docs-reviewers
|
||||
/docs/generated/packages/jest/** @nrwl/nx-testing-tools-reviewers @nrwl/nx-docs-reviewers
|
||||
/docs/shared/packages/jest/** @nrwl/nx-testing-tools-reviewers @nrwl/nx-docs-reviewers
|
||||
/docs/shared/packages/cypress/** @nrwl/nx-testing-tools-reviewers @nrwl/nx-docs-reviewers
|
||||
/packages/cypress/** @nrwl/nx-testing-tools-reviewers
|
||||
/e2e/cypress/** @nrwl/nx-testing-tools-reviewers
|
||||
/packages/jest/** @nrwl/nx-testing-tools-reviewers
|
||||
/e2e/jest/** @nrwl/nx-testing-tools-reviewers
|
||||
/packages/playwright/** @nrwl/nx-testing-tools-reviewers
|
||||
/e2e/playwright/** @nrwl/nx-testing-tools-reviewers
|
||||
|
||||
# Linter
|
||||
/docs/generated/packages/eslint-plugin/** @nrwl/nx-linter-reviewers @nrwl/nx-docs-reviewers
|
||||
/docs/generated/packages/eslint/** @nrwl/nx-linter-reviewers @nrwl/nx-docs-reviewers
|
||||
/docs/shared/packages/eslint/** @nrwl/nx-linter-reviewers @nrwl/nx-docs-reviewers
|
||||
/packages/eslint-plugin/** @nrwl/nx-linter-reviewers
|
||||
/packages/eslint/** @nrwl/nx-linter-reviewers
|
||||
/e2e/eslint/** @nrwl/nx-linter-reviewers
|
||||
.eslint* @nrwl/nx-linter-reviewers
|
||||
|
||||
# Storybook
|
||||
/docs/generated/packages/storybook/** @nrwl/nx-storybook-reviewers @nrwl/nx-docs-reviewers
|
||||
/docs/shared/packages/storybook/** @nrwl/nx-storybook-reviewers @nrwl/nx-docs-reviewers
|
||||
/packages/storybook/** @nrwl/nx-storybook-reviewers
|
||||
/e2e/storybook/** @nrwl/nx-storybook-reviewers
|
||||
/e2e/storybook-angular/** @nrwl/nx-storybook-reviewers
|
||||
|
||||
## Devkit
|
||||
/docs/generated/devkit/** @nrwl/nx-devkit-reviewers @nrwl/nx-docs-reviewers
|
||||
/docs/generated/packages/devkit/** @nrwl/nx-devkit-reviewers @nrwl/nx-docs-reviewers
|
||||
/packages/devkit/** @nrwl/nx-devkit-reviewers
|
||||
/packages/devkit/index.ts @FrozenPandaz @vsavkin
|
||||
/packages/devkit/public-api.ts @FrozenPandaz @vsavkin
|
||||
/packages/devkit/nx.ts @FrozenPandaz @vsavkin
|
||||
|
||||
# Nx-Plugin
|
||||
/docs/generated/packages/plugin/** @nrwl/nx-devkit-reviewers @nrwl/nx-docs-reviewers
|
||||
/docs/shared/packages/plugin/** @nrwl/nx-devkit-reviewers @nrwl/nx-docs-reviewers
|
||||
/packages/plugin/** @nrwl/nx-devkit-reviewers
|
||||
/e2e/plugin/** @nrwl/nx-devkit-reviewers
|
||||
|
||||
## Core
|
||||
/docs/generated/cli/** @nrwl/nx-core-reviewers @nrwl/nx-docs-reviewers
|
||||
/docs/generated/packages/nx/** @nrwl/nx-core-reviewers @nrwl/nx-docs-reviewers
|
||||
/docs/generated/packages/workspace/** @nrwl/nx-core-reviewers @nrwl/nx-docs-reviewers
|
||||
/packages/nx/** @nrwl/nx-core-reviewers
|
||||
/packages/nx/src/adapter @nrwl/nx-core-reviewers @leosvelperez
|
||||
/packages/nx/src/native @nrwl/nx-core-reviewers @nrwl/nx-native-reviewers
|
||||
/packages/nx/src/plugins/js/lock-file @nrwl/nx-core-reviewers @meeroslav
|
||||
/packages/nx/src/command-line/init/implementation/angular/** @nrwl/nx-angular-reviewers @nrwl/nx-core-reviewers
|
||||
/e2e/nx-init/src/nx-init-angular.test.ts @nrwl/nx-angular-reviewers
|
||||
/packages/nx/src/command-line/init/implementation/react/** @nrwl/nx-react-reviewers
|
||||
/e2e/nx-init/src/nx-init-react.test.ts @nrwl/nx-react-reviewers
|
||||
/e2e/nx-init/src/files/cra/** @nrwl/nx-react-reviewers
|
||||
/e2e/nx*/** @nrwl/nx-core-reviewers
|
||||
/packages/workspace/** @nrwl/nx-core-reviewers
|
||||
/e2e/workspace-create/** @nrwl/nx-core-reviewers
|
||||
/e2e/workspace-create-npm/** @nrwl/nx-core-reviewers
|
||||
|
||||
# Misc
|
||||
/e2e/lerna-smoke-tests/** @vsavkin @JamesHenry
|
||||
/e2e/utils/** @meeroslav @nrwl/nx-testing-tools-reviewers @vsavkin @mandarini
|
||||
/community @nrwl/nx-docs-reviewers
|
||||
/CONTRIBUTING.md @FrozenPandaz @isaacplmann
|
||||
/CODE_OF_CONDUCT.md @FrozenPandaz @isaacplmann
|
||||
/CODEOWNERS @FrozenPandaz @AgentEnder
|
||||
|
||||
# Scripts
|
||||
/scripts/documentation @nrwl/nx-docs-reviewers
|
||||
/scripts/angular-support-upgrades @nrwl/nx-angular-reviewers
|
||||
|
||||
# CI
|
||||
/.circleci/** @nrwl/nx-pipelines-reviewers
|
||||
/.github/** @nrwl/nx-pipelines-reviewers
|
||||
/.husky/** @nrwl/nx-pipelines-reviewers
|
||||
/packages/workspace/src/generators/ci-workflow/** @nrwl/nx-pipelines-reviewers
|
||||
|
||||
# Global Files
|
||||
project.json @FrozenPandaz @vsavkin
|
||||
jest.config.ts @nrwl/nx-testing-tools-reviewers @FrozenPandaz
|
||||
jest.preset.js @nrwl/nx-testing-tools-reviewers @FrozenPandaz
|
||||
|
||||
# Overrides - These are applied last, so override any matches above.
|
||||
docs/generated/manifests/* @nrwl/nrwlians
|
||||
docs/generated/packages-metadata.json @FrozenPandaz @jaysoo @AgentEnder @nrwl/nx-docs-reviewers
|
||||
@@ -1,11 +0,0 @@
|
||||
# Contributor Code of Conduct
|
||||
|
||||
As contributors and maintainers of the Nx project, we pledge to respect everyone who contributes by posting issues, updating documentation, submitting pull requests, providing feedback in comments, and any other activities.
|
||||
|
||||
Communication through any of Nx's channels (GitHub, Gitter, Discord, IRC, mailing lists, Twitter, etc.) must be constructive and never resort to personal attacks, trolling, public or private harassment, insults, or other unprofessional conduct.
|
||||
|
||||
We promise to extend courtesy and respect to everyone involved in this project regardless of gender, gender identity, sexual orientation, disability, age, race, ethnicity, religion, or level of experience. We expect anyone contributing to the Nx project to do the same.
|
||||
|
||||
If any member of the community violates this code of conduct, the maintainers of the Nx project may take action, removing issues, comments, and PRs or blocking accounts as deemed appropriate.
|
||||
|
||||
If you are subject to or witness unacceptable behavior, or have any other concerns, please email us at conduct@nrwl.io.
|
||||
+60
-215
@@ -6,64 +6,40 @@ We would love for you to contribute to Nx! Read this document to see how to do i
|
||||
|
||||
Watch this 5-minute video:
|
||||
|
||||
<a href="https://www.youtube.com/watch?v=8LCA_4qxc08" target="_blank" rel="noreferrer">
|
||||
<a href="https://www.youtube.com/watch?v=o11p0zSm0No&feature=youtu.be" target="_blank">
|
||||
<p style="text-align: center;"><img src="https://raw.githubusercontent.com/nrwl/nx/master/images/how-to-contribute.png" width="600" alt="Nx - How to contribute"></p>
|
||||
</a>
|
||||
|
||||
## Got a Question?
|
||||
|
||||
We are trying to keep GitHub issues for bug reports and feature requests. Using the `nrwl` tag
|
||||
on [Stack Overflow](https://stackoverflow.com/questions/tagged/nrwl) is a much better place to ask general questions
|
||||
about how to use Nx.
|
||||
We are trying to keep GitHub issues for bug reports and feature requests. Using the `nrwl` tag on [Stack Overflow](https://stackoverflow.com/questions/tagged/nrwl) is a much better place to ask general questions about how to use Nx.
|
||||
|
||||
## Found an Issue?
|
||||
|
||||
If you find a bug in the source code or a mistake in the documentation, you can help us
|
||||
by [submitting an issue](https://github.com/nrwl/nx/blob/master/CONTRIBUTING.md#submit-issue)
|
||||
to [our GitHub Repository](https://github.com/nrwl/nx). Even better, you
|
||||
can [submit a Pull Request](https://github.com/nrwl/nx/blob/master/CONTRIBUTING.md#submit-pr) with a fix.
|
||||
If you find a bug in the source code or a mistake in the documentation, you can help us by [submitting an issue](https://github.com/nrwl/nx/blob/master/CONTRIBUTING.md#submit-issue) to [our GitHub Repository](https://github.com/nrwl/nx). Even better, you can [submit a Pull Request](https://github.com/nrwl/nx/blob/master/CONTRIBUTING.md#submit-pr) with a fix.
|
||||
|
||||
## Project Structure
|
||||
|
||||
Source code and documentation are included in the top-level folders listed below.
|
||||
|
||||
- `docs` - Markdown and configuration files for documentation including tutorials, guides for each supported platform,
|
||||
and API docs.
|
||||
- `docs` - Markdown and configuration files for documentation including tutorials, guides for each supported platform, and API docs.
|
||||
- `e2e` - E2E tests.
|
||||
- `packages` - Source code for Nx packages such as Angular, React, Web, NestJS, Next and others including generators and
|
||||
executors (or builders).
|
||||
- `packages` - Source code for Nx packages such as Angular, React, Web, NestJS, Next and others including generators and executors (or builders).
|
||||
- `scripts` - Miscellaneous scripts for project tasks such as building documentation, testing, and code formatting.
|
||||
- `tmp` - Folder used by e2e tests. If you are a WebStorm user, make sure to mark this folder as excluded.
|
||||
|
||||
## Development Workstation Setup
|
||||
|
||||
If you are using `VSCode`, and provided you have [Docker](https://docker.com) installed on your machine, then you can leverage [Dev Containers](https://containers.dev) through this [VSCode extension](https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.remote-containers), to easily setup your development environment, with everything needed to contribute to Nx, already installed (namely `NodeJS`, `Yarn`, `Rust`, `Cargo`, plus some useful extensions like `Nx Console`).
|
||||
|
||||
To do so, simply:
|
||||
|
||||
- Checkout the repo
|
||||
- Open it with VSCode
|
||||
- Open the [Command Palette](https://code.visualstudio.com/docs/getstarted/userinterface#_command-palette) and select "Dev Containers: Open Folder in Container..."
|
||||
|
||||
The repo comes with a preconfigured `devcontainer.json` file (located in `.devcontainer/` folder at root), that `VSCode` will automatically use to install the aforementioned tools, inside a Docker image. It will even run `pnpm install` for you, so you can start contributing to Nx right after.
|
||||
|
||||
If you open the repo in [Github Codespace](https://github.com/features/codespaces), it will also leverage this config file, to setup the codespace, with the same required tools.
|
||||
|
||||
## Building the Project
|
||||
|
||||
> Nx uses Rust to build native bindings for Node. Please make sure that you have Rust installed via [rustup.rs](https://rustup.rs)
|
||||
> If you have VSCode + Docker, this can be automated for you, see [section](#development-workstation-setup) above
|
||||
|
||||
After cloning the project to your machine, to install the dependencies, run:
|
||||
|
||||
```bash
|
||||
pnpm i
|
||||
yarn
|
||||
```
|
||||
|
||||
To build all the packages, run:
|
||||
|
||||
```bash
|
||||
pnpm build
|
||||
yarn build
|
||||
```
|
||||
|
||||
## Publishing to a local registry
|
||||
@@ -73,48 +49,26 @@ it can be useful to publish to a local registry.
|
||||
|
||||
Check out [this video for a live walkthrough](https://youtu.be/Tx257WpNsxc) or follow the instructions below:
|
||||
|
||||
- Run `pnpm local-registry` in Terminal 1 (keep it running)
|
||||
- Run `npm adduser --registry http://localhost:4873` in Terminal 2 (real credentials are not required, you just need to
|
||||
be logged in. You can use test/test/test@test.io.)
|
||||
- Run `pnpm nx-release 18.0.0 --local` in Terminal 2 - you can choose any nonexistent version number here, but it's recommended to use the next major
|
||||
- Run `cd ./tmp` in Terminal 2
|
||||
- Run `npx create-nx-workspace@18.0.0` in Terminal 2
|
||||
```bash
|
||||
# Starts the local registry. Keep this running in a separate terminal.
|
||||
yarn local-registry start
|
||||
|
||||
If you have problems publishing, make sure you use Node 18 and NPM 8.
|
||||
# Set npm and yarn to use the local registry.
|
||||
# Note: This reroutes your installs to your local registry
|
||||
yarn local-registry enable
|
||||
|
||||
**NOTE:** To use this newly published local version, you need to make a new workspace, run `nx migrate` or change all of your target packages to this new version, eg: `"nx": "^18.0.0",` and re-run `pnpm i` in your testing project.
|
||||
# Revert npm and yarn to use their default registries
|
||||
yarn local-registry disable
|
||||
```
|
||||
|
||||
### Publishing for Yarn 2+ (Berry)
|
||||
To publish packages to a local registry, do the following:
|
||||
|
||||
Yarn Berry operates slightly differently than Yarn Classic. In order to publish packages for Berry follow next steps:
|
||||
|
||||
- Run `yarn set version berry` to switch to latest Yarn version.
|
||||
- Create `.yarnrc.yml` in root with following contents:
|
||||
|
||||
```yml
|
||||
nodeLinker: node-modules
|
||||
npmRegistryServer: 'http://localhost:4873'
|
||||
unsafeHttpWhitelist:
|
||||
- localhost
|
||||
```
|
||||
|
||||
- Run `pnpm local-registry` in Terminal 1 (keep it running)
|
||||
- If you are creating nx workspace outside of your nx repo, make sure to add npm registry info to your root yarnrc (
|
||||
usually in ~/.yarnrc.yml). The file should look something like this:
|
||||
|
||||
```yml
|
||||
npmRegistries:
|
||||
'https://registry.yarnpkg.com':
|
||||
npmAuthToken: npm_******************
|
||||
yarnPath: .yarn/releases/yarn-3.2.2.cjs
|
||||
npmRegistryServer: 'http://localhost:4873'
|
||||
unsafeHttpWhitelist:
|
||||
- localhost
|
||||
```
|
||||
|
||||
- Run `pnpm nx-release minor --local` in Terminal 2 to publish next minor version. The output will report the version of published packages.
|
||||
- Go to your target folder (e.g. `cd ./tmp`) in Terminal 2
|
||||
- Run `yarn dlx create-nx-workspace@123.4.5` in Terminal 2 (replace `123.4.5` with the version that got published).
|
||||
- Run `yarn local-registry start` in Terminal 1 (keep it running)
|
||||
- Run `npm adduser --registry http://localhost:4873` in Terminal 2 (real credentials are not required, you just need to be logged in)
|
||||
- Run `yarn local-registry enable` in Terminal 2
|
||||
- Run `yarn nx-release 999.9.9 --local` in Terminal 2
|
||||
- Run `cd /tmp` in Terminal 2
|
||||
- Run `npx create-nx-workspace@999.9.9` in Terminal 2
|
||||
|
||||
### Running Unit Tests
|
||||
|
||||
@@ -132,157 +86,65 @@ nx test jest
|
||||
|
||||
### Running E2E Tests
|
||||
|
||||
**Use Node 18 and NPM 8. E2E tests won't work on Node 15 and NPM 7.**
|
||||
|
||||
To make sure your changes do not break any E2E tests, run:
|
||||
|
||||
```bash
|
||||
nx e2e e2e-vite # or any other project here
|
||||
nx e2e e2e-cli # or any other project here
|
||||
```
|
||||
|
||||
Running E2E tests can take some time, so it is often useful to run a single test. To run a single suite of tests, run:
|
||||
|
||||
```bash
|
||||
nx e2e e2e-vite -t versions # I often add qqqq to my test name so I can use -t qqqq
|
||||
nx e2e e2e-cli -t versions # I often add qqqq to my test name so I can use -t qqqq
|
||||
```
|
||||
|
||||
Sometimes tests pass locally but they fail on the CI. To reproduce the CI environment and be able to debug the issue, run:
|
||||
|
||||
```bash
|
||||
NX_VERBOSE_LOGGING=true CI=true SELECTED_PM=pnpm pnpm nx e2e e2e-vite --t="should do something is this test"
|
||||
```
|
||||
|
||||
The above command sets verbose logging (this exposes stack traces and underlying errors), sets the defaults to be CI-like and sets Pnpm as the selected package manager.
|
||||
|
||||
### Developing on Windows
|
||||
|
||||
To build Nx on Windows, you need to use WSL.
|
||||
|
||||
- Run `pnpm install` in WSL. Yarn will compile several dependencies. If you don't run `install` in WSL, they will be
|
||||
compiled for Windows.
|
||||
- Run `nx affected --target=test` and other commands in WSL.
|
||||
|
||||
## Documentation Contributions
|
||||
|
||||
We would love for you to contribute to our documentation as well! Please feel welcome to submit fixes or enhancements to
|
||||
our existing documentation pages and the `nx-dev` application in this repo.
|
||||
|
||||
### Documentation Structure
|
||||
|
||||
#### Documentation Pages
|
||||
|
||||
Our documentation pages can be found within this repo under the `docs` directory.
|
||||
|
||||
The `docs/map.json` file is considered our source of truth for our site's structure, and should be updated when adding a
|
||||
new page to our documentation to ensure that it is included in the documentation site. We also run automated scripts
|
||||
based on this `map.json` data to safeguard against common human errors that could break our site.
|
||||
|
||||
When you make a change to the `map.json` file, make sure to run `pnpm documentation` to propagate your changes to the `nx-dev` application.
|
||||
|
||||
#### Nx-Dev Application
|
||||
|
||||
Our public `nx.dev` documentation site is a [Next.js](https://nextjs.org/) application, that can be found in
|
||||
the `nx-dev` directory of this repo.
|
||||
The documentation site is consuming the `docs/` directly by copy-ing its content while deploying, so the website is
|
||||
always in sync and reflects the latest version of `docs/`.
|
||||
|
||||
Jump to [Running the Documentation Site Locally](#running-the-documentation-site-locally) to see how to preview your
|
||||
changes while serving.
|
||||
|
||||
### Changing Generated API documentation
|
||||
|
||||
`.md` files documenting the API for our CLI (including executor and generator API docs) are generated via the
|
||||
corresponding `schema.json` file for the given command.
|
||||
|
||||
After adjusting the `schema.json` file, `.md` files for these commands can be generated by running:
|
||||
|
||||
```bash
|
||||
pnpm documentation
|
||||
```
|
||||
|
||||
This will update the corresponding contents of the `docs` directory. These are generated automatically on push (via
|
||||
husky) as well.
|
||||
|
||||
Note that adjusting the `schema.json` files will also affect the CLI manuals and Nx Console behavior, in addition to
|
||||
adjusting the docs.
|
||||
|
||||
### Running the Documentation Site Locally
|
||||
|
||||
To run `nx-dev` locally, run the command:
|
||||
|
||||
```bash
|
||||
npx nx serve-docs nx-dev
|
||||
```
|
||||
|
||||
You can then access the application locally at `localhost:4200`. Changes to markdown documentation files will be automatically applied to the site when you refresh the browser.
|
||||
|
||||
#### Troubleshooting: `JavaScript heap out of memory`
|
||||
|
||||
If you see an error that states: `FATAL ERROR: Reached heap limit Allocation failed - JavaScript heap out of memory`,
|
||||
you need
|
||||
to [increase the max memory size of V8's old memory section](https://nodejs.org/api/cli.html#--max-old-space-sizesize-in-megabytes):
|
||||
|
||||
```bash
|
||||
export NODE_OPTIONS="--max-old-space-size=4096"
|
||||
```
|
||||
|
||||
After configuring this, try to run `npx nx serve nx-dev` again.
|
||||
|
||||
### PR Preview
|
||||
|
||||
When submitting a PR, this repo will automatically generate a preview of the `nx-dev` application based on the contents
|
||||
of your pull request.
|
||||
|
||||
Once the preview site is launched, a comment will automatically be added to your PR with the link your PR's preview. To
|
||||
check your docs changes, make sure to select `Preview` from the version selection box of the site.
|
||||
- Run `yarn install` in WSL. Yarn will compile several dependencies. If you don't run `install` in WSL, they will be compiled for Windows.
|
||||
- Run `yarn test` and other commands in WSL.
|
||||
|
||||
## Submission Guidelines
|
||||
|
||||
### <a name="submit-issue"></a> Submitting an Issue
|
||||
|
||||
Before you submit an issue, please search the issue tracker. An issue for your problem may already exist and has been
|
||||
resolved, or the discussion might inform you of workarounds readily available.
|
||||
Before you submit an issue, please search the issue tracker. An issue for your problem may already exist and has been resolved, or the discussion might inform you of workarounds readily available.
|
||||
|
||||
We want to fix all the issues as soon as possible, but before fixing a bug we need to reproduce and confirm it. Having a
|
||||
reproducible scenario gives us wealth of important information without going back and forth with you requiring
|
||||
additional information, such as:
|
||||
We want to fix all the issues as soon as possible, but before fixing a bug we need to reproduce and confirm it. Having a reproducible scenario gives us wealth of important information without going back and forth with you requiring additional information, such as:
|
||||
|
||||
- the output of `nx report`
|
||||
- `yarn.lock` or `package-lock.json` or `pnpm-lock.yaml`
|
||||
- `yarn.lock` or `package-lock.json`
|
||||
- and most importantly - a use-case that fails
|
||||
|
||||
A minimal reproduction allows us to quickly confirm a bug (or point out a coding problem) as well as confirm that we are
|
||||
fixing the right problem.
|
||||
A minimal reproduction allows us to quickly confirm a bug (or point out coding problem) as well as confirm that we are fixing the right problem.
|
||||
|
||||
We will be insisting on a minimal reproduction in order to save maintainers' time and ultimately be able to fix more
|
||||
bugs. Interestingly, from our experience, users often find coding problems themselves while preparing a minimal
|
||||
reproduction repository. We understand that sometimes it might be hard to extract essentials bits of code from a larger
|
||||
codebase, but we really need to isolate the problem before we can fix it.
|
||||
We will be insisting on a minimal reproduction in order to save maintainers time and ultimately be able to fix more bugs. Interestingly, from our experience, users often find coding problems themselves while preparing a minimal repository. We understand that sometimes it might be hard to extract essentials bits of code from a larger code-base but we really need to isolate the problem before we can fix it.
|
||||
|
||||
You can file new issues by filling out our [issue form](https://github.com/nrwl/nx/issues/new/choose).
|
||||
You can file new issues by filling out our [issue form](https://github.com/nrwl/nx/issues/new).
|
||||
|
||||
### <a name="submit-pr"></a> Submitting a PR
|
||||
|
||||
Please follow the following guidelines:
|
||||
|
||||
- Make sure unit tests pass (`nx affected --target=test`)
|
||||
- Make sure unit tests pass (`yarn test`)
|
||||
- Target a specific project with: `nx run proj:test` (i.e. `nx run angular:test` to target `packages/angular`)
|
||||
- Target a specific unit test file (i.e. `packages/angular/src/utils/ast-command-line-utils.spec.ts`)
|
||||
with `npx jest angular/src/utils/ast-utils` or `npx jest packages/angular/src/utils/ast-utils`
|
||||
- Target a specific unit test file (i.e. `packages/angular/src/utils/ast-utils.spec.ts`) with `npx jest angular/src/utils/ast-utils` or `npx jest packages/angular/src/utils/ast-utils`
|
||||
- For more options on running tests - check `npx jest --help` or visit [jestjs.io](https://jestjs.io/)
|
||||
- Debug with `node --inspect-brk ./node_modules/jest/bin/jest.js build/packages/angular/src/utils/ast-utils.spec.js`
|
||||
- Make sure e2e tests pass (this can take a while, so you can always let CI check those) (`nx affected --target=e2e`)
|
||||
- Target a specific e2e test with `nx e2e e2e-cypress`
|
||||
- Make sure you run `nx format`
|
||||
- Update documentation with `pnpm documentation`. For documentation, check for spelling and grammatical errors.
|
||||
- Update your commit message to follow the guidelines below (use `pnpm commit` to automate compliance)
|
||||
- `pnpm check-commit` will check to make sure your commit messages are formatted correctly
|
||||
- Make sure e2e tests pass (this can take a while, so you can always let CI check those) (`yarn e2e`)
|
||||
- Target a specific e2e test (i.e. `/build/e2e/cypress.test.js`) with `yarn e2e cypress`
|
||||
- Debug with `node --inspect-brk ./node_modules/jest/bin/jest.js build/e2e/cypress.test.js`
|
||||
- Make sure you run `yarn format`
|
||||
- Update documentation with `yarn documentation`. For documentation, check for spelling and grammatical errors.
|
||||
- Update your commit message to follow the guidelines below (use `yarn commit` to automate compliance)
|
||||
- `yarn check-commit` will check to make sure your commit messages are formatted correctly
|
||||
|
||||
#### Commit Message Guidelines
|
||||
|
||||
The commit message should follow the following format:
|
||||
|
||||
```plain
|
||||
```
|
||||
type(scope): subject
|
||||
BLANK LINE
|
||||
body
|
||||
@@ -292,59 +154,43 @@ body
|
||||
|
||||
The type must be one of the following:
|
||||
|
||||
- feat - New or improved behavior being introduced (e.g. Updating to new versions of React or Jest which bring in new
|
||||
features)
|
||||
- fix - Fixes the current unexpected behavior to match expected behavior (e.g. Fixing the library generator to create
|
||||
the proper named project)
|
||||
- cleanup - Code Style changes that have little to no effect on the user (e.g. Refactoring some functions into a
|
||||
different file)
|
||||
- docs - Changes to the documentation (e.g. Adding more details into the getting started guide)
|
||||
- chore - Changes that have absolutely no effect on users (e.g. Updating the version of Nx used to build the repo)
|
||||
- chore
|
||||
- feat
|
||||
- fix
|
||||
- cleanup
|
||||
- docs
|
||||
|
||||
##### Scope
|
||||
|
||||
The scope must be one of the following:
|
||||
|
||||
- angular - anything Angular specific
|
||||
- bundling - anything bundling specific (e.g. rollup, webpack, etc.)
|
||||
- core - anything Nx core specific
|
||||
- detox - anything Detox specific
|
||||
- devkit - devkit-related changes
|
||||
- graph - anything graph app specific
|
||||
- expo - anything Expo specific
|
||||
- express - anything Express specific
|
||||
- js - anything related to @nx/js package or general js/ts support
|
||||
- linter - anything Linter specific
|
||||
- nest - anything Nest specific
|
||||
- nxdev - anything related to docs infrastructure
|
||||
- nextjs - anything Next specific
|
||||
- nest - anything Nest specific
|
||||
- node - anything Node specific
|
||||
- nx-cloud - anything NxCloud specific
|
||||
- nx-plugin - anything Nx Plugin specific
|
||||
- nx-dev - anything related to docs infrastructure
|
||||
- linter - anything Linter specific
|
||||
- react - anything React specific
|
||||
- react-native - anything React Native specific
|
||||
- repo - anything related to managing the Nx repo itself
|
||||
- storybook - anything Storybook specific
|
||||
- testing - anything testing specific (e.g., Jest or Cypress)
|
||||
- vite - anything Vite specific
|
||||
- vue - anything Vue specific
|
||||
- web - anything Web specific
|
||||
- webpack - anything Webpack specific
|
||||
- storybook - anything Storybook specific
|
||||
- testing - anything testing specific (e.g., jest or cypress)
|
||||
- repo - anything related to managing the repo itself
|
||||
- misc - misc stuff
|
||||
- devkit - devkit-related changes
|
||||
|
||||
##### Subject and Body
|
||||
|
||||
The subject must contain a description of the change, and the body of the message contains any additional details to
|
||||
provide more context about the change.
|
||||
The subject must contain a description of the change, and the body of the message contains any additional details to provide more context about the change.
|
||||
|
||||
Including the issue number that the PR relates to also helps with tracking.
|
||||
|
||||
#### Example
|
||||
|
||||
```plain
|
||||
feat(angular): add an option to generate lazy-loadable modules
|
||||
```
|
||||
feat(generators): add an option to generate lazy-loadable modules
|
||||
|
||||
`nx generate lib mylib --lazy` provisions the mylib project in .eslintrc.json
|
||||
`nx generate lib mylib --lazy` provisions the mylib project in tslint.json
|
||||
|
||||
Closes #157
|
||||
```
|
||||
@@ -352,5 +198,4 @@ Closes #157
|
||||
#### Commitizen
|
||||
|
||||
To simplify and automate the process of committing with this format,
|
||||
**Nx is a [Commitizen](https://github.com/commitizen/cz-cli) friendly repository**, just do `git add` and
|
||||
execute `pnpm commit`.
|
||||
**Nx is a [Commitizen](https://github.com/commitizen/cz-cli) friendly repository**, just do `git add` and execute `yarn commit`.
|
||||
|
||||
Generated
-2702
File diff suppressed because it is too large
Load Diff
@@ -1,9 +0,0 @@
|
||||
|
||||
[workspace]
|
||||
resolver = '2'
|
||||
members = [
|
||||
'packages/nx',
|
||||
]
|
||||
|
||||
[profile.release]
|
||||
lto = true
|
||||
@@ -1,22 +1,22 @@
|
||||
(The MIT License)
|
||||
|
||||
Copyright (c) 2017-2023 Narwhal Technologies Inc.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
'Software'), to deal in the Software without restriction, including
|
||||
without limitation the rights to use, copy, modify, merge, publish,
|
||||
distribute, sublicense, and/or sell copies of the Software, and to
|
||||
permit persons to whom the Software is furnished to do so, subject to
|
||||
the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
(The MIT License)
|
||||
|
||||
Copyright (c) 2017-2021 Narwhal Technologies Inc.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
'Software'), to deal in the Software without restriction, including
|
||||
without limitation the rights to use, copy, modify, merge, publish,
|
||||
distribute, sublicense, and/or sell copies of the Software, and to
|
||||
permit persons to whom the Software is furnished to do so, subject to
|
||||
the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
@@ -1,79 +1,219 @@
|
||||
<p style="text-align: center;">
|
||||
<picture>
|
||||
<source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/nrwl/nx/master/images/nx-dark.svg">
|
||||
<img alt="Nx - Smart, Fast and Extensible Build System" src="https://raw.githubusercontent.com/nrwl/nx/master/images/nx-light.svg" width="100%">
|
||||
</picture>
|
||||
</p>
|
||||
<p style="text-align: center;"><img src="https://raw.githubusercontent.com/nrwl/nx/master/images/nx.png" width="600" alt="Nx - Powerful, Extensible Dev Tools"></p>
|
||||
|
||||
<div style="text-align: center;">
|
||||
|
||||
[](https://circleci.com/gh/nrwl/nx)
|
||||
[]()
|
||||
[](https://www.npmjs.com/package/nx)
|
||||
[]()
|
||||
[](https://www.npmjs.com/@nrwl/workspace)
|
||||
[]()
|
||||
[](http://commitizen.github.io/cz-cli/)
|
||||
[](https://gitter.im/nrwl-nx/community?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
|
||||
[](https://go.nx.dev/community)
|
||||
[](http://go.nrwl.io/join-slack)
|
||||
|
||||
</div>
|
||||
|
||||
<hr>
|
||||
|
||||
# Smart, Fast and Extensible Build System
|
||||
# What is Nx?
|
||||
|
||||
Nx is a next generation build system with first class monorepo support and powerful integrations.
|
||||
🔎 **Powerful, Extensible Dev Tools.**
|
||||
|
||||
A few links to help you get started:
|
||||
## Nx Helps You
|
||||
|
||||
- [Nx.Dev: Documentation, Guides, Interactive Tutorials](https://nx.dev)
|
||||
- [Nx.Dev: Core Tutorials](https://nx.dev/getting-started/intro)
|
||||
- [Recipe: Adding Nx to an Existing Monorepo](https://nx.dev/recipes/adopting-nx/adding-to-monorepo)
|
||||
- [Official Nx YouTube Channel](https://www.youtube.com/@NxDevtools)
|
||||
- [Blog Posts About Nx](https://blog.nrwl.io/nx/home)
|
||||
### Develop like Google, Facebook, and Microsoft
|
||||
|
||||
<p style="text-align: center;"><a href="https://nx.dev/#learning-materials" target="_blank" rel="noreferrer"><img src="./images/nx-courses-and-videos.svg"
|
||||
width="100%" alt="Nx - Smart, Fast and Extensible Build System"></a></p>
|
||||
Nx helps scale your development from one team building one application to many teams building multiple frontend and backend applications all in the same workspace. When using Nx, developers have a holistic dev experience powered by an advanced CLI (with editor plugins), capabilities for controlled code sharing and consistent code generation.
|
||||
|
||||
# Engage with the Core Team and the Community
|
||||
### Use Intelligent Build System with Distributed Caching
|
||||
|
||||
- [Nx.Dev Community Page: Community Discord Channel, Newsletter, etc.](https://nx.dev/community)
|
||||
- [The Nx Show Playlist on YouTube](https://www.youtube.com/playlist?list=PLakNactNC1dE8KLQ5zd3fQwu_yQHjTmR5). It's a
|
||||
regular YouTube stream where we talk all things Nx. Join the stream, ask questions, etc.
|
||||
- [Follow Nx on Twitter](https://twitter.com/NxDevTools)
|
||||
Nx is smart. It analyzes your workspace and figures out what can be affected by every code change. That's why Nx doesn't rebuild and retest everything on every commit--it only rebuilds what is necessary.
|
||||
|
||||
Nx also uses a distributed computation cache. If someone has already built or tested similar code, Nx will use their results to speed up the command for everyone else instead of rebuilding or retesting the code from scratch. This, in combination with Nx’s support for distributed and incremental builds, can help teams see up to 10x reduction in build and test times.
|
||||
|
||||
### Use Modern Tools
|
||||
|
||||
Nx is an open platform with plugins for many modern tools and frameworks. It has support for TypeScript, React, Angular, Cypress, Jest, Prettier, Nest.js, Next.js, Storybook, Ionic among others. With Nx, you get a consistent dev experience regardless of the tools used.
|
||||
|
||||
# Getting Started
|
||||
|
||||
## Creating an Nx Workspace
|
||||
|
||||
**Using `npx`**
|
||||
|
||||
```bash
|
||||
npx create-nx-workspace
|
||||
```
|
||||
|
||||
**Using `npm init`**
|
||||
|
||||
```bash
|
||||
npm init nx-workspace
|
||||
```
|
||||
|
||||
**Using `yarn create`**
|
||||
|
||||
```bash
|
||||
yarn create nx-workspace
|
||||
```
|
||||
|
||||
The `create-nx-workspace` command will ask you to select a preset, which will configure some plugins and create your applications to help you get started.
|
||||
|
||||
```
|
||||
? What to create in the new workspace (Use arrow keys)
|
||||
❯ empty [an empty workspace with a layout that works best for building apps]
|
||||
oss [an empty workspace with a layout that works best for open-source projects]
|
||||
web components [a workspace with a single app built using web components]
|
||||
angular [a workspace with a single Angular application]
|
||||
angular-nest [a workspace with a full stack application (Angular + Nest)]
|
||||
react [a workspace with a single React application]
|
||||
react-express [a workspace with a full stack application (React + Express)]
|
||||
next.js [a workspace with a single Next.js application]
|
||||
```
|
||||
|
||||
Select the preset that works best for you. You can always add plugins later.
|
||||
|
||||
```
|
||||
? Workspace name (e.g., org name) happyorg
|
||||
? What to create in the new workspace web components [a workspace with a single app built using web components]
|
||||
? Application name myapp
|
||||
? Default stylesheet format CSS
|
||||
```
|
||||
|
||||
If it's your first Nx project, the command will recommend you to install the `nx` package globally, so you can invoke `nx` directly without going through yarn or npm.
|
||||
|
||||
## Serving Application
|
||||
|
||||
- Run `nx serve myapp` to serve the newly generated application!
|
||||
- Run `nx test myapp` to test it.
|
||||
- Run `nx e2e myapp-e2e` to run e2e tests for it.
|
||||
|
||||
Angular users can also run `ng g/serve/test/e2e`.
|
||||
|
||||
You are good to go!
|
||||
|
||||
## Resources
|
||||
|
||||
### Documentation
|
||||
|
||||
- [Nx Documentation and Guides](https://nx.dev)
|
||||
|
||||
### Quick Start Videos
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<td>
|
||||
<a href="https://www.youtube.com/watch?v=mVKMse-gFBI" target="_blank">
|
||||
<p style="text-align: center;">Angular<br><img src="https://raw.githubusercontent.com/nrwl/nx/master/images/nx-angular-video.png" width="350" alt="Nx - Quick Start Video for Angular"></p>
|
||||
</a>
|
||||
</td>
|
||||
<td>
|
||||
<a href="https://www.youtube.com/watch?v=E188J7E_MDU" target="_blank">
|
||||
<p style="text-align: center;">React<br><img src="https://raw.githubusercontent.com/nrwl/nx/master/images/nx-react-video.png" width="350" alt="Nx - Quick Start Video for React"></p>
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
### Courses
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<td><strong>Scale React Development with Nx</strong></td>
|
||||
<td><strong>Nx Workspaces</strong></td>
|
||||
<td><strong>Advanced Nx Workspaces</strong></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<a href="https://egghead.io/playlists/scale-react-development-with-nx-4038" target="_blank">
|
||||
<p style="text-align: center;"><img src="https://raw.githubusercontent.com/nrwl/nx/master/images/EGH_ScalingReactNx.png" height="150px" alt="Nx - Scale React Development with Nx video course"></p>
|
||||
</a>
|
||||
</td>
|
||||
<td>
|
||||
<a href="https://www.youtube.com/watch?v=2mYLe9Kp9VM&list=PLakNactNC1dH38AfqmwabvOszDmKriGco" target="_blank">
|
||||
<p style="text-align: center;"><img src="https://raw.githubusercontent.com/nrwl/nx/master/images/nx-workspace-course.png" width="350" alt="Nx Workspaces video course"></p>
|
||||
</a>
|
||||
</td>
|
||||
<td>
|
||||
<a href="https://nxplaybook.com/p/advanced-nx-workspaces" target="_blank">
|
||||
<p style="text-align: center;"><img src="https://raw.githubusercontent.com/nrwl/nx/master/images/advanced-nx-workspace-course.png" width="350" alt="Nx Advanced Workspaces video course"></p>
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
### Nx Demo & Tutorial Videos
|
||||
|
||||
- [Nx Dev Tools for Monorepos, In-Depth Explainer (React)](https://www.youtube.com/watch?v=jCf92IyR-GE)
|
||||
|
||||
- [Nx Dev Tools for Monorepos, In-Depth Explainer (Angular)](https://youtu.be/h5FIGDn5YM0)
|
||||
|
||||
- [Storybook Integration with Nx](https://youtu.be/sFpqyjT7u4s)
|
||||
|
||||
- [Building Custom Plugins for Nx](https://youtu.be/XYO689PAhow)
|
||||
|
||||
- [Improved Dependency Graph Visualization for Nx](https://youtu.be/cMZ-ReC-jWU)
|
||||
|
||||
- [Group all your stories into a single viewable Storybook with Nx](https://youtu.be/c323HOuFKkA)
|
||||
|
||||
- [Debug Nx with Node and VSCode](https://youtu.be/OGV4R0cPRPc)
|
||||
|
||||
- [Debug your Jest tests in Nx with VSCode](https://youtu.be/9_lgM2nokLg)
|
||||
|
||||
- [Nx Console - A Must-Have Visual Studio Code Extension for Angular Developers](https://youtu.be/IIetmfgozgI)
|
||||
|
||||
- [Introducing Nx Cloud](https://youtu.be/pwG20nNTEQc)
|
||||
|
||||
- [Setting up distributed caching using Nx Cloud, @nrwl/nx-cloud](https://youtu.be/w1-GiB74ddc)
|
||||
|
||||
- [High Quality React apps with Nx & Cypress](https://youtu.be/mfJBLhjYMdo)
|
||||
|
||||
### Books and Blogs
|
||||
|
||||
- [Nx blog posts](https://blog.nrwl.io/nx/home)
|
||||
|
||||
- [Angular Enterprise Monorepo Patterns Book (free)](https://go.nrwl.io/angular-enterprise-monorepo-patterns-new-book?utm_campaign=Book%3A%20Monorepo%20Patterns%2C%20Jan%202019&utm_source=Github&utm_medium=Banner%20Ad)
|
||||
|
||||
- [High Quality React apps with Nx & Cypress](https://cypress.io/blog/2020/04/14/high-quality-react-apps-with-nx-cypress/) (April 2020)
|
||||
|
||||
- [Shell Library patterns with Nx and Monorepo Architectures](https://indepth.dev/the-shell-library-patterns-with-nx-and-monorepo-architectures/) (March 2020)
|
||||
|
||||
- [Tiny Angular application projects in Nx workspaces](https://indepth.dev/tiny-angular-application-projects-in-nx-workspaces/#peer-reviewers--30/) (March 2020)
|
||||
|
||||
### Additional Resources
|
||||
|
||||
- [nx-examples](https://github.com/nrwl/nx-examples) repo has branches for different nx comments to display expected behavior and example app and libraries. Check out the branch (workspace, ngrx...) to see what gets created for you. More info on readme.
|
||||
|
||||
- [xplat - Cross-platform tools for Nx workspaces](https://nstudio.io/xplat/)
|
||||
- [Nrwl Talks, Presentations, and Podcasts playlist on YouTube](https://www.youtube.com/playlist?list=PLakNactNC1dHHWx4JIORwfnEajRv6FG5m)
|
||||
|
||||
- [Nx Office Hours playlist on YouTube](https://www.youtube.com/playlist?list=PLakNactNC1dE8KLQ5zd3fQwu_yQHjTmR5)
|
||||
|
||||
## Want to help?
|
||||
|
||||
If you want to file a bug or submit a PR, read up on
|
||||
our [guidelines for contributing](https://github.com/nrwl/nx/blob/master/CONTRIBUTING.md) and watch this video that will
|
||||
help you get started.
|
||||
If you want to file a bug or submit a PR, read up on our [guidelines for contributing](https://github.com/nrwl/nx/blob/master/CONTRIBUTING.md) and watch this video that will help you get started.
|
||||
|
||||
<a href="https://www.youtube.com/watch?v=8LCA_4qxc08" target="_blank" rel="noreferrer">
|
||||
<a href="https://www.youtube.com/watch?v=o11p0zSm0No&feature=youtu.be" target="_blank">
|
||||
<p style="text-align: center;"><img src="https://raw.githubusercontent.com/nrwl/nx/master/images/how-to-contribute.png" width="600" alt="Nx - How to contribute video"></p>
|
||||
</a>
|
||||
|
||||
## Core Team
|
||||
|
||||
| Victor Savkin | Jason Jean | Benjamin Cabanes | Jack Hsu |
|
||||
| ---------------------------------------------------------------------- | --------------------------------------------------------------------- | --------------------------------------------------------------------------- | ----------------------------------------------------------------- |
|
||||
|  |  |  |  |
|
||||
| [vsavkin](https://github.com/vsavkin) | [FrozenPandaz](https://github.com/FrozenPandaz) | [bcabanes](https://github.com/bcabanes) | [jaysoo](https://github.com/jaysoo) |
|
||||
| Victor Savkin | Jason Jean | Benjamin Cabanes | Brandon Roberts |
|
||||
| ---------------------------------------------------------------------- | --------------------------------------------------------------------- | --------------------------------------------------------------------------- | ------------------------------------------------------------------------ |
|
||||
|  |  |  |  |
|
||||
| [vsavkin](https://github.com/vsavkin) | [FrozenPandaz](https://github.com/FrozenPandaz) | [bcabanes](https://github.com/bcabanes) | [brandonroberts](https://github.com/brandonroberts) |
|
||||
|
||||
| Jo Hanna Pearce | Jon Cammisuli | Isaac Mann | Juri Strumpflohner |
|
||||
| ------------------------------------------------------------------------- | ------------------------------------------------------------------------ | -------------------------------------------------------------------- | ---------------------------------------------------------------------------- |
|
||||
|  |  |  |  |
|
||||
| [jdpearce](https://github.com/jdpearce) | [cammisuli](https://github.com/cammisuli) | [isaacplmann](https://github.com/isaacplmann) | [juristr](https://github.com/juristr) |
|
||||
| Jack Hsu | Jo Hanna Pearce | Jon Cammisuli | Isaac Mann |
|
||||
| --------------------------------------------------------------------- | ----------------------------------------------------------------------------- | ---------------------------------------------------------------------------- | -------------------------------------------------------------------- |
|
||||
|  |  |  |  |
|
||||
| [jaysoo](https://github.com/jaysoo) | [jdpearce](https://github.com/jdpearce) | [cammisuli](https://github.com/cammisuli) | [isaacplmann](https://github.com/isaacplmann) |
|
||||
|
||||
| Philip Fulcher | Caleb Ukle | Katerina Skroumpelou | Colum Ferry |
|
||||
| ------------------------------------------------------------------------- | --------------------------------------------------------------------- | ------------------------------------------------------------------------------- | ---------------------------------------------------------------------- |
|
||||
|  |  |  |  |
|
||||
| [philipjfulcher](https://github.com/philipjfulcher) | [barbados-clemens](https://github.com/barbados-clemens) | [mandarini](https://github.com/mandarini) | [Coly010](https://github.com/Coly010) |
|
||||
| Tasos Bekos | Juri Strumpflohner | Philip Fulcher | Katerina Skroumpelou |
|
||||
| ------------------------------------------------------------------------ | -------------------------------------------------------------------------------- | ------------------------------------------------------------------------- | ----------------------------------------------------------------------------------- |
|
||||
|  |  |  |  |
|
||||
| [bekos](https://github.com/bekos) | [juristr](https://github.com/juristr) | [philipjfulcher](https://github.com/philipjfulcher) | [mandarini](https://github.com/mandarini) |
|
||||
|
||||
| Emily Xiong | Miroslav Jonaš | Leosvel Pérez Espinosa | Zachary DeRose |
|
||||
| ---------------------------------------------------------------------- | ----------------------------------------------------------------------- | --------------------------------------------------------------------------------- | ------------------------------------------------------------------------ |
|
||||
|  |  |  |  |
|
||||
| [xiongemi](https://github.com/xiongemi) | [meeroslav](https://github.com/meeroslav) | [leosvelperez](https://github.com/leosvelperez) | [ZackDeRose](https://github.com/ZackDeRose) |
|
||||
|
||||
| Craigory Coppola | Chau Tran | Nicholas Cunningham |
|
||||
| -------------------------------------------------------------------------- | -------------------------------------------------------------------- | ---------------------------------------------------------------------------- |
|
||||
|  |  |  |
|
||||
| [AgentEnder](https://github.com/AgentEnder) | [nartc](https://github.com/nartc) | [ndcunningham](https://github.com/ndcunningham) |
|
||||
| Kirils Ladovs |
|
||||
| --------------------------------------------------------------------------- |
|
||||
|  |
|
||||
| [kirjai](https://github.com/kirjai) |
|
||||
|
||||
+43
-318
@@ -1,54 +1,4 @@
|
||||
[
|
||||
{
|
||||
"name": "@ahryman40k/nx-vitepress",
|
||||
"description": "Nx plugin add vitepress project to your workspace",
|
||||
"url": "https://github.com/Ahryman40k/nx-vitepress/tree/main/packages/nx-vitepress"
|
||||
},
|
||||
{
|
||||
"name": "@nightwatch/nx",
|
||||
"description": "The NightwatchJS plugin allows your workspace to use the power of NightwatchJS for E2E and Component Testing on Desktop and Mobile",
|
||||
"url": "https://github.com/nightwatchjs/nightwatch-plugin-nx/"
|
||||
},
|
||||
{
|
||||
"name": "@nxkit/playwright",
|
||||
"description": "The Playwright plugin allows your workspace to use the power of Playwright end-to-end testing",
|
||||
"url": "https://github.com/nxkit/nxkit"
|
||||
},
|
||||
{
|
||||
"name": "qwik-nx",
|
||||
"description": "Get first class support for Qwik inside of Nx monorepos with Qwik optimized custom executors, generators and a vite plugin",
|
||||
"url": "https://github.com/qwikifiers/qwik-nx"
|
||||
},
|
||||
{
|
||||
"name": "@nxkit/style-dictionary",
|
||||
"description": "Nx plugin to generate and build Style Dictionary projects inside your Nx workspace",
|
||||
"url": "https://github.com/nxkit/nxkit"
|
||||
},
|
||||
{
|
||||
"name": "nx-plugin-vite",
|
||||
"description": "Nx plugin integrations with Vite.",
|
||||
"url": "https://nx-plugins.netlify.app/"
|
||||
},
|
||||
{
|
||||
"name": "@ago-dev/nx-aws-cdk-v2",
|
||||
"description": "An nx plugin for the aws-cdk v2.",
|
||||
"url": "https://github.com/adrian-goe/nx-aws-cdk-v2"
|
||||
},
|
||||
{
|
||||
"name": "@berenddeboer/nx-aws-cdk",
|
||||
"description": "Nx plugin to generate a CDK stack with support for the vitest runner. Supports all CDK commands.",
|
||||
"url": "https://github.com/berenddeboer/nx-plugins/tree/main/packages/nx-aws-cdk"
|
||||
},
|
||||
{
|
||||
"name": "@berenddeboer/nx-sst",
|
||||
"description": "Nx plugin to generate an SST stack and execute all SST commands.",
|
||||
"url": "https://github.com/berenddeboer/nx-plugins/tree/main/packages/nx-sst"
|
||||
},
|
||||
{
|
||||
"name": "@rxap/plugin-localazy",
|
||||
"description": "An Nx plugin for localazy.com upload and download tasks.",
|
||||
"url": "https://gitlab.com/rxap/plugins/-/tree/master/libs/localazy"
|
||||
},
|
||||
{
|
||||
"name": "nx-electron",
|
||||
"description": "An Nx plugin for developing Electron applications",
|
||||
@@ -60,25 +10,35 @@
|
||||
"url": "https://github.com/Phillip9587/nx-stylelint"
|
||||
},
|
||||
{
|
||||
"name": "@nxext/ionic-react",
|
||||
"name": "@nxtend/ionic-react",
|
||||
"description": "An Nx plugin for developing Ionic React applications and libraries",
|
||||
"url": "https://github.com/nxext/nx-extensions/tree/main/packages/ionic-react"
|
||||
"url": "https://github.com/nxtend-team/nxtend/tree/main/packages/ionic-react"
|
||||
},
|
||||
{
|
||||
"name": "@nxext/ionic-angular",
|
||||
"name": "@nxtend/ionic-angular",
|
||||
"description": "An Nx plugin for developing Ionic Angular applications and libraries",
|
||||
"url": "https://github.com/nxext/nx-extensions/tree/main/packages/ionic-angular"
|
||||
"url": "https://github.com/nxtend-team/nxtend/tree/main/packages/ionic-angular"
|
||||
},
|
||||
{
|
||||
"name": "@nxext/capacitor",
|
||||
"name": "@nxtend/capacitor",
|
||||
"description": "An Nx plugin for developing cross-platform applications using Capacitor",
|
||||
"url": "https://github.com/nxext/nx-extensions/tree/main/packages/capacitor"
|
||||
"url": "https://github.com/nxtend-team/nxtend/tree/main/packages/capacitor"
|
||||
},
|
||||
{
|
||||
"name": "@nxtend/firebase",
|
||||
"description": "An Nx plugin for developing applications using Firebase",
|
||||
"url": "https://github.com/nxtend-team/nxtend/tree/main/packages/firebase"
|
||||
},
|
||||
{
|
||||
"name": "@angular-architects/ddd",
|
||||
"description": "Nx plugin for structuring a monorepo with domains and layers",
|
||||
"url": "https://github.com/angular-architects/nx-ddd-plugin"
|
||||
},
|
||||
{
|
||||
"name": "@offeringsolutions/nx-karma-to-jest",
|
||||
"description": "Nx plugin for replacing karma with jest in an Nx workspace",
|
||||
"url": "https://github.com/FabianGosebrink/nx-karma-to-jest"
|
||||
},
|
||||
{
|
||||
"name": "@flowaccount/nx-serverless",
|
||||
"description": "Nx plugin for node/angular-universal schematics and deployment builders in an Nx workspace",
|
||||
@@ -95,9 +55,24 @@
|
||||
"url": "https://github.com/Bielik20/nx-plugins/tree/master/packages/nx-jest-playwright"
|
||||
},
|
||||
{
|
||||
"name": "@ns3/nx-playwright",
|
||||
"description": "Nx plugin to run playwright e2e tests in an Nx workspace",
|
||||
"url": "https://github.com/Bielik20/nx-plugins/tree/master/packages/nx-playwright"
|
||||
"name": "@dev-thought/nx-deploy-it",
|
||||
"description": "Nx plugin to deploy applications on your favorite cloud provider",
|
||||
"url": "https://github.com/Dev-Thought/nx-plugins/tree/master/libs/nx-deploy-it"
|
||||
},
|
||||
{
|
||||
"name": "@offeringsolutions/nx-protractor-to-cypress",
|
||||
"description": "Nx plugin to replace protractor with cypress in an nx workspace",
|
||||
"url": "https://github.com/FabianGosebrink/nx-protractor-to-cypress"
|
||||
},
|
||||
{
|
||||
"name": "@nx-tools/nx-docker",
|
||||
"description": "Nx plugin to build docker images of your affected apps",
|
||||
"url": "https://github.com/gperdomor/nx-tools/tree/main/packages/nx-docker"
|
||||
},
|
||||
{
|
||||
"name": "@angular-custom-builders/lite-serve",
|
||||
"description": "Nx plugin to run the e2e test on an existing dist folder",
|
||||
"url": "https://github.com/mauriziovitale/angular-plugins/tree/master/libs/lite-serve"
|
||||
},
|
||||
{
|
||||
"name": "@nx-plus/nuxt",
|
||||
@@ -119,16 +94,6 @@
|
||||
"description": "Nx Plugin to integrate the generation of documentation with Compodoc in the Nx workflow",
|
||||
"url": "https://github.com/twittwer/nx-tools/tree/master/libs/compodoc#readme"
|
||||
},
|
||||
{
|
||||
"name": "@enio.ai/nx-install",
|
||||
"description": "nx-install is a plugin for Nx workspaces to quickly setup custom install commands via npm.",
|
||||
"url": "https://github.com/enio-ireland/enio/tree/develop/packages/nx-install#readme"
|
||||
},
|
||||
{
|
||||
"name": "@enio.ai/typedoc",
|
||||
"description": "typedoc is a plugin for Nx workspaces to quickly setup documentation automation on your projects using typedoc.",
|
||||
"url": "https://github.com/enio-ireland/enio/tree/develop/packages/typedoc#readme"
|
||||
},
|
||||
{
|
||||
"name": "@nxext/svelte",
|
||||
"description": "Nx plugin to use Svelte within nx workspaces",
|
||||
@@ -140,25 +105,15 @@
|
||||
"url": "https://github.com/nxext/nx-extensions/tree/master/packages/stencil"
|
||||
},
|
||||
{
|
||||
"name": "@nxext/vue",
|
||||
"description": "Nx plugin to use VueJS 3 within nx workspaces",
|
||||
"url": "https://github.com/nxext/nx-extensions/tree/master/packages/vue"
|
||||
},
|
||||
{
|
||||
"name": "@nxext/solid",
|
||||
"description": "Nx plugin to use SolidJS within nx workspaces",
|
||||
"url": "https://github.com/nxext/nx-extensions/tree/master/packages/solid"
|
||||
"name": "@joelcode/gcp-function",
|
||||
"description": "Nx plugin to generate, test, lint, build, serve, & deploy Google Cloud Function",
|
||||
"url": "https://github.com/JoelCode/gcp-function"
|
||||
},
|
||||
{
|
||||
"name": "@nx-go/nx-go",
|
||||
"description": "Nx plugin to use Go in a Nx workspace",
|
||||
"url": "https://github.com/nx-go/nx-go"
|
||||
},
|
||||
{
|
||||
"name": "@nx-golang/gin",
|
||||
"description": "Nx plugin to use Go-Gin in a Nx workspace",
|
||||
"url": "https://github.com/nx-golang/nx-golang"
|
||||
},
|
||||
{
|
||||
"name": "@angular-architects/module-federation",
|
||||
"description": "Nx plugin to use webpack module federation",
|
||||
@@ -174,11 +129,6 @@
|
||||
"description": "OpenAPI Plugin for Nx. Keep your API spec files in libs, and auto-generate sources.",
|
||||
"url": "https://github.com/trumbitta/nx-trumbitta/tree/main/packages/nx-plugin-openapi"
|
||||
},
|
||||
{
|
||||
"name": "@trumbitta/nx-plugin-unused-deps",
|
||||
"description": "Check the dependency graph of your monorepo, looking for unused NPM packages.",
|
||||
"url": "https://github.com/trumbitta/nx-trumbitta/tree/main/packages/nx-plugin-unused-deps"
|
||||
},
|
||||
{
|
||||
"name": "@nxrocks/nx-flutter",
|
||||
"description": "Nx Plugin adding first class support for Flutter in your Nx workspace",
|
||||
@@ -200,238 +150,13 @@
|
||||
"url": "https://github.com/bikecoders/ngx-deploy-npm"
|
||||
},
|
||||
{
|
||||
"name": "@nx-dotnet/core",
|
||||
"name": "@trafilea/nx-shopify",
|
||||
"description": "Nx plugin for developing performance-first Shopify themes",
|
||||
"url": "https://github.com/trafilea/nx-shopify"
|
||||
},
|
||||
{
|
||||
"name": "nx-dotnet",
|
||||
"description": "Nx plugin for developing and housing .NET projects within an Nx workspace.",
|
||||
"url": "https://github.com/nx-dotnet/nx-dotnet"
|
||||
},
|
||||
{
|
||||
"name": "@nxrocks/nx-quarkus",
|
||||
"description": "Nx plugin to generate, run, package, build (and more) Quarkus projects inside your Nx workspace",
|
||||
"url": "https://github.com/tinesoft/nxrocks/tree/master/packages/nx-quarkus"
|
||||
},
|
||||
{
|
||||
"name": "@nx-extend/gcp-secrets",
|
||||
"description": "Nx plugin to generate and securely deploy your Google Cloud Secrets",
|
||||
"url": "https://github.com/tripss/nx-extend/tree/master/packages/gcp-secrets"
|
||||
},
|
||||
{
|
||||
"name": "@nx-extend/gcp-storage",
|
||||
"description": "Nx plugin to upload to Google Cloud Storage",
|
||||
"url": "https://github.com/tripss/nx-extend/tree/master/packages/gcp-storage"
|
||||
},
|
||||
{
|
||||
"name": "@nx-extend/gcp-functions",
|
||||
"description": "Nx plugin to generate, run, build and deploy your Google Cloud Functions",
|
||||
"url": "https://github.com/tripss/nx-extend/tree/master/packages/gcp-functions"
|
||||
},
|
||||
{
|
||||
"name": "@nx-extend/gcp-deployment-manager",
|
||||
"description": "Nx plugin to deploy your Google Cloud Deployments",
|
||||
"url": "https://github.com/tripss/nx-extend/tree/master/packages/gcp-deployment-manager"
|
||||
},
|
||||
{
|
||||
"name": "@nx-extend/gcp-cloud-run",
|
||||
"description": "Nx plugin to build and deploy your docker container to Google Cloud Run",
|
||||
"url": "https://github.com/tripss/nx-extend/tree/master/packages/gcp-cloud-run"
|
||||
},
|
||||
{
|
||||
"name": "@nx-extend/translations",
|
||||
"description": "Nx plugin to extract, pull, push and translate your apps translations",
|
||||
"url": "https://github.com/tripss/nx-extend/tree/master/packages/translations"
|
||||
},
|
||||
{
|
||||
"name": "@nx-extend/firebase-hosting",
|
||||
"description": "Nx plugin to deploy your apps to Firebase hosting",
|
||||
"url": "https://github.com/tripss/nx-extend/tree/master/packages/firebase-hosting"
|
||||
},
|
||||
{
|
||||
"name": "@nx-extend/e2e-runner",
|
||||
"description": "Nx plugin that can start your API before running Cypress/Playwright",
|
||||
"url": "https://github.com/tripss/nx-extend/tree/master/packages/e2e-runner"
|
||||
},
|
||||
{
|
||||
"name": "@nx-extend/vercel",
|
||||
"description": "Nx plugin to deploy your apps to Vercel",
|
||||
"url": "https://github.com/tripss/nx-extend/tree/master/packages/vercel"
|
||||
},
|
||||
{
|
||||
"name": "@nx-extend/strapi",
|
||||
"description": "Nx plugin for developing Strapi applications",
|
||||
"url": "https://github.com/tripss/nx-extend/tree/master/packages/strapi"
|
||||
},
|
||||
{
|
||||
"name": "@nx-extend/playwright",
|
||||
"description": "Nx plugin to run playwright e2e tests in an Nx workspace",
|
||||
"url": "https://github.com/tripss/nx-extend/tree/master/packages/playwright"
|
||||
},
|
||||
{
|
||||
"name": "@nx-extend/terraform",
|
||||
"description": "Nx plugin for deploying your resources with Terraform",
|
||||
"url": "https://github.com/tripss/nx-extend/tree/master/packages/terraform"
|
||||
},
|
||||
{
|
||||
"name": "@nx-extend/pulumi",
|
||||
"description": "Nx plugin for deploying your resources with Pulumi",
|
||||
"url": "https://github.com/tripss/nx-extend/tree/master/packages/pulumi"
|
||||
},
|
||||
{
|
||||
"name": "@nativescript/nx",
|
||||
"description": "Nx Plugin adding first class support for NativeScript in your Nx workspace",
|
||||
"url": "https://github.com/nativescript/nx"
|
||||
},
|
||||
{
|
||||
"name": "@nxtensions/astro",
|
||||
"description": "Nx plugin adding first class support for Astro (https://astro.build).",
|
||||
"url": "https://github.com/nxtensions/nxtensions/tree/main/packages/astro"
|
||||
},
|
||||
{
|
||||
"name": "@nxrs/cargo",
|
||||
"description": "Nx plugin adding first-class support for Rust applications and libraries.",
|
||||
"url": "https://github.com/nxrs/cargo/tree/main/packages/cargo"
|
||||
},
|
||||
{
|
||||
"name": "nx-uvu",
|
||||
"description": "An nx executor for the uvu test library",
|
||||
"url": "https://github.com/jmcdo29/nx-uvu"
|
||||
},
|
||||
{
|
||||
"name": "@ndrsg/nx-http",
|
||||
"description": "Plugin with executors, which can perform http-stuff (e.g. requests, webhooks, file up/downloads, ...)",
|
||||
"url": "https://github.com/ndrsg/nx-ext/tree/main/packages/nx-http"
|
||||
},
|
||||
{
|
||||
"name": "@diogovcs/graphql-mesh",
|
||||
"description": "Nx plugin to add GraphQL Mesh integration to Nx Workspace.",
|
||||
"url": "https://github.com/DiogoVCS/nx-workspace-plugins"
|
||||
},
|
||||
{
|
||||
"name": "@computas/nx-yarn",
|
||||
"description": "A plugin to help make nx with yarn a pleasant experience.",
|
||||
"url": "https://github.com/computas/nx-yarn"
|
||||
},
|
||||
{
|
||||
"name": "@theunderscorer/nx-semantic-release",
|
||||
"description": "Nx plugin for automated releases using semantic-release.",
|
||||
"url": "https://github.com/TheUnderScorer/nx-semantic-release"
|
||||
},
|
||||
{
|
||||
"name": "nx-pwm",
|
||||
"description": "Nx plugin and CLI to help maintain packages, inspired by NX repo tooling",
|
||||
"url": "https://github.com/gioragutt/nx-pwm"
|
||||
},
|
||||
{
|
||||
"name": "@nxrocks/nx-micronaut",
|
||||
"description": "Nx plugin to generate, run, package, build (and more) Micronaut projects inside your Nx workspace",
|
||||
"url": "https://github.com/tinesoft/nxrocks/tree/master/packages/nx-micronaut"
|
||||
},
|
||||
{
|
||||
"name": "@koliveira15/nx-sonarqube",
|
||||
"description": "Nx plugin that scans projects using SonarQube / SonarCloud.",
|
||||
"url": "https://github.com/koliveira15/nx-sonarqube"
|
||||
},
|
||||
{
|
||||
"name": "@mands/nx-playwright",
|
||||
"description": "The Playwright plugin allows your workspace to use the power of Playwright end-to-end testing using a native runner.",
|
||||
"url": "https://github.com/marksandspencer/nx-plugins/tree/main/packages/nx-playwright"
|
||||
},
|
||||
{
|
||||
"name": "@diogovcs/stryker-mutator",
|
||||
"description": "Nx plugin to add Stryker Mutator mutation tests to the Nx Workspace.",
|
||||
"url": "https://github.com/DiogoVCS/nx-workspace-plugins"
|
||||
},
|
||||
{
|
||||
"name": "@spaceribs/nx-web-ext",
|
||||
"description": "Nx plugin that allows you to build, test and deploy web extensions.",
|
||||
"url": "https://github.com/spaceribs/spaceribs/tree/main/packages/nx-web-ext"
|
||||
},
|
||||
{
|
||||
"name": "@spaceribs/nx-betterer",
|
||||
"description": "Nx plugin that applies betterer standards on a per-project basis.",
|
||||
"url": "https://github.com/spaceribs/spaceribs/tree/main/packages/nx-betterer"
|
||||
},
|
||||
{
|
||||
"name": "@nx-tools/nx-container",
|
||||
"description": "Nx plugin to build OCI containers with Docker, Podman or Kaniko.",
|
||||
"url": "https://github.com/gperdomor/nx-tools/tree/main/packages/nx-container"
|
||||
},
|
||||
{
|
||||
"name": "@nxrocks/nx-melos",
|
||||
"description": "Nx plugin adding first class support for Melos in your Nx workspace",
|
||||
"url": "https://github.com/tinesoft/nxrocks/tree/master/packages/nx-melos"
|
||||
},
|
||||
{
|
||||
"name": "@monodon/rust",
|
||||
"description": "Adds Cargo and Rust support",
|
||||
"url": "https://github.com/cammisuli/monodon/tree/main/packages/rust"
|
||||
},
|
||||
{
|
||||
"name": "nx-mesh",
|
||||
"description": "GraphQL Mesh support for Nx",
|
||||
"url": "https://github.com/domjtalbot/nx-mesh"
|
||||
},
|
||||
{
|
||||
"name": "@nxazure/func",
|
||||
"description": "Nx plugin to add Azure Functions support to Nx Workspace.",
|
||||
"url": "https://github.com/AlexPshul/nxazure/tree/master/packages/func"
|
||||
},
|
||||
{
|
||||
"name": "@rbnx/webdriverio",
|
||||
"description": "A Nx plugin that adds the WebdriverIO testing framework to a NX workspace.",
|
||||
"url": "https://github.com/Roozenboom/rbnx/tree/main/packages/webdriverio"
|
||||
},
|
||||
{
|
||||
"name": "nx-ngrok",
|
||||
"description": "Ngrok support for Nx",
|
||||
"url": "https://github.com/domjtalbot/nx-ngrok"
|
||||
},
|
||||
{
|
||||
"name": "@nxrocks/nx-ktor",
|
||||
"description": "Nx plugin to generate, run, package, build (and more) Ktor projects inside your Nx workspace",
|
||||
"url": "https://github.com/tinesoft/nxrocks/tree/master/packages/nx-ktor"
|
||||
},
|
||||
{
|
||||
"name": "nx-size-limit",
|
||||
"description": "Adds size-limit support for Nx (performance budget tool for JavaScript)",
|
||||
"url": "https://github.com/LironHazan/nx-size-limit"
|
||||
},
|
||||
{
|
||||
"name": "@loft-orbital/terraform",
|
||||
"description": "Terraform executors and generators",
|
||||
"url": "https://github.com/loft-orbital/nx-plugins/tree/main/packages/terraform"
|
||||
},
|
||||
{
|
||||
"name": "@nxlv/python",
|
||||
"description": "Nx plugin designed to extend the Nx features to work with Python projects based on Poetry.",
|
||||
"url": "https://github.com/lucasvieirasilva/nx-plugins/tree/main/packages/nx-python"
|
||||
},
|
||||
{
|
||||
"name": "nx-gcp-cache",
|
||||
"description": "Nx plugin to use Google Cloud Storage as distributed remote cache",
|
||||
"url": "https://github.com/davidgarciab/nx-gcp-cache"
|
||||
},
|
||||
{
|
||||
"name": "@jnxplus/nx-gradle",
|
||||
"description": "Nx plugin to add Gradle multi-project builds support to Nx workspace",
|
||||
"url": "https://github.com/khalilou88/jnxplus/tree/main/packages/nx-gradle"
|
||||
},
|
||||
{
|
||||
"name": "@jnxplus/nx-maven",
|
||||
"description": "Nx plugin to add Maven multi-module project support to Nx workspace",
|
||||
"url": "https://github.com/khalilou88/jnxplus/tree/main/packages/nx-maven"
|
||||
},
|
||||
{
|
||||
"name": "@naxodev/nx-cloudflare",
|
||||
"description": "Nx plugin for Cloudflare, in particular Cloudflare workers. It allows to generate build and run Cloudflare workers in your Nx workspace.",
|
||||
"url": "https://github.com/naxodev/oss/tree/main/packages/plugins/nx-cloudflare"
|
||||
},
|
||||
{
|
||||
"name": "@ziacik/azure-func",
|
||||
"description": "Generating, serving and publishing Azure Functions 4 apps.",
|
||||
"url": "https://github.com/ziacik/nx-tools/tree/master/packages/azure-func"
|
||||
},
|
||||
{
|
||||
"name": "@simondotm/nx-firebase",
|
||||
"description": "Nx plugin to support Firebase Apps and Cloud Functions in Nx workspaces",
|
||||
"url": "https://github.com/simondotm/nx-firebase"
|
||||
}
|
||||
]
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"fileServerFolder": ".",
|
||||
"fixturesFolder": "./src/fixtures",
|
||||
"integrationFolder": "./src/integration",
|
||||
"modifyObstructiveCode": false,
|
||||
"pluginsFile": "./src/plugins/index",
|
||||
"supportFile": "./src/support/index.ts",
|
||||
"video": true,
|
||||
"videosFolder": "../../dist/cypress/dep-graph/dep-graph-e2e/videos",
|
||||
"screenshotsFolder": "../../dist/cypress/dep-graph/dep-graph-e2e/screenshots",
|
||||
"chromeWebSecurity": false
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
import {
|
||||
getDeselectAllButton,
|
||||
getUnfocusProjectButton,
|
||||
getProjectCheckboxes,
|
||||
getCheckedProjectCheckboxes,
|
||||
getSelectAllButton,
|
||||
getSelectProjectsMessage,
|
||||
getTextFilterInput,
|
||||
getTextFilterButton,
|
||||
getIncludeProjectsInPathButton,
|
||||
} from '../support/app.po';
|
||||
|
||||
describe('dep-graph-client', () => {
|
||||
beforeEach(() => {
|
||||
cy.visit('/');
|
||||
cy.get('[data-cy=project-select]').select('Ocean');
|
||||
});
|
||||
|
||||
it('should display message to select projects', () => {
|
||||
getSelectProjectsMessage().should('be.visible');
|
||||
});
|
||||
|
||||
describe('select all button', () => {
|
||||
it('should check all project checkboxes', () => {
|
||||
getSelectAllButton().click();
|
||||
getProjectCheckboxes().should('be.checked');
|
||||
});
|
||||
});
|
||||
|
||||
describe('deselect all button', () => {
|
||||
it('should uncheck all project checkboxes', () => {
|
||||
getDeselectAllButton().click();
|
||||
getProjectCheckboxes().should('not.be.checked');
|
||||
});
|
||||
});
|
||||
|
||||
describe('focusing projects in sidebar', () => {
|
||||
it('should select appropriate projects', () => {
|
||||
cy.contains('nx-docs-site').siblings('button').click();
|
||||
|
||||
getCheckedProjectCheckboxes().should('have.length', 16);
|
||||
cy.contains('nx-docs-site-e2e').children('input').should('be.checked');
|
||||
cy.contains('common-platform').children('input').should('be.checked');
|
||||
cy.contains('private-nx-cloud')
|
||||
.children('input')
|
||||
.should('not.be.checked');
|
||||
});
|
||||
});
|
||||
|
||||
describe('unfocus button', () => {
|
||||
it('should uncheck all project checkboxes', () => {
|
||||
cy.contains('nx-docs-site').siblings('button').click();
|
||||
getUnfocusProjectButton().click();
|
||||
|
||||
getProjectCheckboxes().should('not.be.checked');
|
||||
});
|
||||
});
|
||||
|
||||
describe('text filtering', () => {
|
||||
it('should filter projects by text when clicked', () => {
|
||||
getTextFilterInput().type('nx-docs-site');
|
||||
getTextFilterButton().click();
|
||||
|
||||
getCheckedProjectCheckboxes().should('have.length', 11);
|
||||
});
|
||||
|
||||
it('should filter projects by text when pressing enter', () => {
|
||||
getTextFilterInput().type('nx-docs-site{enter}');
|
||||
|
||||
getCheckedProjectCheckboxes().should('have.length', 11);
|
||||
});
|
||||
|
||||
it('should include projects in path when option is checked', () => {
|
||||
getTextFilterInput().type('nx-docs-site');
|
||||
getIncludeProjectsInPathButton().click();
|
||||
getTextFilterButton().click();
|
||||
|
||||
getCheckedProjectCheckboxes().should('have.length', 16);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,22 @@
|
||||
// ***********************************************************
|
||||
// This example plugins/index.js can be used to load plugins
|
||||
//
|
||||
// You can change the location of this file or turn off loading
|
||||
// the plugins file with the 'pluginsFile' configuration option.
|
||||
//
|
||||
// You can read more here:
|
||||
// https://on.cypress.io/plugins-guide
|
||||
// ***********************************************************
|
||||
|
||||
// This function is called when a project is opened or re-opened (e.g. due to
|
||||
// the project's config changing)
|
||||
|
||||
const { preprocessTypescript } = require('@nrwl/cypress/plugins/preprocessor');
|
||||
|
||||
module.exports = (on, config) => {
|
||||
// `on` is used to hook into various events Cypress emits
|
||||
// `config` is the resolved Cypress config
|
||||
|
||||
// Preprocess Typescript file using Nx helper
|
||||
on('file:preprocessor', preprocessTypescript(config));
|
||||
};
|
||||
@@ -0,0 +1,20 @@
|
||||
export const getSelectProjectsMessage = () => cy.get('#no-projects-chosen');
|
||||
export const getGraph = () => cy.get('#graph-container');
|
||||
export const getSelectAllButton = () => cy.get('[data-cy=selectAllButton]');
|
||||
export const getDeselectAllButton = () => cy.get('[data-cy=deselectAllButton]');
|
||||
export const getUnfocusProjectButton = () => cy.get('[data-cy=unfocusButton]');
|
||||
|
||||
export const getProjectCheckboxes = () => cy.get('input[name=projectName]');
|
||||
|
||||
export const getCheckedProjectCheckboxes = () =>
|
||||
cy.get('input[name=projectName]:checked');
|
||||
export const getUncheckedProjectCheckboxes = () =>
|
||||
cy.get('input[name=projectName]:not(:checked)');
|
||||
|
||||
export const getGroupByfolderCheckbox = () =>
|
||||
cy.get('input[name=displayOptions][value=groupByFolder]');
|
||||
|
||||
export const getTextFilterInput = () => cy.get('[data-cy=textFilterInput]');
|
||||
export const getTextFilterButton = () => cy.get('[data-cy=textFilterButton]');
|
||||
export const getIncludeProjectsInPathButton = () =>
|
||||
cy.get('input[name=textFilterCheckbox]');
|
||||
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"extends": "./tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"sourceMap": false,
|
||||
"outDir": "../../dist/out-tsc",
|
||||
"allowJs": true,
|
||||
"types": ["cypress", "node"]
|
||||
},
|
||||
"include": ["src/**/*.ts", "src/**/*.js"]
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"extends": "../../tsconfig.base.json",
|
||||
"files": [],
|
||||
"include": [],
|
||||
"references": [
|
||||
{
|
||||
"path": "./tsconfig.e2e.json"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"presets": ["@nrwl/web/babel"]
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
{ "extends": "../../.eslintrc", "rules": {}, "ignorePatterns": ["!**/*"] }
|
||||
@@ -0,0 +1,13 @@
|
||||
# This file is currently used by autoprefixer to adjust CSS to support the below specified browsers
|
||||
# For additional information regarding the format and rule options, please see:
|
||||
# https://github.com/browserslist/browserslist#queries
|
||||
#
|
||||
# If you need to support different browsers in production, you may tweak the list below.
|
||||
|
||||
last 1 Chrome version
|
||||
last 1 Firefox version
|
||||
last 2 Edge major versions
|
||||
last 2 Safari major version
|
||||
last 2 iOS major versions
|
||||
Firefox ESR
|
||||
not IE 9-11 # For IE 9-11 support, remove 'not'.
|
||||
@@ -0,0 +1,15 @@
|
||||
module.exports = {
|
||||
name: 'dep-graph-dep-graph',
|
||||
preset: '../../jest.preset.js',
|
||||
setupFilesAfterEnv: ['<rootDir>/src/test-setup.ts'],
|
||||
globals: {
|
||||
'ts-jest': {
|
||||
tsconfig: '<rootDir>/tsconfig.spec.json',
|
||||
},
|
||||
},
|
||||
transform: {
|
||||
'^.+\\.[tj]s$': 'ts-jest',
|
||||
},
|
||||
moduleFileExtensions: ['ts', 'js', 'html'],
|
||||
coverageDirectory: '../../coverage/dep-graph/dep-graph',
|
||||
};
|
||||
@@ -0,0 +1,105 @@
|
||||
import { combineLatest, fromEvent, Subject } from 'rxjs';
|
||||
import { startWith, takeUntil } from 'rxjs/operators';
|
||||
import { projectGraphs } from '../graphs';
|
||||
import { DebuggerPanel } from './debugger-panel';
|
||||
import { GraphComponent } from './graph';
|
||||
import { GraphTooltipService } from './tooltip-service';
|
||||
import { SidebarComponent } from './ui-sidebar/sidebar';
|
||||
|
||||
export interface AppConfig {
|
||||
showDebugger: boolean;
|
||||
}
|
||||
|
||||
const DEFAULT_CONFIG: AppConfig = {
|
||||
showDebugger: false,
|
||||
};
|
||||
export class AppComponent {
|
||||
private sidebar: SidebarComponent;
|
||||
private tooltipService = new GraphTooltipService();
|
||||
private graph = new GraphComponent(this.tooltipService);
|
||||
private debuggerPanel: DebuggerPanel;
|
||||
|
||||
private windowResize$ = fromEvent(window, 'resize').pipe(startWith({}));
|
||||
private render$ = new Subject<void>();
|
||||
|
||||
constructor(private config: AppConfig = DEFAULT_CONFIG) {
|
||||
this.render$.subscribe(() => this.render());
|
||||
this.render$.next();
|
||||
}
|
||||
|
||||
private onProjectGraphChange(projectGraphId: string) {
|
||||
const project = projectGraphs.find((graph) => graph.id === projectGraphId);
|
||||
const projectGraph = project?.graph;
|
||||
const workspaceLayout = project?.workspaceLayout;
|
||||
|
||||
const nodes = Object.values(projectGraph.nodes).filter(
|
||||
(node) => node.type !== 'npm'
|
||||
);
|
||||
|
||||
window.projects = nodes;
|
||||
window.graph = projectGraph;
|
||||
window.affected = [];
|
||||
window.exclude = [];
|
||||
window.focusedProject = null;
|
||||
window.projectGraphList = projectGraphs;
|
||||
window.selectedProjectGraph = projectGraphId;
|
||||
window.workspaceLayout = workspaceLayout;
|
||||
|
||||
this.render();
|
||||
}
|
||||
|
||||
private render() {
|
||||
const debuggerPanelContainer = document.getElementById('debugger-panel');
|
||||
|
||||
if (this.config.showDebugger) {
|
||||
debuggerPanelContainer.hidden = false;
|
||||
debuggerPanelContainer.style.display = 'flex';
|
||||
|
||||
this.debuggerPanel = new DebuggerPanel(
|
||||
debuggerPanelContainer,
|
||||
window.projectGraphList
|
||||
);
|
||||
|
||||
this.debuggerPanel.selectProject$.subscribe((id) => {
|
||||
this.onProjectGraphChange(id);
|
||||
});
|
||||
}
|
||||
|
||||
this.graph.projectGraph = window.graph;
|
||||
const affectedProjects = window.affected.filter(
|
||||
(affectedProjectName) => !affectedProjectName.startsWith('npm:')
|
||||
);
|
||||
|
||||
this.graph.affectedProjects = affectedProjects;
|
||||
this.sidebar = new SidebarComponent(
|
||||
affectedProjects,
|
||||
this.config.showDebugger
|
||||
);
|
||||
|
||||
combineLatest([
|
||||
this.sidebar.selectedProjectsChanged$,
|
||||
this.sidebar.groupByFolderChanged$,
|
||||
this.windowResize$,
|
||||
])
|
||||
.pipe(takeUntil(this.render$))
|
||||
.subscribe(([selectedProjectNames, groupByFolder]) => {
|
||||
const selectedProjects = [];
|
||||
|
||||
selectedProjectNames.forEach((projectName) => {
|
||||
if (window.graph.nodes[projectName]) {
|
||||
selectedProjects.push(window.graph.nodes[projectName]);
|
||||
}
|
||||
});
|
||||
|
||||
this.graph.render(selectedProjects, groupByFolder);
|
||||
});
|
||||
|
||||
if (this.debuggerPanel) {
|
||||
this.graph.renderTimes$
|
||||
.pipe(takeUntil(this.render$))
|
||||
.subscribe(
|
||||
(renderTime) => (this.debuggerPanel.renderTime = renderTime)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
import { Subject } from 'rxjs';
|
||||
import { GraphPerfReport } from './graph';
|
||||
import { ProjectGraphList } from './models';
|
||||
import { removeChildrenFromContainer } from './util';
|
||||
|
||||
export class DebuggerPanel {
|
||||
set renderTime(renderTime: GraphPerfReport) {
|
||||
this.renderReportElement.innerText = `Last render took ${renderTime.renderTime} milliseconds for ${renderTime.numNodes} nodes and ${renderTime.numEdges} edges.`;
|
||||
}
|
||||
|
||||
private selectProjectSubject = new Subject<string>();
|
||||
|
||||
selectProject$ = this.selectProjectSubject.asObservable();
|
||||
|
||||
private renderReportElement: HTMLElement;
|
||||
|
||||
constructor(
|
||||
private container: HTMLElement,
|
||||
private projectGraphs: ProjectGraphList[]
|
||||
) {
|
||||
this.render();
|
||||
}
|
||||
|
||||
private render() {
|
||||
removeChildrenFromContainer(this.container);
|
||||
|
||||
const header = document.createElement('h4');
|
||||
header.innerText = `Debugger`;
|
||||
|
||||
const select = document.createElement('select');
|
||||
|
||||
this.projectGraphs.forEach((projectGraph) => {
|
||||
const option = document.createElement('option');
|
||||
option.value = projectGraph.id;
|
||||
option.innerText = projectGraph.label;
|
||||
|
||||
select.appendChild(option);
|
||||
});
|
||||
|
||||
select.value = window.selectedProjectGraph;
|
||||
select.dataset['cy'] = 'project-select';
|
||||
|
||||
select.onchange = (event) =>
|
||||
this.selectProjectSubject.next(
|
||||
(event.currentTarget as HTMLSelectElement).value
|
||||
);
|
||||
|
||||
this.renderReportElement = document.createElement('p');
|
||||
|
||||
this.container.appendChild(header);
|
||||
this.container.appendChild(select);
|
||||
this.container.appendChild(this.renderReportElement);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,159 @@
|
||||
import { ProjectGraph, ProjectGraphNode } from '@nrwl/workspace';
|
||||
import * as cy from 'cytoscape';
|
||||
import cytoscapeDagre from 'cytoscape-dagre';
|
||||
import popper from 'cytoscape-popper';
|
||||
import { Subject } from 'rxjs';
|
||||
import { Instance } from 'tippy.js';
|
||||
import { ProjectNodeToolTip } from './project-node-tooltip';
|
||||
import { edgeStyles, nodeStyles } from './styles-graph';
|
||||
import { GraphTooltipService } from './tooltip-service';
|
||||
import {
|
||||
CytoscapeDagreConfig,
|
||||
ParentNode,
|
||||
ProjectEdge,
|
||||
ProjectNode,
|
||||
} from './util-cytoscape';
|
||||
import { VirtualElement } from '@popperjs/core';
|
||||
|
||||
export interface GraphPerfReport {
|
||||
renderTime: number;
|
||||
numNodes: number;
|
||||
numEdges: number;
|
||||
}
|
||||
export class GraphComponent {
|
||||
private graph: cy.Core;
|
||||
private openTooltip: Instance = null;
|
||||
|
||||
affectedProjects: string[];
|
||||
projectGraph: ProjectGraph;
|
||||
|
||||
private renderTimesSubject = new Subject<GraphPerfReport>();
|
||||
renderTimes$ = this.renderTimesSubject.asObservable();
|
||||
|
||||
constructor(private tooltipService: GraphTooltipService) {
|
||||
cy.use(cytoscapeDagre);
|
||||
cy.use(popper);
|
||||
}
|
||||
|
||||
render(selectedProjects: ProjectGraphNode[], groupByFolder: boolean) {
|
||||
const time = Date.now();
|
||||
|
||||
this.tooltipService.hideAll();
|
||||
this.generateCytoscapeLayout(selectedProjects, groupByFolder);
|
||||
this.listenForProjectNodeClicks();
|
||||
|
||||
const renderTime = Date.now() - time;
|
||||
|
||||
const report: GraphPerfReport = {
|
||||
renderTime,
|
||||
numNodes: this.graph.nodes().length,
|
||||
numEdges: this.graph.edges().length,
|
||||
};
|
||||
|
||||
this.renderTimesSubject.next(report);
|
||||
}
|
||||
|
||||
private generateCytoscapeLayout(
|
||||
selectedProjects: ProjectGraphNode[],
|
||||
groupByFolder: boolean
|
||||
) {
|
||||
const elements = this.createElements(selectedProjects, groupByFolder);
|
||||
|
||||
this.graph = cy({
|
||||
container: document.getElementById('graph-container'),
|
||||
elements: [...elements],
|
||||
layout: <CytoscapeDagreConfig>{
|
||||
name: 'dagre',
|
||||
nodeDimensionsIncludeLabels: true,
|
||||
rankSep: 75,
|
||||
edgeSep: 50,
|
||||
ranker: 'network-simplex',
|
||||
},
|
||||
boxSelectionEnabled: false,
|
||||
style: [...nodeStyles, ...edgeStyles],
|
||||
});
|
||||
|
||||
this.graph.on('zoom', () => {
|
||||
if (this.openTooltip) {
|
||||
this.openTooltip.hide();
|
||||
this.openTooltip = null;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private createElements(
|
||||
selectedProjects: ProjectGraphNode[],
|
||||
groupByFolder: boolean
|
||||
) {
|
||||
let elements: cy.ElementDefinition[] = [];
|
||||
const filteredProjectNames = selectedProjects.map(
|
||||
(project) => project.name
|
||||
);
|
||||
|
||||
const projectNodes: ProjectNode[] = [];
|
||||
const edgeNodes: ProjectEdge[] = [];
|
||||
const parents: Record<
|
||||
string,
|
||||
{ id: string; parentId: string; label: string }
|
||||
> = {};
|
||||
|
||||
selectedProjects.forEach((project) => {
|
||||
const workspaceRoot =
|
||||
project.type === 'app' || project.type === 'e2e'
|
||||
? window.workspaceLayout.appsDir
|
||||
: window.workspaceLayout.libsDir;
|
||||
|
||||
const projectNode = new ProjectNode(project, workspaceRoot);
|
||||
projectNode.focused = project.name === window.focusedProject;
|
||||
projectNode.affected = this.affectedProjects.includes(project.name);
|
||||
|
||||
projectNodes.push(projectNode);
|
||||
|
||||
this.projectGraph.dependencies[project.name].forEach((dep) => {
|
||||
if (filteredProjectNames.includes(dep.target)) {
|
||||
const edge = new ProjectEdge(dep);
|
||||
edge.affected =
|
||||
this.affectedProjects.includes(dep.source) &&
|
||||
this.affectedProjects.includes(dep.target);
|
||||
edgeNodes.push(edge);
|
||||
}
|
||||
});
|
||||
|
||||
if (groupByFolder) {
|
||||
const ancestors = projectNode.getAncestors();
|
||||
ancestors.forEach((ancestor) => (parents[ancestor.id] = ancestor));
|
||||
}
|
||||
});
|
||||
|
||||
const projectElements = projectNodes.map((projectNode) =>
|
||||
projectNode.getCytoscapeNodeDef(groupByFolder)
|
||||
);
|
||||
|
||||
const edgeElements = edgeNodes.map((edgeNode) =>
|
||||
edgeNode.getCytosacpeNodeDef()
|
||||
);
|
||||
|
||||
elements = projectElements.concat(edgeElements);
|
||||
|
||||
if (groupByFolder) {
|
||||
const parentElements = Object.keys(parents).map((id) =>
|
||||
new ParentNode(parents[id]).getCytoscapeNodeDef()
|
||||
);
|
||||
elements = parentElements.concat(elements);
|
||||
}
|
||||
|
||||
return elements;
|
||||
}
|
||||
|
||||
listenForProjectNodeClicks() {
|
||||
this.graph.$('node:childless').on('click', (event) => {
|
||||
const node = event.target;
|
||||
|
||||
let ref: VirtualElement = node.popperRef(); // used only for positioning
|
||||
|
||||
const content = new ProjectNodeToolTip(node).render();
|
||||
|
||||
this.openTooltip = this.tooltipService.open(ref, content);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
import { ProjectGraphCache } from '@nrwl/workspace';
|
||||
|
||||
export interface ProjectGraphList {
|
||||
id: string;
|
||||
label: string;
|
||||
graph: ProjectGraphCache;
|
||||
workspaceLayout: WorkspaceLayout;
|
||||
}
|
||||
|
||||
export interface WorkspaceLayout {
|
||||
libsDir: string;
|
||||
appsDir: string;
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
import * as cy from 'cytoscape';
|
||||
|
||||
export class ProjectNodeToolTip {
|
||||
constructor(private node: cy.NodeSingular) {}
|
||||
|
||||
render() {
|
||||
const wrapper = document.createElement('div');
|
||||
const header = this.createHeader();
|
||||
const tags = this.createTags();
|
||||
const buttons = this.createButtons();
|
||||
|
||||
wrapper.appendChild(header);
|
||||
wrapper.appendChild(tags);
|
||||
wrapper.appendChild(buttons);
|
||||
|
||||
return wrapper;
|
||||
}
|
||||
|
||||
private createHeader() {
|
||||
const header = document.createElement('h4');
|
||||
const typeLabel = document.createElement('span');
|
||||
const projectName = document.createTextNode(this.node.attr('id'));
|
||||
|
||||
typeLabel.classList.add('tag');
|
||||
typeLabel.innerText = this.node.attr('type');
|
||||
|
||||
header.appendChild(typeLabel);
|
||||
header.appendChild(projectName);
|
||||
|
||||
return header;
|
||||
}
|
||||
|
||||
private createTags() {
|
||||
const wrapper = document.createElement('p');
|
||||
const tagLabel = document.createElement('strong');
|
||||
const tags = document.createTextNode(
|
||||
this.node.attr('tags')?.join(', ') ?? ''
|
||||
);
|
||||
|
||||
tagLabel.innerText = 'tags';
|
||||
|
||||
wrapper.appendChild(tagLabel);
|
||||
wrapper.appendChild(document.createElement('br'));
|
||||
wrapper.appendChild(tags);
|
||||
|
||||
return wrapper;
|
||||
}
|
||||
|
||||
private createButtons() {
|
||||
const wrapper = document.createElement('div');
|
||||
const focusButton = document.createElement('button');
|
||||
const excludeButton = document.createElement('button');
|
||||
|
||||
wrapper.classList.add('flex');
|
||||
|
||||
focusButton.addEventListener('click', () =>
|
||||
window.focusProject(this.node.attr('id'))
|
||||
);
|
||||
focusButton.innerText = 'Focus';
|
||||
|
||||
excludeButton.addEventListener('click', () => {
|
||||
window.excludeProject(this.node.attr('id'));
|
||||
});
|
||||
|
||||
excludeButton.innerText = 'Exclude';
|
||||
|
||||
wrapper.appendChild(focusButton);
|
||||
wrapper.appendChild(excludeButton);
|
||||
|
||||
return wrapper;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
import { Stylesheet } from 'cytoscape';
|
||||
import { NrwlPalette } from './palette';
|
||||
|
||||
const allEdges: Stylesheet = {
|
||||
selector: 'edge',
|
||||
style: {
|
||||
width: '1px',
|
||||
'line-color': NrwlPalette.black,
|
||||
'curve-style': 'straight',
|
||||
'target-arrow-shape': 'triangle',
|
||||
'target-arrow-fill': 'filled',
|
||||
'target-arrow-color': NrwlPalette.black,
|
||||
},
|
||||
};
|
||||
|
||||
const affectedEdges: Stylesheet = {
|
||||
selector: 'edge.affected',
|
||||
style: {
|
||||
'line-color': NrwlPalette.red,
|
||||
'target-arrow-color': NrwlPalette.red,
|
||||
},
|
||||
};
|
||||
|
||||
const implicitEdges: Stylesheet = {
|
||||
selector: 'edge.implicit',
|
||||
style: {
|
||||
label: 'implicit',
|
||||
'font-size': '16px',
|
||||
'edge-text-rotation': 'autorotate',
|
||||
},
|
||||
};
|
||||
|
||||
const dynamicEdges: Stylesheet = {
|
||||
selector: 'edge.dynamic',
|
||||
style: {
|
||||
'line-dash-pattern': [5, 5],
|
||||
'line-style': 'dashed',
|
||||
},
|
||||
};
|
||||
|
||||
export const edgeStyles: Stylesheet[] = [
|
||||
allEdges,
|
||||
affectedEdges,
|
||||
implicitEdges,
|
||||
dynamicEdges,
|
||||
];
|
||||
@@ -0,0 +1 @@
|
||||
export const FONTS = '"Helvetica Neue", sans-serif';
|
||||
@@ -0,0 +1,80 @@
|
||||
import { Stylesheet } from 'cytoscape';
|
||||
import { FONTS } from './fonts';
|
||||
import { NrwlPalette } from './palette';
|
||||
|
||||
const allNodes: Stylesheet = {
|
||||
selector: 'node',
|
||||
style: {
|
||||
'font-size': '32px',
|
||||
'font-family': FONTS,
|
||||
'border-style': 'solid',
|
||||
'border-color': NrwlPalette.black,
|
||||
'border-width': '1px',
|
||||
'text-halign': 'center',
|
||||
'text-valign': 'center',
|
||||
'padding-left': '16px',
|
||||
label: 'data(id)',
|
||||
width: 'label',
|
||||
backgroundColor: NrwlPalette.white,
|
||||
},
|
||||
};
|
||||
|
||||
const appNodes: Stylesheet = {
|
||||
selector: 'node[type="app"]',
|
||||
style: {
|
||||
shape: 'rectangle',
|
||||
},
|
||||
};
|
||||
|
||||
const libNodes: Stylesheet = {
|
||||
selector: 'node[type="lib"]',
|
||||
style: {
|
||||
shape: 'ellipse',
|
||||
},
|
||||
};
|
||||
|
||||
const e2eNodes: Stylesheet = {
|
||||
selector: 'node[type="e2e"]',
|
||||
style: {
|
||||
shape: 'rectangle',
|
||||
},
|
||||
};
|
||||
|
||||
const focusedNodes: Stylesheet = {
|
||||
selector: 'node.focused',
|
||||
style: {
|
||||
color: NrwlPalette.twilight,
|
||||
'border-color': NrwlPalette.twilight,
|
||||
},
|
||||
};
|
||||
|
||||
const affectedNodes: Stylesheet = {
|
||||
selector: 'node.affected',
|
||||
style: {
|
||||
'border-color': NrwlPalette.red,
|
||||
},
|
||||
};
|
||||
|
||||
const parentNodes: Stylesheet = {
|
||||
selector: ':parent',
|
||||
style: {
|
||||
'background-opacity': 0.5,
|
||||
'background-color': NrwlPalette.twilight,
|
||||
'border-color': NrwlPalette.black,
|
||||
label: 'data(label)',
|
||||
'text-halign': 'center',
|
||||
'text-valign': 'top',
|
||||
'font-weight': 'bold',
|
||||
'font-size': '48px',
|
||||
},
|
||||
};
|
||||
|
||||
export const nodeStyles = [
|
||||
allNodes,
|
||||
appNodes,
|
||||
libNodes,
|
||||
e2eNodes,
|
||||
focusedNodes,
|
||||
affectedNodes,
|
||||
parentNodes,
|
||||
];
|
||||
@@ -0,0 +1,10 @@
|
||||
export enum NrwlPalette {
|
||||
blue = '#48c4e5',
|
||||
lightBlue = '#96d8e9',
|
||||
gray = '#333333',
|
||||
navy = '#143055',
|
||||
twilight = '#086c9f',
|
||||
black = '#231f20',
|
||||
red = '#f85477',
|
||||
white = '#fff',
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
import { VirtualElement } from '@popperjs/core';
|
||||
import tippy, { Instance, hideAll } from 'tippy.js';
|
||||
|
||||
export class GraphTooltipService {
|
||||
open(ref: VirtualElement, tooltipContent: HTMLElement): Instance {
|
||||
let instance = tippy(document.createElement('div'), {
|
||||
trigger: 'manual',
|
||||
theme: 'nx',
|
||||
interactive: true,
|
||||
appendTo: document.body,
|
||||
content: tooltipContent,
|
||||
getReferenceClientRect: ref.getBoundingClientRect,
|
||||
});
|
||||
|
||||
instance.show();
|
||||
|
||||
return instance;
|
||||
}
|
||||
|
||||
hideAll() {
|
||||
hideAll();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
import { Subject } from 'rxjs';
|
||||
import { removeChildrenFromContainer } from '../util';
|
||||
|
||||
export class DisplayOptionsPanel {
|
||||
private showAffected = false;
|
||||
private groupByFolder = false;
|
||||
private selectAffectedSubject = new Subject<void>();
|
||||
private selectAllSubject = new Subject<void>();
|
||||
private deselectAllSubject = new Subject<void>();
|
||||
private groupByFolderSubject = new Subject<boolean>();
|
||||
|
||||
selectAffected$ = this.selectAffectedSubject.asObservable();
|
||||
selectAll$ = this.selectAllSubject.asObservable();
|
||||
deselectAll$ = this.deselectAllSubject.asObservable();
|
||||
groupByFolder$ = this.groupByFolderSubject.asObservable();
|
||||
|
||||
constructor(showAffected = false, groupByFolder = false) {
|
||||
this.showAffected = showAffected;
|
||||
this.groupByFolder = groupByFolder;
|
||||
}
|
||||
|
||||
render(container: HTMLElement) {
|
||||
removeChildrenFromContainer(container);
|
||||
|
||||
const header = document.createElement('h4');
|
||||
header.innerText = 'Display Options';
|
||||
|
||||
const selectButtonsContainer = document.createElement('div');
|
||||
selectButtonsContainer.classList.add('flex');
|
||||
|
||||
if (this.showAffected) {
|
||||
const selectAffectedButton = document.createElement('button');
|
||||
selectAffectedButton.innerText = 'Select Affected';
|
||||
selectAffectedButton.addEventListener('click', () =>
|
||||
this.selectAffectedSubject.next()
|
||||
);
|
||||
selectButtonsContainer.appendChild(selectAffectedButton);
|
||||
}
|
||||
|
||||
const selectAllButton = document.createElement('button');
|
||||
selectAllButton.innerText = 'Select All';
|
||||
selectAllButton.dataset['cy'] = 'selectAllButton';
|
||||
selectAllButton.addEventListener('click', () =>
|
||||
this.selectAllSubject.next()
|
||||
);
|
||||
|
||||
selectButtonsContainer.appendChild(selectAllButton);
|
||||
|
||||
const deselectAllButton = document.createElement('button');
|
||||
deselectAllButton.innerText = 'Deselect All';
|
||||
deselectAllButton.dataset['cy'] = 'deselectAllButton';
|
||||
deselectAllButton.addEventListener('click', () =>
|
||||
this.deselectAllSubject.next()
|
||||
);
|
||||
|
||||
selectButtonsContainer.appendChild(deselectAllButton);
|
||||
|
||||
const groupByFolderLabel = document.createElement('label');
|
||||
|
||||
const groupByFolderCheckbox = document.createElement('input');
|
||||
groupByFolderCheckbox.type = 'checkbox';
|
||||
groupByFolderCheckbox.name = 'displayOptions';
|
||||
groupByFolderCheckbox.value = 'groupByFolder';
|
||||
groupByFolderCheckbox.checked = this.groupByFolder;
|
||||
|
||||
groupByFolderCheckbox.addEventListener('change', (event: InputEvent) =>
|
||||
this.groupByFolderSubject.next((<HTMLInputElement>event.target).checked)
|
||||
);
|
||||
|
||||
groupByFolderLabel.appendChild(groupByFolderCheckbox);
|
||||
groupByFolderLabel.appendChild(document.createTextNode('group by folder'));
|
||||
|
||||
container.appendChild(header);
|
||||
container.appendChild(selectButtonsContainer);
|
||||
container.appendChild(groupByFolderLabel);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
import { Subject } from 'rxjs';
|
||||
import { removeChildrenFromContainer } from '../util';
|
||||
|
||||
export class FocusedProjectPanel {
|
||||
private unfocusSubject = new Subject<void>();
|
||||
|
||||
set projectName(projectName: string) {
|
||||
this.render(projectName);
|
||||
}
|
||||
|
||||
unfocus$ = this.unfocusSubject.asObservable();
|
||||
|
||||
constructor(private container: HTMLElement) {
|
||||
this.render();
|
||||
}
|
||||
|
||||
private render(projectName?: string) {
|
||||
removeChildrenFromContainer(this.container);
|
||||
|
||||
const header = document.createElement('h4');
|
||||
this.container.appendChild(header);
|
||||
|
||||
if (projectName && projectName !== '') {
|
||||
header.innerText = `Focused on ${projectName}`;
|
||||
this.container.hidden = false;
|
||||
} else {
|
||||
this.container.hidden = true;
|
||||
}
|
||||
|
||||
const unfocusButton = document.createElement('button');
|
||||
unfocusButton.innerText = 'Unfocus';
|
||||
|
||||
unfocusButton.dataset['cy'] = 'unfocusButton';
|
||||
|
||||
unfocusButton.addEventListener('click', () => this.unfocusSubject.next());
|
||||
this.container.appendChild(unfocusButton);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,191 @@
|
||||
import { ProjectGraphNode } from '@nrwl/workspace';
|
||||
import { Subject } from 'rxjs';
|
||||
import {
|
||||
parseParentDirectoriesFromPilePath,
|
||||
removeChildrenFromContainer,
|
||||
} from '../util';
|
||||
|
||||
export class ProjectList {
|
||||
private focusProjectSubject = new Subject<string>();
|
||||
private checkedProjectsChangeSubject = new Subject<string[]>();
|
||||
private checkboxes: Record<string, HTMLInputElement> = {};
|
||||
checkedProjectsChange$ = this.checkedProjectsChangeSubject.asObservable();
|
||||
focusProject$ = this.focusProjectSubject.asObservable();
|
||||
|
||||
constructor(
|
||||
private container: HTMLElement,
|
||||
private projects: ProjectGraphNode[]
|
||||
) {
|
||||
this.render();
|
||||
}
|
||||
|
||||
setCheckedProjects(selectedProjects: string[]) {
|
||||
Object.keys(this.checkboxes).forEach((projectName) => {
|
||||
this.checkboxes[projectName].checked = selectedProjects.includes(
|
||||
projectName
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
checkAllProjects() {
|
||||
Object.values(this.checkboxes).forEach(
|
||||
(checkbox) => (checkbox.checked = true)
|
||||
);
|
||||
}
|
||||
|
||||
uncheckAllProjects() {
|
||||
Object.values(this.checkboxes).forEach((checkbox) => {
|
||||
checkbox.checked = false;
|
||||
});
|
||||
}
|
||||
|
||||
uncheckProject(projectName: string) {
|
||||
this.checkboxes[projectName].checked = false;
|
||||
}
|
||||
|
||||
private emitChanges() {
|
||||
const changes = Object.values(this.checkboxes)
|
||||
.filter((checkbox) => checkbox.checked)
|
||||
.map((checkbox) => checkbox.value);
|
||||
this.checkedProjectsChangeSubject.next(changes);
|
||||
}
|
||||
|
||||
private render() {
|
||||
removeChildrenFromContainer(this.container);
|
||||
|
||||
const appProjects = this.getProjectsByType('app');
|
||||
const libProjects = this.getProjectsByType('lib');
|
||||
const e2eProjects = this.getProjectsByType('e2e');
|
||||
|
||||
const appDirectoryGroups = this.groupProjectsByDirectory(appProjects);
|
||||
const libDirectoryGroups = this.groupProjectsByDirectory(libProjects);
|
||||
const e2eDirectoryGroups = this.groupProjectsByDirectory(e2eProjects);
|
||||
|
||||
const sortedAppDirectories = Object.keys(appDirectoryGroups).sort();
|
||||
const sortedLibDirectories = Object.keys(libDirectoryGroups).sort();
|
||||
const sortedE2EDirectories = Object.keys(e2eDirectoryGroups).sort();
|
||||
|
||||
const appsHeader = document.createElement('h4');
|
||||
appsHeader.textContent = 'app projects';
|
||||
this.container.append(appsHeader);
|
||||
|
||||
sortedAppDirectories.forEach((directoryName) => {
|
||||
this.createProjectList(directoryName, appDirectoryGroups[directoryName]);
|
||||
});
|
||||
|
||||
const e2eHeader = document.createElement('h4');
|
||||
e2eHeader.textContent = 'e2e projects';
|
||||
this.container.append(e2eHeader);
|
||||
|
||||
sortedE2EDirectories.forEach((directoryName) => {
|
||||
this.createProjectList(directoryName, e2eDirectoryGroups[directoryName]);
|
||||
});
|
||||
|
||||
const libHeader = document.createElement('h4');
|
||||
libHeader.textContent = 'lib projects';
|
||||
this.container.append(libHeader);
|
||||
|
||||
sortedLibDirectories.forEach((directoryName) => {
|
||||
this.createProjectList(directoryName, libDirectoryGroups[directoryName]);
|
||||
});
|
||||
}
|
||||
|
||||
private getProjectsByType(type) {
|
||||
return this.projects
|
||||
.filter((project) => project.type === type)
|
||||
.sort((a, b) => a.name.localeCompare(b.name));
|
||||
}
|
||||
|
||||
private groupProjectsByDirectory(projects: ProjectGraphNode[]) {
|
||||
let groups = {};
|
||||
|
||||
projects.forEach((project) => {
|
||||
const workspaceRoot =
|
||||
project.type === 'app' || project.type === 'e2e'
|
||||
? window.workspaceLayout.appsDir
|
||||
: window.workspaceLayout.libsDir;
|
||||
const directories = parseParentDirectoriesFromPilePath(
|
||||
project.data.root,
|
||||
workspaceRoot
|
||||
);
|
||||
const directory = directories.join('/');
|
||||
|
||||
if (!groups.hasOwnProperty(directory)) {
|
||||
groups[directory] = [];
|
||||
}
|
||||
groups[directory].push(project);
|
||||
});
|
||||
|
||||
return groups;
|
||||
}
|
||||
|
||||
private createProjectList(headerText, projects) {
|
||||
const header = document.createElement('h5');
|
||||
header.textContent = headerText;
|
||||
|
||||
const formGroup = document.createElement('div');
|
||||
formGroup.className = 'form-group';
|
||||
|
||||
let sortedProjects = [...projects];
|
||||
sortedProjects.sort((a, b) => {
|
||||
return a.name.localeCompare(b.name);
|
||||
});
|
||||
|
||||
projects.forEach((project) => {
|
||||
let formLine = document.createElement('div');
|
||||
formLine.className = 'form-line';
|
||||
|
||||
let focusButton = document.createElement('button');
|
||||
focusButton.className = 'icon';
|
||||
|
||||
let buttonIconContainer = document.createElementNS(
|
||||
'http://www.w3.org/2000/svg',
|
||||
'svg'
|
||||
);
|
||||
let buttonIcon = document.createElementNS(
|
||||
'http://www.w3.org/2000/svg',
|
||||
'use'
|
||||
);
|
||||
|
||||
buttonIcon.setAttributeNS(
|
||||
'http://www.w3.org/1999/xlink',
|
||||
'xlink:href',
|
||||
'#crosshair'
|
||||
);
|
||||
|
||||
buttonIconContainer.appendChild(buttonIcon);
|
||||
|
||||
focusButton.append(buttonIconContainer);
|
||||
|
||||
focusButton.onclick = () => {
|
||||
this.focusProjectSubject.next(project.name);
|
||||
};
|
||||
|
||||
let label = document.createElement('label');
|
||||
label.className = 'form-checkbox';
|
||||
|
||||
let checkbox = document.createElement('input');
|
||||
checkbox.type = 'checkbox';
|
||||
checkbox.name = 'projectName';
|
||||
checkbox.value = project.name;
|
||||
checkbox.checked = false;
|
||||
|
||||
checkbox.addEventListener('change', () => this.emitChanges());
|
||||
|
||||
this.checkboxes[project.name] = checkbox;
|
||||
|
||||
const labelText = document.createTextNode(project.name);
|
||||
|
||||
formLine.append(focusButton);
|
||||
formLine.append(label);
|
||||
|
||||
label.append(checkbox);
|
||||
label.append(labelText);
|
||||
|
||||
formGroup.append(formLine);
|
||||
});
|
||||
|
||||
this.container.append(header);
|
||||
this.container.append(formGroup);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,226 @@
|
||||
import { BehaviorSubject } from 'rxjs';
|
||||
import { DisplayOptionsPanel } from './display-options-panel';
|
||||
import { FocusedProjectPanel } from './focused-project-panel';
|
||||
import { ProjectList } from './project-list';
|
||||
import { TextFilterPanel } from './text-filter-panel';
|
||||
|
||||
export class SidebarComponent {
|
||||
private selectedProjectsChangedSubject = new BehaviorSubject<string[]>([]);
|
||||
private groupByFolderChangedSubject = new BehaviorSubject<boolean>(
|
||||
window.groupByFolder
|
||||
);
|
||||
|
||||
selectedProjectsChanged$ = this.selectedProjectsChangedSubject.asObservable();
|
||||
groupByFolderChanged$ = this.groupByFolderChangedSubject.asObservable();
|
||||
|
||||
private displayOptionsPanel: DisplayOptionsPanel;
|
||||
private focusedProjectPanel: FocusedProjectPanel;
|
||||
private textFilterPanel: TextFilterPanel;
|
||||
private projectList: ProjectList;
|
||||
|
||||
private groupByFolder = window.groupByFolder;
|
||||
private selectedProjects: string[] = [];
|
||||
|
||||
constructor(private affectedProjects: string[], showDebugger: boolean) {
|
||||
const showAffected = this.affectedProjects.length > 0;
|
||||
|
||||
const displayOptionsPanelContainer = document.getElementById(
|
||||
'display-options-panel'
|
||||
);
|
||||
|
||||
this.displayOptionsPanel = new DisplayOptionsPanel(
|
||||
showAffected,
|
||||
this.groupByFolder
|
||||
);
|
||||
this.displayOptionsPanel.render(displayOptionsPanelContainer);
|
||||
|
||||
const focusedProjectPanelContainer = document.getElementById(
|
||||
'focused-project'
|
||||
);
|
||||
this.focusedProjectPanel = new FocusedProjectPanel(
|
||||
focusedProjectPanelContainer
|
||||
);
|
||||
|
||||
const textFilterPanelContainer = document.getElementById(
|
||||
'text-filter-panel'
|
||||
);
|
||||
this.textFilterPanel = new TextFilterPanel(textFilterPanelContainer);
|
||||
|
||||
const projectListContainer = document.getElementById('project-lists');
|
||||
this.projectList = new ProjectList(projectListContainer, window.projects);
|
||||
|
||||
if (showAffected) {
|
||||
this.selectAffectedProjects();
|
||||
}
|
||||
|
||||
window.focusProject = (projectId) => {
|
||||
this.focusProject(projectId);
|
||||
};
|
||||
|
||||
window.excludeProject = (projectId) => {
|
||||
this.excludeProject(projectId);
|
||||
};
|
||||
|
||||
this.listenForDOMEvents();
|
||||
|
||||
if (window.focusedProject !== null) {
|
||||
this.focusProject(window.focusedProject);
|
||||
}
|
||||
|
||||
if (window.exclude.length > 0) {
|
||||
window.exclude.forEach((project) => this.excludeProject(project));
|
||||
}
|
||||
}
|
||||
|
||||
listenForDOMEvents() {
|
||||
this.displayOptionsPanel.selectAll$.subscribe(() => {
|
||||
this.selectAllProjects();
|
||||
});
|
||||
|
||||
this.displayOptionsPanel.deselectAll$.subscribe(() => {
|
||||
this.deselectAllProjects();
|
||||
});
|
||||
|
||||
this.displayOptionsPanel.selectAffected$.subscribe(() => {
|
||||
this.selectAffectedProjects();
|
||||
});
|
||||
|
||||
this.displayOptionsPanel.groupByFolder$.subscribe((groupByFolder) => {
|
||||
this.groupByFolderChangedSubject.next(groupByFolder);
|
||||
});
|
||||
|
||||
this.focusedProjectPanel.unfocus$.subscribe(() => {
|
||||
this.unfocusProject();
|
||||
});
|
||||
|
||||
this.textFilterPanel.changes$.subscribe((event) => {
|
||||
this.filterProjectsByText(event.text, event.includeInPath);
|
||||
});
|
||||
|
||||
this.projectList.checkedProjectsChange$.subscribe((checkedProjects) => {
|
||||
this.emitSelectedProjects(checkedProjects);
|
||||
});
|
||||
|
||||
this.projectList.focusProject$.subscribe((projectName) => {
|
||||
this.focusProject(projectName);
|
||||
});
|
||||
}
|
||||
|
||||
private setFocusedProject(projectId: string = null) {
|
||||
window.focusedProject = projectId;
|
||||
if (projectId) {
|
||||
this.focusedProjectPanel.projectName = window.graph.nodes[projectId].name;
|
||||
} else {
|
||||
this.focusedProjectPanel.projectName = null;
|
||||
}
|
||||
}
|
||||
|
||||
selectAffectedProjects() {
|
||||
this.setFocusedProject(null);
|
||||
this.projectList.setCheckedProjects(this.affectedProjects);
|
||||
this.emitSelectedProjects(this.affectedProjects);
|
||||
}
|
||||
|
||||
selectAllProjects() {
|
||||
this.setFocusedProject(null);
|
||||
this.projectList.checkAllProjects();
|
||||
this.emitSelectedProjects(window.projects.map((project) => project.name));
|
||||
}
|
||||
|
||||
deselectAllProjects() {
|
||||
this.setFocusedProject(null);
|
||||
this.projectList.uncheckAllProjects();
|
||||
this.emitSelectedProjects([]);
|
||||
}
|
||||
|
||||
focusProject(id) {
|
||||
this.setFocusedProject(id);
|
||||
|
||||
const selectedProjects = window.projects
|
||||
.map((project) => project.name)
|
||||
.filter(
|
||||
(projectName) =>
|
||||
this.hasPath(id, projectName, []) || this.hasPath(projectName, id, [])
|
||||
);
|
||||
|
||||
this.projectList.setCheckedProjects(selectedProjects);
|
||||
|
||||
this.emitSelectedProjects(selectedProjects);
|
||||
}
|
||||
|
||||
unfocusProject() {
|
||||
this.setFocusedProject(null);
|
||||
|
||||
this.projectList.uncheckAllProjects();
|
||||
|
||||
this.emitSelectedProjects([]);
|
||||
}
|
||||
|
||||
excludeProject(id: string) {
|
||||
const selectedProjects = [...this.selectedProjects];
|
||||
selectedProjects.splice(this.selectedProjects.indexOf(id), 1);
|
||||
|
||||
this.projectList.uncheckProject(id);
|
||||
this.emitSelectedProjects(selectedProjects);
|
||||
}
|
||||
|
||||
emitSelectedProjects(selectedProjects: string[]) {
|
||||
this.selectedProjects = selectedProjects;
|
||||
|
||||
if (selectedProjects.length === 0) {
|
||||
document.getElementById('no-projects-chosen').style.display = 'flex';
|
||||
} else {
|
||||
document.getElementById('no-projects-chosen').style.display = 'none';
|
||||
}
|
||||
|
||||
this.selectedProjectsChangedSubject.next(selectedProjects);
|
||||
}
|
||||
|
||||
filterProjectsByText(text: string, includeInPath: boolean) {
|
||||
this.setFocusedProject(null);
|
||||
this.projectList.uncheckAllProjects();
|
||||
|
||||
const split = text.split(',').map((splitItem) => splitItem.trim());
|
||||
|
||||
const selectedProjects = new Set<string>();
|
||||
|
||||
window.projects
|
||||
.map((project) => project.name)
|
||||
.forEach((project) => {
|
||||
const projectMatch =
|
||||
split.findIndex((splitItem) => project.includes(splitItem)) > -1;
|
||||
|
||||
if (projectMatch) {
|
||||
selectedProjects.add(project);
|
||||
|
||||
if (includeInPath) {
|
||||
window.projects
|
||||
.map((project) => project.name)
|
||||
.forEach((projectInPath) => {
|
||||
if (
|
||||
this.hasPath(project, projectInPath, []) ||
|
||||
this.hasPath(projectInPath, project, [])
|
||||
) {
|
||||
selectedProjects.add(projectInPath);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
const selectedProjectsArray = Array.from(selectedProjects);
|
||||
this.projectList.setCheckedProjects(selectedProjectsArray);
|
||||
this.emitSelectedProjects(selectedProjectsArray);
|
||||
}
|
||||
|
||||
private hasPath(target, node, visited) {
|
||||
if (target === node) return true;
|
||||
|
||||
for (let d of window.graph.dependencies[node] || []) {
|
||||
if (visited.indexOf(d.target) > -1) continue;
|
||||
visited.push(d.target);
|
||||
if (this.hasPath(target, d.target, visited)) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
import { Subject } from 'rxjs';
|
||||
import { removeChildrenFromContainer } from '../util';
|
||||
|
||||
export interface TextFilterChangeEvent {
|
||||
text: string;
|
||||
includeInPath: boolean;
|
||||
}
|
||||
|
||||
export class TextFilterPanel {
|
||||
private textInput: HTMLInputElement;
|
||||
private includeInPathCheckbox: HTMLInputElement;
|
||||
private changesSubject = new Subject<TextFilterChangeEvent>();
|
||||
|
||||
changes$ = this.changesSubject.asObservable();
|
||||
|
||||
constructor(private container: HTMLElement) {
|
||||
this.render();
|
||||
}
|
||||
|
||||
private emitChanges() {
|
||||
this.changesSubject.next({
|
||||
text: this.textInput.value.toLowerCase(),
|
||||
includeInPath: this.includeInPathCheckbox.checked,
|
||||
});
|
||||
}
|
||||
|
||||
private render() {
|
||||
removeChildrenFromContainer(this.container);
|
||||
|
||||
const inputContainer = document.createElement('div');
|
||||
inputContainer.classList.add('flex');
|
||||
|
||||
this.textInput = document.createElement('input');
|
||||
this.textInput.type = 'text';
|
||||
this.textInput.name = 'filter';
|
||||
this.textInput.dataset['cy'] = 'textFilterInput';
|
||||
this.textInput.addEventListener('keyup', (event) => {
|
||||
if (event.key === 'Enter') {
|
||||
this.emitChanges();
|
||||
}
|
||||
});
|
||||
this.textInput.style.flex = '1';
|
||||
this.textInput.style.marginRight = '1.5em';
|
||||
|
||||
const filterButton = document.createElement('button');
|
||||
filterButton.innerText = 'Filter';
|
||||
filterButton.dataset['cy'] = 'textFilterButton';
|
||||
filterButton.style.flex = 'none';
|
||||
|
||||
filterButton.addEventListener('click', () => {
|
||||
this.emitChanges();
|
||||
});
|
||||
|
||||
inputContainer.appendChild(this.textInput);
|
||||
inputContainer.appendChild(filterButton);
|
||||
|
||||
const includeProjectLabel = document.createElement('label');
|
||||
this.includeInPathCheckbox = document.createElement('input');
|
||||
this.includeInPathCheckbox.type = 'checkbox';
|
||||
this.includeInPathCheckbox.name = 'textFilterCheckbox';
|
||||
this.includeInPathCheckbox.value = 'includeInPath';
|
||||
|
||||
includeProjectLabel.appendChild(this.includeInPathCheckbox);
|
||||
includeProjectLabel.appendChild(
|
||||
document.createTextNode('include projects in path')
|
||||
);
|
||||
|
||||
this.container.appendChild(inputContainer);
|
||||
this.container.appendChild(includeProjectLabel);
|
||||
}
|
||||
}
|
||||
+5
-5
@@ -1,14 +1,14 @@
|
||||
import { EdgeSingular, Position, BaseLayoutOptions } from 'cytoscape';
|
||||
import * as cy from 'cytoscape';
|
||||
|
||||
export interface CytoscapeDagreConfig extends BaseLayoutOptions {
|
||||
export interface CytoscapeDagreConfig extends cy.BaseLayoutOptions {
|
||||
// dagre algo options, uses default value on undefined
|
||||
nodeSep: number; // the separation between adjacent nodes in the same rank
|
||||
edgeSep: number; // the separation between adjacent edges in the same rank
|
||||
rankSep: number; // the separation between each rank in the layout
|
||||
rankDir: 'TB' | 'LR'; // 'TB' for top to bottom flow, 'LR' for left to right,
|
||||
ranker: 'network-simplex' | 'tight-tree' | 'longest-path'; // Type of algorithm to assign a rank to each node in the input graph. Possible values: 'network-simplex', 'tight-tree' or 'longest-path'
|
||||
minLen: (edge: EdgeSingular) => number; // number of ranks to keep between the source and target of the edge
|
||||
edgeWeight: (edge: EdgeSingular) => number; // higher weight edges are generally made shorter and straighter than lower weight edges
|
||||
minLen: (edge: cy.EdgeSingular) => number; // number of ranks to keep between the source and target of the edge
|
||||
edgeWeight: (edge: cy.EdgeSingular) => number; // higher weight edges are generally made shorter and straighter than lower weight edges
|
||||
|
||||
// general layout options
|
||||
fit: boolean; // whether to fit to viewport
|
||||
@@ -22,7 +22,7 @@ export interface CytoscapeDagreConfig extends BaseLayoutOptions {
|
||||
boundingBox:
|
||||
| { x1: number; y1: number; x2: number; y2: number }
|
||||
| { x1: number; y1: number; w: number; h: number }; // constrain layout bounds; { x1, y1, x2, y2 } or { x1, y1, w, h }
|
||||
transform: (node, pos) => Position; // a function that applies a transform to the final node position
|
||||
transform: (node, pos) => cy.Position; // a function that applies a transform to the final node position
|
||||
ready: () => void; // on layoutready
|
||||
stop: () => void; // on layoutstop
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
import { ProjectGraphDependency } from '@nrwl/workspace';
|
||||
|
||||
import * as cy from 'cytoscape';
|
||||
|
||||
export class ProjectEdge {
|
||||
affected = false;
|
||||
|
||||
constructor(private dep: ProjectGraphDependency) {}
|
||||
|
||||
getCytosacpeNodeDef(): cy.NodeDefinition {
|
||||
let edge: cy.EdgeDefinition;
|
||||
edge = {
|
||||
group: 'edges',
|
||||
data: {
|
||||
id: `${this.dep.source}|${this.dep.target}`,
|
||||
source: this.dep.source,
|
||||
target: this.dep.target,
|
||||
},
|
||||
};
|
||||
edge.classes = this.dep.type ?? '';
|
||||
if (this.affected) {
|
||||
edge.classes += ' affected';
|
||||
}
|
||||
|
||||
return edge;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
export * from './cytoscape.models';
|
||||
export * from './edge';
|
||||
export * from './parent-node';
|
||||
export * from './project-node';
|
||||
+1
-3
@@ -5,15 +5,13 @@ export class ParentNode {
|
||||
private config: { id: string; parentId: string; label: string }
|
||||
) {}
|
||||
|
||||
getCytoscapeNodeDef(): cy.NodeDefinition & { pannable?: boolean } {
|
||||
getCytoscapeNodeDef(): cy.NodeDefinition {
|
||||
return {
|
||||
group: 'nodes',
|
||||
classes: 'parentNode',
|
||||
data: {
|
||||
id: this.config.id,
|
||||
parent: this.config.parentId,
|
||||
label: this.config.label,
|
||||
type: 'dir',
|
||||
},
|
||||
selectable: false,
|
||||
grabbable: false,
|
||||
+9
-6
@@ -4,7 +4,6 @@ describe('ProjectNode', () => {
|
||||
describe('app nodes', () => {
|
||||
it('should not set parentId if groupByFolder is false', () => {
|
||||
const projectNode = new ProjectNode(
|
||||
{},
|
||||
{
|
||||
name: 'sub-app',
|
||||
type: 'app',
|
||||
@@ -12,7 +11,9 @@ describe('ProjectNode', () => {
|
||||
projectType: 'application',
|
||||
root: 'apps/sub/app',
|
||||
sourceRoot: 'apps/sub/app/src',
|
||||
prefix: 'sub-app',
|
||||
tags: [],
|
||||
files: [],
|
||||
},
|
||||
},
|
||||
'apps'
|
||||
@@ -25,7 +26,6 @@ describe('ProjectNode', () => {
|
||||
|
||||
it('should not set parentId if app is not nested', () => {
|
||||
const projectNode = new ProjectNode(
|
||||
{},
|
||||
{
|
||||
name: 'app',
|
||||
type: 'app',
|
||||
@@ -33,7 +33,9 @@ describe('ProjectNode', () => {
|
||||
projectType: 'application',
|
||||
root: 'apps/app',
|
||||
sourceRoot: 'apps/app/src',
|
||||
prefix: 'app',
|
||||
tags: [],
|
||||
files: [],
|
||||
},
|
||||
},
|
||||
'apps'
|
||||
@@ -46,7 +48,6 @@ describe('ProjectNode', () => {
|
||||
|
||||
it('should set parentId if the app is nested and groupByFolder is true', () => {
|
||||
const projectNode = new ProjectNode(
|
||||
{},
|
||||
{
|
||||
name: 'sub-app',
|
||||
type: 'app',
|
||||
@@ -54,7 +55,9 @@ describe('ProjectNode', () => {
|
||||
projectType: 'application',
|
||||
root: 'apps/sub/app',
|
||||
sourceRoot: 'apps/sub/app/src',
|
||||
prefix: 'sub-app',
|
||||
tags: [],
|
||||
files: [],
|
||||
},
|
||||
},
|
||||
'apps'
|
||||
@@ -69,7 +72,6 @@ describe('ProjectNode', () => {
|
||||
describe('lib nodes', () => {
|
||||
it('should not set parentId if groupByFolder is false', () => {
|
||||
const projectNode = new ProjectNode(
|
||||
{},
|
||||
{
|
||||
name: 'sub-lib',
|
||||
type: 'lib',
|
||||
@@ -77,6 +79,7 @@ describe('ProjectNode', () => {
|
||||
root: 'libs/sub/lib',
|
||||
sourceRoot: 'libs/sub/lib/src',
|
||||
projectType: 'library',
|
||||
files: [],
|
||||
},
|
||||
},
|
||||
'libs'
|
||||
@@ -89,7 +92,6 @@ describe('ProjectNode', () => {
|
||||
|
||||
it('should not set parentId if lib is not nested', () => {
|
||||
const projectNode = new ProjectNode(
|
||||
{},
|
||||
{
|
||||
name: 'lib',
|
||||
type: 'lib',
|
||||
@@ -97,6 +99,7 @@ describe('ProjectNode', () => {
|
||||
root: 'libs/lib',
|
||||
sourceRoot: 'libs/lib/src',
|
||||
projectType: 'library',
|
||||
files: [],
|
||||
},
|
||||
},
|
||||
'libs'
|
||||
@@ -109,7 +112,6 @@ describe('ProjectNode', () => {
|
||||
|
||||
it('should set parentId if the lib is nested and groupByFolder is true', () => {
|
||||
const projectNode = new ProjectNode(
|
||||
{},
|
||||
{
|
||||
name: 'sub-lib',
|
||||
type: 'lib',
|
||||
@@ -117,6 +119,7 @@ describe('ProjectNode', () => {
|
||||
root: 'libs/sub/lib',
|
||||
sourceRoot: 'libs/sub/lib/src',
|
||||
projectType: 'library',
|
||||
files: [],
|
||||
},
|
||||
},
|
||||
'libs'
|
||||
@@ -0,0 +1,97 @@
|
||||
import { ProjectGraphNode } from '@nrwl/workspace';
|
||||
import * as cy from 'cytoscape';
|
||||
import { parseParentDirectoriesFromPilePath } from '../util';
|
||||
|
||||
interface NodeDataDefinition extends cy.NodeDataDefinition {
|
||||
id: string;
|
||||
type: string;
|
||||
tags: string[];
|
||||
}
|
||||
|
||||
interface Ancestor {
|
||||
id: string;
|
||||
parentId: string;
|
||||
label: string;
|
||||
}
|
||||
export class ProjectNode {
|
||||
affected = false;
|
||||
focused = false;
|
||||
|
||||
constructor(
|
||||
private project: ProjectGraphNode,
|
||||
private workspaceRoot: string
|
||||
) {}
|
||||
|
||||
getCytoscapeNodeDef(groupByFolder: boolean): cy.NodeDefinition {
|
||||
return {
|
||||
group: 'nodes',
|
||||
data: this.getData(groupByFolder),
|
||||
classes: this.getClasses(),
|
||||
selectable: false,
|
||||
grabbable: false,
|
||||
pannable: true,
|
||||
};
|
||||
}
|
||||
|
||||
private getData(groupByFolder: boolean): NodeDataDefinition {
|
||||
return {
|
||||
id: this.project.name,
|
||||
type: this.project.type,
|
||||
tags: this.project.data.tags,
|
||||
parent:
|
||||
groupByFolder && this.project.data.hasOwnProperty('root')
|
||||
? this.getParentId()
|
||||
: null,
|
||||
};
|
||||
}
|
||||
|
||||
private getClasses(): string {
|
||||
let classes = this.project.type ?? '';
|
||||
|
||||
if (this.focused) {
|
||||
classes += ' focused';
|
||||
}
|
||||
|
||||
if (this.affected) {
|
||||
classes += ' affected';
|
||||
}
|
||||
|
||||
return classes;
|
||||
}
|
||||
|
||||
private getParentId(): string | null {
|
||||
const ancestors = this.getAncestors();
|
||||
|
||||
if (ancestors.length > 0) {
|
||||
return ancestors[ancestors.length - 1].id;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public getAncestors(): Ancestor[] {
|
||||
// if there's no root, we can't figure out the parent
|
||||
if (!this.project.data.root) {
|
||||
return [];
|
||||
}
|
||||
|
||||
const directories = parseParentDirectoriesFromPilePath(
|
||||
this.project.data.root,
|
||||
this.workspaceRoot
|
||||
);
|
||||
|
||||
return directories.map((directory, index, allDirectories) => {
|
||||
const label = [...allDirectories].slice(0, index + 1).join('/');
|
||||
const id = `dir-${label}`;
|
||||
const parentId =
|
||||
index > 0
|
||||
? `dir-${[...allDirectories].slice(0, index).join('/')}`
|
||||
: null;
|
||||
return {
|
||||
label,
|
||||
id,
|
||||
parentId,
|
||||
};
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
import { parseParentDirectoriesFromPilePath } from './util';
|
||||
|
||||
describe('parseParentDirectoriesFromPilePath', () => {
|
||||
// path, workspaceRoot, output
|
||||
const cases: [string, string, string[]][] = [
|
||||
['apps/app1', 'apps', []],
|
||||
['apps/app1', '', ['apps']],
|
||||
['apps/nested/app1', 'apps', ['nested']],
|
||||
['libs/scope/some-lib', 'libs', ['scope']],
|
||||
[
|
||||
'libs/very/very/very/deeply/nested/lib',
|
||||
'libs',
|
||||
['very', 'very', 'very', 'deeply', 'nested'],
|
||||
],
|
||||
['packages/published', 'packages', []],
|
||||
['packages/published', '', ['packages']],
|
||||
['packages/published', 'libs', ['packages']],
|
||||
['libs/trailing/slash/', 'libs', ['trailing']],
|
||||
['libs/trailing/slash', 'libs/', ['trailing']],
|
||||
];
|
||||
|
||||
test.each(cases)(
|
||||
'given filepath %p and workspaceRoot %p, parent directories are %p',
|
||||
(path, workspaceRoot, expected) => {
|
||||
const result = parseParentDirectoriesFromPilePath(path, workspaceRoot);
|
||||
|
||||
expect(result).toEqual(expected);
|
||||
}
|
||||
);
|
||||
});
|
||||
@@ -0,0 +1,29 @@
|
||||
export function removeChildrenFromContainer(container: HTMLElement) {
|
||||
Array.from(container.children).forEach((child) =>
|
||||
container.removeChild(child)
|
||||
);
|
||||
}
|
||||
|
||||
export function trimBackSlash(value: string): string {
|
||||
return value.replace(/\/$/, '');
|
||||
}
|
||||
|
||||
export function parseParentDirectoriesFromPilePath(
|
||||
path: string,
|
||||
workspaceRoot: string
|
||||
) {
|
||||
const root = trimBackSlash(path);
|
||||
|
||||
// split the source root on directory separator
|
||||
const split: string[] = root.split('/');
|
||||
|
||||
// check the first part for libs or apps, depending on workspaceLayout
|
||||
if (split[0] === trimBackSlash(workspaceRoot)) {
|
||||
split.shift();
|
||||
}
|
||||
|
||||
// pop off the last element, which should be the lib name
|
||||
split.pop();
|
||||
|
||||
return split;
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
import { AppConfig } from '../app/app';
|
||||
|
||||
export const environment: { release: boolean; appConfig: AppConfig } = {
|
||||
release: true,
|
||||
appConfig: {
|
||||
showDebugger: false,
|
||||
},
|
||||
};
|
||||
@@ -0,0 +1,11 @@
|
||||
// This file can be replaced during build by using the `fileReplacements` array.
|
||||
// When building for production, this file is replaced with `environment.prod.ts`.
|
||||
|
||||
import { AppConfig } from '../app/app';
|
||||
|
||||
export const environment: { release: boolean; appConfig: AppConfig } = {
|
||||
release: false,
|
||||
appConfig: {
|
||||
showDebugger: true,
|
||||
},
|
||||
};
|
||||
|
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 15 KiB |
Vendored
+44
@@ -0,0 +1,44 @@
|
||||
import { WorkspaceConfiguration } from '@nrwl/devkit';
|
||||
import { ProjectGraph, ProjectGraphNode } from '@nrwl/workspace';
|
||||
import { ProjectGraphList } from './graphs';
|
||||
|
||||
export declare global {
|
||||
export interface Window {
|
||||
projects: ProjectGraphNode[];
|
||||
graph: ProjectGraph;
|
||||
filteredProjects: ProjectGraphNode[];
|
||||
affected: string[];
|
||||
exclude: string[];
|
||||
focusedProject: string;
|
||||
groupByFolder: boolean;
|
||||
focusProject: Function;
|
||||
excludeProject: Function;
|
||||
projectGraphList: ProjectGraphList[];
|
||||
selectedProjectGraph: string;
|
||||
workspaceLayout: {
|
||||
libsDir: string;
|
||||
appsDir: string;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
declare module 'cytoscape' {
|
||||
interface Core {
|
||||
anywherePanning: Function;
|
||||
}
|
||||
|
||||
interface ElementDefinition {
|
||||
pannable?: boolean;
|
||||
}
|
||||
|
||||
interface NodeSingular {
|
||||
popperRef: Function;
|
||||
pannable: () => boolean;
|
||||
}
|
||||
|
||||
namespace Css {
|
||||
interface EdgeLine {
|
||||
'edge-text-rotation'?: string;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
import { ProjectGraphList } from '../app/models';
|
||||
import { oceanGraph, oceanWorkspaceLayout } from './ocean';
|
||||
import { nxGraph, nxWorkspaceLayout } from './nx';
|
||||
import { storybookGraph, storybookWorkspaceLayout } from './storybook';
|
||||
import { subAppsGraph, subAppsWorkspaceLayout } from './sub-apps';
|
||||
import { nxExamplesGraph, nxExamplesWorkspaceLayout } from './nx-examples';
|
||||
|
||||
export const projectGraphs: ProjectGraphList[] = [
|
||||
{
|
||||
id: 'nx',
|
||||
label: 'Nx',
|
||||
graph: nxGraph,
|
||||
workspaceLayout: nxWorkspaceLayout,
|
||||
},
|
||||
{
|
||||
id: 'ocean',
|
||||
label: 'Ocean',
|
||||
graph: oceanGraph,
|
||||
workspaceLayout: oceanWorkspaceLayout,
|
||||
},
|
||||
{
|
||||
id: 'nx-examples',
|
||||
label: 'Nx Examples',
|
||||
graph: nxExamplesGraph,
|
||||
workspaceLayout: nxExamplesWorkspaceLayout,
|
||||
},
|
||||
{
|
||||
id: 'sub-apps',
|
||||
label: 'Sub Apps',
|
||||
graph: subAppsGraph,
|
||||
workspaceLayout: subAppsWorkspaceLayout,
|
||||
},
|
||||
{
|
||||
id: 'storybook',
|
||||
label: 'Storybook',
|
||||
graph: storybookGraph,
|
||||
workspaceLayout: storybookWorkspaceLayout,
|
||||
},
|
||||
];
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,65 @@
|
||||
<!DOCTYPE html>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
|
||||
<title>Nx Workspace Dependency Graph</title>
|
||||
<base href="/" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
|
||||
<link
|
||||
href="https://fonts.googleapis.com/css?family=Montserrat&display=swap"
|
||||
rel="stylesheet"
|
||||
/>
|
||||
</head>
|
||||
<body>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" style="display: none">
|
||||
<symbol id="crosshair" viewBox="0 0 24 24">
|
||||
<g
|
||||
fill="none"
|
||||
stroke="#ffffff"
|
||||
stroke-width="2"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
>
|
||||
<circle cx="12" cy="12" r="10" />
|
||||
<line x1="22" y1="12" x2="18" y2="12" />
|
||||
<line x1="6" y1="12" x2="2" y2="12" />
|
||||
<line x1="12" y1="6" x2="12" y2="2" />
|
||||
<line x1="12" y1="22" x2="12" y2="18" />
|
||||
</g>
|
||||
</symbol>
|
||||
</svg>
|
||||
|
||||
<div id="app">
|
||||
<div class="sidebar">
|
||||
<div class="sidebar-content">
|
||||
<div class="sidebar-section" id="focused-project"></div>
|
||||
|
||||
<div class="sidebar-section" id="display-options-panel"></div>
|
||||
|
||||
<div class="sidebar-section" id="text-filter-panel"></div>
|
||||
|
||||
<div id="project-lists"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="main-content">
|
||||
<div id="debugger-panel" hidden></div>
|
||||
<div id="no-projects-chosen">
|
||||
<h4>Please select projects in the sidebar.</h4>
|
||||
</div>
|
||||
<div id="graph-container"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
window.projects = [];
|
||||
window.graph = {};
|
||||
window.affected = [];
|
||||
window.focusedProject = null;
|
||||
window.filteredProjects = [];
|
||||
window.groupByFolder = false;
|
||||
window.exclude = [];
|
||||
window.workspaceLayout = null;
|
||||
</script>
|
||||
</body>
|
||||
@@ -0,0 +1,21 @@
|
||||
import { AppComponent } from './app/app';
|
||||
import { environment } from './environments/environment';
|
||||
import { projectGraphs } from './graphs';
|
||||
import { nxGraph } from './graphs/nx';
|
||||
|
||||
if (!environment.release) {
|
||||
const currentGraph = nxGraph;
|
||||
|
||||
const nodes = Object.values(currentGraph.nodes).filter(
|
||||
(node) => node.type !== 'npm'
|
||||
);
|
||||
|
||||
window.projects = nodes;
|
||||
window.graph = currentGraph;
|
||||
window.affected = [];
|
||||
window.exclude = [];
|
||||
window.projectGraphList = projectGraphs;
|
||||
window.selectedProjectGraph = projectGraphs[0].id;
|
||||
window.workspaceLayout = projectGraphs[0].workspaceLayout;
|
||||
}
|
||||
setTimeout(() => new AppComponent(environment.appConfig));
|
||||
@@ -0,0 +1,221 @@
|
||||
@import '~tippy.js/dist/tippy.css';
|
||||
|
||||
$color-nrwl-blue: #48c4e5 !default;
|
||||
$color-nrwl-light-blue: #96d8e9 !default;
|
||||
$color-nrwl-gray: #333333 !default;
|
||||
$color-nrwl-navy: #143055 !default;
|
||||
$color-nrwl-twilight: #086c9f !default;
|
||||
$color-nrwl-black: #231f20 !default;
|
||||
$color-nrwl-red: #f85477 !default;
|
||||
$font-family: 'Montserrat', 'Helvetica Neue', sans-serif !default;
|
||||
$color-primary: $color-nrwl-navy !default;
|
||||
|
||||
* {
|
||||
-webkit-box-sizing: border-box;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
html {
|
||||
line-height: 1.6;
|
||||
font-size: 14px;
|
||||
font-family: $font-family;
|
||||
}
|
||||
|
||||
button {
|
||||
padding: 0.5em 1em;
|
||||
border-radius: 4px;
|
||||
border: 1px solid transparent;
|
||||
font-size: 1em;
|
||||
line-height: 1;
|
||||
text-align: center;
|
||||
-webkit-transition: opacity 0.2s ease;
|
||||
transition: opacity 0.2s ease;
|
||||
text-decoration: none;
|
||||
-webkit-transform: scale(1);
|
||||
transform: scale(1);
|
||||
display: inline-block;
|
||||
cursor: pointer;
|
||||
|
||||
background-color: $color-primary;
|
||||
color: #fff;
|
||||
|
||||
&:hover {
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
||||
&.icon {
|
||||
width: 1.5em;
|
||||
height: 1.5em;
|
||||
padding: 0;
|
||||
text-align: center;
|
||||
line-height: 50%;
|
||||
|
||||
svg {
|
||||
width: 1.25em;
|
||||
height: 1.25em;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.form-line {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
label {
|
||||
flex: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.flex {
|
||||
display: flex;
|
||||
|
||||
button {
|
||||
flex: 1;
|
||||
|
||||
&:not(:last-child) {
|
||||
margin-right: 1.5em;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
label {
|
||||
display: inline-block;
|
||||
margin: 0.5em 0;
|
||||
}
|
||||
|
||||
h4,
|
||||
h5 {
|
||||
margin-top: 0;
|
||||
margin-bottom: 0.5em;
|
||||
}
|
||||
|
||||
.form-group {
|
||||
margin-bottom: 1em;
|
||||
}
|
||||
|
||||
.sidebar {
|
||||
min-width: 260px;
|
||||
max-width: calc(50% - 10px);
|
||||
z-index: 1;
|
||||
position: relative;
|
||||
height: 100%;
|
||||
box-shadow: 2px 0 2px rgba(51, 51, 51, 0.1);
|
||||
}
|
||||
|
||||
.sidebar > .sidebar-content {
|
||||
box-sizing: border-box;
|
||||
height: 100%;
|
||||
overflow-y: auto;
|
||||
padding: 1.5em;
|
||||
width: 100%;
|
||||
|
||||
> .sidebar-section {
|
||||
margin-bottom: 1em;
|
||||
}
|
||||
|
||||
h5 {
|
||||
color: $color-nrwl-twilight;
|
||||
}
|
||||
|
||||
.form-line {
|
||||
display: flex;
|
||||
}
|
||||
.form-line label {
|
||||
flex: 1;
|
||||
}
|
||||
}
|
||||
|
||||
#main-content {
|
||||
flex: 1;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
#debugger-panel {
|
||||
display: none;
|
||||
width: 100%;
|
||||
background-color: $color-nrwl-light-blue;
|
||||
padding: 1.5em;
|
||||
align-items: baseline;
|
||||
|
||||
& > * {
|
||||
margin-right: 1em;
|
||||
}
|
||||
|
||||
p {
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
|
||||
#apps,
|
||||
#libs,
|
||||
#e2e {
|
||||
padding: 0;
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
#apps,
|
||||
#libs,
|
||||
#e2e input {
|
||||
padding-right: 8px;
|
||||
}
|
||||
|
||||
#app,
|
||||
body,
|
||||
html {
|
||||
height: 100%;
|
||||
margin: 0;
|
||||
overflow: hidden;
|
||||
padding: 0;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
#app {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.tippy-box[data-theme~='nx'] {
|
||||
background-color: $color-nrwl-twilight;
|
||||
|
||||
.tippy-content {
|
||||
padding: 1.5em;
|
||||
}
|
||||
|
||||
&[data-placement^='top'] > .tippy-arrow::before {
|
||||
border-top-color: $color-nrwl-twilight;
|
||||
}
|
||||
&[data-placement^='bottom'] > .tippy-arrow::before {
|
||||
border-bottom-color: $color-nrwl-twilight;
|
||||
}
|
||||
&[data-placement^='left'] > .tippy-arrow::before {
|
||||
border-left-color: $color-nrwl-twilight;
|
||||
}
|
||||
&[data-placement^='right'] > .tippy-arrow::before {
|
||||
border-right-color: $color-nrwl-twilight;
|
||||
}
|
||||
}
|
||||
|
||||
.tag {
|
||||
padding: 0.5rem;
|
||||
font-size: 0.75em;
|
||||
display: inline-block;
|
||||
border: 1px solid $color-nrwl-light-blue;
|
||||
text-transform: uppercase;
|
||||
color: #fff;
|
||||
line-height: 1;
|
||||
letter-spacing: 0.5px;
|
||||
margin-right: 0.4em;
|
||||
}
|
||||
|
||||
#no-projects-chosen {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
#graph-container {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
import 'document-register-element';
|
||||
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"extends": "./tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "../../dist/out-tsc",
|
||||
"types": ["node"],
|
||||
"lib": ["DOM"]
|
||||
},
|
||||
"exclude": ["**/*.spec.ts"],
|
||||
"include": ["**/*.ts"]
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"extends": "../../tsconfig.base.json",
|
||||
"files": [],
|
||||
"include": [],
|
||||
"references": [
|
||||
{
|
||||
"path": "./tsconfig.app.json"
|
||||
},
|
||||
{
|
||||
"path": "./tsconfig.spec.json"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"extends": "./tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "../../dist/out-tsc",
|
||||
"module": "commonjs",
|
||||
"types": ["jest", "node"],
|
||||
"lib": ["DOM"]
|
||||
},
|
||||
"files": ["src/test-setup.ts"],
|
||||
"include": ["**/*.spec.ts", "**/*.d.ts"]
|
||||
}
|
||||
-345
@@ -1,345 +0,0 @@
|
||||
# Documentation
|
||||
|
||||
## Structure of the Documentation
|
||||
|
||||
When writing documentation, it is important to know the audience you are writing for and what kind of document you are writing. We try to follow the framework listed below, but there are always some exceptions since the documentation is always changing. This framework is valuable to keep in mind, but we also follow the principle that if a PR is better than the existing content on the site, we'll merge it in and follow up to make it better later if it doesn't perfectly match the standards.
|
||||
|
||||
### Types of Documents
|
||||
|
||||
We are generally following the [Diataxis](https://diataxis.fr) model where documents are divided into tutorials, concept guides, recipes and reference.
|
||||
|
||||
- Tutorial - Focused on explaining a concept through step by step instructions.
|
||||
- Concept guide - Explains why something works the way it does or how to think about something.
|
||||
- Recipe - Focused directions to accomplish a specific task. Describes how to do something.
|
||||
- Reference - Lists what you can do with the tool (i.e. API docs).
|
||||
|
||||
### Audiences
|
||||
|
||||
We also have different audiences in mind when writing docs:
|
||||
|
||||
👶 New user
|
||||
|
||||
- They know their framework of choice
|
||||
- They have probably heard the term monorepo but don't really know what it is
|
||||
- They're smart and eager to learn
|
||||
|
||||
👦 Intermediate User
|
||||
|
||||
- They know how to create an Nx repo or add Nx to an existing repo
|
||||
- They have heard the terms integrated and package-based
|
||||
- They know what a project is and how to make one
|
||||
- They understand how to run a task and the basics of caching
|
||||
- They can launch the graph
|
||||
- They know that it is possible to enforce project boundaries
|
||||
|
||||
👨🦳 Advanced User
|
||||
|
||||
- They know everything about Nx except the specific piece of knowledge that is being taught by this document.
|
||||
|
||||
### Outline
|
||||
|
||||
- Getting Started - These documents assume a new user and are generally concept guides with a lot of links to other parts of the site. There are some elements of recipes mixed in, but those should be kept to a minimum.
|
||||
- Tutorials - These are tutorials written for a new user. After completing one of these tutorials, the user should have enough knowledge to be an intermediate user.
|
||||
- Core Features - These are primarily recipes with a little concept mixed in. These documents should be short and provide the basic information that people will want 80% of the time and link to anything more complex. A new user should be able to click through these documents and skim them to get a good understanding of what Nx does without getting overwhelmed with details.
|
||||
- Concepts - These are concept guides written for a new user. Any recipe content should be split into a recipe document and linked.
|
||||
- More Concepts (or other categories under Concepts) - These are concept guides written for an intermediate user.
|
||||
- Recipes - These are recipes written for an advanced user.
|
||||
- Nx with Your Favorite Tech - These are tutorials written for an intermediate user.
|
||||
- Benchmarks - Reference documents linking to external resources.
|
||||
- Reference - Reference documents.
|
||||
|
||||
## Markdown syntax available
|
||||
|
||||
The default markdown syntax is supported when writing documentation.
|
||||
|
||||
### Front matter
|
||||
|
||||
Front matter is used to add metadata to your Markdown file (`title` & `description`). It is provided at the very top of the file, enclosed by three dashes `---`. The content is parsed as `YAML`.
|
||||
|
||||
If no Front matter is detected, the metadata will be populated with the following:
|
||||
|
||||
- `title`: first main title detected
|
||||
- `description`: first paragraph detected
|
||||
|
||||
```markdown
|
||||
---
|
||||
title: This is a custom title
|
||||
description: This is a custom description
|
||||
---
|
||||
```
|
||||
|
||||
### Custom markdown syntax
|
||||
|
||||
The documentation website [nx.dev](https://nx.dev) is using custom Markdown syntax to enable the authors to add functionality to its content.
|
||||
|
||||
#### Callouts
|
||||
|
||||
Callouts are available to get the attention of the reader on some specific type of information.
|
||||
|
||||
```markdown
|
||||
{% callout type="caution|check|note|warning" title="string" %}
|
||||
Your content goes here.
|
||||
{% /callout %}
|
||||
```
|
||||
|
||||
#### Cards
|
||||
|
||||
Cards allow showing content in a grid system with a title, a description, a type and an url (internal/external).
|
||||
|
||||
```markdown
|
||||
{% cards %}
|
||||
{% card title="string" description="string" type="documentation|external|video" url="string" /%}
|
||||
{% card title="string" description="string" type="documentation|external|video" url="string" /%}
|
||||
// as many as cards you want
|
||||
{% /cards %}
|
||||
```
|
||||
|
||||
Title cards allow to only show a title in a card with a title and an url.
|
||||
|
||||
```markdown
|
||||
{% cards cols="4" %}
|
||||
{% title-card title="string" url="string" /%}
|
||||
{% title-card title="string" url="string" /%}
|
||||
{% title-card title="string" url="string" /%}
|
||||
{% title-card title="string" url="string" /%}
|
||||
{% /cards %}
|
||||
```
|
||||
|
||||
#### Code
|
||||
|
||||
You can add specific languages and a filename on the code snippet displayed.
|
||||
|
||||
````
|
||||
```javascript {% fileName="main.js" %}
|
||||
const code = "goes here";
|
||||
```
|
||||
````
|
||||
|
||||
#### Line Highlighting
|
||||
|
||||
You can define groups of lines that can be interactively highlighted to illustrate a point.
|
||||
|
||||
````
|
||||
```javascript {% lineGroups={ first:[2,3],second:[4,5] } %}
|
||||
const code = "goes here";
|
||||
This is in the first group
|
||||
This is also in the first group
|
||||
This is in the second group
|
||||
This is also in the second group
|
||||
```
|
||||
````
|
||||
|
||||
The line groups can be highlighted using a button on the code fence itself, or by clicking on a link that you provide that changes the url fragment.
|
||||
|
||||
For example:
|
||||
|
||||
```
|
||||
[This will highlight the first group.](#first)
|
||||
```
|
||||
|
||||
You can also statically highlight a set of lines (the user won't be able to change what is highlighted):
|
||||
|
||||
````
|
||||
```javascript {% highlightLines=[2,3] %}
|
||||
const code = "goes here";
|
||||
This is highlighted
|
||||
This is also highlighted
|
||||
This is not highlighted
|
||||
Neither is this
|
||||
```
|
||||
````
|
||||
|
||||
You can also specify ranges like `highlightLines=[2,3,"8-10"]`.
|
||||
|
||||
#### Terminal command
|
||||
|
||||
To display a terminal command, use:
|
||||
|
||||
````
|
||||
```shell
|
||||
npx nx build
|
||||
```
|
||||
````
|
||||
|
||||
#### Terminal Output
|
||||
|
||||
You can display your terminal output with a dedicated component the same way you would show code.
|
||||
|
||||
````
|
||||
``` {% command="node index.js" %}
|
||||
My terminal output here!
|
||||
```
|
||||
````
|
||||
|
||||
You can optionally also pass a `path` like
|
||||
|
||||
````
|
||||
``` {% command="node index.js" path="~/myorg" %}
|
||||
My terminal output here!
|
||||
```
|
||||
````
|
||||
|
||||
#### Terminal Video Output
|
||||
|
||||
You can have a more dynamic visualization of a terminal output by using the following component:
|
||||
|
||||
```
|
||||
{% terminal-video src="/documentation/shared/images/caching/cache-terminal-animation.mp4" /%}
|
||||
```
|
||||
|
||||
#### Custom iframes
|
||||
|
||||
We can display a special iframe and setting its width inside the document.
|
||||
|
||||
```markdown
|
||||
{% iframe
|
||||
src="https://staging.nx.app/orgs/62d013d4d26f260059f7765e/workspaces/62d013ea0852fe0a2df74438?hideHeader=true"
|
||||
title="Nx Cloud dashboard"
|
||||
width="100%" /%}
|
||||
```
|
||||
|
||||
If the type of the card is set to `type="video"` the `url` is a valid YouTube url, then the card will show a thumbnail of the video.
|
||||
|
||||
#### GitHub repositories
|
||||
|
||||
We can display a special button inviting the reader to go to a GitHub repository.
|
||||
|
||||
```markdown
|
||||
{% github-repository url="https://github.com/nrwl/nx-examples" /%}
|
||||
```
|
||||
|
||||
#### Stackblitz Buttons
|
||||
|
||||
You can add an "open in stackblitz" button as follows:
|
||||
|
||||
```markdown
|
||||
{% stackblitz-button url="github.com/nrwl/nx-recipes/tree/main/angular-standalone?file=README.md" /%}
|
||||
```
|
||||
|
||||
#### Install Nx Console
|
||||
|
||||
We can display a special button inviting the reader to go to a VSCode marketplace to install the official Nx plugin.
|
||||
|
||||
```markdown
|
||||
{% install-nx-console /%}
|
||||
```
|
||||
|
||||
#### Side by side
|
||||
|
||||
You can show content in a grid of 2 columns, via the `side-by-side` shortcode.
|
||||
|
||||
```markdown
|
||||
{% side-by-side %}
|
||||
You first content is here.
|
||||
|
||||
You second content is over here. _Note the space in between._
|
||||
{% /side-by-side %}
|
||||
```
|
||||
|
||||
#### Tabs
|
||||
|
||||
You can display multiple related information via a tabbing system.
|
||||
|
||||
```markdown
|
||||
{% tabs %}
|
||||
{% tab label="npm" %}
|
||||
NPM related information.
|
||||
{% /tab %}
|
||||
{% tab label="yarn" %}
|
||||
Yarn related information.
|
||||
{% /tab %}
|
||||
{% /tabs %}
|
||||
```
|
||||
|
||||
##### Youtube
|
||||
|
||||
Embed a YouTube video directly with the following shortcode, control the title and the associated width. `src` can be the Youtube URL from the browser, the "share" button (short YT url) or the embed URL.
|
||||
|
||||
```markdown
|
||||
{% youtube
|
||||
src="https://www.youtube.com/embed/rNImFxo9gYs"
|
||||
title="Nx Console Run UI Form"
|
||||
width="100%" /%}
|
||||
```
|
||||
|
||||
#### Youtube Section Link
|
||||
|
||||
Have a more decent button-like widget that you can place below sections of a tutorial with a link to a specific point in a Youtube video.
|
||||
|
||||
```markdown
|
||||
{% video-link link="https://youtu.be/OQ-Zc5tcxJE?t=64" /%}
|
||||
```
|
||||
|
||||
#### Graph
|
||||
|
||||
Embed an Nx Graph visualization that can be panned by the user.
|
||||
|
||||
````markdown
|
||||
{% graph height="450px" %}
|
||||
|
||||
```json
|
||||
{
|
||||
"projects": [
|
||||
{
|
||||
"type": "app",
|
||||
"name": "app-changed",
|
||||
"data": {
|
||||
"tags": ["scope:cart"]
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "lib",
|
||||
"name": "lib",
|
||||
"data": {
|
||||
"tags": ["scope:cart"]
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "lib",
|
||||
"name": "lib2",
|
||||
"data": {
|
||||
"tags": ["scope:cart"]
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "lib",
|
||||
"name": "lib3",
|
||||
"data": {
|
||||
"tags": ["scope:cart"]
|
||||
}
|
||||
}
|
||||
],
|
||||
"groupByFolder": false,
|
||||
"workspaceLayout": {
|
||||
"appsDir": "apps",
|
||||
"libsDir": "libs"
|
||||
},
|
||||
"dependencies": {
|
||||
"app-changed": [
|
||||
{
|
||||
"target": "lib",
|
||||
"source": "app-changed",
|
||||
"type": "direct"
|
||||
}
|
||||
],
|
||||
"lib": [
|
||||
{
|
||||
"target": "lib2",
|
||||
"source": "lib",
|
||||
"type": "implicit"
|
||||
},
|
||||
{
|
||||
"target": "lib3",
|
||||
"source": "lib",
|
||||
"type": "direct"
|
||||
}
|
||||
],
|
||||
"lib2": [],
|
||||
"lib3": []
|
||||
},
|
||||
"affectedProjectIds": []
|
||||
}
|
||||
```
|
||||
|
||||
{% /graph %}
|
||||
````
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user