Compare commits
71 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 2c9ed8fc67 | |||
| 5eedb37285 | |||
| 508d91e4dc | |||
| 8eed5808bc | |||
| db7ef37596 | |||
| cd7f2ba224 | |||
| 7992b7aa8f | |||
| 684a357f65 | |||
| 6337e5423b | |||
| b8bf803963 | |||
| 3f0b2dc716 | |||
| e966be7545 | |||
| f4892c5c58 | |||
| 5d6a2dd669 | |||
| c29dc0a67a | |||
| a10a4201b8 | |||
| 8808cb7c1f | |||
| 6ce05845d0 | |||
| f0a5c2f728 | |||
| 3012dba2d0 | |||
| f834ffe9a7 | |||
| 7cc121c010 | |||
| 53e07ca01a | |||
| 859c082e06 | |||
| 5991bf5df9 | |||
| 9b0fb37eb6 | |||
| 46848b9b8d | |||
| b8ee55b1cc | |||
| 42c2d0dc45 | |||
| d53e008d5f | |||
| e2a6b3e551 | |||
| b9be698f13 | |||
| 5df65700b9 | |||
| ad01165391 | |||
| 1cf850f964 | |||
| 11ba75f4e4 | |||
| b001a4529b | |||
| 8c7edfb431 | |||
| 758c5a6f13 | |||
| be3e3dc3d9 | |||
| 0b143a7306 | |||
| 3aaedd3d57 | |||
| f0779ee7bd | |||
| b6abd81bc5 | |||
| 3781cfeaec | |||
| d5b829e62f | |||
| b848dd47f5 | |||
| 3e88dcecca | |||
| 63465ad044 | |||
| 2b371eabc4 | |||
| 7c6cbbf339 | |||
| 2953a17906 | |||
| 9bcb39364f | |||
| ae7de55920 | |||
| afab5299d0 | |||
| 2f1d887032 | |||
| c4eff655c4 | |||
| 2abc3c6d7a | |||
| 8b64caaaa5 | |||
| 91aa699b00 | |||
| c5ba63f976 | |||
| 89523f9e8a | |||
| 14130ad0ea | |||
| a5b1ec330b | |||
| 4ded9bdd00 | |||
| d1a32b034f | |||
| d387b064d3 | |||
| e6476528b1 | |||
| d6dedaba42 | |||
| 0347c1daed | |||
| 6fcb011935 |
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"mcpServers": {
|
||||
"nx-mcp": {
|
||||
"url": "http://localhost:9470/sse"
|
||||
"url": "http://localhost:9470/mcp"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@ name: publish
|
||||
on:
|
||||
# Automated schedule - canary releases from master
|
||||
schedule:
|
||||
- cron: "0 3 * * 2-6" # Tuesdays - Saturdays, at 3am UTC
|
||||
- cron: "0 19 * * 1-5" # Monday - Friday, at 19:00 UTC (7pm UTC)
|
||||
# Manual trigger - PR releases or dry-runs (based on workflow inputs)
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
@@ -22,7 +22,7 @@ env:
|
||||
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)
|
||||
PNPM_VERSION: 10.28.2 # 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 statica and we can use
|
||||
# - We are either running a dry-run on the current branch, in which case the version will be static 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,31 +51,23 @@ jobs:
|
||||
publish_branch: ${{ steps.script.outputs.publish_branch }}
|
||||
ref: ${{ steps.script.outputs.ref }}
|
||||
repo: ${{ steps.script.outputs.repo }}
|
||||
env:
|
||||
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
|
||||
pr_number: ${{ steps.script.outputs.pr_number }}
|
||||
pr_author: ${{ steps.script.outputs.pr_author }}
|
||||
steps:
|
||||
# Default checkout on the triggering branch so that the latest publish-resolve-data.js script is available
|
||||
- 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 }}
|
||||
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
||||
|
||||
- name: Setup node
|
||||
uses: actions/setup-node@v4
|
||||
uses: actions/setup-node@a0853c24544627f65ddf259abe73b1d18a591444 # v5.0.0
|
||||
with:
|
||||
node-version: ${{ env.NODE_VERSION }}
|
||||
registry-url: 'https://registry.npmjs.org'
|
||||
check-latest: true
|
||||
|
||||
# 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)
|
||||
package-manager-cache: false
|
||||
|
||||
- name: Resolve and set checkout and version data to use for release
|
||||
id: script
|
||||
uses: actions/github-script@v7
|
||||
uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0
|
||||
env:
|
||||
PR_NUMBER: ${{ github.event.inputs.pr }}
|
||||
with:
|
||||
@@ -86,7 +78,7 @@ jobs:
|
||||
|
||||
- name: (PR Release Only) Check out latest master
|
||||
if: ${{ steps.script.outputs.ref != '' }}
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
||||
with:
|
||||
# Check out the latest master branch to get its copy of nx-release.ts
|
||||
repository: nrwl/nx
|
||||
@@ -95,24 +87,31 @@ jobs:
|
||||
|
||||
- name: (PR Release Only) Check out PR branch
|
||||
if: ${{ steps.script.outputs.ref != '' }}
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
||||
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 nx-release.ts has not changed in the PR being released
|
||||
- name: (PR Release Only) Ensure that release scripts have not changed in the PR being released
|
||||
if: ${{ steps.script.outputs.ref != '' }}
|
||||
env:
|
||||
FILE_TO_COMPARE: "scripts/nx-release.ts"
|
||||
run: |
|
||||
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
|
||||
# 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
|
||||
|
||||
build:
|
||||
needs: [ resolve-required-data ]
|
||||
@@ -121,16 +120,21 @@ jobs:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
settings:
|
||||
- host: macos-13
|
||||
- host: macos-latest
|
||||
target: x86_64-apple-darwin
|
||||
setup: |-
|
||||
rustup target add aarch64-apple-darwin
|
||||
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: pnpm nx run-many --target=build-native -- --target=x86_64-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
|
||||
target: x86_64-pc-windows-msvc
|
||||
# Windows 32bit (not needed)
|
||||
# - host: windows-latest
|
||||
@@ -144,16 +148,22 @@ jobs:
|
||||
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
|
||||
pnpm nx run-many --verbose --target=build-native -- --target=x86_64-unknown-linux-gnu
|
||||
@@ -164,27 +174,32 @@ jobs:
|
||||
bash -c "
|
||||
set -e
|
||||
echo 'https://dl-cdn.alpinelinux.org/alpine/edge/community' >> /etc/apk/repositories
|
||||
apk add --no-cache curl xz
|
||||
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-13
|
||||
- host: macos-latest
|
||||
target: aarch64-apple-darwin
|
||||
setup: |-
|
||||
rustup target add aarch64-apple-darwin
|
||||
@@ -201,17 +216,23 @@ jobs:
|
||||
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
|
||||
pnpm nx run-many --verbose --target=build-native -- --target=aarch64-unknown-linux-gnu
|
||||
@@ -239,59 +260,61 @@ jobs:
|
||||
bash -c "
|
||||
set -e
|
||||
echo 'https://dl-cdn.alpinelinux.org/alpine/edge/community' >> /etc/apk/repositories
|
||||
apk add --no-cache curl xz
|
||||
|
||||
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
|
||||
rustup target add aarch64-unknown-linux-musl
|
||||
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: pnpm nx run-many --target=build-native -- --target=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
|
||||
runs-on: ${{ matrix.settings.host }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
||||
with:
|
||||
repository: ${{ needs.resolve-required-data.outputs.repo }}
|
||||
ref: ${{ needs.resolve-required-data.outputs.ref }}
|
||||
repository: ${{ needs.resolve-required-data.outputs.repo || github.repository }}
|
||||
ref: ${{ needs.resolve-required-data.outputs.ref || github.ref }}
|
||||
|
||||
- uses: pnpm/action-setup@v4
|
||||
with:
|
||||
version: ${{ env.PNPM_VERSION }}
|
||||
|
||||
- name: Setup node
|
||||
uses: actions/setup-node@v4
|
||||
- name: Setup dev tools with mise
|
||||
uses: jdx/mise-action@146a28175021df8ca24f8ee1828cc2a60f980bd5 # v3
|
||||
if: ${{ !matrix.settings.docker }}
|
||||
with:
|
||||
node-version: ${{ env.NODE_VERSION }}
|
||||
check-latest: true
|
||||
cache: 'pnpm'
|
||||
|
||||
- name: Install
|
||||
uses: dtolnay/rust-toolchain@stable
|
||||
- name: Enable corepack and install pnpm
|
||||
if: ${{ !matrix.settings.docker }}
|
||||
with:
|
||||
targets: ${{ matrix.settings.target }}
|
||||
run: |
|
||||
corepack enable
|
||||
corepack prepare --activate
|
||||
|
||||
- name: Cache cargo
|
||||
uses: actions/cache@v4
|
||||
uses: actions/cache@0400d5f644dc74513175e3cd8d07132dd4860809 # v4.2.4
|
||||
with:
|
||||
path: |
|
||||
~/.cargo/registry/index/
|
||||
@@ -301,7 +324,7 @@ jobs:
|
||||
target/
|
||||
key: ${{ matrix.settings.target }}-cargo-registry
|
||||
|
||||
- uses: goto-bus-stop/setup-zig@v2
|
||||
- uses: goto-bus-stop/setup-zig@abea47f85e598557f500fa1fd2ab7464fcb39406 # v2.2.1
|
||||
if: ${{ matrix.settings.target == 'armv7-unknown-linux-gnueabihf' }}
|
||||
with:
|
||||
version: 0.10.0
|
||||
@@ -322,7 +345,7 @@ jobs:
|
||||
timeout-minutes: 30
|
||||
|
||||
- name: Setup node x86
|
||||
uses: actions/setup-node@v4
|
||||
uses: actions/setup-node@a0853c24544627f65ddf259abe73b1d18a591444 # v5.0.0
|
||||
if: matrix.settings.target == 'i686-pc-windows-msvc'
|
||||
with:
|
||||
node-version: ${{ env.NODE_VERSION }}
|
||||
@@ -331,7 +354,7 @@ jobs:
|
||||
architecture: x86
|
||||
|
||||
- name: Build in docker
|
||||
uses: addnab/docker-run-action@v3
|
||||
uses: addnab/docker-run-action@4f65fabd2431ebc8d299f8e5a018d79a769ae185 # v3
|
||||
if: ${{ matrix.settings.docker }}
|
||||
with:
|
||||
image: ${{ matrix.settings.docker }}
|
||||
@@ -344,12 +367,12 @@ jobs:
|
||||
shell: bash
|
||||
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
|
||||
with:
|
||||
name: bindings-${{ matrix.settings.target }}
|
||||
path: |
|
||||
packages/**/*.node
|
||||
packages/**/*.wasm
|
||||
packages/nx/src/native/*.node
|
||||
packages/nx/src/native/*.wasm
|
||||
if-no-files-found: error
|
||||
|
||||
build-freebsd:
|
||||
@@ -359,14 +382,14 @@ jobs:
|
||||
name: Build FreeBSD
|
||||
timeout-minutes: 45
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
||||
with:
|
||||
repository: ${{ needs.resolve-required-data.outputs.repo }}
|
||||
ref: ${{ needs.resolve-required-data.outputs.ref }}
|
||||
repository: ${{ needs.resolve-required-data.outputs.repo || github.repository }}
|
||||
ref: ${{ needs.resolve-required-data.outputs.ref || github.ref }}
|
||||
|
||||
- name: Build
|
||||
id: build
|
||||
uses: cross-platform-actions/action@v0.25.0
|
||||
uses: cross-platform-actions/action@462ed697694d2ac9aa49e1225f395f7bb6dd49fe # v0.29.0
|
||||
env:
|
||||
DEBUG: napi:*
|
||||
RUSTUP_IO_THREADS: 1
|
||||
@@ -382,8 +405,12 @@ jobs:
|
||||
run: |
|
||||
env
|
||||
whoami
|
||||
sudo pkg install -y -f node libnghttp2 www/npm git
|
||||
sudo npm install --location=global --ignore-scripts pnpm@10.11.1
|
||||
sudo pkg install -y -f node libnghttp2 www/npm git openjdk17
|
||||
sudo npm install --location=global --ignore-scripts pnpm@10.28.2
|
||||
# Set up Java 17
|
||||
export JAVA_HOME=/usr/local/openjdk17
|
||||
export PATH="$JAVA_HOME/bin:$PATH"
|
||||
java --version
|
||||
curl https://sh.rustup.rs -sSf --output rustup.sh
|
||||
sh rustup.sh -y --profile minimal --default-toolchain stable
|
||||
source "$HOME/.cargo/env"
|
||||
@@ -398,8 +425,75 @@ jobs:
|
||||
whoami
|
||||
env
|
||||
freebsd-version
|
||||
echo "Installing dependencies"
|
||||
pnpm install --frozen-lockfile --ignore-scripts
|
||||
pnpm nx run-many --verbose --outputStyle stream --target=build-native -- --target=x86_64-unknown-freebsd
|
||||
|
||||
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
|
||||
|
||||
# Remove unnecessary workspace directories
|
||||
rm -rf docs astro-docs nx-dev || true
|
||||
|
||||
echo "Checking disk space after cleanup"
|
||||
df -h
|
||||
|
||||
echo "Building FreeBSD bindings"
|
||||
BUILD_EXIT=0
|
||||
pnpm nx run-many --verbose --outputStyle stream --target=build-native -- --target=x86_64-unknown-freebsd || BUILD_EXIT=$?
|
||||
|
||||
echo "=== Disk usage after build ==="
|
||||
df -h
|
||||
|
||||
if [ "$BUILD_EXIT" -ne 0 ]; then
|
||||
echo "Build failed with exit code $BUILD_EXIT"
|
||||
exit $BUILD_EXIT
|
||||
fi
|
||||
|
||||
echo "Build succeeded"
|
||||
|
||||
echo "Cleaning up"
|
||||
pnpm nx reset
|
||||
rm -rf node_modules
|
||||
rm -rf dist
|
||||
@@ -408,16 +502,18 @@ jobs:
|
||||
echo "COMPLETE"
|
||||
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
|
||||
with:
|
||||
name: bindings-freebsd
|
||||
path: packages/**/*.node
|
||||
path: |
|
||||
packages/nx/src/native/*.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
|
||||
@@ -428,31 +524,28 @@ jobs:
|
||||
- build
|
||||
env:
|
||||
GH_TOKEN: ${{ github.token }}
|
||||
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
|
||||
NPM_CONFIG_PROVENANCE: true
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
||||
with:
|
||||
repository: ${{ needs.resolve-required-data.outputs.repo }}
|
||||
ref: ${{ needs.resolve-required-data.outputs.ref }}
|
||||
repository: ${{ needs.resolve-required-data.outputs.repo || github.repository }}
|
||||
ref: ${{ needs.resolve-required-data.outputs.ref || github.ref }}
|
||||
|
||||
- uses: pnpm/action-setup@v4
|
||||
with:
|
||||
version: ${{ env.PNPM_VERSION }}
|
||||
- name: Setup dev tools with mise
|
||||
uses: jdx/mise-action@146a28175021df8ca24f8ee1828cc2a60f980bd5 # v3
|
||||
|
||||
- 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: Enable corepack and install pnpm
|
||||
run: |
|
||||
corepack enable
|
||||
corepack prepare --activate
|
||||
|
||||
- name: Use npm 11.5.2
|
||||
run: sudo npm install -g npm@11.5.2
|
||||
|
||||
- name: Install dependencies
|
||||
run: pnpm install --frozen-lockfile
|
||||
|
||||
- name: Download all artifacts
|
||||
uses: actions/download-artifact@v4
|
||||
uses: actions/download-artifact@634f93cb2916e3fdff6788551b99b062d0335ce0 # v5.0.0
|
||||
with:
|
||||
path: artifacts
|
||||
|
||||
@@ -464,6 +557,7 @@ 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:
|
||||
@@ -488,11 +582,11 @@ jobs:
|
||||
|
||||
- name: (PR Release Only) Create comment for successful PR release
|
||||
if: success() && github.event.inputs.pr
|
||||
uses: actions/github-script@v7
|
||||
uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0
|
||||
env:
|
||||
SUCCESS_COMMENT: ${{ needs.resolve-required-data.outputs.success_comment }}
|
||||
with:
|
||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
# github-token defaults to ${{ github.token }} so we don't need to specify it
|
||||
script: |
|
||||
const successComment = JSON.parse(process.env.SUCCESS_COMMENT);
|
||||
await github.rest.issues.createComment({
|
||||
@@ -502,22 +596,55 @@ 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@v7
|
||||
uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0
|
||||
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({
|
||||
@@ -526,3 +653,4 @@ jobs:
|
||||
issue_number: ${{ github.event.inputs.pr }},
|
||||
body: message
|
||||
});
|
||||
|
||||
|
||||
@@ -344,6 +344,7 @@ 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
|
||||
|
||||
@@ -53,7 +53,7 @@ Finally, add the following to your `lerna.json`.
|
||||
|
||||
That's mostly it. You can continue using the usual Lerna commands, but at this point Lerna would delegate its operations to Nx underneath.
|
||||
|
||||
To get more out of it, you might want to create a small `nx.json` file (or run `npx nx init` to generate one) for going into some more details on configuring the cacheable operations:
|
||||
To get more out of it, you might want to create a small `nx.json` file (or run `npx nx@latest init` to generate one) for going into some more details on configuring the cacheable operations:
|
||||
|
||||
```json5 {% fileName="nx.json" %}
|
||||
{
|
||||
@@ -88,7 +88,7 @@ By having Nx integrated, you not just get faster builds but also some other Nx's
|
||||
**Distributed caching** — Right now when you enable `useNx` in your existing Lerna repo, you will get local caching, meaning the cache sits in a local folder on your machine. You get much more value out of it when you start distributing and sharing it with your teammates but especially in CI. This can be done by adding Nx Cloud, which comes with a no-credit card, 500 hours free / month offer which is more than what most workspaces need. Adding that is easy and can be done by adding `@nrwl/nx-cloud` to your root-level `package.json` and then by running:
|
||||
|
||||
```shell
|
||||
npx nx connect-to-nx-cloud
|
||||
npx nx@latest connect-to-nx-cloud
|
||||
```
|
||||
|
||||
**Distributed task execution** — Distribution of the cache is one thing, but the real speed improvements come from also [distributing the task execution](/ci/features/distribute-task-execution) to speed up your CI. Having the Nx project graph and as well as the cache and historical data about previous runs, Nx Cloud DTE is able to maximize the CI agent utilization by evenly distributing tasks based on their (historical) duration as well as based on their topological order. In addition, the DTE process makes sure to properly move cached assets between the agents. Setting up DTE is straightforward, read more on our [Nx Cloud docs](/ci/features/distribute-task-execution). Hint: we also have a CI generator in Nx (you need the `@nrwl/workspace` package) that allows you to generate your CI setup using a single command: `npx nx generate @nrwl/workspace:ci-workflow --ci=github`
|
||||
|
||||
@@ -75,7 +75,7 @@ In v14 we already simplified Nx (we have a whole section in [our release blog po
|
||||
Whenever you need to fine-tune the default settings you can run the following command to get a `nx.json` generated or you can obviously create it by hand:
|
||||
|
||||
```shell
|
||||
npx nx init
|
||||
npx nx@latest init
|
||||
```
|
||||
|
||||
## Run Nx graph on any monorepo!
|
||||
|
||||
@@ -509,7 +509,7 @@ If you're currently on a [CRA](https://create-react-app.dev/) setup, you can eas
|
||||
{% youtube src="https://youtu.be/zvYb7XCLQzU" /%}
|
||||
|
||||
```shell
|
||||
npx nx init
|
||||
npx nx@latest init
|
||||
```
|
||||
|
||||
Read more on the Nx docs: [/recipes/adopting-nx/adding-to-existing-project](/recipes/adopting-nx/adding-to-existing-project)
|
||||
|
||||
@@ -65,7 +65,7 @@ When you run `nx init` in your existing Nuxt.js project, Nx does the following:
|
||||
To begin the integration process, simply navigate to the root of your existing Nuxt.js project and run:
|
||||
|
||||
```shell
|
||||
npx nx init
|
||||
npx nx@latest init
|
||||
```
|
||||
|
||||
This approach offers several key benefits for teams looking to adopt Nx:
|
||||
|
||||
@@ -120,7 +120,7 @@ Versioning and publishing packages is always a bit tricky. Mix in the added comp
|
||||
|
||||
For a long time, Nx has been purposefully versioning and publishing agnostic, but given our time spent as [stewards of Lerna](/blog/lerna-is-dead-long-live-lerna) (the OG Javascript monorepo tool), we've been able to take alot of that experience and finally feel confident creating our own versioning and publishing implementation.
|
||||
|
||||
Therefore, we've been working on a new command to the Nx CLI: [nx release](/recipes/nx-release/get-started-with-nx-release#get-started-with-nx-release). We launched this on Friday of our Launch Nx week!
|
||||
Therefore, we've been working on a new command to the Nx CLI: [nx release](/recipes/nx-release/release-npm-packages). We launched this on Friday of our Launch Nx week!
|
||||
|
||||
Juri goes into [full details in this blog post](/blog/versioning-and-releasing-packages-in-a-monorepo), and James Henry — our Director of Engineering and the primary engineer responsible for both maintaining Lerna and creating Nx Release — expands further in his conference talk:
|
||||
|
||||
|
||||
@@ -169,7 +169,7 @@ nx affected --targets=lint,test,build,e2e-ci
|
||||
|
||||
In CI, Nx Agents will allow all tasks to run in parallel on the same machine, except for the atomized end-to-end tasks, which will only run in isolation.
|
||||
|
||||
Learn more about how you can [Parallelize Tasks Across Multiple Machines Using Nx Agents](/ci/intro/tutorials/github-actions#parallelize-tasks-across-multiple-machines-using-nx-agents):
|
||||
Learn more about how you can [Parallelize Tasks Across Multiple Machines Using Nx Agents](/ci/features/split-e2e-tasks):
|
||||
|
||||
{% youtube
|
||||
src="https://youtu.be/0YxcxIR7QU0"
|
||||
|
||||
@@ -33,7 +33,7 @@ If you prefer the previous log view in your CI, you can opt-out of the new table
|
||||
If you're not on Nx Cloud yet, you can **connect your Nx workspace** by running:
|
||||
|
||||
```shell
|
||||
npx nx connect
|
||||
npx nx@latest connect
|
||||
```
|
||||
|
||||
This command will guide you through the setup. We recently introduced a [new Hobby plan](/pricing), which lets you experiment with all the Nx Cloud features for free. This is a great way to see if it's a good fit for your team.
|
||||
|
||||
@@ -94,7 +94,7 @@ The routes exist as projects which are then imported by the application. We can
|
||||
|
||||
Adopting a monorepo powered by Nx on its own does not solve build speeds or CI pipeline times. But adopting a monorepo and taking the time to reevaluate your architecture can lead to a significant improvement in build times when best practices are applied. If you're curious to know more, reach out to us to see how Nx can improve your monorepo experience and ship faster!
|
||||
|
||||
{% call-to-action title="Explore Nx Cloud for Enterprises" url="/enterprise" icon="nxcloud" description="Learn more about our offerings for enterprises and contact our team" %} Explore Nx Cloud for Enterprises {% /call-to-action %}
|
||||
{% call-to-action title="Reach out to our team!" url="/contact/sales" icon="nxcloud" description="Looking to transform your teams velocity? Reach out to learn more about Nx Enterprise and see how we can help your team achieve similar results." /%}
|
||||
|
||||
## Further reading
|
||||
|
||||
|
||||
@@ -86,4 +86,4 @@ Consolidating projects into a single repository **eliminated the complexity of m
|
||||
|
||||
Hetzner Cloud continues to **work closely with the Nx Developer Productivity Engineering (DPE) team** to monitor and refine their setup. By actively collaborating, they ensure that their monorepo remains optimized and that their CI is continuously improved. This ongoing partnership allows Hetzner Cloud to adapt to new challenges, fine-tune configurations, and further push the boundaries of efficiency in their development workflow.
|
||||
|
||||
{% call-to-action title="Want to achieve similar results?" url="/enterprise" icon="nxcloud" description="Learn more about Nx Enterprise or get started with a free trial." /%}
|
||||
{% call-to-action title="Reach out to our team!" url="/contact/sales" icon="nxcloud" description="Looking to transform your teams velocity? Reach out to learn more about Nx Enterprise and see how we can help your team achieve similar results." /%}
|
||||
|
||||
@@ -73,6 +73,4 @@ Other engineers in other business units are seeing the advantage of Nx, and thei
|
||||
|
||||
What's blocking you from getting your products to market fast? Let our team figure it out for you! With Nx Enterprise, you receive expert guidance from day one, ensuring your setup is optimized for maximum efficiency. Whether you're starting fresh, migrating, or scaling your developer platform, we'll work with you to tailor the perfect solution for your team.
|
||||
|
||||
{% call-to-action title="Get a Free Trial of Nx Enterprise" url="/enterprise" icon="nxcloud" description="Learn more about our enterprise offerings or request a free trial of Nx Enterprise" %}
|
||||
|
||||
{% /call-to-action %}
|
||||
{% call-to-action title="Reach out to our team!" url="/contact/sales" icon="nxcloud" description="Looking to transform your teams velocity? Reach out to learn more about Nx Enterprise and see how we can help your team achieve similar results." /%}
|
||||
|
||||
@@ -106,10 +106,10 @@ If you view the `my-app-e2e` project (`npx nx show project my-app-e2e`), you wil
|
||||
When run on a single machine, `e2e-ci` will be slower because it starts multiple Playwright processes, which is why we only allow it to run through distribution. To [enable distribution](/ci/features/split-e2e-tasks#enable-automated-e2e-task-splitting), you must connect your workspace to [Nx Cloud](/nx-cloud). This is easily done with the `connect` command.
|
||||
|
||||
```shell
|
||||
npx nx connect
|
||||
npx nx@latest connect
|
||||
```
|
||||
|
||||
Follow the onboarding steps and you should be connected within five minutes. For more information, check out our [GitHub Actions Tutorial](/ci/intro/tutorials/github-actions) or our [guides](/ci/recipes/set-up) for all supported CI providers (GitHub, GitLab, Azure, etc.).
|
||||
Follow the onboarding steps and you should be connected within five minutes. For more information, check out our [setup guides](/ci/recipes/set-up) for all supported CI providers (GitHub, GitLab, Azure, etc.).
|
||||
|
||||
Now, let's take a look at a concrete example to get an idea of how much time-saving you can unlock with Nx Atomizer. I created [this repo](https://github.com/jaysoo/angular-testing-demo) that contains a simple Angular application and a UI package. It also has 40 Playwright test files.
|
||||
|
||||
|
||||
@@ -161,7 +161,7 @@ It uses Nx for running and building your project. Nx relies on the Angular Devki
|
||||
If you have an existing Angular CLI project, you can also [add Nx support to it](/technologies/angular/migration/angular) by running:
|
||||
|
||||
```shell
|
||||
npx nx init
|
||||
npx nx@latest init
|
||||
```
|
||||
|
||||
If you already know you want to go straight to an Nx monorepo, you can add the `--integrated` flag to the `nx init` command.
|
||||
|
||||
@@ -72,7 +72,7 @@ The steps are very simple:
|
||||
2. Run `nx g @nx/angular:convert-to-rspack` to migrate your Angular application to Rspack.
|
||||
|
||||
There is also a [guide in our documentation](/technologies/angular/angular-rspack/recipes/migrate-from-webpack) that walks you through the process step-by-step.
|
||||
Even if you're currently using the Angular CLI, it's as simple as first running `npx nx init` in your workspace and then running `npx nx g convert-to-rspack`.
|
||||
Even if you're currently using the Angular CLI, it's as simple as first running `npx nx@latest init` in your workspace and then running `npx nx g convert-to-rspack`.
|
||||
|
||||
## Using Angular Rspack
|
||||
|
||||
|
||||
@@ -99,7 +99,7 @@ To enable Self-Healing CI on your workspace:
|
||||
If you haven't already connected to Nx Cloud:
|
||||
|
||||
```shell
|
||||
npx nx connect
|
||||
npx nx@latest connect
|
||||
```
|
||||
|
||||
You can [start with the free Hobby plan](/pricing) and play around with the new AI features.
|
||||
@@ -179,7 +179,7 @@ Self-Healing CI completes Nx Cloud's comprehensive approach to eliminating CI fr
|
||||
- **Built on proven infrastructure**: Uses the same robust Nx Cloud infrastructure that powers distributed task execution
|
||||
- **Part of a broader vision**: Continues our mission to optimize "time to green" and eliminate developer workflow friction
|
||||
|
||||
**Ready to try it?** Self-Healing CI is rolling out as an early access feature and is available to everyone right now—no special approval or signup required. If you don't have an Nx Cloud account yet, you can quickly [start with the Hobby plan](/pricing), connect your workspace with `npx nx connect`, and get going immediately.
|
||||
**Ready to try it?** Self-Healing CI is rolling out as an early access feature and is available to everyone right now—no special approval or signup required. If you don't have an Nx Cloud account yet, you can quickly [start with the Hobby plan](/pricing), connect your workspace with `npx nx@latest connect`, and get going immediately.
|
||||
|
||||
**For enterprise teams:** If you're already using Nx Cloud and want to learn more about how AI features like Self-Healing CI can enhance your existing setup, [reach out to us](/contact). We'd love to help you leverage these capabilities in your organization.
|
||||
|
||||
|
||||
@@ -125,7 +125,7 @@ Then update the JSON configuration as follows, making sure the `cwd` points to t
|
||||
If you haven't already connected your Nx workspace to Nx Cloud, run:
|
||||
|
||||
```shell
|
||||
npx nx connect
|
||||
npx nx@latest connect
|
||||
```
|
||||
|
||||
This command will walk you through connecting your existing Nx workspace to a new Nx Cloud account. **There's a [free hobby plan](/pricing)**. Run it for a couple of weeks and then try out these conversational analytics features.
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
---
|
||||
title: 'The More the Merrier - Groups Save 50% on Nx Essentials Workshop'
|
||||
slug: nx-essentials-workshop
|
||||
authors: []
|
||||
tags: ['workshop']
|
||||
cover_image: /blog/images/2025-07-23/header.avif
|
||||
description: 'Join us for a 2-day deep dive into all things Nx! Instructors from Nx and Push-Based will team up to cover the breadth of tools and techniques needed for any tech lead or individual contributor to be successful setting up and navigating an Nx workspace.'
|
||||
---
|
||||
|
||||
You may have missed the Early Bird discount, but it’s not too late to get an amazing price on our [Nx Essentials online workshop](https://bit.ly/3IYOILt). **Groups of 3 or more can use the promo code NXGROUP at checkout to save 50% on everyone’s registration.**
|
||||
|
||||
## About the Workshop
|
||||
|
||||
**Dates:** July 29th-30th
|
||||
|
||||
**Time:** 12pm - 5pm ET/9am-2pm PT
|
||||
|
||||
This is a 2-day deep dive into all things Nx! Instructors from Nx and Push-Based will team up to cover the breadth of tools and techniques needed for any tech lead or individual contributor to be successful optimizing your development workflow with Nx.
|
||||
|
||||
We believe that the most effective way to learn is often to get in there and start trying things out yourself, so topics will be presented via short presentations followed by hands-on code labs. Our instructors will work with attendees, offering help to anyone who gets stuck and engaging discussion topics for anyone blazing ahead.
|
||||
|
||||
While the course starts with the very basics of Nx, it quickly moves into advanced topics, so attendees of any experience level should come away with new insights.
|
||||
|
||||
We’ll cover…
|
||||
|
||||
- **Using Nx –** Run Tasks, Task Pipelines, Affected, Caching, Generate Code
|
||||
- **Enforcing Organizational Decisions –** Configure Module Boundaries, Create a Custom Plugin to Manage Docker Configs
|
||||
- **Boosting Performance –** Module Federation, Remote Caching, Nx Agents, Optimize Cache Settings, Atomizer, Flaky Tasks
|
||||
|
||||
And more! **Every exercise will also include clear action steps for you to try out in your own repository.**
|
||||
|
||||
## Need help justifying the expense?
|
||||
|
||||
We’ve drafted a [sample justification letter](https://bit.ly/44pNuzX) you can use.
|
||||
|
||||
And if you think your team might be a good fit for Nx Enterprise, your workshop fees can also be applied as a discount towards new contracts signed within 6 months of the workshop date.
|
||||
|
||||
[Check out the full details and save your spot for the Nx Essentials workshop!](https://bit.ly/3IYOILt)
|
||||
@@ -0,0 +1,105 @@
|
||||
---
|
||||
title: 'From 5 Days to 20 Minutes: How PayFit Accelerated Time to Market with Strategic Nx Implementation'
|
||||
slug: payfit-success-story
|
||||
authors: [Juri Strumpflohner]
|
||||
tags: ['customer story']
|
||||
description: Discover how a 4-person platform team at Payfit turned monorepo abandonment into a competitive advantage using strategic Nx implementation.
|
||||
cover_image: /blog/images/articles/bg-payfit-customer-success.avif
|
||||
youtubeUrl: https://youtu.be/Vdk-tza4PCs
|
||||
metrics:
|
||||
- value: '5 days→20 min'
|
||||
label: 'feature deployment time'
|
||||
- value: '75% faster'
|
||||
label: 'coding time'
|
||||
- value: '4 engineers'
|
||||
label: 'platform team managing entire frontend ecosystem'
|
||||
- value: '100%'
|
||||
label: 'teams wanting to migrate back to monorepo'
|
||||
---
|
||||
|
||||
PayFit is a leading European HR and payroll platform serving thousands of businesses across the continent with their innovative SaaS solutions. As one of Europe's fastest-growing HR tech companies, PayFit continues to expand rapidly across multiple markets. Their engineering organization faced a classic scale challenge: maintaining development velocity while managing an increasingly complex codebase distributed across multiple repositories.
|
||||
|
||||
With a lean but highly strategic platform team of just four engineers responsible for frontend tooling, design systems, monorepo health, and CI/CD infrastructure, PayFit needed maximum efficiency to compete in the demanding startup landscape. When deployment cycles stretched from 2-5 days per feature and teams abandoned their shared monorepo due to poor initial implementation, the company was at a critical inflection point that threatened their competitive advantage in the fast-moving European HR tech market.
|
||||
|
||||
## Challenge
|
||||
|
||||
Payfit's journey with Nx began with a top-down mandate that didn't include the necessary knowledge transfer or support systems. This led to a predictable outcome: teams abandoned the monorepo entirely. At a critical tipping point, engineering teams extracted themselves from the shared workspace, prioritizing autonomy over the collaborative benefits that a well-managed monorepo could provide.
|
||||
|
||||
The consequences of this fragmentation were severe:
|
||||
|
||||
- **Deployment complexity** – Deploying a single feature required navigating multiple repositories and systems sequentially, taking between **2 and 5 days** to complete.
|
||||
- **Lost development velocity** – Teams accepted slower development pace as the cost of independence.
|
||||
- **Fragmented ownership** – No clear ownership or maintenance of shared tooling and infrastructure.
|
||||
- **CI/CD inefficiencies** – Each repository required its own CI setup and optimization, leading to duplicated effort and inconsistent performance.
|
||||
|
||||
In a startup environment where speed to market is crucial, these delays were becoming a significant competitive disadvantage.
|
||||
|
||||
## Solution
|
||||
|
||||
Nicolas Beaussart joined Payfit as a staff engineer with a clear mission: revive the monorepo and restore development velocity. Rather than forcing teams back immediately, the platform team took a strategic approach focused on proving value through execution.
|
||||
|
||||
The team focused on making the monorepo a compelling choice rather than a mandate:
|
||||
|
||||
- **Invested in monorepo health** – Properly configured Nx with task inference to ensure everything worked smoothly out of the box.
|
||||
- **Leveraged Nx Cloud** – Implemented Nx Cloud to dramatically speed up CI performance and eliminate the manual optimization burden.
|
||||
- **Pilot program approach** – Started with a few pilot teams to migrate back and demonstrate the benefits in practice.
|
||||
- **Created social proof** – Early positive feedback from pilot teams served as validation for other teams considering the migration.
|
||||
|
||||
### Offloading Complexity with Nx Cloud
|
||||
|
||||
One of the most significant improvements came from adopting [Nx Cloud](https://nx.app) to handle CI optimization. This shift from manual CI optimization to automated intelligence freed the platform team to focus on higher-value work while ensuring optimal performance.
|
||||
|
||||
{% testimonial
|
||||
name="Nicolas Beaussart"
|
||||
title="Staff Engineer, Payfit"
|
||||
image="https://avatars.githubusercontent.com/u/7281023?v=4" %}
|
||||
The number of hours we spent optimizing CI before, trying to load balance in CircleCI, the different number of agents that we run ourselves by hand... it was painful and we spent hours and days trying to do that. The main thing with Nx Cloud is that we don't have to think about that.
|
||||
{% /testimonial %}
|
||||
|
||||
The strategic approach paid off. Positive feedback from pilot teams created a snowball effect:
|
||||
|
||||
> "Slowly but surely it went into a snowball effect where now teams want to migrate themselves back into the monorepo directly themselves."
|
||||
|
||||
This organic adoption was far more sustainable than the original top-down mandate, as teams could see the concrete benefits in their daily work.
|
||||
|
||||
## Results
|
||||
|
||||
### Dramatic Reduction in Deployment Time
|
||||
|
||||
The most striking improvement was in feature deployment speed:
|
||||
|
||||
- **From 2-5 days to 20 minutes maximum** – The initial optimization achieved in the October 2024 interview reduced deployment time to 2 hours (a 97% reduction). Since then, the PayFit team has continued optimizing their deployment pipeline, achieving just _20 minutes from branch push to full production deployment across all environments—including merge, dev, staging, e2e, and production_.
|
||||
- **75% faster coding** – Features that previously took much longer to code can now be developed in a quarter of the time
|
||||
|
||||
{% testimonial
|
||||
name="Nicolas Beaussart"
|
||||
title="Staff Engineer, Payfit"
|
||||
image="/documentation/blog/images/articles/nicolas-beaussart.avif" %}
|
||||
A year ago to deploy a feature it took between 2 and 5 days because you had to go through all of the monorepos, all of the systems one by one to be able to deploy that. Today the same feature can be coded in like a quarter of the time and deploying like 2 hours tops (now even down to only 20 min).
|
||||
{% /testimonial %}
|
||||
|
||||
### Restored Team Confidence in Monorepo Architecture
|
||||
|
||||
The platform team successfully reversed the initial exodus from the monorepo:
|
||||
|
||||
- Teams now **actively request to migrate back** to the main monorepo
|
||||
- **100% positive feedback** from teams that have migrated back
|
||||
- Strong **social proof** driving organic adoption across the organization
|
||||
|
||||
### Operational Efficiency Through Automation
|
||||
|
||||
By leveraging Nx Cloud's intelligent CI optimization, the platform team eliminated a major operational burden:
|
||||
|
||||
- **Zero time spent** on manual CI optimization and load balancing
|
||||
- **Predictable performance** without manual intervention
|
||||
- **Direct support channel** with Nx team for any optimization needs
|
||||
|
||||
### Competitive Advantage in Startup Environment
|
||||
|
||||
For a startup where speed to market is crucial, these improvements translated directly to business impact:
|
||||
|
||||
> "This is critical in a startup world where things need to move fast, and a big part of this answer is Nx and Nx Cloud. Without those pieces, I don't think we could have the same velocity that we have right now."
|
||||
|
||||
The transformation enabled Payfit to maintain their competitive edge while scaling their engineering organization efficiently.
|
||||
|
||||
{% call-to-action title="Reach out to our team!" url="/contact/sales" icon="nxcloud" description="Looking to transform your teams velocity? Reach out to learn more about Nx Enterprise and see how we can help your team achieve similar results." /%}
|
||||
@@ -0,0 +1,69 @@
|
||||
---
|
||||
title: 'The Journey of Nx Gradle: From Prototype to Production'
|
||||
slug: journey-of-nx-gradle
|
||||
authors: [Jason Jean, Mike Hartington]
|
||||
tags: ['java', 'gradle']
|
||||
description: Nx’s Gradle plugin evolved from a prototype into a robust solution for integrating Java projects in monorepos, offering deep Gradle insights, faster CI, and upcoming Maven support.
|
||||
cover_image: /blog/images/2025-07-28/header.avif
|
||||
---
|
||||
|
||||
{% callout type="deepdive" title="Java Week Series" expanded=true %}
|
||||
|
||||
This article is part of the Java Week series:
|
||||
|
||||
- **The Journey of Nx Gradle**
|
||||
- [Polyglot Projects Made Easy](/blog/spring-boot-with-nx)
|
||||
- [Getting Mobile Into Your Monorepo](/blog/android-and-nx)
|
||||
- [Seamless Deploys With Docker](/blog/seamless-deploys-with-docker)
|
||||
|
||||
{% /callout %}
|
||||
|
||||
When Nx first dipped its toes into the world of Java, no one could have predicted the ride ahead. From an accidental prototype to enterprise-level adoption, the path of Java support at Nx, particularly through the `@nx/gradle` plugin, has been one of exploration, iteration, and growing maturity.
|
||||
|
||||
## Humble Beginnings: An Accidental Start
|
||||
|
||||
In February 2020, the Nx team attended their first Java conference, DevNexus. At the time, there was no Java solution from Nx, so we spent the next couple of days thinking about what Nx for Java would look like and what kind of technical challenges would need to be addressed. At the time, Nx was still very much tied to Angular, and while it was technically possible to target Gradle projects this way, it was very rough and never went past the point of being a prototype. Shortly after the conference, Covid lock downs went into place and we put development on pause.
|
||||
|
||||
## Laying the Foundations with Crystal
|
||||
|
||||
Fast forward to 2024, and we made a major change to Nx. Code name **Project Crystal** was a shift in how Nx worked under the hood. Instead of configuring Nx separately to work with a particular tool, most tools have their own configuration that Nx would reference to get even better configuration programmatically. We started using this inferred approach for all of our core supported tools (like Vite) and would read the config from the associated config file (`vite.config.js`). **Project Crystal made Nx more transparent, simplified how Nx was configured, optimized the configuration, made running tools through Nx even faster, and reduced maintenance required all in one fell swoop.** Even during Project Crystal, Gradle was at the forefront of our considerations during this re-architecture. This new architecture set the stage for how Java/Gradle support could be implemented. Nx would get information from Gradle itself for how Nx should run Gradle and Nx would transparently invoke Gradle.
|
||||
|
||||
## The Birth of Nx Gradle
|
||||
|
||||
Shortly after inferred projects shipped, we had a reworked version of that early prototype that was ready for some real world testing as `@nx/gradle`. We [announced the plugin](/blog/manage-your-gradle-project-using-nx) and started to use it internally in our closed-source monorepo. We even had interest from some clients who had Java projects that they wanted to consolidate with their existing Nx monorepo.
|
||||
|
||||
However, after it’s initial usage, we had started to notice some limitations with this approach. The main limitation was our usage of Gradle's built-in `project-report` feature which didn't provide Nx with enough detail for accurate configuration. We went back to the drawing board and reimagined how to add support for more complex setups that we saw in the real world.
|
||||
|
||||
## A Smarter, Deeper Integration: v2 of Nx Gradle
|
||||
|
||||
By November 2024, the team began experimenting with a **v2** of Gradle plugin that aimed to extract richer and more granular data from Gradle itself. This involved building a dedicated **Gradle plugin for Nx (`dev.nx.gradle`)**. The new approach could detect:
|
||||
|
||||
- Available tasks
|
||||
- Task inputs and outputs
|
||||
- Dependency chains (`dependsOn`)
|
||||
- And more!
|
||||
|
||||
At the start of 2025 we started testing this against a much larger and more complex Java codebase, the [Spring Boot repository](https://github.com/xiongemi/spring-boot).
|
||||
|
||||
## Benchmarking Nx in Spring Boot
|
||||
|
||||
Even though we had learned a lot from the initial adoption of `@nx/gradle`, if we can get Nx working here, we can better support other projects with ease. The Spring Boot repo ran more than 8000 tasks for its CI pipeline taking up to 1 hour 40 minutes for the worst case scenario without caching. Integrating Nx into this pipeline required us to make even more improvements to Nx to get things running smoothly. We introduced Batch mode support for running `@nx/gradle` tasks which allowed Nx to run multiple tasks within a single invocation of Gradle greatly reducing the overhead that Nx would incur running Gradle. We also introduced atomization for running Gradle tests. Today, Nx is able to run the same 8000+ tasks in a worst case scenario with no caching in 50 minutes.
|
||||
|
||||
## Looking Ahead
|
||||
|
||||
As of now, the Nx Gradle plugin is in a much better state than when we started last year. We can now handle multi-module Gradle projects, as well as polyglot monorepos with existing JavaScript projects. This week, we're going to take a refreshed look at `@nx/gradle` and what you can expect in the future. We have more plans for Nx’s Java Support (like Maven support) so we're not done yet. In fact, we are actively prototyping a Maven plugin against the [Quarkus repository](https://github.com/quarkusio/quarkus)!
|
||||
|
||||
What began as an off-the-cuff prototype at a conference has matured into a serious offering for Java developers working in monorepos. Nx Gradle has evolved from a limited tool into a reliable, insightful, and enterprise-friendly integration—bringing the Nx developer experience to Java and teams. And with Maven support on the horizon, the journey is far from over.
|
||||
|
||||
**Stay tuned—because the future of Java at Nx is only just getting started.**
|
||||
|
||||
---
|
||||
|
||||
Learn more:
|
||||
|
||||
- 🌌 [Nx Gradle Tutorial](/getting-started/tutorials/gradle-tutorial)
|
||||
- 📖 [Nx Gradle API](/technologies/java/api)
|
||||
- 👩💻 [Nx GitHub](https://github.com/nrwl/nx)
|
||||
- 👩💻 [Nx Console GitHub](https://github.com/nrwl/nx-console)
|
||||
- 💬 [Nx Official Discord Server](https://go.nx.dev/community)
|
||||
- 📹 [Nx Youtube Channel](https://www.youtube.com/@nxdevtools)
|
||||
@@ -0,0 +1,150 @@
|
||||
---
|
||||
title: 'Polyglot Projects Made Easy: Integrating Spring Boot into an Nx Workspace'
|
||||
slug: spring-boot-with-nx
|
||||
authors: ['Mike Hartington']
|
||||
tags: ['nx', 'java', 'springboot']
|
||||
cover_image: /blog/images/2025-07-29/header.avif
|
||||
description: 'Learn how to seamlessly integrate a Spring Boot Java backend into an existing Nx monorepo with a React frontend—streamlining development, simplifying workflows, and enabling powerful fullstack coordination.'
|
||||
youtubeUrl: https://youtu.be/FM2kAw-NNsQ
|
||||
---
|
||||
|
||||
{% callout type="deepdive" title="Java Week Series" expanded=true %}
|
||||
|
||||
This article is part of the Java Week series:
|
||||
|
||||
- [The Journey of Nx Gradle](/blog/journey-of-nx-gradle)
|
||||
- **Polyglot Projects Made Easy**
|
||||
- [Getting Mobile Into Your Monorepo](/blog/android-and-nx)
|
||||
- [Seamless Deploys With Docker](/blog/seamless-deploys-with-docker)
|
||||
|
||||
{% /callout %}
|
||||
|
||||
Behind every modern JavaScript app lies a powerful backend, and for many enterprises, that backend is powered by Java. At Nx, we believe Java is just as much a first-class citizen as JavaScript. While Nx has a proven history of streamlining JavaScript development, we also offer seamless integration for Java projects. With the `@nx/gradle` plugin, you can bring your Java services built with Gradle into your Nx monorepo, creating a unified environment where both frontend and backend thrive together. Let’s dive into how Nx bridges these worlds effortlessly.
|
||||
|
||||
## Spring into Java
|
||||
|
||||
For starters, let's look at our Java backend. It's just a simple app built using the Spring Boot framework. With this, we can set up various rest endpoints for interacting with some data. There's some endpoints for user management, authentication, and session storage for logged in users. For Java developers, running and testing this app is as simple as pressing the "play" button in IntelliJ.
|
||||
|
||||

|
||||
|
||||
Spring has [a project generator](https://start.spring.io/index.html) that can help get you up and running, and you can check out this project on GitHub if you want to follow along.
|
||||
|
||||
Now if I want to interact with this backend, I would need to create a frontend app that I can make request from. But in a real world situation, the frontend and backend are probably maintained by different teams. This is the typical problem space that Nx works in, so we can reduce and simplify the development of this app.
|
||||
|
||||
## You got your Java In my JavaScript
|
||||
|
||||
Our frontend project is just your standard React app. It already exists in a Nx workspace, so I have all of my usual Nx feature available to me. It interacts with the backend by making requests to it, but I need to start the two projects separately, which can just be cumbersome to manage.
|
||||
|
||||

|
||||
|
||||
To actually make these two projects work together, we can utilize the `nx import` command to start migrating the backend into the existing workspace. `import` can take a relative path or a git URL, and it will handle all of the necessary work of maintaining the git history, detecting the project type, and suggesting additional plugins you might want to include.
|
||||
|
||||
For our Java project, it's going to suggest that we include the `@nx/gradle` plugin as we are using [Gradle as our build system](https://gradle.org/). Once installed, we can run `nx graph` or `nx show project java-backend` to inspect.
|
||||
|
||||

|
||||
|
||||
Here we can see all of the available tasks from Gradle that we could run for our Java project. But how does Nx know about these tasks? We actually include a Gradle plugin for Nx that we use under the hood to inspect the Java project. When we call any `nx` command for our java project, we actually invoke Gradle in the background to get all of tasks that Gradle could run directly.
|
||||
|
||||
```groovy
|
||||
plugins {
|
||||
id 'java'
|
||||
id 'org.springframework.boot' version '3.4.5'
|
||||
id 'io.spring.dependency-management' version '1.1.7'
|
||||
// Added by Nx
|
||||
id "dev.nx.gradle.project-graph" version "0.1.0"
|
||||
}
|
||||
|
||||
java {...}
|
||||
configurations {...}
|
||||
repositories {...}
|
||||
dependencies {...}
|
||||
|
||||
allprojects {
|
||||
apply {
|
||||
plugin("dev.nx.gradle.project-graph")
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
This project-graph is added to our `build.gradle` file and is doing the real heavy lifting for us.
|
||||
|
||||
From here, we can start running the Java project
|
||||
|
||||
```bash
|
||||
nx run java-backend:bootRun
|
||||
```
|
||||
|
||||
And our API is up and running:
|
||||
|
||||

|
||||
|
||||
## Connecting Two Tasks
|
||||
|
||||
With the project imported, we can now coordinate the frontend and backend processes so we can easily run them together. This is actually pretty easy to do thanks to `dependsOn`. In the `package.json` for our React app, let's configure the `dev` task and make it start the Java backend.
|
||||
|
||||
```json
|
||||
{
|
||||
"name": "@mono-app/react-frontend",
|
||||
"version": "0.0.1",
|
||||
"private": true,
|
||||
"nx": {
|
||||
"targets": {
|
||||
"dev": {
|
||||
"dependsOn": ["java-backend:bootRun"]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Now we can run `react-frontend:dev` and we'll automatically get our Java backend up and running
|
||||
|
||||

|
||||
|
||||
But we can take this one step further. Let's consider that we have a bug in our Java backend. A bad response from an endpoint, incorrect structure, or something similar. Since our code is all in one place, we could fix this easily, but to get the changes applied, we'll need to stop and restart our server. That's not ideal, and is super slow. So we can expand on that `dependsOn` approach from earlier within our Java backend project.
|
||||
|
||||
If we create a simple `project.json` in the java-backend directory, we'll be able to customize the `bootRun` task. For starters, we want `bootRun` to depend on the `build` task we have:
|
||||
|
||||
```json
|
||||
{
|
||||
"targets": {
|
||||
"bootRun": {
|
||||
"dependsOn": ["build"]
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Now for the build task, we want to pass in an argument to our underlying Gradle command:
|
||||
|
||||
```json
|
||||
"build": {
|
||||
"continuous": true,
|
||||
"options": {
|
||||
"args": ["--continuous"]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
So we have the `options.args` passing in a `--continuous` flag and setting `"continuous": true`. Now, these look similar, but are doing two different things. The `"continuous": true` is telling Nx that this task is long-lived and will not end. The `options.args` part is getting passed to Gradle directly and telling Gradle to watch for file changes.
|
||||
|
||||
> For demo purposes, we're going to target the build task directly, but for more production ready example, create your own task so you do not impact any CI runs.
|
||||
|
||||
Now if we change one of our Java files, Gradle will rebuild our project, and the `bootRun` will refresh with the new changes applied.
|
||||
|
||||

|
||||
|
||||
## A Polyglot Future
|
||||
|
||||
With this, we have the beginnings of a great polyglot experience for teams that have a mix of languages. We can start to incorporate more Java related projects into Nx and bring all of the features that Nx has to offer. Be sure to stop by tomorrow to see what else we have in store for Java developers.
|
||||
|
||||
---
|
||||
|
||||
Learn more:
|
||||
|
||||
- 🌌 [Nx Gradle Tutorial](/getting-started/tutorials/gradle-tutorial)
|
||||
- 📖 [Nx Gradle API](/technologies/java/api)
|
||||
- 👩💻 [Nx GitHub](https://github.com/nrwl/nx)
|
||||
- 👩💻 [Nx Console GitHub](https://github.com/nrwl/nx-console)
|
||||
- 💬 [Nx Official Discord Server](https://go.nx.dev/community)
|
||||
- 📹 [Nx Youtube Channel](https://www.youtube.com/@nxdevtools)
|
||||
@@ -0,0 +1,129 @@
|
||||
---
|
||||
title: 'Getting Mobile Into Your Monorepo: Android + Nx'
|
||||
slug: android-and-nx
|
||||
authors: ['Mike Hartington']
|
||||
tags: ['nx', 'java', 'android']
|
||||
cover_image: /blog/images/2025-07-30/header.avif
|
||||
description: 'Learn how to integrate an Android app using Kotlin and Jetpack Compose into an Nx monorepo, enabling full-stack builds and emulator deployment—all from the Nx CLI.'
|
||||
---
|
||||
|
||||
{% callout type="deepdive" title="Java Week Series" expanded=true %}
|
||||
|
||||
This article is part of the Java Week series:
|
||||
|
||||
- [The Journey of Nx Gradle](/blog/journey-of-nx-gradle)
|
||||
- [Polyglot Projects Made Easy](/blog/spring-boot-with-nx)
|
||||
- **Getting Mobile Into Your Monorepo**
|
||||
- [Seamless Deploys With Docker](/blog/seamless-deploys-with-docker)
|
||||
|
||||
{% /callout %}
|
||||
|
||||
Ok, so we now have a Java project in our monorepo, sitting along side of our React frontend app. We can run each of these from the Nx CLI and have a really good experience. But we can take this further. Java isn't only just used for backend apps. You can use Java to build things like Android apps, and Android apps can be built via Gradle. So in theory you could have frontend, backend, and mobile all coming from one monorepo. Now, I'm going out on my own here. Nx doesn't have an official Nx plugin for native Android, but in a attempt to see what is possible, let's try it!
|
||||
|
||||
## Android Setup
|
||||
|
||||
Ok, we aren't going to be using Java completely, instead we're going to use Kotlin which runs on the JVM. Kotlin's major feature is Jetpack Compose, a declarative approach to building interfaces for Android apps. We can then use Gradle to manage our dependencies and build the final `apk` for installation. But to get started, we do need the IDE of choice for Android development, [Android Studio](https://developer.android.com/studio). Android Studio is built on top of IntelliJ so if you've that before, you should feel at home. The major changes here are to add some needed features to managing your Android SDK and virtual devices.
|
||||
|
||||
Once installed, we'll go through some setup which installs the Android SDK for us. When setup, we'll create a new project based on an Empty Activity template. A word of caution, there are several templates that are based on the older "Views" approach, which is an XML-based approach of building your UI. While this is still a valid way of building Android apps, Google has recommended folks use Jetpack Compose over the XML approach. Be sure to chose the templates that do no include "Views".
|
||||
|
||||

|
||||
|
||||
From here, we do have a bit of work to prepare our project. Out of the box, Android Studio creates what is called a "multi-module" project. This is similar to a monorepo, as we could have multiple Java/Kotlin based apps or libraries in one repo. However, since our goal is to incorporate this into our previous monorepo, we need to consolidate this into a single module project. To do this, we're going to move some files around and merge our Gradle files for the project and for the `app` module.
|
||||
|
||||
> You really shouldn't need to do this, but for simplicity sake, we're doing it so we're not having to deal with Gradle's Composite Build.
|
||||
|
||||
Once built, let's just test a build inside of Android Studio to validate our app still builds and that Gradle has all the dependencies installed.
|
||||
|
||||

|
||||
|
||||
## Bringing in Nx
|
||||
|
||||
From here, we can follow the same process we used when bringing our Spring Boot app over to an existing Nx workspace.
|
||||
|
||||
```shell
|
||||
$ nx import ../mhartington/MyApplication
|
||||
|
||||
✔ Which branch do you want to import? · main
|
||||
✔ Which directory do you want to import into this workspace? ·
|
||||
? Where in this workspace should the code be imported into? › apps/android-frontend
|
||||
```
|
||||
|
||||
Once imported, we do need to help Nx know about this project a bit more. For starter, we need a `project.json` in the root of the app:
|
||||
|
||||
```json {% fileName="project.json" %}
|
||||
{
|
||||
"name": "android-frontend",
|
||||
"root": "apps/android-frontend",
|
||||
"projectType": "application"
|
||||
}
|
||||
```
|
||||
|
||||
Then we need to modify the `build.gradle.kt` to include the Nx Gradle plugin. This is currently a bug in the import process, so this is temporary. Remember, this isn't technically fully supported, so there be dragons:
|
||||
|
||||
```diff {% fileName="build.gralde.kt" %}
|
||||
plugins {
|
||||
+ id("dev.nx.gradle.project-graph") version "0.1.0"
|
||||
alias(libs.plugins.android.application)
|
||||
alias(libs.plugins.kotlin.android)
|
||||
alias(libs.plugins.kotlin.compose)
|
||||
}
|
||||
|
||||
android {...}
|
||||
dependencies {...}
|
||||
|
||||
+ allprojects {
|
||||
+ apply {
|
||||
+ plugin("dev.nx.gradle.project-graph")
|
||||
+ }
|
||||
+ }
|
||||
```
|
||||
|
||||
Then one last thing is to cd into the project and run a Gradle build:
|
||||
|
||||
```shell
|
||||
cd apps/android-frontend
|
||||
./gradlew build
|
||||
cd ../../
|
||||
|
||||
```
|
||||
|
||||
This just let's Gradle install the Nx plugin and sync all the dependencies.
|
||||
|
||||
## We Got Android, Now What?
|
||||
|
||||
Ok, that was a bit of work, but we're getting closer. From here we want to be able to deploy to an emulator from `nx`, so let's see what tasks we have available to use:
|
||||
|
||||
```shell
|
||||
nx show project android-frontend
|
||||
```
|
||||
|
||||

|
||||
|
||||
There are a lot of tasks in here, and most of them are not too relevant for us. How ever, I do know that there is a task we can run, and specifically an `installDebug` task.
|
||||
|
||||

|
||||
|
||||
Behind the scenes, `installDebug` will build our app, and deploy it to any device or emulator we have running.
|
||||
|
||||
```shell
|
||||
nx run android-frontend:installDebug
|
||||
```
|
||||
|
||||
We do need to have an emulator open, so we can start one from Android Studio or if you have the Android SDK available from the command line, you can start it that way. With `installDebug` running, we should be able to see the app get installed to the emulator. We'll need to manually open it up, but it does install.
|
||||
|
||||

|
||||
|
||||
## What’s Next
|
||||
|
||||
And that's it! It might seem not that impressive, but in the future, there could hypothetically be a dedicated Nx Android plugin that could handle starting your emulator and deploying your app. This could build on the Nx Gradle plugin and really help Android developers work more closely with their colleagues on the web team. We got one last blog post this week for our Java developers, so be sure to check back tomorrow and we'll get our app shipped 🚀.
|
||||
|
||||
---
|
||||
|
||||
Learn more:
|
||||
|
||||
- 🌌 [Nx Gradle Tutorial](/getting-started/tutorials/gradle-tutorial)
|
||||
- 📖 [Nx Gradle API](/technologies/java/api)
|
||||
- 👩💻 [Nx GitHub](https://github.com/nrwl/nx)
|
||||
- 👩💻 [Nx Console GitHub](https://github.com/nrwl/nx-console)
|
||||
- 💬 [Nx Official Discord Server](https://go.nx.dev/community)
|
||||
- 📹 [Nx Youtube Channel](https://www.youtube.com/@nxdevtools)
|
||||
@@ -0,0 +1,158 @@
|
||||
---
|
||||
title: 'Seamless Java Deployment in Nx Using Docker'
|
||||
slug: seamless-deploys-with-docker
|
||||
authors: ['Mike Hartington']
|
||||
tags: ['nx', 'java', 'docker']
|
||||
cover_image: /blog/images/2025-07-31/header.avif
|
||||
description: 'Learn how to package, run, and deploy a Java backend from an Nx monorepo using the new Nx Docker plugin—automating builds, streamlining releases, and shipping production-ready containers.'
|
||||
youtubeUrl: https://youtu.be/TOPxKJXUaqw
|
||||
---
|
||||
|
||||
{% callout type="deepdive" title="Java Week Series" expanded=true %}
|
||||
|
||||
This article is part of the Java Week series:
|
||||
|
||||
- [The Journey of Nx Gradle](/blog/journey-of-nx-gradle)
|
||||
- [Polyglot Projects Made Easy](/blog/spring-boot-with-nx)
|
||||
- [Getting Mobile Into Your Monorepo](/blog/android-and-nx)
|
||||
- **Seamless Deploys With Docker**
|
||||
|
||||
{% /callout %}
|
||||
|
||||
We've explored how you can add a Java app to an existing Nx workspace, but just getting the code in the same place doesn't really help _ship_ our code. With JavaScript apps, you simply need to have a static hosting provider or have a platform that can run node. But Java? Where do you even begin? Let's look at how we can get our Java backend deployed and automate it using Nx. We'll also get a sneak peek at a new plugin we've been working on.
|
||||
|
||||
## The Challenge: From Monorepo to Production
|
||||
|
||||
Running both the front-end and back-end within an Nx workspace is straightforward. But when it comes time to deploy your backend to a live URL, questions arise:
|
||||
|
||||
- How do we package and deploy a Java application from the monorepo?
|
||||
- Do we need a hosting provider that supports Java by default?
|
||||
- How do we ensure consistent environments across different platforms?
|
||||
|
||||
The solution: Docker.
|
||||
|
||||
Docker allows us to encapsulate our backend into an image, ensuring that it will run consistently across AWS, GCP, or any other provider. By combining Docker with `nx release`, we can:
|
||||
|
||||
- Automate the creation of Docker images for the backend.
|
||||
- Ensure builds are consistent and reproducible.
|
||||
- Push images directly to registries like Docker Hub for deployment.
|
||||
|
||||
The upcoming `@nx/docker` plugin takes this a step further, letting you define Docker workflows natively within Nx.
|
||||
|
||||
## Setting Up a Dockerfile for the Backend
|
||||
|
||||
To get started, we create a `Dockerfile` inside the Java backend directory of the Nx workspace. This file tells Docker how to build and run our application:
|
||||
|
||||
```
|
||||
FROM openjdk:26-slim-bullseye
|
||||
MAINTAINER baeldung.com
|
||||
EXPOSE 3000
|
||||
COPY build/libs/java-backend-0.0.1-SNAPSHOT.jar app.jar
|
||||
ENTRYPOINT ["java","-jar","/app.jar"]
|
||||
```
|
||||
|
||||
1. **Base Image:** Use `openjdk:26` as the starting point.
|
||||
2. **Expose Ports:** Our backend runs on port `3000`, so we expose this port for the container.
|
||||
3. **Copy the Build Artifact:** Copy the generated `.jar` file into the container as `app.jar`.
|
||||
4. **Set the Entry Point:** Run the app with `java -jar app.jar`.
|
||||
|
||||
This simple setup ensures that the container will spin up our backend just like we would run it locally. Now, we can manually run Docker ourselves from the command line, but we have Nx here, and it can do that for us. Let's add the new Nx Docker plugin:
|
||||
|
||||
```bash
|
||||
nx add @nx/docker
|
||||
```
|
||||
|
||||
In my project, I need to setup some port forwarding, so that the port my Java app runs on, can be exposed when the Docker image is started.
|
||||
|
||||
```json
|
||||
{
|
||||
"name": "java-backend",
|
||||
"root": "apps/java-backend",
|
||||
"projectType": "application",
|
||||
"targets": {
|
||||
"docker:run": {
|
||||
"options": {
|
||||
"args": ["-p", "3000:3000"]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
With this, `localhost:3000` will serve your API endpoints as if they were running directly on your machine.
|
||||
|
||||
Now with this new plugin, you can incorporate various Docker tasks in other parts of your Nx workflow, or as stand alone tasks. We can harness Nx’s task orchestration to build out a task pipeline. We can set `docker:build` to `dependsOn: ["build"]` and the `@nx/docker` plugin will already infer that `docker:run` `dependsOn: ["docker:build"]` ensuring that the docker image is available locally to run.
|
||||
|
||||
```bash
|
||||
nx docker:run java-backend
|
||||
```
|
||||
|
||||
All this from a simple command!
|
||||
|
||||
## Integrating Docker with Nx Release
|
||||
|
||||
Now creating and running a docker image is fine, but we want to coordinate this as part of a release so everything we built can be shipped together. This is where `nx release` comes in. Let's add a new `release` configuration in our `nx.json`:
|
||||
|
||||
```json
|
||||
{
|
||||
"release": {
|
||||
"projects": ["java-backend"],
|
||||
"projectsRelationship": "independent",
|
||||
"releaseTagPattern": "release/{projectName}/{version}",
|
||||
"docker": {
|
||||
"skipVersionActions": true
|
||||
},
|
||||
"changelog": {
|
||||
"projectChangelogs": true
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
This is fairly standard release config, but the `docker` entry is new. The `skipVersionActions` tells Nx to not attempt to version any of the packages we’re releasing. Typically, this means bumping the version to the next major/minor/patch depending on your commits. Since this is just a demo, we don't really need worry about versioning any packages, just versioning the Docker image.
|
||||
|
||||
Then, we need to include some release configuration to tell `nx release` about where we want our `java-backend` released to. Let's open the `project.json` and add a new release setup:
|
||||
|
||||
```json
|
||||
{
|
||||
"name": "java-backend",
|
||||
"root": "apps/java-backend",
|
||||
"projectType": "application",
|
||||
"targets": {...},
|
||||
"release": {
|
||||
"docker": {
|
||||
"repositoryName": "nrwlmike/java-app"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
The `repositoryName` is how `nx release` will know where it should upload the image to after it's ready. By default, this will publish to Docker Hub, but you can also set a `registryURL` to point it to your own private Docker registry if needed.
|
||||
|
||||
Now, it's time to ship it!
|
||||
|
||||
```bash
|
||||
nx release --first-release
|
||||
```
|
||||
|
||||
Nx will build, version, and publish your Docker image to Docker Hub.
|
||||
|
||||
## Deploying Anywhere
|
||||
|
||||
With the Docker image published, deployment becomes as simple as pointing any provider—AWS, GCP, or others—to your image. Your backend will spin up in a consistent, production-ready environment.
|
||||
|
||||
The Docker plugin is still experimental, but its integration into Nx’s existing build and release workflows makes deploying backends seamless. It takes care of the tedious steps, allowing you to focus on building features rather than managing deployment scripts.
|
||||
|
||||
If you're interested in knowing more, let us know! Join our community Discord and be on the look out for the official release of the Docker plugin.
|
||||
|
||||
---
|
||||
|
||||
Learn more:
|
||||
|
||||
- 🌌 [Nx Gradle Tutorial](/getting-started/tutorials/gradle-tutorial)
|
||||
- 📖 [Nx Gradle API](/technologies/java/api)
|
||||
- 📦 [Nx Release](/features/manage-releases)
|
||||
- 👩💻 [Nx GitHub](https://github.com/nrwl/nx)
|
||||
- 👩💻 [Nx Console GitHub](https://github.com/nrwl/nx-console)
|
||||
- 💬 [Nx Official Discord Server](https://go.nx.dev/community)
|
||||
- 📹 [Nx Youtube Channel](https://www.youtube.com/@nxdevtools)
|
||||
|
After Width: | Height: | Size: 17 KiB |
|
After Width: | Height: | Size: 333 KiB |
|
After Width: | Height: | Size: 14 KiB |
|
After Width: | Height: | Size: 761 KiB |
|
After Width: | Height: | Size: 556 KiB |
|
After Width: | Height: | Size: 52 KiB |
|
After Width: | Height: | Size: 440 KiB |
|
After Width: | Height: | Size: 606 KiB |
|
After Width: | Height: | Size: 643 KiB |
|
After Width: | Height: | Size: 433 KiB |
|
After Width: | Height: | Size: 2.0 MiB |
|
After Width: | Height: | Size: 897 KiB |
|
After Width: | Height: | Size: 480 KiB |
|
After Width: | Height: | Size: 716 KiB |
|
After Width: | Height: | Size: 415 KiB |
|
After Width: | Height: | Size: 12 KiB |
|
After Width: | Height: | Size: 707 KiB |
|
After Width: | Height: | Size: 503 KiB |
|
After Width: | Height: | Size: 327 KiB |
|
After Width: | Height: | Size: 13 KiB |
|
After Width: | Height: | Size: 704 KiB |
|
After Width: | Height: | Size: 27 KiB |
|
After Width: | Height: | Size: 972 KiB |
|
After Width: | Height: | Size: 27 KiB |
@@ -0,0 +1,19 @@
|
||||
# Nx 21.3
|
||||
|
||||
## Features
|
||||
|
||||
{% cards cols="2" %}
|
||||
{% card title="Angular 20.1 Support" type="document" url="/technologies/angular/introduction" /%}
|
||||
{% card title="Jest 30 Support" type="document" url="/technologies/test-tools/jest/introduction" /%}
|
||||
{% card title="Enhanced TUI with Live Task Durations" type="external" url="https://github.com/nrwl/nx/pull/31897" /%}
|
||||
{% card title="CI Workflow Enhancements" type="external" url="https://github.com/nrwl/nx/pull/31833" /%}
|
||||
{% /cards %}
|
||||
|
||||
## Bug Fixes
|
||||
|
||||
{% cards cols="2" %}
|
||||
{% card title="Improved TUI Terminal Output for Skipped Tasks" type="external" url="https://github.com/nrwl/nx/pull/31559" /%}
|
||||
{% card title="Better Error Handling in Daemon Server" type="external" url="https://github.com/nrwl/nx/pull/31728" /%}
|
||||
{% card title="Fix Angular NgRx Facade Spec Generation" type="external" url="https://github.com/nrwl/nx/pull/31850" /%}
|
||||
{% card title="Improved Parent Gitignore Handling for Nested Workspaces" type="external" url="https://github.com/nrwl/nx/pull/31911" /%}
|
||||
{% /cards %}
|
||||
@@ -17,4 +17,4 @@ We’ll also take a quick detour to discuss `namedInputs` in `nx.json`, ensuring
|
||||
## Relevant Links
|
||||
|
||||
- [Run Only Tasks Affected by a PR](/ci/features/affected)
|
||||
- [Tutorial: Github Actions with Nx](/ci/intro/tutorials/github-actions#create-a-ci-workflow)
|
||||
- [Guide: Github Actions with Nx](/ci/recipes/set-up/monorepo-ci-github-actions)
|
||||
|
||||
@@ -38,40 +38,6 @@
|
||||
"isExternal": false,
|
||||
"path": "/ci/intro/connect-to-nx-cloud",
|
||||
"tags": []
|
||||
},
|
||||
{
|
||||
"id": "tutorials",
|
||||
"name": "Tutorials",
|
||||
"description": "Tutorials setting up CI with Nx",
|
||||
"mediaImage": "",
|
||||
"file": "",
|
||||
"itemList": [
|
||||
{
|
||||
"id": "circle",
|
||||
"name": "Circle CI with Nx",
|
||||
"description": "",
|
||||
"mediaImage": "",
|
||||
"file": "nx-cloud/tutorial/circle",
|
||||
"itemList": [],
|
||||
"isExternal": false,
|
||||
"path": "/ci/intro/tutorials/circle",
|
||||
"tags": []
|
||||
},
|
||||
{
|
||||
"id": "github-actions",
|
||||
"name": "GitHub Actions with Nx",
|
||||
"description": "",
|
||||
"mediaImage": "",
|
||||
"file": "nx-cloud/tutorial/github-actions",
|
||||
"itemList": [],
|
||||
"isExternal": false,
|
||||
"path": "/ci/intro/tutorials/github-actions",
|
||||
"tags": []
|
||||
}
|
||||
],
|
||||
"isExternal": false,
|
||||
"path": "/ci/intro/tutorials",
|
||||
"tags": []
|
||||
}
|
||||
],
|
||||
"isExternal": false,
|
||||
@@ -111,62 +77,6 @@
|
||||
"path": "/ci/intro/connect-to-nx-cloud",
|
||||
"tags": []
|
||||
},
|
||||
"/ci/intro/tutorials": {
|
||||
"id": "tutorials",
|
||||
"name": "Tutorials",
|
||||
"description": "Tutorials setting up CI with Nx",
|
||||
"mediaImage": "",
|
||||
"file": "",
|
||||
"itemList": [
|
||||
{
|
||||
"id": "circle",
|
||||
"name": "Circle CI with Nx",
|
||||
"description": "",
|
||||
"mediaImage": "",
|
||||
"file": "nx-cloud/tutorial/circle",
|
||||
"itemList": [],
|
||||
"isExternal": false,
|
||||
"path": "/ci/intro/tutorials/circle",
|
||||
"tags": []
|
||||
},
|
||||
{
|
||||
"id": "github-actions",
|
||||
"name": "GitHub Actions with Nx",
|
||||
"description": "",
|
||||
"mediaImage": "",
|
||||
"file": "nx-cloud/tutorial/github-actions",
|
||||
"itemList": [],
|
||||
"isExternal": false,
|
||||
"path": "/ci/intro/tutorials/github-actions",
|
||||
"tags": []
|
||||
}
|
||||
],
|
||||
"isExternal": false,
|
||||
"path": "/ci/intro/tutorials",
|
||||
"tags": []
|
||||
},
|
||||
"/ci/intro/tutorials/circle": {
|
||||
"id": "circle",
|
||||
"name": "Circle CI with Nx",
|
||||
"description": "",
|
||||
"mediaImage": "",
|
||||
"file": "nx-cloud/tutorial/circle",
|
||||
"itemList": [],
|
||||
"isExternal": false,
|
||||
"path": "/ci/intro/tutorials/circle",
|
||||
"tags": []
|
||||
},
|
||||
"/ci/intro/tutorials/github-actions": {
|
||||
"id": "github-actions",
|
||||
"name": "GitHub Actions with Nx",
|
||||
"description": "",
|
||||
"mediaImage": "",
|
||||
"file": "nx-cloud/tutorial/github-actions",
|
||||
"itemList": [],
|
||||
"isExternal": false,
|
||||
"path": "/ci/intro/tutorials/github-actions",
|
||||
"tags": []
|
||||
},
|
||||
"/ci/features": {
|
||||
"id": "features",
|
||||
"name": "Features",
|
||||
|
||||
@@ -462,9 +462,25 @@
|
||||
"isExternal": false,
|
||||
"children": [
|
||||
{
|
||||
"name": "Get Started with Nx Release",
|
||||
"path": "/recipes/nx-release/get-started-with-nx-release",
|
||||
"id": "get-started-with-nx-release",
|
||||
"name": "Release TypeScript/JavaScript Packages to NPM",
|
||||
"path": "/recipes/nx-release/release-npm-packages",
|
||||
"id": "release-npm-packages",
|
||||
"isExternal": false,
|
||||
"children": [],
|
||||
"disableCollapsible": false
|
||||
},
|
||||
{
|
||||
"name": "Release Docker Images",
|
||||
"path": "/recipes/nx-release/release-docker-images",
|
||||
"id": "release-docker-images",
|
||||
"isExternal": false,
|
||||
"children": [],
|
||||
"disableCollapsible": false
|
||||
},
|
||||
{
|
||||
"name": "Release Rust Crates",
|
||||
"path": "/recipes/nx-release/publish-rust-crates",
|
||||
"id": "publish-rust-crates",
|
||||
"isExternal": false,
|
||||
"children": [],
|
||||
"disableCollapsible": false
|
||||
@@ -541,14 +557,6 @@
|
||||
"children": [],
|
||||
"disableCollapsible": false
|
||||
},
|
||||
{
|
||||
"name": "Publish Rust Crates",
|
||||
"path": "/recipes/nx-release/publish-rust-crates",
|
||||
"id": "publish-rust-crates",
|
||||
"isExternal": false,
|
||||
"children": [],
|
||||
"disableCollapsible": false
|
||||
},
|
||||
{
|
||||
"name": "Update Your Local Registry Setup to use Nx Release",
|
||||
"path": "/recipes/nx-release/update-local-registry-setup",
|
||||
@@ -6802,31 +6810,6 @@
|
||||
"isExternal": false,
|
||||
"children": [],
|
||||
"disableCollapsible": false
|
||||
},
|
||||
{
|
||||
"name": "Tutorials",
|
||||
"path": "/ci/intro/tutorials",
|
||||
"id": "tutorials",
|
||||
"isExternal": false,
|
||||
"children": [
|
||||
{
|
||||
"name": "Circle CI with Nx",
|
||||
"path": "/ci/intro/tutorials/circle",
|
||||
"id": "circle",
|
||||
"isExternal": false,
|
||||
"children": [],
|
||||
"disableCollapsible": false
|
||||
},
|
||||
{
|
||||
"name": "GitHub Actions with Nx",
|
||||
"path": "/ci/intro/tutorials/github-actions",
|
||||
"id": "github-actions",
|
||||
"isExternal": false,
|
||||
"children": [],
|
||||
"disableCollapsible": false
|
||||
}
|
||||
],
|
||||
"disableCollapsible": false
|
||||
}
|
||||
],
|
||||
"disableCollapsible": false
|
||||
|
||||
@@ -399,6 +399,16 @@
|
||||
}
|
||||
},
|
||||
"migrations": {
|
||||
"/technologies/angular/api/migrations/21.3.5-jest-package-updates": {
|
||||
"description": "",
|
||||
"file": "generated/packages/angular/migrations/21.3.5-jest-package-updates.json",
|
||||
"hidden": false,
|
||||
"name": "21.3.5-jest-package-updates",
|
||||
"version": "21.3.5-beta.0",
|
||||
"originalFilePath": "/packages/angular",
|
||||
"path": "/technologies/angular/api/migrations/21.3.5-jest-package-updates",
|
||||
"type": "migration"
|
||||
},
|
||||
"/technologies/angular/api/migrations/update-angular-cli-version-20-1-0": {
|
||||
"description": "Update the @angular/cli package version to ~20.1.0.",
|
||||
"file": "generated/packages/angular/migrations/update-angular-cli-version-20-1-0.json",
|
||||
@@ -2218,6 +2228,26 @@
|
||||
}
|
||||
},
|
||||
"migrations": {
|
||||
"/technologies/test-tools/jest/api/migrations/21.3.3-jest-util-package-updates": {
|
||||
"description": "",
|
||||
"file": "generated/packages/jest/migrations/21.3.3-jest-util-package-updates.json",
|
||||
"hidden": false,
|
||||
"name": "21.3.3-jest-util-package-updates",
|
||||
"version": "21.3.3-beta.3",
|
||||
"originalFilePath": "/packages/jest",
|
||||
"path": "/technologies/test-tools/jest/api/migrations/21.3.3-jest-util-package-updates",
|
||||
"type": "migration"
|
||||
},
|
||||
"/technologies/test-tools/jest/api/migrations/21.3.3-package-updates": {
|
||||
"description": "",
|
||||
"file": "generated/packages/jest/migrations/21.3.3-package-updates.json",
|
||||
"hidden": false,
|
||||
"name": "21.3.3-package-updates",
|
||||
"version": "21.3.3-beta.0",
|
||||
"originalFilePath": "/packages/jest",
|
||||
"path": "/technologies/test-tools/jest/api/migrations/21.3.3-package-updates",
|
||||
"type": "migration"
|
||||
},
|
||||
"/technologies/test-tools/jest/api/migrations/rename-test-path-pattern": {
|
||||
"description": "Rename the CLI option `testPathPattern` to `testPathPatterns`.",
|
||||
"file": "generated/packages/jest/migrations/rename-test-path-pattern.json",
|
||||
|
||||
@@ -1057,14 +1057,36 @@
|
||||
"file": "",
|
||||
"itemList": [
|
||||
{
|
||||
"id": "get-started-with-nx-release",
|
||||
"name": "Get Started with Nx Release",
|
||||
"id": "release-npm-packages",
|
||||
"name": "Release TypeScript/JavaScript Packages to NPM",
|
||||
"description": "",
|
||||
"mediaImage": "",
|
||||
"file": "shared/recipes/nx-release/get-started-with-nx-release",
|
||||
"file": "shared/recipes/nx-release/release-typescript-packages-to-npm",
|
||||
"itemList": [],
|
||||
"isExternal": false,
|
||||
"path": "/recipes/nx-release/get-started-with-nx-release",
|
||||
"path": "/recipes/nx-release/release-npm-packages",
|
||||
"tags": ["nx-release"]
|
||||
},
|
||||
{
|
||||
"id": "release-docker-images",
|
||||
"name": "Release Docker Images",
|
||||
"description": "",
|
||||
"mediaImage": "",
|
||||
"file": "shared/recipes/nx-release/release-docker-images",
|
||||
"itemList": [],
|
||||
"isExternal": false,
|
||||
"path": "/recipes/nx-release/release-docker-images",
|
||||
"tags": ["nx-release"]
|
||||
},
|
||||
{
|
||||
"id": "publish-rust-crates",
|
||||
"name": "Release Rust Crates",
|
||||
"description": "",
|
||||
"mediaImage": "",
|
||||
"file": "shared/recipes/nx-release/publish-rust-crates",
|
||||
"itemList": [],
|
||||
"isExternal": false,
|
||||
"path": "/recipes/nx-release/publish-rust-crates",
|
||||
"tags": ["nx-release"]
|
||||
},
|
||||
{
|
||||
@@ -1166,17 +1188,6 @@
|
||||
"path": "/recipes/nx-release/automate-gitlab-releases",
|
||||
"tags": ["nx-release"]
|
||||
},
|
||||
{
|
||||
"id": "publish-rust-crates",
|
||||
"name": "Publish Rust Crates",
|
||||
"description": "",
|
||||
"mediaImage": "",
|
||||
"file": "shared/recipes/nx-release/publish-rust-crates",
|
||||
"itemList": [],
|
||||
"isExternal": false,
|
||||
"path": "/recipes/nx-release/publish-rust-crates",
|
||||
"tags": ["nx-release"]
|
||||
},
|
||||
{
|
||||
"id": "update-local-registry-setup",
|
||||
"name": "Update Your Local Registry Setup to use Nx Release",
|
||||
@@ -2026,14 +2037,36 @@
|
||||
"file": "",
|
||||
"itemList": [
|
||||
{
|
||||
"id": "get-started-with-nx-release",
|
||||
"name": "Get Started with Nx Release",
|
||||
"id": "release-npm-packages",
|
||||
"name": "Release TypeScript/JavaScript Packages to NPM",
|
||||
"description": "",
|
||||
"mediaImage": "",
|
||||
"file": "shared/recipes/nx-release/get-started-with-nx-release",
|
||||
"file": "shared/recipes/nx-release/release-typescript-packages-to-npm",
|
||||
"itemList": [],
|
||||
"isExternal": false,
|
||||
"path": "/recipes/nx-release/get-started-with-nx-release",
|
||||
"path": "/recipes/nx-release/release-npm-packages",
|
||||
"tags": ["nx-release"]
|
||||
},
|
||||
{
|
||||
"id": "release-docker-images",
|
||||
"name": "Release Docker Images",
|
||||
"description": "",
|
||||
"mediaImage": "",
|
||||
"file": "shared/recipes/nx-release/release-docker-images",
|
||||
"itemList": [],
|
||||
"isExternal": false,
|
||||
"path": "/recipes/nx-release/release-docker-images",
|
||||
"tags": ["nx-release"]
|
||||
},
|
||||
{
|
||||
"id": "publish-rust-crates",
|
||||
"name": "Release Rust Crates",
|
||||
"description": "",
|
||||
"mediaImage": "",
|
||||
"file": "shared/recipes/nx-release/publish-rust-crates",
|
||||
"itemList": [],
|
||||
"isExternal": false,
|
||||
"path": "/recipes/nx-release/publish-rust-crates",
|
||||
"tags": ["nx-release"]
|
||||
},
|
||||
{
|
||||
@@ -2135,17 +2168,6 @@
|
||||
"path": "/recipes/nx-release/automate-gitlab-releases",
|
||||
"tags": ["nx-release"]
|
||||
},
|
||||
{
|
||||
"id": "publish-rust-crates",
|
||||
"name": "Publish Rust Crates",
|
||||
"description": "",
|
||||
"mediaImage": "",
|
||||
"file": "shared/recipes/nx-release/publish-rust-crates",
|
||||
"itemList": [],
|
||||
"isExternal": false,
|
||||
"path": "/recipes/nx-release/publish-rust-crates",
|
||||
"tags": ["nx-release"]
|
||||
},
|
||||
{
|
||||
"id": "update-local-registry-setup",
|
||||
"name": "Update Your Local Registry Setup to use Nx Release",
|
||||
@@ -2195,15 +2217,37 @@
|
||||
"path": "/recipes/nx-release",
|
||||
"tags": []
|
||||
},
|
||||
"/recipes/nx-release/get-started-with-nx-release": {
|
||||
"id": "get-started-with-nx-release",
|
||||
"name": "Get Started with Nx Release",
|
||||
"/recipes/nx-release/release-npm-packages": {
|
||||
"id": "release-npm-packages",
|
||||
"name": "Release TypeScript/JavaScript Packages to NPM",
|
||||
"description": "",
|
||||
"mediaImage": "",
|
||||
"file": "shared/recipes/nx-release/get-started-with-nx-release",
|
||||
"file": "shared/recipes/nx-release/release-typescript-packages-to-npm",
|
||||
"itemList": [],
|
||||
"isExternal": false,
|
||||
"path": "/recipes/nx-release/get-started-with-nx-release",
|
||||
"path": "/recipes/nx-release/release-npm-packages",
|
||||
"tags": ["nx-release"]
|
||||
},
|
||||
"/recipes/nx-release/release-docker-images": {
|
||||
"id": "release-docker-images",
|
||||
"name": "Release Docker Images",
|
||||
"description": "",
|
||||
"mediaImage": "",
|
||||
"file": "shared/recipes/nx-release/release-docker-images",
|
||||
"itemList": [],
|
||||
"isExternal": false,
|
||||
"path": "/recipes/nx-release/release-docker-images",
|
||||
"tags": ["nx-release"]
|
||||
},
|
||||
"/recipes/nx-release/publish-rust-crates": {
|
||||
"id": "publish-rust-crates",
|
||||
"name": "Release Rust Crates",
|
||||
"description": "",
|
||||
"mediaImage": "",
|
||||
"file": "shared/recipes/nx-release/publish-rust-crates",
|
||||
"itemList": [],
|
||||
"isExternal": false,
|
||||
"path": "/recipes/nx-release/publish-rust-crates",
|
||||
"tags": ["nx-release"]
|
||||
},
|
||||
"/recipes/nx-release/release-projects-independently": {
|
||||
@@ -2305,17 +2349,6 @@
|
||||
"path": "/recipes/nx-release/automate-gitlab-releases",
|
||||
"tags": ["nx-release"]
|
||||
},
|
||||
"/recipes/nx-release/publish-rust-crates": {
|
||||
"id": "publish-rust-crates",
|
||||
"name": "Publish Rust Crates",
|
||||
"description": "",
|
||||
"mediaImage": "",
|
||||
"file": "shared/recipes/nx-release/publish-rust-crates",
|
||||
"itemList": [],
|
||||
"isExternal": false,
|
||||
"path": "/recipes/nx-release/publish-rust-crates",
|
||||
"tags": ["nx-release"]
|
||||
},
|
||||
"/recipes/nx-release/update-local-registry-setup": {
|
||||
"id": "update-local-registry-setup",
|
||||
"name": "Update Your Local Registry Setup to use Nx Release",
|
||||
|
||||
@@ -672,10 +672,24 @@
|
||||
},
|
||||
{
|
||||
"description": "",
|
||||
"file": "shared/recipes/nx-release/get-started-with-nx-release",
|
||||
"id": "get-started-with-nx-release",
|
||||
"name": "Get Started with Nx Release",
|
||||
"path": "/recipes/nx-release/get-started-with-nx-release"
|
||||
"file": "shared/recipes/nx-release/release-typescript-packages-to-npm",
|
||||
"id": "release-npm-packages",
|
||||
"name": "Release TypeScript/JavaScript Packages to NPM",
|
||||
"path": "/recipes/nx-release/release-npm-packages"
|
||||
},
|
||||
{
|
||||
"description": "",
|
||||
"file": "shared/recipes/nx-release/release-docker-images",
|
||||
"id": "release-docker-images",
|
||||
"name": "Release Docker Images",
|
||||
"path": "/recipes/nx-release/release-docker-images"
|
||||
},
|
||||
{
|
||||
"description": "",
|
||||
"file": "shared/recipes/nx-release/publish-rust-crates",
|
||||
"id": "publish-rust-crates",
|
||||
"name": "Release Rust Crates",
|
||||
"path": "/recipes/nx-release/publish-rust-crates"
|
||||
},
|
||||
{
|
||||
"description": "",
|
||||
@@ -740,13 +754,6 @@
|
||||
"name": "Automate GitLab Releases",
|
||||
"path": "/recipes/nx-release/automate-gitlab-releases"
|
||||
},
|
||||
{
|
||||
"description": "",
|
||||
"file": "shared/recipes/nx-release/publish-rust-crates",
|
||||
"id": "publish-rust-crates",
|
||||
"name": "Publish Rust Crates",
|
||||
"path": "/recipes/nx-release/publish-rust-crates"
|
||||
},
|
||||
{
|
||||
"description": "",
|
||||
"file": "shared/recipes/nx-release/update-local-registry-setup",
|
||||
|
||||
@@ -439,6 +439,16 @@
|
||||
}
|
||||
],
|
||||
"migrations": [
|
||||
{
|
||||
"description": "",
|
||||
"file": "generated/packages/angular/migrations/21.3.5-jest-package-updates.json",
|
||||
"hidden": false,
|
||||
"name": "21.3.5-jest-package-updates",
|
||||
"version": "21.3.5-beta.0",
|
||||
"originalFilePath": "/packages/angular",
|
||||
"path": "angular/migrations/21.3.5-jest-package-updates",
|
||||
"type": "migration"
|
||||
},
|
||||
{
|
||||
"description": "Update the @angular/cli package version to ~20.1.0.",
|
||||
"file": "generated/packages/angular/migrations/update-angular-cli-version-20-1-0.json",
|
||||
@@ -2402,6 +2412,26 @@
|
||||
}
|
||||
],
|
||||
"migrations": [
|
||||
{
|
||||
"description": "",
|
||||
"file": "generated/packages/jest/migrations/21.3.3-jest-util-package-updates.json",
|
||||
"hidden": false,
|
||||
"name": "21.3.3-jest-util-package-updates",
|
||||
"version": "21.3.3-beta.3",
|
||||
"originalFilePath": "/packages/jest",
|
||||
"path": "jest/migrations/21.3.3-jest-util-package-updates",
|
||||
"type": "migration"
|
||||
},
|
||||
{
|
||||
"description": "",
|
||||
"file": "generated/packages/jest/migrations/21.3.3-package-updates.json",
|
||||
"hidden": false,
|
||||
"name": "21.3.3-package-updates",
|
||||
"version": "21.3.3-beta.0",
|
||||
"originalFilePath": "/packages/jest",
|
||||
"path": "jest/migrations/21.3.3-package-updates",
|
||||
"type": "migration"
|
||||
},
|
||||
{
|
||||
"description": "Rename the CLI option `testPathPattern` to `testPathPatterns`.",
|
||||
"file": "generated/packages/jest/migrations/rename-test-path-pattern.json",
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
"name": {
|
||||
"description": "The name of the application.",
|
||||
"type": "string",
|
||||
"pattern": "^[a-zA-Z][^:]*$",
|
||||
"pattern": "(?:^@[a-zA-Z0-9-*~][a-zA-Z0-9-*._~]*\\/[a-zA-Z0-9-~][a-zA-Z0-9-._~]*|^[a-zA-Z][^:]*)$",
|
||||
"x-priority": "important"
|
||||
},
|
||||
"style": {
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
{
|
||||
"name": "21.3.5-jest-package-updates",
|
||||
"version": "21.3.5-beta.0",
|
||||
"requires": {
|
||||
"@angular/compiler-cli": ">=18.0.0 <21.0.0",
|
||||
"@angular/core": ">=18.0.0 <21.0.0",
|
||||
"@angular/platform-browser-dynamic": ">=18.0.0 <21.0.0",
|
||||
"jest": "^30.0.0"
|
||||
},
|
||||
"packages": {
|
||||
"jest-preset-angular": {
|
||||
"version": "~15.0.0",
|
||||
"alwaysAddToPackageJson": false
|
||||
}
|
||||
},
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"hidden": false,
|
||||
"implementation": "",
|
||||
"path": "/packages/angular",
|
||||
"schema": null,
|
||||
"type": "migration"
|
||||
}
|
||||
@@ -27,7 +27,7 @@
|
||||
"name": {
|
||||
"description": "The name of the application.",
|
||||
"type": "string",
|
||||
"pattern": "^[a-zA-Z][^:]*$",
|
||||
"pattern": "(?:^@[a-zA-Z0-9-*~][a-zA-Z0-9-*._~]*\\/[a-zA-Z0-9-~][a-zA-Z0-9-._~]*|^[a-zA-Z][^:]*)$",
|
||||
"x-priority": "important"
|
||||
},
|
||||
"displayName": {
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
},
|
||||
"name": {
|
||||
"description": "The name of the application.",
|
||||
"pattern": "^[a-zA-Z][^:]*$",
|
||||
"pattern": "(?:^@[a-zA-Z0-9-*~][a-zA-Z0-9-*._~]*\\/[a-zA-Z0-9-~][a-zA-Z0-9-._~]*|^[a-zA-Z][^:]*)$",
|
||||
"type": "string"
|
||||
},
|
||||
"skipFormat": {
|
||||
|
||||
@@ -152,7 +152,8 @@ The `@nx/gradle` is configured in the `plugins` array in `nx.json`.
|
||||
"testTargetName": "test",
|
||||
"classesTargetName": "classes",
|
||||
"buildTargetName": "build",
|
||||
"ciTestTargetName": "test-ci"
|
||||
"ciTestTargetName": "test-ci",
|
||||
"ciIntTestTargetName": "intTest-ci"
|
||||
}
|
||||
}
|
||||
]
|
||||
@@ -161,23 +162,101 @@ The `@nx/gradle` is configured in the `plugins` array in `nx.json`.
|
||||
|
||||
Once a Gradle configuration file has been identified, the targets are created with the name you specify under `testTargetName`, `classesTargetName` or `buildTargetName` in the `nx.json` `plugins` array. The default names for the inferred targets are `test`, `classes` and `build`.
|
||||
|
||||
### Splitting Tests
|
||||
### Test Distribution
|
||||
|
||||
The `@nx/gradle` plugin will automatically split your testing tasks by test class if you provide a `ciTestTargetName`. You can read more about the Atomizer feature [here](/ci/features/split-e2e-tasks). Nx will create a task with the name that you specify which can be used in CI to run the tests for each test class in a distributed fashion.
|
||||
Nx provides powerful features for distributing tasks in CI, including test splitting (also known as atomization) and optimized build targets. For Gradle projects, this is facilitated by the `@nx/gradle` plugin, allowing you to run your tests and builds more efficiently in your Continuous Integration (CI) environment.
|
||||
|
||||
```json {% fileName="nx.json" highlightLines=[6] %}
|
||||
#### How to Set Up Test Distribution (Atomizer) in CI
|
||||
|
||||
To enable test distribution for your Gradle projects in CI, follow these steps:
|
||||
|
||||
1. **Generate CI Workflow**: Run the `ci-workflow` generator to set up the necessary CI configurations. This generator creates a GitHub Actions workflow file that integrates with Nx's distributed task execution capabilities.
|
||||
|
||||
```shell
|
||||
nx g @nx/gradle:ci-workflow
|
||||
```
|
||||
|
||||
This command will generate a workflow file (e.g., `.github/workflows/ci.yml`) tailored for your Nx workspace with Gradle projects.
|
||||
|
||||
2. **Configure `nx.json` for Atomizer**: Add or ensure the presence of `ciTestTargetName` or `ciIntTestTargetName` in the `@nx/gradle` plugin options within your `nx.json`.
|
||||
|
||||
```json {% fileName="nx.json" highlightLines=[6,7] %}
|
||||
{
|
||||
"plugins": [
|
||||
{
|
||||
"plugin": "@nx/gradle",
|
||||
"options": {
|
||||
"ciTestTargetName": "test-ci",
|
||||
"ciIntTestTargetName": "intTest-ci"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
Setting these options turns on the atomizer feature in CI. Nx will automatically split your testing tasks (unit and integration tests, respectively) by test class, allowing them to be run in a distributed fashion across your CI agents.
|
||||
|
||||
3. **Update CI Workflow Command**: In your generated CI workflow file, modify the command used to run affected tasks. Instead of using a generic `build` target, leverage the `build-ci` target provided by the `@nx/gradle` plugin:
|
||||
|
||||
```shell
|
||||
# Before:
|
||||
# ./nx affected --base=$NX_BASE --head=$NX_HEAD -t build
|
||||
|
||||
# After:
|
||||
./nx affected --base=$NX_BASE --head=$NX_HEAD -t build-ci
|
||||
```
|
||||
|
||||
This ensures that your CI pipeline utilizes the optimized `build-ci` target, which is designed to integrate seamlessly with Nx's test distribution and caching mechanisms.
|
||||
|
||||
#### The `ci-workflow` Generator
|
||||
|
||||
The `@nx/gradle:ci-workflow` generator is a utility that automates the setup of a CI workflow for your Nx workspace containing Gradle projects. It creates a `.github/workflows` file (or equivalent for other CI providers) that includes steps for checking out code, setting up Java and Gradle, restoring caches, and running affected Nx tasks. Its primary purpose is to streamline the integration of Nx's CI features, such as distributed task execution and caching, into your existing CI pipeline.
|
||||
|
||||
#### The `build-ci` Target
|
||||
|
||||
The `@nx/gradle` plugin can create a `build-ci` target that is specifically designed for use in CI environments. This target allows for a more optimized and consistent build process by ensuring that the `check` task is rewired to its CI counterpart (`check-ci`), which also implies that test tasks (`test` and `intTest`) are rewired to their atomized `test-ci` and `intTest-ci` counterparts respectively.
|
||||
|
||||
##### What is it?
|
||||
|
||||
The `build-ci` target is a synthetic Nx target that acts as a placeholder for your Gradle `build` task in a CI context. Instead of directly running the `build` task, the `build-ci` target ensures that the `check` task (a dependency of `build`) first executes its CI-optimized version (`check-ci`), which in turn uses the split/atomized test tasks (`test-ci`, `intTest-ci`). This allows for distributed execution of tests and efficient caching in CI.
|
||||
|
||||
##### How to Enable?
|
||||
|
||||
To enable the `build-ci` target, you need to configure `ciTestTargetName` or `ciIntTestTargetName` in the `@nx/gradle` plugin options in your `nx.json`.
|
||||
|
||||
For example:
|
||||
|
||||
```json {% fileName="nx.json" %}
|
||||
{
|
||||
"plugins": [
|
||||
{
|
||||
"plugin": "@nx/gradle",
|
||||
"options": {
|
||||
"ciTestTargetName": "test-ci"
|
||||
"ciTestTargetName": "test-ci",
|
||||
"ciBuildTargetName": "build-ci"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
When `ciTestTargetName` (or `ciIntTestTargetName`) is set, the `build-ci` target is automatically created if the `build` task exists for a given Gradle project.
|
||||
|
||||
##### Expected Behavior
|
||||
|
||||
When you run `nx build-ci <your-gradle-project>`, Nx will:
|
||||
|
||||
1. Execute the `check-ci` task (if defined) instead of the standard `check` task.
|
||||
2. The `check-ci` task will, in turn, trigger the atomized test tasks (`test-ci` and `intTest-ci`) if they are configured.
|
||||
3. The `build-ci` target itself will use the `nx:noop` executor, meaning it doesn't execute a direct Gradle command, but rather relies on its dependencies (`check-ci`) to orchestrate the build process in a CI-friendly manner.
|
||||
4. The `build-ci` target is cacheable.
|
||||
|
||||
This setup ensures that your build process in CI leverages Nx's caching and distribution capabilities effectively.
|
||||
|
||||
##### How to Turn it Off?
|
||||
|
||||
To disable the `build-ci` target, simply remove the `ciBuildTargetName` option from the `@nx/gradle` plugin configuration in your `nx.json` file. If `ciTestTargetName` and `ciIntTestTargetName` are also removed, then the special CI targets for tests and check will also be turned off.
|
||||
|
||||
### Continuous Tasks
|
||||
|
||||
Gradle doesn't have a standard way to identify tasks which are [continuous](/reference/project-configuration#continuous), like `bootRun` for serving a Spring Boot project. To ensure Nx handles these continuous tasks correctly, you can explicitly mark them as continuous.
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"name": "21.3.3-jest-util-package-updates",
|
||||
"version": "21.3.3-beta.3",
|
||||
"requires": { "jest": ">=30.0.0 <31.0.0", "ts-jest": ">=29.4.0" },
|
||||
"packages": {
|
||||
"jest-util": { "version": "~30.0.0", "addToPackageJson": "devDependencies" }
|
||||
},
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"hidden": false,
|
||||
"implementation": "",
|
||||
"path": "/packages/jest",
|
||||
"schema": null,
|
||||
"type": "migration"
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"name": "21.3.3-package-updates",
|
||||
"version": "21.3.3-beta.0",
|
||||
"packages": {
|
||||
"ts-jest": { "version": "~29.4.0", "alwaysAddToPackageJson": false }
|
||||
},
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"hidden": false,
|
||||
"implementation": "",
|
||||
"path": "/packages/jest",
|
||||
"schema": null,
|
||||
"type": "migration"
|
||||
}
|
||||
@@ -18,7 +18,7 @@
|
||||
"name": {
|
||||
"description": "The name of the application.",
|
||||
"type": "string",
|
||||
"pattern": "^[a-zA-Z][^:]*$",
|
||||
"pattern": "(?:^@[a-zA-Z0-9-*~][a-zA-Z0-9-*._~]*\\/[a-zA-Z0-9-~][a-zA-Z0-9-._~]*|^[a-zA-Z][^:]*)$",
|
||||
"x-priority": "important"
|
||||
},
|
||||
"skipFormat": {
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
"name": {
|
||||
"description": "The name of the application.",
|
||||
"type": "string",
|
||||
"pattern": "^[a-zA-Z][^:]*$",
|
||||
"pattern": "(?:^@[a-zA-Z0-9-*~][a-zA-Z0-9-*._~]*\\/[a-zA-Z0-9-~][a-zA-Z0-9-._~]*|^[a-zA-Z][^:]*)$",
|
||||
"x-priority": "important"
|
||||
},
|
||||
"style": {
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
"name": {
|
||||
"description": "The name of the application.",
|
||||
"type": "string",
|
||||
"pattern": "^[a-zA-Z][^:]*$",
|
||||
"pattern": "(?:^@[a-zA-Z0-9-*~][a-zA-Z0-9-*._~]*\\/[a-zA-Z0-9-~][a-zA-Z0-9-._~]*|^[a-zA-Z][^:]*)$",
|
||||
"x-priority": "important"
|
||||
},
|
||||
"skipFormat": {
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
"name": {
|
||||
"description": "The name of the application.",
|
||||
"type": "string",
|
||||
"pattern": "^[a-zA-Z][^:]*$",
|
||||
"pattern": "(?:^@[a-zA-Z0-9-*~][a-zA-Z0-9-*._~]*\\/[a-zA-Z0-9-~][a-zA-Z0-9-._~]*|^[a-zA-Z][^:]*)$",
|
||||
"x-priority": "important"
|
||||
},
|
||||
"skipFormat": {
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
},
|
||||
"name": {
|
||||
"description": "The name of the application.",
|
||||
"pattern": "^[a-zA-Z][^:]*$",
|
||||
"pattern": "(?:^@[a-zA-Z0-9-*~][a-zA-Z0-9-*._~]*\\/[a-zA-Z0-9-~][a-zA-Z0-9-._~]*|^[a-zA-Z][^:]*)$",
|
||||
"type": "string"
|
||||
},
|
||||
"displayName": {
|
||||
|
||||
@@ -37,7 +37,7 @@
|
||||
"name": {
|
||||
"description": "The name of the application.",
|
||||
"type": "string",
|
||||
"pattern": "^[a-zA-Z][^:]*$",
|
||||
"pattern": "(?:^@[a-zA-Z0-9-*~][a-zA-Z0-9-*._~]*\\/[a-zA-Z0-9-~][a-zA-Z0-9-._~]*|^[a-zA-Z][^:]*)$",
|
||||
"x-priority": "important"
|
||||
},
|
||||
"style": {
|
||||
|
||||
@@ -245,7 +245,7 @@
|
||||
"type": "string",
|
||||
"description": "The file to include.",
|
||||
"x-completion-type": "file",
|
||||
"x-completion-glob": "**/*@(.css|.scss|.less|.sass|.styl|.stylus)"
|
||||
"x-completion-glob": "**/*@(.css|.scss|.less|.sass)"
|
||||
},
|
||||
"bundleName": {
|
||||
"type": "string",
|
||||
@@ -264,7 +264,7 @@
|
||||
"type": "string",
|
||||
"description": "The file to include.",
|
||||
"x-completion-type": "file",
|
||||
"x-completion-glob": "**/*@(.css|.scss|.less|.sass|.styl|.stylus)"
|
||||
"x-completion-glob": "**/*@(.css|.scss|.less|.sass)"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -316,7 +316,7 @@
|
||||
"type": "string",
|
||||
"description": "The file to include.",
|
||||
"x-completion-type": "file",
|
||||
"x-completion-glob": "**/*@(.css|.scss|.less|.sass|.styl|.stylus)"
|
||||
"x-completion-glob": "**/*@(.css|.scss|.less|.sass)"
|
||||
},
|
||||
"bundleName": {
|
||||
"type": "string",
|
||||
@@ -335,7 +335,7 @@
|
||||
"type": "string",
|
||||
"description": "The file to include.",
|
||||
"x-completion-type": "file",
|
||||
"x-completion-glob": "**/*@(.css|.scss|.less|.sass|.styl|.stylus)"
|
||||
"x-completion-glob": "**/*@(.css|.scss|.less|.sass)"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -409,7 +409,7 @@
|
||||
"type": "string",
|
||||
"description": "The file to include.",
|
||||
"x-completion-type": "file",
|
||||
"x-completion-glob": "**/*@(.css|.scss|.less|.sass|.styl|.stylus)"
|
||||
"x-completion-glob": "**/*@(.css|.scss|.less|.sass)"
|
||||
},
|
||||
"bundleName": {
|
||||
"type": "string",
|
||||
@@ -428,7 +428,7 @@
|
||||
"type": "string",
|
||||
"description": "The file to include.",
|
||||
"x-completion-type": "file",
|
||||
"x-completion-glob": "**/*@(.css|.scss|.less|.sass|.styl|.stylus)"
|
||||
"x-completion-glob": "**/*@(.css|.scss|.less|.sass)"
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
"name": {
|
||||
"description": "The name of the application.",
|
||||
"type": "string",
|
||||
"pattern": "^[a-zA-Z].*$"
|
||||
"pattern": "(?:^@[a-zA-Z0-9-*~][a-zA-Z0-9-*._~]*\\/[a-zA-Z0-9-~][a-zA-Z0-9-._~]*|^[a-zA-Z][^:]*)$"
|
||||
},
|
||||
"framework": {
|
||||
"type": "string",
|
||||
@@ -49,10 +49,6 @@
|
||||
"value": "scss",
|
||||
"label": "SASS(.scss) [ http://sass-lang.com ]"
|
||||
},
|
||||
{
|
||||
"value": "styl",
|
||||
"label": "Stylus(.styl) [ http://stylus-lang.com ]"
|
||||
},
|
||||
{
|
||||
"value": "less",
|
||||
"label": "LESS [ http://lesscss.org ]"
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
"style": {
|
||||
"type": "string",
|
||||
"description": "The style solution to use.",
|
||||
"enum": ["none", "css", "scss", "less", "styl"]
|
||||
"enum": ["none", "css", "scss", "less"]
|
||||
},
|
||||
"rootProject": { "type": "boolean", "x-priority": "internal" },
|
||||
"keepExistingVersions": {
|
||||
|
||||
@@ -24,7 +24,6 @@
|
||||
},
|
||||
"less": { "type": "boolean", "description": "Use less for styling." },
|
||||
"sass": { "type": "boolean", "description": "Use sass for styling." },
|
||||
"stylus": { "type": "boolean", "description": "Use stylus for styling." },
|
||||
"unitTestRunner": {
|
||||
"type": "string",
|
||||
"description": "The unit test runner to use.",
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
"name": {
|
||||
"description": "The name of the application.",
|
||||
"type": "string",
|
||||
"pattern": "^[a-zA-Z][^:]*$",
|
||||
"pattern": "(?:^@[a-zA-Z0-9-*~][a-zA-Z0-9-*._~]*\\/[a-zA-Z0-9-~][a-zA-Z0-9-._~]*|^[a-zA-Z][^:]*)$",
|
||||
"x-priority": "important"
|
||||
},
|
||||
"style": {
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
"name": {
|
||||
"description": "The name of the application.",
|
||||
"type": "string",
|
||||
"pattern": "^[a-zA-Z][^:]*$",
|
||||
"pattern": "(?:^@[a-zA-Z0-9-*~][a-zA-Z0-9-*._~]*\\/[a-zA-Z0-9-~][a-zA-Z0-9-._~]*|^[a-zA-Z][^:]*)$",
|
||||
"x-priority": "important"
|
||||
},
|
||||
"style": {
|
||||
|
||||
@@ -141,7 +141,7 @@
|
||||
"type": "string",
|
||||
"description": "The file to include.",
|
||||
"x-completion-type": "file",
|
||||
"x-completion-glob": "**/*@(.css|.scss|.less|.sass|.styl|.stylus)"
|
||||
"x-completion-glob": "**/*@(.css|.scss|.less|.sass)"
|
||||
},
|
||||
"bundleName": {
|
||||
"type": "string",
|
||||
@@ -160,7 +160,7 @@
|
||||
"type": "string",
|
||||
"description": "The file to include.",
|
||||
"x-completion-type": "file",
|
||||
"x-completion-glob": "**/*@(.css|.scss|.less|.sass|.styl|.stylus)"
|
||||
"x-completion-glob": "**/*@(.css|.scss|.less|.sass)"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -177,7 +177,7 @@
|
||||
"type": "string",
|
||||
"description": "The file to include.",
|
||||
"x-completion-type": "file",
|
||||
"x-completion-glob": "**/*@(.css|.scss|.less|.sass|.styl|.stylus)"
|
||||
"x-completion-glob": "**/*@(.css|.scss|.less|.sass)"
|
||||
},
|
||||
"bundleName": {
|
||||
"type": "string",
|
||||
@@ -196,7 +196,7 @@
|
||||
"type": "string",
|
||||
"description": "The file to include.",
|
||||
"x-completion-type": "file",
|
||||
"x-completion-glob": "**/*@(.css|.scss|.less|.sass|.styl|.stylus)"
|
||||
"x-completion-glob": "**/*@(.css|.scss|.less|.sass)"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -442,7 +442,7 @@
|
||||
"type": "string",
|
||||
"description": "The file to include.",
|
||||
"x-completion-type": "file",
|
||||
"x-completion-glob": "**/*@(.css|.scss|.less|.sass|.styl|.stylus)"
|
||||
"x-completion-glob": "**/*@(.css|.scss|.less|.sass)"
|
||||
},
|
||||
"bundleName": {
|
||||
"type": "string",
|
||||
@@ -461,7 +461,7 @@
|
||||
"type": "string",
|
||||
"description": "The file to include.",
|
||||
"x-completion-type": "file",
|
||||
"x-completion-glob": "**/*@(.css|.scss|.less|.sass|.styl|.stylus)"
|
||||
"x-completion-glob": "**/*@(.css|.scss|.less|.sass)"
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
@@ -363,10 +363,22 @@
|
||||
"description": "Recipes for releasing with Nx release.",
|
||||
"itemList": [
|
||||
{
|
||||
"name": "Get Started with Nx Release",
|
||||
"id": "get-started-with-nx-release",
|
||||
"name": "Release TypeScript/JavaScript Packages to NPM",
|
||||
"id": "release-npm-packages",
|
||||
"tags": ["nx-release"],
|
||||
"file": "shared/recipes/nx-release/get-started-with-nx-release"
|
||||
"file": "shared/recipes/nx-release/release-typescript-packages-to-npm"
|
||||
},
|
||||
{
|
||||
"name": "Release Docker Images",
|
||||
"id": "release-docker-images",
|
||||
"tags": ["nx-release"],
|
||||
"file": "shared/recipes/nx-release/release-docker-images"
|
||||
},
|
||||
{
|
||||
"name": "Release Rust Crates",
|
||||
"id": "publish-rust-crates",
|
||||
"tags": ["nx-release"],
|
||||
"file": "shared/recipes/nx-release/publish-rust-crates"
|
||||
},
|
||||
{
|
||||
"name": "Release Projects Independently",
|
||||
@@ -422,12 +434,6 @@
|
||||
"tags": ["nx-release"],
|
||||
"file": "shared/recipes/nx-release/automate-gitlab-releases"
|
||||
},
|
||||
{
|
||||
"name": "Publish Rust Crates",
|
||||
"id": "publish-rust-crates",
|
||||
"tags": ["nx-release"],
|
||||
"file": "shared/recipes/nx-release/publish-rust-crates"
|
||||
},
|
||||
{
|
||||
"name": "Update Your Local Registry Setup to use Nx Release",
|
||||
"id": "update-local-registry-setup",
|
||||
@@ -2525,23 +2531,6 @@
|
||||
"name": "Connect to Nx Cloud",
|
||||
"id": "connect-to-nx-cloud",
|
||||
"file": "nx-cloud/intro/connect-to-cloud"
|
||||
},
|
||||
{
|
||||
"name": "Tutorials",
|
||||
"id": "tutorials",
|
||||
"description": "Tutorials setting up CI with Nx",
|
||||
"itemList": [
|
||||
{
|
||||
"name": "Circle CI with Nx",
|
||||
"id": "circle",
|
||||
"file": "nx-cloud/tutorial/circle"
|
||||
},
|
||||
{
|
||||
"name": "GitHub Actions with Nx",
|
||||
"id": "github-actions",
|
||||
"file": "nx-cloud/tutorial/github-actions"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
@@ -11,7 +11,7 @@ Flaky Task Detection is enabled by default if your workspace is connected to Nx
|
||||
To connect your workspace to Nx Cloud run:
|
||||
|
||||
```shell
|
||||
npx nx connect
|
||||
npx nx@latest connect
|
||||
```
|
||||
|
||||
See the [connect to Nx Cloud recipe](/ci/intro/connect-to-nx-cloud) for all the details.
|
||||
|
||||
@@ -23,7 +23,7 @@ Manually splitting large e2e test projects can be complex and require ongoing ma
|
||||
To use **automated e2e task splitting**, you need to connect your workspace to Nx Cloud (if you haven't already).
|
||||
|
||||
```shell
|
||||
npx nx connect
|
||||
npx nx@latest connect
|
||||
```
|
||||
|
||||
See the [connect to Nx Cloud recipe](/ci/intro/connect-to-nx-cloud) for all the details.
|
||||
|
||||
@@ -19,7 +19,7 @@ Your CI pipeline with Nx can:
|
||||
[Create an account on Nx Cloud](https://cloud.nx.app) and connect your repository.
|
||||
|
||||
```shell
|
||||
npx nx connect
|
||||
npx nx@latest connect
|
||||
```
|
||||
|
||||
## Learn about Nx on CI
|
||||
@@ -30,9 +30,9 @@ npx nx connect
|
||||
|
||||
{% link-card title="E2E Test Auto-Splitting and Distribution" type="video" url="https://youtu.be/0YxcxIR7QU0" icon="nxagents" /%}
|
||||
|
||||
{% link-card title="Circle CI with Nx" type="tutorial" url="/ci/intro/tutorials/circle" icon="circleci" /%}
|
||||
{% link-card title="Circle CI with Nx" type="tutorial" url="/ci/recipes/set-up/monorepo-ci-circle-ci" icon="circleci" /%}
|
||||
|
||||
{% link-card title="GitHub Actions with Nx" type="tutorial" url="/ci/intro/tutorials/github-actions" icon="github" /%}
|
||||
{% link-card title="GitHub Actions with Nx" type="tutorial" url="/ci/recipes/set-up/monorepo-ci-github-actions" icon="github" /%}
|
||||
|
||||
{% /cards %}
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@ Here's how you get set up.
|
||||
To connect your workspace, **push it to GitHub** (or your respective source control provider) and then run:
|
||||
|
||||
```shell
|
||||
npx nx connect
|
||||
npx nx@latest connect
|
||||
```
|
||||
|
||||
## Step 2: Configure your CI script
|
||||
|
||||
@@ -1,5 +1,66 @@
|
||||
# Enterprise Release Notes
|
||||
|
||||
### 2025.07.1
|
||||
|
||||
- Fix: auth redirect loop when using admin login
|
||||
- Fix: improvement to the flaky task retry mechanism
|
||||
|
||||
### 2025.07
|
||||
|
||||
##### Breaking Change
|
||||
|
||||
This upgrade includes a breaking change to the `nx-cloud` cluster: instead of a message queue, the `nx-api` pod needs a valid Valkey (Redis) connection string.
|
||||
|
||||
1. Install Valkey:
|
||||
1. You can either use the Bitnami chart: https://github.com/bitnami/charts/tree/main/bitnami/valkey
|
||||
2. Or for a simpler deployment, you can use the Valkey docker image directly: https://hub.docker.com/r/valkey/valkey/
|
||||
3. Or you can install it as a system service: https://valkey.io/topics/installation/
|
||||
2. Upgrade to the latest Helm chart `0.16.3`
|
||||
3. Apply the following values
|
||||
|
||||
```yaml
|
||||
enableMessageQueue: false
|
||||
|
||||
nxApi:
|
||||
# add these env vars to the nx-api
|
||||
deployment:
|
||||
env:
|
||||
- name: VALKEY_CLIENT_PROVIDER
|
||||
value: 'redisson'
|
||||
- name: VALKEY_PASSWORD
|
||||
valueFrom:
|
||||
# remember to apply this secret to your cluster
|
||||
secretKeyRef:
|
||||
name: valkey-secrets
|
||||
key: VALKEY_PASSWORD
|
||||
- name: VALKEY_PORT
|
||||
value: '6379'
|
||||
- name: VALKEY_PRIMARY_ADDRESS
|
||||
value: 'valkey'
|
||||
- name: VALKEY_USE_SENTINEL
|
||||
value: 'false'
|
||||
- name: VALKEY_USERNAME
|
||||
value: 'default'
|
||||
- name: NX_CLOUD_CONFORMANCE_RULES_BUCKET
|
||||
value:
|
||||
local-cluster-file-server # use this exact value if you are using the file server, otherwise point it to an S3/Azure/Google bucket
|
||||
# it will use the same role-based auth mechanism you already configured for the NxCloud cache
|
||||
# you can also use the same bucket name that you use for the cache (rules will just be stored in a sub-folder)
|
||||
```
|
||||
|
||||
##### Updates
|
||||
|
||||
- Feat: [Polygraph availability](/ci/recipes/enterprise/polygraph) (Conformance, Workspace Graph, Custom Workflows)
|
||||
- Feat: Nx 21 [continuous tasks](/blog/nx-21-continuous-tasks) support
|
||||
- Feat: Download artifacts button
|
||||
- When you view a task that just ran in CI on the NxCloud UI, there is now a button to download any artifacts that task produced directly from your browser
|
||||
- This is especially useful if you want to view screenshots/videos of failed e2e tests
|
||||
- Feat: [Self-healing CI](/ci/features/self-healing-ci)
|
||||
- Speak to your assigned DPE about testing this
|
||||
- You will need an Anthropic API key and access to Claude's servers
|
||||
- Feat: Dark Mode UI setting
|
||||
- Various fixes and stability improvements to DTE, agent visualization, and other areas of the app
|
||||
|
||||
### 2025.06.3
|
||||
|
||||
- Fix: add timeouts to GitLab requests
|
||||
|
||||
|
Before Width: | Height: | Size: 38 KiB |
|
Before Width: | Height: | Size: 32 KiB |
|
Before Width: | Height: | Size: 136 KiB |
|
Before Width: | Height: | Size: 97 KiB |
|
Before Width: | Height: | Size: 14 KiB |
|
Before Width: | Height: | Size: 70 KiB |
|
Before Width: | Height: | Size: 29 KiB |
|
Before Width: | Height: | Size: 240 KiB |
|
Before Width: | Height: | Size: 26 KiB |
|
Before Width: | Height: | Size: 9.8 KiB |
|
Before Width: | Height: | Size: 84 KiB |
@@ -1,300 +0,0 @@
|
||||
---
|
||||
title: 'Circle CI Tutorial with Nx'
|
||||
description: In this tutorial you'll set up continuous integration with Circle CI and Nx
|
||||
---
|
||||
|
||||
# Circle CI with Nx
|
||||
|
||||
In this tutorial we're going to learn how to leverage Nx to setup a scalable CI pipeline on Circle CI. As repositories get bigger, making sure that the CI is fast, reliable and maintainable can get very challenging. Nx provides a solution.
|
||||
|
||||
- Nx reduces wasted time in CI with the [`affected` command](/ci/features/affected).
|
||||
- Nx Replay's [remote caching](/ci/features/remote-cache) will reuse task artifacts from different CI executions making sure you will never run the same computation twice.
|
||||
- Nx Agents [efficiently distribute tasks across machines](/ci/concepts/parallelization-distribution) ensuring constant CI time regardless of the repository size. The right number of machines is allocated for each PR to ensure good performance without wasting compute.
|
||||
- Nx Atomizer [automatically splits](/ci/features/split-e2e-tasks) large e2e tests to distribute them across machines. Nx can also automatically [identify and rerun flaky e2e tests](/ci/features/flaky-tasks).
|
||||
|
||||
## Example Repository
|
||||
|
||||
To follow along with this tutorial, we recommend using the [nx-shops sample repository](https://github.com/nrwl/nx-shops).
|
||||
|
||||
{% github-repository url="https://github.com/nrwl/nx-shops" /%}
|
||||
|
||||
The `nx-shops` repo is useful to demonstrate the value of the CI pipeline because it has the following characteristics:
|
||||
|
||||
- Multiple Nx projects with interdependencies
|
||||
- Defined lint, test, build and e2e tasks
|
||||
- Running all the tasks takes more than a minute to finish
|
||||
|
||||
To get started:
|
||||
|
||||
1. [Fork the nx-shop repo](https://github.com/nrwl/nx-shops/fork) and then clone it to your local machine
|
||||
|
||||
```shell
|
||||
git clone https://github.com/<your-username>/nx-shops.git
|
||||
```
|
||||
|
||||
2. Install dependencies (this repo uses [PNPM](https://pnpm.io/) but you should be able to also use any other package manager)
|
||||
|
||||
```shell
|
||||
pnpm i
|
||||
```
|
||||
|
||||
3. Make sure all tasks are working on your machine, by running lint, test, build and e2e on all projects of the workspace
|
||||
|
||||
```shell
|
||||
pnpm nx run-many -t lint test build
|
||||
```
|
||||
|
||||
## Connect to Circle CI
|
||||
|
||||
In order to use Circle CI, you need to [sign up and create an organization](https://circleci.com/docs/first-steps/#sign-up-and-create-an-org). Follow the steps in the Circle CI documentation to connect to your GitHub repository to a project.
|
||||
|
||||

|
||||
|
||||
The easiest way is to create a branch and PR in your GitHub repository. Note that a sample pipeline workflow file will be created, which we will overwrite in the next step.
|
||||
|
||||

|
||||
|
||||
Once the PR is created, merge it into your main branch.
|
||||
|
||||

|
||||
|
||||
And pull the changes locally:
|
||||
|
||||
```shell
|
||||
git pull
|
||||
```
|
||||
|
||||
## Create a CI Workflow
|
||||
|
||||
First, we'll create a new branch to start adding a CI workflow.
|
||||
|
||||
```shell
|
||||
git checkout -b setup-ci
|
||||
```
|
||||
|
||||
Now we can use an Nx generator to create a default CI workflow file.
|
||||
|
||||
```shell
|
||||
pnpm nx generate ci-workflow --ci=circleci
|
||||
```
|
||||
|
||||
This generator will overwrite Circle CI's default `.circleci/config.yml` file to create a CI pipeline that will run the `lint`, `test`, `build` and `e2e` tasks for projects that are affected by any given PR.
|
||||
|
||||
The key lines in the CI pipeline are:
|
||||
|
||||
```yml {% fileName=".circleci/config.yml" highlightLines=["27-29"] %}
|
||||
version: 2.1
|
||||
|
||||
orbs:
|
||||
nx: nrwl/nx@1.6.2
|
||||
|
||||
jobs:
|
||||
main:
|
||||
docker:
|
||||
- image: cimg/node:lts-browsers
|
||||
steps:
|
||||
- checkout
|
||||
|
||||
- run:
|
||||
name: Install PNPM
|
||||
command: npm install --prefix=$HOME/.local -g pnpm@8
|
||||
|
||||
# This enables task distribution via Nx Cloud
|
||||
# Run this command as early as possible, before dependencies are installed
|
||||
# Learn more at https://nx.dev/ci/reference/nx-cloud-cli#npx-nxcloud-startcirun
|
||||
# Connect your workspace by running "nx connect" and uncomment this line to enable task distribution
|
||||
# - run: pnpm dlx nx-cloud start-ci-run --distribute-on="3 linux-medium-js" --stop-agents-after="e2e-ci"
|
||||
|
||||
- run: pnpm install --frozen-lockfile
|
||||
- nx/set-shas:
|
||||
main-branch-name: 'main'
|
||||
|
||||
# Prepend any command with "nx-cloud record --" to record its logs to Nx Cloud
|
||||
# - run: pnpm exec nx-cloud record -- echo Hello World
|
||||
- run: pnpm exec nx affected --base=$NX_BASE --head=$NX_HEAD -t lint test build e2e-ci
|
||||
|
||||
workflows:
|
||||
version: 2
|
||||
|
||||
ci:
|
||||
jobs:
|
||||
- main
|
||||
```
|
||||
|
||||
The [`nx affected` command](/ci/features/affected) will run the specified tasks only for projects that have been affected by a particular PR, which can save a lot of time as repositories grow larger.
|
||||
|
||||
Commit your changes and push your branch:
|
||||
|
||||
```shell
|
||||
git add .
|
||||
git commit -am "basic ci workflow"
|
||||
git push -u origin HEAD
|
||||
```
|
||||
|
||||
Open up a new PR to see the run on CircleCI. If you see a message about the `nrwl/nx` orb not being loaded, you need to enable third-party CircleCI orbs in your organization settings. In the Circle CI project dashboard, go to `Organization Settings -> Security` and select `Yes` under Orb Security Settings: Allow Uncertified Orbs.
|
||||
|
||||

|
||||
|
||||
{% callout type="warning" title="Create Your PR on Your Own Repository" %}
|
||||
Make sure that the PR you create is against your own repository's `main` branch - not the `nrwl/nx-shops` repository.
|
||||
{% /callout %}
|
||||
|
||||

|
||||
|
||||
Once CI is green, merge the PR.
|
||||
|
||||

|
||||
|
||||
And make sure to pull the changes locally:
|
||||
|
||||
```shell
|
||||
git checkout main
|
||||
git pull origin main
|
||||
```
|
||||
|
||||
The rest of the tutorial covers remote caching and distribution across multiple machines, which need Nx Cloud to be enabled. Let's set that up next.
|
||||
|
||||
## Connect to Nx Cloud
|
||||
|
||||
Nx Cloud is a companion app for your CI system that provides remote caching, task distribution, e2e test deflaking, better DX and more.
|
||||
|
||||
Let's connect your repository to Nx Cloud with the following command:
|
||||
|
||||
```shell
|
||||
pnpm nx connect
|
||||
```
|
||||
|
||||
A browser window will open to register your repository in your [Nx Cloud](https://cloud.nx.app) account. The link is also printed to the terminal if the windows does not open, or you closed it before finishing the steps. The app will guide you to create a PR to enable Nx Cloud on your repository.
|
||||
|
||||

|
||||
|
||||
Nx Cloud will create a comment on your PR that gives you a summary of the CI run and a link to dig into logs and understand everything that happened during the CI run.
|
||||
|
||||

|
||||
|
||||
Once the PR is green, merge it into your main branch.
|
||||
|
||||

|
||||
|
||||
And make sure you pull the latest changes locally:
|
||||
|
||||
```shell
|
||||
git pull
|
||||
```
|
||||
|
||||
You should now have an `nxCloudId` property specified in the `nx.json` file.
|
||||
|
||||
## Understand Remote Caching
|
||||
|
||||
[Nx Cloud](https://nx.app) provides [Nx Replay](/ci/features/remote-cache), which is a powerful, scalable and, very importantly, secure way to share task artifacts across machines. It lets you configure permissions and guarantees the cached artifacts cannot be tempered with.
|
||||
|
||||
[Nx Replay](/ci/features/remote-cache) is enabled by default. We can see it in action by running a few commands locally. First, let's build every project in the repository:
|
||||
|
||||
```shell
|
||||
pnpm nx run-many -t build
|
||||
```
|
||||
|
||||
Nx will store the output of those tasks locally in the `.nx/cache` folder and remotely in Nx Cloud. If someone else in the organization were to run the same `build` command on the same source code, they would receive the remotely cached outputs instead of re-running the `build` task themselves. We can simulate this by deleting the `.nx/cache` folder and re-running the `build` command.
|
||||
|
||||
```shell
|
||||
rm -rf .nx/cache
|
||||
pnpm nx run-many -t build
|
||||
```
|
||||
|
||||
The `build` tasks complete almost instantly, and you can see in the logs that Nx has pulled the outputs from the remote cache:
|
||||
|
||||
```
|
||||
❯ nx run-many -t build
|
||||
|
||||
✔ nx run shared-product-types:build [remote cache]
|
||||
✔ nx run shared-product-ui:build [remote cache]
|
||||
✔ nx run shared-header:build [remote cache]
|
||||
✔ nx run landing-page:build:production [remote cache]
|
||||
✔ nx run admin:build:production [remote cache]
|
||||
✔ nx run cart:build:production [remote cache]
|
||||
```
|
||||
|
||||
This remote cache is useful to speed up tasks when developing on a local machine, but it is incredibly useful for CI to be able share task results across different CI pipeline executions. When a small commit is added to a large PR, the CI is able to download the results for most of the tasks instead of recomputing everything from scratch.
|
||||
|
||||
You might also want to learn more about [how to fine-tune caching](/recipes/running-tasks/configure-inputs) to get even better results.
|
||||
|
||||
## Parallelize Tasks Across Multiple Machines Using Nx Agents
|
||||
|
||||
The affected command and Nx Replay help speed up the average CI time, but there will be some PRs that affect everything in the repository. The only way to speed up that worst case scenario is through efficient parallelization. The best way to parallelize CI with Nx is to use [Nx Agents](/ci/features/distribute-task-execution).
|
||||
|
||||
The Nx Agents feature
|
||||
|
||||
- takes a command (e.g. `nx affected -t build lint test e2e-ci`) and splits it into individual tasks which it then distributes across multiple agents
|
||||
- distributes tasks by considering the dependencies between them; e.g. if `e2e-ci` depends on `build`, Nx Cloud will make sure that `build` is executed before `e2e-ci`; it does this across machines
|
||||
- distributes tasks to optimize for CPU processing time and reduce idle time by taking into account historical data about how long each task takes to run
|
||||
- collects the results and logs of all the tasks and presents them in a single view
|
||||
- automatically shuts down agents when they are no longer needed
|
||||
|
||||
To enable Nx Agents, make sure the `nx-cloud start-ci-run` line is uncommented in the `.circleci/config.yml` file and the `nx affected` line runs the `e2e-ci` task instead of `e2e`.
|
||||
|
||||
```yml {% fileName=".circleci/config.yml" highlightLines=["21","29"] %}
|
||||
version: 2.1
|
||||
|
||||
orbs:
|
||||
nx: nrwl/nx@1.6.2
|
||||
|
||||
jobs:
|
||||
main:
|
||||
docker:
|
||||
- image: cimg/node:lts-browsers
|
||||
steps:
|
||||
- checkout
|
||||
|
||||
- run:
|
||||
name: Install PNPM
|
||||
command: npm install --prefix=$HOME/.local -g pnpm@8
|
||||
|
||||
# This enables task distribution via Nx Cloud
|
||||
# Run this command as early as possible, before dependencies are installed
|
||||
# Learn more at https://nx.dev/ci/reference/nx-cloud-cli#npx-nxcloud-startcirun
|
||||
# Connect your workspace by running "nx connect" and uncomment this line to enable task distribution
|
||||
- run: pnpm dlx nx-cloud start-ci-run --distribute-on="3 linux-medium-js" --stop-agents-after="e2e-ci"
|
||||
|
||||
- run: pnpm install --frozen-lockfile
|
||||
- nx/set-shas:
|
||||
main-branch-name: 'main'
|
||||
|
||||
# Prepend any command with "nx-cloud record --" to record its logs to Nx Cloud
|
||||
# - run: pnpm exec nx-cloud record -- echo Hello World
|
||||
- run: pnpm exec nx affected --base=$NX_BASE --head=$NX_HEAD -t lint test build e2e-ci
|
||||
|
||||
workflows:
|
||||
version: 2
|
||||
|
||||
ci:
|
||||
jobs:
|
||||
- main
|
||||
```
|
||||
|
||||
We recommend you add this line right after you check out the repo, before installing node modules.
|
||||
|
||||
- `nx-cloud start-ci-run --distribute-on="3 linux-medium-js` lets Nx know that all the tasks after this line should use Nx Agents and that Nx Cloud should use three instances of the `linux-medium-js` launch template. See the separate reference on how to [configure a custom launch template](/ci/reference/launch-templates).
|
||||
- `--stop-agents-after="e2e-ci"` lets Nx Cloud know which line is the last command in this pipeline. Once there are no more e2e tasks for an agent to run, Nx Cloud will automatically shut them down. This way you're not wasting money on idle agents while a particularly long e2e task is running on a single agent.
|
||||
|
||||
Try it out by creating a new PR with the above changes.
|
||||
|
||||
```shell
|
||||
git checkout -b enable-distribution
|
||||
git commit -am 'enable task distribution'
|
||||
```
|
||||
|
||||

|
||||
|
||||
Once Circle CI starts, you can click on the Nx Cloud report to see what tasks agents are executing in real time.
|
||||
|
||||

|
||||
|
||||
With this pipeline configuration in place, no matter how large the repository scales, Nx Cloud will adjust and distribute tasks across agents in the optimal way. If CI pipelines start to slow down, just add some agents. One of the main advantages is that this pipeline definition is declarative. We tell Nx what commands to run, but not how to distribute them. That way even if our monorepo structure changes and evolves over time, the distribution will be taken care of by Nx Cloud.
|
||||
|
||||
## Next Steps
|
||||
|
||||
You now have a highly optimized CI configuration that will scale as your repository scales. See what else you can do with Nx Cloud.
|
||||
|
||||
- Configure [dynamic agent allocation](/ci/features/dynamic-agents)
|
||||
- Learn about [automatically splitting e2e tasks](/ci/features/split-e2e-tasks)
|
||||
- Identify and re-run [flaky tasks](/ci/features/flaky-tasks)
|
||||
|
Before Width: | Height: | Size: 17 KiB |
|
Before Width: | Height: | Size: 35 KiB |
|
Before Width: | Height: | Size: 120 KiB |
|
Before Width: | Height: | Size: 98 KiB |
|
Before Width: | Height: | Size: 31 KiB |
|
Before Width: | Height: | Size: 64 KiB |