Compare commits
1 Commits
patch-error
..
check
| Author | SHA1 | Date | |
|---|---|---|---|
| 53851d85e0 |
@@ -1,5 +1,5 @@
|
||||
[build]
|
||||
target-dir = 'dist/target'
|
||||
target-dir = 'build/target'
|
||||
|
||||
[target.x86_64-unknown-linux-musl]
|
||||
rustflags = [
|
||||
|
||||
@@ -1,47 +0,0 @@
|
||||
# Commit Command
|
||||
|
||||
## Description
|
||||
|
||||
Create a git commit following Nx repository standards and validation requirements.
|
||||
|
||||
## Usage
|
||||
|
||||
```bash
|
||||
/commit [message]
|
||||
```
|
||||
|
||||
## What this command does:
|
||||
|
||||
1. **Pre-commit validation**: Runs the full validation suite (`pnpm nx prepush`) to ensure code quality
|
||||
2. **Formatting**: Automatically formats changed files with Prettier
|
||||
3. **Testing**: Runs tests on affected projects to validate changes
|
||||
4. **Commit creation**: Creates a well-formed commit with proper message formatting (without co-author attribution)
|
||||
5. **Status reporting**: Provides clear feedback on the commit process
|
||||
|
||||
## Workflow:
|
||||
|
||||
1. Format any modified files with Prettier
|
||||
2. Run the prepush validation suite
|
||||
3. If validation passes, stage relevant changes
|
||||
4. Create commit with descriptive message
|
||||
5. Provide summary of what was committed
|
||||
|
||||
## Commit Message Format:
|
||||
|
||||
- Use conventional commit format when appropriate
|
||||
- Include scope (e.g., `feat(core):`, `fix(angular):`, `docs(nx):`)
|
||||
- Keep first line under 72 characters
|
||||
- Include detailed description if needed
|
||||
|
||||
## Examples:
|
||||
|
||||
- `/commit "feat(core): add new project graph visualization"`
|
||||
- `/commit "fix(react): resolve build issues with webpack config"`
|
||||
- `/commit "docs(nx): update getting started guide"`
|
||||
|
||||
## Validation Requirements:
|
||||
|
||||
- All tests must pass
|
||||
- Code must be properly formatted
|
||||
- No linting errors
|
||||
- E2E tests for affected areas should pass
|
||||
@@ -1,155 +0,0 @@
|
||||
# GitHub Issue Planning and Resolution
|
||||
|
||||
This command provides guidance for both automated and manual GitHub issue workflows.
|
||||
|
||||
## Automated Workflow (GitHub Actions)
|
||||
|
||||
The automated workflow consists of two phases:
|
||||
|
||||
### Phase 1: Planning (`@claude plan` or `claude:plan` label)
|
||||
|
||||
- Claude analyzes the issue and creates a detailed implementation plan
|
||||
- Plan is posted as a comment on the issue
|
||||
- Issue is labeled with `claude:planned`
|
||||
|
||||
### Phase 2: Implementation (`@claude implement` or `claude:implement` label)
|
||||
|
||||
- Claude implements the solution based on the plan
|
||||
- Runs validation tests and creates a feature branch
|
||||
- Suggests opening a PR with proper formatting
|
||||
|
||||
## Planning Phase Template
|
||||
|
||||
When creating a plan (either automated or manual), include these sections:
|
||||
|
||||
### Problem Analysis
|
||||
|
||||
- Root cause identification
|
||||
- Impact assessment
|
||||
- Related components or systems affected
|
||||
|
||||
### Proposed Solution
|
||||
|
||||
- High-level approach
|
||||
- Alternative solutions considered
|
||||
- Trade-offs and rationale
|
||||
|
||||
### Implementation Details
|
||||
|
||||
- Files that need to be modified
|
||||
- Key changes required
|
||||
- Dependencies or prerequisites
|
||||
|
||||
### Testing Strategy
|
||||
|
||||
- Unit tests to add/modify
|
||||
- Integration tests needed
|
||||
- E2E test considerations
|
||||
|
||||
### Validation Steps
|
||||
|
||||
```bash
|
||||
# Test specific affected projects
|
||||
nx run-many -t test,build,lint -p PROJECT_NAME
|
||||
|
||||
# Test all affected projects
|
||||
nx affected -t build,test,lint
|
||||
|
||||
# Run affected e2e tests
|
||||
nx affected -t e2e-local
|
||||
|
||||
# Format code
|
||||
npx nx prettier -- FILES
|
||||
|
||||
# Final validation
|
||||
pnpm nx prepush
|
||||
```
|
||||
|
||||
### Risks and Considerations
|
||||
|
||||
- Breaking changes
|
||||
- Performance implications
|
||||
- Migration requirements
|
||||
|
||||
## Manual Workflow
|
||||
|
||||
When working on a GitHub issue manually, follow this systematic approach:
|
||||
|
||||
## 1. Get Issue Details
|
||||
|
||||
```bash
|
||||
# Get issue details using GitHub CLI (replace ISSUE_NUMBER with actual number)
|
||||
gh issue view ISSUE_NUMBER
|
||||
```
|
||||
|
||||
When cloning reproduction repos, please clone within `./tmp/claude/repro-ISSUE_NUMBER`
|
||||
|
||||
## 2. Analyze the Plan
|
||||
|
||||
- Look for a plan or implementation details in the issue description
|
||||
- Check comments for additional context or clarification
|
||||
- Identify affected projects and components
|
||||
|
||||
## 3. Implement the Solution
|
||||
|
||||
- Follow the plan outlined in the issue
|
||||
- Make focused changes that address the specific problem
|
||||
- Ensure code follows existing patterns and conventions
|
||||
|
||||
## 4. Run Full Validation
|
||||
|
||||
```bash
|
||||
# Test specific affected projects first
|
||||
nx run-many -t test,build,lint -p PROJECT_NAME
|
||||
|
||||
# Test all affected projects
|
||||
nx affected -t build,test,lint
|
||||
|
||||
# Run affected e2e tests
|
||||
nx affected -t e2e-local
|
||||
|
||||
# Final pre-push validation
|
||||
pnpm nx prepush
|
||||
```
|
||||
|
||||
## 5. Submit Pull Request
|
||||
|
||||
- Create a descriptive PR title that references the issue
|
||||
- Include "Fixes #ISSUE_NUMBER" in the PR description
|
||||
- Provide a clear summary of changes made
|
||||
- Request appropriate reviewers
|
||||
|
||||
## Pull Request Template
|
||||
|
||||
When creating a pull request, follow the template found in `.github/PULL_REQUEST_TEMPLATE.md`. The template includes:
|
||||
|
||||
### Required Sections
|
||||
|
||||
1. **Current Behavior**: Describe the behavior we have today
|
||||
2. **Expected Behavior**: Describe the behavior we should expect with the changes in this PR
|
||||
3. **Related Issue(s)**: Link the issue being fixed so it gets closed when the PR is merged
|
||||
|
||||
### Template Format
|
||||
|
||||
```markdown
|
||||
## Current Behavior
|
||||
|
||||
<!-- This is the behavior we have today -->
|
||||
|
||||
## Expected Behavior
|
||||
|
||||
<!-- This is the behavior we should expect with the changes in this PR -->
|
||||
|
||||
## Related Issue(s)
|
||||
|
||||
<!-- Please link the issue being fixed so it gets closed when this is merged. -->
|
||||
|
||||
Fixes #ISSUE_NUMBER
|
||||
```
|
||||
|
||||
### Guidelines
|
||||
|
||||
- Ensure your commit message follows the conventional commit format (use `pnpm commit`)
|
||||
- Read the submission guidelines in CONTRIBUTING.md before posting
|
||||
- For complex changes, you can request a dedicated Nx release by mentioning the Nx team
|
||||
- Always link the related issue using "Fixes #ISSUE_NUMBER" to automatically close it when merged
|
||||
@@ -1,30 +0,0 @@
|
||||
# Claude Issue Workflow Usage Guide
|
||||
|
||||
## Quick Start
|
||||
|
||||
## Expected Outputs
|
||||
|
||||
### Planning Phase
|
||||
|
||||
- Detailed analysis comment posted to issue
|
||||
- Implementation plan with steps and file changes
|
||||
- Testing strategy and validation steps
|
||||
- Risk assessment
|
||||
|
||||
### Implementation Phase
|
||||
|
||||
- Code changes made according to plan
|
||||
- Tests run and validated
|
||||
- Feature branch created: `fix/issue-{number}`
|
||||
- PR suggestion with proper title format
|
||||
|
||||
## Manual Override
|
||||
|
||||
If you need to work on an issue manually, use the `/gh-issue-plan` command for structured guidance following the same workflow patterns.
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
- Ensure you're on the authorized users list
|
||||
- Check that the issue has sufficient detail for analysis
|
||||
- For implementation, ensure a plan comment exists from the planning phase
|
||||
- If workflows fail, check the Actions tab for detailed logs
|
||||
@@ -1,34 +0,0 @@
|
||||
{
|
||||
"permissions": {
|
||||
"allow": [
|
||||
"Bash(find:*)",
|
||||
"Bash(ls:*)",
|
||||
"Bash(mkdir:*)",
|
||||
"WebFetch(domain:github.com)",
|
||||
"WebFetch(domain:www.typescriptlang.org)",
|
||||
"Bash(git log:*)",
|
||||
"Bash(gh issue list:*)",
|
||||
"Bash(gh issue view:*)",
|
||||
"Bash(npx prettier:*)",
|
||||
"Bash(nx prepush:*)",
|
||||
"Bash(pnpm commit:*)",
|
||||
"Bash(rg:*)",
|
||||
"mcp__nx__nx_docs",
|
||||
"mcp__nx__nx_workspace",
|
||||
"mcp__nx__nx_project_details",
|
||||
"Bash(nx show projects:*)",
|
||||
"Bash(nx run-many:*)",
|
||||
"Bash(nx run:*)",
|
||||
"Bash(nx affected:*)",
|
||||
"Bash(nx lint:*)",
|
||||
"Bash(nx test:*)",
|
||||
"Bash(nx build:*)",
|
||||
"Bash(nx documentation:*)"
|
||||
],
|
||||
"deny": []
|
||||
},
|
||||
"enableAllProjectMcpServers": true,
|
||||
"env": {
|
||||
"BASH_MAX_TIMEOUT_MS": "1800000"
|
||||
}
|
||||
}
|
||||
@@ -1,87 +0,0 @@
|
||||
---
|
||||
name: run-nx-generator
|
||||
description: Run Nx generators with prioritization for workspace-plugin generators. Use this when generating code, scaffolding new features, or automating repetitive tasks in the monorepo.
|
||||
allowed-tools: Bash, Read, Glob, Grep, mcp__nx-mcp__nx_generators, mcp__nx-mcp__nx_generator_schema
|
||||
---
|
||||
|
||||
# Run Nx Generator
|
||||
|
||||
This skill helps you execute Nx generators efficiently, with special focus on workspace-plugin generators from your internal tooling.
|
||||
|
||||
## Generator Priority List
|
||||
|
||||
Use the `mcp__nx-mcp__nx_generator_schema` tool to get more information about how to use the generator
|
||||
|
||||
Choose which generators to run in this priority order:
|
||||
|
||||
### 🔥 Workspace-Plugin Generators (High Priority)
|
||||
|
||||
These are your custom internal tools in `tools/workspace-plugin/`
|
||||
|
||||
### 📦 Core Nx Generators (Standard)
|
||||
|
||||
Only use these if workspace-plugin generators don't fit:
|
||||
|
||||
- `nx generate @nx/devkit:...` - DevKit utilities
|
||||
- `nx generate @nx/node:...` - Node.js libraries
|
||||
- `nx generate @nx/react:...` - React components and apps
|
||||
- Framework-specific generators
|
||||
|
||||
## How to Run Generators
|
||||
|
||||
1. **List available generators**:
|
||||
|
||||
2. **Get generator schema** (to see available options):
|
||||
Use the `mcp__nx-mcp__nx_generator_schema` tool to get more information about how to use the generator
|
||||
|
||||
3. **Run the generator**:
|
||||
|
||||
```bash
|
||||
nx generate [generator-path] [options]
|
||||
```
|
||||
|
||||
4. **Verify the changes**:
|
||||
- Review generated files
|
||||
- Run tests: `nx affected -t test`
|
||||
- Format code: `npx prettier --write [files]`
|
||||
|
||||
## Best Practices
|
||||
|
||||
- ✅ Always check workspace-plugin first - it has your custom solutions
|
||||
- ✅ Use `--dry-run` flag to preview changes before applying
|
||||
- ✅ Format generated code immediately with Prettier
|
||||
- ✅ Test affected projects after generation
|
||||
- ✅ Commit generator changes separately from manual edits
|
||||
|
||||
## Examples
|
||||
|
||||
### Bumping Maven Version
|
||||
|
||||
When updating the Maven plugin version, use the workspace-plugin generator:
|
||||
|
||||
```bash
|
||||
nx generate @nx/workspace-plugin:bump-maven-version \
|
||||
--newVersion 0.0.10 \
|
||||
--nxVersion 22.1.0-beta.7
|
||||
```
|
||||
|
||||
This automates all the version bumping instead of manual file edits.
|
||||
|
||||
### Creating a New Plugin
|
||||
|
||||
For creating a new create-nodes plugin:
|
||||
|
||||
```bash
|
||||
nx generate @nx/workspace-plugin:create-nodes-plugin \
|
||||
--name my-custom-plugin
|
||||
```
|
||||
|
||||
## When to Use This Skill
|
||||
|
||||
Use this skill when you need to:
|
||||
|
||||
- Generate new code or projects
|
||||
- Scaffold new features or libraries
|
||||
- Automate repetitive setup tasks
|
||||
- Update internal tools and configurations
|
||||
- Create migrations or version updates
|
||||
@@ -8,11 +8,11 @@
|
||||
// Try a more recent distribution, if your are having build issues related to GLIBC version
|
||||
// Here we use 'bookworm', which is based on `Debian-12`, which comes with `GLIBC v2.36`
|
||||
// (Nx tools currenlty requires `GLIBC v2.33` or higher)
|
||||
// Note: Using base debian image instead of typescript-node since mise will manage all tools
|
||||
"image": "mcr.microsoft.com/devcontainers/base:bookworm",
|
||||
"image": "mcr.microsoft.com/devcontainers/typescript-node:20-bookworm",
|
||||
|
||||
// All tools (Node, Java, Rust, Dotnet) are managed by mise via mise.toml
|
||||
"features": {},
|
||||
"features": {
|
||||
"ghcr.io/devcontainers/features/rust:1": {}
|
||||
},
|
||||
|
||||
// Use 'forwardPorts' to make a list of ports inside the container available locally.
|
||||
// 4211 = nx graph port
|
||||
|
||||
@@ -1,30 +1,12 @@
|
||||
#!/bin/bash
|
||||
#!/bin/sh
|
||||
|
||||
# Update the underlying (Debian) OS, to make sure we have the latest security patches and libraries like 'GLIBC'
|
||||
# Update the underlying (Debian) OS, to make sure we have the latest security patches and libraries like 'GLIBC'
|
||||
echo "⚙️ Updating the underlying OS..."
|
||||
sudo apt-get update && sudo apt-get -y upgrade
|
||||
|
||||
# Install mise for managing development tools (Node, Java, Rust, Dotnet)
|
||||
echo "⚙️ Installing mise..."
|
||||
curl https://mise.run | sh
|
||||
|
||||
# Add mise to PATH
|
||||
export PATH="$HOME/.local/bin:$PATH"
|
||||
|
||||
# Trust the mise.toml configuration file
|
||||
echo "⚙️ Trusting mise.toml configuration..."
|
||||
mise trust
|
||||
|
||||
# Install all tools from mise.toml (node, java, rust, dotnet)
|
||||
echo "⚙️ Installing tools via mise (node, java, rust, dotnet)..."
|
||||
mise install
|
||||
|
||||
# Activate mise to make tools available in current shell
|
||||
eval "$(mise activate bash)"
|
||||
|
||||
# Add mise activation to bashrc for future shell sessions
|
||||
echo "⚙️ Configuring mise activation in shell..."
|
||||
echo 'eval "$(~/.local/bin/mise activate bash)"' >> ~/.bashrc
|
||||
# Uninstall globally installed PNPM (required version will be reinstalled through corepack)
|
||||
echo "❌ Uninstalling globally installed PNPM..."
|
||||
npm uninstall -g pnpm
|
||||
|
||||
# Prevent corepack from prompting user before downloading PNPM
|
||||
export COREPACK_ENABLE_DOWNLOAD_PROMPT=0
|
||||
|
||||
@@ -9,7 +9,7 @@ end_of_line = lf
|
||||
insert_final_newline = true
|
||||
|
||||
# 4 space indentation
|
||||
[*.{kts,kt,js,ts,jsx,tsx}]
|
||||
[*.{js,ts,jsx,tsx}]
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
"env": {
|
||||
"node": true
|
||||
},
|
||||
"ignorePatterns": ["**/*.ts", "**/test-output"],
|
||||
"ignorePatterns": ["**/*.ts"],
|
||||
"plugins": ["@typescript-eslint", "@nx"],
|
||||
"extends": ["plugin:storybook/recommended"],
|
||||
"rules": {
|
||||
|
||||
@@ -1,10 +0,0 @@
|
||||
{
|
||||
"mcpServers": {
|
||||
"nx-mcp": {
|
||||
"type": "stdio",
|
||||
"command": "npx",
|
||||
"args": ["nx", "mcp"]
|
||||
}
|
||||
},
|
||||
"contextFileName": "AGENTS.md"
|
||||
}
|
||||
@@ -3,8 +3,7 @@
|
||||
#
|
||||
# Linux start script should use lf
|
||||
/gradlew text eol=lf
|
||||
|
||||
# These are Windows script files and should use crlf
|
||||
*.bat text eol=crlf
|
||||
# Exclude files from Graphite reviews
|
||||
docs/generated/* linguist-generated=true
|
||||
*.pdf,*.gif,*.mp4,*.webp,*.avif,*.png,*.jpeg,*.jpg,*.tiff filter=lfs diff=lfs merge=lfs -text
|
||||
|
||||
|
||||
@@ -28,12 +28,12 @@ Note: We reserve the right to remove unmaintained plugins from the registry. If
|
||||
|
||||
## Steps to Submit Your Plugin
|
||||
- Use the following commit message template: `chore(core): nx plugin submission [PLUGIN_NAME]`
|
||||
- Update the `astro-docs/src/content/approved-community-plugins.json` file with a new entry for your plugin that includes `name`, `url`, `description`:
|
||||
- Update the `community/approved-plugins.json` file with a new entry for your plugin that includes `name`, `url`, `description`:
|
||||
|
||||
Example:
|
||||
|
||||
```json
|
||||
// astro-docs/src/content/approved-community-plugins.json
|
||||
// community/approved-plugins.json
|
||||
|
||||
[{
|
||||
"name": "@community/plugin",
|
||||
@@ -42,7 +42,7 @@ 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/docs/plugin-registry)
|
||||
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
|
||||
|
||||
@@ -4,15 +4,12 @@ on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
- '[0-9]+.[0-9]+.x'
|
||||
pull_request:
|
||||
branches:
|
||||
- "**"
|
||||
|
||||
env:
|
||||
NX_CLOUD_ACCESS_TOKEN: ${{ secrets.NX_CLOUD_ACCESS_TOKEN }}
|
||||
NX_CLOUD_ENABLE_METRICS_COLLECTION: 'true'
|
||||
PNPM_HOME: ~/.pnpm
|
||||
|
||||
jobs:
|
||||
main-linux:
|
||||
@@ -32,7 +29,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
filter: tree:0
|
||||
@@ -42,12 +39,12 @@ jobs:
|
||||
if: ${{ github.event_name == 'pull_request' }}
|
||||
|
||||
- name: Set SHAs
|
||||
uses: nrwl/nx-set-shas@1859e66a83ac9be0dceecbd9a023702e27ac47f4 # v4.3.3
|
||||
uses: nrwl/nx-set-shas@v4
|
||||
with:
|
||||
main-branch-name: 'master'
|
||||
|
||||
- name: Start CI Run
|
||||
run: npx nx-cloud@next start-ci-run --auto-apply-fixes="*format:check*,*sync:check*,*conformance:check*,*format-native*,*lint-native*,*lint*,*astro-docs:validate-links*" --distribute-on="./.nx/workflows/dynamic-changesets.yaml" --stop-agents-after="e2e"
|
||||
run: npx nx-cloud@next start-ci-run --distribute-on="./.nx/workflows/dynamic-changesets.yaml" --stop-agents-after="e2e"
|
||||
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
@@ -55,27 +52,31 @@ jobs:
|
||||
sudo apt-get install -y ca-certificates lsof libvips-dev libglib2.0-dev libgirepository1.0-dev
|
||||
|
||||
- name: Install Chrome
|
||||
uses: browser-actions/setup-chrome@2dbff04819ebbfd5c974947148805a825b8a07fd # v2.1.0
|
||||
uses: browser-actions/setup-chrome@v1
|
||||
|
||||
- name: Setup dev tools with mise
|
||||
uses: jdx/mise-action@146a28175021df8ca24f8ee1828cc2a60f980bd5 # v3
|
||||
|
||||
- name: Enable corepack and install pnpm
|
||||
run: |
|
||||
corepack enable
|
||||
corepack prepare --activate
|
||||
|
||||
- name: Setup Gradle
|
||||
uses: gradle/actions/setup-gradle@48b5f213c81028ace310571dc5ec0fbbca0b2947 # v4.4.3
|
||||
- uses: pnpm/action-setup@v4
|
||||
name: Install pnpm
|
||||
with:
|
||||
version: 9.8.0
|
||||
run_install: false
|
||||
|
||||
- name: Install project dependencies
|
||||
run: |
|
||||
pnpm install --frozen-lockfile
|
||||
pnpm playwright install --with-deps
|
||||
|
||||
- name: Nx Report
|
||||
run:
|
||||
pnpm nx report
|
||||
- name: Install Rust
|
||||
uses: dtolnay/rust-toolchain@stable
|
||||
|
||||
- name: Setup Java
|
||||
uses: actions/setup-java@v4
|
||||
with:
|
||||
distribution: temurin
|
||||
java-version: 17
|
||||
|
||||
- name: Check Documentation
|
||||
run: pnpm nx documentation
|
||||
timeout-minutes: 20
|
||||
|
||||
- name: Run Checks/Lint/Test/Build
|
||||
run: |
|
||||
@@ -90,19 +91,16 @@ jobs:
|
||||
pnpm nx-cloud record -- nx-cloud conformance:check
|
||||
pids+=($!)
|
||||
|
||||
pnpm nx run-many -t check-imports check-lock-files check-codeowners --parallel=1 --no-dte &
|
||||
pnpm nx run-many -t check-imports check-commit check-lock-files check-codeowners --parallel=1 --no-dte &
|
||||
pids+=($!)
|
||||
|
||||
pnpm nx affected --targets=lint,test,test-kt,build,e2e,e2e-ci,format-native,lint-native &
|
||||
pnpm nx affected --targets=lint,test,build,e2e,e2e-ci,format-native &
|
||||
pids+=($!)
|
||||
|
||||
for pid in "${pids[@]}"; do
|
||||
wait "$pid"
|
||||
done
|
||||
timeout-minutes: 100
|
||||
- name: Fix CI
|
||||
run: pnpm nx-cloud fix-ci
|
||||
if: failure()
|
||||
|
||||
main-macos:
|
||||
runs-on: macos-latest
|
||||
@@ -126,7 +124,7 @@ jobs:
|
||||
if: always()
|
||||
|
||||
- name: Checkout
|
||||
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
filter: tree:0
|
||||
@@ -135,34 +133,8 @@ jobs:
|
||||
run: git fetch origin master:master
|
||||
if: ${{ github.event_name == 'pull_request' }}
|
||||
|
||||
- name: Setup dev tools with mise
|
||||
uses: jdx/mise-action@146a28175021df8ca24f8ee1828cc2a60f980bd5 # v3
|
||||
|
||||
- name: Enable corepack and install pnpm
|
||||
run: |
|
||||
corepack enable
|
||||
corepack prepare --activate
|
||||
|
||||
- name: Set SHAs
|
||||
uses: nrwl/nx-set-shas@1859e66a83ac9be0dceecbd9a023702e27ac47f4 # v4.3.3
|
||||
with:
|
||||
main-branch-name: 'master'
|
||||
|
||||
- name: Check for React Native changes
|
||||
id: check-changes
|
||||
run: |
|
||||
HAS_CHANGED=$(node ./scripts/check-react-native-changes.js $NX_BASE $NX_HEAD);
|
||||
if $HAS_CHANGED; then
|
||||
echo "has_changes=true" >> $GITHUB_OUTPUT
|
||||
echo "React Native projects are affected, will run macOS tests"
|
||||
else
|
||||
echo "has_changes=false" >> $GITHUB_OUTPUT
|
||||
echo "No React Native projects affected, skipping macOS tests"
|
||||
fi
|
||||
|
||||
- name: Restore Homebrew packages
|
||||
if: steps.check-changes.outputs.has_changes == 'true'
|
||||
uses: actions/cache@0400d5f644dc74513175e3cd8d07132dd4860809 # v4.2.4
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: |
|
||||
/opt/homebrew
|
||||
@@ -170,120 +142,44 @@ jobs:
|
||||
key: nrwl-nx-homebrew-packages
|
||||
|
||||
- name: Configure Detox Environment, Install applesimutils
|
||||
if: steps.check-changes.outputs.has_changes == 'true'
|
||||
run: |
|
||||
# Ensure Xcode command line tools are installed and configured
|
||||
xcode-select --print-path || sudo xcode-select --reset
|
||||
sudo xcode-select -s /Applications/Xcode.app
|
||||
|
||||
# Install or update applesimutils with error handling
|
||||
if ! brew list applesimutils &>/dev/null; then
|
||||
echo "Installing applesimutils..."
|
||||
HOMEBREW_NO_AUTO_UPDATE=1 brew tap wix/brew >/dev/null
|
||||
HOMEBREW_NO_AUTO_UPDATE=1 brew install applesimutils >/dev/null || {
|
||||
echo "Failed to install applesimutils, retrying with update..."
|
||||
brew update
|
||||
HOMEBREW_NO_AUTO_UPDATE=1 brew install applesimutils
|
||||
}
|
||||
else
|
||||
echo "Updating applesimutils..."
|
||||
HOMEBREW_NO_AUTO_UPDATE=1 brew upgrade applesimutils || true
|
||||
fi
|
||||
|
||||
# Verify applesimutils installation
|
||||
applesimutils --version || (echo "applesimutils installation failed" && exit 1)
|
||||
|
||||
# Configure environment for M-series Mac
|
||||
echo "DEVELOPER_DIR=/Applications/Xcode.app/Contents/Developer" >> $GITHUB_ENV
|
||||
echo "PLATFORM_NAME=iOS Simulator" >> $GITHUB_ENV
|
||||
|
||||
# Set additional environment variables for better debugging
|
||||
echo "DETOX_DISABLE_TELEMETRY=1" >> $GITHUB_ENV
|
||||
echo "DETOX_LOG_LEVEL=trace" >> $GITHUB_ENV
|
||||
|
||||
# Verify Xcode installation
|
||||
xcodebuild -version
|
||||
|
||||
# List available simulators
|
||||
xcrun simctl list devices available
|
||||
timeout-minutes: 10
|
||||
continue-on-error: false
|
||||
|
||||
- name: Reset iOS Simulators
|
||||
if: steps.check-changes.outputs.has_changes == 'true'
|
||||
id: reset-simulators
|
||||
run: |
|
||||
echo "Resetting iOS Simulators..."
|
||||
|
||||
# Kill simulator processes
|
||||
sudo killall -9 com.apple.CoreSimulator.CoreSimulatorService 2>/dev/null || true
|
||||
killall "Simulator" 2>/dev/null || true
|
||||
killall "iOS Simulator" 2>/dev/null || true
|
||||
|
||||
# Wait for processes to terminate
|
||||
sleep 3
|
||||
|
||||
# Shutdown and erase all simulators (ignore failures)
|
||||
xcrun simctl shutdown all 2>/dev/null || true
|
||||
sleep 5
|
||||
xcrun simctl erase all 2>/dev/null || true
|
||||
|
||||
# If erase failed, try the nuclear option
|
||||
if xcrun simctl list devices | grep -q "Booted" 2>/dev/null; then
|
||||
echo "Standard reset failed, using nuclear option..."
|
||||
rm -rf ~/Library/Developer/CoreSimulator/Devices/* 2>/dev/null || true
|
||||
launchctl remove com.apple.CoreSimulator.CoreSimulatorService 2>/dev/null || true
|
||||
sleep 3
|
||||
fi
|
||||
|
||||
# Clean up additional directories
|
||||
rm -rf ~/Library/Developer/CoreSimulator/Caches/* 2>/dev/null || true
|
||||
rm -rf ~/Library/Logs/CoreSimulator/* 2>/dev/null || true
|
||||
rm -rf ~/Library/Developer/Xcode/DerivedData/* 2>/dev/null || true
|
||||
|
||||
echo "Simulator reset completed"
|
||||
timeout-minutes: 5
|
||||
continue-on-error: true
|
||||
|
||||
- name: Verify Simulator Reset
|
||||
if: steps.check-changes.outputs.has_changes == 'true' && steps.reset-simulators.outcome == 'success'
|
||||
run: |
|
||||
# Verify CoreSimulator service restarted
|
||||
pgrep -fl "CoreSimulator" || (echo "CoreSimulator service not running" && exit 1)
|
||||
|
||||
# Check simulator list is clean
|
||||
xcrun simctl list devices
|
||||
|
||||
# Verify simulator runtime paths exist and are writable
|
||||
test -d ~/Library/Developer/CoreSimulator/Devices || (echo "Simulator devices directory missing" && exit 1)
|
||||
touch ~/Library/Developer/CoreSimulator/Devices/test || (echo "Simulator devices directory not writable" && exit 1)
|
||||
rm ~/Library/Developer/CoreSimulator/Devices/test
|
||||
timeout-minutes: 5
|
||||
|
||||
- name: Diagnose Simulator Reset Failure
|
||||
if: steps.check-changes.outputs.has_changes == 'true' && steps.reset-simulators.outcome == 'failure'
|
||||
run: |
|
||||
echo "Simulator reset failed. Collecting diagnostic information..."
|
||||
xcrun simctl list
|
||||
echo "Checking simulator logs..."
|
||||
ls -la ~/Library/Logs/CoreSimulator/ || echo "No simulator logs found"
|
||||
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
|
||||
timeout-minutes: 20
|
||||
|
||||
- name: Save Homebrew Cache
|
||||
if: steps.check-changes.outputs.has_changes == 'true'
|
||||
uses: actions/cache@0400d5f644dc74513175e3cd8d07132dd4860809 # v4.2.4
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: |
|
||||
/opt/homebrew
|
||||
~/Library/Caches/Homebrew
|
||||
key: nrwl-nx-homebrew-packages
|
||||
|
||||
- uses: pnpm/action-setup@v4
|
||||
name: Install pnpm
|
||||
with:
|
||||
version: 9.8.0
|
||||
run_install: false
|
||||
|
||||
- name: Install project dependencies
|
||||
if: steps.check-changes.outputs.has_changes == 'true'
|
||||
run: |
|
||||
pnpm install --frozen-lockfile
|
||||
pnpm playwright install --with-deps
|
||||
|
||||
- name: Install Rust
|
||||
uses: dtolnay/rust-toolchain@stable
|
||||
|
||||
- name: Set SHAs
|
||||
uses: nrwl/nx-set-shas@v4
|
||||
with:
|
||||
main-branch-name: 'master'
|
||||
|
||||
- name: Run E2E Tests for macOS
|
||||
if: steps.check-changes.outputs.has_changes == 'true'
|
||||
run: |
|
||||
pnpm nx affected -t e2e-macos-local --parallel=1 --base=$NX_BASE --head=$NX_HEAD
|
||||
HAS_CHANGED=$(node ./scripts/check-react-native-changes.js $NX_BASE $NX_HEAD);
|
||||
if $HAS_CHANGED; then
|
||||
pnpm nx affected -t e2e-macos-local --parallel=1 --base=$NX_BASE --head=$NX_HEAD
|
||||
else
|
||||
echo "Skip E2E tests for macOS as there are no changes in React Native projects."
|
||||
fi
|
||||
|
||||
@@ -1,114 +0,0 @@
|
||||
# For most projects, this workflow file will not need changing; you simply need
|
||||
# to commit it to your repository.
|
||||
#
|
||||
# You may wish to alter this file to override the set of languages analyzed,
|
||||
# or to provide custom queries or build logic.
|
||||
#
|
||||
# ******** NOTE ********
|
||||
# We have attempted to detect the languages in your repository. Please check
|
||||
# the `language` matrix defined below to confirm you have the correct set of
|
||||
# supported CodeQL languages.
|
||||
#
|
||||
name: "CodeQL"
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ "master" ]
|
||||
schedule:
|
||||
- cron: '20 14 * * 6'
|
||||
|
||||
jobs:
|
||||
analyze:
|
||||
name: Analyze (${{ matrix.language }})
|
||||
# Runner size impacts CodeQL analysis time. To learn more, please see:
|
||||
# - https://gh.io/recommended-hardware-resources-for-running-codeql
|
||||
# - https://gh.io/supported-runners-and-hardware-resources
|
||||
# - https://gh.io/using-larger-runners (GitHub.com only)
|
||||
# Consider using larger runners or machines with greater resources for possible analysis time improvements.
|
||||
runs-on: ${{ (matrix.language == 'swift' && 'macos-latest') || 'ubuntu-latest' }}
|
||||
permissions:
|
||||
# required for all workflows
|
||||
security-events: write
|
||||
|
||||
# required to fetch internal or private CodeQL packs
|
||||
packages: read
|
||||
|
||||
# only required for workflows in private repositories
|
||||
actions: read
|
||||
contents: read
|
||||
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- language: actions
|
||||
build-mode: none
|
||||
|
||||
# We would like to test our Java / Kotlin... but its currently failing. We can follow up.
|
||||
# - language: java-kotlin
|
||||
# build-mode: autobuild
|
||||
- language: javascript-typescript
|
||||
build-mode: none
|
||||
- language: rust
|
||||
build-mode: none
|
||||
- language: csharp
|
||||
build-mode: autobuild
|
||||
# CodeQL supports the following values keywords for 'language': 'actions', 'c-cpp', 'csharp', 'go', 'java-kotlin', 'javascript-typescript', 'python', 'ruby', 'rust', 'swift'
|
||||
# Use `c-cpp` to analyze code written in C, C++ or both
|
||||
# Use 'java-kotlin' to analyze code written in Java, Kotlin or both
|
||||
# Use 'javascript-typescript' to analyze code written in JavaScript, TypeScript or both
|
||||
# To learn more about changing the languages that are analyzed or customizing the build mode for your analysis,
|
||||
# see https://docs.github.com/en/code-security/code-scanning/creating-an-advanced-setup-for-code-scanning/customizing-your-advanced-setup-for-code-scanning.
|
||||
# If you are analyzing a compiled language, you can modify the 'build-mode' for that language to customize how
|
||||
# your codebase is analyzed, see https://docs.github.com/en/code-security/code-scanning/creating-an-advanced-setup-for-code-scanning/codeql-code-scanning-for-compiled-languages
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
||||
|
||||
- name: Setup Language Tooling
|
||||
uses: jdx/mise-action@146a28175021df8ca24f8ee1828cc2a60f980bd5 # v3
|
||||
|
||||
- name: Enable corepack and install pnpm
|
||||
run: |
|
||||
corepack enable
|
||||
corepack prepare --activate
|
||||
|
||||
# Add any setup steps before running the `github/codeql-action/init` action.
|
||||
# This includes steps like installing compilers or runtimes (`actions/setup-node`
|
||||
# or others). This is typically only required for manual builds.
|
||||
# - name: Setup runtime (example)
|
||||
# uses: actions/setup-example@v1
|
||||
|
||||
# Initializes the CodeQL tools for scanning.
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@15403aac29bd91419968e066cded66bde56b0283 # v3
|
||||
with:
|
||||
languages: ${{ matrix.language }}
|
||||
build-mode: ${{ matrix.build-mode }}
|
||||
# If you wish to specify custom queries, you can do so here or in a config file.
|
||||
# By default, queries listed here will override any specified in a config file.
|
||||
# Prefix the list here with "+" to use these queries and those in the config file.
|
||||
|
||||
# For more details on CodeQL's query packs, refer to: https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs
|
||||
# queries: security-extended,security-and-quality
|
||||
|
||||
# If the analyze step fails for one of the languages you are analyzing with
|
||||
# "We were unable to automatically build your code", modify the matrix above
|
||||
# to set the build mode to "manual" for that language. Then modify this step
|
||||
# to build your code.
|
||||
# ℹ️ Command-line programs to run using the OS shell.
|
||||
# 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun
|
||||
- if: matrix.build-mode == 'manual'
|
||||
shell: bash
|
||||
run: |
|
||||
echo 'If you are using a "manual" build mode for one or more of the' \
|
||||
'languages you are analyzing, replace this with the commands to build' \
|
||||
'your code, for example:'
|
||||
echo ' make bootstrap'
|
||||
echo ' make release'
|
||||
exit 1
|
||||
|
||||
- name: Perform CodeQL Analysis
|
||||
uses: github/codeql-action/analyze@15403aac29bd91419968e066cded66bde56b0283 # v3
|
||||
with:
|
||||
category: "/language:${{matrix.language}}"
|
||||
@@ -1,111 +0,0 @@
|
||||
# For most projects, this workflow file will not need changing; you simply need
|
||||
# to commit it to your repository.
|
||||
#
|
||||
# You may wish to alter this file to override the set of languages analyzed,
|
||||
# or to provide custom queries or build logic.
|
||||
#
|
||||
# ******** NOTE ********
|
||||
# We have attempted to detect the languages in your repository. Please check
|
||||
# the `language` matrix defined below to confirm you have the correct set of
|
||||
# supported CodeQL languages.
|
||||
#
|
||||
name: "CodeQL"
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
branches: [ "**" ]
|
||||
|
||||
jobs:
|
||||
analyze:
|
||||
name: Analyze (${{ matrix.language }})
|
||||
# Runner size impacts CodeQL analysis time. To learn more, please see:
|
||||
# - https://gh.io/recommended-hardware-resources-for-running-codeql
|
||||
# - https://gh.io/supported-runners-and-hardware-resources
|
||||
# - https://gh.io/using-larger-runners (GitHub.com only)
|
||||
# Consider using larger runners or machines with greater resources for possible analysis time improvements.
|
||||
runs-on: ${{ (matrix.language == 'swift' && 'macos-latest') || 'ubuntu-latest' }}
|
||||
permissions:
|
||||
# required to fetch internal or private CodeQL packs
|
||||
packages: read
|
||||
|
||||
# only required for workflows in private repositories
|
||||
actions: read
|
||||
contents: read
|
||||
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- language: actions
|
||||
build-mode: none
|
||||
|
||||
# See comment in @./codeql-master.yml about Java / Kotlin
|
||||
# - language: java-kotlin
|
||||
# build-mode: autobuild
|
||||
- language: javascript-typescript
|
||||
build-mode: none
|
||||
- language: rust
|
||||
build-mode: none
|
||||
- language: csharp
|
||||
build-mode: autobuild
|
||||
# CodeQL supports the following values keywords for 'language': 'actions', 'c-cpp', 'csharp', 'go', 'java-kotlin', 'javascript-typescript', 'python', 'ruby', 'rust', 'swift'
|
||||
# Use `c-cpp` to analyze code written in C, C++ or both
|
||||
# Use 'java-kotlin' to analyze code written in Java, Kotlin or both
|
||||
# Use 'javascript-typescript' to analyze code written in JavaScript, TypeScript or both
|
||||
# To learn more about changing the languages that are analyzed or customizing the build mode for your analysis,
|
||||
# see https://docs.github.com/en/code-security/code-scanning/creating-an-advanced-setup-for-code-scanning/customizing-your-advanced-setup-for-code-scanning.
|
||||
# If you are analyzing a compiled language, you can modify the 'build-mode' for that language to customize how
|
||||
# your codebase is analyzed, see https://docs.github.com/en/code-security/code-scanning/creating-an-advanced-setup-for-code-scanning/codeql-code-scanning-for-compiled-languages
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
||||
|
||||
- name: Setup Language Tooling
|
||||
uses: jdx/mise-action@146a28175021df8ca24f8ee1828cc2a60f980bd5 # v3
|
||||
|
||||
- name: Enable corepack and install pnpm
|
||||
run: |
|
||||
corepack enable
|
||||
corepack prepare --activate
|
||||
|
||||
# Add any setup steps before running the `github/codeql-action/init` action.
|
||||
# This includes steps like installing compilers or runtimes (`actions/setup-node`
|
||||
# or others). This is typically only required for manual builds.
|
||||
# - name: Setup runtime (example)
|
||||
# uses: actions/setup-example@v1
|
||||
|
||||
# Initializes the CodeQL tools for scanning.
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@15403aac29bd91419968e066cded66bde56b0283 # v3
|
||||
with:
|
||||
languages: ${{ matrix.language }}
|
||||
build-mode: ${{ matrix.build-mode }}
|
||||
# If you wish to specify custom queries, you can do so here or in a config file.
|
||||
# By default, queries listed here will override any specified in a config file.
|
||||
# Prefix the list here with "+" to use these queries and those in the config file.
|
||||
|
||||
# For more details on CodeQL's query packs, refer to: https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs
|
||||
# queries: security-extended,security-and-quality
|
||||
|
||||
# If the analyze step fails for one of the languages you are analyzing with
|
||||
# "We were unable to automatically build your code", modify the matrix above
|
||||
# to set the build mode to "manual" for that language. Then modify this step
|
||||
# to build your code.
|
||||
# ℹ️ Command-line programs to run using the OS shell.
|
||||
# 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun
|
||||
- if: matrix.build-mode == 'manual'
|
||||
shell: bash
|
||||
run: |
|
||||
echo 'If you are using a "manual" build mode for one or more of the' \
|
||||
'languages you are analyzing, replace this with the commands to build' \
|
||||
'your code, for example:'
|
||||
echo ' make bootstrap'
|
||||
echo ' make release'
|
||||
exit 1
|
||||
|
||||
- name: Perform CodeQL Analysis
|
||||
uses: github/codeql-action/analyze@15403aac29bd91419968e066cded66bde56b0283 # v3
|
||||
with:
|
||||
category: "/language:${{matrix.language}}"
|
||||
upload: 'never'
|
||||
upload-database: false
|
||||
@@ -2,7 +2,7 @@ name: E2E matrix
|
||||
|
||||
on:
|
||||
schedule:
|
||||
- cron: '0 5 * * *'
|
||||
- cron: "0 5 * * *"
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
debug_enabled:
|
||||
@@ -14,65 +14,58 @@ on:
|
||||
env:
|
||||
CYPRESS_CACHE_FOLDER: ${{ github.workspace }}/.cypress
|
||||
|
||||
permissions: {}
|
||||
permissions: { }
|
||||
jobs:
|
||||
preinstall:
|
||||
if: ${{ github.repository_owner == 'nrwl' }}
|
||||
runs-on: ${{ matrix.os }}
|
||||
timeout-minutes: 20
|
||||
env:
|
||||
NODE_VERSION: ${{ matrix.node_version }}
|
||||
strategy:
|
||||
matrix:
|
||||
os:
|
||||
- ubuntu-latest
|
||||
- macos-latest
|
||||
# - windows-latest Windows fails to build gradle wrapper which always runs when we build nx.
|
||||
## https://staging.nx.app/runs/LgD4vxGn8w?utm_source=pull-request&utm_medium=comment
|
||||
- windows-latest
|
||||
node_version:
|
||||
# TODO(v23): remove node 20 - EOL April 2026
|
||||
- 20
|
||||
- 22
|
||||
- 24
|
||||
# - 23
|
||||
exclude:
|
||||
# run just node v24 on macos and windows
|
||||
- os: macos-latest
|
||||
node_version: 20
|
||||
# run just node v20 on macos and windows
|
||||
- os: macos-latest
|
||||
node_version: 22
|
||||
# - os: windows-latest TODO(Jack): Windows fails to build gradle wrapper which always runs when we build nx. Re-enable when we fix this.
|
||||
# node_version: 20
|
||||
# - os: windows-latest TODO (Jack): Windows fails to build gradle wrapper which always runs when we build nx. Re-enable when we fix this.
|
||||
# node_version: 22
|
||||
# - os: macos-latest
|
||||
# node_version: 23
|
||||
- os: windows-latest
|
||||
node_version: 22
|
||||
# - os: windows-latest
|
||||
# node_version: 23
|
||||
|
||||
name: Cache install (${{ matrix.os }}, node v${{ matrix.node_version }})
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
filter: tree:0
|
||||
fetch-depth: 1
|
||||
|
||||
- name: Setup dev tools with mise
|
||||
uses: jdx/mise-action@146a28175021df8ca24f8ee1828cc2a60f980bd5 # v3
|
||||
|
||||
- name: Enable corepack and install pnpm
|
||||
run: |
|
||||
npm install -g corepack@latest
|
||||
corepack enable
|
||||
corepack prepare --activate
|
||||
|
||||
- name: Get pnpm store directory
|
||||
id: pnpm-cache
|
||||
run: echo "path=$(pnpm store path)" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Cache pnpm store
|
||||
uses: actions/cache@0400d5f644dc74513175e3cd8d07132dd4860809 # v4.2.4
|
||||
- uses: pnpm/action-setup@v4
|
||||
name: Install pnpm
|
||||
with:
|
||||
path: ${{ steps.pnpm-cache.outputs.path }}
|
||||
key: ${{ runner.os }}-pnpm-store-${{ hashFiles('pnpm-lock.yaml') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-pnpm-store-
|
||||
version: 9.8.0
|
||||
run_install: false
|
||||
|
||||
- name: Set node
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: ${{ matrix.node_version }}
|
||||
cache: 'pnpm'
|
||||
|
||||
- name: Cache node_modules
|
||||
id: cache-modules
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
lookup-only: true
|
||||
path: '**/node_modules'
|
||||
key: ${{ runner.os }}-modules-${{ matrix.node_version }}-${{ hashFiles('pnpm-lock.yaml') }}
|
||||
|
||||
- name: Ensure Python setuptools Installed on Macos
|
||||
if: ${{ matrix.os == 'macos-latest' }}
|
||||
@@ -80,9 +73,8 @@ jobs:
|
||||
run: brew install python-setuptools
|
||||
|
||||
- name: Install packages
|
||||
run: |
|
||||
pnpm install --frozen-lockfile
|
||||
pnpm playwright install --with-deps
|
||||
if: steps.cache-modules.outputs.cache-hit != 'true'
|
||||
run: pnpm install --frozen-lockfile
|
||||
|
||||
- name: Homebrew cache directory path
|
||||
if: ${{ matrix.os == 'macos-latest' }}
|
||||
@@ -91,7 +83,7 @@ jobs:
|
||||
|
||||
- name: Cache Homebrew
|
||||
if: ${{ matrix.os == 'macos-latest' }}
|
||||
uses: actions/cache@0400d5f644dc74513175e3cd8d07132dd4860809 # v4.2.4
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
lookup-only: true
|
||||
path: ${{ steps.homebrew-cache-dir-path.outputs.dir }}
|
||||
@@ -101,7 +93,7 @@ jobs:
|
||||
|
||||
- name: Cache Cypress
|
||||
id: cache-cypress
|
||||
uses: actions/cache@0400d5f644dc74513175e3cd8d07132dd4860809 # v4.2.4
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
lookup-only: true
|
||||
path: '${{ github.workspace }}/.cypress'
|
||||
@@ -114,20 +106,19 @@ jobs:
|
||||
prepare-matrix:
|
||||
name: Prepare matrix combinations
|
||||
if: ${{ github.repository_owner == 'nrwl' }}
|
||||
timeout-minutes: 5
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
matrix: ${{ steps.process-json.outputs.MATRIX }}
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
filter: tree:0
|
||||
fetch-depth: 1
|
||||
|
||||
- name: Process matrix data
|
||||
id: process-json
|
||||
run: echo "MATRIX=$(npx tsx .github/workflows/nightly/process-matrix.ts | jq -c .)" >> $GITHUB_OUTPUT
|
||||
run:
|
||||
echo "MATRIX=$(npx tsx .github/workflows/nightly/process-matrix.ts | jq -c .)" >> $GITHUB_OUTPUT
|
||||
|
||||
e2e:
|
||||
if: ${{ github.repository_owner == 'nrwl' }}
|
||||
@@ -137,9 +128,6 @@ jobs:
|
||||
permissions:
|
||||
contents: read
|
||||
runs-on: ${{ matrix.os }}
|
||||
timeout-minutes: 200 # <- cap each job to 200 minutes
|
||||
env:
|
||||
NODE_VERSION: ${{ matrix.node_version }}
|
||||
strategy:
|
||||
matrix: ${{fromJson(needs.prepare-matrix.outputs.matrix)}} # Load matrix from previous job
|
||||
fail-fast: false
|
||||
@@ -147,27 +135,34 @@ jobs:
|
||||
name: ${{ matrix.os_name }}/${{ matrix.package_manager }}/${{ matrix.node_version }} ${{ join(matrix.project) }}
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
filter: tree:0
|
||||
fetch-depth: 1
|
||||
|
||||
- name: Prepare dir for output
|
||||
run: mkdir -p outputs
|
||||
|
||||
- name: Setup dev tools with mise
|
||||
uses: jdx/mise-action@146a28175021df8ca24f8ee1828cc2a60f980bd5 # v3
|
||||
- uses: pnpm/action-setup@v4
|
||||
name: Install pnpm
|
||||
with:
|
||||
version: 9.8.0
|
||||
run_install: false
|
||||
|
||||
- name: Enable corepack and install pnpm
|
||||
run: |
|
||||
npm install -g corepack@latest
|
||||
corepack enable
|
||||
corepack prepare --activate
|
||||
- name: Use Node.js ${{ matrix.node_version }}
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: ${{ matrix.node_version }}
|
||||
cache: 'pnpm'
|
||||
|
||||
- name: Cache node_modules
|
||||
id: cache-modules
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: '**/node_modules'
|
||||
key: ${{ runner.os }}-modules-${{ matrix.node_version }}-${{ hashFiles('pnpm-lock.yaml') }}
|
||||
|
||||
- name: Install packages
|
||||
run: |
|
||||
pnpm install --frozen-lockfile
|
||||
pnpm playwright install --with-deps
|
||||
run: pnpm install --frozen-lockfile
|
||||
|
||||
- name: Cleanup
|
||||
if: ${{ matrix.os == 'ubuntu-latest' }}
|
||||
@@ -176,7 +171,7 @@ jobs:
|
||||
# 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 "/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
|
||||
@@ -188,7 +183,7 @@ jobs:
|
||||
|
||||
- name: Cache Homebrew
|
||||
if: ${{ matrix.os == 'macos-latest' }}
|
||||
uses: actions/cache@0400d5f644dc74513175e3cd8d07132dd4860809 # v4.2.4
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: ${{ steps.homebrew-cache-dir-path.outputs.dir }}
|
||||
key: brew-${{ matrix.node_version }}
|
||||
@@ -197,7 +192,7 @@ jobs:
|
||||
|
||||
- name: Cache Cypress
|
||||
id: cache-cypress
|
||||
uses: actions/cache@0400d5f644dc74513175e3cd8d07132dd4860809 # v4.2.4
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: '${{ github.workspace }}/.cypress'
|
||||
key: ${{ runner.os }}-cypress
|
||||
@@ -206,116 +201,26 @@ jobs:
|
||||
if: steps.cache-cypress.outputs.cache-hit != 'true'
|
||||
run: npx cypress install
|
||||
|
||||
- name: Configure Detox Environment, Install applesimutils
|
||||
- name: Install applesimutils, reset ios simulators
|
||||
if: ${{ matrix.os == 'macos-latest' }}
|
||||
run: |
|
||||
# Ensure Xcode command line tools are installed and configured
|
||||
xcode-select --print-path || sudo xcode-select --reset
|
||||
sudo xcode-select -s /Applications/Xcode.app
|
||||
|
||||
# Install or update applesimutils with error handling
|
||||
if ! brew list applesimutils &>/dev/null; then
|
||||
echo 'Installing applesimutils...'
|
||||
HOMEBREW_NO_AUTO_UPDATE=1 brew tap wix/brew >/dev/null
|
||||
HOMEBREW_NO_AUTO_UPDATE=1 brew install applesimutils >/dev/null || {
|
||||
echo 'Failed to install applesimutils, retrying with update...'
|
||||
brew update
|
||||
HOMEBREW_NO_AUTO_UPDATE=1 brew install applesimutils
|
||||
}
|
||||
else
|
||||
echo 'Updating applesimutils...'
|
||||
HOMEBREW_NO_AUTO_UPDATE=1 brew upgrade applesimutils || true
|
||||
fi
|
||||
|
||||
# Verify applesimutils installation
|
||||
applesimutils --version || (echo 'applesimutils installation failed' && exit 1)
|
||||
|
||||
# Configure environment for M-series Mac
|
||||
echo 'DEVELOPER_DIR=/Applications/Xcode.app/Contents/Developer' >> $GITHUB_ENV
|
||||
echo 'PLATFORM_NAME=iOS Simulator' >> $GITHUB_ENV
|
||||
|
||||
# Set additional environment variables for better debugging
|
||||
echo 'DETOX_DISABLE_TELEMETRY=1' >> $GITHUB_ENV
|
||||
echo 'DETOX_LOG_LEVEL=trace' >> $GITHUB_ENV
|
||||
|
||||
# Verify Xcode installation
|
||||
xcodebuild -version
|
||||
|
||||
timeout-minutes: 10
|
||||
continue-on-error: false
|
||||
|
||||
- name: Reset iOS Simulators
|
||||
if: ${{ matrix.os == 'macos-latest' }}
|
||||
id: reset-simulators
|
||||
run: |
|
||||
echo 'Resetting iOS Simulators...'
|
||||
|
||||
# Kill simulator processes
|
||||
sudo killall -9 com.apple.CoreSimulator.CoreSimulatorService 2>/dev/null || true
|
||||
killall 'Simulator' 2>/dev/null || true
|
||||
killall 'iOS Simulator' 2>/dev/null || true
|
||||
|
||||
# Wait for processes to terminate
|
||||
sleep 3
|
||||
|
||||
# Shutdown and erase all simulators (ignore failures)
|
||||
xcrun simctl shutdown all 2>/dev/null || true
|
||||
sleep 5
|
||||
xcrun simctl erase all 2>/dev/null || true
|
||||
|
||||
# If erase failed, try the nuclear option
|
||||
if xcrun simctl list devices | grep -q 'Booted' 2>/dev/null; then
|
||||
echo 'Standard reset failed, using nuclear option...'
|
||||
rm -rf ~/Library/Developer/CoreSimulator/Devices/* 2>/dev/null || true
|
||||
launchctl remove com.apple.CoreSimulator.CoreSimulatorService 2>/dev/null || true
|
||||
sleep 3
|
||||
fi
|
||||
|
||||
# Clean up additional directories
|
||||
rm -rf ~/Library/Developer/CoreSimulator/Caches/* 2>/dev/null || true
|
||||
rm -rf ~/Library/Logs/CoreSimulator/* 2>/dev/null || true
|
||||
rm -rf ~/Library/Developer/Xcode/DerivedData/* 2>/dev/null || true
|
||||
|
||||
echo 'Simulator reset completed'
|
||||
timeout-minutes: 5
|
||||
continue-on-error: true
|
||||
|
||||
- name: Verify Simulator Reset
|
||||
if: ${{ matrix.os == 'macos-latest' && steps.reset-simulators.outcome == 'success' }}
|
||||
run: |
|
||||
# Verify CoreSimulator service restarted
|
||||
pgrep -fl 'CoreSimulator' || (echo 'CoreSimulator service not running' && exit 1)
|
||||
|
||||
# Verify simulator runtime paths exist and are writable
|
||||
test -d ~/Library/Developer/CoreSimulator/Devices || (echo 'Simulator devices directory missing' && exit 1)
|
||||
touch ~/Library/Developer/CoreSimulator/Devices/test || (echo 'Simulator devices directory not writable' && exit 1)
|
||||
rm ~/Library/Developer/CoreSimulator/Devices/test
|
||||
timeout-minutes: 5
|
||||
|
||||
- name: Diagnose Simulator Reset Failure
|
||||
if: ${{ matrix.os == 'macos-latest' && steps.reset-simulators.outcome == 'failure' }}
|
||||
run: |
|
||||
echo 'Simulator reset failed. Collecting diagnostic information...'
|
||||
xcrun simctl list
|
||||
echo 'Checking simulator logs...'
|
||||
ls -la ~/Library/Logs/CoreSimulator/ || echo 'No simulator logs found'
|
||||
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)
|
||||
if: ${{ (matrix.os != 'macos-latest') || (matrix.os == 'macos-latest' && steps.reset-simulators.outcome == 'success') }}
|
||||
run: |
|
||||
git config --global user.email test@test.com
|
||||
git config --global user.name 'Test Test'
|
||||
git config --global user.name "Test Test"
|
||||
|
||||
- name: Set starting timestamp
|
||||
if: ${{ (matrix.os != 'macos-latest') || (matrix.os == 'macos-latest' && steps.reset-simulators.outcome == 'success') }}
|
||||
id: before-e2e
|
||||
shell: bash
|
||||
run: |
|
||||
echo "timestamp=$(date +%s)" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Run e2e tests with pnpm (Linux/Windows)
|
||||
id: e2e-run-pnpm
|
||||
if: ${{ matrix.os != 'macos-latest' }}
|
||||
- name: Run e2e tests
|
||||
id: e2e-run
|
||||
run: pnpm nx run ${{ matrix.project }}:e2e-local
|
||||
shell: bash
|
||||
timeout-minutes: ${{ matrix.os_timeout }}
|
||||
@@ -332,33 +237,6 @@ jobs:
|
||||
SELECTED_PM: ${{ matrix.package_manager }}
|
||||
npm_config_registry: http://localhost:4872
|
||||
YARN_REGISTRY: http://localhost:4872
|
||||
CI: true
|
||||
|
||||
- name: Run e2e tests with npm (macOS)
|
||||
id: e2e-run-npm
|
||||
if: ${{ matrix.os == 'macos-latest' && steps.reset-simulators.outcome == 'success' }}
|
||||
run: |
|
||||
# Run the tests
|
||||
if [[ '${{ matrix.project }}' == 'e2e-detox' ]] || [[ '${{ matrix.project }}' == 'e2e-react-native' ]] || [[ '${{ matrix.project }}' == 'e2e-expo' ]]; then
|
||||
NX_E2E_VERBOSE_DEBUG=1 pnpm nx run ${{ matrix.project }}:e2e-macos-local
|
||||
else
|
||||
NX_E2E_VERBOSE_DEBUG=1 pnpm nx run ${{ matrix.project }}:e2e-local
|
||||
fi
|
||||
|
||||
env:
|
||||
NX_E2E_CI_CACHE_KEY: e2e-gha-${{ matrix.os }}-${{ matrix.node_version }}-${{ matrix.package_manager }}
|
||||
NX_PERF_LOGGING: 'false'
|
||||
NX_CI_EXECUTION_ENV: 'macos'
|
||||
NX_E2E_VERBOSE_LOGGING: 'true'
|
||||
NX_NATIVE_LOGGING: 'false'
|
||||
NX_E2E_RUN_E2E: 'true'
|
||||
NX_E2E_SKIP_CLEANUP: 'true'
|
||||
NODE_OPTIONS: --max_old_space_size=8192
|
||||
SELECTED_PM: 'npm'
|
||||
npm_config_registry: http://localhost:4872
|
||||
YARN_REGISTRY: http://localhost:4872
|
||||
DEVELOPER_DIR: '/Applications/Xcode.app/Contents/Developer'
|
||||
CI: true
|
||||
|
||||
- name: Save matrix config in file
|
||||
if: ${{ always() }}
|
||||
@@ -368,17 +246,13 @@ jobs:
|
||||
before=${{ steps.before-e2e.outputs.timestamp }}
|
||||
now=$(date +%s)
|
||||
delta=$(($now - $before))
|
||||
|
||||
# Determine the outcome based on which step ran
|
||||
outcome='${{ matrix.os == 'macos-latest' && steps.e2e-run-npm.outcome || steps.e2e-run-pnpm.outcome }}'
|
||||
|
||||
matrix=$((
|
||||
echo '${{ toJSON(matrix) }}'
|
||||
) | jq --argjson delta $delta -c '. + { "status": "'"$outcome"'", "duration": $delta }')
|
||||
) | jq --argjson delta $delta -c '. + { "status": "${{ steps.e2e-run.outcome}}", "duration": $delta }')
|
||||
echo "$matrix" > 'outputs/matrix.json'
|
||||
|
||||
- name: Upload matrix config
|
||||
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
|
||||
uses: actions/upload-artifact@v4
|
||||
if: ${{ always() }}
|
||||
with:
|
||||
name: ${{ matrix.os_name}}-${{ matrix.node_version}}-${{ matrix.package_manager}}-${{ matrix.project }}
|
||||
@@ -388,79 +262,198 @@ jobs:
|
||||
|
||||
- name: Setup tmate session
|
||||
if: ${{ github.event_name == 'workflow_dispatch' && inputs.debug_enabled && failure() }}
|
||||
uses: mxschmitt/action-tmate@1fb8b1023602bf1fd0e2994d7f1e93015cb5bbec # v3.22
|
||||
uses: mxschmitt/action-tmate@v3.8
|
||||
timeout-minutes: 15
|
||||
with:
|
||||
sudo: ${{ matrix.os != 'windows-latest' }} # disable sudo for windows debugging
|
||||
|
||||
process-result:
|
||||
if: ${{ always() && github.repository_owner == 'nrwl' && github.event_name != 'workflow_dispatch' }}
|
||||
if: ${{ always() && github.repository_owner == 'nrwl' }}
|
||||
runs-on: ubuntu-latest
|
||||
needs: e2e
|
||||
timeout-minutes: 10
|
||||
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 }}
|
||||
has_golden_failures: ${{ steps.process-json.outputs.has_golden_failures }}
|
||||
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: Checkout
|
||||
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
||||
with:
|
||||
fetch-depth: 0
|
||||
filter: tree:0
|
||||
|
||||
- name: Prepare dir for output
|
||||
run: mkdir -p outputs
|
||||
|
||||
- name: Load outputs
|
||||
uses: actions/download-artifact@634f93cb2916e3fdff6788551b99b062d0335ce0 # v5.0.0
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
path: outputs
|
||||
|
||||
- name: Join and stringify matrix configs
|
||||
id: combine-json
|
||||
run: |
|
||||
combined=$(jq -sc . outputs/*/matrix.json)
|
||||
combined=$((jq -s . outputs/*/matrix.json) | jq tostring)
|
||||
echo "combined=$combined" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Process results with TypeScript script
|
||||
- name: Make slack outputs
|
||||
id: process-json
|
||||
run: |
|
||||
echo '${{ steps.combine-json.outputs.combined }}' | npx tsx .github/workflows/nightly/process-result.ts
|
||||
uses: actions/github-script@v7
|
||||
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} |`
|
||||
lastProject = matrix.project;
|
||||
});
|
||||
result += `\`\`\``;
|
||||
core.setOutput('SLACK_MESSAGE', trimSpace(result));
|
||||
console.log(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 === 20) {
|
||||
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: ${{ always() && needs.process-result.outputs.has_golden_failures == 'true' && github.repository_owner == 'nrwl' && github.event_name != 'workflow_dispatch' }}
|
||||
if: ${{ failure() && github.repository_owner == 'nrwl' && github.event_name != 'workflow_dispatch' }}
|
||||
needs: process-result
|
||||
runs-on: ubuntu-latest
|
||||
name: Report failure
|
||||
timeout-minutes: 10
|
||||
steps:
|
||||
- name: Send notification
|
||||
uses: ravsamhq/notify-slack-action@be814b201e233b2dc673608aa46e5447c8ab13f2 # v11
|
||||
uses: ravsamhq/notify-slack-action@v2
|
||||
with:
|
||||
status: 'failure'
|
||||
message_format: '${{ needs.process-result.outputs.message }}'
|
||||
notification_title: 'Golden Test 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: ${{ always() && needs.process-result.outputs.has_golden_failures == 'false' && github.repository_owner == 'nrwl' && github.event_name != 'workflow_dispatch' }}
|
||||
needs: process-result
|
||||
if: ${{ success() && github.repository_owner == 'nrwl' && github.event_name != 'workflow_dispatch' }}
|
||||
needs: e2e
|
||||
runs-on: ubuntu-latest
|
||||
name: Report status
|
||||
timeout-minutes: 10
|
||||
steps:
|
||||
- name: Send notification
|
||||
uses: ravsamhq/notify-slack-action@be814b201e233b2dc673608aa46e5447c8ab13f2 # v11
|
||||
uses: ravsamhq/notify-slack-action@v2
|
||||
with:
|
||||
status: 'success'
|
||||
message_format: '${{ needs.process-result.outputs.message }}'
|
||||
notification_title: '✅ Golden Tests: All Passed!'
|
||||
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 }}
|
||||
@@ -469,15 +462,14 @@ jobs:
|
||||
if: ${{ always() && github.repository_owner == 'nrwl' && github.event_name != 'workflow_dispatch' }}
|
||||
needs: process-result
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 10
|
||||
name: Report duration per package manager
|
||||
steps:
|
||||
- name: Send notification
|
||||
uses: ravsamhq/notify-slack-action@be814b201e233b2dc673608aa46e5447c8ab13f2 # v11
|
||||
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)'
|
||||
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 }}
|
||||
|
||||
@@ -485,14 +477,13 @@ jobs:
|
||||
if: ${{ always() && github.repository_owner == 'nrwl' && github.event_name != 'workflow_dispatch' }}
|
||||
needs: process-result
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 10
|
||||
name: Report duration per project
|
||||
name: Report duration per package manager
|
||||
steps:
|
||||
- name: Send notification
|
||||
uses: ravsamhq/notify-slack-action@be814b201e233b2dc673608aa46e5447c8ab13f2 # v11
|
||||
uses: ravsamhq/notify-slack-action@v2
|
||||
with:
|
||||
status: 'skipped'
|
||||
message_format: '${{ needs.process-result.outputs.proj_duration }}'
|
||||
notification_title: '⌛ E2E Project duration stats'
|
||||
message_format: '${{ needs.process-result.outputs.proj-duration }}'
|
||||
notification_title: 'E2E Project duration stats'
|
||||
env:
|
||||
SLACK_WEBHOOK_URL: ${{ secrets.ACTION_MONITORING_SLACK }}
|
||||
|
||||
@@ -3,30 +3,29 @@ 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: ['24']
|
||||
node-version: ['20.19.0']
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Install Node.js
|
||||
uses: actions/setup-node@a0853c24544627f65ddf259abe73b1d18a591444 # v5.0.0
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: '24'
|
||||
package-manager-cache: false
|
||||
node-version: '20.19.0'
|
||||
|
||||
- name: Install pnpm
|
||||
uses: pnpm/action-setup@7088e561eb65bb68695d245aa206f005ef30921d # v4.1.0
|
||||
uses: pnpm/action-setup@v4
|
||||
id: pnpm-install
|
||||
with:
|
||||
version: 10.11.1
|
||||
version: 9.8.0
|
||||
run_install: false
|
||||
|
||||
- name: Get pnpm store directory
|
||||
@@ -36,7 +35,7 @@ jobs:
|
||||
echo "STORE_PATH=$(pnpm store path)" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Setup pnpm cache
|
||||
uses: actions/cache@0400d5f644dc74513175e3cd8d07132dd4860809 # v4.2.4
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: ${{ steps.pnpm-cache.outputs.STORE_PATH }}
|
||||
key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
|
||||
@@ -46,11 +45,8 @@ jobs:
|
||||
- name: Install dependencies
|
||||
run: pnpm install --no-frozen-lockfile
|
||||
|
||||
- name: Build docs
|
||||
run: npx nx build astro-docs
|
||||
|
||||
- name: Run embeddings script
|
||||
run: node --import tsx tools/documentation/create-embeddings/src/main.mts --mode=astro
|
||||
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 }}
|
||||
|
||||
@@ -16,21 +16,21 @@ jobs:
|
||||
name: Report status
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- uses: pnpm/action-setup@7088e561eb65bb68695d245aa206f005ef30921d # v4.1.0
|
||||
- uses: pnpm/action-setup@v4
|
||||
with:
|
||||
version: 10.11.1
|
||||
version: 9.8.0
|
||||
|
||||
- name: Use Node.js ${{ matrix.node_version }}
|
||||
uses: actions/setup-node@a0853c24544627f65ddf259abe73b1d18a591444 # v5.0.0
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: '24'
|
||||
node-version: '20.19.0'
|
||||
cache: 'pnpm'
|
||||
|
||||
- name: Cache node_modules
|
||||
id: cache-modules
|
||||
uses: actions/cache@0400d5f644dc74513175e3cd8d07132dd4860809 # v4.2.4
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
lookup-only: true
|
||||
path: '**/node_modules'
|
||||
@@ -41,12 +41,11 @@ jobs:
|
||||
|
||||
- name: Download artifact
|
||||
id: download-artifact
|
||||
uses: dawidd6/action-download-artifact@268677152d06ba59fcec7a7f0b5d961b6ccd7e1e # v2 # Needed since we are downloading artifact from a different workflow run, official actions/download-artifact doesn't support this.
|
||||
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
|
||||
allow_forks: false
|
||||
continue-on-error: true
|
||||
|
||||
- name: Collect Issue Data
|
||||
@@ -55,14 +54,14 @@ jobs:
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ github.token }}
|
||||
|
||||
- uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
|
||||
- uses: actions/upload-artifact@v4
|
||||
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@91efab103c0de0a537f72a35f6b8cda0ee76bf0a # v2.1.1
|
||||
uses: slackapi/slack-github-action@v1.23.0
|
||||
with:
|
||||
payload: ${{ steps.collect.outputs.SLACK_MESSAGE }}
|
||||
env:
|
||||
|
||||
@@ -17,7 +17,7 @@ jobs:
|
||||
if: ${{ github.repository_owner == 'nrwl' }}
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: dessant/lock-threads@7de207be1d3ce97a9abe6ff1306222982d1ca9f9 # v5.0.1
|
||||
- uses: dessant/lock-threads@v4
|
||||
id: lockthreads
|
||||
with:
|
||||
github-token: ${{ github.token }}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
type MatrixDataProject = {
|
||||
name: string,
|
||||
codeowners: string,
|
||||
is_golden?: boolean, // true if this is a golden project, false otherwise
|
||||
};
|
||||
|
||||
type MatrixDataOS = {
|
||||
@@ -20,74 +19,58 @@ type MatrixData = {
|
||||
setup: MatrixDataOS[],
|
||||
}
|
||||
|
||||
export type MatrixItem = {
|
||||
// TODO: Extract Slack groups into named groups for easier maintenance
|
||||
const matrixData: MatrixData = {
|
||||
coreProjects: [
|
||||
{ name: 'e2e-lerna-smoke-tests', codeowners: 'S04TNCVEETS' },
|
||||
{ name: 'e2e-js', codeowners: 'S04SJ6HHP0X' },
|
||||
{ name: 'e2e-nx-init', codeowners: 'S04SYHYKGNP' },
|
||||
{ name: 'e2e-nx', codeowners: 'S04SYHYKGNP' },
|
||||
{ name: 'e2e-release', codeowners: 'S04SYHYKGNP' },
|
||||
{ name: 'e2e-workspace-create', codeowners: 'S04SYHYKGNP' }
|
||||
],
|
||||
projects: [
|
||||
{ name: 'e2e-angular', codeowners: 'S04SS457V38' },
|
||||
{ name: 'e2e-cypress', codeowners: 'S04T16BTJJY' },
|
||||
{ name: 'e2e-detox', codeowners: 'S04TNCNJG5N' },
|
||||
{ name: 'e2e-esbuild', codeowners: 'S04SJ6HHP0X' },
|
||||
{ name: 'e2e-expo', codeowners: 'S04TNCNJG5N' },
|
||||
{ name: 'e2e-gradle', codeowners: 'S04TNCNJG5N' },
|
||||
{ name: 'e2e-jest', codeowners: 'S04T16BTJJY' },
|
||||
{ name: 'e2e-eslint', codeowners: 'S04SYJGKSCT' },
|
||||
{ name: 'e2e-next', codeowners: 'S04TNCNJG5N' },
|
||||
{ name: 'e2e-node', codeowners: 'S04SJ6HHP0X' },
|
||||
{ name: 'e2e-plugin', codeowners: 'S04SYHYKGNP' },
|
||||
{ name: 'e2e-react', codeowners: 'S04TNCNJG5N' },
|
||||
{ name: 'e2e-react-native', codeowners: 'S04TNCNJG5N' },
|
||||
{ name: 'e2e-web', codeowners: 'S04SJ6PL98X' },
|
||||
{ name: 'e2e-rollup', codeowners: 'S04SJ6PL98X' },
|
||||
{ name: 'e2e-storybook', codeowners: 'S04SVQ8H0G5' },
|
||||
{ name: 'e2e-playwright', codeowners: 'S04SVQ8H0G5' },
|
||||
{ name: 'e2e-remix', codeowners: 'S04SVQ8H0G5' },
|
||||
{ name: 'e2e-rspack', codeowners: 'S04SJ6HHP0X' },
|
||||
{ name: 'e2e-vite', codeowners: 'S04SJ6PL98X' },
|
||||
{ name: 'e2e-vue', codeowners: 'S04SJ6PL98X' },
|
||||
{ name: 'e2e-nuxt', codeowners: 'S04SJ6PL98X' },
|
||||
{ name: 'e2e-webpack', codeowners: 'S04SJ6PL98X' }
|
||||
],
|
||||
nodeTLS: 20,
|
||||
setup: [
|
||||
{ os: 'ubuntu-latest', os_name: 'Linux', os_timeout: 60, package_managers: ['npm', 'pnpm', 'yarn'], node_versions: ['20.19.0', "22.12.0"], excluded: ['e2e-detox', 'e2e-react-native', 'e2e-expo'] },
|
||||
{ os: 'macos-latest', os_name: 'MacOS', os_timeout: 90, package_managers: ['npm'], node_versions: ['20.19.0'] },
|
||||
{ os: 'windows-latest', os_name: 'WinOS', os_timeout: 180, package_managers: ['npm'], node_versions: ['20.19.0'], excluded: ['e2e-detox', 'e2e-react-native', 'e2e-expo'] }
|
||||
]
|
||||
};
|
||||
|
||||
const matrix: Array<{
|
||||
project: string,
|
||||
codeowners: string,
|
||||
node_version: number | string,
|
||||
package_manager: string,
|
||||
os: string,
|
||||
os_name: string,
|
||||
os_timeout: number,
|
||||
is_golden?: boolean,
|
||||
};
|
||||
|
||||
// TODO: Extract Slack groups into named groups for easier maintenance
|
||||
const matrixData: MatrixData = {
|
||||
coreProjects: [
|
||||
{ name: 'e2e-lerna-smoke-tests', codeowners: 'S04TNCVEETS', is_golden: true },
|
||||
{ name: 'e2e-js', codeowners: 'S04SJ6HHP0X', is_golden: true },
|
||||
{ name: 'e2e-nx-init', codeowners: 'S04SYHYKGNP', is_golden: true },
|
||||
{ name: 'e2e-nx', codeowners: 'S04SYHYKGNP' },
|
||||
{ name: 'e2e-release', codeowners: 'S04SYHYKGNP' },
|
||||
{ name: 'e2e-workspace-create', codeowners: 'S04SYHYKGNP' }
|
||||
],
|
||||
projects: [
|
||||
{ name: 'e2e-cypress', codeowners: 'S04T16BTJJY', is_golden: true },
|
||||
{ name: 'e2e-docker', codeowners: 'S04SJ6HHP0X', is_golden: true },
|
||||
{ name: 'e2e-detox', codeowners: 'S04TNCNJG5N', is_golden: true },
|
||||
{ name: 'e2e-esbuild', codeowners: 'S04SJ6HHP0X', is_golden: true },
|
||||
{ name: 'e2e-gradle', codeowners: 'S04TNCNJG5N', is_golden: true },
|
||||
{ name: 'e2e-eslint', codeowners: 'S04SYJGKSCT', is_golden: true },
|
||||
{ name: 'e2e-node', codeowners: 'S04SJ6HHP0X', is_golden: true },
|
||||
{ name: 'e2e-playwright', codeowners: 'S04SVQ8H0G5', is_golden: true },
|
||||
{ name: 'e2e-remix', codeowners: 'S04SVQ8H0G5', is_golden: true },
|
||||
{ name: 'e2e-rspack', codeowners: 'S04SJ6HHP0X', is_golden: true },
|
||||
{ name: 'e2e-vite', codeowners: 'S04SJ6PL98X', is_golden: true },
|
||||
{ name: 'e2e-vue', codeowners: 'S04SJ6PL98X', is_golden: true },
|
||||
{ name: 'e2e-web', codeowners: 'S04SJ6PL98X', is_golden: true },
|
||||
{ name: 'e2e-webpack', codeowners: 'S04SJ6PL98X', is_golden: true },
|
||||
{ name: 'e2e-jest', codeowners: 'S04T16BTJJY', is_golden: true },
|
||||
{ name: 'e2e-expo', codeowners: 'S04TNCNJG5N', is_golden: true },
|
||||
{ name: 'e2e-react-native', codeowners: 'S04TNCNJG5N', is_golden: true },
|
||||
{ name: 'e2e-angular', codeowners: 'S04SS457V38' },
|
||||
{ name: 'e2e-next', codeowners: 'S04TNCNJG5N' },
|
||||
{ name: 'e2e-plugin', codeowners: 'S04SYHYKGNP' },
|
||||
{ name: 'e2e-react', codeowners: 'S04TNCNJG5N' },
|
||||
{ name: 'e2e-rollup', codeowners: 'S04SJ6PL98X' },
|
||||
{ name: 'e2e-storybook', codeowners: 'S04SVQ8H0G5' },
|
||||
{ name: 'e2e-nuxt', codeowners: 'S04SJ6PL98X' }
|
||||
],
|
||||
// TODO(v23): remove node 20 - EOL April 2026
|
||||
nodeTLS: 20,
|
||||
setup: [
|
||||
{
|
||||
os: 'ubuntu-latest',
|
||||
os_name: 'Linux',
|
||||
os_timeout: 60,
|
||||
package_managers: ['npm', 'pnpm', 'yarn'],
|
||||
node_versions: ['20.19.0', '22.12.0', '24.0.0'],
|
||||
excluded: ['e2e-detox', 'e2e-react-native', 'e2e-expo']
|
||||
},
|
||||
// Docker is not supported on ARM-based macOS runners (no nested virtualization)
|
||||
// See: https://github.com/docker/setup-docker-action and https://github.com/douglascamata/setup-docker-macos-action
|
||||
// We may want to look into adding intel only for this docker case, at least until vm-in-vm works on latest macos
|
||||
{ os: 'macos-latest', os_name: 'MacOS', os_timeout: 90, package_managers: ['npm'], node_versions: ['24.0.0'], excluded: ['e2e-docker'] }
|
||||
// TODO (Jack): Fix Windows support as gradle fails when running nx build https://staging.nx.app/runs/LgD4vxGn8w?utm_source=pull-request&utm_medium=comment
|
||||
// { os: 'windows-latest', os_name: 'WinOS', os_timeout: 180, package_managers: ['npm'], node_versions: ['24.0.0'], excluded: ['e2e-detox', 'e2e-react-native', 'e2e-expo'] }
|
||||
]
|
||||
};
|
||||
|
||||
const matrix: Array<MatrixItem> = [];
|
||||
os_timeout: number
|
||||
}> = [];
|
||||
|
||||
function addMatrixCombo(project: MatrixDataProject, nodeVersion: number | string, pm: number, os: number) {
|
||||
matrix.push({
|
||||
@@ -98,7 +81,6 @@ function addMatrixCombo(project: MatrixDataProject, nodeVersion: number | string
|
||||
os: matrixData.setup[os].os,
|
||||
os_name: matrixData.setup[os].os_name,
|
||||
os_timeout: matrixData.setup[os].os_timeout,
|
||||
is_golden: !!project.is_golden // Mark golden projects as true, others as false
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -1,197 +0,0 @@
|
||||
import * as fs from 'fs';
|
||||
import { MatrixItem } from './process-matrix';
|
||||
|
||||
interface MatrixResult extends MatrixItem {
|
||||
status: 'success' | 'failure' | 'cancelled';
|
||||
duration: number;
|
||||
}
|
||||
|
||||
interface ProcessedResults {
|
||||
codeowners: string;
|
||||
slack_message: string;
|
||||
slack_proj_duration: string;
|
||||
slack_pm_duration: string;
|
||||
has_golden_failures: string;
|
||||
}
|
||||
|
||||
function trimSpace(res: string): string {
|
||||
return res.split('\n').map((l) => l.trim()).join('\n');
|
||||
}
|
||||
|
||||
function humanizeDuration(num: number): string {
|
||||
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;
|
||||
}
|
||||
|
||||
function processResults(combined: MatrixResult[]): ProcessedResults {
|
||||
const failedProjects = combined.filter(c => c.status === 'failure' || c.status === 'cancelled').sort((a, b) => a.project.localeCompare(b.project));
|
||||
const failedGoldenProjects = failedProjects.filter(c => c.is_golden);
|
||||
const hasGoldenFailures = failedGoldenProjects.length > 0;
|
||||
const codeowners = new Set<string>();
|
||||
failedGoldenProjects.forEach(c => codeowners.add(c.codeowners));
|
||||
|
||||
let result = '';
|
||||
|
||||
const allGoldenProjects = combined.filter(c => c.is_golden);
|
||||
const uniqueGoldenProjects = new Set(allGoldenProjects.map(c => c.project));
|
||||
const uniqueFailedGoldenProjects = new Set(failedGoldenProjects.map(c => c.project));
|
||||
const goldenPassingCount = uniqueGoldenProjects.size - uniqueFailedGoldenProjects.size;
|
||||
const goldenFailingCount = uniqueFailedGoldenProjects.size;
|
||||
|
||||
const allOtherProjects = combined.filter(c => !c.is_golden);
|
||||
const uniqueOtherProjects = new Set(allOtherProjects.map(c => c.project));
|
||||
const failedRegularProjects = failedProjects.filter(c => !c.is_golden);
|
||||
const uniqueFailedOtherProjects = new Set(failedRegularProjects.map(c => c.project));
|
||||
const otherPassingCount = uniqueOtherProjects.size - uniqueFailedOtherProjects.size;
|
||||
const otherFailingCount = uniqueFailedOtherProjects.size;
|
||||
|
||||
result += `\n🌟 *Golden Projects*`;
|
||||
result += `\n✅ Passing: ${goldenPassingCount}`;
|
||||
result += `\n❌ Failing: ${goldenFailingCount}`;
|
||||
|
||||
if (failedGoldenProjects.length > 0) {
|
||||
result += `\n\n🚨 *Failed Golden Projects*\n\`\`\``;
|
||||
result += `\n| Failed project |`;
|
||||
result += `\n|--------------------------------|`;
|
||||
let lastProject: string | undefined;
|
||||
failedGoldenProjects.forEach(matrix => {
|
||||
const project = matrix.project !== lastProject ? matrix.project : '';
|
||||
if (project) {
|
||||
result += `\n| ${project.padEnd(30)} |`;
|
||||
lastProject = matrix.project;
|
||||
}
|
||||
});
|
||||
result += `\n\`\`\``;
|
||||
}
|
||||
|
||||
result += `\n\n🔧 *Other Projects*`;
|
||||
result += `\n✅ Passing: ${otherPassingCount}`;
|
||||
result += `\n❌ Failing: ${otherFailingCount}`;
|
||||
|
||||
// Failed Other Projects Table (if any)
|
||||
if (failedRegularProjects.length > 0) {
|
||||
result += `\n\n⚠️ *Failed Other Projects*\n\`\`\``;
|
||||
result += `\n| Failed project |`;
|
||||
result += `\n|--------------------------------|`;
|
||||
let lastProject: string | undefined;
|
||||
failedRegularProjects.forEach(matrix => {
|
||||
const project = matrix.project !== lastProject ? matrix.project : '';
|
||||
if (project) {
|
||||
result += `\n| ${project.padEnd(30)} |`;
|
||||
lastProject = matrix.project;
|
||||
}
|
||||
});
|
||||
result += `\n\`\`\``;
|
||||
}
|
||||
|
||||
if (failedProjects.length === 0) {
|
||||
result = '🎉 *No test failures detected!* All systems green! 🟢';
|
||||
}
|
||||
|
||||
const timeReport: Record<string, { min: number; max: number; minEnv: string; maxEnv: string }> = {};
|
||||
const pmReport = { npm: 0, yarn: 0, pnpm: 0 };
|
||||
const macosProjects = ['e2e-detox', 'e2e-expo', 'e2e-react-native'];
|
||||
|
||||
combined.forEach(matrix => {
|
||||
const nodeVersion = parseInt(matrix.node_version.toString());
|
||||
if (matrix.os_name === 'Linux' && nodeVersion === 20 && matrix.package_manager in pmReport) {
|
||||
pmReport[matrix.package_manager as keyof typeof pmReport] += 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}`,
|
||||
};
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
let resultPkg = `
|
||||
\`\`\`
|
||||
| Project | Time |
|
||||
|--------------------------------|---------------------------|`;
|
||||
|
||||
function mapProjectTime(proj: string, section: 'min' | 'max'): string {
|
||||
return `${humanizeDuration(timeReport[proj][section])} (${timeReport[proj][`${section}Env`]})`;
|
||||
}
|
||||
|
||||
function durationIcon(proj: string, section: 'min' | 'max'): string {
|
||||
const duration = timeReport[proj][section];
|
||||
if (duration < 12 * 60) return `${section} ✅`;
|
||||
if (duration < 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 += `\`\`\``;
|
||||
|
||||
let resultPm = `
|
||||
\`\`\`
|
||||
| PM | Total time |
|
||||
|------|-------------|`;
|
||||
Object.keys(pmReport).forEach(pm => {
|
||||
resultPm += `\n| ${pm.padEnd(4)} | ${humanizeDuration(pmReport[pm as keyof typeof pmReport]).padEnd(11)} |`;
|
||||
});
|
||||
resultPm += `\`\`\``;
|
||||
|
||||
return {
|
||||
codeowners: Array.from(codeowners).join(','),
|
||||
slack_message: trimSpace(result),
|
||||
slack_proj_duration: trimSpace(resultPkg),
|
||||
slack_pm_duration: trimSpace(resultPm),
|
||||
has_golden_failures: hasGoldenFailures.toString(),
|
||||
};
|
||||
}
|
||||
|
||||
function setOutput(key: string, value: string) {
|
||||
const outputPath = process.env.GITHUB_OUTPUT;
|
||||
if (!outputPath) {
|
||||
console.warn(`GITHUB_OUTPUT not set. Skipping output for "${key}".`);
|
||||
return;
|
||||
}
|
||||
|
||||
if (value.includes('\n')) {
|
||||
const delimiter = `EOF_${key}_${Date.now()}`;
|
||||
fs.appendFileSync(outputPath, `${key}<<${delimiter}\n${value}\n${delimiter}\n`);
|
||||
} else {
|
||||
fs.appendFileSync(outputPath, `${key}=${value}\n`);
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
const combinedInput = process.argv[2]
|
||||
? process.argv[2]
|
||||
: fs.readFileSync(0, 'utf-8').trim();
|
||||
|
||||
const combined: MatrixResult[] = JSON.parse(combinedInput);
|
||||
const results = processResults(combined);
|
||||
|
||||
Object.entries(results).forEach(([key, value]) => {
|
||||
setOutput(key, value);
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('Error processing results:', error);
|
||||
process.exit(1);
|
||||
}
|
||||
@@ -14,11 +14,11 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- uses: pnpm/action-setup@7088e561eb65bb68695d245aa206f005ef30921d # v4.1.0
|
||||
- uses: pnpm/action-setup@v4
|
||||
with:
|
||||
version: 10.11.1 # Aligned with root package.json (pnpm/action-setup will helpfully error if out of sync)
|
||||
version: 9.8.0 # Aligned with root package.json (pnpm/action-setup will helpfully error if out of sync)
|
||||
|
||||
- name: Run a security audit
|
||||
run: pnpm dlx audit-ci --critical --report-type summary
|
||||
@@ -30,7 +30,7 @@ jobs:
|
||||
name: Report status
|
||||
steps:
|
||||
- name: Send notification
|
||||
uses: ravsamhq/notify-slack-action@be814b201e233b2dc673608aa46e5447c8ab13f2 # v11
|
||||
uses: ravsamhq/notify-slack-action@v2
|
||||
with:
|
||||
status: ${{ needs.audit.result }}
|
||||
message_format: '{emoji} Audit has {status_message}'
|
||||
|
||||
@@ -1,30 +0,0 @@
|
||||
name: PR Title Validation
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
types: [opened, edited, synchronize, reopened]
|
||||
|
||||
permissions: read-all
|
||||
|
||||
jobs:
|
||||
validate-pr-title:
|
||||
name: Validate PR Title
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
||||
with:
|
||||
# Ensure's validate-pr-title.js is the copy from master
|
||||
ref: master
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@a0853c24544627f65ddf259abe73b1d18a591444 # v5.0.0
|
||||
with:
|
||||
node-version: 24
|
||||
package-manager-cache: false
|
||||
|
||||
- name: Validate PR title
|
||||
env:
|
||||
PR_TITLE: ${{ github.event.pull_request.title }}
|
||||
PR_BODY: ${{ github.event.pull_request.body }}
|
||||
run: node ./scripts/validate-pr-title.js
|
||||
@@ -3,7 +3,7 @@ name: publish
|
||||
on:
|
||||
# Automated schedule - canary releases from master
|
||||
schedule:
|
||||
- cron: "0 19 * * 1-5" # Monday - Friday, at 19:00 UTC (7pm UTC)
|
||||
- cron: "0 3 * * 2-6" # Tuesdays - Saturdays, at 3am UTC
|
||||
# Manual trigger - PR releases or dry-runs (based on workflow inputs)
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
@@ -21,8 +21,8 @@ env:
|
||||
DEBUG: napi:*
|
||||
NX_RUN_GROUP: ${{ github.run_id }}-${{ github.run_attempt }}
|
||||
CYPRESS_INSTALL_BINARY: 0
|
||||
NODE_VERSION: 22.16.0
|
||||
PNPM_VERSION: 10.11.1 # Aligned with root package.json (pnpm/action-setup will helpfully error if out of sync)
|
||||
NODE_VERSION: 20.19.0
|
||||
PNPM_VERSION: 9.8.0 # Aligned with root package.json (pnpm/action-setup will helpfully error if out of sync)
|
||||
|
||||
jobs:
|
||||
# We first need to determine the version we are releasing, and if we need a custom repo or ref to use for the git checkout in subsequent steps.
|
||||
@@ -37,7 +37,7 @@ jobs:
|
||||
# ref resolution in actions/checkout. The exact version will be generated within scripts/nx-release.ts.
|
||||
#
|
||||
# - workflow_dispatch:
|
||||
# - We are either running a dry-run on the current branch, in which case the version will be static and we can use
|
||||
# - We are either running a dry-run on the current branch, in which case the version will be statica and we can use
|
||||
# default ref resolution in actions/checkout, or we are creating a PR release for the given PR number, in which case
|
||||
# we should generate an applicable version number within publish-resolve-data.js and use a custom ref of the PR branch name.
|
||||
resolve-required-data:
|
||||
@@ -51,23 +51,31 @@ jobs:
|
||||
publish_branch: ${{ steps.script.outputs.publish_branch }}
|
||||
ref: ${{ steps.script.outputs.ref }}
|
||||
repo: ${{ steps.script.outputs.repo }}
|
||||
pr_number: ${{ steps.script.outputs.pr_number }}
|
||||
pr_author: ${{ steps.script.outputs.pr_author }}
|
||||
env:
|
||||
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
|
||||
steps:
|
||||
# Default checkout on the triggering branch so that the latest publish-resolve-data.js script is available
|
||||
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
# Set up pnpm and node so that we can verify our setup and that the NPM_TOKEN secret will work later
|
||||
- uses: pnpm/action-setup@v4
|
||||
with:
|
||||
version: ${{ env.PNPM_VERSION }}
|
||||
|
||||
- name: Setup node
|
||||
uses: actions/setup-node@a0853c24544627f65ddf259abe73b1d18a591444 # v5.0.0
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: ${{ env.NODE_VERSION }}
|
||||
registry-url: 'https://registry.npmjs.org'
|
||||
check-latest: true
|
||||
package-manager-cache: false
|
||||
|
||||
# Ensure that the NPM_TOKEN secret is still valid before wasting any time deriving data or building projects
|
||||
- name: Check NPM Credentials
|
||||
run: npm whoami && echo "NPM credentials are valid" || (echo "NPM credentials are invalid or have expired." && exit 1)
|
||||
|
||||
- name: Resolve and set checkout and version data to use for release
|
||||
id: script
|
||||
uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0
|
||||
uses: actions/github-script@v7
|
||||
env:
|
||||
PR_NUMBER: ${{ github.event.inputs.pr }}
|
||||
with:
|
||||
@@ -78,7 +86,7 @@ jobs:
|
||||
|
||||
- name: (PR Release Only) Check out latest master
|
||||
if: ${{ steps.script.outputs.ref != '' }}
|
||||
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
# Check out the latest master branch to get its copy of nx-release.ts
|
||||
repository: nrwl/nx
|
||||
@@ -87,31 +95,24 @@ jobs:
|
||||
|
||||
- name: (PR Release Only) Check out PR branch
|
||||
if: ${{ steps.script.outputs.ref != '' }}
|
||||
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
# Check out the PR branch to get its copy of nx-release.ts
|
||||
repository: ${{ steps.script.outputs.repo }}
|
||||
ref: ${{ steps.script.outputs.ref }}
|
||||
path: pr-branch-checkout
|
||||
|
||||
- name: (PR Release Only) Ensure that release scripts have not changed in the PR being released
|
||||
- name: (PR Release Only) Ensure that nx-release.ts has not changed in the PR being released
|
||||
if: ${{ steps.script.outputs.ref != '' }}
|
||||
env:
|
||||
FILE_TO_COMPARE: "scripts/nx-release.ts"
|
||||
run: |
|
||||
# List of files that must not change in PR releases
|
||||
FILES_TO_CHECK=(
|
||||
"scripts/nx-release.ts"
|
||||
"scripts/publish-resolve-data.js"
|
||||
)
|
||||
|
||||
for FILE in "${FILES_TO_CHECK[@]}"; do
|
||||
if ! cmp -s "latest-master-checkout/$FILE" "pr-branch-checkout/$FILE"; then
|
||||
echo "🛑 Error: The file $FILE is different on the ${{ steps.script.outputs.ref }} branch on ${{ steps.script.outputs.repo }} vs latest master on nrwl/nx, cancelling workflow."
|
||||
echo "If you did not modify the file, then you likely just need to rebase/merge latest master."
|
||||
exit 1
|
||||
else
|
||||
echo "✅ The file $FILE is identical between the ${{ steps.script.outputs.ref }} branch on ${{ steps.script.outputs.repo }} and latest master on nrwl/nx."
|
||||
fi
|
||||
done
|
||||
if ! cmp -s "latest-master-checkout/${{ env.FILE_TO_COMPARE }}" "pr-branch-checkout/${{ env.FILE_TO_COMPARE }}"; then
|
||||
echo "🛑 Error: The file ${{ env.FILE_TO_COMPARE }} is different on the ${{ steps.script.outputs.ref }} branch on ${{ steps.script.outputs.repo }} vs latest master on nrwl/nx, cancelling workflow. If you did not modify the file, then you likely just need to rebase/merge latest master."
|
||||
exit 1
|
||||
else
|
||||
echo "✅ The file ${{ env.FILE_TO_COMPARE }} is identical between the ${{ steps.script.outputs.ref }} branch on ${{ steps.script.outputs.repo }} and latest master on nrwl/nx."
|
||||
fi
|
||||
|
||||
build:
|
||||
needs: [ resolve-required-data ]
|
||||
@@ -120,21 +121,12 @@ jobs:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
settings:
|
||||
- host: macos-latest
|
||||
- host: macos-13
|
||||
target: x86_64-apple-darwin
|
||||
setup: |-
|
||||
rustup target add x86_64-apple-darwin
|
||||
build: |
|
||||
pnpm nx run-many --target=build-native -- --target=x86_64-apple-darwin
|
||||
- host: windows-latest
|
||||
setup: |-
|
||||
choco install openjdk --version=21.0.0 -y
|
||||
rustup target add aarch64-pc-windows-msvc
|
||||
build: |
|
||||
export JAVA_HOME="C:\Program Files\OpenJDK\jdk-21"
|
||||
export PATH="$JAVA_HOME\bin:$PATH"
|
||||
java -version
|
||||
pnpm nx run-many --target=build-native -- --target=x86_64-pc-windows-msvc
|
||||
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
|
||||
@@ -144,65 +136,23 @@ jobs:
|
||||
- host: ubuntu-latest
|
||||
target: x86_64-unknown-linux-gnu
|
||||
docker: ghcr.io/napi-rs/napi-rs/nodejs-rust:lts-debian
|
||||
build: |
|
||||
set -e
|
||||
apt-get update
|
||||
|
||||
# Install Java 21
|
||||
apt-get install -y openjdk-21-jdk
|
||||
export JAVA_HOME=/usr/lib/jvm/java-21-openjdk-amd64
|
||||
export PATH="$JAVA_HOME/bin:$PATH"
|
||||
java --version
|
||||
|
||||
curl -fsSL https://deb.nodesource.com/setup_22.x | bash -
|
||||
apt-get install -y nodejs=22.16.0-1nodesource1
|
||||
|
||||
export PATH="/usr/local/bin:$PATH"
|
||||
node --version
|
||||
npm --version
|
||||
|
||||
npm i -g pnpm@${PNPM_VERSION} --force
|
||||
pnpm --version
|
||||
|
||||
pnpm install --frozen-lockfile
|
||||
rustup target add x86_64-unknown-linux-gnu
|
||||
build: |-
|
||||
set -e &&
|
||||
npm i -g pnpm@9.8.0 --force &&
|
||||
pnpm --version &&
|
||||
pnpm install --frozen-lockfile &&
|
||||
pnpm nx run-many --verbose --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: |
|
||||
bash -c "
|
||||
set -e
|
||||
echo 'https://dl-cdn.alpinelinux.org/alpine/edge/community' >> /etc/apk/repositories
|
||||
apk add --no-cache curl xz openjdk21
|
||||
|
||||
# Set up Java 21
|
||||
export JAVA_HOME=/usr/lib/jvm/java-21-openjdk
|
||||
export PATH=\"\$JAVA_HOME/bin:\$PATH\"
|
||||
java --version
|
||||
|
||||
curl -fsSL https://unofficial-builds.nodejs.org/download/release/v22.16.0/node-v22.16.0-linux-x64-musl.tar.xz -o node.tar.xz
|
||||
tar -xJf node.tar.xz
|
||||
mv node-v22.16.0-linux-x64-musl /usr/local/node
|
||||
|
||||
export PATH=\"/usr/local/node/bin:\$PATH\"
|
||||
|
||||
echo Node: \$(node -v)
|
||||
echo NPM: \$(npm -v)
|
||||
|
||||
# Install PNPM
|
||||
npm i -g pnpm@${PNPM_VERSION} --force
|
||||
pnpm --version
|
||||
|
||||
# Install deps and run native build
|
||||
pnpm install --frozen-lockfile
|
||||
rustup target add x86_64-unknown-linux-musl
|
||||
pnpm nx run-many --verbose --target=build-native -- --target=x86_64-unknown-linux-musl
|
||||
"
|
||||
- host: macos-latest
|
||||
build: |-
|
||||
set -e &&
|
||||
npm i -g pnpm@9.8.0 --force &&
|
||||
pnpm --version &&
|
||||
pnpm install --frozen-lockfile &&
|
||||
pnpm nx run-many --verbose --target=build-native -- --target=x86_64-unknown-linux-musl
|
||||
- host: macos-13
|
||||
target: aarch64-apple-darwin
|
||||
setup: |-
|
||||
rustup target add aarch64-apple-darwin
|
||||
build: |
|
||||
sudo rm -Rf /Library/Developer/CommandLineTools/SDKs/*;
|
||||
export CC=$(xcrun -f clang);
|
||||
@@ -213,35 +163,17 @@ jobs:
|
||||
- host: ubuntu-latest
|
||||
target: aarch64-unknown-linux-gnu
|
||||
docker: ghcr.io/napi-rs/napi-rs/nodejs-rust:lts-debian-aarch64
|
||||
build: |
|
||||
set -e
|
||||
apt-get update
|
||||
|
||||
# Install Java 21
|
||||
apt-get install -y openjdk-21-jdk
|
||||
export JAVA_HOME=/usr/lib/jvm/java-21-openjdk-amd64
|
||||
export PATH="$JAVA_HOME/bin:$PATH"
|
||||
java --version
|
||||
|
||||
curl -fsSL https://deb.nodesource.com/setup_22.x | bash -
|
||||
apt-get install -y nodejs=22.16.0-1nodesource1
|
||||
|
||||
export PATH="/usr/local/bin:$PATH"
|
||||
node --version
|
||||
npm --version
|
||||
|
||||
npm i -g pnpm@${PNPM_VERSION} --force
|
||||
pnpm --version
|
||||
|
||||
pnpm install --frozen-lockfile
|
||||
rustup target add aarch64-unknown-linux-gnu
|
||||
build: |-
|
||||
set -e &&
|
||||
npm i -g pnpm@9.8.0 --force &&
|
||||
pnpm --version &&
|
||||
pnpm install --frozen-lockfile &&
|
||||
pnpm nx run-many --verbose --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
|
||||
rustup target add armv7-unknown-linux-gnueabihf
|
||||
build: |
|
||||
CARGO_TARGET_ARMV7_UNKNOWN_LINUX_GNUEABIHF_LINKER=/usr/bin/arm-linux-gnueabihf-gcc pnpm nx run-many --target=build-native -- --target=armv7-unknown-linux-gnueabihf
|
||||
# Android (not needed)
|
||||
@@ -256,65 +188,44 @@ jobs:
|
||||
- host: ubuntu-latest
|
||||
target: aarch64-unknown-linux-musl
|
||||
docker: ghcr.io/napi-rs/napi-rs/nodejs-rust:lts-alpine
|
||||
build: |
|
||||
bash -c "
|
||||
set -e
|
||||
echo 'https://dl-cdn.alpinelinux.org/alpine/edge/community' >> /etc/apk/repositories
|
||||
apk add --no-cache curl xz openjdk21
|
||||
|
||||
# Set up Java 21
|
||||
export JAVA_HOME=/usr/lib/jvm/java-21-openjdk
|
||||
export PATH=\"\$JAVA_HOME/bin:\$PATH\"
|
||||
java --version
|
||||
|
||||
curl -fsSL https://unofficial-builds.nodejs.org/download/release/v22.16.0/node-v22.16.0-linux-x64-musl.tar.xz -o node.tar.xz
|
||||
tar -xJf node.tar.xz
|
||||
mv node-v22.16.0-linux-x64-musl /usr/local/node
|
||||
|
||||
export PATH=\"/usr/local/node/bin:\$PATH\"
|
||||
|
||||
echo Node: \$(node -v)
|
||||
echo NPM: \$(npm -v)
|
||||
|
||||
# Install PNPM
|
||||
npm i -g pnpm@${PNPM_VERSION} --force
|
||||
pnpm --version
|
||||
|
||||
# Install deps and run native build
|
||||
pnpm install --frozen-lockfile
|
||||
rustup target add aarch64-unknown-linux-musl
|
||||
pnpm nx run-many --verbose --target=build-native -- --target=aarch64-unknown-linux-musl
|
||||
"
|
||||
build: |-
|
||||
set -e &&
|
||||
rustup target add aarch64-unknown-linux-musl &&
|
||||
npm i -g pnpm@9.8.0 --force &&
|
||||
pnpm --version &&
|
||||
pnpm install --frozen-lockfile &&
|
||||
pnpm nx run-many --verbose --target=build-native -- --target=aarch64-unknown-linux-musl
|
||||
- host: windows-latest
|
||||
target: aarch64-pc-windows-msvc
|
||||
setup: |-
|
||||
choco install openjdk --version=21.0.0 -y
|
||||
rustup target add aarch64-pc-windows-msvc
|
||||
build: |
|
||||
export JAVA_HOME="C:\Program Files\OpenJDK\jdk-21"
|
||||
export PATH="$JAVA_HOME\bin:$PATH"
|
||||
java -version
|
||||
pnpm nx run-many --target=build-native -- --target=aarch64-pc-windows-msvc
|
||||
name: stable - ${{ matrix.settings.target }} - node@22.16.0
|
||||
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@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
repository: ${{ needs.resolve-required-data.outputs.repo || github.repository }}
|
||||
ref: ${{ needs.resolve-required-data.outputs.ref || github.ref }}
|
||||
repository: ${{ needs.resolve-required-data.outputs.repo }}
|
||||
ref: ${{ needs.resolve-required-data.outputs.ref }}
|
||||
|
||||
- name: Setup dev tools with mise
|
||||
uses: jdx/mise-action@146a28175021df8ca24f8ee1828cc2a60f980bd5 # v3
|
||||
if: ${{ !matrix.settings.docker }}
|
||||
- uses: pnpm/action-setup@v4
|
||||
with:
|
||||
version: ${{ env.PNPM_VERSION }}
|
||||
|
||||
- name: Enable corepack and install pnpm
|
||||
- name: Setup node
|
||||
uses: actions/setup-node@v4
|
||||
if: ${{ !matrix.settings.docker }}
|
||||
run: |
|
||||
corepack enable
|
||||
corepack prepare --activate
|
||||
with:
|
||||
node-version: ${{ env.NODE_VERSION }}
|
||||
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@0400d5f644dc74513175e3cd8d07132dd4860809 # v4.2.4
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: |
|
||||
~/.cargo/registry/index/
|
||||
@@ -324,7 +235,7 @@ jobs:
|
||||
target/
|
||||
key: ${{ matrix.settings.target }}-cargo-registry
|
||||
|
||||
- uses: goto-bus-stop/setup-zig@abea47f85e598557f500fa1fd2ab7464fcb39406 # v2.2.1
|
||||
- uses: goto-bus-stop/setup-zig@v2
|
||||
if: ${{ matrix.settings.target == 'armv7-unknown-linux-gnueabihf' }}
|
||||
with:
|
||||
version: 0.10.0
|
||||
@@ -345,7 +256,7 @@ jobs:
|
||||
timeout-minutes: 30
|
||||
|
||||
- name: Setup node x86
|
||||
uses: actions/setup-node@a0853c24544627f65ddf259abe73b1d18a591444 # v5.0.0
|
||||
uses: actions/setup-node@v4
|
||||
if: matrix.settings.target == 'i686-pc-windows-msvc'
|
||||
with:
|
||||
node-version: ${{ env.NODE_VERSION }}
|
||||
@@ -354,7 +265,7 @@ jobs:
|
||||
architecture: x86
|
||||
|
||||
- name: Build in docker
|
||||
uses: addnab/docker-run-action@4f65fabd2431ebc8d299f8e5a018d79a769ae185 # v3
|
||||
uses: addnab/docker-run-action@v3
|
||||
if: ${{ matrix.settings.docker }}
|
||||
with:
|
||||
image: ${{ matrix.settings.docker }}
|
||||
@@ -367,12 +278,12 @@ jobs:
|
||||
shell: bash
|
||||
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: bindings-${{ matrix.settings.target }}
|
||||
path: |
|
||||
packages/nx/src/native/*.node
|
||||
packages/nx/src/native/*.wasm
|
||||
packages/**/*.node
|
||||
packages/**/*.wasm
|
||||
if-no-files-found: error
|
||||
|
||||
build-freebsd:
|
||||
@@ -382,35 +293,30 @@ jobs:
|
||||
name: Build FreeBSD
|
||||
timeout-minutes: 45
|
||||
steps:
|
||||
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
repository: ${{ needs.resolve-required-data.outputs.repo || github.repository }}
|
||||
ref: ${{ needs.resolve-required-data.outputs.ref || github.ref }}
|
||||
repository: ${{ needs.resolve-required-data.outputs.repo }}
|
||||
ref: ${{ needs.resolve-required-data.outputs.ref }}
|
||||
|
||||
- name: Build
|
||||
id: build
|
||||
uses: cross-platform-actions/action@462ed697694d2ac9aa49e1225f395f7bb6dd49fe # v0.29.0
|
||||
uses: cross-platform-actions/action@v0.25.0
|
||||
env:
|
||||
DEBUG: napi:*
|
||||
RUSTUP_IO_THREADS: 1
|
||||
NX_PREFER_TS_NODE: true
|
||||
PLAYWRIGHT_BROWSERS_PATH: 0
|
||||
NODE_VERSION: 22.16.0
|
||||
with:
|
||||
operating_system: freebsd
|
||||
version: '14.0'
|
||||
architecture: x86-64
|
||||
environment_variables: DEBUG RUSTUP_IO_THREADS CI NX_PREFER_TS_NODE PLAYWRIGHT_BROWSERS_PATH NODE_VERSION
|
||||
environment_variables: DEBUG RUSTUP_IO_THREADS CI NX_PREFER_TS_NODE PLAYWRIGHT_BROWSERS_PATH
|
||||
shell: bash
|
||||
run: |
|
||||
env
|
||||
whoami
|
||||
sudo pkg install -y -f node libnghttp2 www/npm git openjdk17
|
||||
sudo npm install --location=global --ignore-scripts pnpm@10.11.1
|
||||
# Set up Java 17
|
||||
export JAVA_HOME=/usr/local/openjdk17
|
||||
export PATH="$JAVA_HOME/bin:$PATH"
|
||||
java --version
|
||||
sudo pkg install -y -f node libnghttp2 www/npm git
|
||||
sudo npm install --location=global --ignore-scripts pnpm@9.8.0
|
||||
curl https://sh.rustup.rs -sSf --output rustup.sh
|
||||
sh rustup.sh -y --profile minimal --default-toolchain stable
|
||||
source "$HOME/.cargo/env"
|
||||
@@ -425,59 +331,8 @@ jobs:
|
||||
whoami
|
||||
env
|
||||
freebsd-version
|
||||
echo "Installing dependencies"
|
||||
pnpm install --frozen-lockfile --ignore-scripts
|
||||
|
||||
echo "Checking disk space before cleanup"
|
||||
df -h
|
||||
echo "Removing unnecessary preinstalled packages"
|
||||
# List all packages first to see what's installed
|
||||
sudo pkg info -a
|
||||
echo "Cleaning up to free disk space"
|
||||
# Clean package caches
|
||||
sudo pkg clean -a -y
|
||||
sudo pkg autoremove -y
|
||||
# Remove unnecessary system files
|
||||
sudo rm -rf /usr/local/lib/*.a
|
||||
sudo rm -rf /usr/local/share/doc/*
|
||||
sudo rm -rf /usr/local/share/man/*
|
||||
sudo rm -rf /usr/local/share/examples/*
|
||||
sudo rm -rf /usr/local/share/locale/*
|
||||
sudo rm -rf /usr/local/share/gtk-doc/*
|
||||
sudo rm -rf /usr/local/share/info/*
|
||||
sudo rm -rf /usr/src/*
|
||||
sudo rm -rf /usr/obj/*
|
||||
sudo rm -rf /usr/tests/*
|
||||
sudo rm -rf /usr/lib/debug/*
|
||||
# Clean var directories
|
||||
sudo rm -rf /var/cache/pkg/*
|
||||
sudo rm -rf /var/db/pkg/*.tbz
|
||||
sudo rm -rf /var/log/*.log
|
||||
sudo rm -rf /var/log/*.old
|
||||
# Clean temporary files
|
||||
sudo rm -rf /tmp/*
|
||||
sudo rm -rf /var/tmp/*
|
||||
# Remove Python cache if present
|
||||
sudo find /usr/local -type d -name "__pycache__" -exec rm -rf {} + 2>/dev/null || true
|
||||
sudo find /usr/local -name "*.pyc" -delete 2>/dev/null || true
|
||||
sudo find /usr/local -name "*.pyo" -delete 2>/dev/null || true
|
||||
# Clean npm/pnpm caches
|
||||
npm cache clean --force || true
|
||||
pnpm store prune || true
|
||||
rm -rf ~/.npm || true
|
||||
rm -rf ~/.pnpm-store || true
|
||||
# Remove Rust build artifacts if any
|
||||
rm -rf ~/.cargo/registry || true
|
||||
rm -rf ~/.cargo/git || true
|
||||
rm -rf ~/.rustup/toolchains/*/share || true
|
||||
# Remove other development tool caches
|
||||
rm -rf ~/.cache/* || true
|
||||
echo "Checking disk space after cleanup"
|
||||
df -h
|
||||
|
||||
echo "Building FreeBSD bindings"
|
||||
pnpm nx run-many --verbose --outputStyle stream --target=build-native -- --target=x86_64-unknown-freebsd
|
||||
echo "Cleaning up"
|
||||
pnpm nx reset
|
||||
rm -rf node_modules
|
||||
rm -rf dist
|
||||
@@ -486,18 +341,16 @@ jobs:
|
||||
echo "COMPLETE"
|
||||
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: bindings-freebsd
|
||||
path: |
|
||||
packages/nx/src/native/*.node
|
||||
path: packages/**/*.node
|
||||
if-no-files-found: error
|
||||
|
||||
publish:
|
||||
if: ${{ github.repository_owner == 'nrwl' }}
|
||||
name: Publish
|
||||
runs-on: ubuntu-latest
|
||||
environment: npm-registry
|
||||
permissions:
|
||||
id-token: write
|
||||
contents: write
|
||||
@@ -508,28 +361,31 @@ jobs:
|
||||
- build
|
||||
env:
|
||||
GH_TOKEN: ${{ github.token }}
|
||||
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
|
||||
NPM_CONFIG_PROVENANCE: true
|
||||
steps:
|
||||
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
repository: ${{ needs.resolve-required-data.outputs.repo || github.repository }}
|
||||
ref: ${{ needs.resolve-required-data.outputs.ref || github.ref }}
|
||||
repository: ${{ needs.resolve-required-data.outputs.repo }}
|
||||
ref: ${{ needs.resolve-required-data.outputs.ref }}
|
||||
|
||||
- name: Setup dev tools with mise
|
||||
uses: jdx/mise-action@146a28175021df8ca24f8ee1828cc2a60f980bd5 # v3
|
||||
- uses: pnpm/action-setup@v4
|
||||
with:
|
||||
version: ${{ env.PNPM_VERSION }}
|
||||
|
||||
- name: Enable corepack and install pnpm
|
||||
run: |
|
||||
corepack enable
|
||||
corepack prepare --activate
|
||||
|
||||
- name: Use npm 11.5.2
|
||||
run: npm install -g npm@11.5.2
|
||||
- name: Setup node
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: ${{ env.NODE_VERSION }}
|
||||
registry-url: 'https://registry.npmjs.org'
|
||||
check-latest: true
|
||||
cache: 'pnpm'
|
||||
|
||||
- name: Install dependencies
|
||||
run: pnpm install --frozen-lockfile
|
||||
|
||||
- name: Download all artifacts
|
||||
uses: actions/download-artifact@634f93cb2916e3fdff6788551b99b062d0335ce0 # v5.0.0
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
path: artifacts
|
||||
|
||||
@@ -541,14 +397,12 @@ jobs:
|
||||
run: |
|
||||
wget https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-23/wasi-sdk-23.0-x86_64-linux.tar.gz
|
||||
tar -xvf wasi-sdk-23.0-x86_64-linux.tar.gz
|
||||
rustup toolchain install nightly-2025-05-09
|
||||
pnpm build:wasm
|
||||
- name: Publish
|
||||
env:
|
||||
VERSION: ${{ needs.resolve-required-data.outputs.version }}
|
||||
DRY_RUN: ${{ needs.resolve-required-data.outputs.dry_run_flag }}
|
||||
PUBLISH_BRANCH: ${{ needs.resolve-required-data.outputs.publish_branch }}
|
||||
NX_VERBOSE_LOGGING: true
|
||||
run: |
|
||||
echo ""
|
||||
# Create and check out the publish branch
|
||||
@@ -566,11 +420,11 @@ jobs:
|
||||
|
||||
- name: (PR Release Only) Create comment for successful PR release
|
||||
if: success() && github.event.inputs.pr
|
||||
uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0
|
||||
uses: actions/github-script@v7
|
||||
env:
|
||||
SUCCESS_COMMENT: ${{ needs.resolve-required-data.outputs.success_comment }}
|
||||
with:
|
||||
# github-token defaults to ${{ github.token }} so we don't need to specify it
|
||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
script: |
|
||||
const successComment = JSON.parse(process.env.SUCCESS_COMMENT);
|
||||
await github.rest.issues.createComment({
|
||||
@@ -580,55 +434,22 @@ jobs:
|
||||
body: successComment
|
||||
});
|
||||
|
||||
report-pending-publish:
|
||||
name: Report Pending Publish to Slack
|
||||
if: ${{ github.repository_owner == 'nrwl' }}
|
||||
needs:
|
||||
- resolve-required-data
|
||||
- build-freebsd
|
||||
- build
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 10
|
||||
continue-on-error: true # Don't fail the workflow if notification fails
|
||||
steps:
|
||||
- name: Send Slack notification
|
||||
uses: ravsamhq/notify-slack-action@be814b201e233b2dc673608aa46e5447c8ab13f2 # v11
|
||||
with:
|
||||
status: ${{ job.status }}
|
||||
notification_title: >-
|
||||
${{ needs.resolve-required-data.outputs.pr_number &&
|
||||
format('📦 PR #{0} Publish Pending Review', needs.resolve-required-data.outputs.pr_number) ||
|
||||
'📦 Publish Pending Review' }}
|
||||
message_format: >-
|
||||
${{ needs.resolve-required-data.outputs.pr_number &&
|
||||
format('Version {0} from PR #{1} by @{2} is being published to NPM - manual review is required',
|
||||
needs.resolve-required-data.outputs.version,
|
||||
needs.resolve-required-data.outputs.pr_number,
|
||||
needs.resolve-required-data.outputs.pr_author) ||
|
||||
format('Version {0} is being published to NPM - manual review is required',
|
||||
needs.resolve-required-data.outputs.version) }}
|
||||
footer: '<{run_url}|View Workflow Run>'
|
||||
mention_users: 'U9NPA6C90' # Jason
|
||||
env:
|
||||
SLACK_WEBHOOK_URL: ${{ secrets.ACTION_MONITORING_SLACK }}
|
||||
|
||||
pr_failure_comment:
|
||||
# Run this job if it is a PR release, running on the nrwl origin, and any of the required jobs failed
|
||||
if: ${{ github.repository_owner == 'nrwl' && github.event.inputs.pr && always() && contains(needs.*.result, 'failure') }}
|
||||
needs: [ resolve-required-data, build, build-freebsd, publish ]
|
||||
name: (PR Release Failure Only) Create comment for failed PR release
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
pull-requests: write
|
||||
steps:
|
||||
- name: Create comment for failed PR release
|
||||
uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0
|
||||
uses: actions/github-script@v7
|
||||
with:
|
||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
# This script is intentionally kept inline (and e.g. not generated in publish-resolve-data.js)
|
||||
# to ensure that an error within the data generation itself is not missed.
|
||||
script: |
|
||||
const message = `
|
||||
Failed to publish a PR release of this pull request, triggered by @${{ github.triggering_actor }}.
|
||||
Failed to publish a PR release of this pull request, triggered by @${{ github.triggering_actor }}.
|
||||
See the failed workflow run at: https://github.com/nrwl/nx/actions/runs/${{ github.run_id }}
|
||||
`;
|
||||
await github.rest.issues.createComment({
|
||||
@@ -637,4 +458,3 @@ jobs:
|
||||
issue_number: ${{ github.event.inputs.pr }},
|
||||
body: message
|
||||
});
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@ jobs:
|
||||
# This handles issues that need more info
|
||||
- name: stale-more-info-needed
|
||||
id: stale-more-info-needed
|
||||
uses: actions/stale@3a9db7e6a41a89f618792c92c0e97cc736e1b13f # v10.0.0
|
||||
uses: actions/stale@v9.0.0
|
||||
with:
|
||||
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
days-before-stale: 7
|
||||
@@ -37,7 +37,7 @@ jobs:
|
||||
# This handles PRs that need to be rebased
|
||||
- name: stale-needs-rebase
|
||||
id: stale-needs-rebase
|
||||
uses: actions/stale@3a9db7e6a41a89f618792c92c0e97cc736e1b13f # v10.0.0
|
||||
uses: actions/stale@v9.0.0
|
||||
with:
|
||||
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
days-before-stale: 7
|
||||
@@ -56,7 +56,7 @@ jobs:
|
||||
# This handles issues that do not have a repro
|
||||
- name: stale-repro-needed
|
||||
id: stale-repro-needed
|
||||
uses: actions/stale@3a9db7e6a41a89f618792c92c0e97cc736e1b13f # v10.0.0
|
||||
uses: actions/stale@v9.0.0
|
||||
with:
|
||||
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
days-before-stale: 7
|
||||
@@ -75,7 +75,7 @@ jobs:
|
||||
|
||||
- name: stale-retry-with-latest
|
||||
id: stale-retry-with-latest
|
||||
uses: actions/stale@3a9db7e6a41a89f618792c92c0e97cc736e1b13f # v10.0.0
|
||||
uses: actions/stale@v9.0.0
|
||||
with:
|
||||
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
days-before-stale: 7
|
||||
@@ -95,7 +95,7 @@ jobs:
|
||||
# This handles issues are really old and were made with a previous major
|
||||
- name: stale-bug
|
||||
id: stale-bug
|
||||
uses: actions/stale@3a9db7e6a41a89f618792c92c0e97cc736e1b13f # v10.0.0
|
||||
uses: actions/stale@v9.0.0
|
||||
with:
|
||||
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
days-before-stale: 180
|
||||
|
||||
@@ -2,8 +2,8 @@ node_modules
|
||||
/.idea
|
||||
/.fleet
|
||||
/.vscode
|
||||
/.cursor
|
||||
dist
|
||||
out-tsc
|
||||
/build
|
||||
/coverage
|
||||
./test
|
||||
@@ -13,8 +13,7 @@ tmp
|
||||
jest.debug.config.js
|
||||
.tool-versions
|
||||
/.nx-cache
|
||||
/.nx/cache
|
||||
/.nx/workspace-data
|
||||
/.nx
|
||||
/.verdaccio/build/local-registry
|
||||
/graph/client/src/assets/environment.js
|
||||
/graph/client/src/assets/dev/environment.js
|
||||
@@ -37,7 +36,6 @@ CHANGELOG.md
|
||||
.next
|
||||
out
|
||||
|
||||
|
||||
# Angular Cache
|
||||
.angular
|
||||
|
||||
@@ -52,6 +50,8 @@ out
|
||||
|
||||
# Fix for issue when working on the repo in a dev container
|
||||
.pnpm-store
|
||||
.nx
|
||||
!.nx/workflows
|
||||
|
||||
.cargo/.package-cache
|
||||
.cargo/bin/
|
||||
@@ -62,8 +62,6 @@ out
|
||||
.profile
|
||||
.rustup/
|
||||
target
|
||||
.flattened-pom.xml
|
||||
dependency-reduced-pom.xml
|
||||
*.wasm
|
||||
/wasi-sdk*
|
||||
|
||||
@@ -74,62 +72,3 @@ storybook-static
|
||||
# Ignore Gradle project-specific cache directory
|
||||
.gradle
|
||||
.kotlin
|
||||
|
||||
.claude/settings.local.json
|
||||
CLAUDE.local.md
|
||||
|
||||
.cursor/mcp.json
|
||||
|
||||
# Added by Claude Task Master
|
||||
# Logs
|
||||
logs
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
dev-debug.log
|
||||
# Dependency directories
|
||||
node_modules/
|
||||
# Environment variables
|
||||
.env
|
||||
!e2e/dotnet/.env
|
||||
# Editor directories and files
|
||||
.idea
|
||||
.vscode
|
||||
*.suo
|
||||
*.ntvs*
|
||||
*.njsproj
|
||||
*.sln
|
||||
*.sw?
|
||||
.specstory/**
|
||||
.cursorindexingignore
|
||||
# OS specific
|
||||
# Task files
|
||||
/tasks.json
|
||||
/tasks
|
||||
|
||||
# Upstream docs local configuration (machine-specific)
|
||||
.upstreamdocs.local.json
|
||||
|
||||
astro-docs/.netlify
|
||||
|
||||
coverage
|
||||
|
||||
# Angular Rspack Specific Options
|
||||
packages/angular-rspack/coverage
|
||||
packages/angular-rspack-compiler/coverage
|
||||
|
||||
# Some Packages use a template to generate the correct README
|
||||
packages/angular-rspack/README.md
|
||||
packages/angular-rspack-compiler/README.md
|
||||
packages/dotnet/README.md
|
||||
packages/maven/README.md
|
||||
|
||||
test-output
|
||||
test-results
|
||||
|
||||
# TypeScript build info files
|
||||
*.tsbuildinfo
|
||||
|
||||
# .NET build output
|
||||
/packages/dotnet/analyzer/bin
|
||||
/packages/dotnet/analyzer/obj
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
node ./scripts/commit-lint.js "$1"
|
||||
@@ -1,12 +1,2 @@
|
||||
# Skip if this is a worktree creation (previous ref is null)
|
||||
if [ "$1" = "0000000000000000000000000000000000000000" ]; then
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Skip if this is a file checkout (not branch switch) - $3 would be 0
|
||||
if [ "$3" = "0" ]; then
|
||||
exit 0
|
||||
fi
|
||||
|
||||
changedFiles="$(git diff-tree -r --name-only --no-commit-id $1 $2)"
|
||||
node ./scripts/notify-lockfile-changes.js $changedFiles
|
||||
node ./scripts/notify-lockfile-changes.js $changedFiles
|
||||
|
||||
@@ -1 +1,5 @@
|
||||
pnpm nx prepush --parallel 8 --tuiAutoExit 0
|
||||
pnpm check-lock-files
|
||||
pnpm check-commit
|
||||
pnpm documentation
|
||||
pnpm pretty-quick --check
|
||||
pnpm nx format-native nx
|
||||
@@ -1 +0,0 @@
|
||||
NX_USE_V8_SERIALIZER=false
|
||||
@@ -1,9 +0,0 @@
|
||||
{
|
||||
"mcpServers": {
|
||||
"nx-mcp": {
|
||||
"type": "stdio",
|
||||
"command": "npx",
|
||||
"args": ["nx", "mcp"]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
wrapperVersion=3.3.4
|
||||
distributionType=only-script
|
||||
distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/4.0.0-rc-5/apache-maven-4.0.0-rc-5-bin.zip
|
||||
@@ -1,76 +1,150 @@
|
||||
common-env-vars: &common-env-vars
|
||||
GIT_AUTHOR_EMAIL: test@test.com
|
||||
GIT_AUTHOR_NAME: Test
|
||||
GIT_COMMITTER_EMAIL: test@test.com
|
||||
GIT_COMMITTER_NAME: Test
|
||||
SELECTED_PM: 'pnpm'
|
||||
NX_NATIVE_LOGGING: 'nx::native::db'
|
||||
# These are need for build and link validation for next.js and astro apps
|
||||
NEXT_PUBLIC_ASTRO_URL: 'https://master--nx-docs.netlify.app'
|
||||
NX_DEV_URL: 'https://canary.nx.dev'
|
||||
|
||||
common-init-steps: &common-init-steps
|
||||
- name: Checkout
|
||||
uses: 'nrwl/nx-cloud-workflows/v5/workflow-steps/checkout/main.yaml'
|
||||
|
||||
- name: Cache restore
|
||||
uses: 'nrwl/nx-cloud-workflows/v5/workflow-steps/cache/main.yaml'
|
||||
inputs:
|
||||
key: 'pnpm-lock.yaml'
|
||||
paths: ~/.local/share/pnpm/store
|
||||
base-branch: 'master'
|
||||
|
||||
# reads mise.toml and installs toolchains needed for repo
|
||||
- name: Setup toolchains
|
||||
uses: 'nrwl/nx-cloud-workflows/v5/workflow-steps/install-mise/main.yaml'
|
||||
|
||||
- name: Verify toolchain versions
|
||||
script: |
|
||||
echo "mise: $(mise --version)"
|
||||
echo "node: $(node --version)"
|
||||
echo "pnpm: $(pnpm --version)"
|
||||
echo "bun: $(bun --version)"
|
||||
echo "rust: $(rustc --version) - $(cargo --version)"
|
||||
echo "dotnet: $(dotnet --version)"
|
||||
echo "java: $(javac --version)"
|
||||
|
||||
- name: Install system deps
|
||||
script: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y ca-certificates lsof libvips-dev libglib2.0-dev libgirepository1.0-dev zip unzip
|
||||
|
||||
- name: Pnpm Install from lockfile
|
||||
script: |
|
||||
pnpm install --frozen-lockfile
|
||||
|
||||
- name: Install browsers
|
||||
script: |
|
||||
pnpm exec cypress install
|
||||
pnpm exec playwright install --with-deps
|
||||
|
||||
- name: Install rust deps
|
||||
script: |
|
||||
cargo fetch
|
||||
|
||||
- name: Setup gradle
|
||||
script: |
|
||||
./gradlew wrapper
|
||||
./gradlew --version
|
||||
|
||||
- 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"
|
||||
|
||||
launch-templates:
|
||||
linux-large:
|
||||
resource-class: 'docker_linux_amd64/large'
|
||||
linux-medium:
|
||||
resource-class: 'docker_linux_amd64/medium+'
|
||||
image: 'us-east1-docker.pkg.dev/nxcloudoperations/nx-cloud/nx-agents-base-images:ubuntu22.04-node20.19-v1'
|
||||
env: *common-env-vars
|
||||
init-steps: *common-init-steps
|
||||
env:
|
||||
GIT_AUTHOR_EMAIL: test@test.com
|
||||
GIT_AUTHOR_NAME: Test
|
||||
GIT_COMMITTER_EMAIL: test@test.com
|
||||
GIT_COMMITTER_NAME: Test
|
||||
SELECTED_PM: 'pnpm'
|
||||
|
||||
NX_NATIVE_LOGGING: 'nx::native::db'
|
||||
init-steps:
|
||||
- name: Checkout
|
||||
uses: 'nrwl/nx-cloud-workflows/v5/workflow-steps/checkout/main.yaml'
|
||||
|
||||
- name: Check Node Version
|
||||
script: node --version
|
||||
|
||||
- name: Cache restore
|
||||
uses: 'nrwl/nx-cloud-workflows/v5/workflow-steps/cache/main.yaml'
|
||||
inputs:
|
||||
key: 'pnpm-lock.yaml'
|
||||
paths: .pnpm-store
|
||||
base-branch: 'master'
|
||||
|
||||
- name: Install zip and unzip
|
||||
script: sudo apt-get -yqq install zip unzip
|
||||
|
||||
- name: Install bun
|
||||
script: |
|
||||
curl -fsSL https://bun.sh/install | bash
|
||||
echo "BUN_INSTALL=$HOME/.bun" >> $NX_CLOUD_ENV
|
||||
echo "PATH=$HOME/.bun/bin:$PATH" >> $NX_CLOUD_ENV
|
||||
|
||||
- name: Check bun
|
||||
script: |
|
||||
bun --version
|
||||
|
||||
- name: Install e2e deps
|
||||
script: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y ca-certificates lsof libvips-dev libglib2.0-dev libgirepository1.0-dev
|
||||
|
||||
- name: Pnpm Install from lockfile
|
||||
script: |
|
||||
pnpm install --frozen-lockfile
|
||||
|
||||
- name: Install Browsers
|
||||
script: |
|
||||
pnpm exec cypress install
|
||||
pnpm exec playwright install --with-deps
|
||||
|
||||
- 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: Setup Java 17
|
||||
script: |
|
||||
sudo apt update
|
||||
sudo apt install -y openjdk-17-jdk
|
||||
sudo update-alternatives --set java /usr/lib/jvm/java-17-openjdk-amd64/bin/java
|
||||
java -version
|
||||
|
||||
- name: Setup Gradle
|
||||
script: |
|
||||
./gradlew wrapper
|
||||
./gradlew --version
|
||||
|
||||
linux-extra-large:
|
||||
resource-class: 'docker_linux_amd64/extra_large'
|
||||
image: 'us-east1-docker.pkg.dev/nxcloudoperations/nx-cloud/nx-agents-base-images:ubuntu22.04-node20.19-v1'
|
||||
env: *common-env-vars
|
||||
init-steps: *common-init-steps
|
||||
env:
|
||||
GIT_AUTHOR_EMAIL: test@test.com
|
||||
GIT_AUTHOR_NAME: Test
|
||||
GIT_COMMITTER_EMAIL: test@test.com
|
||||
GIT_COMMITTER_NAME: Test
|
||||
SELECTED_PM: 'pnpm'
|
||||
NX_NATIVE_LOGGING: 'nx::native::db'
|
||||
init-steps:
|
||||
- name: Checkout
|
||||
uses: 'nrwl/nx-cloud-workflows/v5/workflow-steps/checkout/main.yaml'
|
||||
|
||||
- name: Check Node Version
|
||||
script: node --version
|
||||
|
||||
- name: Cache restore
|
||||
uses: 'nrwl/nx-cloud-workflows/v5/workflow-steps/cache/main.yaml'
|
||||
inputs:
|
||||
key: 'pnpm-lock.yaml'
|
||||
paths: .pnpm-store
|
||||
base-branch: 'master'
|
||||
|
||||
- name: Install zip and unzip
|
||||
script: sudo apt-get -yqq install zip unzip
|
||||
|
||||
- name: Install bun
|
||||
script: |
|
||||
curl -fsSL https://bun.sh/install | bash
|
||||
echo "BUN_INSTALL=$HOME/.bun" >> $NX_CLOUD_ENV
|
||||
echo "PATH=$HOME/.bun/bin:$PATH" >> $NX_CLOUD_ENV
|
||||
|
||||
- name: Check bun
|
||||
script: |
|
||||
bun --version
|
||||
|
||||
- name: Install e2e deps
|
||||
script: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y ca-certificates lsof libvips-dev libglib2.0-dev libgirepository1.0-dev
|
||||
|
||||
- name: Pnpm Install from lockfile
|
||||
script: |
|
||||
pnpm install --frozen-lockfile
|
||||
|
||||
- name: Install Browsers
|
||||
script: |
|
||||
pnpm exec cypress install
|
||||
pnpm exec playwright install --with-deps
|
||||
|
||||
- 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: Setup Java 21
|
||||
script: |
|
||||
sudo apt update
|
||||
sudo apt install -y openjdk-21-jdk
|
||||
sudo update-alternatives --set java /usr/lib/jvm/java-21-openjdk-amd64/bin/java
|
||||
java -version
|
||||
|
||||
@@ -1,61 +1,14 @@
|
||||
distribute-on:
|
||||
default: auto linux-large, 3 linux-extra-large
|
||||
default: auto linux-medium, 1 linux-extra-large
|
||||
assignment-rules:
|
||||
- projects:
|
||||
- e2e-gradle
|
||||
targets:
|
||||
- e2e-ci**
|
||||
run-on:
|
||||
- agent: linux-extra-large
|
||||
parallelism: 1
|
||||
|
||||
- projects:
|
||||
- nx
|
||||
- workspace
|
||||
- remix
|
||||
- nx-maven-plugin
|
||||
targets:
|
||||
- install
|
||||
- test
|
||||
run-on:
|
||||
- agent: linux-large
|
||||
parallelism: 1
|
||||
- agent: linux-extra-large
|
||||
parallelism: 1
|
||||
|
||||
- projects:
|
||||
- e2e-release
|
||||
- e2e-angular
|
||||
- e2e-react
|
||||
- e2e-next
|
||||
- e2e-web
|
||||
- e2e-eslint
|
||||
- e2e-remix
|
||||
- e2e-cypress
|
||||
- e2e-docker
|
||||
- e2e-js
|
||||
- e2e-nx-init
|
||||
- e2e-dotnet
|
||||
- e2e-workspace-create
|
||||
- e2e-rollup
|
||||
targets:
|
||||
- e2e-ci**
|
||||
run-on:
|
||||
- agent: linux-large
|
||||
parallelism: 1
|
||||
- agent: linux-extra-large
|
||||
parallelism: 1
|
||||
|
||||
# All other e2e tests can run in parallel
|
||||
- targets:
|
||||
- e2e-ci**
|
||||
run-on:
|
||||
- agent: linux-large
|
||||
parallelism: 2
|
||||
- agent: linux-medium
|
||||
parallelism: 1
|
||||
- agent: linux-extra-large
|
||||
parallelism: 3
|
||||
parallelism: 1
|
||||
|
||||
# These projects should not need to be isolated.
|
||||
- projects:
|
||||
- nx-dev
|
||||
targets:
|
||||
@@ -63,27 +16,17 @@ assignment-rules:
|
||||
run-on:
|
||||
- agent: linux-extra-large
|
||||
parallelism: 1
|
||||
- projects:
|
||||
- angular
|
||||
- react
|
||||
targets:
|
||||
- test
|
||||
run-on:
|
||||
- agent: linux-extra-large
|
||||
parallelism: 1
|
||||
|
||||
- targets:
|
||||
- lint
|
||||
run-on:
|
||||
- agent: linux-large
|
||||
parallelism: 6
|
||||
- agent: linux-extra-large
|
||||
- agent: linux-medium
|
||||
parallelism: 6
|
||||
|
||||
- targets:
|
||||
- "*"
|
||||
- '*'
|
||||
run-on:
|
||||
- agent: linux-large
|
||||
- agent: linux-medium
|
||||
parallelism: 3
|
||||
- agent: linux-extra-large
|
||||
parallelism: 3
|
||||
|
||||
@@ -1,13 +0,0 @@
|
||||
# Enable pre/post-install which are disabled by default. Installing peer deps which is also disabled by default
|
||||
auto-install-peers=true
|
||||
enable-pre-post-scripts=true
|
||||
|
||||
# Enable lifecycle scripts for specific packages that require them (like post-install)
|
||||
enable-scripts=@napi-rs/canvas,sharp,@swc/core,@swc/cli,@swc-node/register,esbuild
|
||||
|
||||
# Compatibility
|
||||
strict-peer-dependencies=false
|
||||
lockfile-version-strict=false
|
||||
|
||||
# Consistency across environments
|
||||
use-node-version=20.19.0
|
||||
@@ -51,6 +51,3 @@ CODEOWNERS
|
||||
/.nx/workflows/dynamic-changesets.yaml
|
||||
_files
|
||||
_solution
|
||||
|
||||
# this file uses TS import attributes which the current prettier version does not support
|
||||
tools/documentation/create-embeddings/src/main.mts
|
||||
|
||||
@@ -1,14 +1,5 @@
|
||||
{
|
||||
"singleQuote": true,
|
||||
"endOfLine": "lf",
|
||||
"trailingComma": "es5",
|
||||
"plugins": ["prettier-plugin-tailwindcss"],
|
||||
"overrides": [
|
||||
{
|
||||
"files": "*.mdoc",
|
||||
"options": {
|
||||
"parser": "markdown"
|
||||
}
|
||||
}
|
||||
]
|
||||
"plugins": ["prettier-plugin-tailwindcss"]
|
||||
}
|
||||
|
||||
@@ -1,10 +0,0 @@
|
||||
{
|
||||
"include": ["apps/**/*", "libs/**/*", "packages/**/*"],
|
||||
"exclude": [
|
||||
"**/*.spec.*",
|
||||
"**/test/**/*",
|
||||
"**/__tests__/**/*",
|
||||
"**/*.test.*",
|
||||
"node_modules/**/*"
|
||||
]
|
||||
}
|
||||
@@ -5,7 +5,7 @@ auth:
|
||||
htpasswd:
|
||||
file: ./htpasswd
|
||||
|
||||
max_body_size: 20mb
|
||||
max_body_size: 15mb
|
||||
|
||||
# a list of other known repositories we can talk to
|
||||
uplinks:
|
||||
|
||||
@@ -1,223 +0,0 @@
|
||||
When responding to queries about this repository:
|
||||
|
||||
1. Suggest relevant commands from the "Essential Commands" section when applicable
|
||||
2. Highlight Nx's focus on monorepos and its key features like smart task execution, code generation, and project graph
|
||||
analysis
|
||||
3. Mention the plugin ecosystem and support for various frameworks when relevant
|
||||
4. Emphasize the importance of running the full validation suite before committing changes
|
||||
|
||||
Always strive to provide accurate, helpful responses that align with the best practices and workflows described in this
|
||||
file.
|
||||
|
||||
## Documentation Contributions
|
||||
|
||||
When working on Nx documentation, all documentation content lives in the `astro-docs/` folder. This is the new Astro-based documentation site built with Starlight.
|
||||
|
||||
**Important**: Before making any documentation changes, read the `astro-docs/README.md` file for detailed guidance on:
|
||||
|
||||
- Project structure and architecture
|
||||
- Content types (regular docs, dynamic plugin docs, CLI docs)
|
||||
- Available Markdoc tags for rich content
|
||||
- Development workflow and commands
|
||||
- Sidebar management
|
||||
|
||||
### Quick Reference
|
||||
|
||||
- Documentation content: `astro-docs/src/content/docs/`
|
||||
- Use `.mdoc` (Markdoc) or `.mdx` format for documentation files
|
||||
- Run `nx serve astro-docs` to start the local dev server
|
||||
- Sidebar structure is defined in `astro-docs/sidebar.mts`
|
||||
|
||||
## GitHub Issue Response Mode
|
||||
|
||||
When responding to GitHub issues, determine your approach based on how the request is phrased:
|
||||
|
||||
### Plan-First Mode (Default)
|
||||
|
||||
Use this approach when users ask you to:
|
||||
|
||||
- "analyze", "investigate", "assess", "review", "examine", or "plan"
|
||||
- Or when the request is ambiguous
|
||||
|
||||
In this mode:
|
||||
|
||||
1. Provide a detailed analysis of the issue
|
||||
2. Create a comprehensive implementation plan
|
||||
3. Break down the solution into clear steps
|
||||
4. Then please post the plan as a comment on the issue
|
||||
|
||||
### Immediate Implementation Mode
|
||||
|
||||
Use this approach when users ask you to:
|
||||
|
||||
- "fix", "implement", "solve", "build", "create", "update", or "add"
|
||||
- Or when they explicitly request immediate action
|
||||
|
||||
In this mode:
|
||||
|
||||
1. Analyze the issue quickly
|
||||
2. Implement the complete solution immediately
|
||||
3. Make all necessary code changes. Please make multiple commits so that the changes are easier to review.
|
||||
4. Run appropriate tests and validation
|
||||
5. If the tests, are not passing, please fix the issues and continue doing this up to 3 more times until the tests pass
|
||||
6. Once the tests pass, push a branch and then suggest opening a PR which has a description of the changes made, and
|
||||
that
|
||||
it make sure that it explicitly says "Fixes #ISSUE_NUMBER" to automatically close the issue when the PR is merged.
|
||||
|
||||
## Avoid making changes to generated files
|
||||
|
||||
Files under `generated` directories are generated based on a different source file and should not be modified directly.
|
||||
Find the underlying source and modify that instead.
|
||||
|
||||
## Essential Commands
|
||||
|
||||
### Code Formatting
|
||||
|
||||
After code changes are made, please make sure to format the files with prettier via `npx prettier -- FILE_NAME`
|
||||
|
||||
### Pre-push Validation
|
||||
|
||||
```bash
|
||||
# Full validation suite - run before committing
|
||||
nx prepush
|
||||
```
|
||||
|
||||
If the prepush validation suite fails, please fix the issues before proceeding with your work. This ensures that all
|
||||
code adheres to the project's standards and passes all tests. DO NOT make a new commit to fix these issues. Instead,
|
||||
amend the current commit.
|
||||
|
||||
### Testing Changes
|
||||
|
||||
After code changes are made, first test the specific project where the changes were made:
|
||||
|
||||
```bash
|
||||
nx run-many -t test,build,lint -p PROJECT_NAME
|
||||
```
|
||||
|
||||
After verifying the individual project, validate that the changes in projects which have been affected:
|
||||
|
||||
```bash
|
||||
# Test only affected projects (recommended for development)
|
||||
nx affected -t build,test,lint
|
||||
```
|
||||
|
||||
As the last step, run the e2e tests to fully ensure that changes are valid:
|
||||
|
||||
```bash
|
||||
# Run affected e2e tests (recommended for development)
|
||||
nx affected -t e2e-local
|
||||
```
|
||||
|
||||
## Fixing GitHub Issues
|
||||
|
||||
When working on a GitHub issue, follow this systematic approach:
|
||||
|
||||
### 1. Get Issue Details
|
||||
|
||||
```bash
|
||||
# Get issue details using GitHub CLI (replace ISSUE_NUMBER with actual number)
|
||||
gh issue view ISSUE_NUMBER
|
||||
|
||||
# View multiple issues efficiently in one command
|
||||
gh issue list --limit 50 --json number,title,state,labels,assignees,updatedAt,body --jq '.[] | select(.number == 123 or .number == 456 or .number == 789)'
|
||||
|
||||
# Or filter by specific criteria to get multiple related issues
|
||||
gh issue list --label "bug" --state "open" --json number,title,body,labels --jq '.[]'
|
||||
gh issue list --assignee "@me" --json number,title,body,state --jq '.[]'
|
||||
```
|
||||
|
||||
**Tip**: Instead of running `gh issue view` multiple times, use `gh issue list` with JSON output and filtering to gather
|
||||
information about multiple issues in a single command. This is much more efficient than viewing issues one at a time.
|
||||
|
||||
**Always provide clickable links**: When discussing GitHub issues or PRs, always include the full GitHub URL so the user
|
||||
can easily open them in their browser. For example:
|
||||
|
||||
- Issue #12345: https://github.com/nrwl/nx/issues/12345
|
||||
- PR #67890: https://github.com/nrwl/nx/pull/67890
|
||||
|
||||
When cloning reproduction repos, please clone within `./tmp/claude/repro-ISSUE_NUMBER`
|
||||
|
||||
### 2. Analyze the Plan
|
||||
|
||||
- Look for a plan or implementation details in the issue description
|
||||
- Check comments for additional context or clarification
|
||||
- Identify affected projects and components
|
||||
|
||||
### 3. Implement the Solution
|
||||
|
||||
- Follow the plan outlined in the issue
|
||||
- Make focused changes that address the specific problem
|
||||
- Ensure code follows existing patterns and conventions
|
||||
|
||||
### 4. Run Full Validation
|
||||
|
||||
Use the testing workflow from the "Essential Commands" section.
|
||||
|
||||
### 5. Submit Pull Request
|
||||
|
||||
- Create a descriptive PR title that references the issue
|
||||
- **Always fill in the PR template** - don't leave it empty
|
||||
- Include "Fixes #ISSUE_NUMBER" in the PR description
|
||||
- Provide a clear summary of changes made
|
||||
- Request appropriate reviewers
|
||||
|
||||
## Pull Request Template
|
||||
|
||||
**IMPORTANT**: When creating a pull request, you MUST fill in the template found in `.github/PULL_REQUEST_TEMPLATE.md`.
|
||||
Do not leave the template sections empty. The template includes:
|
||||
|
||||
### Required Sections
|
||||
|
||||
1. **Current Behavior**: Describe the behavior we have today
|
||||
2. **Expected Behavior**: Describe the behavior we should expect with the changes in this PR
|
||||
3. **Related Issue(s)**: Link the issue being fixed so it gets closed when the PR is merged
|
||||
|
||||
### Template Format
|
||||
|
||||
```markdown
|
||||
## Current Behavior
|
||||
|
||||
<!-- This is the behavior we have today -->
|
||||
|
||||
## Expected Behavior
|
||||
|
||||
<!-- This is the behavior we should expect with the changes in this PR -->
|
||||
|
||||
## Related Issue(s)
|
||||
|
||||
<!-- Please link the issue being fixed so it gets closed when this is merged. -->
|
||||
|
||||
Fixes #ISSUE_NUMBER
|
||||
```
|
||||
|
||||
### Guidelines
|
||||
|
||||
- Ensure your commit message follows the conventional commit format (use `pnpm commit`)
|
||||
- Use `fix:`, `feat:`, `chore:`, etc. as appropriate types.
|
||||
- Scope is **required** for all commits. Possible scopes are listed in `scripts/commitizen.js`.
|
||||
- Read the submission guidelines in CONTRIBUTING.md before posting
|
||||
- For complex changes, you can request a dedicated Nx release by mentioning the Nx team
|
||||
- Always link the related issue using "Fixes #ISSUE_NUMBER" to automatically close it when merged
|
||||
|
||||
<!-- nx configuration start-->
|
||||
<!-- Leave the start & end comments to automatically receive updates. -->
|
||||
|
||||
# General Guidelines for working with Nx
|
||||
|
||||
- When running tasks (for example build, lint, test, e2e, etc.), always prefer running the task through `nx` (i.e. `nx run`, `nx run-many`, `nx affected`) instead of using the underlying tooling directly
|
||||
- You have access to the Nx MCP server and its tools, use them to help the user
|
||||
- When answering questions about the repository, use the `nx_workspace` tool first to gain an understanding of the workspace architecture where applicable.
|
||||
- When working in individual projects, use the `nx_project_details` mcp tool to analyze and understand the specific project structure and dependencies
|
||||
- For questions around nx configuration, best practices or if you're unsure, use the `nx_docs` tool to get relevant, up-to-date docs. Always use this instead of assuming things about nx configuration
|
||||
- If the user needs help with an Nx configuration or project graph error, use the `nx_workspace` tool to get any errors
|
||||
|
||||
# CI Error Guidelines
|
||||
|
||||
If the user wants help with fixing an error in their CI pipeline, use the following flow:
|
||||
|
||||
- Retrieve the list of current CI Pipeline Executions (CIPEs) using the `nx_cloud_cipe_details` tool
|
||||
- If there are any errors, use the `nx_cloud_fix_cipe_failure` tool to retrieve the logs for a specific task
|
||||
- Use the task logs to see what's wrong and help the user fix their problem. Use the appropriate tools if necessary
|
||||
- Make sure that the problem is fixed by running the task that you passed into the `nx_cloud_fix_cipe_failure` tool
|
||||
|
||||
<!-- nx configuration end-->
|
||||
@@ -1,223 +0,0 @@
|
||||
When responding to queries about this repository:
|
||||
|
||||
1. Suggest relevant commands from the "Essential Commands" section when applicable
|
||||
2. Highlight Nx's focus on monorepos and its key features like smart task execution, code generation, and project graph
|
||||
analysis
|
||||
3. Mention the plugin ecosystem and support for various frameworks when relevant
|
||||
4. Emphasize the importance of running the full validation suite before committing changes
|
||||
|
||||
Always strive to provide accurate, helpful responses that align with the best practices and workflows described in this
|
||||
file.
|
||||
|
||||
## Documentation Contributions
|
||||
|
||||
When working on Nx documentation, all documentation content lives in the `astro-docs/` folder. This is the new Astro-based documentation site built with Starlight.
|
||||
|
||||
**Important**: Before making any documentation changes, read the `astro-docs/README.md` file for detailed guidance on:
|
||||
|
||||
- Project structure and architecture
|
||||
- Content types (regular docs, dynamic plugin docs, CLI docs)
|
||||
- Available Markdoc tags for rich content
|
||||
- Development workflow and commands
|
||||
- Sidebar management
|
||||
|
||||
### Quick Reference
|
||||
|
||||
- Documentation content: `astro-docs/src/content/docs/`
|
||||
- Use `.mdoc` (Markdoc) or `.mdx` format for documentation files
|
||||
- Run `nx serve astro-docs` to start the local dev server
|
||||
- Sidebar structure is defined in `astro-docs/sidebar.mts`
|
||||
|
||||
## GitHub Issue Response Mode
|
||||
|
||||
When responding to GitHub issues, determine your approach based on how the request is phrased:
|
||||
|
||||
### Plan-First Mode (Default)
|
||||
|
||||
Use this approach when users ask you to:
|
||||
|
||||
- "analyze", "investigate", "assess", "review", "examine", or "plan"
|
||||
- Or when the request is ambiguous
|
||||
|
||||
In this mode:
|
||||
|
||||
1. Provide a detailed analysis of the issue
|
||||
2. Create a comprehensive implementation plan
|
||||
3. Break down the solution into clear steps
|
||||
4. Then please post the plan as a comment on the issue
|
||||
|
||||
### Immediate Implementation Mode
|
||||
|
||||
Use this approach when users ask you to:
|
||||
|
||||
- "fix", "implement", "solve", "build", "create", "update", or "add"
|
||||
- Or when they explicitly request immediate action
|
||||
|
||||
In this mode:
|
||||
|
||||
1. Analyze the issue quickly
|
||||
2. Implement the complete solution immediately
|
||||
3. Make all necessary code changes. Please make multiple commits so that the changes are easier to review.
|
||||
4. Run appropriate tests and validation
|
||||
5. If the tests, are not passing, please fix the issues and continue doing this up to 3 more times until the tests pass
|
||||
6. Once the tests pass, push a branch and then suggest opening a PR which has a description of the changes made, and
|
||||
that
|
||||
it make sure that it explicitly says "Fixes #ISSUE_NUMBER" to automatically close the issue when the PR is merged.
|
||||
|
||||
## Avoid making changes to generated files
|
||||
|
||||
Files under `generated` directories are generated based on a different source file and should not be modified directly.
|
||||
Find the underlying source and modify that instead.
|
||||
|
||||
## Essential Commands
|
||||
|
||||
### Code Formatting
|
||||
|
||||
After code changes are made, please make sure to format the files with prettier via `npx prettier -- FILE_NAME`
|
||||
|
||||
### Pre-push Validation
|
||||
|
||||
```bash
|
||||
# Full validation suite - run before committing
|
||||
nx prepush
|
||||
```
|
||||
|
||||
If the prepush validation suite fails, please fix the issues before proceeding with your work. This ensures that all
|
||||
code adheres to the project's standards and passes all tests. DO NOT make a new commit to fix these issues. Instead,
|
||||
amend the current commit.
|
||||
|
||||
### Testing Changes
|
||||
|
||||
After code changes are made, first test the specific project where the changes were made:
|
||||
|
||||
```bash
|
||||
nx run-many -t test,build,lint -p PROJECT_NAME
|
||||
```
|
||||
|
||||
After verifying the individual project, validate that the changes in projects which have been affected:
|
||||
|
||||
```bash
|
||||
# Test only affected projects (recommended for development)
|
||||
nx affected -t build,test,lint
|
||||
```
|
||||
|
||||
As the last step, run the e2e tests to fully ensure that changes are valid:
|
||||
|
||||
```bash
|
||||
# Run affected e2e tests (recommended for development)
|
||||
nx affected -t e2e-local
|
||||
```
|
||||
|
||||
## Fixing GitHub Issues
|
||||
|
||||
When working on a GitHub issue, follow this systematic approach:
|
||||
|
||||
### 1. Get Issue Details
|
||||
|
||||
```bash
|
||||
# Get issue details using GitHub CLI (replace ISSUE_NUMBER with actual number)
|
||||
gh issue view ISSUE_NUMBER
|
||||
|
||||
# View multiple issues efficiently in one command
|
||||
gh issue list --limit 50 --json number,title,state,labels,assignees,updatedAt,body --jq '.[] | select(.number == 123 or .number == 456 or .number == 789)'
|
||||
|
||||
# Or filter by specific criteria to get multiple related issues
|
||||
gh issue list --label "bug" --state "open" --json number,title,body,labels --jq '.[]'
|
||||
gh issue list --assignee "@me" --json number,title,body,state --jq '.[]'
|
||||
```
|
||||
|
||||
**Tip**: Instead of running `gh issue view` multiple times, use `gh issue list` with JSON output and filtering to gather
|
||||
information about multiple issues in a single command. This is much more efficient than viewing issues one at a time.
|
||||
|
||||
**Always provide clickable links**: When discussing GitHub issues or PRs, always include the full GitHub URL so the user
|
||||
can easily open them in their browser. For example:
|
||||
|
||||
- Issue #12345: https://github.com/nrwl/nx/issues/12345
|
||||
- PR #67890: https://github.com/nrwl/nx/pull/67890
|
||||
|
||||
When cloning reproduction repos, please clone within `./tmp/claude/repro-ISSUE_NUMBER`
|
||||
|
||||
### 2. Analyze the Plan
|
||||
|
||||
- Look for a plan or implementation details in the issue description
|
||||
- Check comments for additional context or clarification
|
||||
- Identify affected projects and components
|
||||
|
||||
### 3. Implement the Solution
|
||||
|
||||
- Follow the plan outlined in the issue
|
||||
- Make focused changes that address the specific problem
|
||||
- Ensure code follows existing patterns and conventions
|
||||
|
||||
### 4. Run Full Validation
|
||||
|
||||
Use the testing workflow from the "Essential Commands" section.
|
||||
|
||||
### 5. Submit Pull Request
|
||||
|
||||
- Create a descriptive PR title that references the issue
|
||||
- **Always fill in the PR template** - don't leave it empty
|
||||
- Include "Fixes #ISSUE_NUMBER" in the PR description
|
||||
- Provide a clear summary of changes made
|
||||
- Request appropriate reviewers
|
||||
|
||||
## Pull Request Template
|
||||
|
||||
**IMPORTANT**: When creating a pull request, you MUST fill in the template found in `.github/PULL_REQUEST_TEMPLATE.md`.
|
||||
Do not leave the template sections empty. The template includes:
|
||||
|
||||
### Required Sections
|
||||
|
||||
1. **Current Behavior**: Describe the behavior we have today
|
||||
2. **Expected Behavior**: Describe the behavior we should expect with the changes in this PR
|
||||
3. **Related Issue(s)**: Link the issue being fixed so it gets closed when the PR is merged
|
||||
|
||||
### Template Format
|
||||
|
||||
```markdown
|
||||
## Current Behavior
|
||||
|
||||
<!-- This is the behavior we have today -->
|
||||
|
||||
## Expected Behavior
|
||||
|
||||
<!-- This is the behavior we should expect with the changes in this PR -->
|
||||
|
||||
## Related Issue(s)
|
||||
|
||||
<!-- Please link the issue being fixed so it gets closed when this is merged. -->
|
||||
|
||||
Fixes #ISSUE_NUMBER
|
||||
```
|
||||
|
||||
### Guidelines
|
||||
|
||||
- Ensure your commit message follows the conventional commit format (use `pnpm commit`)
|
||||
- Use `fix:`, `feat:`, `chore:`, etc. as appropriate types.
|
||||
- Scope is **required** for all commits. Possible scopes are listed in `scripts/commitizen.js`.
|
||||
- Read the submission guidelines in CONTRIBUTING.md before posting
|
||||
- For complex changes, you can request a dedicated Nx release by mentioning the Nx team
|
||||
- Always link the related issue using "Fixes #ISSUE_NUMBER" to automatically close it when merged
|
||||
|
||||
<!-- nx configuration start-->
|
||||
<!-- Leave the start & end comments to automatically receive updates. -->
|
||||
|
||||
# General Guidelines for working with Nx
|
||||
|
||||
- When running tasks (for example build, lint, test, e2e, etc.), always prefer running the task through `nx` (i.e. `nx run`, `nx run-many`, `nx affected`) instead of using the underlying tooling directly
|
||||
- You have access to the Nx MCP server and its tools, use them to help the user
|
||||
- When answering questions about the repository, use the `nx_workspace` tool first to gain an understanding of the workspace architecture where applicable.
|
||||
- When working in individual projects, use the `nx_project_details` mcp tool to analyze and understand the specific project structure and dependencies
|
||||
- For questions around nx configuration, best practices or if you're unsure, use the `nx_docs` tool to get relevant, up-to-date docs. Always use this instead of assuming things about nx configuration
|
||||
- If the user needs help with an Nx configuration or project graph error, use the `nx_workspace` tool to get any errors
|
||||
|
||||
# CI Error Guidelines
|
||||
|
||||
If the user wants help with fixing an error in their CI pipeline, use the following flow:
|
||||
|
||||
- Retrieve the list of current CI Pipeline Executions (CIPEs) using the `nx_cloud_cipe_details` tool
|
||||
- If there are any errors, use the `nx_cloud_fix_cipe_failure` tool to retrieve the logs for a specific task
|
||||
- Use the task logs to see what's wrong and help the user fix their problem. Use the appropriate tools if necessary
|
||||
- Make sure that the problem is fixed by running the task that you passed into the `nx_cloud_fix_cipe_failure` tool
|
||||
|
||||
<!-- nx configuration end-->
|
||||
@@ -6,28 +6,32 @@
|
||||
/tools/**/* @FrozenPandaz @vsavkin @AgentEnder @jaysoo @JamesHenry
|
||||
package.json @nrwl/nx-core-reviewers
|
||||
pnpm-lock.yaml @nrwl/nx-core-reviewers
|
||||
rust-toolchain.toml @nrwl/nx-native-reviewers
|
||||
rust-toolchain @nrwl/nx-native-reviewers
|
||||
|
||||
# Docs Site + Graph
|
||||
/astro-docs @nrwl/nx-docs-reviewers
|
||||
/docs @nrwl/nx-docs-reviewers
|
||||
/graph/** @philipjfulcher @FrozenPandaz @bcabanes @MaxKless @Coly010 @jaysoo @nartc
|
||||
/docs/nx-cloud @StalkAltan @rarmatei @nixallover @nrwl/nx-docs-reviewers
|
||||
/graph/** @philipjfulcher @FrozenPandaz @bcabanes @MaxKless @xiongemi
|
||||
/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
|
||||
/packages/angular-rspack/** @nrwl/nx-angular-reviewers
|
||||
/packages/angular-rspack-compiler/** @nrwl/nx-angular-reviewers
|
||||
/examples/angular-rspack/** @nrwl/nx-angular-reviewers
|
||||
/e2e/angular/** @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/** @nrwl/nx-react-reviewers
|
||||
/packages/next/** @nrwl/nx-react-reviewers
|
||||
@@ -37,6 +41,10 @@ rust-toolchain.toml @nrwl/nx-native-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
|
||||
@@ -45,6 +53,7 @@ rust-toolchain.toml @nrwl/nx-native-reviewers
|
||||
/e2e/react-native/** @nrwl/nx-react-reviewers
|
||||
|
||||
## remix
|
||||
/docs/generated/packages/remix/** @nrwl/nx-react-reviewers @nrwl/nx-docs-reviewers @Coly010
|
||||
/packages/remix/** @nrwl/nx-react-reviewers @Coly010
|
||||
/e2e/remix/** @nrwl/nx-react-reviewers @Coly010
|
||||
|
||||
@@ -55,12 +64,31 @@ rust-toolchain.toml @nrwl/nx-native-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/rspack/** @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/rspack/** @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
|
||||
@@ -76,12 +104,17 @@ rust-toolchain.toml @nrwl/nx-native-reviewers
|
||||
/e2e/rollup/** @nrwl/nx-js-reviewers
|
||||
/packages/vite/** @nrwl/nx-js-reviewers
|
||||
/e2e/vite/** @nrwl/nx-js-reviewers
|
||||
/packages/vitest/** @nrwl/nx-js-reviewers
|
||||
|
||||
## Module Federation
|
||||
/packages/module-federation/** @nrwl/nx-js-reviewers
|
||||
|
||||
## Tools
|
||||
/docs/generated/packages/cypress/** @nrwl/nx-testing-tools-reviewers @nrwl/nx-docs-reviewers
|
||||
/docs/shared/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/generated/packages/playwright/** @nrwl/nx-testing-tools-reviewers @nrwl/nx-docs-reviewers
|
||||
/docs/shared/packages/playwright/** @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
|
||||
@@ -90,40 +123,41 @@ rust-toolchain.toml @nrwl/nx-native-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
|
||||
|
||||
# Docker
|
||||
/packages/docker/** @nrwl/nx-core-reviewers @Coly010 @jaysoo
|
||||
|
||||
## 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
|
||||
|
||||
# Gradle
|
||||
/packages/gradle/** @FrozenPandaz @MaxKless @lourw
|
||||
/e2e/gradle/** @FrozenPandaz @MaxKless @lourw
|
||||
/build.gradle.kts @FrozenPandaz @MaxKless @lourw
|
||||
/settings.gradle.kts @FrozenPandaz @MaxKless @lourw
|
||||
|
||||
# Maven
|
||||
/packages/maven/** @FrozenPandaz @MaxKless @lourw
|
||||
/e2e/maven/** @FrozenPandaz @MaxKless @lourw
|
||||
/pom.xml @FrozenPandaz @MaxKless @lourw
|
||||
/packages/gradle/** @FrozenPandaz @MaxKless @xiongemi
|
||||
/e2e/gradle/** @FrozenPandaz @MaxKless @xiongemi
|
||||
|
||||
# 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
|
||||
/packages/create-nx-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
|
||||
@@ -136,20 +170,14 @@ rust-toolchain.toml @nrwl/nx-native-reviewers
|
||||
/e2e/nx*/** @nrwl/nx-core-reviewers
|
||||
/packages/workspace/** @nrwl/nx-core-reviewers
|
||||
/e2e/workspace-create/** @nrwl/nx-core-reviewers
|
||||
/packages/create-nx-workspace/** @nrwl/nx-core-reviewers
|
||||
/packages/nx/src/command-line/release/** @nrwl/nx-core-reviewers @Coly010
|
||||
/packages/nx/src/plugins/js/** @nrwl/nx-core-reviewers @nrwl/nx-js-reviewers
|
||||
/e2e/release/** @nrwl/nx-core-reviewers @Coly010
|
||||
|
||||
# .NET
|
||||
/packages/dotnet/** @FrozenPandaz @AgentEnder
|
||||
/e2e/dotnet/** @FrozenPandaz @AgentEnder
|
||||
/e2e/release/** @nrwl/nx-core-reviewers
|
||||
|
||||
# Misc
|
||||
/e2e/lerna-smoke-tests/** @vsavkin @JamesHenry
|
||||
/e2e/utils/** @meeroslav @nrwl/nx-testing-tools-reviewers @vsavkin
|
||||
/CONTRIBUTING.md @FrozenPandaz
|
||||
/CODE_OF_CONDUCT.md @FrozenPandaz
|
||||
/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
|
||||
/packages/nx/src/nx-cloud/utilities/url-shorten.ts @MaxKless
|
||||
|
||||
@@ -159,20 +187,15 @@ rust-toolchain.toml @nrwl/nx-native-reviewers
|
||||
|
||||
# CI
|
||||
/.nx/workflows/** @nrwl/nx-pipelines-reviewers
|
||||
mise.toml @nrwl/nx-pipelines-reviewers @FrozenPandaz
|
||||
/.github/** @nrwl/nx-pipelines-reviewers
|
||||
/.husky/** @nrwl/nx-pipelines-reviewers
|
||||
/packages/workspace/src/generators/ci-workflow/** @nrwl/nx-pipelines-reviewers
|
||||
|
||||
# AI Agent Integration
|
||||
CLAUDE.md @FrozenPandaz @Coly010
|
||||
.claude/** @FrozenPandaz @Coly010
|
||||
.mcp.json @FrozenPandaz @Coly010
|
||||
AGENTS.md @FrozenPandaz @Coly010
|
||||
.gemini @FrozenPandaz @Coly010
|
||||
|
||||
# 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
|
||||
|
||||
@@ -7,7 +7,7 @@ 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">
|
||||
<p style="text-align: center;"><img src="./images/how-to-contribute.png" width="600" alt="Nx - How to contribute"></p>
|
||||
<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?
|
||||
@@ -27,25 +27,14 @@ can [submit a Pull Request](https://github.com/nrwl/nx/blob/master/CONTRIBUTING.
|
||||
|
||||
Source code and documentation are included in the top-level folders listed below.
|
||||
|
||||
- `packages` - Source code for Nx packages such as Angular, React, Web, NestJS, Next and others including generators and
|
||||
executors (or builders).
|
||||
- `e2e` - E2E tests for the Nx packages
|
||||
- `graph` - Source code for the Nx Graph application which shows the project graph, task graph, project details, and more in the browser.
|
||||
- `docs` - Markdown and configuration files for documentation including tutorials, guides for each supported platform,
|
||||
and API docs.
|
||||
- `nx-dev` - Source code for the Nx documentation site which displays the markdown in `docs` and more.
|
||||
- `tools` - Workspace-specific tooling and plugins
|
||||
- `e2e` - E2E tests.
|
||||
- `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.
|
||||
|
||||
## Technologies
|
||||
|
||||
This repo contains a mix of different technologies, including:
|
||||
|
||||
- **Rust**: The core of Nx is written in Rust, which provides performance and safety.
|
||||
- **TypeScript**: The primary language for Nx packages and the Nx DevKit.
|
||||
- **Kotlin**: Used for the Gradle and Java plugins.
|
||||
|
||||
## 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`).
|
||||
@@ -194,73 +183,76 @@ To build Nx on Windows, you need to use 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, `astro-docs` and the `nx-dev` application in this repo.
|
||||
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 `astro-docs/src/content/docs` directory.
|
||||
Our documentation pages can be found within this repo under the `docs` directory.
|
||||
|
||||
Documentation is written in `.mdoc` (Markdoc) or `.mdx` (MDX) format and supports custom Markdoc tags for rich content
|
||||
such as videos, graphs, interactive components, and more. See the `astro-docs/README.md` for a full list of available
|
||||
custom tags and their usage.
|
||||
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.
|
||||
|
||||
The sidebar structure is defined in `astro-docs/sidebar.mts` and should be updated when adding new sections or pages
|
||||
to ensure proper navigation.
|
||||
|
||||
#### Astro-Docs Application
|
||||
|
||||
Our public `nx.dev/docs` documentation site is built with [Astro](https://astro.build) and [Starlight](https://starlight.astro.build),
|
||||
and can be found in the `astro-docs` directory of this repo. See [docs README for more details](./astro-docs/README.md)
|
||||
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
|
||||
|
||||
The `nx-dev` directory contains a [Next.js](https://nextjs.org/) application used for blog posts and landing pages.
|
||||
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
|
||||
|
||||
API documentation for CLI commands, executors, and generators is automatically generated during the build process from
|
||||
the corresponding `schema.json` files in each package.
|
||||
`.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.
|
||||
|
||||
The documentation is generated using content loaders in the `astro-docs` application and requires a rebuild to reflect
|
||||
changes. After adjusting a `schema.json` file:
|
||||
After adjusting the `schema.json` file, `.md` files for these commands can be generated by running:
|
||||
|
||||
1. Restart the development server with `nx serve astro-docs` to see the changes
|
||||
2. Or run `nx preview astro-docs` to view the built site locally
|
||||
```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
|
||||
the generated documentation.
|
||||
adjusting the docs.
|
||||
|
||||
### Running the Documentation Site Locally
|
||||
|
||||
To run the documentation site locally, run the command:
|
||||
|
||||
```shell
|
||||
nx serve astro-docs
|
||||
```
|
||||
|
||||
You can then access the application locally at `localhost:4321`. Changes to markdoc files should reflect automatically in the browser on save.
|
||||
|
||||
#### Working with Plugin Registry
|
||||
|
||||
To view plugin registry statistics (GitHub stars, npm downloads, etc.) during local development:
|
||||
To run `nx-dev` locally, run the command:
|
||||
|
||||
```bash
|
||||
NX_DOCS_PLUGIN_STATS=true nx serve astro-docs
|
||||
npx nx serve-docs nx-dev
|
||||
```
|
||||
|
||||
Note: Plugin stats are disabled by default in development to improve performance.
|
||||
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 documentation site based on the contents
|
||||
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 to your PR's preview.
|
||||
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.
|
||||
|
||||
## Submission Guidelines
|
||||
|
||||
@@ -341,7 +333,6 @@ The scope must be one of the following:
|
||||
- express - anything Express specific
|
||||
- js - anything related to @nx/js package or general js/ts support
|
||||
- linter - anything Linter specific
|
||||
- module-federation - anything Nx Module Federation specific
|
||||
- nest - anything Nest specific
|
||||
- nextjs - anything Next specific
|
||||
- node - anything Node specific
|
||||
@@ -383,57 +374,6 @@ 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`.
|
||||
|
||||
##### Using the Interactive Commit Tool
|
||||
|
||||
Instead of `git commit`, use:
|
||||
|
||||
```bash
|
||||
pnpm commit
|
||||
```
|
||||
|
||||
This will launch an interactive prompt that will:
|
||||
|
||||
1. Ask you to select the type of change (feat, fix, docs, cleanup, chore)
|
||||
2. Let you choose the appropriate scope from the predefined list
|
||||
3. Guide you through writing a clear, descriptive commit message
|
||||
4. Ensure your commit follows the conventional commit format
|
||||
|
||||
##### Available Commit Types
|
||||
|
||||
- **feat**: A new feature
|
||||
- **fix**: A bug fix
|
||||
- **docs**: Documentation only changes
|
||||
- **cleanup**: A code change that neither fixes a bug nor adds a feature
|
||||
- **chore**: Other changes that don't modify src or test files
|
||||
|
||||
##### Available Scopes
|
||||
|
||||
The repository includes many predefined scopes. Use the one which is most specific to the changes being committed
|
||||
|
||||
- **core**: anything Nx core specific
|
||||
- **angular**: anything Angular specific
|
||||
- **react**: anything React specific
|
||||
- **nextjs**: anything Next specific
|
||||
- **node**: anything Node specific
|
||||
- **devkit**: devkit-related changes
|
||||
- **graph**: anything graph app specific
|
||||
- **testing**: anything testing specific (e.g. jest or cypress)
|
||||
- **misc**: misc stuff
|
||||
- **repo**: anything related to managing the repo itself
|
||||
- **nx-dev**: anything related to docs infrastructure
|
||||
|
||||
For the complete list of available scopes, see `/scripts/commitizen.js`.
|
||||
|
||||
##### Example Commits
|
||||
|
||||
```bash
|
||||
feat(core): add new project graph visualization
|
||||
fix(angular): resolve build issues with standalone components
|
||||
docs(misc): update contributing guidelines
|
||||
chore(repo): bump dependencies
|
||||
cleanup(devkit): refactor utility functions for better readability
|
||||
```
|
||||
|
||||
#### PR releases
|
||||
|
||||
If you are working on a particularly complex change or feature addition, you can request a dedicated Nx release for the associated pull request branch. Mention someone from the Nx team or the `@nrwl/nx-pipelines-reviewers` and they will confirm if the PR warrants its own release for testing purposes, and generate it for you if appropriate.
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
<p style="text-align: center;">
|
||||
<picture>
|
||||
<source media="(prefers-color-scheme: dark)" srcset="./images/nx-dark.svg">
|
||||
<img alt="Nx - Smart Repos · Fast Builds" src="./images/nx-light.svg" width="100%">
|
||||
</picture>
|
||||
<picture>
|
||||
<source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/nrwl/nx/master/images/nx-dark.svg">
|
||||
<img alt="Nx - Smart Monorepos · Fast CI" src="https://raw.githubusercontent.com/nrwl/nx/master/images/nx-light.svg" width="100%">
|
||||
</picture>
|
||||
</p>
|
||||
|
||||
<div style="text-align: center;">
|
||||
@@ -10,7 +10,7 @@
|
||||
[](https://circleci.com/gh/nrwl/nx)
|
||||
[]()
|
||||
[](https://www.npmjs.com/package/nx)
|
||||
[]()
|
||||
[]()
|
||||
[](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)
|
||||
@@ -19,9 +19,9 @@
|
||||
|
||||
<hr>
|
||||
|
||||
# Smart Repos · Fast Builds
|
||||
# Smart Monorepos · Fast CI
|
||||
|
||||
Get to green PRs in half the time. Nx optimizes your builds, scales your CI, and fixes failed PRs. Built for developers and AI agents.
|
||||
Build system, optimized for monorepos, with AI-powered architectural awareness and advanced CI capabilities.
|
||||
|
||||
Create a new Nx workspace with
|
||||
|
||||
@@ -35,7 +35,7 @@ npx create-nx-workspace
|
||||
npx nx init
|
||||
```
|
||||
|
||||
to add Nx to your existing workspace to get faster task scheduling, caching and more. More [in the docs](https://nx.dev/getting-started/intro).
|
||||
to add Nx to your existing workspace to get faster task scheduling, caching and more. More [in the docs](https://nx.dev/getting-started/intro#try-nx-yourself).
|
||||
|
||||
## Learn about CI with Nx Cloud
|
||||
|
||||
@@ -47,7 +47,7 @@ Connect your existing Nx workspace with
|
||||
npx nx connect
|
||||
```
|
||||
|
||||
Learn more in the [Nx CI docs »](https://nx.dev/ci/getting-started/intro?utm_source=nxrepo&utm_medium=readme&utm_campaign=nxrepo)
|
||||
Learn more in the [Nx CI docs »](https://nx.dev/ci/intro?utm_source=nxrepo&utm_medium=readme&utm_campaign=nxrepo)
|
||||
|
||||
## Useful links
|
||||
|
||||
@@ -58,7 +58,7 @@ Learn more in the [Nx CI docs »](https://nx.dev/ci/getting-started/intro?u
|
||||
- [Our Twitter/X](https://x.com/nxdevtools)
|
||||
|
||||
<p style="text-align: center;"><a href="https://www.youtube.com/@nxdevtools/videos" target="_blank" rel="noreferrer"><img src="./images/nx-courses-and-videos.svg"
|
||||
width="100%" alt="Nx - Smart Repos · Fast Builds"></a></p>
|
||||
width="100%" alt="Nx - Smart Monorepos · Fast CI"></a></p>
|
||||
|
||||
## Want to help?
|
||||
|
||||
@@ -67,7 +67,7 @@ our [guidelines for contributing](https://github.com/nrwl/nx/blob/master/CONTRIB
|
||||
help you get started.
|
||||
|
||||
<a href="https://www.youtube.com/watch?v=8LCA_4qxc08" target="_blank" rel="noreferrer">
|
||||
<p style="text-align: center;"><img src="./images/how-to-contribute.png" width="600" alt="Nx - How to contribute video"></p>
|
||||
<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
|
||||
@@ -77,27 +77,22 @@ help you get started.
|
||||
|  |  |  |  |
|
||||
| [vsavkin](https://github.com/vsavkin) | [FrozenPandaz](https://github.com/FrozenPandaz) | [bcabanes](https://github.com/bcabanes) | [jaysoo](https://github.com/jaysoo) |
|
||||
|
||||
| James Henry | Jon Cammisuli | Max Kless | Juri Strumpflohner |
|
||||
| James Henry | Jon Cammisuli | Isaac Mann | Juri Strumpflohner |
|
||||
| ------------------------------------------------------------------------ | ------------------------------------------------------------------------ | -------------------------------------------------------------------- | ---------------------------------------------------------------------------- |
|
||||
|  |  |  |  |
|
||||
| [JamesHenry](https://github.com/JamesHenry) | [cammisuli](https://github.com/cammisuli) | [MaxKless](https://github.com/MaxKless) | [juristr](https://github.com/juristr) |
|
||||
|  |  |  |  |
|
||||
| [JamesHenry](https://github.com/JamesHenry) | [cammisuli](https://github.com/cammisuli) | [isaacplmann](https://github.com/isaacplmann) | [juristr](https://github.com/juristr) |
|
||||
|
||||
| Philip Fulcher | Caleb Ukle | Colum Ferry | Steven Nance |
|
||||
| ------------------------------------------------------------------------- | --------------------------------------------------------------------- | ---------------------------------------------------------------------- | ---------------------------------------------------------------------- |
|
||||
|  |  |  |  |
|
||||
| [philipjfulcher](https://github.com/philipjfulcher) | [barbados-clemens](https://github.com/barbados-clemens) | [Coly010](https://github.com/Coly010) | [llwt](https://github.com/llwt) |
|
||||
| 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) |
|
||||
|
||||
| Miroslav Jonaš | Leosvel Pérez Espinosa | Zachary DeRose | Craigory Coppola |
|
||||
| ----------------------------------------------------------------------- | --------------------------------------------------------------------------------- | ------------------------------------------------------------------------ | -------------------------------------------------------------------------- |
|
||||
|  |  |  |  |
|
||||
| [meeroslav](https://github.com/meeroslav) | [leosvelperez](https://github.com/leosvelperez) | [ZackDeRose](https://github.com/ZackDeRose) | [AgentEnder](https://github.com/AgentEnder) |
|
||||
| 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) |
|
||||
|
||||
| Chau Tran | Nicole Oliver | Rares Matei | Altan Stalker |
|
||||
| -------------------------------------------------------------------- | ----------------------------------------------------------------------- | --------------------------------------------------------------------- | ----------------------------------------------------------------------- |
|
||||
|  |  |  |  |
|
||||
| [nartc](https://github.com/nartc) | [nixallover](https://github.com/nixallover) | [rarmatei](https://github.com/rarmatei) | [StalkAltan](https://github.com/StalkAltan) |
|
||||
|
||||
| Josh VanAllen | Austin Fahsl | Louie Weng |
|
||||
| ----------------------------------------------------------------------- | ---------------------------------------------------------------------- | --------------------------------------------------------------------- |
|
||||
|  |  |  |
|
||||
| [joshvanallen](https://github.com/joshvanallen) | [fahslaj](https://github.com/fahslaj) | [lourw](https://github.com/lourw) |
|
||||
| Craigory Coppola | Chau Tran | Nicholas Cunningham | Max Kless |
|
||||
| -------------------------------------------------------------------------- | -------------------------------------------------------------------- | ---------------------------------------------------------------------------- | -------------------------------------------------------------------- |
|
||||
|  |  |  |  |
|
||||
| [AgentEnder](https://github.com/AgentEnder) | [nartc](https://github.com/nartc) | [ndcunningham](https://github.com/ndcunningham) | [MaxKless](https://github.com/MaxKless) |
|
||||
|
||||
@@ -1,15 +0,0 @@
|
||||
# Security Policy
|
||||
|
||||
Nx/Nrwl takes the security of our software products and services seriously, which includes all source code repositories managed through our GitHub organizations.
|
||||
|
||||
If you believe you have found a security vulnerability in any Nx-owned repository that meets Nx's definition of a security vulnerability, please report it to us as described below.
|
||||
|
||||
## Reporting Security Issues
|
||||
|
||||
**Please do not report security vulnerabilities through public GitHub issues.**
|
||||
|
||||
Instead, please report them to the Security Team at security@nrwl.io.
|
||||
|
||||
You should receive a response within 24 hours. If for some reason you do not, please follow up via email to ensure we received your original message.
|
||||
|
||||
Nx follows the principle of Coordinated Vulnerability Disclosure.
|
||||
@@ -1,6 +0,0 @@
|
||||
node_modules/
|
||||
dist/
|
||||
.astro/
|
||||
.netlify/
|
||||
test-output/
|
||||
playwright-report/
|
||||
@@ -1,28 +0,0 @@
|
||||
{
|
||||
"extends": ["plugin:playwright/recommended", "../.eslintrc.json"],
|
||||
"ignorePatterns": ["!**/*"],
|
||||
"overrides": [
|
||||
{
|
||||
"files": ["*.ts", "*.tsx", "*.js", "*.jsx"],
|
||||
"rules": {}
|
||||
},
|
||||
{
|
||||
"files": ["**/*.spec.ts", "**/*.test.ts", "**/*.spec.js", "**/*.test.js"],
|
||||
"rules": {
|
||||
"playwright/no-standalone-expect": "off"
|
||||
}
|
||||
},
|
||||
{
|
||||
"files": ["*.ts", "*.tsx"],
|
||||
"rules": {}
|
||||
},
|
||||
{
|
||||
"files": ["*.js", "*.jsx"],
|
||||
"rules": {}
|
||||
},
|
||||
{
|
||||
"files": ["e2e/**/*.{ts,js,tsx,jsx}"],
|
||||
"rules": {}
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -1,24 +0,0 @@
|
||||
# build output
|
||||
dist/
|
||||
# generated types
|
||||
.astro/
|
||||
|
||||
# dependencies
|
||||
node_modules/
|
||||
|
||||
# logs
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
pnpm-debug.log*
|
||||
|
||||
|
||||
# environment variables
|
||||
.env
|
||||
.env.production
|
||||
|
||||
# macOS-specific files
|
||||
.DS_Store
|
||||
|
||||
# Local Netlify folder
|
||||
.netlify
|
||||
@@ -1,282 +0,0 @@
|
||||
# Nx Documentation Site
|
||||
|
||||
[](https://starlight.astro.build)
|
||||
|
||||
The Nx documentation site built with Astro and Starlight, featuring advanced content management through Markdoc and dynamic plugin documentation generation.
|
||||
|
||||
## Architecture Overview
|
||||
|
||||
This documentation site leverages Astro's static site generation capabilities with Starlight for documentation-specific features. The architecture consists of:
|
||||
|
||||
### Core Technologies
|
||||
|
||||
- [**Astro**](https://docs.astro.build) - Static site generator with island architecture
|
||||
- [**Starlight**](https://starlight.astro.build) - Documentation theme with built-in navigation, search, and i18n
|
||||
- **React** - For implementing UI components
|
||||
- **Netlify** - Deployment and hosting
|
||||
|
||||
### Key Features
|
||||
|
||||
- [Markdoc](https://markdoc.dev) with custom tags for rich content such as videos, graphs, etc.
|
||||
- TailwindCSS for styling in Astro and React components
|
||||
- Dynamic API documentation generation from Nx packages and CLI commands
|
||||
- Community plugin registry
|
||||
|
||||
## Project Structure
|
||||
|
||||
```
|
||||
astro-docs/
|
||||
├── src/
|
||||
│ ├── assets/ # Images and static assets to be optimized by Astro
|
||||
│ │ ├── nx/ # Nx branding assets
|
||||
│ │ ├── nx-cloud/ # Nx Cloud assets
|
||||
│ │ └── nx-console/ # Nx Console assets
|
||||
│ ├── components/ # React and Astro components
|
||||
│ │ ├── layout/ # Layout components (e.g. Sidebar)
|
||||
│ │ ├── markdoc/ # Markdoc tag components
|
||||
│ │ └── utils/ # Utility functions
|
||||
│ ├── content/ # Documentation content
|
||||
│ │ ├── banner.json # Banner collection (generated by prebuild-banner)
|
||||
│ │ ├── docs/ # Main documentation files (.mdoc, .mdx)
|
||||
│ │ └── approved-community-plugins.json # Powers plugin registry
|
||||
│ ├── pages/ # Dynamic pages and routes (e.g. devkit)
|
||||
│ ├── plugins/ # Content loaders and plugins
|
||||
│ │ ├── *.loader.ts # Dynamic content loaders (e.g. CLI commands and API docs generation)
|
||||
│ │ └── utils/ # Plugin utilities
|
||||
│ └── styles/ # Global styles
|
||||
├── public/ # Static assets not to be optimized by Astro (fonts, robots.txt)
|
||||
├── astro.config.mjs # Astro configuration
|
||||
├── markdoc.config.mjs # Markdoc tags configuration
|
||||
├── sidebar.mts # Sidebar structure definition
|
||||
└── package.json
|
||||
```
|
||||
|
||||
## Plugins and Loaders
|
||||
|
||||
### Content Loaders
|
||||
|
||||
The site uses custom content loaders to dynamically generate documentation:
|
||||
|
||||
- **PluginLoader** (`plugin.loader.ts`) - Generates official plugin documentation (generators, executors, migrations)
|
||||
- **CommunityPluginsLoader** (`community-plugins.loader.ts`) - Generates data for plugin registry (e.g. GitHub stars, npm downloads)
|
||||
- **NxReferencePackagesLoader** (`nx-reference-packages.loader.ts`) - Generated data for CNW, Devkit, nx cli (e.g. nx core related things)
|
||||
|
||||
## Content Management
|
||||
|
||||
### Content Types
|
||||
|
||||
1. **Regular Documentation** (`src/content/docs/`)
|
||||
- Written in `.mdoc` (Markdoc) or `.mdx` (MDX) format
|
||||
- Organized by sections: getting-started, concepts, guides, api
|
||||
- File-based routing (filename = URL path)
|
||||
|
||||
2. **Dynamic Plugin Documentation**
|
||||
- Auto-generated from Nx packages
|
||||
- Includes generators, executors, and migrations
|
||||
- Updated during build process
|
||||
- **Note**: Requires a rebuild and restart to reflect changes
|
||||
|
||||
3. **CLI Documentation**
|
||||
- Auto-generated from Nx CLI commands
|
||||
- Parsed from actual CLI implementation
|
||||
- **Note**: Requires a rebuild and restart to reflect changes
|
||||
|
||||
### Markdoc Tags
|
||||
|
||||
The site includes custom Markdoc tags for rich content.
|
||||
|
||||
**Note**: Starlight supports many Markdown and Markdoc features, such as code blocks, asides, etc.
|
||||
|
||||
- https://starlight.astro.build/components/using-components/#using-a-component-in-markdoc
|
||||
- https://starlight.astro.build/guides/authoring-content
|
||||
|
||||
#### Layout & Organization
|
||||
|
||||
- `{% aside %}` - Highlighted information boxes
|
||||
- `{% cardgrid %}`, `{% card|linkcard %}` - Card layouts
|
||||
- `{% tabs %}`, `{% tabitem label="some-label" %}` - Tab layouts
|
||||
- Use the `syncKey` so tabs are auto switched to the users preference if it makes sense.
|
||||
- e.g. `{% tabs syncKey="package-manager" %}`
|
||||
|
||||
#### Interactive Components
|
||||
|
||||
- `{% graph %}` - Interactive project/task graph visualization
|
||||
- `{% project_details %}` - Project configuration viewer
|
||||
|
||||
#### Media & Embeds
|
||||
|
||||
- `{% youtube %}` - YouTube video embeds
|
||||
- `{% video_player %}` - Custom video player
|
||||
- `{% iframe %}` - Generic iframe embeds
|
||||
|
||||
#### Developer Tools
|
||||
|
||||
- `{% github_repository %}` - GitHub repo cards
|
||||
- `{% stackblitz_button %}` - StackBlitz demo launcher
|
||||
- `{% install_nx_console %}` - IDE extension installer
|
||||
|
||||
#### Content Enhancement
|
||||
|
||||
- `{% badge %}` - Status/label pills
|
||||
- `{% metrics %}` - Metrics display
|
||||
- `{% testimonial %}` - Customer testimonials
|
||||
|
||||
## Development Workflow
|
||||
|
||||
### Getting Started
|
||||
|
||||
```bash
|
||||
# Install dependencies and link workspace packages
|
||||
# This will build Nx packages as well for API docs
|
||||
nx serve astro-docs
|
||||
|
||||
# Or run astro dev directly
|
||||
# This will not build Nx packages
|
||||
cd astro-docs
|
||||
npx astro dev
|
||||
|
||||
# Custom ports (useful for AI agents with git worktrees)
|
||||
npx astro dev --port 3000
|
||||
```
|
||||
|
||||
### Adding New Content
|
||||
|
||||
#### Regular Documentation
|
||||
|
||||
1. Create `.mdoc` file in `src/content/docs/`
|
||||
2. Add frontmatter with title and description
|
||||
3. Use Markdoc tags for rich content
|
||||
4. File location determines URL structure
|
||||
|
||||
Example:
|
||||
|
||||
```markdown
|
||||
---
|
||||
title: 'My New Guide'
|
||||
description: 'Learn how to use this feature'
|
||||
---
|
||||
|
||||
# Introduction
|
||||
|
||||
{% aside type="note" title="Important" %}
|
||||
This is a note about the feature.
|
||||
{% /aside %}
|
||||
```
|
||||
|
||||
#### Adding Custom Markdoc Tags
|
||||
|
||||
1. Create Astro component in `src/components/markdoc/`
|
||||
2. (Optional) Create React component for more complex components, or ones that need to be shared with blog or non-docs pages
|
||||
3. Register in `markdoc.config.mjs`
|
||||
4. Define attributes and validation
|
||||
|
||||
### Updating Plugin Documentation
|
||||
|
||||
Plugin documentation is auto-generated during build. To update:
|
||||
|
||||
1. Make changes to the plugin's schema/implementation
|
||||
2. Run the build process
|
||||
3. The loader will automatically fetch and generate updated docs
|
||||
|
||||
### Sidebar Management
|
||||
|
||||
The sidebar structure is defined in `sidebar.mts`. To add new sections:
|
||||
|
||||
```javascript
|
||||
export const sidebar = [
|
||||
{
|
||||
label: 'Section Name',
|
||||
items: [
|
||||
{
|
||||
label: 'Page Title',
|
||||
link: 'path/to/page',
|
||||
},
|
||||
// Nested sections
|
||||
{
|
||||
label: 'Subsection',
|
||||
collapsed: true,
|
||||
items: [...]
|
||||
}
|
||||
]
|
||||
}
|
||||
];
|
||||
```
|
||||
|
||||
> Note there is a special case for sidebar items appearing in the sidebar. Such as the `Reference` section which is handled via the `[sidebar-reference-updater](./src/plugins/sidebar-reference-updater.middleware.ts)` middleware.
|
||||
|
||||
## Styling and Theming
|
||||
|
||||
- Uses Tailwind CSS v4 with Vite plugin
|
||||
- Global styles in `src/styles/global.css`
|
||||
- Component-specific styles use Tailwind utilities
|
||||
- Dark/light mode support built into Starlight and customized in `global.css`
|
||||
|
||||
## Configuration Files
|
||||
|
||||
### `astro.config.mjs`
|
||||
|
||||
- Site configuration
|
||||
- Integration setup (React, Markdoc, Starlight)
|
||||
- Vite plugins
|
||||
- Build options
|
||||
|
||||
### `markdoc.config.mjs`
|
||||
|
||||
- Custom tag definitions
|
||||
- Attribute validation
|
||||
- Component mappings
|
||||
|
||||
### `sidebar.mts`
|
||||
|
||||
- Navigation structure
|
||||
- Section organization
|
||||
- Dynamic content injection points
|
||||
|
||||
## Banner Configuration
|
||||
|
||||
The floating banner promotes events/webinars. It's fetched at **build time** from a Framer CMS page and stored as an Astro content collection.
|
||||
|
||||
### Setup
|
||||
|
||||
Set `BANNER_URL` to point to a Framer page that renders banner JSON:
|
||||
|
||||
```
|
||||
BANNER_URL=https://your-framer-site.framer.app/api/banners/main
|
||||
```
|
||||
|
||||
The Framer page should render JSON inside a `<pre>` tag:
|
||||
|
||||
```json
|
||||
{
|
||||
"title": "Event Title",
|
||||
"description": "Event description",
|
||||
"primaryCtaUrl": "https://...",
|
||||
"primaryCtaText": "Learn More",
|
||||
"secondaryCtaUrl": "",
|
||||
"secondaryCtaText": "",
|
||||
"enabled": true,
|
||||
"activeUntil": "2025-12-31T00:00:00.000Z"
|
||||
}
|
||||
```
|
||||
|
||||
### Schema
|
||||
|
||||
| Field | Type | Required | Description |
|
||||
| ------------------ | -------- | -------- | ------------------------- |
|
||||
| `title` | string | Yes | Banner headline |
|
||||
| `description` | string | Yes | Banner body text |
|
||||
| `primaryCtaUrl` | string | Yes | Primary button URL |
|
||||
| `primaryCtaText` | string | Yes | Primary button text |
|
||||
| `secondaryCtaUrl` | string | No | Secondary button URL |
|
||||
| `secondaryCtaText` | string | No | Secondary button text |
|
||||
| `enabled` | boolean | Yes | Show/hide the banner |
|
||||
| `activeUntil` | ISO 8601 | No | Auto-hide after this date |
|
||||
|
||||
### Behavior
|
||||
|
||||
- Banner is fetched during `prebuild-banner` target and saved to `src/content/banner.json` as a collection (array)
|
||||
- Uses Astro content collection with `file()` loader and schema validation
|
||||
- Requires rebuild/redeploy to update the banner
|
||||
- Users can dismiss the banner (stored in localStorage)
|
||||
- If `enabled` is `false` or `activeUntil` has passed, the banner won't show
|
||||
- If `BANNER_URL` is not set, an empty collection is generated
|
||||
@@ -1,158 +0,0 @@
|
||||
// @ts-check
|
||||
import { defineConfig } from 'astro/config';
|
||||
import starlight from '@astrojs/starlight';
|
||||
import netlify from '@astrojs/netlify';
|
||||
import react from '@astrojs/react';
|
||||
import markdoc from '@astrojs/markdoc';
|
||||
import tailwindcss from '@tailwindcss/vite';
|
||||
import { sidebar } from './sidebar.mts';
|
||||
|
||||
const BASE = '/docs';
|
||||
|
||||
// This is exposed as window.__CONFIG
|
||||
const PUBLIC_CONFIG = {
|
||||
cookiebotDisabled: process.env.COOKIEBOT_DISABLED === 'true',
|
||||
cookiebotId: process.env.COOKIEBOT_ID ?? null,
|
||||
gaMeasurementId: 'UA-88380372-10',
|
||||
gtmMeasurementId: 'GTM-KW8423B6',
|
||||
isProd: process.env.NODE_ENV === 'production',
|
||||
};
|
||||
|
||||
// https://astro.build/config
|
||||
export default defineConfig({
|
||||
base: BASE,
|
||||
vite: { plugins: [tailwindcss()] },
|
||||
// Allow this to be configured per environment for robots.txt detection
|
||||
// Note: this happens during build time so we don't use `import.meta.env`
|
||||
site: process.env.NX_DEV_URL ?? 'https://nx.dev',
|
||||
image: {
|
||||
service: {
|
||||
entrypoint: 'astro/assets/services/sharp',
|
||||
config: {
|
||||
limitInputPixels: false, // Disable pixel limit
|
||||
},
|
||||
},
|
||||
},
|
||||
trailingSlash: 'never',
|
||||
// This adapter doesn't support local previews, so only load it on Netlify.
|
||||
adapter: process.env['NETLIFY'] ? netlify() : undefined,
|
||||
integrations: [
|
||||
markdoc(),
|
||||
// https://starlight.astro.build/reference/configuration/
|
||||
starlight({
|
||||
title: 'Nx',
|
||||
tagline:
|
||||
'Get to green PRs in half the time. Nx optimizes your builds, scales your CI, and fixes failed PRs. Built for developers and AI agents.',
|
||||
customCss: ['./src/styles/global.css'],
|
||||
favicon: '/favicon.svg',
|
||||
logo: {
|
||||
light: './src/assets/nx/Nx-dark.png',
|
||||
dark: './src/assets/nx/Nx-light.png',
|
||||
replacesTitle: true,
|
||||
},
|
||||
disable404Route: true,
|
||||
head: [
|
||||
{
|
||||
tag: 'script',
|
||||
content: `window.__CONFIG = ${JSON.stringify(PUBLIC_CONFIG)};`,
|
||||
},
|
||||
...(process.env.COOKIEBOT_ID &&
|
||||
process.env.COOKIEBOT_DISABLED !== 'true'
|
||||
? [
|
||||
{
|
||||
/** @type {"script"} */
|
||||
tag: 'script',
|
||||
attrs: {
|
||||
id: 'Cookiebot',
|
||||
src: 'https://consent.cookiebot.com/uc.js',
|
||||
'data-cbid': process.env.COOKIEBOT_ID,
|
||||
'data-blockingmode': 'auto',
|
||||
type: 'text/javascript',
|
||||
},
|
||||
},
|
||||
]
|
||||
: []),
|
||||
{
|
||||
tag: 'script',
|
||||
attrs: {
|
||||
src: `${BASE}/global-scripts.js`,
|
||||
defer: true,
|
||||
},
|
||||
},
|
||||
],
|
||||
plugins: [],
|
||||
routeMiddleware: [
|
||||
// NOTE: this is responsibile for populating the Reference section
|
||||
// with generated routes from the nx-reference-packages content collection
|
||||
// since the sidebar doesn't auto generate w/ dynamic routes from src/pages/reference
|
||||
// only the src/content/docs/reference files
|
||||
'./src/plugins/sidebar-reference-updater.middleware.ts',
|
||||
'./src/plugins/sidebar-icons.middleware.ts',
|
||||
'./src/plugins/og.middleware.ts',
|
||||
'./src/plugins/github-stars.middleware.ts',
|
||||
'./src/plugins/raw-content.middleware.ts',
|
||||
'./src/plugins/canonical.middleware.ts',
|
||||
],
|
||||
markdown: {
|
||||
// this breaks the renderMarkdown function in the plugin loader due to starlight path normalization
|
||||
// as to _why_ it has to normalize a path?
|
||||
// idk just working around the issue for now but we'll want to have linked headers so will need to fix
|
||||
headingLinks: false,
|
||||
},
|
||||
social: [
|
||||
{ icon: 'github', label: 'GitHub', href: 'https://github.com/nrwl/nx' },
|
||||
{
|
||||
icon: 'youtube',
|
||||
label: 'YouTube',
|
||||
href: 'https://www.youtube.com/@NxDevtools?utm_source=nx.dev',
|
||||
},
|
||||
{
|
||||
icon: 'x.com',
|
||||
label: 'X',
|
||||
href: 'https://x.com/NxDevTools?utm_source=nx.dev',
|
||||
},
|
||||
{
|
||||
icon: 'discord',
|
||||
label: 'Discord',
|
||||
href: 'https://go.nx.dev/community',
|
||||
},
|
||||
],
|
||||
editLink: {
|
||||
baseUrl: 'https://github.com/nrwl/nx/tree/main/',
|
||||
},
|
||||
sidebar,
|
||||
components: {
|
||||
Header: './src/components/layout/Header.astro',
|
||||
Footer: './src/components/layout/Footer.astro',
|
||||
PageFrame: './src/components/layout/PageFrame.astro',
|
||||
Sidebar: './src/components/layout/Sidebar.astro',
|
||||
TwoColumnContent: './src/components/layout/TwoColumnContent.astro',
|
||||
PageTitle: './src/components/layout/PageTitle.astro',
|
||||
TableOfContents: './src/components/layout/TableOfContents.astro',
|
||||
},
|
||||
pagefind: {
|
||||
ranking: {
|
||||
// termFrequency changes the ranking balance between
|
||||
// frequency of the term relative to document length
|
||||
// versus weighted term count.
|
||||
// default is 1.0
|
||||
termFrequency: 0.75,
|
||||
// pageLength changes the way ranking compares page lengths with the average page lengths on your site.
|
||||
// default 0.75
|
||||
pageLength: 0.5,
|
||||
// termSaturation controls how quickly a term “saturates” on a page.
|
||||
// Once a term has appeared on a page many times,
|
||||
// further appearances have a reduced impact on the page rank.
|
||||
// default: 1.4
|
||||
// termSaturation: 1.4,
|
||||
// termSimilarity changes the ranking based on
|
||||
// similarity of terms to the search query.
|
||||
// Currently this only takes the length of the term into account.
|
||||
// default is 1.0
|
||||
// termSimilarity: 1.0,
|
||||
},
|
||||
},
|
||||
}),
|
||||
react(),
|
||||
],
|
||||
});
|
||||
@@ -1,45 +0,0 @@
|
||||
import { test, expect } from '@playwright/test';
|
||||
|
||||
test('links in descriptions of properties should correctly link to the same page w/ url fragments', async ({
|
||||
page,
|
||||
}) => {
|
||||
await page.goto('/docs/reference/devkit/NxJsonConfiguration');
|
||||
|
||||
await expect(
|
||||
page.getByRole('heading', { name: 'NxJsonConfiguration' })
|
||||
).toBeVisible();
|
||||
|
||||
await page
|
||||
.getByTestId('main-pane')
|
||||
.getByRole('link', { name: 'nxCloudAccessToken' })
|
||||
.click();
|
||||
|
||||
await expect(
|
||||
page.getByRole('heading', { name: 'nxCloudAccessToken' })
|
||||
).toBeVisible();
|
||||
|
||||
const description = page
|
||||
.getByRole('paragraph')
|
||||
.filter({ has: page.getByRole('link', { name: 'tasksRunnerOptions' }) })
|
||||
.first();
|
||||
await expect(description).toBeVisible();
|
||||
|
||||
const linkedProperty = description.getByRole('link', {
|
||||
name: 'tasksRunnerOptions',
|
||||
});
|
||||
|
||||
await expect(linkedProperty).toBeVisible();
|
||||
|
||||
await expect(linkedProperty).toHaveAttribute(
|
||||
'href',
|
||||
'/docs/reference/devkit/NxJsonConfiguration#tasksrunneroptions'
|
||||
);
|
||||
|
||||
await linkedProperty.click();
|
||||
|
||||
expect(page.url()).toContain('#tasksrunneroptions');
|
||||
|
||||
await expect(
|
||||
page.getByRole('heading', { name: 'tasksRunnerOptions' })
|
||||
).toBeVisible();
|
||||
});
|
||||
@@ -1,71 +0,0 @@
|
||||
import { test, expect } from '@playwright/test';
|
||||
|
||||
test('should apply system theme by default', async ({ page }) => {
|
||||
await page.goto('/docs/getting-started/intro');
|
||||
|
||||
await expect(
|
||||
page.getByRole('heading', { name: 'What is Nx?' })
|
||||
).toBeVisible();
|
||||
|
||||
const themeSelector = page.getByRole('combobox', {
|
||||
name: /theme/i,
|
||||
});
|
||||
|
||||
await expect(themeSelector).toBeVisible();
|
||||
|
||||
await expect(themeSelector).toHaveValue('auto');
|
||||
|
||||
const dataTheme = await page.evaluate(
|
||||
() => document.documentElement.dataset.theme
|
||||
);
|
||||
// The data-theme should be either 'light' or 'dark' based on system preference
|
||||
// It won't be 'auto' on the document element
|
||||
expect(['light', 'dark']).toContain(dataTheme);
|
||||
});
|
||||
|
||||
test('should switch to between light and dark theme', async ({ page }) => {
|
||||
await page.goto('/docs/getting-started/intro');
|
||||
|
||||
await expect(
|
||||
page.getByRole('heading', { name: 'What is Nx?' })
|
||||
).toBeVisible();
|
||||
|
||||
const themeSelector = page.getByRole('combobox', {
|
||||
name: /theme/i,
|
||||
});
|
||||
|
||||
await test.step('light theme renders', async () => {
|
||||
await expect(themeSelector).toBeVisible();
|
||||
|
||||
await themeSelector.selectOption('light');
|
||||
|
||||
await expect(themeSelector).toHaveValue('light');
|
||||
|
||||
const dataTheme = await page.evaluate(
|
||||
() => document.documentElement.dataset.theme
|
||||
);
|
||||
expect(dataTheme).toBe('light');
|
||||
});
|
||||
|
||||
await test.step('dark theme renders', async () => {
|
||||
await themeSelector.selectOption('dark');
|
||||
|
||||
await expect(themeSelector).toHaveValue('dark');
|
||||
|
||||
const dataTheme = await page.evaluate(
|
||||
() => document.documentElement.dataset.theme
|
||||
);
|
||||
expect(dataTheme).toBe('dark');
|
||||
});
|
||||
|
||||
await test.step('switch back to auto', async () => {
|
||||
await themeSelector.selectOption('auto');
|
||||
|
||||
await expect(themeSelector).toHaveValue('auto');
|
||||
|
||||
const dataTheme = await page.evaluate(
|
||||
() => document.documentElement.dataset.theme
|
||||
);
|
||||
expect(['light', 'dark']).toContain(dataTheme);
|
||||
});
|
||||
});
|
||||
@@ -1,129 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# | xargs -0 sed -i '' 's/<match>/<replace>/g'
|
||||
|
||||
# replace links that start with /concepts to /docs/concepts
|
||||
rg "\(/concepts" --type-add "mdoc:*mdoc" -t mdoc -l --null | xargs -0 sed -i '' 's|](/concepts|](/docs/concepts|g'
|
||||
# usage in link card aka href="/concepts/..."
|
||||
rg "=\"/concepts" --type-add "mdoc:*mdoc" -t mdoc -l --null | xargs -0 sed -i '' 's|="/concepts|="/docs/concepts|g'
|
||||
|
||||
# /recipes -> /docs/guides
|
||||
rg "\(/recipes" --type-add "mdoc:*mdoc" -t mdoc -l --null | xargs -0 sed -i '' 's|](/recipes|](/docs/guides|g'
|
||||
rg "=\"/recipes" --type-add "mdoc:*mdoc" -t mdoc -l --null | xargs -0 sed -i '' 's|="/recipes|="/docs/guides|g'
|
||||
|
||||
# /deprecated -> /docs/reference/deprecated
|
||||
rg "\(/deprecated" --type-add "mdoc:*mdoc" -t mdoc -l --null | xargs -0 sed -i '' 's|](/deprecated|](/docs/reference/deprecated|g'
|
||||
rg "=\"/deprecated" --type-add "mdoc:*mdoc" -t mdoc -l --null | xargs -0 sed -i '' 's|="/deprecated|="/docs/reference/deprecated|g'
|
||||
|
||||
# /troubleshooting -> /docs/troublshooting
|
||||
rg "\(/troubleshooting" --type-add "mdoc:*mdoc" -t mdoc -l --null | xargs -0 sed -i '' 's|](/troubleshooting|](/docs/troubleshooting|g'
|
||||
rg "=\"/troubleshooting" --type-add "mdoc:*mdoc" -t mdoc -l --null | xargs -0 sed -i '' 's|="/troubleshooting|="/docs/troubleshooting|g'
|
||||
|
||||
# /plugin-registry -> /docs/plugin-registry
|
||||
rg "\(/plugin-registry" --type-add "mdoc:*mdoc" -t mdoc -l --null | xargs -0 sed -i '' 's|](/plugin-registry|](/docs/plugin-registry|g'
|
||||
rg "=\"/plugin-registry" --type-add "mdoc:*mdoc" -t mdoc -l --null | xargs -0 sed -i '' 's|="/plugin-registry|="/docs/plugin-registry|g'
|
||||
|
||||
# /features -> /docs/features
|
||||
rg "\(/features" --type-add "mdoc:*mdoc" -t mdoc -l --null | xargs -0 sed -i '' 's|](/features|](/docs/features|g'
|
||||
rg "=\"/features" --type-add "mdoc:*mdoc" -t mdoc -l --null | xargs -0 sed -i '' 's|="/features|="/docs/features|g'
|
||||
|
||||
# /extending-nx -> /docs/extending-nx
|
||||
rg "\(/extending-nx" --type-add "mdoc:*mdoc" -t mdoc -l --null | xargs -0 sed -i '' 's|](/extending-nx|](/docs/extending-nx|g'
|
||||
rg "=\"/extending-nx" --type-add "mdoc:*mdoc" -t mdoc -l --null | xargs -0 sed -i '' 's|="/extending-nx|="/docs/extending-nx|g'
|
||||
rg "/extending-nx/recipes" --type-add "mdoc:*mdoc" -t mdoc -l --null | xargs -0 sed -i '' 's|/extending-nx/recipes|/extending-nx|g'
|
||||
|
||||
# /tech -> /docs/tech
|
||||
rg "\(/tech" --type-add "mdoc:*mdoc" -t mdoc -l --null | xargs -0 sed -i '' 's|](/tech|](/docs/tech|g'
|
||||
rg "=\"/tech" --type-add "mdoc:*mdoc" -t mdoc -l --null | xargs -0 sed -i '' 's|="/tech|="/docs/tech|g'
|
||||
|
||||
## /recipes/running-tasks -> /docs/guides/tasks--caching
|
||||
rg "\(/recipes/running-tasks" --type-add "mdoc:*mdoc" -t mdoc -l --null | xargs -0 sed -i '' 's|](/recipes/running-tasks|](/docs/guides/tasks--caching|g'
|
||||
rg "=\"/recipes/running-tasks" --type-add "mdoc:*mdoc" -t mdoc -l --null | xargs -0 sed -i '' 's|="/recipes/running-tasks|="/docs/guides/tasks--caching|g'
|
||||
|
||||
# /ci/features -> /docs/features/ci-features
|
||||
rg "\(/ci/features" --type-add "mdoc:*mdoc" -t mdoc -l --null | xargs -0 sed -i '' 's|](/ci/features|](/docs/features/ci-features|g'
|
||||
rg "=\"/ci/features" --type-add "mdoc:*mdoc" -t mdoc -l --null | xargs -0 sed -i '' 's|="/ci/features|="/docs/features/ci-features|g'
|
||||
|
||||
# /ci/concepts -> /docs/concepts/ci-concepts
|
||||
rg "\(/ci/concepts" --type-add "mdoc:*mdoc" -t mdoc -l --null | xargs -0 sed -i '' 's|](/ci/concepts|](/docs/concepts/ci-concepts|g'
|
||||
rg "=\"/ci/concepts" --type-add "mdoc:*mdoc" -t mdoc -l --null | xargs -0 sed -i '' 's|="/ci/concepts|="/docs/concepts/ci-concepts|g'
|
||||
|
||||
# /ci/guides/security -> /docs/guides/nx-cloud
|
||||
rg "\(/ci/guides/security" --type-add "mdoc:*mdoc" -t mdoc -l --null | xargs -0 sed -i '' 's|](/ci/guides/security|](/docs/guides/nx-cloud|g'
|
||||
rg "=\"/ci/guides/security" --type-add "mdoc:*mdoc" -t mdoc -l --null | xargs -0 sed -i '' 's|="/ci/guides/security|="/docs/guides/nx-cloud|g'
|
||||
rg "\(/ci/recipes/security" --type-add "mdoc:*mdoc" -t mdoc -l --null | xargs -0 sed -i '' 's|](/ci/recipes/security|](/docs/guides/nx-cloud|g'
|
||||
rg "=\"/ci/recipes/security" --type-add "mdoc:*mdoc" -t mdoc -l --null | xargs -0 sed -i '' 's|="/ci/recipes/security|="/docs/guides/nx-cloud|g'
|
||||
|
||||
# /ci/recipes/enterprise -> /docs/enterprise
|
||||
rg "\(/ci/recipes/enterprise" --type-add "mdoc:*mdoc" -t mdoc -l --null | xargs -0 sed -i '' 's|](/ci/recipes/enterprise|](/docs/enterprise|g'
|
||||
rg "=\"/ci/recipes/enterprise" --type-add "mdoc:*mdoc" -t mdoc -l --null | xargs -0 sed -i '' 's|="/ci/recipes/enterprise|="/docs/enterprise|g'
|
||||
|
||||
# /ci/recipes -> /docs/guides/nx-cloud
|
||||
rg "\(/ci/guides" --type-add "mdoc:*mdoc" -t mdoc -l --null | xargs -0 sed -i '' 's|](/ci/guides|](/docs/guides/nx-cloud|g'
|
||||
rg "=\"/ci/guides" --type-add "mdoc:*mdoc" -t mdoc -l --null | xargs -0 sed -i '' 's|="/ci/guides|="/docs/guides/nx-cloud|g'
|
||||
rg "\(/ci/recipes" --type-add "mdoc:*mdoc" -t mdoc -l --null | xargs -0 sed -i '' 's|](/ci/recipes|](/docs/guides/nx-cloud|g'
|
||||
rg "=\"/ci/recipes" --type-add "mdoc:*mdoc" -t mdoc -l --null | xargs -0 sed -i '' 's|="/ci/recipes|="/docs/guides/nx-cloud|g'
|
||||
|
||||
# /getting-started -> /docs/getting-started
|
||||
rg "\(/getting" --type-add "mdoc:*mdoc" -t mdoc -l --null | xargs -0 sed -i '' 's|](/getting|](/docs/getting|g'
|
||||
rg "=\"/getting" --type-add "mdoc:*mdoc" -t mdoc -l --null | xargs -0 sed -i '' 's|="/getting|="/docs/getting|g'
|
||||
|
||||
# /ci/recipes/set-up -> /docs/guides/nx-cloud/setup-ci
|
||||
rg "\(/ci/recipes/set-up" --type-add "mdoc:*mdoc" -t mdoc -l --null | xargs -0 sed -i '' 's|](/ci/recipes/set-up|](/docs/guides/nx-cloud/setup-ci|g'
|
||||
rg "=\"/ci/recipes/set-up" --type-add "mdoc:*mdoc" -t mdoc -l --null | xargs -0 sed -i '' 's|="/ci/recipes/set-up|="/docs/guides/nx-cloud/setup-ci|g'
|
||||
# I merged all the set-up ci guides into 1 page with tabs so we need to remove any links that go to specific guides
|
||||
rg "/monorepo-ci-" --type-add "mdoc:*mdoc" -t mdoc -l --null | xargs -0 sed -i '' 's|\(/[^)]*\)/monorepo-ci-[^)]*\()\)|\1\2|g'
|
||||
|
||||
# /ci/reference/nx-cloud-cli -> /docs/reference/nx-cloud-cli
|
||||
rg "\(/ci/reference/nx-cloud-cli" --type-add "mdoc:*mdoc" -t mdoc -l --null | xargs -0 sed -i '' 's|](/ci/reference/nx-cloud-cli|](/docs/reference/nx-cloud-cli|g'
|
||||
rg "=\"/ci/reference/nx-cloud-cli" --type-add "mdoc:*mdoc" -t mdoc -l --null | xargs -0 sed -i '' 's|="/ci/reference/nx-cloud-cli|="/docs/reference/nx-cloud-cli|g'
|
||||
|
||||
# /blog -> https://nx.dev/blog
|
||||
rg "\(/blog" --type-add "mdoc:*mdoc" -t mdoc -l --null | xargs -0 sed -i '' 's|](/blog|](https://nx.dev/blog|g'
|
||||
rg "=\"/blog" --type-add "mdoc:*mdoc" -t mdoc -l --null | xargs -0 sed -i '' 's|="/blog|="https://nx.dev/blog|g'
|
||||
|
||||
# /enterprise -> https://nx.dev/enterprise
|
||||
rg "\(/enterprise" --type-add "mdoc:*mdoc" -t mdoc -l --null | xargs -0 sed -i '' 's|](/enterprise|](https://nx.dev/enterprise|g'
|
||||
rg "=\"/enterprise" --type-add "mdoc:*mdoc" -t mdoc -l --null | xargs -0 sed -i '' 's|="/enterprise|="https://nx.dev/enterprise|g'
|
||||
|
||||
# /pricing -> https://nx.dev/pricing
|
||||
rg "\(/pricing" --type-add "mdoc:*mdoc" -t mdoc -l --null | xargs -0 sed -i '' 's|](/pricing|](https://nx.dev/pricing|g'
|
||||
rg "=\"/pricing" --type-add "mdoc:*mdoc" -t mdoc -l --null | xargs -0 sed -i '' 's|="/pricing|="https://nx.dev/pricing|g'
|
||||
|
||||
# /contact -> https://nx.dev/contact
|
||||
rg "\(/contact" --type-add "mdoc:*mdoc" -t mdoc -l --null | xargs -0 sed -i '' 's|](/contact|](https://nx.dev/contact|g'
|
||||
rg "=\"/contact" --type-add "mdoc:*mdoc" -t mdoc -l --null | xargs -0 sed -i '' 's|="/contact|="https://nx.dev/contact|g'
|
||||
|
||||
# /nx-cloud -> https://nx.dev/nx-cloud
|
||||
rg "\(/nx-cloud" --type-add "mdoc:*mdoc" -t mdoc -l --null | xargs -0 sed -i '' 's|](/nx-cloud|](https://nx.dev/nx-cloud|g'
|
||||
rg "=\"/nx-cloud" --type-add "mdoc:*mdoc" -t mdoc -l --null | xargs -0 sed -i '' 's|="/nx-cloud|="https://nx.dev/nx-cloud|g'
|
||||
|
||||
# /courses -> https://nx.dev/courses
|
||||
rg "\(/courses" --type-add "mdoc:*mdoc" -t mdoc -l --null | xargs -0 sed -i '' 's|](/courses|](https://nx.dev/courses|g'
|
||||
rg "=\"/courses" --type-add "mdoc:*mdoc" -t mdoc -l --null | xargs -0 sed -i '' 's|="/courses|="https://nx.dev/courses|g'
|
||||
# /community -> https://nx.dev/community
|
||||
rg "\(/community" --type-add "mdoc:*mdoc" -t mdoc -l --null | xargs -0 sed -i '' 's|](/community|](https://nx.dev/community|g'
|
||||
rg "=\"/community" --type-add "mdoc:*mdoc" -t mdoc -l --null | xargs -0 sed -i '' 's|="/community|="https://nx.dev/community|g'
|
||||
|
||||
# though these URLS that have `core-api` in them need to be special handled
|
||||
# but we can search for 'core-api' later and do a different replace mechinism
|
||||
# /reference -> /docs/reference
|
||||
rg "\(/reference" --type-add "mdoc:*mdoc" -t mdoc -l --null | xargs -0 sed -i '' 's|](/reference|](/docs/reference|g'
|
||||
rg "=\"/reference" --type-add "mdoc:*mdoc" -t mdoc -l --null | xargs -0 sed -i '' 's|="/reference|="/docs/reference|g'
|
||||
|
||||
# /docs/reference/core-api/nx/documents/:command -> /docs/reference/nx-commands#:command
|
||||
rg "\(/docs/reference/core-api/nx/documents/" --type-add "mdoc:*mdoc" -t mdoc -l --null | xargs -0 sed -i '' 's|](/docs/reference/core-api/nx/documents/|](/docs/reference/nx-commands#|g'
|
||||
rg "=\"/docs/reference/core-api/nx/documents/" --type-add "mdoc:*mdoc" -t mdoc -l --null | xargs -0 sed -i '' 's|="/docs/reference/core-api/nx/documents/|="/docs/reference/nx-commands#|g'
|
||||
|
||||
# /docs/reference/core-api/:remote-cache-plugin/overview -> /docs/reference/remote-cache-plugins/:remote-cache-plugin/overview
|
||||
# For s3-cache
|
||||
rg "/docs/reference/core-api/s3-cache" --type-add "mdoc:*mdoc" -t mdoc -l --null | xargs -0 sed -i '' 's|/docs/reference/core-api/s3-cache|/docs/reference/remote-cache-plugins/s3-cache|g'
|
||||
|
||||
# For azure-cache
|
||||
rg "/docs/reference/core-api/azure-cache" --type-add "mdoc:*mdoc" -t mdoc -l --null | xargs -0 sed -i '' 's|/docs/reference/core-api/azure-cache|/docs/reference/remote-cache-plugins/azure-cache|g'
|
||||
|
||||
# For gcs-cache
|
||||
rg "/docs/reference/core-api/gcs-cache" --type-add "mdoc:*mdoc" -t mdoc -l --null | xargs -0 sed -i '' 's|/docs/reference/core-api/gcs-cache|/docs/reference/remote-cache-plugins/gcs-cache|g'
|
||||
|
||||
# For shared-fs-cache
|
||||
rg "/docs/reference/core-api/shared-fs-cache" --type-add "mdoc:*mdoc" -t mdoc -l --null | xargs -0 sed -i '' 's|/docs/reference/core-api/shared-fs-cache|/docs/reference/remote-cache-plugins/shared-fs-cache|g'
|
||||
@@ -1,35 +0,0 @@
|
||||
const url = 'http://localhost:4321/docs';
|
||||
const timeout = 120000; // 2 minutes in milliseconds
|
||||
|
||||
console.log('starting up....');
|
||||
export default async function globalSetup() {
|
||||
const startTime = Date.now();
|
||||
const maxEndTime = startTime + timeout;
|
||||
|
||||
console.log(`Waiting for ${url} to be available...`);
|
||||
|
||||
while (Date.now() < maxEndTime) {
|
||||
try {
|
||||
const response = await fetch(url);
|
||||
if (response.ok) {
|
||||
console.log(`✓ Server is ready at ${url}`);
|
||||
return;
|
||||
}
|
||||
console.log(
|
||||
`Server responded with status ${response.status}, retrying...`
|
||||
);
|
||||
} catch (error) {
|
||||
// Server not available yet, continue polling
|
||||
const remainingTime = Math.round((maxEndTime - Date.now()) / 1000);
|
||||
if (remainingTime % 10 === 0 && remainingTime > 0) {
|
||||
console.log(`Still waiting... ${remainingTime} seconds remaining`);
|
||||
}
|
||||
}
|
||||
|
||||
await new Promise((resolve) => setTimeout(resolve, 1000));
|
||||
}
|
||||
|
||||
throw new Error(
|
||||
`Server at ${url} did not become available within ${timeout / 1000} seconds`
|
||||
);
|
||||
}
|
||||
@@ -1,427 +0,0 @@
|
||||
import {
|
||||
defineMarkdocConfig,
|
||||
component,
|
||||
Markdoc,
|
||||
} from '@astrojs/markdoc/config';
|
||||
import starlightMarkdoc from '@astrojs/starlight-markdoc';
|
||||
|
||||
export default defineMarkdocConfig({
|
||||
extends: [starlightMarkdoc()],
|
||||
tags: {
|
||||
call_to_action: {
|
||||
render: component('./src/components/markdoc/CallToAction.astro'),
|
||||
attributes: {
|
||||
url: {
|
||||
type: 'String',
|
||||
required: true,
|
||||
},
|
||||
title: {
|
||||
type: 'String',
|
||||
required: true,
|
||||
},
|
||||
description: {
|
||||
type: 'String',
|
||||
required: false,
|
||||
},
|
||||
icon: {
|
||||
type: 'String',
|
||||
required: false,
|
||||
},
|
||||
variant: {
|
||||
type: 'String',
|
||||
required: false,
|
||||
default: 'default',
|
||||
matches: [
|
||||
'default',
|
||||
'gradient',
|
||||
'inverted',
|
||||
'gradient-alt',
|
||||
'simple',
|
||||
],
|
||||
},
|
||||
size: {
|
||||
type: 'String',
|
||||
required: false,
|
||||
default: 'sm',
|
||||
matches: ['sm', 'md', 'lg'],
|
||||
},
|
||||
},
|
||||
},
|
||||
callout: {
|
||||
render: component('./src/components/markdoc/Callout.astro'),
|
||||
children: ['paragraph', 'tag', 'list'],
|
||||
attributes: {
|
||||
type: {
|
||||
type: 'String',
|
||||
default: 'note',
|
||||
matches: [
|
||||
'announcement',
|
||||
'caution',
|
||||
'check',
|
||||
'note',
|
||||
'warning',
|
||||
'deepdive',
|
||||
],
|
||||
errorLevel: 'critical',
|
||||
},
|
||||
title: {
|
||||
type: 'String',
|
||||
required: true,
|
||||
},
|
||||
expanded: {
|
||||
type: 'Boolean',
|
||||
default: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
card: {
|
||||
render: component('./src/components/markdoc/Card.astro'),
|
||||
attributes: {
|
||||
title: {
|
||||
type: 'String',
|
||||
required: true,
|
||||
},
|
||||
description: {
|
||||
type: 'String',
|
||||
default: '',
|
||||
},
|
||||
type: {
|
||||
type: 'String',
|
||||
default: 'documentation',
|
||||
},
|
||||
url: {
|
||||
type: 'String',
|
||||
default: '',
|
||||
},
|
||||
},
|
||||
},
|
||||
cards: {
|
||||
render: component('./src/components/markdoc/Cards.astro'),
|
||||
attributes: {
|
||||
cols: {
|
||||
type: 'Number',
|
||||
},
|
||||
smCols: {
|
||||
type: 'Number',
|
||||
},
|
||||
mdCols: {
|
||||
type: 'Number',
|
||||
},
|
||||
lgCols: {
|
||||
type: 'Number',
|
||||
},
|
||||
moreLink: {
|
||||
type: 'String',
|
||||
},
|
||||
},
|
||||
},
|
||||
course_video: {
|
||||
render: component('./src/components/markdoc/CourseVideo.astro'),
|
||||
attributes: {
|
||||
src: {
|
||||
type: 'String',
|
||||
required: true,
|
||||
},
|
||||
courseTitle: {
|
||||
type: 'String',
|
||||
required: true,
|
||||
},
|
||||
courseUrl: {
|
||||
type: 'String',
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
github_repository: {
|
||||
render: component('./src/components/markdoc/GithubRepository.astro'),
|
||||
attributes: {
|
||||
url: {
|
||||
type: 'String',
|
||||
required: true,
|
||||
},
|
||||
title: {
|
||||
type: 'String',
|
||||
required: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
graph: {
|
||||
render: component('./src/components/markdoc/Graph.astro'),
|
||||
attributes: {
|
||||
jsonFile: {
|
||||
type: 'String',
|
||||
},
|
||||
title: {
|
||||
type: 'String',
|
||||
},
|
||||
type: {
|
||||
type: 'String',
|
||||
matches: ['project', 'task'],
|
||||
default: 'project',
|
||||
},
|
||||
height: {
|
||||
type: 'String',
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
transform(node, config) {
|
||||
const attributes = node.transformAttributes(config);
|
||||
let rawContent = null;
|
||||
for (const child of node.children) {
|
||||
if (child.type === 'fence') {
|
||||
rawContent = child.attributes.content;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return new Markdoc.Tag(
|
||||
this.render,
|
||||
{
|
||||
...attributes,
|
||||
astroRawData: rawContent,
|
||||
},
|
||||
[]
|
||||
);
|
||||
},
|
||||
},
|
||||
iframe: {
|
||||
render: component('./src/components/markdoc/Iframe.astro'),
|
||||
attributes: {
|
||||
src: {
|
||||
type: 'String',
|
||||
required: true,
|
||||
},
|
||||
title: {
|
||||
type: 'String',
|
||||
required: true,
|
||||
},
|
||||
width: {
|
||||
type: 'String',
|
||||
default: '50%',
|
||||
},
|
||||
},
|
||||
},
|
||||
install_nx_console: {
|
||||
render: component('./src/components/markdoc/InstallNxConsole.astro'),
|
||||
attributes: {},
|
||||
},
|
||||
link_card: {
|
||||
render: component('./src/components/markdoc/LinkCard.astro'),
|
||||
attributes: {
|
||||
title: {
|
||||
type: 'String',
|
||||
required: true,
|
||||
},
|
||||
type: {
|
||||
type: 'String',
|
||||
required: true,
|
||||
},
|
||||
icon: {
|
||||
type: 'String',
|
||||
required: false,
|
||||
},
|
||||
url: {
|
||||
type: 'String',
|
||||
default: '',
|
||||
},
|
||||
appearance: {
|
||||
type: 'String',
|
||||
default: 'default',
|
||||
},
|
||||
},
|
||||
},
|
||||
index_page_cards: {
|
||||
render: component('./src/components/markdoc/IndexPageCards.astro'),
|
||||
attributes: {
|
||||
path: {
|
||||
type: 'String',
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
metrics: {
|
||||
render: component('./src/components/markdoc/Metrics.astro'),
|
||||
attributes: {
|
||||
metrics: {
|
||||
type: 'Array',
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
persona: {
|
||||
render: component('./src/components/markdoc/Persona.astro'),
|
||||
children: ['paragraph', 'tag', 'list'],
|
||||
attributes: {
|
||||
title: {
|
||||
type: 'String',
|
||||
},
|
||||
type: {
|
||||
type: 'String',
|
||||
default: 'integrated',
|
||||
required: true,
|
||||
matches: [
|
||||
'cache',
|
||||
'distribute',
|
||||
'javascript',
|
||||
'lerna',
|
||||
'react',
|
||||
'angular',
|
||||
'integrated',
|
||||
],
|
||||
errorLevel: 'critical',
|
||||
},
|
||||
url: {
|
||||
type: 'String',
|
||||
required: true,
|
||||
errorLevel: 'critical',
|
||||
},
|
||||
},
|
||||
},
|
||||
personas: {
|
||||
render: component('./src/components/markdoc/Personas.astro'),
|
||||
},
|
||||
pill: {
|
||||
render: component('./src/components/markdoc/Pill.astro'),
|
||||
attributes: {
|
||||
url: {
|
||||
type: 'String',
|
||||
default: '',
|
||||
},
|
||||
},
|
||||
},
|
||||
project_details: {
|
||||
render: component('./src/components/markdoc/ProjectDetails.astro'),
|
||||
children: [],
|
||||
attributes: {
|
||||
jsonFile: {
|
||||
type: 'String',
|
||||
},
|
||||
title: {
|
||||
type: 'String',
|
||||
},
|
||||
height: {
|
||||
type: 'String',
|
||||
},
|
||||
expandedTargets: {
|
||||
type: 'Array',
|
||||
},
|
||||
},
|
||||
transform(node, config) {
|
||||
const attributes = node.transformAttributes(config);
|
||||
let rawContent = null;
|
||||
for (const child of node.children) {
|
||||
if (child.type === 'fence') {
|
||||
rawContent = child.attributes.content;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return new Markdoc.Tag(
|
||||
this.render,
|
||||
{
|
||||
...attributes,
|
||||
astroRawData: rawContent,
|
||||
},
|
||||
[]
|
||||
);
|
||||
},
|
||||
},
|
||||
stackblitz_button: {
|
||||
render: component('./src/components/markdoc/StackblitzButton.astro'),
|
||||
attributes: {
|
||||
url: {
|
||||
type: 'String',
|
||||
required: true,
|
||||
},
|
||||
title: {
|
||||
type: 'String',
|
||||
required: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
testimonial: {
|
||||
render: component('./src/components/markdoc/Testimonial.astro'),
|
||||
children: ['paragraph'],
|
||||
attributes: {
|
||||
name: {
|
||||
type: 'String',
|
||||
},
|
||||
title: {
|
||||
type: 'String',
|
||||
},
|
||||
image: {
|
||||
type: 'String',
|
||||
},
|
||||
},
|
||||
},
|
||||
video_link: {
|
||||
render: component('./src/components/markdoc/VideoLink.astro'),
|
||||
attributes: {
|
||||
link: {
|
||||
type: 'String',
|
||||
required: true,
|
||||
},
|
||||
text: {
|
||||
type: 'String',
|
||||
required: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
video_player: {
|
||||
render: component('./src/components/markdoc/VideoPlayer.astro'),
|
||||
attributes: {
|
||||
src: {
|
||||
type: 'String',
|
||||
required: true,
|
||||
},
|
||||
alt: {
|
||||
type: 'String',
|
||||
required: false,
|
||||
},
|
||||
link: {
|
||||
type: 'String',
|
||||
required: false,
|
||||
},
|
||||
showDescription: {
|
||||
type: 'Boolean',
|
||||
required: false,
|
||||
default: false,
|
||||
},
|
||||
showControls: {
|
||||
type: 'Boolean',
|
||||
required: false,
|
||||
default: false,
|
||||
},
|
||||
autoPlay: {
|
||||
type: 'Boolean',
|
||||
required: false,
|
||||
default: false,
|
||||
},
|
||||
loop: {
|
||||
type: 'Boolean',
|
||||
required: false,
|
||||
default: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
youtube: {
|
||||
render: component('./src/components/markdoc/Youtube.astro'),
|
||||
attributes: {
|
||||
src: {
|
||||
type: 'String',
|
||||
required: true,
|
||||
},
|
||||
title: {
|
||||
type: 'String',
|
||||
required: true,
|
||||
},
|
||||
width: {
|
||||
type: 'String',
|
||||
default: '100%',
|
||||
},
|
||||
caption: {
|
||||
type: 'String',
|
||||
required: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
@@ -1,28 +0,0 @@
|
||||
# Permanent redirects (301 by default)
|
||||
|
||||
# Storybook docs consolidation
|
||||
[[redirects]]
|
||||
from = "/docs/technologies/test-tools/storybook/guides/storybook-9-setup"
|
||||
to = "/docs/technologies/test-tools/storybook/guides/upgrading-storybook"
|
||||
|
||||
[[redirects]]
|
||||
from = "/"
|
||||
to = "/docs/getting-started/intro"
|
||||
|
||||
[[redirects]]
|
||||
from = "/showcase"
|
||||
to = "/docs/quickstart"
|
||||
|
||||
[[redirects]]
|
||||
from = "/showcase/example-repos/*"
|
||||
to = "/docs/quickstart"
|
||||
|
||||
[[redirects]]
|
||||
from = "/showcase/benchmarks/*"
|
||||
to = "/docs/reference/benchmarks/:splat"
|
||||
|
||||
# Rewrite for base path handling (keeps URL the same)
|
||||
[[redirects]]
|
||||
from = "/docs/*"
|
||||
to = "/:splat"
|
||||
status = 200
|
||||
@@ -1,25 +0,0 @@
|
||||
{
|
||||
"name": "astro-docs",
|
||||
"version": "0.0.1",
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"@astrojs/check": "^0.7.0",
|
||||
"@astrojs/markdoc": "^0.15.0",
|
||||
"@astrojs/netlify": "^6.4.0",
|
||||
"@astrojs/react": "^4.3.0",
|
||||
"@astrojs/starlight": "0.34.6",
|
||||
"@astrojs/starlight-markdoc": "^0.4.0",
|
||||
"@astrojs/starlight-tailwind": "^4.0.1",
|
||||
"@nx/nx-dev-feature-analytics": "workspace:*",
|
||||
"@nx/nx-dev-ui-animations": "workspace:*",
|
||||
"@nx/nx-dev-ui-common": "workspace:*",
|
||||
"@nx/nx-dev-ui-icons": "workspace:*",
|
||||
"@nx/nx-dev-ui-markdoc": "workspace:*",
|
||||
"@tailwindcss/vite": "^4.1.11",
|
||||
"astro": "^5.10.1",
|
||||
"astro-og-canvas": "^0.7.0",
|
||||
"canvaskit-wasm": "^0.40.0",
|
||||
"octokit": "^2.0.14",
|
||||
"tailwindcss": "4.1.11"
|
||||
}
|
||||
}
|
||||
@@ -1,42 +0,0 @@
|
||||
import { defineConfig, devices } from '@playwright/test';
|
||||
import { nxE2EPreset } from '@nx/playwright/preset';
|
||||
import { workspaceRoot } from '@nx/devkit';
|
||||
import { join } from 'path';
|
||||
|
||||
// For CI, you may want to set BASE_URL to the deployed application.
|
||||
const baseURL = process.env['BASE_URL'] || 'http://localhost:4321';
|
||||
const reportDir = join(
|
||||
workspaceRoot,
|
||||
'dist',
|
||||
'astro-docs',
|
||||
'playwright-report'
|
||||
);
|
||||
|
||||
export default defineConfig({
|
||||
...nxE2EPreset(__filename, { testDir: './e2e' }),
|
||||
reporter: [
|
||||
['list', { printSteps: true }],
|
||||
['html', { outputFolder: reportDir, open: 'never' }],
|
||||
[
|
||||
'junit',
|
||||
{
|
||||
// JUnit only respects the outputFile option, and not outputDir or outputFolder
|
||||
outputFile: `${reportDir}/test-e2e-nx-cloud.xml`,
|
||||
},
|
||||
],
|
||||
],
|
||||
/* Global setup to wait for server */
|
||||
globalSetup: require.resolve('./global-setup.e2e.ts'),
|
||||
/* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */
|
||||
use: {
|
||||
baseURL,
|
||||
/* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */
|
||||
trace: 'on-first-retry',
|
||||
},
|
||||
projects: [
|
||||
{
|
||||
name: 'chromium',
|
||||
use: { ...devices['Desktop Chrome'] },
|
||||
},
|
||||
],
|
||||
});
|
||||
@@ -1,113 +0,0 @@
|
||||
{
|
||||
"name": "astro-docs",
|
||||
"$schema": "../node_modules/nx/schemas/project-schema.json",
|
||||
"comment": "package.json#scripts runs in the project root directory with astro assumes is where the node_modules is. which fails. so run the scripts in project.json#targets with --root command instead",
|
||||
"targets": {
|
||||
"prebuild-banner": {
|
||||
"cache": false,
|
||||
"outputs": ["{projectRoot}/src/content/banner.json"],
|
||||
"command": "node ../scripts/documentation/prebuild-banner.mjs",
|
||||
"options": {
|
||||
"cwd": "astro-docs",
|
||||
"env": {
|
||||
"BANNER_OUTPUT_PATH": "src/content/banner.json",
|
||||
"BANNER_ENV_VAR": "BANNER_URL"
|
||||
}
|
||||
}
|
||||
},
|
||||
"serve": {
|
||||
"continuous": true,
|
||||
"dependsOn": [
|
||||
"prebuild-banner",
|
||||
{
|
||||
"projects": ["devkit", "create-nx-workspace", "dotnet", "maven"],
|
||||
"target": "build"
|
||||
}
|
||||
],
|
||||
"command": "astro dev",
|
||||
"options": {
|
||||
"cwd": "astro-docs"
|
||||
}
|
||||
},
|
||||
"build": {
|
||||
"dependsOn": [
|
||||
"prebuild-banner",
|
||||
{
|
||||
"projects": ["devkit", "create-nx-workspace", "dotnet", "maven"],
|
||||
"target": "build"
|
||||
}
|
||||
],
|
||||
"inputs": [
|
||||
"production",
|
||||
"^production",
|
||||
"{projectRoot}/src/content/banner.json",
|
||||
{ "env": "NX_DEV_URL" }
|
||||
],
|
||||
"outputs": [
|
||||
"{projectRoot}/dist",
|
||||
"{projectRoot}/.astro",
|
||||
"{projectRoot}/.netlify"
|
||||
],
|
||||
"command": "astro build",
|
||||
"options": {
|
||||
"cwd": "astro-docs"
|
||||
}
|
||||
},
|
||||
"preview": {
|
||||
"dependsOn": ["build"],
|
||||
"command": "astro preview",
|
||||
"continuous": true,
|
||||
"options": {
|
||||
"cwd": "astro-docs"
|
||||
}
|
||||
},
|
||||
"astro": {
|
||||
"command": "astro",
|
||||
"options": {
|
||||
"cwd": "astro-docs"
|
||||
}
|
||||
},
|
||||
"test": {
|
||||
"executor": "nx:noop",
|
||||
"dependsOn": ["vite:test", "validate-links", "format"]
|
||||
},
|
||||
"pw-e2e": {
|
||||
"dependsOn": ["serve"],
|
||||
"parallelism": true
|
||||
},
|
||||
"e2e-ci--**/*": {
|
||||
"dependsOn": ["preview"],
|
||||
"parallelism": true,
|
||||
"options": {
|
||||
"args": []
|
||||
}
|
||||
},
|
||||
"show-report": {
|
||||
"command": "playwright show-report dist/astro-docs/playwright-report"
|
||||
},
|
||||
"validate-links": {
|
||||
"dependsOn": ["build"],
|
||||
"cache": true,
|
||||
"inputs": [
|
||||
"{projectRoot}/src/**/*",
|
||||
"{projectRoot}/astro.config.mjs",
|
||||
"{projectRoot}/sidebar.mts",
|
||||
"{projectRoot}/markdoc.config.mjs",
|
||||
"{projectRoot}/tsconfig.json",
|
||||
"{projectRoot}/package.json"
|
||||
],
|
||||
"command": "tsx validate-links.ts",
|
||||
"options": {
|
||||
"cwd": "astro-docs"
|
||||
}
|
||||
},
|
||||
"format": {
|
||||
"cache": true,
|
||||
"//": "nx format doesn't respect overrides, so we manually run prettier for mdoc files",
|
||||
"command": "prettier **/*.mdoc --check"
|
||||
},
|
||||
"format:write": {
|
||||
"command": "prettier **/*.mdoc --write"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
<svg role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><title>Nx</title><path d="M11.987 14.138l-3.132 4.923-5.193-8.427-.012 8.822H0V4.544h3.691l5.247 8.833.005-3.998 3.044 4.759zm.601-5.761c.024-.048 0-3.784.008-3.833h-3.65c.002.059-.005 3.776-.003 3.833h3.645zm5.634 4.134a2.061 2.061 0 0 0-1.969 1.336 1.963 1.963 0 0 1 2.343-.739c.396.161.917.422 1.33.283a2.1 2.1 0 0 0-1.704-.88zm3.39 1.061c-.375-.13-.8-.277-1.109-.681-.06-.08-.116-.17-.176-.265a2.143 2.143 0 0 0-.533-.642c-.294-.216-.68-.322-1.18-.322a2.482 2.482 0 0 0-2.294 1.536 2.325 2.325 0 0 1 4.002.388.75.75 0 0 0 .836.334c.493-.105.46.36 1.203.518v-.133c-.003-.446-.246-.55-.75-.733zm2.024 1.266a.723.723 0 0 0 .347-.638c-.01-2.957-2.41-5.487-5.37-5.487a5.364 5.364 0 0 0-4.487 2.418c-.01-.026-1.522-2.39-1.538-2.418H8.943l3.463 5.423-3.379 5.32h3.54l1.54-2.366 1.568 2.366h3.541l-3.21-5.052a.7.7 0 0 1-.084-.32 2.69 2.69 0 0 1 2.69-2.691h.001c1.488 0 1.736.89 2.057 1.308.634.826 1.9.464 1.9 1.541a.707.707 0 0 0 1.066.596zm.35.133c-.173.372-.56.338-.755.639-.176.271.114.412.114.412s.337.156.538-.311c.104-.231.14-.488.103-.74z"/></svg>
|
||||
|
Before Width: | Height: | Size: 1.1 KiB |
@@ -1,259 +0,0 @@
|
||||
(function () {
|
||||
// Open search modal if signaled via sessionStorage (e.g., from Cmd+K on non-docs pages)
|
||||
var SEARCH_STORAGE_KEY = 'nx-open-search';
|
||||
var SEARCH_EXPIRY_MS = 30000; // 30 seconds
|
||||
|
||||
function openSearchFromStorage() {
|
||||
var timestamp = sessionStorage.getItem(SEARCH_STORAGE_KEY);
|
||||
if (!timestamp) return;
|
||||
|
||||
// Clear immediately to prevent re-triggering
|
||||
sessionStorage.removeItem(SEARCH_STORAGE_KEY);
|
||||
|
||||
// Check if expired (older than 30 seconds)
|
||||
var age = Date.now() - parseInt(timestamp, 10);
|
||||
if (age > SEARCH_EXPIRY_MS) return;
|
||||
|
||||
var openSearchBtn = document.querySelector('button[data-open-modal]');
|
||||
if (openSearchBtn) {
|
||||
openSearchBtn.click();
|
||||
// Focus the search input after modal opens
|
||||
setTimeout(function () {
|
||||
var searchInput = document.querySelector('dialog[open] input');
|
||||
if (searchInput) {
|
||||
searchInput.focus();
|
||||
}
|
||||
}, 100);
|
||||
}
|
||||
}
|
||||
|
||||
// Check on load
|
||||
if (document.readyState === 'loading') {
|
||||
document.addEventListener('DOMContentLoaded', openSearchFromStorage);
|
||||
} else {
|
||||
// Small delay to ensure search component is initialized
|
||||
setTimeout(openSearchFromStorage, 100);
|
||||
}
|
||||
|
||||
const config = window.__CONFIG || {};
|
||||
if (!config.isProd) return;
|
||||
|
||||
const isCookiebotDisabled = config.cookiebotDisabled ?? false;
|
||||
const gaMeasurementId = config.gaMeasurementId ?? 'UA-88380372-10';
|
||||
const gtmMeasurementId = config.gtmMeasurementId ?? 'GTM-KW8423B6';
|
||||
|
||||
// Initialize global objects
|
||||
window.Cookiebot = window.Cookiebot || {};
|
||||
window.dataLayer = window.dataLayer || [];
|
||||
window.gtag =
|
||||
window.gtag ||
|
||||
function () {
|
||||
window.dataLayer.push(arguments);
|
||||
};
|
||||
|
||||
const loadGoogleAnalytics = () => {
|
||||
const script = document.createElement('script');
|
||||
script.src = `https://www.googletagmanager.com/gtag/js?id=${gaMeasurementId}`;
|
||||
script.async = true;
|
||||
document.head.appendChild(script);
|
||||
|
||||
// Initialize gtag
|
||||
window.gtag('js', new Date());
|
||||
window.gtag('config', gaMeasurementId, {
|
||||
page_path: window.location.pathname,
|
||||
});
|
||||
};
|
||||
|
||||
const loadGTM = () => {
|
||||
if (!gtmMeasurementId) return;
|
||||
|
||||
(function (w, d, s, l, i) {
|
||||
w[l] = w[l] || [];
|
||||
w[l].push({ 'gtm.start': new Date().getTime(), event: 'gtm.js' });
|
||||
var f = d.getElementsByTagName(s)[0],
|
||||
j = d.createElement(s),
|
||||
dl = l != 'dataLayer' ? '&l=' + l : '';
|
||||
j.async = true;
|
||||
j.src = 'https://www.googletagmanager.com/gtm.js?id=' + i + dl;
|
||||
f.parentNode.insertBefore(j, f);
|
||||
})(window, document, 'script', 'dataLayer', gtmMeasurementId);
|
||||
};
|
||||
|
||||
const loadHubSpot = () => {
|
||||
const hsScript = document.createElement('script');
|
||||
hsScript.src = 'https://js.hs-scripts.com/2757427.js';
|
||||
hsScript.async = true;
|
||||
hsScript.defer = true;
|
||||
document.head.appendChild(hsScript);
|
||||
|
||||
// Load HubSpot Forms
|
||||
const hsFormsScript = document.createElement('script');
|
||||
hsFormsScript.src = '//js.hsforms.net/forms/v2.js';
|
||||
hsFormsScript.async = true;
|
||||
hsFormsScript.defer = true;
|
||||
document.head.appendChild(hsFormsScript);
|
||||
};
|
||||
|
||||
const loadApollo = () => {
|
||||
const n = Math.random().toString(36).substring(7);
|
||||
const script = document.createElement('script');
|
||||
script.src = `https://assets.apollo.io/micro/website-tracker/tracker.iife.js?nocache=${n}`;
|
||||
script.async = true;
|
||||
script.defer = true;
|
||||
script.onload = function () {
|
||||
if (window.trackingFunctions?.onLoad) {
|
||||
window.trackingFunctions.onLoad({
|
||||
appId: '65e1db2f1976f30300fd8b26',
|
||||
});
|
||||
}
|
||||
};
|
||||
document.head.appendChild(script);
|
||||
};
|
||||
|
||||
const loadHotjar = () => {
|
||||
(function (h, o, t, j, a, r) {
|
||||
h.hj =
|
||||
h.hj ||
|
||||
function () {
|
||||
(h.hj.q = h.hj.q || []).push(arguments);
|
||||
};
|
||||
h._hjSettings = { hjid: 2774127, hjsv: 6 };
|
||||
a = o.getElementsByTagName('head')[0];
|
||||
r = o.createElement('script');
|
||||
r.async = 1;
|
||||
r.src = t + h._hjSettings.hjid + j + h._hjSettings.hjsv;
|
||||
a.appendChild(r);
|
||||
})(window, document, 'https://static.hotjar.com/c/hotjar-', '.js?sv=');
|
||||
};
|
||||
|
||||
const loadTwitterPixel = () => {
|
||||
!(function (e, t, n, s, u, a) {
|
||||
e.twq ||
|
||||
((s = e.twq =
|
||||
function () {
|
||||
s.exe ? s.exe.apply(s, arguments) : s.queue.push(arguments);
|
||||
}),
|
||||
(s.version = '1.1'),
|
||||
(s.queue = []),
|
||||
(u = t.createElement(n)),
|
||||
(u.async = !0),
|
||||
(u.src = 'https://static.ads-twitter.com/uwt.js'),
|
||||
(a = t.getElementsByTagName(n)[0]),
|
||||
a.parentNode.insertBefore(u, a));
|
||||
})(window, document, 'script');
|
||||
window.twq('config', 'obtp4');
|
||||
};
|
||||
|
||||
const SEARCH_DEBOUNCE_MS = 1000;
|
||||
let searchDebounceTimer;
|
||||
let lastSearchQuery = '';
|
||||
let currentSearchInput = null;
|
||||
let inputHandler = null;
|
||||
|
||||
function sendSearchEvent(eventType, data) {
|
||||
if (typeof window.gtag !== 'undefined')
|
||||
window.gtag('event', eventType, data);
|
||||
}
|
||||
|
||||
function trackSearchQuery(query) {
|
||||
if (!query || query === lastSearchQuery) return;
|
||||
|
||||
clearTimeout(searchDebounceTimer);
|
||||
searchDebounceTimer = setTimeout(() => {
|
||||
lastSearchQuery = query;
|
||||
sendSearchEvent('search_query', {
|
||||
query: query,
|
||||
});
|
||||
}, SEARCH_DEBOUNCE_MS);
|
||||
}
|
||||
|
||||
function setupSearchTracking() {
|
||||
const observer = new MutationObserver(() => {
|
||||
const searchDialog = document.querySelector(
|
||||
'dialog[open] .search-container'
|
||||
);
|
||||
// If dialog is found, then set up tracking
|
||||
if (searchDialog) {
|
||||
if (currentSearchInput && inputHandler) return; // Already tracking
|
||||
const searchInput = searchDialog.querySelector(
|
||||
'input[type="search"], input[type="text"]'
|
||||
);
|
||||
if (searchInput) {
|
||||
inputHandler = (e) => {
|
||||
const query = e.target.value.trim();
|
||||
trackSearchQuery(query);
|
||||
};
|
||||
searchInput.addEventListener('input', inputHandler);
|
||||
currentSearchInput = searchInput;
|
||||
}
|
||||
}
|
||||
// If dialog is not found but we have handler, etc. then it must be closed and we should clean up
|
||||
else if (currentSearchInput && inputHandler) {
|
||||
currentSearchInput.removeEventListener('input', inputHandler);
|
||||
currentSearchInput = null;
|
||||
inputHandler = null;
|
||||
}
|
||||
});
|
||||
|
||||
observer.observe(document.body, {
|
||||
childList: true,
|
||||
subtree: true,
|
||||
attributes: true,
|
||||
attributeFilter: ['open'],
|
||||
});
|
||||
}
|
||||
|
||||
const checkAndLoadScripts = () => {
|
||||
if (isCookiebotDisabled) {
|
||||
loadGoogleAnalytics();
|
||||
loadGTM();
|
||||
loadHubSpot();
|
||||
setupSearchTracking();
|
||||
} else if (window.Cookiebot && window.Cookiebot.consent) {
|
||||
// Statistics cookies (Google Analytics, GTM, Search Tracking)
|
||||
if (window.Cookiebot.consent.statistics) {
|
||||
loadGoogleAnalytics();
|
||||
loadGTM();
|
||||
setupSearchTracking();
|
||||
}
|
||||
|
||||
// Marketing cookies (HubSpot, Apollo, Hotjar, Twitter)
|
||||
if (window.Cookiebot.consent.marketing) {
|
||||
loadHubSpot();
|
||||
loadApollo();
|
||||
loadHotjar();
|
||||
loadTwitterPixel();
|
||||
}
|
||||
} else {
|
||||
// Wait for Cookiebot to load
|
||||
setTimeout(checkAndLoadScripts, 100);
|
||||
}
|
||||
};
|
||||
|
||||
// Add GTM noscript iframe to body
|
||||
const addGTMNoScript = () => {
|
||||
const noscript = document.createElement('noscript');
|
||||
const iframe = document.createElement('iframe');
|
||||
iframe.src = `https://www.googletagmanager.com/ns.html?id=${gtmMeasurementId}`;
|
||||
iframe.height = '0';
|
||||
iframe.width = '0';
|
||||
iframe.style.display = 'none';
|
||||
iframe.style.visibility = 'hidden';
|
||||
iframe.title = 'Google Tag Manager';
|
||||
noscript.appendChild(iframe);
|
||||
document.body.insertBefore(noscript, document.body.firstChild);
|
||||
};
|
||||
|
||||
// Listen for user consent to cookies
|
||||
window.addEventListener('CookiebotOnAccept', checkAndLoadScripts);
|
||||
|
||||
// Initial check
|
||||
checkAndLoadScripts();
|
||||
|
||||
// Add GTM noscript on DOM ready
|
||||
if (document.readyState === 'loading') {
|
||||
document.addEventListener('DOMContentLoaded', addGTMNoScript);
|
||||
} else {
|
||||
addGTMNoScript();
|
||||
}
|
||||
})();
|
||||
@@ -1 +0,0 @@
|
||||
<svg role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><title>Angular</title><path d="M16.712 17.711H7.288l-1.204 2.916L12 24l5.916-3.373-1.204-2.916ZM14.692 0l7.832 16.855.814-12.856L14.692 0ZM9.308 0 .662 3.999l.814 12.856L9.308 0Zm-.405 13.93h6.198L12 6.396 8.903 13.93Z"/></svg>
|
||||
|
Before Width: | Height: | Size: 299 B |
@@ -1,3 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="size-6">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="m21 7.5-9-5.25L3 7.5m18 0-9 5.25m9-5.25v9l-9 5.25M3 7.5l9 5.25M3 7.5v9l9 5.25m0-9v9" />
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 284 B |
@@ -1 +0,0 @@
|
||||
<svg role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><title>C#</title><path d="M1.194 7.543v8.913c0 1.103.588 2.122 1.544 2.674l7.718 4.456a3.086 3.086 0 0 0 3.088 0l7.718-4.456a3.087 3.087 0 0 0 1.544-2.674V7.543a3.084 3.084 0 0 0-1.544-2.673L13.544.414a3.086 3.086 0 0 0-3.088 0L2.738 4.87a3.085 3.085 0 0 0-1.544 2.673Zm5.403 2.914v3.087a.77.77 0 0 0 .772.772.773.773 0 0 0 .772-.772.773.773 0 0 1 1.317-.546.775.775 0 0 1 .226.546 2.314 2.314 0 1 1-4.631 0v-3.087c0-.615.244-1.203.679-1.637a2.312 2.312 0 0 1 3.274 0c.434.434.678 1.023.678 1.637a.769.769 0 0 1-.226.545.767.767 0 0 1-1.091 0 .77.77 0 0 1-.226-.545.77.77 0 0 0-.772-.772.771.771 0 0 0-.772.772Zm12.35 3.087a.77.77 0 0 1-.772.772h-.772v.772a.773.773 0 0 1-1.544 0v-.772h-1.544v.772a.773.773 0 0 1-1.317.546.775.775 0 0 1-.226-.546v-.772H12a.771.771 0 1 1 0-1.544h.772v-1.543H12a.77.77 0 1 1 0-1.544h.772v-.772a.773.773 0 0 1 1.317-.546.775.775 0 0 1 .226.546v.772h1.544v-.772a.773.773 0 0 1 1.544 0v.772h.772a.772.772 0 0 1 0 1.544h-.772v1.543h.772a.776.776 0 0 1 .772.772Zm-3.088-2.315h-1.544v1.543h1.544v-1.543Z"/></svg>
|
||||
|
Before Width: | Height: | Size: 1.1 KiB |
@@ -1 +0,0 @@
|
||||
<svg role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><title>.NET</title><path d="M24 8.77h-2.468v7.565h-1.425V8.77h-2.462V7.53H24zm-6.852 7.565h-4.821V7.53h4.63v1.24h-3.205v2.494h2.953v1.234h-2.953v2.604h3.396zm-6.708 0H8.882L4.78 9.863a2.896 2.896 0 0 1-.258-.51h-.036c.032.189.048.592.048 1.21v5.772H3.157V7.53h1.659l3.965 6.32c.167.261.275.442.323.54h.024c-.04-.233-.06-.629-.06-1.185V7.529h1.372zm-8.703-.693a.868.829 0 0 1-.869.829.868.829 0 0 1-.868-.83.868.829 0 0 1 .868-.828.868.829 0 0 1 .869.829Z"/></svg>
|
||||
|
Before Width: | Height: | Size: 534 B |
@@ -1 +0,0 @@
|
||||
<svg role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><title>ESLint</title><path d="M7.257 9.132L11.816 6.5a.369.369 0 0 1 .368 0l4.559 2.632a.369.369 0 0 1 .184.32v5.263a.37.37 0 0 1-.184.319l-4.559 2.632a.369.369 0 0 1-.368 0l-4.559-2.632a.369.369 0 0 1-.184-.32V9.452a.37.37 0 0 1 .184-.32M23.852 11.53l-5.446-9.475c-.198-.343-.564-.596-.96-.596H6.555c-.396 0-.762.253-.96.596L.149 11.509a1.127 1.127 0 0 0 0 1.117l5.447 9.398c.197.342.563.517.959.517h10.893c.395 0 .76-.17.959-.512l5.446-9.413a1.069 1.069 0 0 0 0-1.086m-4.51 4.556a.4.4 0 0 1-.204.338L12.2 20.426a.395.395 0 0 1-.392 0l-6.943-4.002a.4.4 0 0 1-.205-.338V8.08c0-.14.083-.269.204-.338L11.8 3.74c.12-.07.272-.07.392 0l6.943 4.003a.4.4 0 0 1 .206.338z"/></svg>
|
||||
|
Before Width: | Height: | Size: 743 B |
@@ -1 +0,0 @@
|
||||
<svg role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><title>F#</title><path d="M0 12 11.39.61v5.695L5.695 12l5.695 5.695v5.695L0 12zm7.322 0 4.068-4.068v8.136L7.322 12zM24 12 12.203.61v5.695L17.898 12l-5.695 5.695v5.695L24 12z"/></svg>
|
||||
|
Before Width: | Height: | Size: 253 B |
@@ -1 +0,0 @@
|
||||
<svg fill="#000000" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M 16.921875 2.25 C 16.71679725 2.26171875 16.4970705 2.3408205 16.2890625 2.5078125 C 15.40722675 3.2138669999999996 15.541992 3.5771482499999996 15.1171875 4.4296875 C 14.973633 4.9248045 14.736328499999999 4.962891 14.53125 4.5234375 C 14.28515625 4.08691425 14.16503925 3.5419919999999996 13.78125 3.2109375 C 13.16308575 2.67773475 12.4658205 3.0791017500000004 12.84375 3.6796875 C 13.2216795 4.28027325 13.376953499999999 4.91308575 13.5234375 5.90625 C 13.74316425 7.3857420000000005 13.125 9.03222675 12.3046875 9.8203125 C 10.822266 6.7880857500000005 8.885742 4.53808575 7.5234375 3.84375 C 7.1103517499999995 3.6328125 6.984375 3.80859375 6.984375 4.0078125 C 7.2421875 6.978516000000001 7.3359375 9.02929725 7.171875 10.546875 C 7.0986329999999995 11.2265625 5.49609375 13.734375 5.578125 14.3203125 C 5.66015625 14.9033205 6.12890625 15.817383 6.4453125 16.2890625 C 6.31640625 16.1953125 5.99121075 16.4091795 6.0703125 16.7109375 C 5.49902325 17.03027325 5.551758 17.51953125 6.140625 17.6484375 C 6.29296875 18.0439455 6.3251954999999995 18.24023475 6.75 18.421875 C 6.66796875 19.25683575 6.580078500000001 20.11523475 6.4921875 21.046875 C 6.873047250000001 22.921875 9.776367 19.67871075 10.1484375 19.40625 C 12.161133 17.9296875 12.46875 21.15234375 13.875 21.65625 C 16.2421875 22.5029295 15.474609749999999 17.52246075 13.5703125 12.6328125 C 13.34472675 9.489258 14.40234375 8.59277325 15.421875 8.1796875 C 15.958008 8.00390625 16.3564455 7.96875 17.0859375 8.1796875 C 18.33984375 8.54003925 18.60058575 7.11328125 17.484375 6.9375 C 17.0595705 6.8701170000000005 16.7519535 6.8759767499999995 16.359375 6.703125 C 16.5175785 6.0732420000000005 17.14453125 6.041016000000001 17.765625 5.953125 C 19.17773475 5.75390625 19.0546875 4.23046875 17.484375 4.59375 C 16.7988285 4.754883 16.49121075 5.16210975 16.2421875 5.15625 C 16.56152325 4.573242 17.10058575 4.072266 17.625 3.328125 C 18.0175785 2.7685545 17.5341795 2.21484375 16.921875 2.25 Z M 9.6328125 7.734375 C 9.817383 7.7109375 9.978516 7.72265625 10.1484375 7.78125 C 10.8251955 8.009766 11.05371075 8.87109375 10.640625 9.6796875 C 10.22753925 10.48828125 9.3251955 10.9394535 8.6484375 10.7109375 C 7.9716795000000005 10.48242225 7.7666017499999995 9.64453125 8.1796875 8.8359375 C 8.49023475 8.229492 9.07910175 7.8076170000000005 9.6328125 7.734375 Z M 8.90625 8.8359375 C 8.80371075 8.838867 8.698242 8.89746075 8.6015625 9 C 8.4082035 9.208008 8.34375 9.55078125 8.4609375 9.75 C 8.5810545 9.94921875 8.8300785 9.9345705 9.0234375 9.7265625 C 9.21679725 9.5185545 9.2841795 9.17578125 9.1640625 8.9765625 C 9.10546875 8.8769535 9.00878925 8.833008 8.90625 8.8359375 Z M 11.390625 10.7578125 C 12.521484749999999 12.919922249999999 13.587890999999999 15.48046875 13.8046875 18.3984375 C 13.90722675 19.78710975 12.791015999999999 18.28710975 12.65625 18.046875 C 10.359375 13.91015625 7.4091795000000005 22.40625 7.9921875 17.0859375 C 8.2939455 14.89453125 8.4404295 14.604492 8.5078125 12.046875 C 8.5078125 12.046875 10.265625 12.963867 11.390625 10.7578125 Z M 7.21875 13.2890625 C 7.1630857500000005 14.0126955 7.1484375 14.490234749999999 7.078125 15.234375 C 6.9228517499999995 14.830078499999999 6.7177732500000005 14.7890625 6.609375 14.4140625 C 6.8349607500000005 14.16796875 6.990234750000001 13.6875 7.21875 13.2890625 Z"/></svg>
|
||||
|
Before Width: | Height: | Size: 3.3 KiB |
@@ -1,18 +0,0 @@
|
||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<g clip-path="url(#clip0_1244_718)">
|
||||
<path d="M9.35205 3.72154V7.35041L12.0002 8.93803M9.35205 3.72154L12.0002 2.13391L14.6483 3.72154M9.35205 3.72154L12.0002 5.08236M12.0002 8.93803L14.6483 7.35041V3.72154M12.0002 8.93803V5.08236M14.6483 3.72154L12.0002 5.08236" stroke="black" stroke-width="0.5" stroke-linejoin="round"/>
|
||||
<path d="M8.3335 3.26804L12.0002 1L15.6668 3.26804V7.80412L12.0002 10.0722L8.3335 7.80412V3.26804Z" stroke="black" stroke-width="0.5" stroke-linejoin="round"/>
|
||||
<path d="M2.01855 15.2888V18.9177L4.6667 20.5053M2.01855 15.2888L4.6667 13.7012L7.31485 15.2888M2.01855 15.2888L4.6667 16.8764M4.6667 20.5053L7.31485 18.9177V15.2888M4.6667 20.5053V16.8764M7.31485 15.2888L4.6667 16.8764" stroke="black" stroke-width="0.5" stroke-linejoin="round"/>
|
||||
<path d="M1 14.8349L4.66667 12.5669L8.33333 14.8349V19.371L4.66667 21.6391L1 19.371V14.8349Z" stroke="black" stroke-width="0.5" stroke-linejoin="round"/>
|
||||
<path d="M16.6855 15.2888V18.9177L19.3337 20.5053M16.6855 15.2888L19.3337 13.7012L21.9818 15.2888M16.6855 15.2888L19.3337 16.6496M19.3337 20.5053L21.9818 18.9177V15.2888M19.3337 20.5053V16.6496M21.9818 15.2888L19.3337 16.6496" stroke="black" stroke-width="0.5" stroke-linejoin="round"/>
|
||||
<path d="M15.6665 14.8349L19.3332 12.5669L22.9998 14.8349V19.371L19.3332 21.6391L15.6665 19.371V14.8349Z" stroke="black" stroke-width="0.5" stroke-linejoin="round"/>
|
||||
<path d="M8.33317 6.89685L4.6665 9.16489V12.567" stroke="black" stroke-width="0.5" stroke-linejoin="round"/>
|
||||
<path d="M15.6668 6.89685L19.3335 9.16489V12.567" stroke="black" stroke-width="0.5" stroke-linejoin="round"/>
|
||||
<path d="M7.51855 19.8248L12 23.0001L16.4815 19.8248" stroke="black" stroke-width="0.5" stroke-linejoin="round"/>
|
||||
</g>
|
||||
<defs>
|
||||
<clipPath id="clip0_1244_718">
|
||||
<rect width="24" height="24" fill="white"/>
|
||||
</clipPath>
|
||||
</defs>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 1.9 KiB |
@@ -1 +0,0 @@
|
||||
<svg role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><title>Node.js</title><path d="M11.998,24c-0.321,0-0.641-0.084-0.922-0.247l-2.936-1.737c-0.438-0.245-0.224-0.332-0.08-0.383 c0.585-0.203,0.703-0.25,1.328-0.604c0.065-0.037,0.151-0.023,0.218,0.017l2.256,1.339c0.082,0.045,0.197,0.045,0.272,0l8.795-5.076 c0.082-0.047,0.134-0.141,0.134-0.238V6.921c0-0.099-0.053-0.192-0.137-0.242l-8.791-5.072c-0.081-0.047-0.189-0.047-0.271,0 L3.075,6.68C2.99,6.729,2.936,6.825,2.936,6.921v10.15c0,0.097,0.054,0.189,0.139,0.235l2.409,1.392 c1.307,0.654,2.108-0.116,2.108-0.89V7.787c0-0.142,0.114-0.253,0.256-0.253h1.115c0.139,0,0.255,0.112,0.255,0.253v10.021 c0,1.745-0.95,2.745-2.604,2.745c-0.508,0-0.909,0-2.026-0.551L2.28,18.675c-0.57-0.329-0.922-0.945-0.922-1.604V6.921 c0-0.659,0.353-1.275,0.922-1.603l8.795-5.082c0.557-0.315,1.296-0.315,1.848,0l8.794,5.082c0.57,0.329,0.924,0.944,0.924,1.603 v10.15c0,0.659-0.354,1.273-0.924,1.604l-8.794,5.078C12.643,23.916,12.324,24,11.998,24z M19.099,13.993 c0-1.9-1.284-2.406-3.987-2.763c-2.731-0.361-3.009-0.548-3.009-1.187c0-0.528,0.235-1.233,2.258-1.233 c1.807,0,2.473,0.389,2.747,1.607c0.024,0.115,0.129,0.199,0.247,0.199h1.141c0.071,0,0.138-0.031,0.186-0.081 c0.048-0.054,0.074-0.123,0.067-0.196c-0.177-2.098-1.571-3.076-4.388-3.076c-2.508,0-4.004,1.058-4.004,2.833 c0,1.925,1.488,2.457,3.895,2.695c2.88,0.282,3.103,0.703,3.103,1.269c0,0.983-0.789,1.402-2.642,1.402 c-2.327,0-2.839-0.584-3.011-1.742c-0.02-0.124-0.126-0.215-0.253-0.215h-1.137c-0.141,0-0.254,0.112-0.254,0.253 c0,1.482,0.806,3.248,4.655,3.248C17.501,17.007,19.099,15.91,19.099,13.993z"/></svg>
|
||||
|
Before Width: | Height: | Size: 1.6 KiB |
@@ -1 +0,0 @@
|
||||
<svg role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><title>React</title><path d="M14.23 12.004a2.236 2.236 0 0 1-2.235 2.236 2.236 2.236 0 0 1-2.236-2.236 2.236 2.236 0 0 1 2.235-2.236 2.236 2.236 0 0 1 2.236 2.236zm2.648-10.69c-1.346 0-3.107.96-4.888 2.622-1.78-1.653-3.542-2.602-4.887-2.602-.41 0-.783.093-1.106.278-1.375.793-1.683 3.264-.973 6.365C1.98 8.917 0 10.42 0 12.004c0 1.59 1.99 3.097 5.043 4.03-.704 3.113-.39 5.588.988 6.38.32.187.69.275 1.102.275 1.345 0 3.107-.96 4.888-2.624 1.78 1.654 3.542 2.603 4.887 2.603.41 0 .783-.09 1.106-.275 1.374-.792 1.683-3.263.973-6.365C22.02 15.096 24 13.59 24 12.004c0-1.59-1.99-3.097-5.043-4.032.704-3.11.39-5.587-.988-6.38-.318-.184-.688-.277-1.092-.278zm-.005 1.09v.006c.225 0 .406.044.558.127.666.382.955 1.835.73 3.704-.054.46-.142.945-.25 1.44-.96-.236-2.006-.417-3.107-.534-.66-.905-1.345-1.727-2.035-2.447 1.592-1.48 3.087-2.292 4.105-2.295zm-9.77.02c1.012 0 2.514.808 4.11 2.28-.686.72-1.37 1.537-2.02 2.442-1.107.117-2.154.298-3.113.538-.112-.49-.195-.964-.254-1.42-.23-1.868.054-3.32.714-3.707.19-.09.4-.127.563-.132zm4.882 3.05c.455.468.91.992 1.36 1.564-.44-.02-.89-.034-1.345-.034-.46 0-.915.01-1.36.034.44-.572.895-1.096 1.345-1.565zM12 8.1c.74 0 1.477.034 2.202.093.406.582.802 1.203 1.183 1.86.372.64.71 1.29 1.018 1.946-.308.655-.646 1.31-1.013 1.95-.38.66-.773 1.288-1.18 1.87-.728.063-1.466.098-2.21.098-.74 0-1.477-.035-2.202-.093-.406-.582-.802-1.204-1.183-1.86-.372-.64-.71-1.29-1.018-1.946.303-.657.646-1.313 1.013-1.954.38-.66.773-1.286 1.18-1.868.728-.064 1.466-.098 2.21-.098zm-3.635.254c-.24.377-.48.763-.704 1.16-.225.39-.435.782-.635 1.174-.265-.656-.49-1.31-.676-1.947.64-.15 1.315-.283 2.015-.386zm7.26 0c.695.103 1.365.23 2.006.387-.18.632-.405 1.282-.66 1.933-.2-.39-.41-.783-.64-1.174-.225-.392-.465-.774-.705-1.146zm3.063.675c.484.15.944.317 1.375.498 1.732.74 2.852 1.708 2.852 2.476-.005.768-1.125 1.74-2.857 2.475-.42.18-.88.342-1.355.493-.28-.958-.646-1.956-1.1-2.98.45-1.017.81-2.01 1.085-2.964zm-13.395.004c.278.96.645 1.957 1.1 2.98-.45 1.017-.812 2.01-1.086 2.964-.484-.15-.944-.318-1.37-.5-1.732-.737-2.852-1.706-2.852-2.474 0-.768 1.12-1.742 2.852-2.476.42-.18.88-.342 1.356-.494zm11.678 4.28c.265.657.49 1.312.676 1.948-.64.157-1.316.29-2.016.39.24-.375.48-.762.705-1.158.225-.39.435-.788.636-1.18zm-9.945.02c.2.392.41.783.64 1.175.23.39.465.772.705 1.143-.695-.102-1.365-.23-2.006-.386.18-.63.406-1.282.66-1.933zM17.92 16.32c.112.493.2.968.254 1.423.23 1.868-.054 3.32-.714 3.708-.147.09-.338.128-.563.128-1.012 0-2.514-.807-4.11-2.28.686-.72 1.37-1.536 2.02-2.44 1.107-.118 2.154-.3 3.113-.54zm-11.83.01c.96.234 2.006.415 3.107.532.66.905 1.345 1.727 2.035 2.446-1.595 1.483-3.092 2.295-4.11 2.295-.22-.005-.406-.05-.553-.132-.666-.38-.955-1.834-.73-3.703.054-.46.142-.944.25-1.438zm4.56.64c.44.02.89.034 1.345.034.46 0 .915-.01 1.36-.034-.44.572-.895 1.095-1.345 1.565-.455-.47-.91-.993-1.36-1.565z"/></svg>
|
||||
|
Before Width: | Height: | Size: 2.9 KiB |
@@ -1,3 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="size-6">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M9.75 3.104v5.714a2.25 2.25 0 0 1-.659 1.591L5 14.5M9.75 3.104c-.251.023-.501.05-.75.082m.75-.082a24.301 24.301 0 0 1 4.5 0m0 0v5.714c0 .597.237 1.17.659 1.591L19.8 15.3M14.25 3.104c.251.023.501.05.75.082M19.8 15.3l-1.57.393A9.065 9.065 0 0 1 12 15a9.065 9.065 0 0 0-6.23-.693L5 14.5m14.8.8 1.402 1.402c1.232 1.232.65 3.318-1.067 3.611A48.309 48.309 0 0 1 12 21c-2.773 0-5.491-.235-8.135-.687-1.718-.293-2.3-2.379-1.067-3.61L5 14.5" />
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 632 B |
@@ -1,4 +0,0 @@
|
||||
<svg role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
|
||||
<title>TypeScript</title>
|
||||
<path d="M0 12v12h24V0H0zm19.341-.956c.61.152 1.074.423 1.501.865.221.236.549.666.575.77.008.03-1.036.73-1.668 1.123-.023.015-.115-.084-.217-.236-.31-.45-.633-.644-1.128-.678-.728-.05-1.196.331-1.192.967a.88.88 0 0 0 .102.45c.16.331.458.53 1.39.933 1.719.74 2.454 1.227 2.911 1.92.51.773.625 2.008.278 2.926-.38.998-1.325 1.676-2.655 1.9-.411.073-1.386.062-1.828-.018-.964-.172-1.878-.648-2.442-1.273-.221-.243-.652-.88-.625-.925.011-.016.11-.077.22-.141.108-.061.511-.294.892-.515l.69-.4.145.214c.202.308.643.731.91.872.766.404 1.817.347 2.335-.118a.883.883 0 0 0 .313-.72c0-.278-.035-.4-.18-.61-.186-.266-.567-.49-1.649-.96-1.238-.533-1.771-.864-2.259-1.39a3.165 3.165 0 0 1-.659-1.2c-.091-.339-.114-1.189-.042-1.531.255-1.197 1.158-2.03 2.461-2.278.423-.08 1.406-.05 1.821.053zm-5.634 1.002l.008.983H10.59v8.876H8.38v-8.876H5.258v-.964c0-.534.011-.98.026-.99.012-.016 1.913-.024 4.217-.02l4.195.012z"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 1019 B |
@@ -1 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" role="img" viewBox="0 0 24 24"><title>Visual Basic</title><path d="M6.363 17.719a7.57 7.57 0 0 1 .34-1.348L10.887 4.5h1.863l-5.473 15h-1.91L0 4.5h1.934l4.09 11.895c.078.218.14.437.187.656s.098.441.152.668zM20.66 11.53c.5.063.957.188 1.371.375s.766.442 1.055.762.512.691.668 1.113.238.89.246 1.406c0 .696-.133 1.31-.398 1.84s-.622.98-1.067 1.348-.96.645-1.547.832-1.203.285-1.851.293h-4.371v-15h4.265c.54 0 1.059.066 1.559.2s.95.335 1.348.609.714.628.949 1.066.355.957.363 1.559c0 .859-.227 1.601-.68 2.226s-1.09 1.067-1.91 1.324v.047zm-4.137-.597h1.793c.43 0 .832-.051 1.207-.153s.704-.258.985-.469.5-.488.656-.832.238-.746.246-1.207c0-.43-.078-.785-.234-1.066s-.367-.504-.633-.668-.57-.277-.914-.34-.707-.097-1.09-.105h-2.016v4.84zm2.38 6.972c.437 0 .85-.05 1.242-.152s.738-.262 1.043-.48.539-.5.703-.844.254-.762.27-1.254c0-.54-.102-.98-.306-1.324s-.476-.614-.82-.809-.73-.332-1.16-.41-.875-.117-1.336-.117h-2.016v5.39h2.38z"/></svg>
|
||||
|
Before Width: | Height: | Size: 975 B |
@@ -1 +0,0 @@
|
||||
<svg role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><title>Vue.js</title><path d="M24,1.61H14.06L12,5.16,9.94,1.61H0L12,22.39ZM12,14.08,5.16,2.23H9.59L12,6.41l2.41-4.18h4.43Z"/></svg>
|
||||
|
Before Width: | Height: | Size: 202 B |
|
Before Width: | Height: | Size: 78 KiB |
|
Before Width: | Height: | Size: 334 KiB |
|
Before Width: | Height: | Size: 172 KiB |
|
Before Width: | Height: | Size: 18 KiB |
|
Before Width: | Height: | Size: 196 KiB |
|
Before Width: | Height: | Size: 408 KiB |
|
Before Width: | Height: | Size: 149 KiB |
@@ -1 +0,0 @@
|
||||
<svg role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><title>Nx</title><path d="M11.987 14.138l-3.132 4.923-5.193-8.427-.012 8.822H0V4.544h3.691l5.247 8.833.005-3.998 3.044 4.759zm.601-5.761c.024-.048 0-3.784.008-3.833h-3.65c.002.059-.005 3.776-.003 3.833h3.645zm5.634 4.134a2.061 2.061 0 0 0-1.969 1.336 1.963 1.963 0 0 1 2.343-.739c.396.161.917.422 1.33.283a2.1 2.1 0 0 0-1.704-.88zm3.39 1.061c-.375-.13-.8-.277-1.109-.681-.06-.08-.116-.17-.176-.265a2.143 2.143 0 0 0-.533-.642c-.294-.216-.68-.322-1.18-.322a2.482 2.482 0 0 0-2.294 1.536 2.325 2.325 0 0 1 4.002.388.75.75 0 0 0 .836.334c.493-.105.46.36 1.203.518v-.133c-.003-.446-.246-.55-.75-.733zm2.024 1.266a.723.723 0 0 0 .347-.638c-.01-2.957-2.41-5.487-5.37-5.487a5.364 5.364 0 0 0-4.487 2.418c-.01-.026-1.522-2.39-1.538-2.418H8.943l3.463 5.423-3.379 5.32h3.54l1.54-2.366 1.568 2.366h3.541l-3.21-5.052a.7.7 0 0 1-.084-.32 2.69 2.69 0 0 1 2.69-2.691h.001c1.488 0 1.736.89 2.057 1.308.634.826 1.9.464 1.9 1.541a.707.707 0 0 0 1.066.596zm.35.133c-.173.372-.56.338-.755.639-.176.271.114.412.114.412s.337.156.538-.311c.104-.231.14-.488.103-.74z"/></svg>
|
||||
|
Before Width: | Height: | Size: 1.1 KiB |
|
Before Width: | Height: | Size: 68 KiB |
|
Before Width: | Height: | Size: 15 KiB |
|
Before Width: | Height: | Size: 112 KiB |
|
Before Width: | Height: | Size: 7.7 MiB |
|
Before Width: | Height: | Size: 231 KiB |
@@ -1,6 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<sitemapindex xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
|
||||
<sitemap>
|
||||
<loc>https://nx.dev/docs/sitemap-0.xml</loc>
|
||||
</sitemap>
|
||||
</sitemapindex>
|
||||
@@ -1,249 +0,0 @@
|
||||
import type { StarlightUserConfig } from '@astrojs/starlight/types';
|
||||
import { getPluginItems } from './src/plugins/utils/plugin-mappings';
|
||||
|
||||
export const sidebar: StarlightUserConfig['sidebar'] = [
|
||||
{
|
||||
label: 'Getting Started',
|
||||
collapsed: false,
|
||||
autogenerate: { directory: 'getting-started', collapsed: true },
|
||||
},
|
||||
{
|
||||
label: 'Features',
|
||||
collapsed: false,
|
||||
autogenerate: { directory: 'features', collapsed: true },
|
||||
},
|
||||
{
|
||||
label: 'Core Guides',
|
||||
collapsed: true,
|
||||
autogenerate: { directory: 'guides', collapsed: true },
|
||||
},
|
||||
{
|
||||
label: 'Core Concepts',
|
||||
collapsed: true,
|
||||
autogenerate: { directory: 'concepts', collapsed: true },
|
||||
},
|
||||
{
|
||||
label: 'Technologies',
|
||||
collapsed: false,
|
||||
// manually type the tech routes due to complexity of order and structure
|
||||
items: [
|
||||
{
|
||||
label: 'TypeScript',
|
||||
collapsed: true,
|
||||
items: getPluginItems('js'),
|
||||
},
|
||||
{
|
||||
label: 'Angular',
|
||||
collapsed: true,
|
||||
items: [
|
||||
...getPluginItems('angular'),
|
||||
{
|
||||
label: 'Angular Rspack',
|
||||
collapsed: true,
|
||||
items: getPluginItems('angular-rspack', 'angular'),
|
||||
},
|
||||
{
|
||||
label: 'Angular Rsbuild',
|
||||
collapsed: true,
|
||||
items: getPluginItems('angular-rsbuild', 'angular'),
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
label: 'React',
|
||||
collapsed: true,
|
||||
items: [
|
||||
...getPluginItems('react'),
|
||||
{
|
||||
label: 'Next',
|
||||
collapsed: true,
|
||||
items: getPluginItems('next', 'react'),
|
||||
},
|
||||
{
|
||||
label: 'Remix',
|
||||
collapsed: true,
|
||||
items: getPluginItems('remix', 'react'),
|
||||
},
|
||||
{
|
||||
label: 'React Native',
|
||||
collapsed: true,
|
||||
items: getPluginItems('react-native', 'react'),
|
||||
},
|
||||
{
|
||||
label: 'Expo',
|
||||
collapsed: true,
|
||||
items: getPluginItems('expo', 'react'),
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
label: 'Vue',
|
||||
collapsed: true,
|
||||
items: [
|
||||
...getPluginItems('vue'),
|
||||
{
|
||||
label: 'Nuxt',
|
||||
collapsed: true,
|
||||
items: getPluginItems('nuxt', 'vue'),
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
label: 'Node.js',
|
||||
collapsed: true,
|
||||
items: [
|
||||
...getPluginItems('node'),
|
||||
{
|
||||
label: 'Express',
|
||||
collapsed: true,
|
||||
items: getPluginItems('express', 'node'),
|
||||
},
|
||||
{
|
||||
label: 'Nest',
|
||||
collapsed: true,
|
||||
items: getPluginItems('nest', 'node'),
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
label: 'Java',
|
||||
collapsed: true,
|
||||
items: [
|
||||
{
|
||||
label: 'Introduction',
|
||||
link: 'technologies/java/introduction',
|
||||
},
|
||||
{
|
||||
label: 'Gradle',
|
||||
collapsed: true,
|
||||
items: getPluginItems('gradle', 'java'),
|
||||
},
|
||||
{
|
||||
label: 'Maven',
|
||||
collapsed: true,
|
||||
items: getPluginItems('maven', 'java'),
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
label: '.NET',
|
||||
collapsed: true,
|
||||
items: getPluginItems('dotnet'),
|
||||
},
|
||||
{
|
||||
label: 'Module Federation',
|
||||
collapsed: true,
|
||||
items: getPluginItems('module-federation'),
|
||||
},
|
||||
{
|
||||
label: 'ESLint',
|
||||
collapsed: true,
|
||||
items: [
|
||||
...getPluginItems('eslint'),
|
||||
{
|
||||
label: 'ESLint Plugin',
|
||||
collapsed: true,
|
||||
items: getPluginItems('eslint-plugin', 'eslint'),
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
label: 'Build Tools',
|
||||
collapsed: true,
|
||||
items: [
|
||||
{
|
||||
label: 'Webpack',
|
||||
collapsed: true,
|
||||
items: getPluginItems('webpack', 'build-tools'),
|
||||
},
|
||||
{
|
||||
label: 'Vite',
|
||||
collapsed: true,
|
||||
items: getPluginItems('vite', 'build-tools'),
|
||||
},
|
||||
{
|
||||
label: 'Rollup',
|
||||
collapsed: true,
|
||||
items: getPluginItems('rollup', 'build-tools'),
|
||||
},
|
||||
{
|
||||
label: 'ESBuild',
|
||||
collapsed: true,
|
||||
items: getPluginItems('esbuild', 'build-tools'),
|
||||
},
|
||||
{
|
||||
label: 'Rspack',
|
||||
collapsed: true,
|
||||
items: getPluginItems('rspack', 'build-tools'),
|
||||
},
|
||||
{
|
||||
label: 'Rsbuild',
|
||||
collapsed: true,
|
||||
items: getPluginItems('rsbuild', 'build-tools'),
|
||||
},
|
||||
{
|
||||
label: 'Docker',
|
||||
collapsed: true,
|
||||
items: getPluginItems('docker', 'build-tools'),
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
label: 'Test Tools',
|
||||
collapsed: true,
|
||||
items: [
|
||||
{
|
||||
label: 'Cypress',
|
||||
collapsed: true,
|
||||
items: getPluginItems('cypress', 'test-tools'),
|
||||
},
|
||||
{
|
||||
label: 'Vitest',
|
||||
collapsed: true,
|
||||
items: getPluginItems('vitest', 'test-tools'),
|
||||
},
|
||||
{
|
||||
label: 'Jest',
|
||||
collapsed: true,
|
||||
items: getPluginItems('jest', 'test-tools'),
|
||||
},
|
||||
{
|
||||
label: 'Playwright',
|
||||
collapsed: true,
|
||||
items: getPluginItems('playwright', 'test-tools'),
|
||||
},
|
||||
{
|
||||
label: 'Storybook',
|
||||
collapsed: true,
|
||||
items: getPluginItems('storybook', 'test-tools'),
|
||||
},
|
||||
{
|
||||
label: 'Detox',
|
||||
collapsed: true,
|
||||
items: getPluginItems('detox', 'test-tools'),
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
label: 'Enterprise',
|
||||
collapsed: true,
|
||||
autogenerate: { directory: 'enterprise', collapsed: true },
|
||||
},
|
||||
{
|
||||
label: 'Extending Nx',
|
||||
collapsed: true,
|
||||
autogenerate: { directory: 'extending-nx', collapsed: true },
|
||||
},
|
||||
{
|
||||
label: 'Reference',
|
||||
collapsed: false,
|
||||
autogenerate: { directory: 'reference', collapsed: true },
|
||||
},
|
||||
{
|
||||
label: 'Troubleshooting',
|
||||
collapsed: false,
|
||||
autogenerate: { directory: 'troubleshooting', collapsed: true },
|
||||
},
|
||||
];
|
||||
|
Before Width: | Height: | Size: 56 KiB |
|
Before Width: | Height: | Size: 334 KiB |
|
Before Width: | Height: | Size: 78 KiB |
@@ -1,233 +0,0 @@
|
||||
{
|
||||
"project": {
|
||||
"name": "myreactapp",
|
||||
"type": "app",
|
||||
"data": {
|
||||
"root": "apps/myreactapp",
|
||||
"targets": {
|
||||
"build": {
|
||||
"options": {
|
||||
"cwd": "apps/myreactapp",
|
||||
"command": "vite build"
|
||||
},
|
||||
"cache": true,
|
||||
"dependsOn": ["^build"],
|
||||
"inputs": [
|
||||
"production",
|
||||
"^production",
|
||||
{
|
||||
"externalDependencies": ["vite"]
|
||||
}
|
||||
],
|
||||
"outputs": ["{workspaceRoot}/dist/apps/myreactapp"],
|
||||
"executor": "nx:run-commands",
|
||||
"configurations": {},
|
||||
"metadata": {
|
||||
"technologies": ["vite"]
|
||||
}
|
||||
},
|
||||
"serve": {
|
||||
"options": {
|
||||
"cwd": "apps/myreactapp",
|
||||
"command": "vite serve",
|
||||
"continuous": true
|
||||
},
|
||||
"executor": "nx:run-commands",
|
||||
"configurations": {},
|
||||
"metadata": {
|
||||
"technologies": ["vite"]
|
||||
}
|
||||
},
|
||||
"preview": {
|
||||
"options": {
|
||||
"cwd": "apps/myreactapp",
|
||||
"command": "vite preview"
|
||||
},
|
||||
"executor": "nx:run-commands",
|
||||
"configurations": {},
|
||||
"metadata": {
|
||||
"technologies": ["vite"]
|
||||
}
|
||||
},
|
||||
"serve-static": {
|
||||
"executor": "@nx/web:file-server",
|
||||
"options": {
|
||||
"buildTarget": "build",
|
||||
"continuous": true
|
||||
},
|
||||
"configurations": {}
|
||||
},
|
||||
"test": {
|
||||
"options": {
|
||||
"cwd": "apps/myreactapp",
|
||||
"command": "vitest run"
|
||||
},
|
||||
"cache": true,
|
||||
"inputs": [
|
||||
"default",
|
||||
"^production",
|
||||
{
|
||||
"externalDependencies": ["vitest"]
|
||||
}
|
||||
],
|
||||
"outputs": ["{workspaceRoot}/coverage/apps/myreactapp"],
|
||||
"executor": "nx:run-commands",
|
||||
"configurations": {},
|
||||
"metadata": {
|
||||
"technologies": ["vite"]
|
||||
}
|
||||
},
|
||||
"lint": {
|
||||
"cache": true,
|
||||
"options": {
|
||||
"cwd": "apps/myreactapp",
|
||||
"command": "eslint ."
|
||||
},
|
||||
"inputs": [
|
||||
"default",
|
||||
"{workspaceRoot}/.eslintrc.json",
|
||||
"{workspaceRoot}/apps/myreactapp/.eslintrc.json",
|
||||
"{workspaceRoot}/tools/eslint-rules/**/*",
|
||||
{
|
||||
"externalDependencies": ["eslint"]
|
||||
}
|
||||
],
|
||||
"executor": "nx:run-commands",
|
||||
"configurations": {},
|
||||
"metadata": {
|
||||
"technologies": ["eslint"]
|
||||
}
|
||||
}
|
||||
},
|
||||
"name": "myreactapp",
|
||||
"$schema": "../../../node_modules/nx/schemas/project-schema.json",
|
||||
"sourceRoot": "apps/myreactapp/src",
|
||||
"projectType": "application",
|
||||
"tags": [],
|
||||
"implicitDependencies": [],
|
||||
"metadata": {
|
||||
"technologies": ["react"]
|
||||
}
|
||||
}
|
||||
},
|
||||
"sourceMap": {
|
||||
"root": ["apps/myreactapp/project.json", "nx/core/project-json"],
|
||||
"targets": ["apps/myreactapp/project.json", "nx/core/project-json"],
|
||||
"targets.build": ["apps/myreactapp/vite.config.ts", "@nx/vite/plugin"],
|
||||
"targets.build.command": [
|
||||
"apps/myreactapp/vite.config.ts",
|
||||
"@nx/vite/plugin"
|
||||
],
|
||||
"targets.build.options": [
|
||||
"apps/myreactapp/vite.config.ts",
|
||||
"@nx/vite/plugin"
|
||||
],
|
||||
"targets.build.cache": [
|
||||
"apps/myreactapp/vite.config.ts",
|
||||
"@nx/vite/plugin"
|
||||
],
|
||||
"targets.build.dependsOn": [
|
||||
"apps/myreactapp/vite.config.ts",
|
||||
"@nx/vite/plugin"
|
||||
],
|
||||
"targets.build.inputs": [
|
||||
"apps/myreactapp/vite.config.ts",
|
||||
"@nx/vite/plugin"
|
||||
],
|
||||
"targets.build.outputs": [
|
||||
"apps/myreactapp/vite.config.ts",
|
||||
"@nx/vite/plugin"
|
||||
],
|
||||
"targets.build.options.cwd": [
|
||||
"apps/myreactapp/vite.config.ts",
|
||||
"@nx/vite/plugin"
|
||||
],
|
||||
"targets.serve": ["apps/myreactapp/vite.config.ts", "@nx/vite/plugin"],
|
||||
"targets.serve.command": [
|
||||
"apps/myreactapp/vite.config.ts",
|
||||
"@nx/vite/plugin"
|
||||
],
|
||||
"targets.serve.options": [
|
||||
"apps/myreactapp/vite.config.ts",
|
||||
"@nx/vite/plugin"
|
||||
],
|
||||
"targets.serve.options.cwd": [
|
||||
"apps/myreactapp/vite.config.ts",
|
||||
"@nx/vite/plugin"
|
||||
],
|
||||
"targets.preview": ["apps/myreactapp/vite.config.ts", "@nx/vite/plugin"],
|
||||
"targets.preview.command": [
|
||||
"apps/myreactapp/vite.config.ts",
|
||||
"@nx/vite/plugin"
|
||||
],
|
||||
"targets.preview.options": [
|
||||
"apps/myreactapp/vite.config.ts",
|
||||
"@nx/vite/plugin"
|
||||
],
|
||||
"targets.preview.options.cwd": [
|
||||
"apps/myreactapp/vite.config.ts",
|
||||
"@nx/vite/plugin"
|
||||
],
|
||||
"targets.serve-static": [
|
||||
"apps/myreactapp/vite.config.ts",
|
||||
"@nx/vite/plugin"
|
||||
],
|
||||
"targets.serve-static.executor": [
|
||||
"apps/myreactapp/vite.config.ts",
|
||||
"@nx/vite/plugin"
|
||||
],
|
||||
"targets.serve-static.options": [
|
||||
"apps/myreactapp/vite.config.ts",
|
||||
"@nx/vite/plugin"
|
||||
],
|
||||
"targets.serve-static.options.buildTarget": [
|
||||
"apps/myreactapp/vite.config.ts",
|
||||
"@nx/vite/plugin"
|
||||
],
|
||||
"targets.test": ["apps/myreactapp/vite.config.ts", "@nx/vite/plugin"],
|
||||
"targets.test.command": [
|
||||
"apps/myreactapp/vite.config.ts",
|
||||
"@nx/vite/plugin"
|
||||
],
|
||||
"targets.test.options": [
|
||||
"apps/myreactapp/vite.config.ts",
|
||||
"@nx/vite/plugin"
|
||||
],
|
||||
"targets.test.cache": ["apps/myreactapp/vite.config.ts", "@nx/vite/plugin"],
|
||||
"targets.test.inputs": [
|
||||
"apps/myreactapp/vite.config.ts",
|
||||
"@nx/vite/plugin"
|
||||
],
|
||||
"targets.test.outputs": [
|
||||
"apps/myreactapp/vite.config.ts",
|
||||
"@nx/vite/plugin"
|
||||
],
|
||||
"targets.test.options.cwd": [
|
||||
"apps/myreactapp/vite.config.ts",
|
||||
"@nx/vite/plugin"
|
||||
],
|
||||
"targets.lint": ["apps/myreactapp/project.json", "@nx/eslint/plugin"],
|
||||
"targets.lint.command": [
|
||||
"apps/myreactapp/project.json",
|
||||
"@nx/eslint/plugin"
|
||||
],
|
||||
"targets.lint.cache": ["apps/myreactapp/project.json", "@nx/eslint/plugin"],
|
||||
"targets.lint.options": [
|
||||
"apps/myreactapp/project.json",
|
||||
"@nx/eslint/plugin"
|
||||
],
|
||||
"targets.lint.inputs": [
|
||||
"apps/myreactapp/project.json",
|
||||
"@nx/eslint/plugin"
|
||||
],
|
||||
"targets.lint.options.cwd": [
|
||||
"apps/myreactapp/project.json",
|
||||
"@nx/eslint/plugin"
|
||||
],
|
||||
"name": ["apps/myreactapp/project.json", "nx/core/project-json"],
|
||||
"$schema": ["apps/myreactapp/project.json", "nx/core/project-json"],
|
||||
"sourceRoot": ["apps/myreactapp/project.json", "nx/core/project-json"],
|
||||
"projectType": ["apps/myreactapp/project.json", "nx/core/project-json"],
|
||||
"tags": ["apps/myreactapp/project.json", "nx/core/project-json"]
|
||||
}
|
||||
}
|
||||