Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 24 additions & 0 deletions .claude/settings.local.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
{
"permissions": {
"allow": [
"Bash(npx nx show:*)",
"Bash(find:*)",
"Bash(npx nx reset:*)",
"Bash(npx nx list:*)",
"Bash(npx nx run:*)",
"Bash(rm:*)",
"Bash(npx nx:*)",
"Bash(sed:*)",
"Bash(./gradlew:*)",
"Bash(chmod:*)",
"Bash(ls:*)",
"Bash(/Users/emily/code/tmp/spring-boot/remove_lock.sh)",
"Bash(rg:*)",
"Bash(grep:*)",
"Bash(jq:*)",
"Bash(node:*)",
"Bash(npm install)"
],
"deny": []
}
}
5 changes: 5 additions & 0 deletions .env
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
NX_BATCH_MODE=true
NX_VERBOSE_LOGGING=true
NX_CLOUD_VERBOSE_LOGGING=true
NX_TUI=false
CI=true
22 changes: 11 additions & 11 deletions .github/actions/build/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -68,17 +68,17 @@ runs:
COMMERCIAL_REPO_PASSWORD: ${{ inputs.commercial-repository-password }}
COMMERCIAL_REPO_USERNAME: ${{ inputs.commercial-repository-username }}
COMMERCIAL_SNAPSHOT_REPO_URL: ${{ inputs.commercial-snapshot-repository-url }}
run: ./gradlew build
- name: Publish
id: publish
if: ${{ inputs.publish == 'true' }}
shell: bash
env:
COMMERCIAL_RELEASE_REPO_URL: ${{ inputs.commercial-release-repository-url }}
COMMERCIAL_REPO_PASSWORD: ${{ inputs.commercial-repository-password }}
COMMERCIAL_REPO_USERNAME: ${{ inputs.commercial-repository-username }}
COMMERCIAL_SNAPSHOT_REPO_URL: ${{ inputs.commercial-snapshot-repository-url }}
run: ./gradlew -PdeploymentRepository=$(pwd)/deployment-repository ${{ !startsWith(github.event.head_commit.message, 'Next development version') && 'build' || '' }} publishAllPublicationsToDeploymentRepository
run: NX_BATCH_MODE=true NX_CLOUD_DEREFERENCE_SYMLINKS=true NX_VERBOSE_LOGGING=true NX_PERF_LOGGING=true NX_CLOUD_NO_TIMEOUTS=true NX_CLOUD_VERBOSE_LOGGING=true npx nx run-many -t build-ci --parallel=32 --batch --outputStyle=stream
# - name: Publish
# id: publish
# if: ${{ inputs.publish == 'true' }}
# shell: bash
# env:
# COMMERCIAL_RELEASE_REPO_URL: ${{ inputs.commercial-release-repository-url }}
# COMMERCIAL_REPO_PASSWORD: ${{ inputs.commercial-repository-password }}
# COMMERCIAL_REPO_USERNAME: ${{ inputs.commercial-repository-username }}
# COMMERCIAL_SNAPSHOT_REPO_URL: ${{ inputs.commercial-snapshot-repository-url }}
# run: ./gradlew -PdeploymentRepository=$(pwd)/deployment-repository ${{ !startsWith(github.event.head_commit.message, 'Next development version') && 'build' || '' }} publishAllPublicationsToDeploymentRepository
- name: Read Version From gradle.properties
id: read-version
shell: bash
Expand Down
18 changes: 17 additions & 1 deletion .github/workflows/build-pull-request.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,30 @@ permissions:
jobs:
build:
name: Build Pull Request
if: ${{ github.repository == 'spring-projects/spring-boot' }}
runs-on: ${{ vars.UBUNTU_MEDIUM || 'ubuntu-latest' }}
steps:
- name: Check Out Code
uses: actions/checkout@v4
- name: Use Node.js
uses: actions/setup-node@v4
with:
node-version: 22
check-latest: true
cache: npm
- run: npm install

# 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
# Uncomment this line to enable task distribution
- run: NX_CLOUD_FORCE_USE_EXECUTE_TASKS_V3=true NX_CLOUD_DEREFERENCE_SYMLINKS=true NX_CLOUD_RETRIEVAL_CONCURRENCY=30 NX_CLOUD_NO_TIMEOUTS=true NX_VERBOSE_LOGGING=true NX_CLOUD_VERBOSE_LOGGING=true NX_PERF_LOGGING=true npx nx-cloud start-ci-run --require-explicit-completion --distribute-on="../../.nx/workflows/distribution-config.yaml"

- name: Build
id: build
uses: ./.github/actions/build
- name: Stop nx cloud agents
if: always()
run: npx nx-cloud complete-ci-run
- name: Print JVM Thread Dumps When Cancelled
if: cancelled()
uses: ./.github/actions/print-jvm-thread-dumps
Expand Down
7 changes: 7 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -41,3 +41,10 @@ secrets.yml
.sts4-cache
.git-hooks/
node_modules

.nx/installation
.nx/cache
.nx/workspace-data

.specstory/**
.cursorindexingignore
116 changes: 116 additions & 0 deletions .nx/nxw.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
"use strict";
// This file should be committed to your repository! It wraps Nx and ensures
// that your local installation matches nx.json.
// See: https://nx.dev/recipes/installation/install-non-javascript for more info.




Object.defineProperty(exports, "__esModule", { value: true });
const fs = require('fs');
const path = require('path');
const cp = require('child_process');
const installationPath = path.join(__dirname, 'installation', 'package.json');
function matchesCurrentNxInstall(currentInstallation, nxJsonInstallation) {
if (!currentInstallation.devDependencies ||
!Object.keys(currentInstallation.devDependencies).length) {
return false;
}
try {
if (currentInstallation.devDependencies['nx'] !==
nxJsonInstallation.version ||
require(path.join(path.dirname(installationPath), 'node_modules', 'nx', 'package.json')).version !== nxJsonInstallation.version) {
return false;
}
for (const [plugin, desiredVersion] of Object.entries(nxJsonInstallation.plugins || {})) {
if (currentInstallation.devDependencies[plugin] !== desiredVersion) {
return false;
}
}
return true;
}
catch {
return false;
}
}
function ensureDir(p) {
if (!fs.existsSync(p)) {
fs.mkdirSync(p, { recursive: true });
}
}
function getCurrentInstallation() {
try {
return require(installationPath);
}
catch {
return {
name: 'nx-installation',
version: '0.0.0',
devDependencies: {},
};
}
}
function performInstallation(currentInstallation, nxJson) {
fs.writeFileSync(installationPath, JSON.stringify({
name: 'nx-installation',
devDependencies: {
nx: nxJson.installation.version,
...nxJson.installation.plugins,
},
}));
try {
cp.execSync('npm i', {
cwd: path.dirname(installationPath),
stdio: 'inherit',
windowsHide: false,
});
}
catch (e) {
// revert possible changes to the current installation
fs.writeFileSync(installationPath, JSON.stringify(currentInstallation));
// rethrow
throw e;
}
}
function ensureUpToDateInstallation() {
const nxJsonPath = path.join(__dirname, '..', 'nx.json');
let nxJson;
try {
nxJson = require(nxJsonPath);
if (!nxJson.installation) {
console.error('[NX]: The "installation" entry in the "nx.json" file is required when running the nx wrapper. See https://nx.dev/recipes/installation/install-non-javascript');
process.exit(1);
}
}
catch {
console.error('[NX]: The "nx.json" file is required when running the nx wrapper. See https://nx.dev/recipes/installation/install-non-javascript');
process.exit(1);
}
try {
ensureDir(path.join(__dirname, 'installation'));
const currentInstallation = getCurrentInstallation();
if (!matchesCurrentNxInstall(currentInstallation, nxJson.installation)) {
performInstallation(currentInstallation, nxJson);
}
}
catch (e) {
const messageLines = [
'[NX]: Nx wrapper failed to synchronize installation.',
];
if (e instanceof Error) {
messageLines.push('');
messageLines.push(e.message);
messageLines.push(e.stack);
}
else {
messageLines.push(e.toString());
}
console.error(messageLines.join('\n'));
process.exit(1);
}
}
if (!process.env.NX_WRAPPER_SKIP_INSTALL) {
ensureUpToDateInstallation();
}

require('./installation/node_modules/nx/bin/nx');
35 changes: 35 additions & 0 deletions .nx/workflows/agents.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
launch-templates:
linux-extra-large-plus-jvm:
env:
NX_CLOUD_FORCE_USE_EXECUTE_TASKS_V3: "false"
DOCKER_HOST: ""
SERVICES_HOST: ""
LANG: C.UTF-8
resource-class: 'docker_linux_amd64/extra_large'
image: 'ubuntu22.04-node20.19-v3'
init-steps:
- name: Make tmp directory in agent workflow dir
script: mkdir /home/workflows/tmp

- name: java version
script: java -version

- name: Checkout
uses: 'nrwl/nx-cloud-workflows/v3.6/workflow-steps/checkout/main.yaml'

- name: Setup Java 21
script: |
sudo apt update
sudo apt install -y openjdk-21-jdk openssh-server neovim lynx fzf
java -version
- name: Setup gradle
script: ./gradlew wrapper && ./gradlew --stop && ./gradlew clean

- name: Restore Node Modules Cache
uses: 'nrwl/nx-cloud-workflows/v4/workflow-steps/cache/main.yaml'
inputs:
key: 'package-lock.json|yarn.lock|pnpm-lock.yaml'
paths: 'node_modules'
base-branch: 'main'
- name: Install Node Modules
uses: 'nrwl/nx-cloud-workflows/v4/workflow-steps/install-node-modules/main.yaml'
20 changes: 20 additions & 0 deletions .nx/workflows/distribution-config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
distribute-on:
default: 5 linux-extra-large-plus-jvm

assignment-rules:
- targets:
- 'ciIntTest*'
run-on:
- agent: linux-extra-large-plus-jvm
parallelism: 1

- targets:
- 'dockerTest'
run-on:
- agent: linux-extra-large-plus-jvm
parallelism: 1

- projects:
- "*"
run-on:
- agent: linux-extra-large-plus-jvm
14 changes: 12 additions & 2 deletions build.gradle
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
plugins {
id "dev.nx.gradle.project-graph" version "0.0.1-alpha.7"
id "base"
id "org.jetbrains.kotlin.jvm" apply false // https://youtrack.jetbrains.com/issue/KT-30276
}
Expand All @@ -9,18 +10,27 @@ defaultTasks 'build'

allprojects {
group = "org.springframework.boot"
apply {
plugin("dev.nx.gradle.project-graph")
}
}

subprojects {
apply plugin: "org.springframework.boot.conventions"

repositories {
mavenLocal()
mavenCentral()
spring.mavenRepositories()
}

tasks.withType(Test).configureEach {
if (it.name == 'dockerTest') {
environment("_JAVA_OPTIONS", "-Djava.io.tmpdir=/home/workflows/tmp")
}
}

configurations.all {
resolutionStrategy.cacheChangingModulesFor 0, "minutes"
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
import org.gradle.api.plugins.JavaBasePlugin;
import org.gradle.api.provider.Provider;
import org.gradle.api.tasks.Copy;
import org.gradle.api.tasks.PathSensitivity;
import org.gradle.api.tasks.TaskContainer;
import org.gradle.api.tasks.TaskProvider;

Expand Down Expand Up @@ -90,7 +91,8 @@ private void apply(Project project, AntoraPlugin antoraPlugin) {
TaskProvider<Copy> copyAntoraPackageJsonTask = tasks.register("copyAntoraPackageJson", Copy.class,
(task) -> configureCopyAntoraPackageJsonTask(project, task));
TaskProvider<NpmInstallTask> npmInstallTask = tasks.register("antoraNpmInstall", NpmInstallTask.class,
(task) -> configureNpmInstallTask(project, task, copyAntoraPackageJsonTask));
(task) -> configureNpmInstallTask(project, task, copyAntoraPackageJsonTask,
generateAntoraPlaybookTask));
tasks.withType(GenerateAntoraYmlTask.class,
(generateAntoraYmlTask) -> configureGenerateAntoraYmlTask(project, generateAntoraYmlTask, resolvedBom));
tasks.withType(AntoraTask.class,
Expand All @@ -114,13 +116,24 @@ private void configureCopyAntoraPackageJsonTask(Project project, Copy copyAntora
}

private void configureNpmInstallTask(Project project, NpmInstallTask npmInstallTask,
TaskProvider<Copy> copyAntoraPackageJson) {
TaskProvider<Copy> copyAntoraPackageJson, TaskProvider<GenerateAntoraPlaybook> generateAntoraPlaybookTask) {
npmInstallTask.dependsOn(copyAntoraPackageJson);
npmInstallTask.dependsOn(generateAntoraPlaybookTask);
Map<String, String> environment = new HashMap<>();
environment.put("npm_config_omit", "optional");
environment.put("npm_config_update_notifier", "false");
npmInstallTask.getEnvironment().set(environment);
npmInstallTask.getNpmCommand().set(List.of("ci", "--silent", "--no-progress"));

npmInstallTask.getInputs()
.files(project.getLayout().getBuildDirectory().dir(".gradle/nodejs"))
.withPropertyName("antoraNodeJs")
.withPathSensitivity(PathSensitivity.RELATIVE);

npmInstallTask.getInputs()
.files(getNodeProjectDir(project))
.withPropertyName("antoraNodeProjectDir")
.withPathSensitivity(PathSensitivity.RELATIVE);
}

private void configureGenerateAntoraYmlTask(Project project, GenerateAntoraYmlTask generateAntoraYmlTask,
Expand Down Expand Up @@ -163,6 +176,22 @@ private void configureAntoraTask(Project project, AntoraTask antoraTask,
TaskProvider<GenerateAntoraPlaybook> generateAntoraPlaybookTask) {
antoraTask.setGroup("Documentation");
antoraTask.dependsOn(npmInstallTask, generateAntoraPlaybookTask);

antoraTask.getInputs()
.file(generateAntoraPlaybookTask.flatMap(GenerateAntoraPlaybook::getOutputFile))
.withPropertyName("antoraPlaybookFile")
.withPathSensitivity(PathSensitivity.RELATIVE);

antoraTask.getInputs()
.files(project.getLayout().getBuildDirectory().dir(".gradle/nodejs"))
.withPropertyName("antoraNodeJs")
.withPathSensitivity(PathSensitivity.RELATIVE);

antoraTask.getInputs()
.files(getNodeProjectDir(project))
.withPropertyName("antoraNodeProjectDir")
.withPathSensitivity(PathSensitivity.RELATIVE);

antoraTask.setPlaybook("antora-playbook.yml");
antoraTask.setUiBundleUrl(getUiBundleUrl(project));
antoraTask.getArgs().set(project.provider(() -> getAntoraNpxArs(project, antoraTask)));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ public void apply(Project project) {
}

private void setUpProjectRepository(Project project, Task publishTask, File repositoryLocation) {
publishTask.getOutputs().dir(repositoryLocation);
publishTask.doFirst(new CleanAction(repositoryLocation));
Configuration projectRepository = project.getConfigurations().create(MAVEN_REPOSITORY_CONFIGURATION_NAME);
project.getArtifacts()
Expand Down
Loading
Loading