diff --git a/.github/actions/build/action.yml b/.github/actions/build/action.yml
index 0ebb7f087176..6328d227e43f 100644
--- a/.github/actions/build/action.yml
+++ b/.github/actions/build/action.yml
@@ -5,13 +5,17 @@ inputs:
required: false
default: '17'
description: 'The Java version to compile and test with'
+ java-distribution:
+ required: false
+ default: 'liberica'
+ description: 'The Java distribution to use for the build'
java-toolchain:
required: false
- default: false
+ default: 'false'
description: 'Whether a Java toolchain should be used'
publish:
required: false
- default: false
+ default: 'false'
description: 'Whether to publish artifacts ready for deployment to Artifactory'
develocity-access-key:
required: false
@@ -29,21 +33,19 @@ runs:
- name: Prepare Gradle Build
uses: ./.github/actions/prepare-gradle-build
with:
+ develocity-access-key: ${{ inputs.develocity-access-key }}
java-version: ${{ inputs.java-version }}
+ java-distribution: ${{ inputs.java-distribution }}
java-toolchain: ${{ inputs.java-toolchain }}
- name: Build
id: build
if: ${{ inputs.publish == 'false' }}
shell: bash
- env:
- DEVELOCITY_ACCESS_KEY: ${{ inputs.develocity-access-key }}
run: ./gradlew build
- name: Publish
id: publish
if: ${{ inputs.publish == 'true' }}
shell: bash
- env:
- DEVELOCITY_ACCESS_KEY: ${{ inputs.develocity-access-key }}
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
diff --git a/.github/actions/create-github-release/action.yml b/.github/actions/create-github-release/action.yml
index d30dacef4c83..d5cc67fb9be3 100644
--- a/.github/actions/create-github-release/action.yml
+++ b/.github/actions/create-github-release/action.yml
@@ -7,11 +7,15 @@ inputs:
token:
description: Token to use for authentication with GitHub
required: true
+ pre-release:
+ description: Whether the release is a pre-release (a milestone or release candidate)
+ required: false
+ default: 'false'
runs:
using: composite
steps:
- name: Generate Changelog
- uses: spring-io/github-changelog-generator@052892c62af51f8af87a9da6de55e70864b7df12
+ uses: spring-io/github-changelog-generator@185319ad7eaa75b0e8e72e4b6db19c8b2cb8c4c1 #v0.0.11
with:
milestone: ${{ inputs.milestone }}
token: ${{ inputs.token }}
@@ -20,4 +24,4 @@ runs:
env:
GITHUB_TOKEN: ${{ inputs.token }}
shell: bash
- run: gh release create ${{ format('v{0}', inputs.milestone) }} --notes-file changelog.md
+ run: gh release create ${{ format('v{0}', inputs.milestone) }} --notes-file changelog.md ${{ inputs.pre-release == 'true' && '--prerelease' || '' }}
diff --git a/.github/actions/prepare-gradle-build/action.yml b/.github/actions/prepare-gradle-build/action.yml
index dbcd610b0653..29f80d71663d 100644
--- a/.github/actions/prepare-gradle-build/action.yml
+++ b/.github/actions/prepare-gradle-build/action.yml
@@ -5,10 +5,17 @@ inputs:
required: false
default: '17'
description: 'The Java version to use for the build'
+ java-distribution:
+ required: false
+ default: 'liberica'
+ description: 'The Java distribution to use for the build'
java-toolchain:
required: false
- default: false
+ default: 'false'
description: 'Whether a Java toolchain should be used'
+ develocity-access-key:
+ required: false
+ description: 'The access key for authentication with ge.spring.io'
runs:
using: composite
steps:
@@ -20,14 +27,15 @@ runs:
- name: Set Up Java
uses: actions/setup-java@v4
with:
- distribution: 'liberica'
+ distribution: ${{ inputs.java-distribution }}
java-version: |
${{ inputs.java-version }}
${{ inputs.java-toolchain == 'true' && '17' || '' }}
- name: Set Up Gradle
- uses: gradle/actions/setup-gradle@db19848a5fa7950289d3668fb053140cf3028d43 # v3.3.2
+ uses: gradle/actions/setup-gradle@d9c87d481d55275bb5441eef3fe0e46805f9ef70 # v3.5.0
with:
cache-read-only: false
+ develocity-access-key: ${{ inputs.develocity-access-key }}
- name: Configure Gradle Properties
shell: bash
run: |
diff --git a/.github/actions/print-jvm-thread-dumps/action.yml b/.github/actions/print-jvm-thread-dumps/action.yml
index bab22e54897a..9b0905b77725 100644
--- a/.github/actions/print-jvm-thread-dumps/action.yml
+++ b/.github/actions/print-jvm-thread-dumps/action.yml
@@ -7,7 +7,7 @@ runs:
shell: bash
run: |
for jvm_pid in $(jps -q -J-XX:+PerfDisableSharedMem); do
- jcmd $java_pid Thread.print
+ jcmd $jvm_pid Thread.print
done
- if: ${{ runner.os == 'Windows' }}
shell: powershell
diff --git a/.github/actions/publish-gradle-plugin/action.yml b/.github/actions/publish-gradle-plugin/action.yml
index ee61f9feb9ec..ccc5b1bab305 100644
--- a/.github/actions/publish-gradle-plugin/action.yml
+++ b/.github/actions/publish-gradle-plugin/action.yml
@@ -21,7 +21,7 @@ runs:
using: composite
steps:
- name: Set Up JFrog CLI
- uses: jfrog/setup-jfrog-cli@727b480bafd0d8adbdfdb2257a7d7c2e08eb1779 # v4.0.2
+ uses: jfrog/setup-jfrog-cli@8bab65dc312163b065ac5b03de6f6a5bdd1bec41 # v4.1.3
env:
JF_ENV_SPRING: ${{ inputs.jfrog-cli-config-token }}
- name: Download Artifacts
diff --git a/.github/actions/publish-to-sdkman/action.yml b/.github/actions/publish-to-sdkman/action.yml
index 2d23b18232bc..7458c863ac57 100644
--- a/.github/actions/publish-to-sdkman/action.yml
+++ b/.github/actions/publish-to-sdkman/action.yml
@@ -29,7 +29,7 @@ runs:
- shell: bash
if: ${{ inputs.make-default == 'true' }}
run: >
- curl -X POST \
+ curl -X PUT \
-H "Consumer-Key: ${{ inputs.sdkman-consumer-key }}" \
-H "Consumer-Token: ${{ inputs.sdkman-consumer-token }}" \
-H "Content-Type: application/json" \
diff --git a/.github/actions/sync-to-maven-central/action.yml b/.github/actions/sync-to-maven-central/action.yml
index ef74ce2f6cf9..8ebef462a1cc 100644
--- a/.github/actions/sync-to-maven-central/action.yml
+++ b/.github/actions/sync-to-maven-central/action.yml
@@ -20,7 +20,7 @@ runs:
using: composite
steps:
- name: Set Up JFrog CLI
- uses: jfrog/setup-jfrog-cli@727b480bafd0d8adbdfdb2257a7d7c2e08eb1779 # v4.0.2
+ uses: jfrog/setup-jfrog-cli@8bab65dc312163b065ac5b03de6f6a5bdd1bec41 # v4.1.3
env:
JF_ENV_SPRING: ${{ inputs.jfrog-cli-config-token }}
- name: Download Release Artifacts
diff --git a/.github/actions/update-homebrew-tap/action.yml b/.github/actions/update-homebrew-tap/action.yml
new file mode 100644
index 000000000000..52b20e0990a8
--- /dev/null
+++ b/.github/actions/update-homebrew-tap/action.yml
@@ -0,0 +1,32 @@
+name: Update Homebrew Tap
+description: Updates the Homebrew Tap for the Spring Boot CLI
+inputs:
+ spring-boot-version:
+ description: 'The version to publish'
+ required: true
+ token:
+ description: 'Token to use for GitHub authentication'
+ required: true
+runs:
+ using: composite
+ steps:
+ - name: Check Out Homebrew Tap Repo
+ uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
+ with:
+ path: updated-homebrew-tap-repo
+ repository: spring-io/homebrew-tap
+ token: ${{ inputs.token }}
+ - name: Update Homebrew Tap
+ shell: bash
+ run: |
+ pushd updated-homebrew-tap-repo > /dev/null
+ curl https://repo.maven.apache.org/maven2/org/springframework/boot/spring-boot-cli/${{ inputs.spring-boot-version }}/spring-boot-cli-${{ inputs.spring-boot-version }}-homebrew.rb --output spring-boot-cli-${{ inputs.spring-boot-version }}-homebrew.rb
+ rm spring-boot.rb
+ mv spring-boot-cli-*.rb spring-boot.rb
+ git config user.name "Spring Builds" > /dev/null
+ git config user.email "spring-builds@users.noreply.github.com" > /dev/null
+ git add spring-boot.rb > /dev/null
+ git commit -m "Upgrade to Spring Boot ${{ inputs.spring-boot-version }}" > /dev/null
+ git push
+ echo "DONE"
+ popd > /dev/null
diff --git a/.github/dependabot.yml b/.github/dependabot.yml
index 5ace4600a1f2..187fe1cd726c 100644
--- a/.github/dependabot.yml
+++ b/.github/dependabot.yml
@@ -4,3 +4,5 @@ updates:
directory: "/"
schedule:
interval: "weekly"
+ labels:
+ - "type: task"
diff --git a/.github/workflows/build-and-deploy-snapshot.yml b/.github/workflows/build-and-deploy-snapshot.yml
index 787addc332eb..5984b036652a 100644
--- a/.github/workflows/build-and-deploy-snapshot.yml
+++ b/.github/workflows/build-and-deploy-snapshot.yml
@@ -2,7 +2,7 @@ name: Build and Deploy Snapshot
on:
push:
branches:
- - 3.1.x
+ - main
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
jobs:
@@ -25,13 +25,11 @@ jobs:
uri: 'https://repo.spring.io'
username: ${{ secrets.ARTIFACTORY_USERNAME }}
password: ${{ secrets.ARTIFACTORY_PASSWORD }}
- build-name: ${{ format('spring-boot-{0}', github.ref_name)}}
+ build-name: 'spring-boot-3.4.x'
repository: 'libs-snapshot-local'
folder: 'deployment-repository'
signing-key: ${{ secrets.GPG_PRIVATE_KEY }}
signing-passphrase: ${{ secrets.GPG_PASSPHRASE }}
- artifact-properties: |
- /**/spring-boot-docs-*.zip::zip.type=docs,zip.deployed=false
- name: Send Notification
uses: ./.github/actions/send-notification
if: always()
@@ -42,6 +40,17 @@ jobs:
run-name: ${{ format('{0} | Linux | Java 17', github.ref_name) }}
outputs:
version: ${{ steps.build-and-publish.outputs.version }}
+ trigger-docs-build:
+ name: Trigger Docs Build
+ runs-on: ubuntu-latest
+ needs: build-and-deploy-snapshot
+ permissions:
+ actions: write
+ steps:
+ - name: Run Deploy Docs Workflow
+ env:
+ GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ run: gh workflow run deploy-docs.yml --repo spring-projects/spring-boot -r docs-build -f build-refname=${{ github.ref_name }} -f build-version=${{ needs.build-and-deploy-snapshot.outputs.version }}
verify:
name: Verify
needs: build-and-deploy-snapshot
diff --git a/.github/workflows/build-pull-request.yml b/.github/workflows/build-pull-request.yml
index 2573dbea2e4c..cf40231b357d 100644
--- a/.github/workflows/build-pull-request.yml
+++ b/.github/workflows/build-pull-request.yml
@@ -23,9 +23,9 @@ jobs:
- name: Check Out
uses: actions/checkout@v4
- name: Validate Gradle Wrapper
- uses: gradle/actions/wrapper-validation@db19848a5fa7950289d3668fb053140cf3028d43 #v3.3.2
+ uses: gradle/actions/wrapper-validation@d9c87d481d55275bb5441eef3fe0e46805f9ef70 # v3.5.0
- name: Set Up Gradle
- uses: gradle/actions/setup-gradle@db19848a5fa7950289d3668fb053140cf3028d43 # v3.3.2
+ uses: gradle/actions/setup-gradle@d9c87d481d55275bb5441eef3fe0e46805f9ef70 # v3.5.0
- name: Build
env:
CI: 'true'
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index ea93c4539933..feee333bb63b 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -2,7 +2,7 @@ name: CI
on:
push:
branches:
- - 3.1.x
+ - main
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
jobs:
@@ -22,6 +22,8 @@ jobs:
toolchain: false
- version: 21
toolchain: true
+ - version: 22
+ toolchain: true
exclude:
- os:
name: Linux
@@ -41,6 +43,7 @@ jobs:
uses: ./.github/actions/build
with:
java-version: ${{ matrix.java.version }}
+ java-distribution: ${{ matrix.java.distribution || 'liberica' }}
java-toolchain: ${{ matrix.java.toolchain }}
develocity-access-key: ${{ secrets.GRADLE_ENTERPRISE_SECRET_ACCESS_KEY }}
- name: Send Notification
diff --git a/.github/workflows/release-milestone.yml b/.github/workflows/release-milestone.yml
new file mode 100644
index 000000000000..838aeb1074b6
--- /dev/null
+++ b/.github/workflows/release-milestone.yml
@@ -0,0 +1,75 @@
+name: Release Milestone
+on:
+ push:
+ tags:
+ - v3.4.0-M[0-9]
+ - v3.4.0-RC[0-9]
+concurrency:
+ group: ${{ github.workflow }}-${{ github.ref }}
+jobs:
+ build-and-stage-release:
+ name: Build and Stage Release
+ runs-on: ubuntu-latest
+ if: ${{ github.repository == 'spring-projects/spring-boot' }}
+ steps:
+ - name: Check Out Code
+ uses: actions/checkout@v4
+ - name: Build and Publish
+ id: build-and-publish
+ uses: ./.github/actions/build
+ with:
+ develocity-access-key: ${{ secrets.GRADLE_ENTERPRISE_SECRET_ACCESS_KEY }}
+ publish: true
+ - name: Stage Release
+ uses: spring-io/artifactory-deploy-action@26bbe925a75f4f863e1e529e85be2d0093cac116 # v0.0.1
+ with:
+ uri: 'https://repo.spring.io'
+ username: ${{ secrets.ARTIFACTORY_USERNAME }}
+ password: ${{ secrets.ARTIFACTORY_PASSWORD }}
+ build-name: ${{ format('spring-boot-{0}', steps.build-and-publish.outputs.version)}}
+ repository: 'libs-staging-local'
+ folder: 'deployment-repository'
+ signing-key: ${{ secrets.GPG_PRIVATE_KEY }}
+ signing-passphrase: ${{ secrets.GPG_PASSPHRASE }}
+ outputs:
+ version: ${{ steps.build-and-publish.outputs.version }}
+ verify:
+ name: Verify
+ needs: build-and-stage-release
+ uses: ./.github/workflows/verify.yml
+ with:
+ staging: true
+ version: ${{ needs.build-and-stage-release.outputs.version }}
+ secrets:
+ google-chat-webhook-url: ${{ secrets.GOOGLE_CHAT_WEBHOOK_URL }}
+ repository-password: ${{ secrets.ARTIFACTORY_PASSWORD }}
+ repository-username: ${{ secrets.ARTIFACTORY_USERNAME }}
+ token: ${{ secrets.GH_ACTIONS_REPO_TOKEN }}
+ promote-release:
+ name: Promote Release
+ needs:
+ - build-and-stage-release
+ - verify
+ runs-on: ubuntu-latest
+ steps:
+ - name: Set up JFrog CLI
+ uses: jfrog/setup-jfrog-cli@8bab65dc312163b065ac5b03de6f6a5bdd1bec41 # v4.1.3
+ env:
+ JF_ENV_SPRING: ${{ secrets.JF_ARTIFACTORY_SPRING }}
+ - name: Promote build
+ run: jfrog rt build-promote ${{ format('spring-boot-{0}', needs.build-and-stage-release.outputs.version)}} ${{ github.run_number }} libs-milestone-local
+ create-github-release:
+ name: Create GitHub Release
+ needs:
+ - build-and-stage-release
+ - promote-release
+ runs-on: ubuntu-latest
+ steps:
+ - name: Check Out Code
+ uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
+ - name: Create GitHub Release
+ uses: ./.github/actions/create-github-release
+ with:
+ milestone: ${{ needs.build-and-stage-release.outputs.version }}
+ token: ${{ secrets.GH_ACTIONS_REPO_TOKEN }}
+ pre-release: true
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index cd7eca367b9d..41bf496bef30 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -2,14 +2,14 @@ name: Release
on:
push:
tags:
- - v3.1.[0-9]+
+ - v3.4.[0-9]+
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
jobs:
build-and-stage-release:
- if: ${{ github.repository == 'spring-projects/spring-boot' }}
name: Build and Stage Release
runs-on: ubuntu-latest
+ if: ${{ github.repository == 'spring-projects/spring-boot' }}
steps:
- name: Check Out Code
uses: actions/checkout@v4
@@ -22,16 +22,14 @@ jobs:
- name: Stage Release
uses: spring-io/artifactory-deploy-action@26bbe925a75f4f863e1e529e85be2d0093cac116 # v0.0.1
with:
- build-name: ${{ format('spring-boot-{0}', steps.build-and-publish.outputs.version)}}
- folder: 'deployment-repository'
+ uri: 'https://repo.spring.io'
+ username: ${{ secrets.ARTIFACTORY_USERNAME }}
password: ${{ secrets.ARTIFACTORY_PASSWORD }}
+ build-name: ${{ format('spring-boot-{0}', steps.build-and-publish.outputs.version)}}
repository: 'libs-staging-local'
+ folder: 'deployment-repository'
signing-key: ${{ secrets.GPG_PRIVATE_KEY }}
signing-passphrase: ${{ secrets.GPG_PASSPHRASE }}
- uri: 'https://repo.spring.io'
- username: ${{ secrets.ARTIFACTORY_USERNAME }}
- artifact-properties: |
- /**/spring-boot-docs-*.zip::zip.type=docs,zip.deployed=false
outputs:
version: ${{ steps.build-and-publish.outputs.version }}
verify:
@@ -71,7 +69,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Set up JFrog CLI
- uses: jfrog/setup-jfrog-cli@727b480bafd0d8adbdfdb2257a7d7c2e08eb1779 # v4.0.2
+ uses: jfrog/setup-jfrog-cli@8bab65dc312163b065ac5b03de6f6a5bdd1bec41 # v4.1.3
env:
JF_ENV_SPRING: ${{ secrets.JF_ARTIFACTORY_SPRING }}
- name: Promote build
@@ -104,9 +102,24 @@ jobs:
- name: Publish to SDKMAN!
uses: ./.github/actions/publish-to-sdkman
with:
+ make-default: true
sdkman-consumer-key: ${{ secrets.SDKMAN_CONSUMER_KEY }}
sdkman-consumer-token: ${{ secrets.SDKMAN_CONSUMER_TOKEN }}
spring-boot-version: ${{ needs.build-and-stage-release.outputs.version }}
+ update-homebrew-tap:
+ name: Update Homebrew Tap
+ needs:
+ - build-and-stage-release
+ - sync-to-maven-central
+ runs-on: ubuntu-latest
+ steps:
+ - name: Check Out Code
+ uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
+ - name: Update Homebrew Tap
+ uses: ./.github/actions/update-homebrew-tap
+ with:
+ spring-boot-version: ${{ needs.build-and-stage-release.outputs.version }}
+ token: ${{ secrets.GH_ACTIONS_REPO_TOKEN }}
create-github-release:
name: Create GitHub Release
needs:
@@ -114,6 +127,7 @@ jobs:
- promote-release
- publish-gradle-plugin
- publish-to-sdkman
+ - update-homebrew-tap
runs-on: ubuntu-latest
steps:
- name: Check Out Code
diff --git a/.github/workflows/run-system-tests.yml b/.github/workflows/run-system-tests.yml
index bd3cc5365df0..0e18c07cd4c4 100644
--- a/.github/workflows/run-system-tests.yml
+++ b/.github/workflows/run-system-tests.yml
@@ -2,7 +2,7 @@ name: Run System Tests
on:
push:
branches:
- - 3.1.x
+ - main
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
jobs:
@@ -23,18 +23,13 @@ jobs:
- name: Prepare Gradle Build
uses: ./.github/actions/prepare-gradle-build
with:
+ develocity-access-key: ${{ secrets.GRADLE_ENTERPRISE_SECRET_ACCESS_KEY }}
java-version: ${{ matrix.java.version }}
java-toolchain: ${{ matrix.java.toolchain }}
- name: Run System Tests
id: run-system-tests
shell: bash
- env:
- GRADLE_ENTERPRISE_URL: 'https://ge.spring.io'
- GRADLE_ENTERPRISE_ACCESS_KEY: ${{ secrets.GRADLE_ENTERPRISE_SECRET_ACCESS_KEY }}
- GRADLE_ENTERPRISE_CACHE_USERNAME: ${{ secrets.GRADLE_ENTERPRISE_CACHE_USER }}
- GRADLE_ENTERPRISE_CACHE_PASSWORD: ${{ secrets.GRADLE_ENTERPRISE_CACHE_PASSWORD }}
- run: |
- ./gradlew systemTest
+ run: ./gradlew systemTest
- name: Send Notification
uses: ./.github/actions/send-notification
if: always()
diff --git a/.github/workflows/trigger-docs-build.yml b/.github/workflows/trigger-docs-build.yml
new file mode 100644
index 000000000000..4fe7f96e569b
--- /dev/null
+++ b/.github/workflows/trigger-docs-build.yml
@@ -0,0 +1,29 @@
+name: Trigger Docs Build
+on:
+ push:
+ branches: main
+ paths: [ 'antora/*' ]
+ workflow_dispatch:
+ inputs:
+ build-refname:
+ description: Enter git refname to build (e.g., 1.0.x).
+ required: false
+ build-version:
+ description: Enter the version being build (e.g. 1.0.3-SNAPSHOT)
+ required: false
+permissions:
+ actions: write
+jobs:
+ trigger-docs-build:
+ name: Trigger Docs Build
+ runs-on: ubuntu-latest
+ if: github.repository_owner == 'spring-projects'
+ steps:
+ - name: Check Out
+ uses: actions/checkout@v4
+ with:
+ ref: docs-build
+ - name: Trigger Workflow
+ env:
+ GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ run: gh workflow run deploy-docs.yml -r docs-build -f build-refname=${{ github.event.inputs.build-refname }} -f build-version=${{ github.event.inputs.build-version }}
diff --git a/.github/workflows/validate-gradle-wrapper.yml b/.github/workflows/validate-gradle-wrapper.yml
index 9569f38789b9..7a473b3afe72 100644
--- a/.github/workflows/validate-gradle-wrapper.yml
+++ b/.github/workflows/validate-gradle-wrapper.yml
@@ -8,4 +8,4 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- - uses: gradle/actions/wrapper-validation@db19848a5fa7950289d3668fb053140cf3028d43 #v3.3.2
+ - uses: gradle/actions/wrapper-validation@d9c87d481d55275bb5441eef3fe0e46805f9ef70 # v3.5.0
diff --git a/.github/workflows/verify.yml b/.github/workflows/verify.yml
index 54bf05234624..9f401f7bea99 100644
--- a/.github/workflows/verify.yml
+++ b/.github/workflows/verify.yml
@@ -42,7 +42,7 @@ jobs:
- name: Set Up Homebrew
uses: Homebrew/actions/setup-homebrew@7657c9512f50e1c35b640971116425935bab3eea
- name: Set Up Gradle
- uses: gradle/actions/setup-gradle@db19848a5fa7950289d3668fb053140cf3028d43 #v3.3.2
+ uses: gradle/actions/setup-gradle@d9c87d481d55275bb5441eef3fe0e46805f9ef70 # v3.5.0
with:
cache-read-only: false
- name: Configure Gradle Properties
diff --git a/.gitignore b/.gitignore
index 2a812bc5079c..1198c2da875d 100644
--- a/.gitignore
+++ b/.gitignore
@@ -40,3 +40,4 @@ secrets.yml
.gradletasknamecache
.sts4-cache
.git-hooks/
+node_modules
diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml
index 7f1766dd1b68..df1bf12fd2db 100644
--- a/.idea/inspectionProfiles/Project_Default.xml
+++ b/.idea/inspectionProfiles/Project_Default.xml
@@ -2,6 +2,16 @@
+
+
+
+
+
+
+
+
+
+
-
\ No newline at end of file
+
diff --git a/CODE_OF_CONDUCT.adoc b/CODE_OF_CONDUCT.adoc
deleted file mode 100644
index 18c62c93ec8c..000000000000
--- a/CODE_OF_CONDUCT.adoc
+++ /dev/null
@@ -1,44 +0,0 @@
-= Contributor Code of Conduct
-
-As contributors and maintainers of this project, and in the interest of fostering an open
-and welcoming community, we pledge to respect all people who contribute through reporting
-issues, posting feature requests, updating documentation, submitting pull requests or
-patches, and other activities.
-
-We are committed to making participation in this project a harassment-free experience for
-everyone, regardless of level of experience, gender, gender identity and expression,
-sexual orientation, disability, personal appearance, body size, race, ethnicity, age,
-religion, or nationality.
-
-Examples of unacceptable behavior by participants include:
-
-* The use of sexualized language or imagery
-* Personal attacks
-* Trolling or insulting/derogatory comments
-* Public or private harassment
-* Publishing other's private information, such as physical or electronic addresses,
- without explicit permission
-* Other unethical or unprofessional conduct
-
-Project maintainers have the right and responsibility to remove, edit, or reject comments,
-commits, code, wiki edits, issues, and other contributions that are not aligned to this
-Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors
-that they deem inappropriate, threatening, offensive, or harmful.
-
-By adopting this Code of Conduct, project maintainers commit themselves to fairly and
-consistently applying these principles to every aspect of managing this project. Project
-maintainers who do not follow or enforce the Code of Conduct may be permanently removed
-from the project team.
-
-This Code of Conduct applies both within project spaces and in public spaces when an
-individual is representing the project or its community.
-
-Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by
-contacting a project maintainer at code-of-conduct@spring.io. All complaints will
-be reviewed and investigated and will result in a response that is deemed necessary and
-appropriate to the circumstances. Maintainers are obligated to maintain confidentiality
-with regard to the reporter of an incident.
-
-This Code of Conduct is adapted from the
-https://contributor-covenant.org[Contributor Covenant], version 1.3.0, available at
-https://contributor-covenant.org/version/1/3/0/[contributor-covenant.org/version/1/3/0/]
diff --git a/CONTRIBUTING.adoc b/CONTRIBUTING.adoc
index d2541b7a7ed5..fba0d2aa2808 100755
--- a/CONTRIBUTING.adoc
+++ b/CONTRIBUTING.adoc
@@ -5,12 +5,14 @@ Spring Boot is released under the Apache 2.0 license. If you would like to contr
== Code of Conduct
-This project adheres to the Contributor Covenant link:CODE_OF_CONDUCT.adoc[code of conduct].
+
+This project adheres to the Contributor Covenant https://github.com/spring-projects/spring-boot?tab=coc-ov-file#contributor-code-of-conduct[code of conduct].
By participating, you are expected to uphold this code. Please report unacceptable behavior to code-of-conduct@spring.io.
== Using GitHub Issues
+
We use GitHub issues to track bugs and enhancements.
If you have a general usage question please ask on https://stackoverflow.com[Stack Overflow].
The Spring Boot team and the broader community monitor the https://stackoverflow.com/tags/spring-boot[`spring-boot`] tag.
@@ -21,12 +23,14 @@ Ideally, that would include a small sample project that reproduces the problem.
== Reporting Security Vulnerabilities
+
If you think you have found a security vulnerability in Spring Boot please *DO NOT* disclose it publicly until we've had a chance to fix it.
Please don't report security vulnerabilities using GitHub issues, instead head over to https://spring.io/security-policy and learn how to disclose them responsibly.
== Sign the Contributor License Agreement
+
Before we accept a non-trivial patch or pull request we will need you to https://cla.pivotal.io/sign/spring[sign the Contributor License Agreement].
Signing the contributor's agreement does not grant anyone commit rights to the main repository, but it does mean that we can accept your contributions, and you will get an author credit if we do.
Active contributors might be asked to join the core team, and given the ability to merge pull requests.
@@ -34,6 +38,7 @@ Active contributors might be asked to join the core team, and given the ability
== Code Conventions and Housekeeping
+
None of these is essential for a pull request, but they will all help. They can also be
added after the original pull request but before a merge.
@@ -55,4 +60,5 @@ added after the original pull request but before a merge.
== Working with the Code
+
For information on editing, building, and testing the code, see the https://github.com/spring-projects/spring-boot/wiki/Working-with-the-Code[Working with the Code] page on the project wiki.
diff --git a/README.adoc b/README.adoc
index a9bc69b52994..bbbbc664d51e 100755
--- a/README.adoc
+++ b/README.adoc
@@ -1,5 +1,6 @@
-= Spring Boot image:https://github.com/spring-projects/spring-boot/actions/workflows/build-and-deploy-snapshot.yml/badge.svg?branch=3.1.x["Build Status", link="https://github.com/spring-projects/spring-boot/actions/workflows/build-and-deploy-snapshot.yml?query=branch%3A3.1.x"] image:https://badges.gitter.im/Join Chat.svg["Chat",link="https://gitter.im/spring-projects/spring-boot?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge"] image:https://img.shields.io/badge/Revved%20up%20by-Develocity-06A0CE?logo=Gradle&labelColor=02303A["Revved up by Develocity", link="https://ge.spring.io/scans?&search.rootProjectNames=Spring%20Boot%20Build&search.rootProjectNames=spring-boot-build"]
-:docs: https://docs.spring.io/spring-boot/docs/current-SNAPSHOT/reference
+= Spring Boot image:https://github.com/spring-projects/spring-boot/actions/workflows/build-and-deploy-snapshot.yml/badge.svg?branch=main["Build Status", link="https://github.com/spring-projects/spring-boot/actions/workflows/build-and-deploy-snapshot.yml?query=branch%3Amain"] image:https://badges.gitter.im/Join Chat.svg["Chat",link="https://gitter.im/spring-projects/spring-boot?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge"] image:https://img.shields.io/badge/Revved%20up%20by-Develocity-06A0CE?logo=Gradle&labelColor=02303A["Revved up by Develocity", link="https://ge.spring.io/scans?&search.rootProjectNames=Spring%20Boot%20Build&search.rootProjectNames=spring-boot-build"]
+
+:docs: https://docs.spring.io/spring-boot
:github: https://github.com/spring-projects/spring-boot
Spring Boot helps you to create Spring-powered, production-grade applications and services with absolute minimum fuss.
@@ -18,38 +19,40 @@ Our primary goals are:
== Installation and Getting Started
-The {docs}/html/[reference documentation] includes detailed {docs}/html/getting-started.html#getting-started-installing-spring-boot[installation instructions] as well as a comprehensive {docs}/html/getting-started.html#getting-started-first-application[``getting started``] guide.
+
+The {docs}[reference documentation] includes detailed {docs}/installing.html[installation instructions] as well as a comprehensive {docs}/tutorial/first-application/index.html[``getting started``] guide.
Here is a quick teaser of a complete Spring Boot application in Java:
-[source,java,indent=0]
+[source,java]
----
- import org.springframework.boot.*;
- import org.springframework.boot.autoconfigure.*;
- import org.springframework.web.bind.annotation.*;
-
- @RestController
- @SpringBootApplication
- public class Example {
+import org.springframework.boot.*;
+import org.springframework.boot.autoconfigure.*;
+import org.springframework.web.bind.annotation.*;
- @RequestMapping("/")
- String home() {
- return "Hello World!";
- }
+@RestController
+@SpringBootApplication
+public class Example {
- public static void main(String[] args) {
- SpringApplication.run(Example.class, args);
- }
+ @RequestMapping("/")
+ String home() {
+ return "Hello World!";
+ }
+ public static void main(String[] args) {
+ SpringApplication.run(Example.class, args);
}
+
+}
----
== Getting Help
+
Are you having trouble with Spring Boot? We want to help!
-* Check the {docs}/html/[reference documentation], especially the {docs}/html/howto.html#howto[How-to's] -- they provide solutions to the most common questions.
+* Check the {docs}/[reference documentation], especially the {docs}/how-to/index.html[How-to's] -- they provide solutions to the most common questions.
* Learn the Spring basics -- Spring Boot builds on many other Spring projects; check the https://spring.io[spring.io] website for a wealth of reference documentation.
If you are new to Spring, try one of the https://spring.io/guides[guides].
* If you are upgrading, read the {github}/wiki[release notes] for upgrade instructions and "new and noteworthy" features.
@@ -60,6 +63,7 @@ Are you having trouble with Spring Boot? We want to help!
== Reporting Issues
+
Spring Boot uses GitHub's integrated issue tracking system to record bugs and feature requests.
If you want to raise an issue, please follow the recommendations below:
@@ -74,31 +78,34 @@ We like to know the Spring Boot version, operating system, and JVM version you'r
== Building from Source
+
You don't need to build from source to use Spring Boot (binaries in https://repo.spring.io[repo.spring.io]), but if you want to try out the latest and greatest, Spring Boot can be built and published to your local Maven cache using the https://docs.gradle.org/current/userguide/gradle_wrapper.html[Gradle wrapper].
You also need JDK 17.
-[indent=0]
+[source,shell]
----
- $ ./gradlew publishToMavenLocal
+$ ./gradlew publishToMavenLocal
----
This will build all of the jars and documentation and publish them to your local Maven cache.
It won't run any of the tests.
If you want to build everything, use the `build` task:
-[indent=0]
+[source,shell]
----
- $ ./gradlew build
+$ ./gradlew build
----
== Modules
+
There are several modules in Spring Boot. Here is a quick overview:
=== spring-boot
+
The main library providing features that support the other parts of Spring Boot. These include:
* The `SpringApplication` class, providing static convenience methods that can be used to write a stand-alone Spring Application.
@@ -110,6 +117,7 @@ The main library providing features that support the other parts of Spring Boot.
=== spring-boot-autoconfigure
+
Spring Boot can configure large parts of typical applications based on the content of their classpath.
A single `@EnableAutoConfiguration` annotation triggers auto-configuration of the Spring context.
@@ -119,6 +127,7 @@ Auto-configuration will always back away as the user starts to define their own
=== spring-boot-starters
+
Starters are a set of convenient dependency descriptors that you can include in your application.
You get a one-stop shop for all the Spring and related technology you need without having to hunt through sample code and copy-paste loads of dependency descriptors.
For example, if you want to get started using Spring and JPA for database access, include the `spring-boot-starter-data-jpa` dependency in your project, and you are good to go.
@@ -126,6 +135,7 @@ For example, if you want to get started using Spring and JPA for database access
=== spring-boot-actuator
+
Actuator endpoints let you monitor and interact with your application.
Spring Boot Actuator provides the infrastructure required for actuator endpoints.
It contains annotation support for actuator endpoints.
@@ -134,6 +144,7 @@ This module provides many endpoints, including the `HealthEndpoint`, `Environmen
=== spring-boot-actuator-autoconfigure
+
This provides auto-configuration for actuator endpoints based on the content of the classpath and a set of properties.
For instance, if Micrometer is on the classpath, it will auto-configure the `MetricsEndpoint`.
It contains configuration to expose endpoints over HTTP or JMX.
@@ -142,29 +153,34 @@ Just like Spring Boot AutoConfigure, this will back away as the user starts to d
=== spring-boot-test
+
This module contains core items and annotations that can be helpful when testing your application.
=== spring-boot-test-autoconfigure
+
Like other Spring Boot auto-configuration modules, spring-boot-test-autoconfigure provides auto-configuration for tests based on the classpath.
It includes many annotations that can automatically configure a slice of your application that needs to be tested.
=== spring-boot-loader
+
Spring Boot Loader provides the secret sauce that allows you to build a single jar file that can be launched using `java -jar`.
Generally, you will not need to use `spring-boot-loader` directly but work with the link:spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin[Gradle] or link:spring-boot-project/spring-boot-tools/spring-boot-maven-plugin[Maven] plugin instead.
=== spring-boot-devtools
+
The spring-boot-devtools module provides additional development-time features, such as automatic restarts, for a smoother application development experience.
Developer tools are automatically disabled when running a fully packaged application.
== Guides
+
The https://spring.io/[spring.io] site contains several guides that show how to use Spring Boot step-by-step:
* https://spring.io/guides/gs/spring-boot/[Building an Application with Spring Boot] is an introductory guide that shows you how to create an application, run it, and add some management services.
@@ -174,4 +190,5 @@ The https://spring.io/[spring.io] site contains several guides that show how to
== License
+
Spring Boot is Open Source software released under the https://www.apache.org/licenses/LICENSE-2.0.html[Apache 2.0 license].
diff --git a/SUPPORT.adoc b/SUPPORT.adoc
index 898f5caa8a16..23a8b8bbe549 100755
--- a/SUPPORT.adoc
+++ b/SUPPORT.adoc
@@ -1,6 +1,9 @@
= Getting support for Spring Boot
+
+
== GitHub issues
+
We choose not to use GitHub issues for general usage questions and support, preferring to
use issues solely for the tracking of bugs and enhancements. If you have a general
usage question please do not open a GitHub issue, but use one of the other channels
@@ -10,17 +13,26 @@ If you are reporting a bug, please help to speed up problem diagnosis by providi
much information as possible. Ideally, that would include a small sample project that
reproduces the problem.
+
+
== Stack Overflow
+
The Spring Boot community monitors the
https://stackoverflow.com/tags/spring-boot[`spring-boot`] tag on Stack Overflow. Before
asking a question, please familiarize yourself with Stack Overflow's
https://stackoverflow.com/help/how-to-ask[advice on how to ask a good question].
+
+
== Gitter
+
If you want to discuss something or have a question that isn't suited to Stack Overflow,
the Spring Boot community chat in the
https://gitter.im/spring-projects/spring-boot[#spring-boot room on Gitter].
+
+
== VMware Open Source Software Support
+
If you are interested in more dedicated support, VMware provides
https://spring.io/support[premium support] for Spring Boot.
diff --git a/antora/package-lock.json b/antora/package-lock.json
new file mode 100644
index 000000000000..c3d2ead92458
--- /dev/null
+++ b/antora/package-lock.json
@@ -0,0 +1,2968 @@
+{
+ "name": "antora",
+ "lockfileVersion": 3,
+ "requires": true,
+ "packages": {
+ "": {
+ "dependencies": {
+ "@antora/atlas-extension": "1.0.0-alpha.2",
+ "@antora/cli": "3.2.0-alpha.4",
+ "@antora/site-generator": "3.2.0-alpha.4",
+ "@asciidoctor/tabs": "1.0.0-beta.6",
+ "@springio/antora-extensions": "1.11.1",
+ "@springio/antora-xref-extension": "1.0.0-alpha.3",
+ "@springio/antora-zip-contents-collector-extension": "1.0.0-alpha.8",
+ "@springio/asciidoctor-extensions": "1.0.0-alpha.10"
+ }
+ },
+ "node_modules/@antora/asciidoc-loader": {
+ "version": "3.2.0-alpha.4",
+ "resolved": "https://registry.npmjs.org/@antora/asciidoc-loader/-/asciidoc-loader-3.2.0-alpha.4.tgz",
+ "integrity": "sha512-FRNq3ErMFMJPHxYQxHyuMdX4YULs9aXc+njmAoMGbyO9SNAYCwzirOBXVQegefcGDn85Y/3zLU6BanZNpxCaXQ==",
+ "dependencies": {
+ "@antora/logger": "3.2.0-alpha.4",
+ "@antora/user-require-helper": "~2.0",
+ "@asciidoctor/core": "~2.2"
+ },
+ "engines": {
+ "node": ">=16.0.0"
+ }
+ },
+ "node_modules/@antora/atlas-extension": {
+ "version": "1.0.0-alpha.2",
+ "resolved": "https://registry.npmjs.org/@antora/atlas-extension/-/atlas-extension-1.0.0-alpha.2.tgz",
+ "integrity": "sha512-tOQy3eQjvoYGV3UnDaOjkaCehbWSpjQWRdCCYXx8c2Do4rysclOVVN4t4AsfeOHK+BoWlKqa7mldb1DCYOBQTw==",
+ "dependencies": {
+ "@antora/expand-path-helper": "~2.0",
+ "cache-directory": "~2.0",
+ "node-gzip": "~1.1",
+ "simple-get": "~4.0"
+ },
+ "engines": {
+ "node": ">=16.0.0"
+ }
+ },
+ "node_modules/@antora/cli": {
+ "version": "3.2.0-alpha.4",
+ "resolved": "https://registry.npmjs.org/@antora/cli/-/cli-3.2.0-alpha.4.tgz",
+ "integrity": "sha512-tRTdO1Cp5hmV4sZZbD/Y0bZ+fQSCcESc1Y8txmCG+25lFC8PefjKC0mgWOq25RAjNxlUZ390DU35NNR9McjUsA==",
+ "dependencies": {
+ "@antora/logger": "3.2.0-alpha.4",
+ "@antora/playbook-builder": "3.2.0-alpha.4",
+ "@antora/user-require-helper": "~2.0",
+ "commander": "~10.0"
+ },
+ "bin": {
+ "antora": "bin/antora"
+ },
+ "engines": {
+ "node": ">=16.0.0"
+ }
+ },
+ "node_modules/@antora/content-aggregator": {
+ "version": "3.2.0-alpha.4",
+ "resolved": "https://registry.npmjs.org/@antora/content-aggregator/-/content-aggregator-3.2.0-alpha.4.tgz",
+ "integrity": "sha512-+Y6WybHnNN7bw/MFUPL8ca6SiNqT2AUZCI1NRhwYym2JD6dBIwGedNEh76a7MGTObQXKjlBrmm025FHBWg4j5Q==",
+ "dependencies": {
+ "@antora/expand-path-helper": "~2.0",
+ "@antora/logger": "3.2.0-alpha.4",
+ "@antora/user-require-helper": "~2.0",
+ "braces": "~3.0",
+ "cache-directory": "~2.0",
+ "glob-stream": "~7.0",
+ "hpagent": "~1.2",
+ "isomorphic-git": "~1.25",
+ "js-yaml": "~4.1",
+ "multi-progress": "~4.0",
+ "picomatch": "~2.3",
+ "progress": "~2.0",
+ "should-proxy": "~1.0",
+ "simple-get": "~4.0",
+ "vinyl": "~2.2"
+ },
+ "engines": {
+ "node": ">=16.0.0"
+ }
+ },
+ "node_modules/@antora/content-classifier": {
+ "version": "3.2.0-alpha.4",
+ "resolved": "https://registry.npmjs.org/@antora/content-classifier/-/content-classifier-3.2.0-alpha.4.tgz",
+ "integrity": "sha512-XN5JzSum/nxv1fEb7j8vFG1FLaEnBXnPxzY+hC1/pGODXVVlFVyRoxR35fx91oJ8TgVIHI+bLvymsF/MJYYmbQ==",
+ "dependencies": {
+ "@antora/asciidoc-loader": "3.2.0-alpha.4",
+ "@antora/logger": "3.2.0-alpha.4",
+ "mime-types": "~2.1",
+ "vinyl": "~2.2"
+ },
+ "engines": {
+ "node": ">=16.0.0"
+ }
+ },
+ "node_modules/@antora/document-converter": {
+ "version": "3.2.0-alpha.4",
+ "resolved": "https://registry.npmjs.org/@antora/document-converter/-/document-converter-3.2.0-alpha.4.tgz",
+ "integrity": "sha512-Wbh76FELpHBfqvnKiAPvXtxkTeGP0Fk/2nZBkmTTWbpBSs98o7YfNWnVQ9Ky86jdXGmxM+LMNFoXKVIzNbpd3g==",
+ "dependencies": {
+ "@antora/asciidoc-loader": "3.2.0-alpha.4"
+ },
+ "engines": {
+ "node": ">=16.0.0"
+ }
+ },
+ "node_modules/@antora/expand-path-helper": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/@antora/expand-path-helper/-/expand-path-helper-2.0.0.tgz",
+ "integrity": "sha512-CSMBGC+tI21VS2kGW3PV7T2kQTM5eT3f2GTPVLttwaNYbNxDve08en/huzszHJfxo11CcEs26Ostr0F2c1QqeA==",
+ "engines": {
+ "node": ">=10.17.0"
+ }
+ },
+ "node_modules/@antora/file-publisher": {
+ "version": "3.2.0-alpha.4",
+ "resolved": "https://registry.npmjs.org/@antora/file-publisher/-/file-publisher-3.2.0-alpha.4.tgz",
+ "integrity": "sha512-DqH5RpdcshVhA4Xq2JQ2M7Rk3IhrOtV5ivI+oXU4yQlQW7IqchJnCmsOa885xPo8f5v2fpXRaZ5iyvRBUMaH2A==",
+ "dependencies": {
+ "@antora/expand-path-helper": "~2.0",
+ "@antora/user-require-helper": "~2.0",
+ "@vscode/gulp-vinyl-zip": "~2.5",
+ "vinyl": "~2.2",
+ "vinyl-fs": "~3.0"
+ },
+ "engines": {
+ "node": ">=16.0.0"
+ }
+ },
+ "node_modules/@antora/logger": {
+ "version": "3.2.0-alpha.4",
+ "resolved": "https://registry.npmjs.org/@antora/logger/-/logger-3.2.0-alpha.4.tgz",
+ "integrity": "sha512-ph+vIUVvZQHLA3EreBaViAB01IYzq0yjdcUSp5CVcqxU9+CnuuBKDvix6Pll7LJwgFJ8i3UX4mVVW1lI3h2tYg==",
+ "dependencies": {
+ "@antora/expand-path-helper": "~2.0",
+ "pino": "~8.14",
+ "pino-pretty": "~10.0",
+ "sonic-boom": "~3.3"
+ },
+ "engines": {
+ "node": ">=16.0.0"
+ }
+ },
+ "node_modules/@antora/navigation-builder": {
+ "version": "3.2.0-alpha.4",
+ "resolved": "https://registry.npmjs.org/@antora/navigation-builder/-/navigation-builder-3.2.0-alpha.4.tgz",
+ "integrity": "sha512-qoF57QOIi2RvmqSYuaetA2IRoHizPXIs5kUKmk/uqiMq6akWaklSI9QHPhq6VsNgLdWaUomQ+gJCvnhjQQkw5w==",
+ "dependencies": {
+ "@antora/asciidoc-loader": "3.2.0-alpha.4"
+ },
+ "engines": {
+ "node": ">=16.0.0"
+ }
+ },
+ "node_modules/@antora/page-composer": {
+ "version": "3.2.0-alpha.4",
+ "resolved": "https://registry.npmjs.org/@antora/page-composer/-/page-composer-3.2.0-alpha.4.tgz",
+ "integrity": "sha512-LAbNdUYomqx9iCT+mP1bF17U5vIoBObD0VAtjF6IMD+b5xyDN1O82rZgHhDByn8R6es0oA6DrkQMwPH+oxR7fQ==",
+ "dependencies": {
+ "@antora/logger": "3.2.0-alpha.4",
+ "handlebars": "~4.7",
+ "require-from-string": "~2.0"
+ },
+ "engines": {
+ "node": ">=16.0.0"
+ }
+ },
+ "node_modules/@antora/playbook-builder": {
+ "version": "3.2.0-alpha.4",
+ "resolved": "https://registry.npmjs.org/@antora/playbook-builder/-/playbook-builder-3.2.0-alpha.4.tgz",
+ "integrity": "sha512-79ERFWrOAaxr1iEW8qS7rMpjyYD9Lwt53Y18qIGLf0jtqgIVmmgJtaSR1qwrO/rYd2GIqWpm+s12NWzqJLZAog==",
+ "dependencies": {
+ "@iarna/toml": "~2.2",
+ "convict": "~6.2",
+ "js-yaml": "~4.1",
+ "json5": "~2.2"
+ },
+ "engines": {
+ "node": ">=16.0.0"
+ }
+ },
+ "node_modules/@antora/redirect-producer": {
+ "version": "3.2.0-alpha.4",
+ "resolved": "https://registry.npmjs.org/@antora/redirect-producer/-/redirect-producer-3.2.0-alpha.4.tgz",
+ "integrity": "sha512-BMm0l6jGdKN7r5xCP8cQmHy+owTwT0pXlsx1ZmTXZiq66Ec0H6ykKNQhx7scezbytlg18bwXUYNAtEQg/6c2AA==",
+ "dependencies": {
+ "vinyl": "~2.2"
+ },
+ "engines": {
+ "node": ">=16.0.0"
+ }
+ },
+ "node_modules/@antora/site-generator": {
+ "version": "3.2.0-alpha.4",
+ "resolved": "https://registry.npmjs.org/@antora/site-generator/-/site-generator-3.2.0-alpha.4.tgz",
+ "integrity": "sha512-QYaq9TMyPLHnUnyiO4AzRnU7igGE6Kc41j9ff8ijrGEK/YqxRmDTG74r8VdgdtotpSjcnXTQPJ46neJKExcKvg==",
+ "dependencies": {
+ "@antora/asciidoc-loader": "3.2.0-alpha.4",
+ "@antora/content-aggregator": "3.2.0-alpha.4",
+ "@antora/content-classifier": "3.2.0-alpha.4",
+ "@antora/document-converter": "3.2.0-alpha.4",
+ "@antora/file-publisher": "3.2.0-alpha.4",
+ "@antora/logger": "3.2.0-alpha.4",
+ "@antora/navigation-builder": "3.2.0-alpha.4",
+ "@antora/page-composer": "3.2.0-alpha.4",
+ "@antora/playbook-builder": "3.2.0-alpha.4",
+ "@antora/redirect-producer": "3.2.0-alpha.4",
+ "@antora/site-mapper": "3.2.0-alpha.4",
+ "@antora/site-publisher": "3.2.0-alpha.4",
+ "@antora/ui-loader": "3.2.0-alpha.4",
+ "@antora/user-require-helper": "~2.0"
+ },
+ "engines": {
+ "node": ">=16.0.0"
+ }
+ },
+ "node_modules/@antora/site-mapper": {
+ "version": "3.2.0-alpha.4",
+ "resolved": "https://registry.npmjs.org/@antora/site-mapper/-/site-mapper-3.2.0-alpha.4.tgz",
+ "integrity": "sha512-9SD2HOxqYjNQ88qg4QDVbIvSyd3aYeVAUwdA50eRvWLgnToTwDorjt/nfZnbRXGNszWil9nOZ+F8+LV2BkPpTw==",
+ "dependencies": {
+ "@antora/content-classifier": "3.2.0-alpha.4",
+ "vinyl": "~2.2"
+ },
+ "engines": {
+ "node": ">=16.0.0"
+ }
+ },
+ "node_modules/@antora/site-publisher": {
+ "version": "3.2.0-alpha.4",
+ "resolved": "https://registry.npmjs.org/@antora/site-publisher/-/site-publisher-3.2.0-alpha.4.tgz",
+ "integrity": "sha512-GiakkrGR/eTjh7o/ZISoYDUcDSXn/zodXTiX++fqHSrzscWTOcId4IC3Lj8oRDmISrh7U3la6Ydtld4xMbtSsQ==",
+ "dependencies": {
+ "@antora/file-publisher": "3.2.0-alpha.4"
+ },
+ "engines": {
+ "node": ">=16.0.0"
+ }
+ },
+ "node_modules/@antora/ui-loader": {
+ "version": "3.2.0-alpha.4",
+ "resolved": "https://registry.npmjs.org/@antora/ui-loader/-/ui-loader-3.2.0-alpha.4.tgz",
+ "integrity": "sha512-I7srOOR/tsORa+L+xIkPCVR365yQKO1JEylDkQbaMhbuPFhTmRV4mQXgUeLsfprtVXiSoaFw960SrWd77TX/dA==",
+ "dependencies": {
+ "@antora/expand-path-helper": "~2.0",
+ "@vscode/gulp-vinyl-zip": "~2.5",
+ "braces": "~3.0",
+ "cache-directory": "~2.0",
+ "glob-stream": "~7.0",
+ "hpagent": "~1.2",
+ "js-yaml": "~4.1",
+ "picomatch": "~2.3",
+ "should-proxy": "~1.0",
+ "simple-get": "~4.0",
+ "vinyl": "~2.2"
+ },
+ "engines": {
+ "node": ">=16.0.0"
+ }
+ },
+ "node_modules/@antora/user-require-helper": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/@antora/user-require-helper/-/user-require-helper-2.0.0.tgz",
+ "integrity": "sha512-5fMfBZfw4zLoFdDAPMQX6Frik90uvfD8rXOA4UpXPOUikkX4uT1Rk6m0/4oi8oS3fcjiIl0k/7Nc+eTxW5TcQQ==",
+ "dependencies": {
+ "@antora/expand-path-helper": "~2.0"
+ },
+ "engines": {
+ "node": ">=10.17.0"
+ }
+ },
+ "node_modules/@asciidoctor/core": {
+ "version": "2.2.7",
+ "resolved": "https://registry.npmjs.org/@asciidoctor/core/-/core-2.2.7.tgz",
+ "integrity": "sha512-63cfnV606vXNUnh/zcuUi5e3tY5qTzaYY5pGP4p9sRk8CcCmX4Z8OfU0BkfM8/k2Y7Cz/jZqxL+vzHjrLQa8tw==",
+ "dependencies": {
+ "asciidoctor-opal-runtime": "0.3.3",
+ "unxhr": "1.0.1"
+ },
+ "engines": {
+ "node": ">=8.11",
+ "npm": ">=5.0.0",
+ "yarn": ">=1.1.0"
+ }
+ },
+ "node_modules/@asciidoctor/tabs": {
+ "version": "1.0.0-beta.6",
+ "resolved": "https://registry.npmjs.org/@asciidoctor/tabs/-/tabs-1.0.0-beta.6.tgz",
+ "integrity": "sha512-gGZnW7UfRXnbiyKNd9PpGKtSuD8+DsqaaTSbQ1dHVkZ76NaolLhdQg8RW6/xqN3pX1vWZEcF4e81+Oe9rNRWxg==",
+ "engines": {
+ "node": ">=16.0.0"
+ }
+ },
+ "node_modules/@babel/runtime": {
+ "version": "7.24.5",
+ "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.24.5.tgz",
+ "integrity": "sha512-Nms86NXrsaeU9vbBJKni6gXiEXZ4CVpYVzEjDH9Sb8vmZ3UljyA1GSOJl/6LGPO8EHLuSF9H+IxNXHPX8QHJ4g==",
+ "dependencies": {
+ "regenerator-runtime": "^0.14.0"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@iarna/toml": {
+ "version": "2.2.5",
+ "resolved": "https://registry.npmjs.org/@iarna/toml/-/toml-2.2.5.tgz",
+ "integrity": "sha512-trnsAYxU3xnS1gPHPyU961coFyLkh4gAD/0zQ5mymY4yOZ+CYvsPqUbOFSw0aDM4y0tV7tiFxL/1XfXPNC6IPg=="
+ },
+ "node_modules/@springio/antora-extensions": {
+ "version": "1.11.1",
+ "resolved": "https://registry.npmjs.org/@springio/antora-extensions/-/antora-extensions-1.11.1.tgz",
+ "integrity": "sha512-mS5w7Nq1AGUEmOqhohRUG6qIBkYaG+ApKshqbb+e+Slg8ZnPsjrNeAJumXwLsv1CrEFJRWdxq6owXiK/21Rzyw==",
+ "dependencies": {
+ "@antora/expand-path-helper": "~2.0",
+ "archiver": "^5.3.1",
+ "asciinema-player": "^3.6.1",
+ "cache-directory": "~2.0",
+ "ci": "^2.3.0",
+ "decompress": "4.2.1",
+ "fast-xml-parser": "latest",
+ "handlebars": "latest"
+ },
+ "engines": {
+ "node": ">=16.0.0"
+ }
+ },
+ "node_modules/@springio/antora-xref-extension": {
+ "version": "1.0.0-alpha.3",
+ "resolved": "https://registry.npmjs.org/@springio/antora-xref-extension/-/antora-xref-extension-1.0.0-alpha.3.tgz",
+ "integrity": "sha512-6NJqrHrnwnfkBcQHDABxVNaCP74MBp3iCayaxTeXL90BVo93Pqo4bQhzrISSrBXpb5rXqZWb3DPuFMCXSeWolg==",
+ "engines": {
+ "node": ">=16.0.0"
+ }
+ },
+ "node_modules/@springio/antora-zip-contents-collector-extension": {
+ "version": "1.0.0-alpha.8",
+ "resolved": "https://registry.npmjs.org/@springio/antora-zip-contents-collector-extension/-/antora-zip-contents-collector-extension-1.0.0-alpha.8.tgz",
+ "integrity": "sha512-pp1hozg/UGQpkrJ17NImrcRd5b8hxIsLXHDYeBBR/vtzR7uiokxA1JxtL6PTfPAdjnrYf+2ApXdCgzLdNI7Rgg==",
+ "dependencies": {
+ "@antora/expand-path-helper": "~2.0",
+ "cache-directory": "~2.0",
+ "glob-stream": "~7.0",
+ "isomorphic-git": "~1.21",
+ "js-yaml": "~4.1"
+ },
+ "engines": {
+ "node": ">=20.0.0"
+ }
+ },
+ "node_modules/@springio/antora-zip-contents-collector-extension/node_modules/isomorphic-git": {
+ "version": "1.21.0",
+ "resolved": "https://registry.npmjs.org/isomorphic-git/-/isomorphic-git-1.21.0.tgz",
+ "integrity": "sha512-ZqCAUM63CYepA3fB8H7NVyPSiOkgzIbQ7T+QPrm9xtYgQypN9JUJ5uLMjB5iTfomdJf3mdm6aSxjZwnT6ubvEA==",
+ "dependencies": {
+ "async-lock": "^1.1.0",
+ "clean-git-ref": "^2.0.1",
+ "crc-32": "^1.2.0",
+ "diff3": "0.0.3",
+ "ignore": "^5.1.4",
+ "minimisted": "^2.0.0",
+ "pako": "^1.0.10",
+ "pify": "^4.0.1",
+ "readable-stream": "^3.4.0",
+ "sha.js": "^2.4.9",
+ "simple-get": "^4.0.1"
+ },
+ "bin": {
+ "isogit": "cli.cjs"
+ },
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@springio/antora-zip-contents-collector-extension/node_modules/pify": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz",
+ "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==",
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/@springio/asciidoctor-extensions": {
+ "version": "1.0.0-alpha.10",
+ "resolved": "https://registry.npmjs.org/@springio/asciidoctor-extensions/-/asciidoctor-extensions-1.0.0-alpha.10.tgz",
+ "integrity": "sha512-3+LYhKYsTZKlUq3M99L5W67x+wI6TGlFkD23ZcjKP6undjy3xf7xZL7Ndmslf8trQ24V+QkaCmFtF/2JQY9KwA==",
+ "dependencies": {
+ "js-yaml": "~4.1"
+ },
+ "engines": {
+ "node": ">=16.0.0"
+ }
+ },
+ "node_modules/@vscode/gulp-vinyl-zip": {
+ "version": "2.5.0",
+ "resolved": "https://registry.npmjs.org/@vscode/gulp-vinyl-zip/-/gulp-vinyl-zip-2.5.0.tgz",
+ "integrity": "sha512-PP/xkOoLBSY3V04HmzRxF+NOxkRJ/m2D0YwWpfx1FCFv5G8+sZUGPvxX+LRgdJ5vQcR1RHck5x1IkHi75Qjdbw==",
+ "dependencies": {
+ "queue": "^4.2.1",
+ "through": "^2.3.8",
+ "through2": "^2.0.3",
+ "vinyl": "^2.0.2",
+ "vinyl-fs": "^3.0.3",
+ "yauzl": "^2.2.1",
+ "yazl": "^2.2.1"
+ },
+ "engines": {
+ "node": ">= 10"
+ }
+ },
+ "node_modules/abort-controller": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz",
+ "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==",
+ "dependencies": {
+ "event-target-shim": "^5.0.0"
+ },
+ "engines": {
+ "node": ">=6.5"
+ }
+ },
+ "node_modules/append-buffer": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/append-buffer/-/append-buffer-1.0.2.tgz",
+ "integrity": "sha512-WLbYiXzD3y/ATLZFufV/rZvWdZOs+Z/+5v1rBZ463Jn398pa6kcde27cvozYnBoxXblGZTFfoPpsaEw0orU5BA==",
+ "dependencies": {
+ "buffer-equal": "^1.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/archiver": {
+ "version": "5.3.2",
+ "resolved": "https://registry.npmjs.org/archiver/-/archiver-5.3.2.tgz",
+ "integrity": "sha512-+25nxyyznAXF7Nef3y0EbBeqmGZgeN/BxHX29Rs39djAfaFalmQ89SE6CWyDCHzGL0yt/ycBtNOmGTW0FyGWNw==",
+ "dependencies": {
+ "archiver-utils": "^2.1.0",
+ "async": "^3.2.4",
+ "buffer-crc32": "^0.2.1",
+ "readable-stream": "^3.6.0",
+ "readdir-glob": "^1.1.2",
+ "tar-stream": "^2.2.0",
+ "zip-stream": "^4.1.0"
+ },
+ "engines": {
+ "node": ">= 10"
+ }
+ },
+ "node_modules/archiver-utils": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/archiver-utils/-/archiver-utils-2.1.0.tgz",
+ "integrity": "sha512-bEL/yUb/fNNiNTuUz979Z0Yg5L+LzLxGJz8x79lYmR54fmTIb6ob/hNQgkQnIUDWIFjZVQwl9Xs356I6BAMHfw==",
+ "dependencies": {
+ "glob": "^7.1.4",
+ "graceful-fs": "^4.2.0",
+ "lazystream": "^1.0.0",
+ "lodash.defaults": "^4.2.0",
+ "lodash.difference": "^4.5.0",
+ "lodash.flatten": "^4.4.0",
+ "lodash.isplainobject": "^4.0.6",
+ "lodash.union": "^4.6.0",
+ "normalize-path": "^3.0.0",
+ "readable-stream": "^2.0.0"
+ },
+ "engines": {
+ "node": ">= 6"
+ }
+ },
+ "node_modules/archiver-utils/node_modules/readable-stream": {
+ "version": "2.3.8",
+ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz",
+ "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==",
+ "dependencies": {
+ "core-util-is": "~1.0.0",
+ "inherits": "~2.0.3",
+ "isarray": "~1.0.0",
+ "process-nextick-args": "~2.0.0",
+ "safe-buffer": "~5.1.1",
+ "string_decoder": "~1.1.1",
+ "util-deprecate": "~1.0.1"
+ }
+ },
+ "node_modules/archiver-utils/node_modules/safe-buffer": {
+ "version": "5.1.2",
+ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
+ "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="
+ },
+ "node_modules/archiver-utils/node_modules/string_decoder": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
+ "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
+ "dependencies": {
+ "safe-buffer": "~5.1.0"
+ }
+ },
+ "node_modules/argparse": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
+ "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q=="
+ },
+ "node_modules/asciidoctor-opal-runtime": {
+ "version": "0.3.3",
+ "resolved": "https://registry.npmjs.org/asciidoctor-opal-runtime/-/asciidoctor-opal-runtime-0.3.3.tgz",
+ "integrity": "sha512-/CEVNiOia8E5BMO9FLooo+Kv18K4+4JBFRJp8vUy/N5dMRAg+fRNV4HA+o6aoSC79jVU/aT5XvUpxSxSsTS8FQ==",
+ "dependencies": {
+ "glob": "7.1.3",
+ "unxhr": "1.0.1"
+ },
+ "engines": {
+ "node": ">=8.11"
+ }
+ },
+ "node_modules/asciidoctor-opal-runtime/node_modules/glob": {
+ "version": "7.1.3",
+ "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz",
+ "integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==",
+ "dependencies": {
+ "fs.realpath": "^1.0.0",
+ "inflight": "^1.0.4",
+ "inherits": "2",
+ "minimatch": "^3.0.4",
+ "once": "^1.3.0",
+ "path-is-absolute": "^1.0.0"
+ },
+ "engines": {
+ "node": "*"
+ }
+ },
+ "node_modules/asciinema-player": {
+ "version": "3.7.1",
+ "resolved": "https://registry.npmjs.org/asciinema-player/-/asciinema-player-3.7.1.tgz",
+ "integrity": "sha512-zDJteGjBzNQhHEnD0aG7GqV3E53sOyKb1WCxKNRm2PquU70Lq3s4xxb91wyDS0hBJ3J/TB8aY3y8gjGPN+T23A==",
+ "dependencies": {
+ "@babel/runtime": "^7.21.0",
+ "solid-js": "^1.3.0"
+ }
+ },
+ "node_modules/async": {
+ "version": "3.2.5",
+ "resolved": "https://registry.npmjs.org/async/-/async-3.2.5.tgz",
+ "integrity": "sha512-baNZyqaaLhyLVKm/DlvdW051MSgO6b8eVfIezl9E5PqWxFgzLm/wQntEW4zOytVburDEr0JlALEpdOFwvErLsg=="
+ },
+ "node_modules/async-lock": {
+ "version": "1.4.1",
+ "resolved": "https://registry.npmjs.org/async-lock/-/async-lock-1.4.1.tgz",
+ "integrity": "sha512-Az2ZTpuytrtqENulXwO3GGv1Bztugx6TT37NIo7imr/Qo0gsYiGtSdBa2B6fsXhTpVZDNfu1Qn3pk531e3q+nQ=="
+ },
+ "node_modules/atomic-sleep": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/atomic-sleep/-/atomic-sleep-1.0.0.tgz",
+ "integrity": "sha512-kNOjDqAh7px0XWNI+4QbzoiR/nTkHAWNud2uvnJquD1/x5a7EQZMJT0AczqK0Qn67oY/TTQ1LbUKajZpp3I9tQ==",
+ "engines": {
+ "node": ">=8.0.0"
+ }
+ },
+ "node_modules/balanced-match": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
+ "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="
+ },
+ "node_modules/base64-js": {
+ "version": "1.5.1",
+ "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz",
+ "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==",
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/feross"
+ },
+ {
+ "type": "patreon",
+ "url": "https://www.patreon.com/feross"
+ },
+ {
+ "type": "consulting",
+ "url": "https://feross.org/support"
+ }
+ ]
+ },
+ "node_modules/bl": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz",
+ "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==",
+ "dependencies": {
+ "buffer": "^5.5.0",
+ "inherits": "^2.0.4",
+ "readable-stream": "^3.4.0"
+ }
+ },
+ "node_modules/brace-expansion": {
+ "version": "1.1.11",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
+ "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
+ "dependencies": {
+ "balanced-match": "^1.0.0",
+ "concat-map": "0.0.1"
+ }
+ },
+ "node_modules/braces": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz",
+ "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==",
+ "dependencies": {
+ "fill-range": "^7.1.1"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/buffer": {
+ "version": "5.7.1",
+ "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz",
+ "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==",
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/feross"
+ },
+ {
+ "type": "patreon",
+ "url": "https://www.patreon.com/feross"
+ },
+ {
+ "type": "consulting",
+ "url": "https://feross.org/support"
+ }
+ ],
+ "dependencies": {
+ "base64-js": "^1.3.1",
+ "ieee754": "^1.1.13"
+ }
+ },
+ "node_modules/buffer-alloc": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/buffer-alloc/-/buffer-alloc-1.2.0.tgz",
+ "integrity": "sha512-CFsHQgjtW1UChdXgbyJGtnm+O/uLQeZdtbDo8mfUgYXCHSM1wgrVxXm6bSyrUuErEb+4sYVGCzASBRot7zyrow==",
+ "dependencies": {
+ "buffer-alloc-unsafe": "^1.1.0",
+ "buffer-fill": "^1.0.0"
+ }
+ },
+ "node_modules/buffer-alloc-unsafe": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/buffer-alloc-unsafe/-/buffer-alloc-unsafe-1.1.0.tgz",
+ "integrity": "sha512-TEM2iMIEQdJ2yjPJoSIsldnleVaAk1oW3DBVUykyOLsEsFmEc9kn+SFFPz+gl54KQNxlDnAwCXosOS9Okx2xAg=="
+ },
+ "node_modules/buffer-crc32": {
+ "version": "0.2.13",
+ "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz",
+ "integrity": "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==",
+ "engines": {
+ "node": "*"
+ }
+ },
+ "node_modules/buffer-equal": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/buffer-equal/-/buffer-equal-1.0.1.tgz",
+ "integrity": "sha512-QoV3ptgEaQpvVwbXdSO39iqPQTCxSF7A5U99AxbHYqUdCizL/lH2Z0A2y6nbZucxMEOtNyZfG2s6gsVugGpKkg==",
+ "engines": {
+ "node": ">=0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/buffer-fill": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/buffer-fill/-/buffer-fill-1.0.0.tgz",
+ "integrity": "sha512-T7zexNBwiiaCOGDg9xNX9PBmjrubblRkENuptryuI64URkXDFum9il/JGL8Lm8wYfAXpredVXXZz7eMHilimiQ=="
+ },
+ "node_modules/cache-directory": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/cache-directory/-/cache-directory-2.0.0.tgz",
+ "integrity": "sha512-7YKEapH+2Uikde8hySyfobXBqPKULDyHNl/lhKm7cKf/GJFdG/tU/WpLrOg2y9aUrQrWUilYqawFIiGJPS6gDA==",
+ "dependencies": {
+ "xdg-basedir": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/call-bind": {
+ "version": "1.0.7",
+ "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz",
+ "integrity": "sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==",
+ "dependencies": {
+ "es-define-property": "^1.0.0",
+ "es-errors": "^1.3.0",
+ "function-bind": "^1.1.2",
+ "get-intrinsic": "^1.2.4",
+ "set-function-length": "^1.2.1"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/ci": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/ci/-/ci-2.3.0.tgz",
+ "integrity": "sha512-0MGXkzJKkwV3enG7RUxjJKdiAkbaZ7visCjitfpCN2BQjv02KGRMxCHLv4RPokkjJ4xR33FLMAXweS+aQ0pFSQ==",
+ "bin": {
+ "ci": "dist/cli.js"
+ },
+ "funding": {
+ "url": "https://github.com/privatenumber/ci?sponsor=1"
+ }
+ },
+ "node_modules/clean-git-ref": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/clean-git-ref/-/clean-git-ref-2.0.1.tgz",
+ "integrity": "sha512-bLSptAy2P0s6hU4PzuIMKmMJJSE6gLXGH1cntDu7bWJUksvuM+7ReOK61mozULErYvP6a15rnYl0zFDef+pyPw=="
+ },
+ "node_modules/clone": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/clone/-/clone-2.1.2.tgz",
+ "integrity": "sha512-3Pe/CF1Nn94hyhIYpjtiLhdCoEoz0DqQ+988E9gmeEdQZlojxnOb74wctFyuwWQHzqyf9X7C7MG8juUpqBJT8w==",
+ "engines": {
+ "node": ">=0.8"
+ }
+ },
+ "node_modules/clone-buffer": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/clone-buffer/-/clone-buffer-1.0.0.tgz",
+ "integrity": "sha512-KLLTJWrvwIP+OPfMn0x2PheDEP20RPUcGXj/ERegTgdmPEZylALQldygiqrPPu8P45uNuPs7ckmReLY6v/iA5g==",
+ "engines": {
+ "node": ">= 0.10"
+ }
+ },
+ "node_modules/clone-stats": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/clone-stats/-/clone-stats-1.0.0.tgz",
+ "integrity": "sha512-au6ydSpg6nsrigcZ4m8Bc9hxjeW+GJ8xh5G3BJCMt4WXe1H10UNaVOamqQTmrx1kjVuxAHIQSNU6hY4Nsn9/ag=="
+ },
+ "node_modules/cloneable-readable": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/cloneable-readable/-/cloneable-readable-1.1.3.tgz",
+ "integrity": "sha512-2EF8zTQOxYq70Y4XKtorQupqF0m49MBz2/yf5Bj+MHjvpG3Hy7sImifnqD6UA+TKYxeSV+u6qqQPawN5UvnpKQ==",
+ "dependencies": {
+ "inherits": "^2.0.1",
+ "process-nextick-args": "^2.0.0",
+ "readable-stream": "^2.3.5"
+ }
+ },
+ "node_modules/cloneable-readable/node_modules/readable-stream": {
+ "version": "2.3.8",
+ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz",
+ "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==",
+ "dependencies": {
+ "core-util-is": "~1.0.0",
+ "inherits": "~2.0.3",
+ "isarray": "~1.0.0",
+ "process-nextick-args": "~2.0.0",
+ "safe-buffer": "~5.1.1",
+ "string_decoder": "~1.1.1",
+ "util-deprecate": "~1.0.1"
+ }
+ },
+ "node_modules/cloneable-readable/node_modules/safe-buffer": {
+ "version": "5.1.2",
+ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
+ "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="
+ },
+ "node_modules/cloneable-readable/node_modules/string_decoder": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
+ "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
+ "dependencies": {
+ "safe-buffer": "~5.1.0"
+ }
+ },
+ "node_modules/colorette": {
+ "version": "2.0.20",
+ "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz",
+ "integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w=="
+ },
+ "node_modules/commander": {
+ "version": "10.0.1",
+ "resolved": "https://registry.npmjs.org/commander/-/commander-10.0.1.tgz",
+ "integrity": "sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==",
+ "engines": {
+ "node": ">=14"
+ }
+ },
+ "node_modules/compress-commons": {
+ "version": "4.1.2",
+ "resolved": "https://registry.npmjs.org/compress-commons/-/compress-commons-4.1.2.tgz",
+ "integrity": "sha512-D3uMHtGc/fcO1Gt1/L7i1e33VOvD4A9hfQLP+6ewd+BvG/gQ84Yh4oftEhAdjSMgBgwGL+jsppT7JYNpo6MHHg==",
+ "dependencies": {
+ "buffer-crc32": "^0.2.13",
+ "crc32-stream": "^4.0.2",
+ "normalize-path": "^3.0.0",
+ "readable-stream": "^3.6.0"
+ },
+ "engines": {
+ "node": ">= 10"
+ }
+ },
+ "node_modules/concat-map": {
+ "version": "0.0.1",
+ "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
+ "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg=="
+ },
+ "node_modules/convert-source-map": {
+ "version": "1.9.0",
+ "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz",
+ "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A=="
+ },
+ "node_modules/convict": {
+ "version": "6.2.4",
+ "resolved": "https://registry.npmjs.org/convict/-/convict-6.2.4.tgz",
+ "integrity": "sha512-qN60BAwdMVdofckX7AlohVJ2x9UvjTNoKVXCL2LxFk1l7757EJqf1nySdMkPQer0bt8kQ5lQiyZ9/2NvrFBuwQ==",
+ "dependencies": {
+ "lodash.clonedeep": "^4.5.0",
+ "yargs-parser": "^20.2.7"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/core-util-is": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz",
+ "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ=="
+ },
+ "node_modules/crc-32": {
+ "version": "1.2.2",
+ "resolved": "https://registry.npmjs.org/crc-32/-/crc-32-1.2.2.tgz",
+ "integrity": "sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ==",
+ "bin": {
+ "crc32": "bin/crc32.njs"
+ },
+ "engines": {
+ "node": ">=0.8"
+ }
+ },
+ "node_modules/crc32-stream": {
+ "version": "4.0.3",
+ "resolved": "https://registry.npmjs.org/crc32-stream/-/crc32-stream-4.0.3.tgz",
+ "integrity": "sha512-NT7w2JVU7DFroFdYkeq8cywxrgjPHWkdX1wjpRQXPX5Asews3tA+Ght6lddQO5Mkumffp3X7GEqku3epj2toIw==",
+ "dependencies": {
+ "crc-32": "^1.2.0",
+ "readable-stream": "^3.4.0"
+ },
+ "engines": {
+ "node": ">= 10"
+ }
+ },
+ "node_modules/csstype": {
+ "version": "3.1.3",
+ "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz",
+ "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw=="
+ },
+ "node_modules/dateformat": {
+ "version": "4.6.3",
+ "resolved": "https://registry.npmjs.org/dateformat/-/dateformat-4.6.3.tgz",
+ "integrity": "sha512-2P0p0pFGzHS5EMnhdxQi7aJN+iMheud0UhG4dlE1DLAlvL8JHjJJTX/CSm4JXwV0Ka5nGk3zC5mcb5bUQUxxMA==",
+ "engines": {
+ "node": "*"
+ }
+ },
+ "node_modules/decompress": {
+ "version": "4.2.1",
+ "resolved": "https://registry.npmjs.org/decompress/-/decompress-4.2.1.tgz",
+ "integrity": "sha512-e48kc2IjU+2Zw8cTb6VZcJQ3lgVbS4uuB1TfCHbiZIP/haNXm+SVyhu+87jts5/3ROpd82GSVCoNs/z8l4ZOaQ==",
+ "dependencies": {
+ "decompress-tar": "^4.0.0",
+ "decompress-tarbz2": "^4.0.0",
+ "decompress-targz": "^4.0.0",
+ "decompress-unzip": "^4.0.1",
+ "graceful-fs": "^4.1.10",
+ "make-dir": "^1.0.0",
+ "pify": "^2.3.0",
+ "strip-dirs": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/decompress-response": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz",
+ "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==",
+ "dependencies": {
+ "mimic-response": "^3.1.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/decompress-tar": {
+ "version": "4.1.1",
+ "resolved": "https://registry.npmjs.org/decompress-tar/-/decompress-tar-4.1.1.tgz",
+ "integrity": "sha512-JdJMaCrGpB5fESVyxwpCx4Jdj2AagLmv3y58Qy4GE6HMVjWz1FeVQk1Ct4Kye7PftcdOo/7U7UKzYBJgqnGeUQ==",
+ "dependencies": {
+ "file-type": "^5.2.0",
+ "is-stream": "^1.1.0",
+ "tar-stream": "^1.5.2"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/decompress-tar/node_modules/bl": {
+ "version": "1.2.3",
+ "resolved": "https://registry.npmjs.org/bl/-/bl-1.2.3.tgz",
+ "integrity": "sha512-pvcNpa0UU69UT341rO6AYy4FVAIkUHuZXRIWbq+zHnsVcRzDDjIAhGuuYoi0d//cwIwtt4pkpKycWEfjdV+vww==",
+ "dependencies": {
+ "readable-stream": "^2.3.5",
+ "safe-buffer": "^5.1.1"
+ }
+ },
+ "node_modules/decompress-tar/node_modules/readable-stream": {
+ "version": "2.3.8",
+ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz",
+ "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==",
+ "dependencies": {
+ "core-util-is": "~1.0.0",
+ "inherits": "~2.0.3",
+ "isarray": "~1.0.0",
+ "process-nextick-args": "~2.0.0",
+ "safe-buffer": "~5.1.1",
+ "string_decoder": "~1.1.1",
+ "util-deprecate": "~1.0.1"
+ }
+ },
+ "node_modules/decompress-tar/node_modules/safe-buffer": {
+ "version": "5.1.2",
+ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
+ "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="
+ },
+ "node_modules/decompress-tar/node_modules/string_decoder": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
+ "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
+ "dependencies": {
+ "safe-buffer": "~5.1.0"
+ }
+ },
+ "node_modules/decompress-tar/node_modules/tar-stream": {
+ "version": "1.6.2",
+ "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-1.6.2.tgz",
+ "integrity": "sha512-rzS0heiNf8Xn7/mpdSVVSMAWAoy9bfb1WOTYC78Z0UQKeKa/CWS8FOq0lKGNa8DWKAn9gxjCvMLYc5PGXYlK2A==",
+ "dependencies": {
+ "bl": "^1.0.0",
+ "buffer-alloc": "^1.2.0",
+ "end-of-stream": "^1.0.0",
+ "fs-constants": "^1.0.0",
+ "readable-stream": "^2.3.0",
+ "to-buffer": "^1.1.1",
+ "xtend": "^4.0.0"
+ },
+ "engines": {
+ "node": ">= 0.8.0"
+ }
+ },
+ "node_modules/decompress-tarbz2": {
+ "version": "4.1.1",
+ "resolved": "https://registry.npmjs.org/decompress-tarbz2/-/decompress-tarbz2-4.1.1.tgz",
+ "integrity": "sha512-s88xLzf1r81ICXLAVQVzaN6ZmX4A6U4z2nMbOwobxkLoIIfjVMBg7TeguTUXkKeXni795B6y5rnvDw7rxhAq9A==",
+ "dependencies": {
+ "decompress-tar": "^4.1.0",
+ "file-type": "^6.1.0",
+ "is-stream": "^1.1.0",
+ "seek-bzip": "^1.0.5",
+ "unbzip2-stream": "^1.0.9"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/decompress-tarbz2/node_modules/file-type": {
+ "version": "6.2.0",
+ "resolved": "https://registry.npmjs.org/file-type/-/file-type-6.2.0.tgz",
+ "integrity": "sha512-YPcTBDV+2Tm0VqjybVd32MHdlEGAtuxS3VAYsumFokDSMG+ROT5wawGlnHDoz7bfMcMDt9hxuXvXwoKUx2fkOg==",
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/decompress-targz": {
+ "version": "4.1.1",
+ "resolved": "https://registry.npmjs.org/decompress-targz/-/decompress-targz-4.1.1.tgz",
+ "integrity": "sha512-4z81Znfr6chWnRDNfFNqLwPvm4db3WuZkqV+UgXQzSngG3CEKdBkw5jrv3axjjL96glyiiKjsxJG3X6WBZwX3w==",
+ "dependencies": {
+ "decompress-tar": "^4.1.1",
+ "file-type": "^5.2.0",
+ "is-stream": "^1.1.0"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/decompress-unzip": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/decompress-unzip/-/decompress-unzip-4.0.1.tgz",
+ "integrity": "sha512-1fqeluvxgnn86MOh66u8FjbtJpAFv5wgCT9Iw8rcBqQcCo5tO8eiJw7NNTrvt9n4CRBVq7CstiS922oPgyGLrw==",
+ "dependencies": {
+ "file-type": "^3.8.0",
+ "get-stream": "^2.2.0",
+ "pify": "^2.3.0",
+ "yauzl": "^2.4.2"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/decompress-unzip/node_modules/file-type": {
+ "version": "3.9.0",
+ "resolved": "https://registry.npmjs.org/file-type/-/file-type-3.9.0.tgz",
+ "integrity": "sha512-RLoqTXE8/vPmMuTI88DAzhMYC99I8BWv7zYP4A1puo5HIjEJ5EX48ighy4ZyKMG9EDXxBgW6e++cn7d1xuFghA==",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/define-data-property": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz",
+ "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==",
+ "dependencies": {
+ "es-define-property": "^1.0.0",
+ "es-errors": "^1.3.0",
+ "gopd": "^1.0.1"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/define-properties": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz",
+ "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==",
+ "dependencies": {
+ "define-data-property": "^1.0.1",
+ "has-property-descriptors": "^1.0.0",
+ "object-keys": "^1.1.1"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/diff3": {
+ "version": "0.0.3",
+ "resolved": "https://registry.npmjs.org/diff3/-/diff3-0.0.3.tgz",
+ "integrity": "sha512-iSq8ngPOt0K53A6eVr4d5Kn6GNrM2nQZtC740pzIriHtn4pOQ2lyzEXQMBeVcWERN0ye7fhBsk9PbLLQOnUx/g=="
+ },
+ "node_modules/duplexify": {
+ "version": "4.1.3",
+ "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-4.1.3.tgz",
+ "integrity": "sha512-M3BmBhwJRZsSx38lZyhE53Csddgzl5R7xGJNk7CVddZD6CcmwMCH8J+7AprIrQKH7TonKxaCjcv27Qmf+sQ+oA==",
+ "dependencies": {
+ "end-of-stream": "^1.4.1",
+ "inherits": "^2.0.3",
+ "readable-stream": "^3.1.1",
+ "stream-shift": "^1.0.2"
+ }
+ },
+ "node_modules/end-of-stream": {
+ "version": "1.4.4",
+ "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz",
+ "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==",
+ "dependencies": {
+ "once": "^1.4.0"
+ }
+ },
+ "node_modules/es-define-property": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz",
+ "integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==",
+ "dependencies": {
+ "get-intrinsic": "^1.2.4"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/es-errors": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz",
+ "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==",
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/event-target-shim": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz",
+ "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==",
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/events": {
+ "version": "3.3.0",
+ "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz",
+ "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==",
+ "engines": {
+ "node": ">=0.8.x"
+ }
+ },
+ "node_modules/extend": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz",
+ "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g=="
+ },
+ "node_modules/fast-copy": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/fast-copy/-/fast-copy-3.0.2.tgz",
+ "integrity": "sha512-dl0O9Vhju8IrcLndv2eU4ldt1ftXMqqfgN4H1cpmGV7P6jeB9FwpN9a2c8DPGE1Ys88rNUJVYDHq73CGAGOPfQ=="
+ },
+ "node_modules/fast-redact": {
+ "version": "3.5.0",
+ "resolved": "https://registry.npmjs.org/fast-redact/-/fast-redact-3.5.0.tgz",
+ "integrity": "sha512-dwsoQlS7h9hMeYUq1W++23NDcBLV4KqONnITDV9DjfS3q1SgDGVrBdvvTLUotWtPSD7asWDV9/CmsZPy8Hf70A==",
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/fast-safe-stringify": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.1.1.tgz",
+ "integrity": "sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA=="
+ },
+ "node_modules/fast-xml-parser": {
+ "version": "4.4.0",
+ "resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-4.4.0.tgz",
+ "integrity": "sha512-kLY3jFlwIYwBNDojclKsNAC12sfD6NwW74QB2CoNGPvtVxjliYehVunB3HYyNi+n4Tt1dAcgwYvmKF/Z18flqg==",
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/NaturalIntelligence"
+ },
+ {
+ "type": "paypal",
+ "url": "https://paypal.me/naturalintelligence"
+ }
+ ],
+ "dependencies": {
+ "strnum": "^1.0.5"
+ },
+ "bin": {
+ "fxparser": "src/cli/cli.js"
+ }
+ },
+ "node_modules/fd-slicer": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz",
+ "integrity": "sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==",
+ "dependencies": {
+ "pend": "~1.2.0"
+ }
+ },
+ "node_modules/file-type": {
+ "version": "5.2.0",
+ "resolved": "https://registry.npmjs.org/file-type/-/file-type-5.2.0.tgz",
+ "integrity": "sha512-Iq1nJ6D2+yIO4c8HHg4fyVb8mAJieo1Oloy1mLLaB2PvezNedhBVm+QU7g0qM42aiMbRXTxKKwGD17rjKNJYVQ==",
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/fill-range": {
+ "version": "7.1.1",
+ "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz",
+ "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==",
+ "dependencies": {
+ "to-regex-range": "^5.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/flush-write-stream": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/flush-write-stream/-/flush-write-stream-1.1.1.tgz",
+ "integrity": "sha512-3Z4XhFZ3992uIq0XOqb9AreonueSYphE6oYbpt5+3u06JWklbsPkNv3ZKkP9Bz/r+1MWCaMoSQ28P85+1Yc77w==",
+ "dependencies": {
+ "inherits": "^2.0.3",
+ "readable-stream": "^2.3.6"
+ }
+ },
+ "node_modules/flush-write-stream/node_modules/readable-stream": {
+ "version": "2.3.8",
+ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz",
+ "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==",
+ "dependencies": {
+ "core-util-is": "~1.0.0",
+ "inherits": "~2.0.3",
+ "isarray": "~1.0.0",
+ "process-nextick-args": "~2.0.0",
+ "safe-buffer": "~5.1.1",
+ "string_decoder": "~1.1.1",
+ "util-deprecate": "~1.0.1"
+ }
+ },
+ "node_modules/flush-write-stream/node_modules/safe-buffer": {
+ "version": "5.1.2",
+ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
+ "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="
+ },
+ "node_modules/flush-write-stream/node_modules/string_decoder": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
+ "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
+ "dependencies": {
+ "safe-buffer": "~5.1.0"
+ }
+ },
+ "node_modules/fs-constants": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz",
+ "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow=="
+ },
+ "node_modules/fs-mkdirp-stream": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/fs-mkdirp-stream/-/fs-mkdirp-stream-1.0.0.tgz",
+ "integrity": "sha512-+vSd9frUnapVC2RZYfL3FCB2p3g4TBhaUmrsWlSudsGdnxIuUvBB2QM1VZeBtc49QFwrp+wQLrDs3+xxDgI5gQ==",
+ "dependencies": {
+ "graceful-fs": "^4.1.11",
+ "through2": "^2.0.3"
+ },
+ "engines": {
+ "node": ">= 0.10"
+ }
+ },
+ "node_modules/fs.realpath": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
+ "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw=="
+ },
+ "node_modules/function-bind": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
+ "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==",
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/get-intrinsic": {
+ "version": "1.2.4",
+ "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz",
+ "integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==",
+ "dependencies": {
+ "es-errors": "^1.3.0",
+ "function-bind": "^1.1.2",
+ "has-proto": "^1.0.1",
+ "has-symbols": "^1.0.3",
+ "hasown": "^2.0.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/get-stream": {
+ "version": "2.3.1",
+ "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-2.3.1.tgz",
+ "integrity": "sha512-AUGhbbemXxrZJRD5cDvKtQxLuYaIbNtDTK8YqupCI393Q2KSTreEsLUN3ZxAWFGiKTzL6nKuzfcIvieflUX9qA==",
+ "dependencies": {
+ "object-assign": "^4.0.1",
+ "pinkie-promise": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/glob": {
+ "version": "7.2.3",
+ "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz",
+ "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==",
+ "dependencies": {
+ "fs.realpath": "^1.0.0",
+ "inflight": "^1.0.4",
+ "inherits": "2",
+ "minimatch": "^3.1.1",
+ "once": "^1.3.0",
+ "path-is-absolute": "^1.0.0"
+ },
+ "engines": {
+ "node": "*"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
+ }
+ },
+ "node_modules/glob-parent": {
+ "version": "6.0.2",
+ "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz",
+ "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==",
+ "dependencies": {
+ "is-glob": "^4.0.3"
+ },
+ "engines": {
+ "node": ">=10.13.0"
+ }
+ },
+ "node_modules/glob-stream": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/glob-stream/-/glob-stream-7.0.0.tgz",
+ "integrity": "sha512-evR4kvr6s0Yo5t4CD4H171n4T8XcnPFznvsbeN8K9FPzc0Q0wYqcOWyGtck2qcvJSLXKnU6DnDyfmbDDabYvRQ==",
+ "dependencies": {
+ "extend": "^3.0.2",
+ "glob": "^7.2.0",
+ "glob-parent": "^6.0.2",
+ "is-negated-glob": "^1.0.0",
+ "ordered-read-streams": "^1.0.1",
+ "pumpify": "^2.0.1",
+ "readable-stream": "^3.6.0",
+ "remove-trailing-separator": "^1.1.0",
+ "to-absolute-glob": "^2.0.2",
+ "unique-stream": "^2.3.1"
+ },
+ "engines": {
+ "node": ">=10.13.0"
+ }
+ },
+ "node_modules/gopd": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz",
+ "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==",
+ "dependencies": {
+ "get-intrinsic": "^1.1.3"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/graceful-fs": {
+ "version": "4.2.11",
+ "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz",
+ "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ=="
+ },
+ "node_modules/handlebars": {
+ "version": "4.7.8",
+ "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.8.tgz",
+ "integrity": "sha512-vafaFqs8MZkRrSX7sFVUdo3ap/eNiLnb4IakshzvP56X5Nr1iGKAIqdX6tMlm6HcNRIkr6AxO5jFEoJzzpT8aQ==",
+ "dependencies": {
+ "minimist": "^1.2.5",
+ "neo-async": "^2.6.2",
+ "source-map": "^0.6.1",
+ "wordwrap": "^1.0.0"
+ },
+ "bin": {
+ "handlebars": "bin/handlebars"
+ },
+ "engines": {
+ "node": ">=0.4.7"
+ },
+ "optionalDependencies": {
+ "uglify-js": "^3.1.4"
+ }
+ },
+ "node_modules/has-property-descriptors": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz",
+ "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==",
+ "dependencies": {
+ "es-define-property": "^1.0.0"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/has-proto": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.3.tgz",
+ "integrity": "sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==",
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/has-symbols": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz",
+ "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==",
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/hasown": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz",
+ "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==",
+ "dependencies": {
+ "function-bind": "^1.1.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/help-me": {
+ "version": "4.2.0",
+ "resolved": "https://registry.npmjs.org/help-me/-/help-me-4.2.0.tgz",
+ "integrity": "sha512-TAOnTB8Tz5Dw8penUuzHVrKNKlCIbwwbHnXraNJxPwf8LRtE2HlM84RYuezMFcwOJmoYOCWVDyJ8TQGxn9PgxA==",
+ "dependencies": {
+ "glob": "^8.0.0",
+ "readable-stream": "^3.6.0"
+ }
+ },
+ "node_modules/help-me/node_modules/brace-expansion": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
+ "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==",
+ "dependencies": {
+ "balanced-match": "^1.0.0"
+ }
+ },
+ "node_modules/help-me/node_modules/glob": {
+ "version": "8.1.0",
+ "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz",
+ "integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==",
+ "dependencies": {
+ "fs.realpath": "^1.0.0",
+ "inflight": "^1.0.4",
+ "inherits": "2",
+ "minimatch": "^5.0.1",
+ "once": "^1.3.0"
+ },
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
+ }
+ },
+ "node_modules/help-me/node_modules/minimatch": {
+ "version": "5.1.6",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz",
+ "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==",
+ "dependencies": {
+ "brace-expansion": "^2.0.1"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/hpagent": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/hpagent/-/hpagent-1.2.0.tgz",
+ "integrity": "sha512-A91dYTeIB6NoXG+PxTQpCCDDnfHsW9kc06Lvpu1TEe9gnd6ZFeiBoRO9JvzEv6xK7EX97/dUE8g/vBMTqTS3CA==",
+ "engines": {
+ "node": ">=14"
+ }
+ },
+ "node_modules/ieee754": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz",
+ "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==",
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/feross"
+ },
+ {
+ "type": "patreon",
+ "url": "https://www.patreon.com/feross"
+ },
+ {
+ "type": "consulting",
+ "url": "https://feross.org/support"
+ }
+ ]
+ },
+ "node_modules/ignore": {
+ "version": "5.3.1",
+ "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.1.tgz",
+ "integrity": "sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw==",
+ "engines": {
+ "node": ">= 4"
+ }
+ },
+ "node_modules/inflight": {
+ "version": "1.0.6",
+ "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
+ "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==",
+ "dependencies": {
+ "once": "^1.3.0",
+ "wrappy": "1"
+ }
+ },
+ "node_modules/inherits": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
+ "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
+ },
+ "node_modules/is-absolute": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-absolute/-/is-absolute-1.0.0.tgz",
+ "integrity": "sha512-dOWoqflvcydARa360Gvv18DZ/gRuHKi2NU/wU5X1ZFzdYfH29nkiNZsF3mp4OJ3H4yo9Mx8A/uAGNzpzPN3yBA==",
+ "dependencies": {
+ "is-relative": "^1.0.0",
+ "is-windows": "^1.0.1"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/is-buffer": {
+ "version": "1.1.6",
+ "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz",
+ "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w=="
+ },
+ "node_modules/is-extglob": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
+ "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/is-glob": {
+ "version": "4.0.3",
+ "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz",
+ "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==",
+ "dependencies": {
+ "is-extglob": "^2.1.1"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/is-natural-number": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/is-natural-number/-/is-natural-number-4.0.1.tgz",
+ "integrity": "sha512-Y4LTamMe0DDQIIAlaer9eKebAlDSV6huy+TWhJVPlzZh2o4tRP5SQWFlLn5N0To4mDD22/qdOq+veo1cSISLgQ=="
+ },
+ "node_modules/is-negated-glob": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-negated-glob/-/is-negated-glob-1.0.0.tgz",
+ "integrity": "sha512-czXVVn/QEmgvej1f50BZ648vUI+em0xqMq2Sn+QncCLN4zj1UAxlT+kw/6ggQTOaZPd1HqKQGEqbpQVtJucWug==",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/is-number": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
+ "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
+ "engines": {
+ "node": ">=0.12.0"
+ }
+ },
+ "node_modules/is-relative": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-relative/-/is-relative-1.0.0.tgz",
+ "integrity": "sha512-Kw/ReK0iqwKeu0MITLFuj0jbPAmEiOsIwyIXvvbfa6QfmN9pkD1M+8pdk7Rl/dTKbH34/XBFMbgD4iMJhLQbGA==",
+ "dependencies": {
+ "is-unc-path": "^1.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/is-stream": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz",
+ "integrity": "sha512-uQPm8kcs47jx38atAcWTVxyltQYoPT68y9aWYdV6yWXSyW8mzSat0TL6CiWdZeCdF3KrAvpVtnHbTv4RN+rqdQ==",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/is-unc-path": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-unc-path/-/is-unc-path-1.0.0.tgz",
+ "integrity": "sha512-mrGpVd0fs7WWLfVsStvgF6iEJnbjDFZh9/emhRDcGWTduTfNHd9CHeUwH3gYIjdbwo4On6hunkztwOaAw0yllQ==",
+ "dependencies": {
+ "unc-path-regex": "^0.1.2"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/is-utf8": {
+ "version": "0.2.1",
+ "resolved": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz",
+ "integrity": "sha512-rMYPYvCzsXywIsldgLaSoPlw5PfoB/ssr7hY4pLfcodrA5M/eArza1a9VmTiNIBNMjOGr1Ow9mTyU2o69U6U9Q=="
+ },
+ "node_modules/is-valid-glob": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-valid-glob/-/is-valid-glob-1.0.0.tgz",
+ "integrity": "sha512-AhiROmoEFDSsjx8hW+5sGwgKVIORcXnrlAx/R0ZSeaPw70Vw0CqkGBBhHGL58Uox2eXnU1AnvXJl1XlyedO5bA==",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/is-windows": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz",
+ "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/isarray": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
+ "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ=="
+ },
+ "node_modules/isomorphic-git": {
+ "version": "1.25.10",
+ "resolved": "https://registry.npmjs.org/isomorphic-git/-/isomorphic-git-1.25.10.tgz",
+ "integrity": "sha512-IxGiaKBwAdcgBXwIcxJU6rHLk+NrzYaaPKXXQffcA0GW3IUrQXdUPDXDo+hkGVcYruuz/7JlGBiuaeTCgIgivQ==",
+ "dependencies": {
+ "async-lock": "^1.4.1",
+ "clean-git-ref": "^2.0.1",
+ "crc-32": "^1.2.0",
+ "diff3": "0.0.3",
+ "ignore": "^5.1.4",
+ "minimisted": "^2.0.0",
+ "pako": "^1.0.10",
+ "pify": "^4.0.1",
+ "readable-stream": "^3.4.0",
+ "sha.js": "^2.4.9",
+ "simple-get": "^4.0.1"
+ },
+ "bin": {
+ "isogit": "cli.cjs"
+ },
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/isomorphic-git/node_modules/pify": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz",
+ "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==",
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/joycon": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/joycon/-/joycon-3.1.1.tgz",
+ "integrity": "sha512-34wB/Y7MW7bzjKRjUKTa46I2Z7eV62Rkhva+KkopW7Qvv/OSWBqvkSY7vusOPrNuZcUG3tApvdVgNB8POj3SPw==",
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/js-yaml": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz",
+ "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==",
+ "dependencies": {
+ "argparse": "^2.0.1"
+ },
+ "bin": {
+ "js-yaml": "bin/js-yaml.js"
+ }
+ },
+ "node_modules/json-stable-stringify-without-jsonify": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz",
+ "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw=="
+ },
+ "node_modules/json5": {
+ "version": "2.2.3",
+ "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz",
+ "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==",
+ "bin": {
+ "json5": "lib/cli.js"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/lazystream": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/lazystream/-/lazystream-1.0.1.tgz",
+ "integrity": "sha512-b94GiNHQNy6JNTrt5w6zNyffMrNkXZb3KTkCZJb2V1xaEGCk093vkZ2jk3tpaeP33/OiXC+WvK9AxUebnf5nbw==",
+ "dependencies": {
+ "readable-stream": "^2.0.5"
+ },
+ "engines": {
+ "node": ">= 0.6.3"
+ }
+ },
+ "node_modules/lazystream/node_modules/readable-stream": {
+ "version": "2.3.8",
+ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz",
+ "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==",
+ "dependencies": {
+ "core-util-is": "~1.0.0",
+ "inherits": "~2.0.3",
+ "isarray": "~1.0.0",
+ "process-nextick-args": "~2.0.0",
+ "safe-buffer": "~5.1.1",
+ "string_decoder": "~1.1.1",
+ "util-deprecate": "~1.0.1"
+ }
+ },
+ "node_modules/lazystream/node_modules/safe-buffer": {
+ "version": "5.1.2",
+ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
+ "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="
+ },
+ "node_modules/lazystream/node_modules/string_decoder": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
+ "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
+ "dependencies": {
+ "safe-buffer": "~5.1.0"
+ }
+ },
+ "node_modules/lead": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/lead/-/lead-1.0.0.tgz",
+ "integrity": "sha512-IpSVCk9AYvLHo5ctcIXxOBpMWUe+4TKN3VPWAKUbJikkmsGp0VrSM8IttVc32D6J4WUsiPE6aEFRNmIoF/gdow==",
+ "dependencies": {
+ "flush-write-stream": "^1.0.2"
+ },
+ "engines": {
+ "node": ">= 0.10"
+ }
+ },
+ "node_modules/lodash.clonedeep": {
+ "version": "4.5.0",
+ "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz",
+ "integrity": "sha512-H5ZhCF25riFd9uB5UCkVKo61m3S/xZk1x4wA6yp/L3RFP6Z/eHH1ymQcGLo7J3GMPfm0V/7m1tryHuGVxpqEBQ=="
+ },
+ "node_modules/lodash.defaults": {
+ "version": "4.2.0",
+ "resolved": "https://registry.npmjs.org/lodash.defaults/-/lodash.defaults-4.2.0.tgz",
+ "integrity": "sha512-qjxPLHd3r5DnsdGacqOMU6pb/avJzdh9tFX2ymgoZE27BmjXrNy/y4LoaiTeAb+O3gL8AfpJGtqfX/ae2leYYQ=="
+ },
+ "node_modules/lodash.difference": {
+ "version": "4.5.0",
+ "resolved": "https://registry.npmjs.org/lodash.difference/-/lodash.difference-4.5.0.tgz",
+ "integrity": "sha512-dS2j+W26TQ7taQBGN8Lbbq04ssV3emRw4NY58WErlTO29pIqS0HmoT5aJ9+TUQ1N3G+JOZSji4eugsWwGp9yPA=="
+ },
+ "node_modules/lodash.flatten": {
+ "version": "4.4.0",
+ "resolved": "https://registry.npmjs.org/lodash.flatten/-/lodash.flatten-4.4.0.tgz",
+ "integrity": "sha512-C5N2Z3DgnnKr0LOpv/hKCgKdb7ZZwafIrsesve6lmzvZIRZRGaZ/l6Q8+2W7NaT+ZwO3fFlSCzCzrDCFdJfZ4g=="
+ },
+ "node_modules/lodash.isplainobject": {
+ "version": "4.0.6",
+ "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz",
+ "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA=="
+ },
+ "node_modules/lodash.union": {
+ "version": "4.6.0",
+ "resolved": "https://registry.npmjs.org/lodash.union/-/lodash.union-4.6.0.tgz",
+ "integrity": "sha512-c4pB2CdGrGdjMKYLA+XiRDO7Y0PRQbm/Gzg8qMj+QH+pFVAoTp5sBpO0odL3FjoPCGjK96p6qsP+yQoiLoOBcw=="
+ },
+ "node_modules/make-dir": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-1.3.0.tgz",
+ "integrity": "sha512-2w31R7SJtieJJnQtGc7RVL2StM2vGYVfqUOvUDxH6bC6aJTxPxTF0GnIgCyu7tjockiUWAYQRbxa7vKn34s5sQ==",
+ "dependencies": {
+ "pify": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/make-dir/node_modules/pify": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz",
+ "integrity": "sha512-C3FsVNH1udSEX48gGX1xfvwTWfsYWj5U+8/uK15BGzIGrKoUpghX8hWZwa/OFnakBiiVNmBvemTJR5mcy7iPcg==",
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/mime-db": {
+ "version": "1.52.0",
+ "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
+ "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/mime-types": {
+ "version": "2.1.35",
+ "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
+ "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
+ "dependencies": {
+ "mime-db": "1.52.0"
+ },
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/mimic-response": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz",
+ "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==",
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/minimatch": {
+ "version": "3.1.2",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
+ "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
+ "dependencies": {
+ "brace-expansion": "^1.1.7"
+ },
+ "engines": {
+ "node": "*"
+ }
+ },
+ "node_modules/minimist": {
+ "version": "1.2.8",
+ "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz",
+ "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==",
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/minimisted": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/minimisted/-/minimisted-2.0.1.tgz",
+ "integrity": "sha512-1oPjfuLQa2caorJUM8HV8lGgWCc0qqAO1MNv/k05G4qslmsndV/5WdNZrqCiyqiz3wohia2Ij2B7w2Dr7/IyrA==",
+ "dependencies": {
+ "minimist": "^1.2.5"
+ }
+ },
+ "node_modules/multi-progress": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/multi-progress/-/multi-progress-4.0.0.tgz",
+ "integrity": "sha512-9zcjyOou3FFCKPXsmkbC3ethv51SFPoA4dJD6TscIp2pUmy26kBDZW6h9XofPELrzseSkuD7r0V+emGEeo39Pg==",
+ "peerDependencies": {
+ "progress": "^2.0.0"
+ }
+ },
+ "node_modules/neo-async": {
+ "version": "2.6.2",
+ "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz",
+ "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw=="
+ },
+ "node_modules/node-gzip": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/node-gzip/-/node-gzip-1.1.2.tgz",
+ "integrity": "sha512-ZB6zWpfZHGtxZnPMrJSKHVPrRjURoUzaDbLFj3VO70mpLTW5np96vXyHwft4Id0o+PYIzgDkBUjIzaNHhQ8srw=="
+ },
+ "node_modules/normalize-path": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
+ "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/now-and-later": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/now-and-later/-/now-and-later-2.0.1.tgz",
+ "integrity": "sha512-KGvQ0cB70AQfg107Xvs/Fbu+dGmZoTRJp2TaPwcwQm3/7PteUyN2BCgk8KBMPGBUXZdVwyWS8fDCGFygBm19UQ==",
+ "dependencies": {
+ "once": "^1.3.2"
+ },
+ "engines": {
+ "node": ">= 0.10"
+ }
+ },
+ "node_modules/object-assign": {
+ "version": "4.1.1",
+ "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
+ "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/object-keys": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz",
+ "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==",
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/object.assign": {
+ "version": "4.1.5",
+ "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.5.tgz",
+ "integrity": "sha512-byy+U7gp+FVwmyzKPYhW2h5l3crpmGsxl7X2s8y43IgxvG4g3QZ6CffDtsNQy1WsmZpQbO+ybo0AlW7TY6DcBQ==",
+ "dependencies": {
+ "call-bind": "^1.0.5",
+ "define-properties": "^1.2.1",
+ "has-symbols": "^1.0.3",
+ "object-keys": "^1.1.1"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/on-exit-leak-free": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/on-exit-leak-free/-/on-exit-leak-free-2.1.2.tgz",
+ "integrity": "sha512-0eJJY6hXLGf1udHwfNftBqH+g73EU4B504nZeKpz1sYRKafAghwxEJunB2O7rDZkL4PGfsMVnTXZ2EjibbqcsA==",
+ "engines": {
+ "node": ">=14.0.0"
+ }
+ },
+ "node_modules/once": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
+ "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==",
+ "dependencies": {
+ "wrappy": "1"
+ }
+ },
+ "node_modules/ordered-read-streams": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/ordered-read-streams/-/ordered-read-streams-1.0.1.tgz",
+ "integrity": "sha512-Z87aSjx3r5c0ZB7bcJqIgIRX5bxR7A4aSzvIbaxd0oTkWBCOoKfuGHiKj60CHVUgg1Phm5yMZzBdt8XqRs73Mw==",
+ "dependencies": {
+ "readable-stream": "^2.0.1"
+ }
+ },
+ "node_modules/ordered-read-streams/node_modules/readable-stream": {
+ "version": "2.3.8",
+ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz",
+ "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==",
+ "dependencies": {
+ "core-util-is": "~1.0.0",
+ "inherits": "~2.0.3",
+ "isarray": "~1.0.0",
+ "process-nextick-args": "~2.0.0",
+ "safe-buffer": "~5.1.1",
+ "string_decoder": "~1.1.1",
+ "util-deprecate": "~1.0.1"
+ }
+ },
+ "node_modules/ordered-read-streams/node_modules/safe-buffer": {
+ "version": "5.1.2",
+ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
+ "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="
+ },
+ "node_modules/ordered-read-streams/node_modules/string_decoder": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
+ "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
+ "dependencies": {
+ "safe-buffer": "~5.1.0"
+ }
+ },
+ "node_modules/pako": {
+ "version": "1.0.11",
+ "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz",
+ "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw=="
+ },
+ "node_modules/path-dirname": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/path-dirname/-/path-dirname-1.0.2.tgz",
+ "integrity": "sha512-ALzNPpyNq9AqXMBjeymIjFDAkAFH06mHJH/cSBHAgU0s4vfpBn6b2nf8tiRLvagKD8RbTpq2FKTBg7cl9l3c7Q=="
+ },
+ "node_modules/path-is-absolute": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
+ "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/pend": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz",
+ "integrity": "sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg=="
+ },
+ "node_modules/picomatch": {
+ "version": "2.3.1",
+ "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
+ "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
+ "engines": {
+ "node": ">=8.6"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/jonschlinkert"
+ }
+ },
+ "node_modules/pify": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz",
+ "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/pinkie": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz",
+ "integrity": "sha512-MnUuEycAemtSaeFSjXKW/aroV7akBbY+Sv+RkyqFjgAe73F+MR0TBWKBRDkmfWq/HiFmdavfZ1G7h4SPZXaCSg==",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/pinkie-promise": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz",
+ "integrity": "sha512-0Gni6D4UcLTbv9c57DfxDGdr41XfgUjqWZu492f0cIGr16zDU06BWP/RAEvOuo7CQ0CNjHaLlM59YJJFm3NWlw==",
+ "dependencies": {
+ "pinkie": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/pino": {
+ "version": "8.14.2",
+ "resolved": "https://registry.npmjs.org/pino/-/pino-8.14.2.tgz",
+ "integrity": "sha512-zKu9aWeSWTy1JgvxIpZveJKKsAr4+6uNMZ0Vf0KRwzl/UNZA3XjHiIl/0WwqLMkDwuHuDkT5xAgPA2jpKq4whA==",
+ "dependencies": {
+ "atomic-sleep": "^1.0.0",
+ "fast-redact": "^3.1.1",
+ "on-exit-leak-free": "^2.1.0",
+ "pino-abstract-transport": "v1.0.0",
+ "pino-std-serializers": "^6.0.0",
+ "process-warning": "^2.0.0",
+ "quick-format-unescaped": "^4.0.3",
+ "real-require": "^0.2.0",
+ "safe-stable-stringify": "^2.3.1",
+ "sonic-boom": "^3.1.0",
+ "thread-stream": "^2.0.0"
+ },
+ "bin": {
+ "pino": "bin.js"
+ }
+ },
+ "node_modules/pino-abstract-transport": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/pino-abstract-transport/-/pino-abstract-transport-1.0.0.tgz",
+ "integrity": "sha512-c7vo5OpW4wIS42hUVcT5REsL8ZljsUfBjqV/e2sFxmFEFZiq1XLUp5EYLtuDH6PEHq9W1egWqRbnLUP5FuZmOA==",
+ "dependencies": {
+ "readable-stream": "^4.0.0",
+ "split2": "^4.0.0"
+ }
+ },
+ "node_modules/pino-abstract-transport/node_modules/buffer": {
+ "version": "6.0.3",
+ "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz",
+ "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==",
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/feross"
+ },
+ {
+ "type": "patreon",
+ "url": "https://www.patreon.com/feross"
+ },
+ {
+ "type": "consulting",
+ "url": "https://feross.org/support"
+ }
+ ],
+ "dependencies": {
+ "base64-js": "^1.3.1",
+ "ieee754": "^1.2.1"
+ }
+ },
+ "node_modules/pino-abstract-transport/node_modules/readable-stream": {
+ "version": "4.5.2",
+ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-4.5.2.tgz",
+ "integrity": "sha512-yjavECdqeZ3GLXNgRXgeQEdz9fvDDkNKyHnbHRFtOr7/LcfgBcmct7t/ET+HaCTqfh06OzoAxrkN/IfjJBVe+g==",
+ "dependencies": {
+ "abort-controller": "^3.0.0",
+ "buffer": "^6.0.3",
+ "events": "^3.3.0",
+ "process": "^0.11.10",
+ "string_decoder": "^1.3.0"
+ },
+ "engines": {
+ "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+ }
+ },
+ "node_modules/pino-pretty": {
+ "version": "10.0.1",
+ "resolved": "https://registry.npmjs.org/pino-pretty/-/pino-pretty-10.0.1.tgz",
+ "integrity": "sha512-yrn00+jNpkvZX/NrPVCPIVHAfTDy3ahF0PND9tKqZk4j9s+loK8dpzrJj4dGb7i+WLuR50ussuTAiWoMWU+qeA==",
+ "dependencies": {
+ "colorette": "^2.0.7",
+ "dateformat": "^4.6.3",
+ "fast-copy": "^3.0.0",
+ "fast-safe-stringify": "^2.1.1",
+ "help-me": "^4.0.1",
+ "joycon": "^3.1.1",
+ "minimist": "^1.2.6",
+ "on-exit-leak-free": "^2.1.0",
+ "pino-abstract-transport": "^1.0.0",
+ "pump": "^3.0.0",
+ "readable-stream": "^4.0.0",
+ "secure-json-parse": "^2.4.0",
+ "sonic-boom": "^3.0.0",
+ "strip-json-comments": "^3.1.1"
+ },
+ "bin": {
+ "pino-pretty": "bin.js"
+ }
+ },
+ "node_modules/pino-pretty/node_modules/buffer": {
+ "version": "6.0.3",
+ "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz",
+ "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==",
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/feross"
+ },
+ {
+ "type": "patreon",
+ "url": "https://www.patreon.com/feross"
+ },
+ {
+ "type": "consulting",
+ "url": "https://feross.org/support"
+ }
+ ],
+ "dependencies": {
+ "base64-js": "^1.3.1",
+ "ieee754": "^1.2.1"
+ }
+ },
+ "node_modules/pino-pretty/node_modules/readable-stream": {
+ "version": "4.5.2",
+ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-4.5.2.tgz",
+ "integrity": "sha512-yjavECdqeZ3GLXNgRXgeQEdz9fvDDkNKyHnbHRFtOr7/LcfgBcmct7t/ET+HaCTqfh06OzoAxrkN/IfjJBVe+g==",
+ "dependencies": {
+ "abort-controller": "^3.0.0",
+ "buffer": "^6.0.3",
+ "events": "^3.3.0",
+ "process": "^0.11.10",
+ "string_decoder": "^1.3.0"
+ },
+ "engines": {
+ "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+ }
+ },
+ "node_modules/pino-std-serializers": {
+ "version": "6.2.2",
+ "resolved": "https://registry.npmjs.org/pino-std-serializers/-/pino-std-serializers-6.2.2.tgz",
+ "integrity": "sha512-cHjPPsE+vhj/tnhCy/wiMh3M3z3h/j15zHQX+S9GkTBgqJuTuJzYJ4gUyACLhDaJ7kk9ba9iRDmbH2tJU03OiA=="
+ },
+ "node_modules/process": {
+ "version": "0.11.10",
+ "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz",
+ "integrity": "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==",
+ "engines": {
+ "node": ">= 0.6.0"
+ }
+ },
+ "node_modules/process-nextick-args": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
+ "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag=="
+ },
+ "node_modules/process-warning": {
+ "version": "2.3.2",
+ "resolved": "https://registry.npmjs.org/process-warning/-/process-warning-2.3.2.tgz",
+ "integrity": "sha512-n9wh8tvBe5sFmsqlg+XQhaQLumwpqoAUruLwjCopgTmUBjJ/fjtBsJzKleCaIGBOMXYEhp1YfKl4d7rJ5ZKJGA=="
+ },
+ "node_modules/progress": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz",
+ "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==",
+ "engines": {
+ "node": ">=0.4.0"
+ }
+ },
+ "node_modules/pump": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz",
+ "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==",
+ "dependencies": {
+ "end-of-stream": "^1.1.0",
+ "once": "^1.3.1"
+ }
+ },
+ "node_modules/pumpify": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/pumpify/-/pumpify-2.0.1.tgz",
+ "integrity": "sha512-m7KOje7jZxrmutanlkS1daj1dS6z6BgslzOXmcSEpIlCxM3VJH7lG5QLeck/6hgF6F4crFf01UtQmNsJfweTAw==",
+ "dependencies": {
+ "duplexify": "^4.1.1",
+ "inherits": "^2.0.3",
+ "pump": "^3.0.0"
+ }
+ },
+ "node_modules/queue": {
+ "version": "4.5.1",
+ "resolved": "https://registry.npmjs.org/queue/-/queue-4.5.1.tgz",
+ "integrity": "sha512-AMD7w5hRXcFSb8s9u38acBZ+309u6GsiibP4/0YacJeaurRshogB7v/ZcVPxP5gD5+zIw6ixRHdutiYUJfwKHw==",
+ "dependencies": {
+ "inherits": "~2.0.0"
+ }
+ },
+ "node_modules/quick-format-unescaped": {
+ "version": "4.0.4",
+ "resolved": "https://registry.npmjs.org/quick-format-unescaped/-/quick-format-unescaped-4.0.4.tgz",
+ "integrity": "sha512-tYC1Q1hgyRuHgloV/YXs2w15unPVh8qfu/qCTfhTYamaw7fyhumKa2yGpdSo87vY32rIclj+4fWYQXUMs9EHvg=="
+ },
+ "node_modules/readable-stream": {
+ "version": "3.6.2",
+ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz",
+ "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==",
+ "dependencies": {
+ "inherits": "^2.0.3",
+ "string_decoder": "^1.1.1",
+ "util-deprecate": "^1.0.1"
+ },
+ "engines": {
+ "node": ">= 6"
+ }
+ },
+ "node_modules/readdir-glob": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/readdir-glob/-/readdir-glob-1.1.3.tgz",
+ "integrity": "sha512-v05I2k7xN8zXvPD9N+z/uhXPaj0sUFCe2rcWZIpBsqxfP7xXFQ0tipAd/wjj1YxWyWtUS5IDJpOG82JKt2EAVA==",
+ "dependencies": {
+ "minimatch": "^5.1.0"
+ }
+ },
+ "node_modules/readdir-glob/node_modules/brace-expansion": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
+ "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==",
+ "dependencies": {
+ "balanced-match": "^1.0.0"
+ }
+ },
+ "node_modules/readdir-glob/node_modules/minimatch": {
+ "version": "5.1.6",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz",
+ "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==",
+ "dependencies": {
+ "brace-expansion": "^2.0.1"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/real-require": {
+ "version": "0.2.0",
+ "resolved": "https://registry.npmjs.org/real-require/-/real-require-0.2.0.tgz",
+ "integrity": "sha512-57frrGM/OCTLqLOAh0mhVA9VBMHd+9U7Zb2THMGdBUoZVOtGbJzjxsYGDJ3A9AYYCP4hn6y1TVbaOfzWtm5GFg==",
+ "engines": {
+ "node": ">= 12.13.0"
+ }
+ },
+ "node_modules/regenerator-runtime": {
+ "version": "0.14.1",
+ "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz",
+ "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw=="
+ },
+ "node_modules/remove-bom-buffer": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/remove-bom-buffer/-/remove-bom-buffer-3.0.0.tgz",
+ "integrity": "sha512-8v2rWhaakv18qcvNeli2mZ/TMTL2nEyAKRvzo1WtnZBl15SHyEhrCu2/xKlJyUFKHiHgfXIyuY6g2dObJJycXQ==",
+ "dependencies": {
+ "is-buffer": "^1.1.5",
+ "is-utf8": "^0.2.1"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/remove-bom-stream": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/remove-bom-stream/-/remove-bom-stream-1.2.0.tgz",
+ "integrity": "sha512-wigO8/O08XHb8YPzpDDT+QmRANfW6vLqxfaXm1YXhnFf3AkSLyjfG3GEFg4McZkmgL7KvCj5u2KczkvSP6NfHA==",
+ "dependencies": {
+ "remove-bom-buffer": "^3.0.0",
+ "safe-buffer": "^5.1.0",
+ "through2": "^2.0.3"
+ },
+ "engines": {
+ "node": ">= 0.10"
+ }
+ },
+ "node_modules/remove-trailing-separator": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz",
+ "integrity": "sha512-/hS+Y0u3aOfIETiaiirUFwDBDzmXPvO+jAfKTitUngIPzdKc6Z0LoFjM/CK5PL4C+eKwHohlHAb6H0VFfmmUsw=="
+ },
+ "node_modules/replace-ext": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/replace-ext/-/replace-ext-1.0.1.tgz",
+ "integrity": "sha512-yD5BHCe7quCgBph4rMQ+0KkIRKwWCrHDOX1p1Gp6HwjPM5kVoCdKGNhN7ydqqsX6lJEnQDKZ/tFMiEdQ1dvPEw==",
+ "engines": {
+ "node": ">= 0.10"
+ }
+ },
+ "node_modules/require-from-string": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz",
+ "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/resolve-options": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/resolve-options/-/resolve-options-1.1.0.tgz",
+ "integrity": "sha512-NYDgziiroVeDC29xq7bp/CacZERYsA9bXYd1ZmcJlF3BcrZv5pTb4NG7SjdyKDnXZ84aC4vo2u6sNKIA1LCu/A==",
+ "dependencies": {
+ "value-or-function": "^3.0.0"
+ },
+ "engines": {
+ "node": ">= 0.10"
+ }
+ },
+ "node_modules/safe-buffer": {
+ "version": "5.2.1",
+ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
+ "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==",
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/feross"
+ },
+ {
+ "type": "patreon",
+ "url": "https://www.patreon.com/feross"
+ },
+ {
+ "type": "consulting",
+ "url": "https://feross.org/support"
+ }
+ ]
+ },
+ "node_modules/safe-stable-stringify": {
+ "version": "2.4.3",
+ "resolved": "https://registry.npmjs.org/safe-stable-stringify/-/safe-stable-stringify-2.4.3.tgz",
+ "integrity": "sha512-e2bDA2WJT0wxseVd4lsDP4+3ONX6HpMXQa1ZhFQ7SU+GjvORCmShbCMltrtIDfkYhVHrOcPtj+KhmDBdPdZD1g==",
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/secure-json-parse": {
+ "version": "2.7.0",
+ "resolved": "https://registry.npmjs.org/secure-json-parse/-/secure-json-parse-2.7.0.tgz",
+ "integrity": "sha512-6aU+Rwsezw7VR8/nyvKTx8QpWH9FrcYiXXlqC4z5d5XQBDRqtbfsRjnwGyqbi3gddNtWHuEk9OANUotL26qKUw=="
+ },
+ "node_modules/seek-bzip": {
+ "version": "1.0.6",
+ "resolved": "https://registry.npmjs.org/seek-bzip/-/seek-bzip-1.0.6.tgz",
+ "integrity": "sha512-e1QtP3YL5tWww8uKaOCQ18UxIT2laNBXHjV/S2WYCiK4udiv8lkG89KRIoCjUagnAmCBurjF4zEVX2ByBbnCjQ==",
+ "dependencies": {
+ "commander": "^2.8.1"
+ },
+ "bin": {
+ "seek-bunzip": "bin/seek-bunzip",
+ "seek-table": "bin/seek-bzip-table"
+ }
+ },
+ "node_modules/seek-bzip/node_modules/commander": {
+ "version": "2.20.3",
+ "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz",
+ "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ=="
+ },
+ "node_modules/seroval": {
+ "version": "1.0.7",
+ "resolved": "https://registry.npmjs.org/seroval/-/seroval-1.0.7.tgz",
+ "integrity": "sha512-n6ZMQX5q0Vn19Zq7CIKNIo7E75gPkGCFUEqDpa8jgwpYr/vScjqnQ6H09t1uIiZ0ZSK0ypEGvrYK2bhBGWsGdw==",
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/seroval-plugins": {
+ "version": "1.0.7",
+ "resolved": "https://registry.npmjs.org/seroval-plugins/-/seroval-plugins-1.0.7.tgz",
+ "integrity": "sha512-GO7TkWvodGp6buMEX9p7tNyIkbwlyuAWbI6G9Ec5bhcm7mQdu3JOK1IXbEUwb3FVzSc363GraG/wLW23NSavIw==",
+ "engines": {
+ "node": ">=10"
+ },
+ "peerDependencies": {
+ "seroval": "^1.0"
+ }
+ },
+ "node_modules/set-function-length": {
+ "version": "1.2.2",
+ "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz",
+ "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==",
+ "dependencies": {
+ "define-data-property": "^1.1.4",
+ "es-errors": "^1.3.0",
+ "function-bind": "^1.1.2",
+ "get-intrinsic": "^1.2.4",
+ "gopd": "^1.0.1",
+ "has-property-descriptors": "^1.0.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/sha.js": {
+ "version": "2.4.11",
+ "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz",
+ "integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==",
+ "dependencies": {
+ "inherits": "^2.0.1",
+ "safe-buffer": "^5.0.1"
+ },
+ "bin": {
+ "sha.js": "bin.js"
+ }
+ },
+ "node_modules/should-proxy": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/should-proxy/-/should-proxy-1.0.4.tgz",
+ "integrity": "sha512-RPQhIndEIVUCjkfkQ6rs6sOR6pkxJWCNdxtfG5pP0RVgUYbK5911kLTF0TNcCC0G3YCGd492rMollFT2aTd9iQ=="
+ },
+ "node_modules/simple-concat": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.1.tgz",
+ "integrity": "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==",
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/feross"
+ },
+ {
+ "type": "patreon",
+ "url": "https://www.patreon.com/feross"
+ },
+ {
+ "type": "consulting",
+ "url": "https://feross.org/support"
+ }
+ ]
+ },
+ "node_modules/simple-get": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-4.0.1.tgz",
+ "integrity": "sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA==",
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/feross"
+ },
+ {
+ "type": "patreon",
+ "url": "https://www.patreon.com/feross"
+ },
+ {
+ "type": "consulting",
+ "url": "https://feross.org/support"
+ }
+ ],
+ "dependencies": {
+ "decompress-response": "^6.0.0",
+ "once": "^1.3.1",
+ "simple-concat": "^1.0.0"
+ }
+ },
+ "node_modules/solid-js": {
+ "version": "1.8.17",
+ "resolved": "https://registry.npmjs.org/solid-js/-/solid-js-1.8.17.tgz",
+ "integrity": "sha512-E0FkUgv9sG/gEBWkHr/2XkBluHb1fkrHywUgA6o6XolPDCJ4g1HaLmQufcBBhiF36ee40q+HpG/vCZu7fLpI3Q==",
+ "dependencies": {
+ "csstype": "^3.1.0",
+ "seroval": "^1.0.4",
+ "seroval-plugins": "^1.0.3"
+ }
+ },
+ "node_modules/sonic-boom": {
+ "version": "3.3.0",
+ "resolved": "https://registry.npmjs.org/sonic-boom/-/sonic-boom-3.3.0.tgz",
+ "integrity": "sha512-LYxp34KlZ1a2Jb8ZQgFCK3niIHzibdwtwNUWKg0qQRzsDoJ3Gfgkf8KdBTFU3SkejDEIlWwnSnpVdOZIhFMl/g==",
+ "dependencies": {
+ "atomic-sleep": "^1.0.0"
+ }
+ },
+ "node_modules/source-map": {
+ "version": "0.6.1",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
+ "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/split2": {
+ "version": "4.2.0",
+ "resolved": "https://registry.npmjs.org/split2/-/split2-4.2.0.tgz",
+ "integrity": "sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==",
+ "engines": {
+ "node": ">= 10.x"
+ }
+ },
+ "node_modules/stream-shift": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.3.tgz",
+ "integrity": "sha512-76ORR0DO1o1hlKwTbi/DM3EXWGf3ZJYO8cXX5RJwnul2DEg2oyoZyjLNoQM8WsvZiFKCRfC1O0J7iCvie3RZmQ=="
+ },
+ "node_modules/string_decoder": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz",
+ "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==",
+ "dependencies": {
+ "safe-buffer": "~5.2.0"
+ }
+ },
+ "node_modules/strip-dirs": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/strip-dirs/-/strip-dirs-2.1.0.tgz",
+ "integrity": "sha512-JOCxOeKLm2CAS73y/U4ZeZPTkE+gNVCzKt7Eox84Iej1LT/2pTWYpZKJuxwQpvX1LiZb1xokNR7RLfuBAa7T3g==",
+ "dependencies": {
+ "is-natural-number": "^4.0.1"
+ }
+ },
+ "node_modules/strip-json-comments": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz",
+ "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==",
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/strnum": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/strnum/-/strnum-1.0.5.tgz",
+ "integrity": "sha512-J8bbNyKKXl5qYcR36TIO8W3mVGVHrmmxsd5PAItGkmyzwJvybiw2IVq5nqd0i4LSNSkB/sx9VHllbfFdr9k1JA=="
+ },
+ "node_modules/tar-stream": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz",
+ "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==",
+ "dependencies": {
+ "bl": "^4.0.3",
+ "end-of-stream": "^1.4.1",
+ "fs-constants": "^1.0.0",
+ "inherits": "^2.0.3",
+ "readable-stream": "^3.1.1"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/thread-stream": {
+ "version": "2.7.0",
+ "resolved": "https://registry.npmjs.org/thread-stream/-/thread-stream-2.7.0.tgz",
+ "integrity": "sha512-qQiRWsU/wvNolI6tbbCKd9iKaTnCXsTwVxhhKM6nctPdujTyztjlbUkUTUymidWcMnZ5pWR0ej4a0tjsW021vw==",
+ "dependencies": {
+ "real-require": "^0.2.0"
+ }
+ },
+ "node_modules/through": {
+ "version": "2.3.8",
+ "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz",
+ "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg=="
+ },
+ "node_modules/through2": {
+ "version": "2.0.5",
+ "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz",
+ "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==",
+ "dependencies": {
+ "readable-stream": "~2.3.6",
+ "xtend": "~4.0.1"
+ }
+ },
+ "node_modules/through2-filter": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/through2-filter/-/through2-filter-3.0.0.tgz",
+ "integrity": "sha512-jaRjI2WxN3W1V8/FMZ9HKIBXixtiqs3SQSX4/YGIiP3gL6djW48VoZq9tDqeCWs3MT8YY5wb/zli8VW8snY1CA==",
+ "dependencies": {
+ "through2": "~2.0.0",
+ "xtend": "~4.0.0"
+ }
+ },
+ "node_modules/through2/node_modules/readable-stream": {
+ "version": "2.3.8",
+ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz",
+ "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==",
+ "dependencies": {
+ "core-util-is": "~1.0.0",
+ "inherits": "~2.0.3",
+ "isarray": "~1.0.0",
+ "process-nextick-args": "~2.0.0",
+ "safe-buffer": "~5.1.1",
+ "string_decoder": "~1.1.1",
+ "util-deprecate": "~1.0.1"
+ }
+ },
+ "node_modules/through2/node_modules/safe-buffer": {
+ "version": "5.1.2",
+ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
+ "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="
+ },
+ "node_modules/through2/node_modules/string_decoder": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
+ "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
+ "dependencies": {
+ "safe-buffer": "~5.1.0"
+ }
+ },
+ "node_modules/to-absolute-glob": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/to-absolute-glob/-/to-absolute-glob-2.0.2.tgz",
+ "integrity": "sha512-rtwLUQEwT8ZeKQbyFJyomBRYXyE16U5VKuy0ftxLMK/PZb2fkOsg5r9kHdauuVDbsNdIBoC/HCthpidamQFXYA==",
+ "dependencies": {
+ "is-absolute": "^1.0.0",
+ "is-negated-glob": "^1.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/to-buffer": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/to-buffer/-/to-buffer-1.1.1.tgz",
+ "integrity": "sha512-lx9B5iv7msuFYE3dytT+KE5tap+rNYw+K4jVkb9R/asAb+pbBSM17jtunHplhBe6RRJdZx3Pn2Jph24O32mOVg=="
+ },
+ "node_modules/to-regex-range": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
+ "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
+ "dependencies": {
+ "is-number": "^7.0.0"
+ },
+ "engines": {
+ "node": ">=8.0"
+ }
+ },
+ "node_modules/to-through": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/to-through/-/to-through-2.0.0.tgz",
+ "integrity": "sha512-+QIz37Ly7acM4EMdw2PRN389OneM5+d844tirkGp4dPKzI5OE72V9OsbFp+CIYJDahZ41ZV05hNtcPAQUAm9/Q==",
+ "dependencies": {
+ "through2": "^2.0.3"
+ },
+ "engines": {
+ "node": ">= 0.10"
+ }
+ },
+ "node_modules/uglify-js": {
+ "version": "3.17.4",
+ "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.17.4.tgz",
+ "integrity": "sha512-T9q82TJI9e/C1TAxYvfb16xO120tMVFZrGA3f9/P4424DNu6ypK103y0GPFVa17yotwSyZW5iYXgjYHkGrJW/g==",
+ "optional": true,
+ "bin": {
+ "uglifyjs": "bin/uglifyjs"
+ },
+ "engines": {
+ "node": ">=0.8.0"
+ }
+ },
+ "node_modules/unbzip2-stream": {
+ "version": "1.4.3",
+ "resolved": "https://registry.npmjs.org/unbzip2-stream/-/unbzip2-stream-1.4.3.tgz",
+ "integrity": "sha512-mlExGW4w71ebDJviH16lQLtZS32VKqsSfk80GCfUlwT/4/hNRFsoscrF/c++9xinkMzECL1uL9DDwXqFWkruPg==",
+ "dependencies": {
+ "buffer": "^5.2.1",
+ "through": "^2.3.8"
+ }
+ },
+ "node_modules/unc-path-regex": {
+ "version": "0.1.2",
+ "resolved": "https://registry.npmjs.org/unc-path-regex/-/unc-path-regex-0.1.2.tgz",
+ "integrity": "sha512-eXL4nmJT7oCpkZsHZUOJo8hcX3GbsiDOa0Qu9F646fi8dT3XuSVopVqAcEiVzSKKH7UoDti23wNX3qGFxcW5Qg==",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/unique-stream": {
+ "version": "2.3.1",
+ "resolved": "https://registry.npmjs.org/unique-stream/-/unique-stream-2.3.1.tgz",
+ "integrity": "sha512-2nY4TnBE70yoxHkDli7DMazpWiP7xMdCYqU2nBRO0UB+ZpEkGsSija7MvmvnZFUeC+mrgiUfcHSr3LmRFIg4+A==",
+ "dependencies": {
+ "json-stable-stringify-without-jsonify": "^1.0.1",
+ "through2-filter": "^3.0.0"
+ }
+ },
+ "node_modules/unxhr": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/unxhr/-/unxhr-1.0.1.tgz",
+ "integrity": "sha512-MAhukhVHyaLGDjyDYhy8gVjWJyhTECCdNsLwlMoGFoNJ3o79fpQhtQuzmAE4IxCMDwraF4cW8ZjpAV0m9CRQbg==",
+ "engines": {
+ "node": ">=8.11"
+ }
+ },
+ "node_modules/util-deprecate": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
+ "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw=="
+ },
+ "node_modules/value-or-function": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/value-or-function/-/value-or-function-3.0.0.tgz",
+ "integrity": "sha512-jdBB2FrWvQC/pnPtIqcLsMaQgjhdb6B7tk1MMyTKapox+tQZbdRP4uLxu/JY0t7fbfDCUMnuelzEYv5GsxHhdg==",
+ "engines": {
+ "node": ">= 0.10"
+ }
+ },
+ "node_modules/vinyl": {
+ "version": "2.2.1",
+ "resolved": "https://registry.npmjs.org/vinyl/-/vinyl-2.2.1.tgz",
+ "integrity": "sha512-LII3bXRFBZLlezoG5FfZVcXflZgWP/4dCwKtxd5ky9+LOtM4CS3bIRQsmR1KMnMW07jpE8fqR2lcxPZ+8sJIcw==",
+ "dependencies": {
+ "clone": "^2.1.1",
+ "clone-buffer": "^1.0.0",
+ "clone-stats": "^1.0.0",
+ "cloneable-readable": "^1.0.0",
+ "remove-trailing-separator": "^1.0.1",
+ "replace-ext": "^1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.10"
+ }
+ },
+ "node_modules/vinyl-fs": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/vinyl-fs/-/vinyl-fs-3.0.3.tgz",
+ "integrity": "sha512-vIu34EkyNyJxmP0jscNzWBSygh7VWhqun6RmqVfXePrOwi9lhvRs//dOaGOTRUQr4tx7/zd26Tk5WeSVZitgng==",
+ "dependencies": {
+ "fs-mkdirp-stream": "^1.0.0",
+ "glob-stream": "^6.1.0",
+ "graceful-fs": "^4.0.0",
+ "is-valid-glob": "^1.0.0",
+ "lazystream": "^1.0.0",
+ "lead": "^1.0.0",
+ "object.assign": "^4.0.4",
+ "pumpify": "^1.3.5",
+ "readable-stream": "^2.3.3",
+ "remove-bom-buffer": "^3.0.0",
+ "remove-bom-stream": "^1.2.0",
+ "resolve-options": "^1.1.0",
+ "through2": "^2.0.0",
+ "to-through": "^2.0.0",
+ "value-or-function": "^3.0.0",
+ "vinyl": "^2.0.0",
+ "vinyl-sourcemap": "^1.1.0"
+ },
+ "engines": {
+ "node": ">= 0.10"
+ }
+ },
+ "node_modules/vinyl-fs/node_modules/duplexify": {
+ "version": "3.7.1",
+ "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-3.7.1.tgz",
+ "integrity": "sha512-07z8uv2wMyS51kKhD1KsdXJg5WQ6t93RneqRxUHnskXVtlYYkLqM0gqStQZ3pj073g687jPCHrqNfCzawLYh5g==",
+ "dependencies": {
+ "end-of-stream": "^1.0.0",
+ "inherits": "^2.0.1",
+ "readable-stream": "^2.0.0",
+ "stream-shift": "^1.0.0"
+ }
+ },
+ "node_modules/vinyl-fs/node_modules/glob-parent": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz",
+ "integrity": "sha512-E8Ak/2+dZY6fnzlR7+ueWvhsH1SjHr4jjss4YS/h4py44jY9MhK/VFdaZJAWDz6BbL21KeteKxFSFpq8OS5gVA==",
+ "dependencies": {
+ "is-glob": "^3.1.0",
+ "path-dirname": "^1.0.0"
+ }
+ },
+ "node_modules/vinyl-fs/node_modules/glob-stream": {
+ "version": "6.1.0",
+ "resolved": "https://registry.npmjs.org/glob-stream/-/glob-stream-6.1.0.tgz",
+ "integrity": "sha512-uMbLGAP3S2aDOHUDfdoYcdIePUCfysbAd0IAoWVZbeGU/oNQ8asHVSshLDJUPWxfzj8zsCG7/XeHPHTtow0nsw==",
+ "dependencies": {
+ "extend": "^3.0.0",
+ "glob": "^7.1.1",
+ "glob-parent": "^3.1.0",
+ "is-negated-glob": "^1.0.0",
+ "ordered-read-streams": "^1.0.0",
+ "pumpify": "^1.3.5",
+ "readable-stream": "^2.1.5",
+ "remove-trailing-separator": "^1.0.1",
+ "to-absolute-glob": "^2.0.0",
+ "unique-stream": "^2.0.2"
+ },
+ "engines": {
+ "node": ">= 0.10"
+ }
+ },
+ "node_modules/vinyl-fs/node_modules/is-glob": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz",
+ "integrity": "sha512-UFpDDrPgM6qpnFNI+rh/p3bUaq9hKLZN8bMUWzxmcnZVS3omf4IPK+BrewlnWjO1WmUsMYuSjKh4UJuV4+Lqmw==",
+ "dependencies": {
+ "is-extglob": "^2.1.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/vinyl-fs/node_modules/pump": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/pump/-/pump-2.0.1.tgz",
+ "integrity": "sha512-ruPMNRkN3MHP1cWJc9OWr+T/xDP0jhXYCLfJcBuX54hhfIBnaQmAUMfDcG4DM5UMWByBbJY69QSphm3jtDKIkA==",
+ "dependencies": {
+ "end-of-stream": "^1.1.0",
+ "once": "^1.3.1"
+ }
+ },
+ "node_modules/vinyl-fs/node_modules/pumpify": {
+ "version": "1.5.1",
+ "resolved": "https://registry.npmjs.org/pumpify/-/pumpify-1.5.1.tgz",
+ "integrity": "sha512-oClZI37HvuUJJxSKKrC17bZ9Cu0ZYhEAGPsPUy9KlMUmv9dKX2o77RUmq7f3XjIxbwyGwYzbzQ1L2Ks8sIradQ==",
+ "dependencies": {
+ "duplexify": "^3.6.0",
+ "inherits": "^2.0.3",
+ "pump": "^2.0.0"
+ }
+ },
+ "node_modules/vinyl-fs/node_modules/readable-stream": {
+ "version": "2.3.8",
+ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz",
+ "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==",
+ "dependencies": {
+ "core-util-is": "~1.0.0",
+ "inherits": "~2.0.3",
+ "isarray": "~1.0.0",
+ "process-nextick-args": "~2.0.0",
+ "safe-buffer": "~5.1.1",
+ "string_decoder": "~1.1.1",
+ "util-deprecate": "~1.0.1"
+ }
+ },
+ "node_modules/vinyl-fs/node_modules/safe-buffer": {
+ "version": "5.1.2",
+ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
+ "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="
+ },
+ "node_modules/vinyl-fs/node_modules/string_decoder": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
+ "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
+ "dependencies": {
+ "safe-buffer": "~5.1.0"
+ }
+ },
+ "node_modules/vinyl-sourcemap": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/vinyl-sourcemap/-/vinyl-sourcemap-1.1.0.tgz",
+ "integrity": "sha512-NiibMgt6VJGJmyw7vtzhctDcfKch4e4n9TBeoWlirb7FMg9/1Ov9k+A5ZRAtywBpRPiyECvQRQllYM8dECegVA==",
+ "dependencies": {
+ "append-buffer": "^1.0.2",
+ "convert-source-map": "^1.5.0",
+ "graceful-fs": "^4.1.6",
+ "normalize-path": "^2.1.1",
+ "now-and-later": "^2.0.0",
+ "remove-bom-buffer": "^3.0.0",
+ "vinyl": "^2.0.0"
+ },
+ "engines": {
+ "node": ">= 0.10"
+ }
+ },
+ "node_modules/vinyl-sourcemap/node_modules/normalize-path": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz",
+ "integrity": "sha512-3pKJwH184Xo/lnH6oyP1q2pMd7HcypqqmRs91/6/i2CGtWwIKGCkOOMTm/zXbgTEWHw1uNpNi/igc3ePOYHb6w==",
+ "dependencies": {
+ "remove-trailing-separator": "^1.0.1"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/wordwrap": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz",
+ "integrity": "sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q=="
+ },
+ "node_modules/wrappy": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
+ "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ=="
+ },
+ "node_modules/xdg-basedir": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/xdg-basedir/-/xdg-basedir-3.0.0.tgz",
+ "integrity": "sha512-1Dly4xqlulvPD3fZUQJLY+FUIeqN3N2MM3uqe4rCJftAvOjFa3jFGfctOgluGx4ahPbUCsZkmJILiP0Vi4T6lQ==",
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/xtend": {
+ "version": "4.0.2",
+ "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz",
+ "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==",
+ "engines": {
+ "node": ">=0.4"
+ }
+ },
+ "node_modules/yargs-parser": {
+ "version": "20.2.9",
+ "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz",
+ "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==",
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/yauzl": {
+ "version": "2.10.0",
+ "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz",
+ "integrity": "sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==",
+ "dependencies": {
+ "buffer-crc32": "~0.2.3",
+ "fd-slicer": "~1.1.0"
+ }
+ },
+ "node_modules/yazl": {
+ "version": "2.5.1",
+ "resolved": "https://registry.npmjs.org/yazl/-/yazl-2.5.1.tgz",
+ "integrity": "sha512-phENi2PLiHnHb6QBVot+dJnaAZ0xosj7p3fWl+znIjBDlnMI2PsZCJZ306BPTFOaHf5qdDEI8x5qFrSOBN5vrw==",
+ "dependencies": {
+ "buffer-crc32": "~0.2.3"
+ }
+ },
+ "node_modules/zip-stream": {
+ "version": "4.1.1",
+ "resolved": "https://registry.npmjs.org/zip-stream/-/zip-stream-4.1.1.tgz",
+ "integrity": "sha512-9qv4rlDiopXg4E69k+vMHjNN63YFMe9sZMrdlvKnCjlCRWeCBswPPMPUfx+ipsAWq1LXHe70RcbaHdJJpS6hyQ==",
+ "dependencies": {
+ "archiver-utils": "^3.0.4",
+ "compress-commons": "^4.1.2",
+ "readable-stream": "^3.6.0"
+ },
+ "engines": {
+ "node": ">= 10"
+ }
+ },
+ "node_modules/zip-stream/node_modules/archiver-utils": {
+ "version": "3.0.4",
+ "resolved": "https://registry.npmjs.org/archiver-utils/-/archiver-utils-3.0.4.tgz",
+ "integrity": "sha512-KVgf4XQVrTjhyWmx6cte4RxonPLR9onExufI1jhvw/MQ4BB6IsZD5gT8Lq+u/+pRkWna/6JoHpiQioaqFP5Rzw==",
+ "dependencies": {
+ "glob": "^7.2.3",
+ "graceful-fs": "^4.2.0",
+ "lazystream": "^1.0.0",
+ "lodash.defaults": "^4.2.0",
+ "lodash.difference": "^4.5.0",
+ "lodash.flatten": "^4.4.0",
+ "lodash.isplainobject": "^4.0.6",
+ "lodash.union": "^4.6.0",
+ "normalize-path": "^3.0.0",
+ "readable-stream": "^3.6.0"
+ },
+ "engines": {
+ "node": ">= 10"
+ }
+ }
+ }
+}
diff --git a/antora/package.json b/antora/package.json
new file mode 100644
index 000000000000..f7aa971cd360
--- /dev/null
+++ b/antora/package.json
@@ -0,0 +1,18 @@
+{
+ "scripts": {
+ "antora": "node npm/antora.js"
+ },
+ "dependencies": {
+ "@antora/cli": "3.2.0-alpha.4",
+ "@antora/site-generator": "3.2.0-alpha.4",
+ "@antora/atlas-extension": "1.0.0-alpha.2",
+ "@springio/antora-extensions": "1.11.1",
+ "@springio/antora-xref-extension": "1.0.0-alpha.3",
+ "@springio/antora-zip-contents-collector-extension": "1.0.0-alpha.8",
+ "@asciidoctor/tabs": "1.0.0-beta.6",
+ "@springio/asciidoctor-extensions": "1.0.0-alpha.10"
+ },
+ "config": {
+ "ui-bundle-url": "https://github.com/spring-io/antora-ui-spring/releases/download/v0.4.16/ui-bundle.zip"
+ }
+}
diff --git a/build.gradle b/build.gradle
index 0795f569d49e..4f490c8e7c19 100644
--- a/build.gradle
+++ b/build.gradle
@@ -1,29 +1,12 @@
plugins {
id "base"
id "org.jetbrains.kotlin.jvm" apply false // https://youtrack.jetbrains.com/issue/KT-30276
- id "io.spring.nohttp" version "0.0.11"
}
description = "Spring Boot Build"
defaultTasks 'build'
-nohttp {
- allowlistFile = project.file("src/nohttp/allowlist.lines")
- source.exclude "**/bin/**"
- source.exclude "**/build/**"
- source.exclude "**/out/**"
- source.exclude "**/target/**"
- source.exclude "**/.settings/**"
- source.exclude "**/.classpath"
- source.exclude "**/.project"
- source.exclude "spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/docker/export.tar"
-}
-
-check {
- dependsOn checkstyleNohttp
-}
-
allprojects {
group "org.springframework.boot"
@@ -41,7 +24,3 @@ allprojects {
resolutionStrategy.cacheChangingModulesFor 0, "minutes"
}
}
-
-tasks.named("checkstyleNohttp").configure {
- maxHeapSize = "1536m"
-}
diff --git a/buildSrc/build.gradle b/buildSrc/build.gradle
index 7afefa5d753a..8356c4275f8b 100644
--- a/buildSrc/build.gradle
+++ b/buildSrc/build.gradle
@@ -17,11 +17,12 @@ def versions = [:]
new File(projectDir.parentFile, "gradle.properties").withInputStream {
def properties = new Properties()
properties.load(it)
- ["assertj", "commonsCodec", "hamcrest", "jackson", "junitJupiter",
- "kotlin", "maven", "springFramework"].each {
+ ["assertj", "commonsCodec", "hamcrest", "junitJupiter", "kotlin", "maven", "snakeYaml"].each {
versions[it] = properties[it + "Version"]
}
}
+versions["jackson"] = "2.15.3"
+versions["springFramework"] = "6.0.12"
ext.set("versions", versions)
if (versions.springFramework.contains("-")) {
repositories {
@@ -40,19 +41,25 @@ dependencies {
implementation(platform("org.springframework:spring-framework-bom:${versions.springFramework}"))
implementation("com.diffplug.gradle:goomph:3.37.2")
+ implementation("dev.adamko.dokkatoo:dokkatoo-plugin:2.3.1")
implementation("com.fasterxml.jackson.core:jackson-databind:${versions.jackson}")
+ implementation("com.github.node-gradle:gradle-node-plugin:3.5.1")
implementation("com.gradle:develocity-gradle-plugin:3.17.2")
implementation("com.tngtech.archunit:archunit:1.0.0")
implementation("commons-codec:commons-codec:${versions.commonsCodec}")
implementation("de.undercouch.download:de.undercouch.download.gradle.plugin:5.5.0")
+ implementation("io.spring.gradle.antora:spring-antora-plugin:0.0.1")
implementation("io.spring.javaformat:spring-javaformat-gradle-plugin:${javaFormatVersion}")
+ implementation("io.spring.nohttp:nohttp-gradle:0.0.11")
+ implementation("org.apache.httpcomponents.client5:httpclient5:5.3.1")
implementation("org.apache.maven:maven-embedder:${versions.maven}")
- implementation("org.asciidoctor:asciidoctor-gradle-jvm:3.3.2")
+ implementation("org.antora:gradle-antora-plugin:1.0.0")
implementation("org.jetbrains.kotlin:kotlin-gradle-plugin:${versions.kotlin}")
implementation("org.jetbrains.kotlin:kotlin-compiler-embeddable:${versions.kotlin}")
implementation("org.springframework:spring-context")
implementation("org.springframework:spring-core")
implementation("org.springframework:spring-web")
+ implementation("org.yaml:snakeyaml:${versions.snakeYaml}")
testImplementation("org.assertj:assertj-core:${versions.assertj}")
testImplementation("org.hamcrest:hamcrest:${versions.hamcrest}")
@@ -62,6 +69,12 @@ dependencies {
testRuntimeOnly("org.junit.platform:junit-platform-launcher")
}
+configurations.all {
+ exclude group:"org.slf4j", module:"slf4j-api"
+ exclude group:"ch.qos.logback", module:"logback-classic"
+ exclude group:"ch.qos.logback", module:"logback-core"
+}
+
gradlePlugin {
plugins {
annotationProcessorPlugin {
@@ -92,6 +105,10 @@ gradlePlugin {
id = "org.springframework.boot.deployed"
implementationClass = "org.springframework.boot.build.DeployedPlugin"
}
+ dockerTestPlugin {
+ id = "org.springframework.boot.docker-test"
+ implementationClass = "org.springframework.boot.build.test.DockerTestPlugin"
+ }
integrationTestPlugin {
id = "org.springframework.boot.integration-test"
implementationClass = "org.springframework.boot.build.test.IntegrationTestPlugin"
@@ -131,9 +148,12 @@ test {
useJUnitPlatform()
}
-eclipse.classpath.file.whenMerged {
- def jreEntry = entries.find { it.path.contains("org.eclipse.jdt.launching.JRE_CONTAINER") }
- jreEntry.entryAttributes['module'] = 'true'
- jreEntry.entryAttributes['limit-modules'] = 'java.base'
+eclipse {
+ jdt {
+ file {
+ withProperties {
+ it["org.eclipse.jdt.core.compiler.ignoreUnnamedModuleForSplitPackage"] = "enabled"
+ }
+ }
+ }
}
-
diff --git a/buildSrc/src/main/java/org/springframework/boot/build/AntoraConventions.java b/buildSrc/src/main/java/org/springframework/boot/build/AntoraConventions.java
new file mode 100644
index 000000000000..a05289a4a220
--- /dev/null
+++ b/buildSrc/src/main/java/org/springframework/boot/build/AntoraConventions.java
@@ -0,0 +1,213 @@
+/*
+ * Copyright 2023-2024 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.boot.build;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.UncheckedIOException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.github.gradle.node.NodeExtension;
+import com.github.gradle.node.npm.task.NpmInstallTask;
+import io.spring.gradle.antora.GenerateAntoraYmlPlugin;
+import io.spring.gradle.antora.GenerateAntoraYmlTask;
+import org.antora.gradle.AntoraPlugin;
+import org.antora.gradle.AntoraTask;
+import org.gradle.StartParameter;
+import org.gradle.api.Project;
+import org.gradle.api.logging.LogLevel;
+import org.gradle.api.plugins.JavaBasePlugin;
+import org.gradle.api.tasks.Copy;
+import org.gradle.api.tasks.TaskContainer;
+
+import org.springframework.boot.build.antora.AntoraAsciidocAttributes;
+import org.springframework.boot.build.antora.GenerateAntoraPlaybook;
+import org.springframework.boot.build.bom.BomExtension;
+import org.springframework.boot.build.constraints.ExtractVersionConstraints;
+import org.springframework.util.Assert;
+import org.springframework.util.StringUtils;
+
+/**
+ * Conventions that are applied in the presence of the {@link AntoraPlugin}.
+ *
+ * @author Phillip Webb
+ */
+public class AntoraConventions {
+
+ private static final String DEPENDENCIES_PATH = ":spring-boot-project:spring-boot-dependencies";
+
+ private static final String ANTORA_SOURCE_DIR = "src/docs/antora";
+
+ private static final List NAV_FILES = List.of("nav.adoc", "local-nav.adoc");
+
+ void apply(Project project) {
+ project.getPlugins().withType(AntoraPlugin.class, (antoraPlugin) -> apply(project, antoraPlugin));
+ }
+
+ private void apply(Project project, AntoraPlugin antoraPlugin) {
+ ExtractVersionConstraints dependencyVersionsTask = addDependencyVersionsTask(project);
+ project.getPlugins().apply(GenerateAntoraYmlPlugin.class);
+ TaskContainer tasks = project.getTasks();
+ GenerateAntoraPlaybook generateAntoraPlaybookTask = tasks.create("generateAntoraPlaybook",
+ GenerateAntoraPlaybook.class);
+ configureGenerateAntoraPlaybookTask(project, generateAntoraPlaybookTask);
+ Copy copyAntoraPackageJsonTask = tasks.create("copyAntoraPackageJson", Copy.class);
+ configureCopyAntoraPackageJsonTask(project, copyAntoraPackageJsonTask);
+ NpmInstallTask npmInstallTask = tasks.create("antoraNpmInstall", NpmInstallTask.class);
+ configureNpmInstallTask(project, npmInstallTask, copyAntoraPackageJsonTask);
+ tasks.withType(GenerateAntoraYmlTask.class, (generateAntoraYmlTask) -> configureGenerateAntoraYmlTask(project,
+ generateAntoraYmlTask, dependencyVersionsTask));
+ tasks.withType(AntoraTask.class,
+ (antoraTask) -> configureAntoraTask(project, antoraTask, npmInstallTask, generateAntoraPlaybookTask));
+ project.getExtensions()
+ .configure(NodeExtension.class, (nodeExtension) -> configureNodeExtension(project, nodeExtension));
+ }
+
+ private void configureGenerateAntoraPlaybookTask(Project project,
+ GenerateAntoraPlaybook generateAntoraPlaybookTask) {
+ File nodeProjectDir = getNodeProjectDir(project.getBuildDir());
+ generateAntoraPlaybookTask.getOutputFile().set(new File(nodeProjectDir, "antora-playbook.yml"));
+ }
+
+ private void configureCopyAntoraPackageJsonTask(Project project, Copy copyAntoraPackageJsonTask) {
+ copyAntoraPackageJsonTask
+ .from(project.getRootProject().file("antora"), (spec) -> spec.include("package.json", "package-lock.json"))
+ .into(getNodeProjectDir(project.getBuildDir()));
+ }
+
+ private void configureNpmInstallTask(Project project, NpmInstallTask npmInstallTask, Copy copyAntoraPackageJson) {
+ npmInstallTask.dependsOn(copyAntoraPackageJson);
+ Map 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"));
+ }
+
+ private ExtractVersionConstraints addDependencyVersionsTask(Project project) {
+ return project.getTasks()
+ .create("dependencyVersions", ExtractVersionConstraints.class,
+ (task) -> task.enforcedPlatform(DEPENDENCIES_PATH));
+ }
+
+ private void configureGenerateAntoraYmlTask(Project project, GenerateAntoraYmlTask generateAntoraYmlTask,
+ ExtractVersionConstraints dependencyVersionsTask) {
+ generateAntoraYmlTask.getOutputs().doNotCacheIf("getAsciidocAttributes() changes output", (task) -> true);
+ generateAntoraYmlTask.dependsOn(dependencyVersionsTask);
+ generateAntoraYmlTask.setProperty("componentName", "boot");
+ generateAntoraYmlTask.setProperty("outputFile",
+ new File(project.getBuildDir(), "generated/docs/antora-yml/antora.yml"));
+ generateAntoraYmlTask.setProperty("yml", getDefaultYml(project));
+ generateAntoraYmlTask.doFirst((task) -> generateAntoraYmlTask.getAsciidocAttributes()
+ .putAll(project.provider(() -> getAsciidocAttributes(project, dependencyVersionsTask))));
+ }
+
+ private Map getDefaultYml(Project project) {
+ String navFile = null;
+ for (String candidate : NAV_FILES) {
+ if (project.file(ANTORA_SOURCE_DIR + "/" + candidate).exists()) {
+ Assert.state(navFile == null, "Multiple nav files found");
+ navFile = candidate;
+ }
+ }
+ Map defaultYml = new LinkedHashMap<>();
+ defaultYml.put("title", "Spring Boot");
+ if (navFile != null) {
+ defaultYml.put("nav", List.of(navFile));
+ }
+ return defaultYml;
+ }
+
+ private Map getAsciidocAttributes(Project project,
+ ExtractVersionConstraints dependencyVersionsTask) {
+ BomExtension bom = (BomExtension) project.project(DEPENDENCIES_PATH).getExtensions().getByName("bom");
+ Map dependencyVersions = dependencyVersionsTask.getVersionConstraints();
+ AntoraAsciidocAttributes attributes = new AntoraAsciidocAttributes(project, bom, dependencyVersions);
+ return attributes.get();
+ }
+
+ private void configureAntoraTask(Project project, AntoraTask antoraTask, NpmInstallTask npmInstallTask,
+ GenerateAntoraPlaybook generateAntoraPlaybookTask) {
+ antoraTask.setGroup("Documentation");
+ antoraTask.dependsOn(npmInstallTask, generateAntoraPlaybookTask);
+ antoraTask.setPlaybook("antora-playbook.yml");
+ antoraTask.setUiBundleUrl(getUiBundleUrl(project));
+ antoraTask.getArgs().set(project.provider(() -> getAntoraNpxArs(project, antoraTask)));
+ project.getPlugins()
+ .withType(JavaBasePlugin.class,
+ (javaBasePlugin) -> project.getTasks()
+ .getByName(JavaBasePlugin.CHECK_TASK_NAME)
+ .dependsOn(antoraTask));
+ }
+
+ private List getAntoraNpxArs(Project project, AntoraTask antoraTask) {
+ logWarningIfNodeModulesInUserHome(project);
+ StartParameter startParameter = project.getGradle().getStartParameter();
+ boolean showStacktrace = startParameter.getShowStacktrace().name().startsWith("ALWAYS");
+ boolean debugLogging = project.getGradle().getStartParameter().getLogLevel() == LogLevel.DEBUG;
+ String playbookPath = antoraTask.getPlaybook();
+ List arguments = new ArrayList<>();
+ arguments.addAll(List.of("--package", "@antora/cli"));
+ arguments.add("antora");
+ arguments.addAll((!showStacktrace) ? Collections.emptyList() : List.of("--stacktrace"));
+ arguments.addAll((!debugLogging) ? List.of("--quiet") : List.of("--log-level", "all"));
+ arguments.addAll(List.of("--ui-bundle-url", antoraTask.getUiBundleUrl()));
+ arguments.add(playbookPath);
+ return arguments;
+ }
+
+ private void logWarningIfNodeModulesInUserHome(Project project) {
+ if (new File(System.getProperty("user.home"), "node_modules").exists()) {
+ project.getLogger()
+ .warn("Detected the existence of $HOME/node_modules. This directory is "
+ + "not compatible with this plugin. Please remove it.");
+ }
+ }
+
+ private String getUiBundleUrl(Project project) {
+ try {
+ File packageJson = project.getRootProject().file("antora/package.json");
+ ObjectMapper objectMapper = new ObjectMapper();
+ Map, ?> json = objectMapper.readerFor(Map.class).readValue(packageJson);
+ Map, ?> config = (json != null) ? (Map, ?>) json.get("config") : null;
+ String url = (config != null) ? (String) config.get("ui-bundle-url") : null;
+ Assert.state(StringUtils.hasText(url.toString()), "package.json has not ui-bundle-url config");
+ return url;
+ }
+ catch (IOException ex) {
+ throw new UncheckedIOException(ex);
+ }
+ }
+
+ private void configureNodeExtension(Project project, NodeExtension nodeExtension) {
+ File buildDir = project.getBuildDir();
+ nodeExtension.getWorkDir().set(buildDir.toPath().resolve(".gradle/nodejs").toFile());
+ nodeExtension.getNpmWorkDir().set(buildDir.toPath().resolve(".gradle/npm").toFile());
+ nodeExtension.getNodeProjectDir().set(getNodeProjectDir(buildDir));
+ }
+
+ private File getNodeProjectDir(File buildDir) {
+ return buildDir.toPath().resolve(".gradle/nodeproject").toFile();
+ }
+
+}
diff --git a/buildSrc/src/main/java/org/springframework/boot/build/AsciidoctorConventions.java b/buildSrc/src/main/java/org/springframework/boot/build/AsciidoctorConventions.java
deleted file mode 100644
index 537ff277f739..000000000000
--- a/buildSrc/src/main/java/org/springframework/boot/build/AsciidoctorConventions.java
+++ /dev/null
@@ -1,159 +0,0 @@
-/*
- * Copyright 2012-2023 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.springframework.boot.build;
-
-import java.io.File;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.Map;
-
-import org.asciidoctor.gradle.jvm.AbstractAsciidoctorTask;
-import org.asciidoctor.gradle.jvm.AsciidoctorJExtension;
-import org.asciidoctor.gradle.jvm.AsciidoctorJPlugin;
-import org.asciidoctor.gradle.jvm.AsciidoctorTask;
-import org.gradle.api.JavaVersion;
-import org.gradle.api.Project;
-import org.gradle.api.tasks.PathSensitivity;
-import org.gradle.api.tasks.Sync;
-
-import org.springframework.boot.build.artifacts.ArtifactRelease;
-import org.springframework.util.StringUtils;
-
-/**
- * Conventions that are applied in the presence of the {@link AsciidoctorJPlugin}. When
- * the plugin is applied:
- *
- *
- * All warnings are made fatal.
- * The version of AsciidoctorJ is upgraded to 2.4.3.
- * An {@code asciidoctorExtensions} configuration is created.
- * For each {@link AsciidoctorTask} (HTML only):
- *
- * A task is created to sync the documentation resources to its output directory.
- * {@code doctype} {@link AsciidoctorTask#options(Map) option} is configured.
- * The {@code backend} is configured.
- *
- * For each {@link AbstractAsciidoctorTask} (HTML and PDF):
- *
- * {@link AsciidoctorTask#attributes(Map) Attributes} are configured to enable
- * warnings for references to missing attributes, the GitHub tag, the Artifactory repo for
- * the current version, etc.
- * {@link AbstractAsciidoctorTask#baseDirFollowsSourceDir() baseDirFollowsSourceDir()}
- * is enabled.
- * {@code asciidoctorExtensions} is added to the task's configurations.
- *
- *
- *
- * @author Andy Wilkinson
- * @author Scott Frederick
- */
-class AsciidoctorConventions {
-
- private static final String ASCIIDOCTORJ_VERSION = "2.4.3";
-
- private static final String EXTENSIONS_CONFIGURATION_NAME = "asciidoctorExtensions";
-
- void apply(Project project) {
- project.getPlugins().withType(AsciidoctorJPlugin.class, (asciidoctorPlugin) -> {
- makeAllWarningsFatal(project);
- upgradeAsciidoctorJVersion(project);
- createAsciidoctorExtensionsConfiguration(project);
- project.getTasks()
- .withType(AbstractAsciidoctorTask.class,
- (asciidoctorTask) -> configureAsciidoctorTask(project, asciidoctorTask));
- });
- }
-
- private void makeAllWarningsFatal(Project project) {
- project.getExtensions().getByType(AsciidoctorJExtension.class).fatalWarnings(".*");
- }
-
- private void upgradeAsciidoctorJVersion(Project project) {
- project.getExtensions().getByType(AsciidoctorJExtension.class).setVersion(ASCIIDOCTORJ_VERSION);
- }
-
- private void createAsciidoctorExtensionsConfiguration(Project project) {
- project.getConfigurations().create(EXTENSIONS_CONFIGURATION_NAME, (configuration) -> {
- project.getConfigurations()
- .matching((candidate) -> "dependencyManagement".equals(candidate.getName()))
- .all(configuration::extendsFrom);
- configuration.getDependencies()
- .add(project.getDependencies()
- .create("io.spring.asciidoctor.backends:spring-asciidoctor-backends:0.0.5"));
- configuration.getDependencies()
- .add(project.getDependencies().create("org.asciidoctor:asciidoctorj-pdf:1.5.3"));
- });
- }
-
- private void configureAsciidoctorTask(Project project, AbstractAsciidoctorTask asciidoctorTask) {
- asciidoctorTask.configurations(EXTENSIONS_CONFIGURATION_NAME);
- configureCommonAttributes(project, asciidoctorTask);
- configureOptions(asciidoctorTask);
- configureForkOptions(asciidoctorTask);
- asciidoctorTask.baseDirFollowsSourceDir();
- createSyncDocumentationSourceTask(project, asciidoctorTask);
- if (asciidoctorTask instanceof AsciidoctorTask task) {
- boolean pdf = task.getName().toLowerCase().contains("pdf");
- String backend = (!pdf) ? "spring-html" : "spring-pdf";
- task.outputOptions((outputOptions) -> outputOptions.backends(backend));
- }
- }
-
- private void configureCommonAttributes(Project project, AbstractAsciidoctorTask asciidoctorTask) {
- ArtifactRelease artifacts = ArtifactRelease.forProject(project);
- Map attributes = new HashMap<>();
- attributes.put("attribute-missing", "warn");
- attributes.put("github-tag", determineGitHubTag(project));
- attributes.put("artifact-release-type", artifacts.getType());
- attributes.put("artifact-download-repo", artifacts.getDownloadRepo());
- attributes.put("revnumber", null);
- asciidoctorTask.attributes(attributes);
- }
-
- // See https://github.com/asciidoctor/asciidoctor-gradle-plugin/issues/597
- private void configureForkOptions(AbstractAsciidoctorTask asciidoctorTask) {
- if (JavaVersion.current().isCompatibleWith(JavaVersion.VERSION_16)) {
- asciidoctorTask.forkOptions((options) -> options.jvmArgs("--add-opens", "java.base/sun.nio.ch=ALL-UNNAMED",
- "--add-opens", "java.base/java.io=ALL-UNNAMED"));
- }
- }
-
- private String determineGitHubTag(Project project) {
- String version = "v" + project.getVersion();
- return (version.endsWith("-SNAPSHOT")) ? "3.1.x" : version;
- }
-
- private void configureOptions(AbstractAsciidoctorTask asciidoctorTask) {
- asciidoctorTask.options(Collections.singletonMap("doctype", "book"));
- }
-
- private Sync createSyncDocumentationSourceTask(Project project, AbstractAsciidoctorTask asciidoctorTask) {
- Sync syncDocumentationSource = project.getTasks()
- .create("syncDocumentationSourceFor" + StringUtils.capitalize(asciidoctorTask.getName()), Sync.class);
- File syncedSource = new File(project.getBuildDir(), "docs/src/" + asciidoctorTask.getName());
- syncDocumentationSource.setDestinationDir(syncedSource);
- syncDocumentationSource.from("src/docs/");
- asciidoctorTask.dependsOn(syncDocumentationSource);
- asciidoctorTask.getInputs()
- .dir(syncedSource)
- .withPathSensitivity(PathSensitivity.RELATIVE)
- .withPropertyName("synced source");
- asciidoctorTask.setSourceDir(project.relativePath(new File(syncedSource, "asciidoc/")));
- return syncDocumentationSource;
- }
-
-}
diff --git a/buildSrc/src/main/java/org/springframework/boot/build/ConventionsPlugin.java b/buildSrc/src/main/java/org/springframework/boot/build/ConventionsPlugin.java
index 8a50535a4365..8b4769be00e0 100644
--- a/buildSrc/src/main/java/org/springframework/boot/build/ConventionsPlugin.java
+++ b/buildSrc/src/main/java/org/springframework/boot/build/ConventionsPlugin.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2012-2023 the original author or authors.
+ * Copyright 2012-2024 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -16,7 +16,7 @@
package org.springframework.boot.build;
-import org.asciidoctor.gradle.jvm.AsciidoctorJPlugin;
+import org.antora.gradle.AntoraPlugin;
import org.gradle.api.Plugin;
import org.gradle.api.Project;
import org.gradle.api.plugins.JavaBasePlugin;
@@ -32,8 +32,8 @@
* When the {@link MavenPublishPlugin} is applied, the conventions in
* {@link MavenPublishingConventions} are applied.
*
- * When the {@link AsciidoctorJPlugin} is applied, the conventions in
- * {@link AsciidoctorConventions} are applied.
+ * When the {@link AntoraPlugin} is applied, the conventions in {@link AntoraConventions}
+ * are applied.
*
* @author Andy Wilkinson
* @author Christoph Dreis
@@ -43,9 +43,10 @@ public class ConventionsPlugin implements Plugin {
@Override
public void apply(Project project) {
+ new NoHttpConventions().apply(project);
new JavaConventions().apply(project);
new MavenPublishingConventions().apply(project);
- new AsciidoctorConventions().apply(project);
+ new AntoraConventions().apply(project);
new KotlinConventions().apply(project);
new WarConventions().apply(project);
new EclipseConventions().apply(project);
diff --git a/buildSrc/src/main/java/org/springframework/boot/build/ExtractResources.java b/buildSrc/src/main/java/org/springframework/boot/build/ExtractResources.java
index 78473cec471f..35e295b4aaf2 100644
--- a/buildSrc/src/main/java/org/springframework/boot/build/ExtractResources.java
+++ b/buildSrc/src/main/java/org/springframework/boot/build/ExtractResources.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2012-2022 the original author or authors.
+ * Copyright 2012-2024 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -21,15 +21,13 @@
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
import org.gradle.api.DefaultTask;
import org.gradle.api.GradleException;
import org.gradle.api.Task;
import org.gradle.api.file.DirectoryProperty;
+import org.gradle.api.provider.ListProperty;
+import org.gradle.api.provider.MapProperty;
import org.gradle.api.tasks.Input;
import org.gradle.api.tasks.OutputDirectory;
import org.gradle.api.tasks.TaskAction;
@@ -42,54 +40,30 @@
*
* @author Andy Wilkinson
*/
-public class ExtractResources extends DefaultTask {
+public abstract class ExtractResources extends DefaultTask {
private final PropertyPlaceholderHelper propertyPlaceholderHelper = new PropertyPlaceholderHelper("${", "}");
- private final Map properties = new HashMap<>();
-
- private final DirectoryProperty destinationDirectory;
-
- private List resourceNames = new ArrayList<>();
-
- public ExtractResources() {
- this.destinationDirectory = getProject().getObjects().directoryProperty();
- }
-
@Input
- public List getResourceNames() {
- return this.resourceNames;
- }
-
- public void setResourcesNames(List resourceNames) {
- this.resourceNames = resourceNames;
- }
+ public abstract ListProperty getResourceNames();
@OutputDirectory
- public DirectoryProperty getDestinationDirectory() {
- return this.destinationDirectory;
- }
-
- public void property(String name, String value) {
- this.properties.put(name, value);
- }
+ public abstract DirectoryProperty getDestinationDirectory();
@Input
- public Map getProperties() {
- return this.properties;
- }
+ public abstract MapProperty getProperties();
@TaskAction
void extractResources() throws IOException {
- for (String resourceName : this.resourceNames) {
+ for (String resourceName : getResourceNames().get()) {
InputStream resourceStream = getClass().getClassLoader().getResourceAsStream(resourceName);
if (resourceStream == null) {
throw new GradleException("Resource '" + resourceName + "' does not exist");
}
String resource = FileCopyUtils.copyToString(new InputStreamReader(resourceStream, StandardCharsets.UTF_8));
- resource = this.propertyPlaceholderHelper.replacePlaceholders(resource, this.properties::get);
+ resource = this.propertyPlaceholderHelper.replacePlaceholders(resource, getProperties().get()::get);
FileCopyUtils.copy(resource,
- new FileWriter(this.destinationDirectory.file(resourceName).get().getAsFile()));
+ new FileWriter(getDestinationDirectory().file(resourceName).get().getAsFile()));
}
}
diff --git a/buildSrc/src/main/java/org/springframework/boot/build/JavaConventions.java b/buildSrc/src/main/java/org/springframework/boot/build/JavaConventions.java
index fc59efaec9b2..e5ce6df4244f 100644
--- a/buildSrc/src/main/java/org/springframework/boot/build/JavaConventions.java
+++ b/buildSrc/src/main/java/org/springframework/boot/build/JavaConventions.java
@@ -129,8 +129,8 @@ private void configureJarManifestConventions(Project project) {
ExtractResources extractLegalResources = project.getTasks()
.create("extractLegalResources", ExtractResources.class);
extractLegalResources.getDestinationDirectory().set(project.getLayout().getBuildDirectory().dir("legal"));
- extractLegalResources.setResourcesNames(Arrays.asList("LICENSE.txt", "NOTICE.txt"));
- extractLegalResources.property("version", project.getVersion().toString());
+ extractLegalResources.getResourceNames().set(Arrays.asList("LICENSE.txt", "NOTICE.txt"));
+ extractLegalResources.getProperties().put("version", project.getVersion().toString());
SourceSetContainer sourceSets = project.getExtensions().getByType(SourceSetContainer.class);
Set sourceJarTaskNames = sourceSets.stream()
.map(SourceSet::getSourcesJarTaskName)
@@ -261,8 +261,9 @@ private void configureDependencyManagement(Project project) {
configuration.setCanBeResolved(false);
});
configurations
- .matching((configuration) -> configuration.getName().endsWith("Classpath")
+ .matching((configuration) -> (configuration.getName().endsWith("Classpath")
|| JavaPlugin.ANNOTATION_PROCESSOR_CONFIGURATION_NAME.equals(configuration.getName()))
+ && (!configuration.getName().contains("dokkatoo")))
.all((configuration) -> configuration.extendsFrom(dependencyManagement));
Dependency springBootParent = project.getDependencies()
.enforcedPlatform(project.getDependencies()
diff --git a/buildSrc/src/main/java/org/springframework/boot/build/KotlinConventions.java b/buildSrc/src/main/java/org/springframework/boot/build/KotlinConventions.java
index c5e896160b47..9975dcfca550 100644
--- a/buildSrc/src/main/java/org/springframework/boot/build/KotlinConventions.java
+++ b/buildSrc/src/main/java/org/springframework/boot/build/KotlinConventions.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2012-2023 the original author or authors.
+ * Copyright 2012-2024 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -16,10 +16,15 @@
package org.springframework.boot.build;
+import java.net.URI;
import java.util.ArrayList;
import java.util.List;
+import dev.adamko.dokkatoo.DokkatooExtension;
+import dev.adamko.dokkatoo.formats.DokkatooHtmlPlugin;
import org.gradle.api.Project;
+import org.gradle.api.tasks.SourceSet;
+import org.gradle.api.tasks.SourceSetContainer;
import org.jetbrains.kotlin.gradle.dsl.KotlinJvmOptions;
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile;
@@ -44,9 +49,10 @@
class KotlinConventions {
void apply(Project project) {
- project.getPlugins()
- .withId("org.jetbrains.kotlin.jvm",
- (plugin) -> project.getTasks().withType(KotlinCompile.class, this::configure));
+ project.getPlugins().withId("org.jetbrains.kotlin.jvm", (plugin) -> {
+ project.getTasks().withType(KotlinCompile.class, this::configure);
+ configureDokkatoo(project);
+ });
}
private void configure(KotlinCompile compile) {
@@ -60,4 +66,27 @@ private void configure(KotlinCompile compile) {
compile.getKotlinOptions().setFreeCompilerArgs(freeCompilerArgs);
}
+ private void configureDokkatoo(Project project) {
+ project.getPlugins().apply(DokkatooHtmlPlugin.class);
+ DokkatooExtension dokkatoo = project.getExtensions().getByType(DokkatooExtension.class);
+ dokkatoo.getDokkatooSourceSets().named(SourceSet.MAIN_SOURCE_SET_NAME).configure((sourceSet) -> {
+ sourceSet.getSourceRoots().setFrom(project.file("src/main/kotlin"));
+ sourceSet.getClasspath()
+ .from(project.getExtensions()
+ .getByType(SourceSetContainer.class)
+ .getByName(SourceSet.MAIN_SOURCE_SET_NAME)
+ .getOutput());
+ sourceSet.getExternalDocumentationLinks().create("spring-boot-javadoc", (link) -> {
+ link.getUrl().set(URI.create("https://docs.spring.io/spring-boot/api/java/"));
+ link.getPackageListUrl().set(URI.create("https://docs.spring.io/spring-boot/api/java/element-list"));
+ });
+ sourceSet.getExternalDocumentationLinks().create("spring-framework-javadoc", (link) -> {
+ String url = "https://docs.spring.io/spring-framework/docs/%s/javadoc-api/"
+ .formatted(project.property("springFrameworkVersion"));
+ link.getUrl().set(URI.create(url));
+ link.getPackageListUrl().set(URI.create(url + "/element-list"));
+ });
+ });
+ }
+
}
diff --git a/buildSrc/src/main/java/org/springframework/boot/build/MavenPublishingConventions.java b/buildSrc/src/main/java/org/springframework/boot/build/MavenPublishingConventions.java
index fc1f5cb357dc..53ddea4f2edf 100644
--- a/buildSrc/src/main/java/org/springframework/boot/build/MavenPublishingConventions.java
+++ b/buildSrc/src/main/java/org/springframework/boot/build/MavenPublishingConventions.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2012-2023 the original author or authors.
+ * Copyright 2012-2024 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -19,8 +19,6 @@
import org.apache.maven.artifact.repository.MavenArtifactRepository;
import org.gradle.api.Project;
import org.gradle.api.attributes.Usage;
-import org.gradle.api.component.AdhocComponentWithVariants;
-import org.gradle.api.component.ConfigurationVariantDetails;
import org.gradle.api.plugins.JavaPlugin;
import org.gradle.api.plugins.JavaPluginExtension;
import org.gradle.api.publish.PublishingExtension;
@@ -83,7 +81,6 @@ private void customizeMavenPublication(MavenPublication publication, Project pro
project.getPlugins()
.withType(JavaPlugin.class)
.all((javaPlugin) -> customizeJavaMavenPublication(publication, project));
- suppressMavenOptionalFeatureWarnings(publication);
}
private void customizePom(MavenPom pom, Project project) {
@@ -102,34 +99,12 @@ private void customizePom(MavenPom pom, Project project) {
}
private void customizeJavaMavenPublication(MavenPublication publication, Project project) {
- addMavenOptionalFeature(project);
publication.versionMapping((strategy) -> strategy.usage(Usage.JAVA_API, (mappingStrategy) -> mappingStrategy
.fromResolutionOf(JavaPlugin.RUNTIME_CLASSPATH_CONFIGURATION_NAME)));
publication.versionMapping(
(strategy) -> strategy.usage(Usage.JAVA_RUNTIME, VariantVersionMappingStrategy::fromResolutionResult));
}
- /**
- * Add a feature that allows maven plugins to declare optional dependencies that
- * appear in the POM. This is required to make m2e in Eclipse happy.
- * @param project the project to add the feature to
- */
- private void addMavenOptionalFeature(Project project) {
- JavaPluginExtension extension = project.getExtensions().getByType(JavaPluginExtension.class);
- extension.registerFeature("mavenOptional",
- (feature) -> feature.usingSourceSet(extension.getSourceSets().getByName("main")));
- AdhocComponentWithVariants javaComponent = (AdhocComponentWithVariants) project.getComponents()
- .findByName("java");
- javaComponent.addVariantsFromConfiguration(
- project.getConfigurations().findByName("mavenOptionalRuntimeElements"),
- ConfigurationVariantDetails::mapToOptional);
- }
-
- private void suppressMavenOptionalFeatureWarnings(MavenPublication publication) {
- publication.suppressPomMetadataWarningsFor("mavenOptionalApiElements");
- publication.suppressPomMetadataWarningsFor("mavenOptionalRuntimeElements");
- }
-
private void customizeOrganization(MavenPomOrganization organization) {
organization.getName().set("VMware, Inc.");
organization.getUrl().set("https://spring.io");
diff --git a/buildSrc/src/main/java/org/springframework/boot/build/NoHttpConventions.java b/buildSrc/src/main/java/org/springframework/boot/build/NoHttpConventions.java
new file mode 100644
index 000000000000..7b4847ff2aec
--- /dev/null
+++ b/buildSrc/src/main/java/org/springframework/boot/build/NoHttpConventions.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2012-2024 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.boot.build;
+
+import io.spring.nohttp.gradle.NoHttpCheckstylePlugin;
+import io.spring.nohttp.gradle.NoHttpExtension;
+import org.gradle.api.Project;
+import org.gradle.api.file.ConfigurableFileTree;
+import org.gradle.api.plugins.quality.Checkstyle;
+
+/**
+ * Conventions that are applied to enforce that no HTTP urls are used.
+ *
+ * @author Phillip Webb
+ */
+public class NoHttpConventions {
+
+ void apply(Project project) {
+ project.getPluginManager().apply(NoHttpCheckstylePlugin.class);
+ configureNoHttpExtension(project, project.getExtensions().getByType(NoHttpExtension.class));
+ project.getTasks()
+ .named(NoHttpCheckstylePlugin.CHECKSTYLE_NOHTTP_TASK_NAME, Checkstyle.class)
+ .configure((task) -> task.getConfigDirectory().set(project.getRootProject().file("src/nohttp")));
+ }
+
+ private void configureNoHttpExtension(Project project, NoHttpExtension extension) {
+ extension.setAllowlistFile(project.getRootProject().file("src/nohttp/allowlist.lines"));
+ ConfigurableFileTree source = extension.getSource();
+ source.exclude("bin/**");
+ source.exclude("build/**");
+ source.exclude("out/**");
+ source.exclude("target/**");
+ source.exclude(".settings/**");
+ source.exclude(".classpath");
+ source.exclude(".project");
+ source.exclude(".gradle");
+ source.exclude("**/docker/export.tar");
+ }
+
+}
diff --git a/buildSrc/src/main/java/org/springframework/boot/build/SyncAppSource.java b/buildSrc/src/main/java/org/springframework/boot/build/SyncAppSource.java
index 5a863d221a74..ae318adf0f84 100644
--- a/buildSrc/src/main/java/org/springframework/boot/build/SyncAppSource.java
+++ b/buildSrc/src/main/java/org/springframework/boot/build/SyncAppSource.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2021-2023 the original author or authors.
+ * Copyright 2021-2024 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -18,7 +18,6 @@
import org.gradle.api.DefaultTask;
import org.gradle.api.file.DirectoryProperty;
-import org.gradle.api.model.ObjectFactory;
import org.gradle.api.provider.Property;
import org.gradle.api.tasks.Input;
import org.gradle.api.tasks.InputDirectory;
@@ -31,45 +30,29 @@
*
* @author Andy Wilkinson
*/
-public class SyncAppSource extends DefaultTask {
+public abstract class SyncAppSource extends DefaultTask {
- private final DirectoryProperty sourceDirectory;
+ public SyncAppSource() {
+ getPluginVersion().convention(getProject().provider(() -> getProject().getVersion().toString()));
+ }
- private final DirectoryProperty destinationDirectory;
+ @InputDirectory
+ public abstract DirectoryProperty getSourceDirectory();
- private final Property pluginVersion;
+ @OutputDirectory
+ public abstract DirectoryProperty getDestinationDirectory();
- public SyncAppSource() {
- ObjectFactory objects = getProject().getObjects();
- this.sourceDirectory = objects.directoryProperty();
- this.destinationDirectory = objects.directoryProperty();
- this.pluginVersion = objects.property(String.class)
- .convention(getProject().provider(() -> getProject().getVersion().toString()));
- }
+ @Input
+ public abstract Property getPluginVersion();
@TaskAction
void syncAppSources() {
getProject().sync((copySpec) -> {
- copySpec.from(this.sourceDirectory);
- copySpec.into(this.destinationDirectory);
+ copySpec.from(getSourceDirectory());
+ copySpec.into(getDestinationDirectory());
copySpec.filter((line) -> line.replace("id \"org.springframework.boot\"",
"id \"org.springframework.boot\" version \"" + getProject().getVersion() + "\""));
});
}
- @InputDirectory
- public DirectoryProperty getSourceDirectory() {
- return this.sourceDirectory;
- }
-
- @OutputDirectory
- public DirectoryProperty getDestinationDirectory() {
- return this.destinationDirectory;
- }
-
- @Input
- public Property getPluginVersion() {
- return this.pluginVersion;
- }
-
}
diff --git a/buildSrc/src/main/java/org/springframework/boot/build/antora/AntoraAsciidocAttributes.java b/buildSrc/src/main/java/org/springframework/boot/build/antora/AntoraAsciidocAttributes.java
new file mode 100644
index 000000000000..3d5bec724ae7
--- /dev/null
+++ b/buildSrc/src/main/java/org/springframework/boot/build/antora/AntoraAsciidocAttributes.java
@@ -0,0 +1,162 @@
+/*
+ * Copyright 2012-2024 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.boot.build.antora;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.UncheckedIOException;
+import java.util.Collections;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+
+import org.gradle.api.Project;
+
+import org.springframework.boot.build.artifacts.ArtifactRelease;
+import org.springframework.boot.build.bom.BomExtension;
+import org.springframework.boot.build.bom.Library;
+import org.springframework.util.Assert;
+
+/**
+ * Generates Asciidoctor attributes for use with Antora.
+ *
+ * @author Phillip Webb
+ */
+public class AntoraAsciidocAttributes {
+
+ private static final String DASH_SNAPSHOT = "-SNAPSHOT";
+
+ private final String version;
+
+ private final boolean latestVersion;
+
+ private final ArtifactRelease artifactRelease;
+
+ private final List libraries;
+
+ private final Map dependencyVersions;
+
+ private final Map projectProperties;
+
+ public AntoraAsciidocAttributes(Project project, BomExtension dependencyBom,
+ Map dependencyVersions) {
+ this.version = String.valueOf(project.getVersion());
+ this.latestVersion = Boolean.parseBoolean(String.valueOf(project.findProperty("latestVersion")));
+ this.artifactRelease = ArtifactRelease.forProject(project);
+ this.libraries = dependencyBom.getLibraries();
+ this.dependencyVersions = dependencyVersions;
+ this.projectProperties = project.getProperties();
+ }
+
+ AntoraAsciidocAttributes(String version, boolean latestVersion, List libraries,
+ Map dependencyVersions, Map projectProperties) {
+ this.version = version;
+ this.latestVersion = latestVersion;
+ this.artifactRelease = ArtifactRelease.forVersion(version);
+ this.libraries = (libraries != null) ? libraries : Collections.emptyList();
+ this.dependencyVersions = (dependencyVersions != null) ? dependencyVersions : Collections.emptyMap();
+ this.projectProperties = (projectProperties != null) ? projectProperties : Collections.emptyMap();
+ }
+
+ public Map get() {
+ Map attributes = new LinkedHashMap<>();
+ addGitHubAttributes(attributes);
+ addVersionAttributes(attributes);
+ addUrlArtifactRepository(attributes);
+ addUrlLibraryLinkAttributes(attributes);
+ addPropertyAttributes(attributes);
+ return attributes;
+ }
+
+ private void addGitHubAttributes(Map attributes) {
+ attributes.put("github-repo", "spring-projects/spring-boot");
+ attributes.put("github-ref", determineGitHubRef());
+ }
+
+ private String determineGitHubRef() {
+ int snapshotIndex = this.version.lastIndexOf(DASH_SNAPSHOT);
+ if (snapshotIndex == -1) {
+ return "v" + this.version;
+ }
+ if (this.latestVersion) {
+ return "main";
+ }
+ String versionRoot = this.version.substring(0, snapshotIndex);
+ int lastDot = versionRoot.lastIndexOf('.');
+ return versionRoot.substring(0, lastDot) + ".x";
+ }
+
+ private void addVersionAttributes(Map attributes) {
+ this.libraries.forEach((library) -> {
+ String name = "version-" + library.getLinkRootName();
+ String value = library.getVersion().toString();
+ attributes.put(name, value);
+ });
+ attributes.put("version-native-build-tools", (String) this.projectProperties.get("nativeBuildToolsVersion"));
+ attributes.put("version-graal", (String) this.projectProperties.get("graalVersion"));
+ addSpringDataDependencyVersion(attributes, "spring-data-commons");
+ addSpringDataDependencyVersion(attributes, "spring-data-couchbase");
+ addSpringDataDependencyVersion(attributes, "spring-data-elasticsearch");
+ addSpringDataDependencyVersion(attributes, "spring-data-jdbc");
+ addSpringDataDependencyVersion(attributes, "spring-data-jpa");
+ addSpringDataDependencyVersion(attributes, "spring-data-mongodb");
+ addSpringDataDependencyVersion(attributes, "spring-data-neo4j");
+ addSpringDataDependencyVersion(attributes, "spring-data-r2dbc");
+ addSpringDataDependencyVersion(attributes, "spring-data-rest", "spring-data-rest-core");
+ }
+
+ private void addSpringDataDependencyVersion(Map attributes, String artifactId) {
+ addSpringDataDependencyVersion(attributes, artifactId, artifactId);
+ }
+
+ private void addSpringDataDependencyVersion(Map attributes, String name, String artifactId) {
+ String version = this.dependencyVersions.get("org.springframework.data:" + artifactId);
+ Assert.notNull(version, () -> "No version found for Spring Data artifact " + artifactId);
+ attributes.put("version-" + name, version);
+ }
+
+ private void addUrlArtifactRepository(Map attributes) {
+ attributes.put("url-artifact-repository", this.artifactRelease.getDownloadRepo());
+ }
+
+ private void addUrlLibraryLinkAttributes(Map attributes) {
+ this.libraries.forEach((library) -> {
+ String prefix = "url-" + library.getLinkRootName() + "-";
+ library.getLinks().forEach((name, link) -> attributes.put(prefix + name, link));
+ });
+ }
+
+ private void addPropertyAttributes(Map attributes) {
+ Properties properties = new Properties() {
+
+ @Override
+ public synchronized Object put(Object key, Object value) {
+ // Put directly because order is important for us
+ return attributes.put(key.toString(), value.toString());
+ }
+
+ };
+ try (InputStream in = getClass().getResourceAsStream("antora-asciidoc-attributes.properties")) {
+ properties.load(in);
+ }
+ catch (IOException ex) {
+ throw new UncheckedIOException(ex);
+ }
+ }
+
+}
diff --git a/buildSrc/src/main/java/org/springframework/boot/build/antora/Extensions.java b/buildSrc/src/main/java/org/springframework/boot/build/antora/Extensions.java
new file mode 100644
index 000000000000..8234edfea98a
--- /dev/null
+++ b/buildSrc/src/main/java/org/springframework/boot/build/antora/Extensions.java
@@ -0,0 +1,190 @@
+/*
+ * Copyright 2012-2024 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.boot.build.antora;
+
+import java.nio.file.Path;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.TreeMap;
+import java.util.function.Consumer;
+import java.util.stream.Stream;
+
+/**
+ * Antora and Asciidoc extensions used by Spring Boot.
+ *
+ * @author Phillip Webb
+ */
+public final class Extensions {
+
+ private static final String ROOT_COMPONENT_EXTENSION = "@springio/antora-extensions/root-component-extension";
+
+ private static final List antora;
+ static {
+ List extensions = new ArrayList<>();
+ extensions.add(new Extension("@springio/antora-extensions", ROOT_COMPONENT_EXTENSION,
+ "@springio/antora-extensions/static-page-extension",
+ "@springio/antora-extensions/override-navigation-builder-extension"));
+ extensions.add(new Extension("@springio/antora-xref-extension"));
+ extensions.add(new Extension("@springio/antora-zip-contents-collector-extension"));
+ antora = List.copyOf(extensions);
+ }
+
+ private static final List asciidoc;
+ static {
+ List extensions = new ArrayList<>();
+ extensions.add(new Extension("@asciidoctor/tabs"));
+ extensions.add(new Extension("@springio/asciidoctor-extensions", "@springio/asciidoctor-extensions",
+ "@springio/asciidoctor-extensions/configuration-properties-extension",
+ "@springio/asciidoctor-extensions/section-ids-extension"));
+ asciidoc = List.copyOf(extensions);
+ }
+
+ private static final Map localOverrides = Collections.emptyMap();
+
+ private Extensions() {
+ }
+
+ static List> antora(Consumer extensions) {
+ AntoraExtensionsConfiguration result = new AntoraExtensionsConfiguration(
+ antora.stream().flatMap(Extension::names).sorted().toList());
+ extensions.accept(result);
+ return result.config();
+ }
+
+ static List asciidoc() {
+ return asciidoc.stream().flatMap(Extension::names).sorted().toList();
+ }
+
+ private record Extension(String name, String... includeNames) {
+
+ Stream names() {
+ return (this.includeNames.length != 0) ? Arrays.stream(this.includeNames) : Stream.of(this.name);
+ }
+
+ }
+
+ static final class AntoraExtensionsConfiguration {
+
+ private Map> extensions = new TreeMap<>();
+
+ private AntoraExtensionsConfiguration(List names) {
+ names.forEach((name) -> this.extensions.put(name, null));
+ }
+
+ void xref(Consumer xref) {
+ xref.accept(new Xref());
+ }
+
+ void zipContentsCollector(Consumer zipContentsCollector) {
+ zipContentsCollector.accept(new ZipContentsCollector());
+ }
+
+ void rootComponent(Consumer rootComponent) {
+ rootComponent.accept(new RootComponent());
+ }
+
+ List> config() {
+ List> config = new ArrayList<>();
+ Map> orderedExtensions = new LinkedHashMap<>(this.extensions);
+ // The root component extension must be last
+ Map rootComponentConfig = orderedExtensions.remove(ROOT_COMPONENT_EXTENSION);
+ orderedExtensions.put(ROOT_COMPONENT_EXTENSION, rootComponentConfig);
+ orderedExtensions.forEach((name, customizations) -> {
+ Map extensionConfig = new LinkedHashMap<>();
+ extensionConfig.put("require", localOverrides.getOrDefault(name, name));
+ if (customizations != null) {
+ extensionConfig.putAll(customizations);
+ }
+ config.add(extensionConfig);
+ });
+ return List.copyOf(config);
+ }
+
+ abstract class Customizer {
+
+ private final String name;
+
+ Customizer(String name) {
+ this.name = name;
+ }
+
+ protected void customize(String key, Object value) {
+ AntoraExtensionsConfiguration.this.extensions.computeIfAbsent(this.name, (name) -> new TreeMap<>())
+ .put(key, value);
+ }
+
+ }
+
+ class Xref extends Customizer {
+
+ Xref() {
+ super("@springio/antora-xref-extension");
+ }
+
+ void stub(List stub) {
+ if (stub != null && !stub.isEmpty()) {
+ customize("stub", stub);
+ }
+ }
+
+ }
+
+ class ZipContentsCollector extends Customizer {
+
+ ZipContentsCollector() {
+ super("@springio/antora-zip-contents-collector-extension");
+ }
+
+ void versionFile(String versionFile) {
+ customize("version_file", versionFile);
+ }
+
+ void locations(Path... locations) {
+ locations(Arrays.stream(locations).map(Path::toString).toList());
+ }
+
+ private void locations(List locations) {
+ customize("locations", locations);
+ }
+
+ void alwaysInclude(Map alwaysInclude) {
+ if (alwaysInclude != null && !alwaysInclude.isEmpty()) {
+ customize("always_include", List.of(new TreeMap<>(alwaysInclude)));
+ }
+ }
+
+ }
+
+ class RootComponent extends Customizer {
+
+ RootComponent() {
+ super(ROOT_COMPONENT_EXTENSION);
+ }
+
+ void name(String name) {
+ customize("root_component_name", name);
+ }
+
+ }
+
+ }
+
+}
diff --git a/buildSrc/src/main/java/org/springframework/boot/build/antora/GenerateAntoraPlaybook.java b/buildSrc/src/main/java/org/springframework/boot/build/antora/GenerateAntoraPlaybook.java
new file mode 100644
index 000000000000..f5dd4d80936e
--- /dev/null
+++ b/buildSrc/src/main/java/org/springframework/boot/build/antora/GenerateAntoraPlaybook.java
@@ -0,0 +1,209 @@
+/*
+ * Copyright 2012-2024 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.boot.build.antora;
+
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.UncheckedIOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.Collections;
+import java.util.LinkedHashMap;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.gradle.api.DefaultTask;
+import org.gradle.api.Project;
+import org.gradle.api.artifacts.Configuration;
+import org.gradle.api.artifacts.ProjectDependency;
+import org.gradle.api.file.RegularFileProperty;
+import org.gradle.api.provider.ListProperty;
+import org.gradle.api.provider.MapProperty;
+import org.gradle.api.provider.Property;
+import org.gradle.api.tasks.Input;
+import org.gradle.api.tasks.Optional;
+import org.gradle.api.tasks.OutputFile;
+import org.gradle.api.tasks.TaskAction;
+import org.yaml.snakeyaml.DumperOptions;
+import org.yaml.snakeyaml.Yaml;
+
+/**
+ * Task to generate a local Antora playbook.
+ *
+ * @author Phillip Webb
+ */
+public abstract class GenerateAntoraPlaybook extends DefaultTask {
+
+ private static final String ANTORA_SOURCE_DIR = "src/docs/antora";
+
+ private static final String GENERATED_DOCS = "build/generated/docs/";
+
+ @OutputFile
+ public abstract RegularFileProperty getOutputFile();
+
+ @Input
+ public abstract Property getContentSourceConfiguration();
+
+ @Input
+ @Optional
+ public abstract ListProperty getXrefStubs();
+
+ @Input
+ @Optional
+ public abstract MapProperty getAlwaysInclude();
+
+ public GenerateAntoraPlaybook() {
+ setGroup("Documentation");
+ setDescription("Generates an Antora playbook.yml file for local use");
+ getOutputFile().convention(getProject().getLayout()
+ .getBuildDirectory()
+ .file("generated/docs/antora-playbook/antora-playbook.yml"));
+ getContentSourceConfiguration().convention("antoraContent");
+ }
+
+ @TaskAction
+ public void writePlaybookYml() throws IOException {
+ File file = getOutputFile().get().getAsFile();
+ file.getParentFile().mkdirs();
+ try (FileWriter out = new FileWriter(file)) {
+ createYaml().dump(getData(), out);
+ }
+ }
+
+ @Input
+ final Map getData() throws IOException {
+ Map data = loadPlaybookTemplate();
+ addExtensions(data);
+ addSources(data);
+ addDir(data);
+ return data;
+ }
+
+ @SuppressWarnings("unchecked")
+ private Map loadPlaybookTemplate() throws IOException {
+ try (InputStream resource = getClass().getResourceAsStream("antora-playbook-template.yml")) {
+ return createYaml().loadAs(resource, LinkedHashMap.class);
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ private void addExtensions(Map data) {
+ Map antora = (Map) data.get("antora");
+ antora.put("extensions", Extensions.antora((extensions) -> {
+ extensions.xref((xref) -> xref.stub(getXrefStubs().getOrElse(Collections.emptyList())));
+ extensions.zipContentsCollector((zipContentsCollector) -> {
+ zipContentsCollector.versionFile("gradle.properties");
+ String locationName = getProject().getName() + "-${version}-${name}-${classifier}.zip";
+ Path antoraContent = getRelativeProjectPath()
+ .resolve(GENERATED_DOCS + "antora-content/" + locationName);
+ Path antoraDependencies = getRelativeProjectPath()
+ .resolve(GENERATED_DOCS + "antora-dependencies-content/" + locationName);
+ zipContentsCollector.locations(antoraContent, antoraDependencies);
+ zipContentsCollector.alwaysInclude(getAlwaysInclude().getOrNull());
+ });
+ extensions.rootComponent((rootComponent) -> rootComponent.name("boot"));
+ }));
+ Map asciidoc = (Map) data.get("asciidoc");
+ asciidoc.put("extensions", Extensions.asciidoc());
+ }
+
+ private void addSources(Map data) {
+ List> contentSources = getList(data, "content.sources");
+ contentSources.add(createContentSource());
+ }
+
+ private Map createContentSource() {
+ Map source = new LinkedHashMap<>();
+ Path playbookPath = getOutputFile().get().getAsFile().toPath().getParent();
+ Path antoraSrc = getProjectPath(getProject()).resolve(ANTORA_SOURCE_DIR);
+ StringBuilder url = new StringBuilder(".");
+ relativizeFromRootProject(playbookPath).normalize().forEach((path) -> url.append(File.separator).append(".."));
+ source.put("url", url.toString());
+ source.put("branches", "HEAD");
+ source.put("version", getProject().getVersion().toString());
+ Set startPaths = new LinkedHashSet<>();
+ addAntoraContentStartPaths(startPaths);
+ startPaths.add(relativizeFromRootProject(antoraSrc).toString());
+ source.put("start_paths", startPaths.stream().toList());
+ return source;
+ }
+
+ private void addAntoraContentStartPaths(Set startPaths) {
+ Configuration configuration = getProject().getConfigurations().findByName("antoraContent");
+ if (configuration != null) {
+ for (ProjectDependency dependency : configuration.getAllDependencies().withType(ProjectDependency.class)) {
+ Path path = dependency.getDependencyProject().getProjectDir().toPath();
+ startPaths.add(relativizeFromRootProject(path).resolve(ANTORA_SOURCE_DIR).toString());
+ }
+ }
+ }
+
+ private void addDir(Map data) {
+ Path playbookDir = toRealPath(getOutputFile().get().getAsFile().toPath()).getParent();
+ Path outputDir = toRealPath(getProject().getBuildDir().toPath().resolve("site"));
+ data.put("output", Map.of("dir", "." + File.separator + playbookDir.relativize(outputDir).toString()));
+ }
+
+ @SuppressWarnings("unchecked")
+ private List getList(Map data, String location) {
+ return (List) get(data, location);
+ }
+
+ @SuppressWarnings("unchecked")
+ private Object get(Map data, String location) {
+ Object result = data;
+ String[] keys = location.split("\\.");
+ for (String key : keys) {
+ result = ((Map) result).get(key);
+ }
+ return result;
+ }
+
+ private Yaml createYaml() {
+ DumperOptions options = new DumperOptions();
+ options.setDefaultFlowStyle(DumperOptions.FlowStyle.BLOCK);
+ options.setPrettyFlow(true);
+ return new Yaml(options);
+ }
+
+ private Path getRelativeProjectPath() {
+ return relativizeFromRootProject(getProjectPath(getProject()));
+ }
+
+ private Path relativizeFromRootProject(Path subPath) {
+ Path rootProjectPath = getProjectPath(getProject().getRootProject());
+ return rootProjectPath.relativize(subPath).normalize();
+ }
+
+ private Path getProjectPath(Project project) {
+ return toRealPath(project.getProjectDir().toPath());
+ }
+
+ private Path toRealPath(Path path) {
+ try {
+ return Files.exists(path) ? path.toRealPath() : path;
+ }
+ catch (IOException ex) {
+ throw new UncheckedIOException(ex);
+ }
+ }
+
+}
diff --git a/buildSrc/src/main/java/org/springframework/boot/build/architecture/ArchitectureCheck.java b/buildSrc/src/main/java/org/springframework/boot/build/architecture/ArchitectureCheck.java
index d671304708db..c36d46a67502 100644
--- a/buildSrc/src/main/java/org/springframework/boot/build/architecture/ArchitectureCheck.java
+++ b/buildSrc/src/main/java/org/springframework/boot/build/architecture/ArchitectureCheck.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2022-2023 the original author or authors.
+ * Copyright 2022-2024 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -26,12 +26,16 @@
import java.util.stream.Collectors;
import com.tngtech.archunit.base.DescribedPredicate;
+import com.tngtech.archunit.core.domain.JavaCall;
import com.tngtech.archunit.core.domain.JavaClass;
import com.tngtech.archunit.core.domain.JavaClass.Predicates;
import com.tngtech.archunit.core.domain.JavaClasses;
import com.tngtech.archunit.core.domain.JavaMethod;
import com.tngtech.archunit.core.domain.JavaParameter;
import com.tngtech.archunit.core.domain.properties.CanBeAnnotated;
+import com.tngtech.archunit.core.domain.properties.HasName;
+import com.tngtech.archunit.core.domain.properties.HasOwner.Predicates.With;
+import com.tngtech.archunit.core.domain.properties.HasParameterTypes;
import com.tngtech.archunit.core.importer.ClassFileImporter;
import com.tngtech.archunit.lang.ArchCondition;
import com.tngtech.archunit.lang.ArchRule;
@@ -58,11 +62,14 @@
import org.gradle.api.tasks.SkipWhenEmpty;
import org.gradle.api.tasks.TaskAction;
+import org.springframework.util.ResourceUtils;
+
/**
* {@link Task} that checks for architecture problems.
*
* @author Andy Wilkinson
* @author Yanming Zhou
+ * @author Scott Frederick
*/
public abstract class ArchitectureCheck extends DefaultTask {
@@ -75,7 +82,8 @@ public ArchitectureCheck() {
allBeanFactoryPostProcessorBeanMethodsShouldBeStaticAndHaveNoParameters(),
noClassesShouldCallStepVerifierStepVerifyComplete(),
noClassesShouldConfigureDefaultStepVerifierTimeout(), noClassesShouldCallCollectorsToList(),
- noClassesShouldCallURLEncoderWithStringEncoding(), noClassesShouldCallURLDecoderWithStringEncoding());
+ noClassesShouldCallURLEncoderWithStringEncoding(), noClassesShouldCallURLDecoderWithStringEncoding(),
+ noClassesShouldLoadResourcesUsingResourceUtils());
getRuleDescriptions().set(getRules().map((rules) -> rules.stream().map(ArchRule::getDescription).toList()));
}
@@ -208,6 +216,18 @@ private ArchRule noClassesShouldCallURLDecoderWithStringEncoding() {
.because("java.net.URLDecoder.decode(String s, Charset charset) should be used instead");
}
+ private ArchRule noClassesShouldLoadResourcesUsingResourceUtils() {
+ return ArchRuleDefinition.noClasses()
+ .should()
+ .callMethodWhere(JavaCall.Predicates.target(With.owner(Predicates.type(ResourceUtils.class)))
+ .and(JavaCall.Predicates.target(HasName.Predicates.name("getURL")))
+ .and(JavaCall.Predicates.target(HasParameterTypes.Predicates.rawParameterTypes(String.class)))
+ .or(JavaCall.Predicates.target(With.owner(Predicates.type(ResourceUtils.class)))
+ .and(JavaCall.Predicates.target(HasName.Predicates.name("getFile")))
+ .and(JavaCall.Predicates.target(HasParameterTypes.Predicates.rawParameterTypes(String.class)))))
+ .because("org.springframework.boot.io.ApplicationResourceLoader should be used instead");
+ }
+
public void setClasses(FileCollection classes) {
this.classes = classes;
}
diff --git a/buildSrc/src/main/java/org/springframework/boot/build/architecture/ArchitecturePlugin.java b/buildSrc/src/main/java/org/springframework/boot/build/architecture/ArchitecturePlugin.java
index afeaf6311700..4c73e021df27 100644
--- a/buildSrc/src/main/java/org/springframework/boot/build/architecture/ArchitecturePlugin.java
+++ b/buildSrc/src/main/java/org/springframework/boot/build/architecture/ArchitecturePlugin.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2012-2023 the original author or authors.
+ * Copyright 2012-2024 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -51,6 +51,7 @@ private void registerTasks(Project project) {
(task) -> {
task.setClasses(sourceSet.getOutput().getClassesDirs());
task.getResourcesDirectory().set(sourceSet.getOutput().getResourcesDir());
+ task.dependsOn(sourceSet.getProcessResourcesTaskName());
task.setDescription("Checks the architecture of the classes of the " + sourceSet.getName()
+ " source set.");
task.setGroup(LifecycleBasePlugin.VERIFICATION_GROUP);
diff --git a/buildSrc/src/main/java/org/springframework/boot/build/artifacts/ArtifactRelease.java b/buildSrc/src/main/java/org/springframework/boot/build/artifacts/ArtifactRelease.java
index 3cf861543b0b..a0def21d15e5 100644
--- a/buildSrc/src/main/java/org/springframework/boot/build/artifacts/ArtifactRelease.java
+++ b/buildSrc/src/main/java/org/springframework/boot/build/artifacts/ArtifactRelease.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2012-2023 the original author or authors.
+ * Copyright 2012-2024 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -26,24 +26,18 @@
*/
public final class ArtifactRelease {
- private static final String SNAPSHOT = "snapshot";
-
- private static final String MILESTONE = "milestone";
-
- private static final String RELEASE = "release";
-
private static final String SPRING_REPO = "https://repo.spring.io/%s";
private static final String MAVEN_REPO = "https://repo.maven.apache.org/maven2";
- private final String type;
+ private final Type type;
- private ArtifactRelease(String type) {
+ private ArtifactRelease(Type type) {
this.type = type;
}
public String getType() {
- return this.type;
+ return this.type.toString().toLowerCase();
}
public String getDownloadRepo() {
@@ -51,24 +45,34 @@ public String getDownloadRepo() {
}
public boolean isRelease() {
- return RELEASE.equals(this.type);
+ return this.type == Type.RELEASE;
}
public static ArtifactRelease forProject(Project project) {
- return new ArtifactRelease(determineReleaseType(project));
+ return forVersion(project.getVersion().toString());
}
- private static String determineReleaseType(Project project) {
- String version = project.getVersion().toString();
- int modifierIndex = version.lastIndexOf('-');
- if (modifierIndex == -1) {
- return RELEASE;
- }
- String type = version.substring(modifierIndex + 1);
- if (type.startsWith("M") || type.startsWith("RC")) {
- return MILESTONE;
+ public static ArtifactRelease forVersion(String version) {
+ return new ArtifactRelease(Type.forVersion(version));
+ }
+
+ enum Type {
+
+ SNAPSHOT, MILESTONE, RELEASE;
+
+ static Type forVersion(String version) {
+ int modifierIndex = version.lastIndexOf('-');
+ if (modifierIndex == -1) {
+ return RELEASE;
+ }
+ String type = version.substring(modifierIndex + 1);
+ if (type.startsWith("M") || type.startsWith("RC")) {
+ return MILESTONE;
+ }
+ return SNAPSHOT;
+
}
- return SNAPSHOT;
+
}
}
diff --git a/buildSrc/src/main/java/org/springframework/boot/build/autoconfigure/AutoConfigurationMetadata.java b/buildSrc/src/main/java/org/springframework/boot/build/autoconfigure/AutoConfigurationMetadata.java
index 751ca0b87521..bf24d219dd25 100644
--- a/buildSrc/src/main/java/org/springframework/boot/build/autoconfigure/AutoConfigurationMetadata.java
+++ b/buildSrc/src/main/java/org/springframework/boot/build/autoconfigure/AutoConfigurationMetadata.java
@@ -28,11 +28,15 @@
import java.util.List;
import java.util.Properties;
import java.util.Set;
-import java.util.concurrent.Callable;
import org.gradle.api.DefaultTask;
import org.gradle.api.Task;
+import org.gradle.api.file.FileCollection;
+import org.gradle.api.file.RegularFileProperty;
+import org.gradle.api.tasks.Classpath;
+import org.gradle.api.tasks.InputFile;
import org.gradle.api.tasks.OutputFile;
+import org.gradle.api.tasks.PathSensitive;
import org.gradle.api.tasks.PathSensitivity;
import org.gradle.api.tasks.SourceSet;
import org.gradle.api.tasks.TaskAction;
@@ -48,47 +52,45 @@
* @author Andy Wilkinson
* @author Scott Frederick
*/
-public class AutoConfigurationMetadata extends DefaultTask {
+public abstract class AutoConfigurationMetadata extends DefaultTask {
private static final String COMMENT_START = "#";
private final String moduleName;
- private SourceSet sourceSet;
-
- private File outputFile;
+ private FileCollection classesDirectories;
public AutoConfigurationMetadata() {
- getInputs()
- .file((Callable) () -> new File(this.sourceSet.getOutput().getResourcesDir(),
- "META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports"))
- .withPathSensitivity(PathSensitivity.RELATIVE)
- .withPropertyName("org.springframework.boot.autoconfigure.AutoConfiguration");
-
- dependsOn((Callable) () -> this.sourceSet.getProcessResourcesTaskName());
getProject().getConfigurations()
.maybeCreate(AutoConfigurationPlugin.AUTO_CONFIGURATION_METADATA_CONFIGURATION_NAME);
this.moduleName = getProject().getName();
}
public void setSourceSet(SourceSet sourceSet) {
- this.sourceSet = sourceSet;
+ getAutoConfigurationImports().set(new File(sourceSet.getOutput().getResourcesDir(),
+ "META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports"));
+ this.classesDirectories = sourceSet.getOutput().getClassesDirs();
+ dependsOn(sourceSet.getOutput());
}
+ @InputFile
+ @PathSensitive(PathSensitivity.RELATIVE)
+ abstract RegularFileProperty getAutoConfigurationImports();
+
@OutputFile
- public File getOutputFile() {
- return this.outputFile;
- }
+ public abstract RegularFileProperty getOutputFile();
- public void setOutputFile(File outputFile) {
- this.outputFile = outputFile;
+ @Classpath
+ FileCollection getClassesDirectories() {
+ return this.classesDirectories;
}
@TaskAction
void documentAutoConfiguration() throws IOException {
Properties autoConfiguration = readAutoConfiguration();
- getOutputFile().getParentFile().mkdirs();
- try (FileWriter writer = new FileWriter(getOutputFile())) {
+ File outputFile = getOutputFile().get().getAsFile();
+ outputFile.getParentFile().mkdirs();
+ try (FileWriter writer = new FileWriter(outputFile)) {
autoConfiguration.store(writer, null);
}
}
@@ -120,8 +122,7 @@ private Properties readAutoConfiguration() throws IOException {
* @return auto-configurations
*/
private List readAutoConfigurationsFile() throws IOException {
- File file = new File(this.sourceSet.getOutput().getResourcesDir(),
- "META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports");
+ File file = getAutoConfigurationImports().getAsFile().get();
if (!file.exists()) {
return Collections.emptyList();
}
@@ -140,7 +141,7 @@ private String stripComment(String line) {
private File findClassFile(String className) {
String classFileName = className.replace(".", "/") + ".class";
- for (File classesDir : this.sourceSet.getOutput().getClassesDirs()) {
+ for (File classesDir : this.classesDirectories) {
File classFile = new File(classesDir, classFileName);
if (classFile.isFile()) {
return classFile;
diff --git a/buildSrc/src/main/java/org/springframework/boot/build/autoconfigure/AutoConfigurationPlugin.java b/buildSrc/src/main/java/org/springframework/boot/build/autoconfigure/AutoConfigurationPlugin.java
index eaaadf3b9474..97f36eb2c46c 100644
--- a/buildSrc/src/main/java/org/springframework/boot/build/autoconfigure/AutoConfigurationPlugin.java
+++ b/buildSrc/src/main/java/org/springframework/boot/build/autoconfigure/AutoConfigurationPlugin.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2012-2023 the original author or authors.
+ * Copyright 2012-2024 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -22,7 +22,6 @@
import java.nio.file.Path;
import java.util.Collections;
import java.util.List;
-import java.util.concurrent.Callable;
import com.tngtech.archunit.core.domain.JavaClass;
import com.tngtech.archunit.lang.ArchCondition;
@@ -94,10 +93,9 @@ public void apply(Project project) {
.getByName(SourceSet.MAIN_SOURCE_SET_NAME);
task.setSourceSet(main);
task.dependsOn(main.getClassesTaskName());
- task.setOutputFile(new File(project.getBuildDir(), "auto-configuration-metadata.properties"));
+ task.getOutputFile().set(new File(project.getBuildDir(), "auto-configuration-metadata.properties"));
project.getArtifacts()
- .add(AutoConfigurationPlugin.AUTO_CONFIGURATION_METADATA_CONFIGURATION_NAME,
- project.provider((Callable) task::getOutputFile),
+ .add(AutoConfigurationPlugin.AUTO_CONFIGURATION_METADATA_CONFIGURATION_NAME, task.getOutputFile(),
(artifact) -> artifact.builtBy(task));
});
project.getPlugins().withType(ArchitecturePlugin.class, (architecturePlugin) -> {
diff --git a/buildSrc/src/main/java/org/springframework/boot/build/autoconfigure/DocumentAutoConfigurationClasses.java b/buildSrc/src/main/java/org/springframework/boot/build/autoconfigure/DocumentAutoConfigurationClasses.java
index ce8fbc414619..3eb1a4b36c1b 100644
--- a/buildSrc/src/main/java/org/springframework/boot/build/autoconfigure/DocumentAutoConfigurationClasses.java
+++ b/buildSrc/src/main/java/org/springframework/boot/build/autoconfigure/DocumentAutoConfigurationClasses.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2012-2020 the original author or authors.
+ * Copyright 2012-2024 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -31,6 +31,7 @@
import org.gradle.api.DefaultTask;
import org.gradle.api.Task;
import org.gradle.api.file.FileCollection;
+import org.gradle.api.file.RegularFileProperty;
import org.gradle.api.tasks.InputFiles;
import org.gradle.api.tasks.OutputDirectory;
import org.gradle.api.tasks.TaskAction;
@@ -42,12 +43,10 @@
*
* @author Andy Wilkinson
*/
-public class DocumentAutoConfigurationClasses extends DefaultTask {
+public abstract class DocumentAutoConfigurationClasses extends DefaultTask {
private FileCollection autoConfiguration;
- private File outputDir;
-
@InputFiles
public FileCollection getAutoConfiguration() {
return this.autoConfiguration;
@@ -58,13 +57,7 @@ public void setAutoConfiguration(FileCollection autoConfiguration) {
}
@OutputDirectory
- public File getOutputDir() {
- return this.outputDir;
- }
-
- public void setOutputDir(File outputDir) {
- this.outputDir = outputDir;
- }
+ public abstract RegularFileProperty getOutputDir();
@TaskAction
void documentAutoConfigurationClasses() throws IOException {
@@ -80,18 +73,19 @@ void documentAutoConfigurationClasses() throws IOException {
}
private void writeTable(AutoConfiguration autoConfigurationClasses) throws IOException {
- this.outputDir.mkdirs();
+ File outputDir = getOutputDir().getAsFile().get();
+ outputDir.mkdirs();
try (PrintWriter writer = new PrintWriter(
- new FileWriter(new File(this.outputDir, autoConfigurationClasses.module + ".adoc")))) {
+ new FileWriter(new File(outputDir, autoConfigurationClasses.module + ".adoc")))) {
writer.println("[cols=\"4,1\"]");
writer.println("|===");
writer.println("| Configuration Class | Links");
for (AutoConfigurationClass autoConfigurationClass : autoConfigurationClasses.classes) {
writer.println();
- writer.printf("| {spring-boot-code}/spring-boot-project/%s/src/main/java/%s.java[`%s`]%n",
+ writer.printf("| {code-spring-boot}/spring-boot-project/%s/src/main/java/%s.java[`%s`]%n",
autoConfigurationClasses.module, autoConfigurationClass.path, autoConfigurationClass.name);
- writer.printf("| {spring-boot-api}/%s.html[javadoc]%n", autoConfigurationClass.path);
+ writer.printf("| xref:api:java/%s.html[javadoc]%n", autoConfigurationClass.path);
}
writer.println("|===");
diff --git a/buildSrc/src/main/java/org/springframework/boot/build/bom/BomExtension.java b/buildSrc/src/main/java/org/springframework/boot/build/bom/BomExtension.java
index 57d0935c52db..59bc52845431 100644
--- a/buildSrc/src/main/java/org/springframework/boot/build/bom/BomExtension.java
+++ b/buildSrc/src/main/java/org/springframework/boot/build/bom/BomExtension.java
@@ -26,6 +26,7 @@
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
+import java.util.function.Function;
import javax.inject.Inject;
import javax.xml.parsers.DocumentBuilderFactory;
@@ -66,11 +67,14 @@
import org.springframework.boot.build.bom.bomr.version.DependencyVersion;
import org.springframework.boot.build.mavenplugin.MavenExec;
import org.springframework.util.FileCopyUtils;
+import org.springframework.util.PropertyPlaceholderHelper;
+import org.springframework.util.PropertyPlaceholderHelper.PlaceholderResolver;
/**
* DSL extensions for {@link BomPlugin}.
*
* @author Andy Wilkinson
+ * @author Phillip Webb
*/
public class BomExtension {
@@ -121,7 +125,8 @@ public void library(String name, String version, Action action)
: null;
addLibrary(new Library(name, libraryHandler.calendarName, libraryVersion, libraryHandler.groups,
libraryHandler.prohibitedVersions, libraryHandler.considerSnapshots, versionAlignment,
- libraryHandler.alignWith.dependencyManagementDeclaredIn));
+ libraryHandler.alignWith.dependencyManagementDeclaredIn, libraryHandler.linkRootName,
+ libraryHandler.links));
}
public void effectiveBomArtifact() {
@@ -149,7 +154,7 @@ public void effectiveBomArtifact() {
}
MavenExec generateEffectiveBom = this.project.getTasks()
.create("generateEffectiveBom", MavenExec.class);
- generateEffectiveBom.setProjectDir(generatedBomDir);
+ generateEffectiveBom.getProjectDir().set(generatedBomDir);
File effectiveBom = new File(this.project.getBuildDir(),
"generated/effective-bom/" + this.project.getName() + "-effective-bom.xml");
generateEffectiveBom.args("--settings", "settings.xml", "help:effective-pom",
@@ -229,6 +234,10 @@ public static class LibraryHandler {
private String calendarName;
+ private String linkRootName;
+
+ private final Map> links = new HashMap<>();
+
@Inject
public LibraryHandler(Project project, String version) {
this.version = version;
@@ -265,6 +274,17 @@ public void alignWith(Action action) {
action.execute(this.alignWith);
}
+ public void links(Action action) {
+ links(null, action);
+ }
+
+ public void links(String linkRootName, Action action) {
+ LinksHandler handler = new LinksHandler();
+ action.execute(handler);
+ this.linkRootName = linkRootName;
+ this.links.putAll(handler.links);
+ }
+
public static class ProhibitedHandler {
private String reason;
@@ -417,6 +437,67 @@ public void managedBy(String managedBy) {
}
+ public static class LinksHandler {
+
+ private final Map> links = new HashMap<>();
+
+ public void site(String linkTemplate) {
+ site(asFactory(linkTemplate));
+ }
+
+ public void site(Function linkFactory) {
+ add("site", linkFactory);
+ }
+
+ public void github(String linkTemplate) {
+ github(asFactory(linkTemplate));
+ }
+
+ public void github(Function linkFactory) {
+ add("github", linkFactory);
+ }
+
+ public void docs(String linkTemplate) {
+ docs(asFactory(linkTemplate));
+ }
+
+ public void docs(Function linkFactory) {
+ add("docs", linkFactory);
+ }
+
+ public void javadoc(String linkTemplate) {
+ javadoc(asFactory(linkTemplate));
+ }
+
+ public void javadoc(Function linkFactory) {
+ add("javadoc", linkFactory);
+ }
+
+ public void releaseNotes(String linkTemplate) {
+ releaseNotes(asFactory(linkTemplate));
+ }
+
+ public void releaseNotes(Function linkFactory) {
+ add("releaseNotes", linkFactory);
+ }
+
+ public void add(String name, String linkTemplate) {
+ add(name, asFactory(linkTemplate));
+ }
+
+ public void add(String name, Function linkFactory) {
+ this.links.put(name, linkFactory);
+ }
+
+ private Function asFactory(String linkTemplate) {
+ return (version) -> {
+ PlaceholderResolver resolver = (name) -> "version".equals(name) ? version.toString() : null;
+ return new PropertyPlaceholderHelper("{", "}").replacePlaceholders(linkTemplate, resolver);
+ };
+ }
+
+ }
+
public static class UpgradeHandler {
private UpgradePolicy upgradePolicy;
diff --git a/buildSrc/src/main/java/org/springframework/boot/build/bom/BomPlugin.java b/buildSrc/src/main/java/org/springframework/boot/build/bom/BomPlugin.java
index 6cbd5ae787b5..07474bd79b79 100644
--- a/buildSrc/src/main/java/org/springframework/boot/build/bom/BomPlugin.java
+++ b/buildSrc/src/main/java/org/springframework/boot/build/bom/BomPlugin.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2012-2023 the original author or authors.
+ * Copyright 2012-2024 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -66,8 +66,8 @@ public void apply(Project project) {
project.getTasks().named("check").configure((check) -> check.dependsOn(checkBom));
project.getTasks().create("bomrUpgrade", UpgradeBom.class, bom);
project.getTasks().create("moveToSnapshots", MoveToSnapshots.class, bom);
+ project.getTasks().register("checkLinks", CheckLinks.class, bom);
new PublishingCustomizer(project, bom).customize();
-
}
private void createApiEnforcedConfiguration(Project project) {
@@ -291,9 +291,7 @@ private boolean isNodeWithName(Object candidate, String name) {
if ((node.name() instanceof QName qname) && name.equals(qname.getLocalPart())) {
return true;
}
- if (name.equals(node.name())) {
- return true;
- }
+ return name.equals(node.name());
}
return false;
}
diff --git a/buildSrc/src/main/java/org/springframework/boot/build/bom/CheckBom.java b/buildSrc/src/main/java/org/springframework/boot/build/bom/CheckBom.java
index f600097b3d52..fb3f6e962215 100644
--- a/buildSrc/src/main/java/org/springframework/boot/build/bom/CheckBom.java
+++ b/buildSrc/src/main/java/org/springframework/boot/build/bom/CheckBom.java
@@ -45,7 +45,7 @@
*
* @author Andy Wilkinson
*/
-public class CheckBom extends DefaultTask {
+public abstract class CheckBom extends DefaultTask {
private final BomExtension bom;
diff --git a/buildSrc/src/main/java/org/springframework/boot/build/bom/CheckLinks.java b/buildSrc/src/main/java/org/springframework/boot/build/bom/CheckLinks.java
new file mode 100644
index 000000000000..ca5a71b187d9
--- /dev/null
+++ b/buildSrc/src/main/java/org/springframework/boot/build/bom/CheckLinks.java
@@ -0,0 +1,85 @@
+/*
+ * Copyright 2012-2024 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.boot.build.bom;
+
+import java.io.IOException;
+import java.net.URI;
+import java.net.URISyntaxException;
+
+import javax.inject.Inject;
+
+import org.apache.hc.client5.http.config.RequestConfig;
+import org.apache.hc.client5.http.impl.classic.CloseableHttpClient;
+import org.apache.hc.client5.http.impl.classic.HttpClients;
+import org.gradle.api.DefaultTask;
+import org.gradle.api.tasks.TaskAction;
+import org.gradle.internal.impldep.org.apache.http.client.config.CookieSpecs;
+
+import org.springframework.http.HttpMethod;
+import org.springframework.http.ResponseEntity;
+import org.springframework.http.client.ClientHttpResponse;
+import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
+import org.springframework.web.client.DefaultResponseErrorHandler;
+import org.springframework.web.client.RestTemplate;
+
+/**
+ * Task to check that links are working.
+ *
+ * @author Andy Wilkinson
+ * @author Phillip Webb
+ */
+public abstract class CheckLinks extends DefaultTask {
+
+ private final BomExtension bom;
+
+ @Inject
+ public CheckLinks(BomExtension bom) {
+ this.bom = bom;
+ }
+
+ @TaskAction
+ void releaseNotes() {
+ RequestConfig config = RequestConfig.custom().setCookieSpec(CookieSpecs.IGNORE_COOKIES).build();
+ CloseableHttpClient httpClient = HttpClients.custom().setDefaultRequestConfig(config).build();
+ HttpComponentsClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory(httpClient);
+ RestTemplate restTemplate = new RestTemplate(requestFactory);
+ restTemplate.setErrorHandler(new IgnoringErrorHandler());
+ for (Library library : this.bom.getLibraries()) {
+ library.getLinks().forEach((name, link) -> {
+ URI uri;
+ try {
+ uri = new URI(link);
+ ResponseEntity response = restTemplate.exchange(uri, HttpMethod.HEAD, null, String.class);
+ System.out.println("[%3d] %s - %s (%s)".formatted(response.getStatusCode().value(),
+ library.getName(), name, uri));
+ }
+ catch (URISyntaxException ex) {
+ throw new RuntimeException(ex);
+ }
+ });
+ }
+ }
+
+ static class IgnoringErrorHandler extends DefaultResponseErrorHandler {
+
+ @Override
+ public void handleError(ClientHttpResponse response) throws IOException {
+ }
+
+ }
+
+}
diff --git a/buildSrc/src/main/java/org/springframework/boot/build/bom/Library.java b/buildSrc/src/main/java/org/springframework/boot/build/bom/Library.java
index b1f66f2b1d19..4a0928c0c997 100644
--- a/buildSrc/src/main/java/org/springframework/boot/build/bom/Library.java
+++ b/buildSrc/src/main/java/org/springframework/boot/build/bom/Library.java
@@ -17,6 +17,7 @@
package org.springframework.boot.build.bom;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
@@ -24,13 +25,14 @@
import java.util.Locale;
import java.util.Map;
import java.util.Set;
+import java.util.TreeMap;
+import java.util.function.Function;
import org.apache.maven.artifact.versioning.DefaultArtifactVersion;
import org.apache.maven.artifact.versioning.VersionRange;
import org.gradle.api.Project;
import org.gradle.api.artifacts.Configuration;
import org.gradle.api.artifacts.Dependency;
-import org.gradle.api.artifacts.dsl.DependencyHandler;
import org.gradle.api.artifacts.result.DependencyResult;
import org.springframework.boot.build.bom.bomr.version.DependencyVersion;
@@ -61,6 +63,10 @@ public class Library {
private final String alignsWithBom;
+ private final String linkRootName;
+
+ private final Map> links;
+
/**
* Create a new {@code Library} with the given {@code name}, {@code version}, and
* {@code groups}.
@@ -73,11 +79,14 @@ public class Library {
* @param considerSnapshots whether to consider snapshots
* @param versionAlignment version alignment, if any, for the library
* @param alignsWithBom the coordinates of the bom, if any, that this library should
- * inline
+ * align with
+ * @param linkRootName the root name to use when generating link variable or
+ * {@code null} to generate one based on the library {@code name}
+ * @param links a list of HTTP links relevant to the library
*/
public Library(String name, String calendarName, LibraryVersion version, List groups,
List prohibitedVersions, boolean considerSnapshots, VersionAlignment versionAlignment,
- String alignsWithBom) {
+ String alignsWithBom, String linkRootName, Map> links) {
this.name = name;
this.calendarName = (calendarName != null) ? calendarName : name;
this.version = version;
@@ -88,6 +97,12 @@ public Library(String name, String calendarName, LibraryVersion version, List getLinks() {
+ Map links = new TreeMap<>();
+ this.links.forEach((name, linkFactory) -> links.put(name, linkFactory.apply(this.version)));
+ return Collections.unmodifiableMap(links);
+ }
+
/**
* A version or range of versions that are prohibited from being used in a bom.
*/
@@ -194,6 +219,44 @@ public DependencyVersion getVersion() {
return this.version;
}
+ public int[] componentInts() {
+ return Arrays.stream(parts()).mapToInt(Integer::parseInt).toArray();
+ }
+
+ public String major() {
+ return parts()[0];
+ }
+
+ public String minor() {
+ return parts()[1];
+ }
+
+ public String patch() {
+ return parts()[2];
+ }
+
+ @Override
+ public String toString() {
+ return this.version.toString();
+ }
+
+ public String toString(String separator) {
+ return this.version.toString().replace(".", separator);
+ }
+
+ public String forAntora() {
+ String[] parts = parts();
+ String result = parts[0] + "." + parts[1];
+ if (toString().endsWith("SNAPSHOT")) {
+ result += "-SNAPSHOT";
+ }
+ return result;
+ }
+
+ private String[] parts() {
+ return toString().split("[.-]");
+ }
+
}
/**
@@ -334,17 +397,10 @@ public static class VersionAlignment {
}
public Set resolve() {
- if (this.managedBy == null) {
- throw new IllegalStateException("Version alignment without managedBy is not supported");
- }
if (this.alignedVersions != null) {
return this.alignedVersions;
}
- Library managingLibrary = this.libraries.stream()
- .filter((candidate) -> this.managedBy.equals(candidate.getName()))
- .findFirst()
- .orElseThrow(() -> new IllegalStateException("Managing library '" + this.managedBy + "' not found."));
- Map versions = resolveAligningDependencies(managingLibrary);
+ Map versions = resolveAligningDependencies();
Set versionsInLibrary = new HashSet<>();
for (Group group : this.groups) {
for (Module module : group.getModules()) {
@@ -364,18 +420,8 @@ public Set resolve() {
return this.alignedVersions;
}
- private Map resolveAligningDependencies(Library manager) {
- DependencyHandler dependencyHandler = this.project.getDependencies();
- List boms = manager.getGroups()
- .stream()
- .flatMap((group) -> group.getBoms()
- .stream()
- .map((bom) -> dependencyHandler
- .platform(group.getId() + ":" + bom + ":" + manager.getVersion().getVersion())))
- .toList();
- List dependencies = new ArrayList<>();
- dependencies.addAll(boms);
- dependencies.add(dependencyHandler.create(this.from));
+ private Map resolveAligningDependencies() {
+ List dependencies = getAligningDependencies();
Configuration alignmentConfiguration = this.project.getConfigurations()
.detachedConfiguration(dependencies.toArray(new Dependency[0]));
Map versions = new HashMap<>();
@@ -388,6 +434,58 @@ private Map resolveAligningDependencies(Library manager) {
return versions;
}
+ private List getAligningDependencies() {
+ if (this.managedBy == null) {
+ Library fromLibrary = findFromLibrary();
+ return List
+ .of(this.project.getDependencies().create(this.from + ":" + fromLibrary.getVersion().getVersion()));
+ }
+ else {
+ Library managingLibrary = findManagingLibrary();
+ List boms = getBomDependencies(managingLibrary);
+ List dependencies = new ArrayList<>();
+ dependencies.addAll(boms);
+ dependencies.add(this.project.getDependencies().create(this.from));
+ return dependencies;
+ }
+ }
+
+ private Library findFromLibrary() {
+ for (Library library : this.libraries) {
+ for (Group group : library.getGroups()) {
+ for (Module module : group.getModules()) {
+ if (this.from.equals(group.getId() + ":" + module.getName())) {
+ return library;
+ }
+ }
+ }
+ }
+ return null;
+ }
+
+ private Library findManagingLibrary() {
+ if (this.managedBy == null) {
+ return null;
+ }
+ return this.libraries.stream()
+ .filter((candidate) -> this.managedBy.equals(candidate.getName()))
+ .findFirst()
+ .orElseThrow(() -> new IllegalStateException("Managing library '" + this.managedBy + "' not found."));
+ }
+
+ private List getBomDependencies(Library manager) {
+ if (manager == null) {
+ return Collections.emptyList();
+ }
+ return manager.getGroups()
+ .stream()
+ .flatMap((group) -> group.getBoms()
+ .stream()
+ .map((bom) -> this.project.getDependencies()
+ .platform(group.getId() + ":" + bom + ":" + manager.getVersion().getVersion())))
+ .toList();
+ }
+
String getFrom() {
return this.from;
}
@@ -398,7 +496,11 @@ String getManagedBy() {
@Override
public String toString() {
- return "version from dependencies of " + this.from + " that is managed by " + this.managedBy;
+ String result = "version from dependencies of " + this.from;
+ if (this.managedBy != null) {
+ result += " that is managed by " + this.managedBy;
+ }
+ return result;
}
}
diff --git a/buildSrc/src/main/java/org/springframework/boot/build/bom/UpgradePolicy.java b/buildSrc/src/main/java/org/springframework/boot/build/bom/UpgradePolicy.java
index e9d72393965f..340c29a7a1c6 100644
--- a/buildSrc/src/main/java/org/springframework/boot/build/bom/UpgradePolicy.java
+++ b/buildSrc/src/main/java/org/springframework/boot/build/bom/UpgradePolicy.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2012-2023 the original author or authors.
+ * Copyright 2012-2024 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -35,12 +35,12 @@ public enum UpgradePolicy implements BiPredicate candidate.isSameMajor(current)),
+ SAME_MAJOR_VERSION(DependencyVersion::isSameMajor),
/**
* Patch versions of the current minor version.
*/
- SAME_MINOR_VERSION((candidate, current) -> candidate.isSameMinor(current));
+ SAME_MINOR_VERSION(DependencyVersion::isSameMinor);
private final BiPredicate delegate;
diff --git a/buildSrc/src/main/java/org/springframework/boot/build/bom/bomr/StandardLibraryUpdateResolver.java b/buildSrc/src/main/java/org/springframework/boot/build/bom/bomr/StandardLibraryUpdateResolver.java
index 517bf262a3a9..f5ffd02cac42 100644
--- a/buildSrc/src/main/java/org/springframework/boot/build/bom/bomr/StandardLibraryUpdateResolver.java
+++ b/buildSrc/src/main/java/org/springframework/boot/build/bom/bomr/StandardLibraryUpdateResolver.java
@@ -19,14 +19,12 @@
import java.time.Duration;
import java.util.ArrayList;
import java.util.Collection;
-import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.SortedSet;
import java.util.function.BiPredicate;
-import java.util.stream.Collectors;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -113,19 +111,14 @@ private List determineResolvedVersionOptions(Library library) {
getLaterVersionsForModule(group.getId(), plugin, library));
}
}
- List allVersions = moduleVersions.values()
+ return moduleVersions.values()
.stream()
.flatMap(SortedSet::stream)
.distinct()
.filter((dependencyVersion) -> this.predicate.test(library, dependencyVersion))
- .toList();
- if (allVersions.isEmpty()) {
- return Collections.emptyList();
- }
- return allVersions.stream()
- .map((version) -> new VersionOption.ResolvedVersionOption(version,
+ .map((version) -> (VersionOption) new VersionOption.ResolvedVersionOption(version,
getMissingModules(moduleVersions, version)))
- .collect(Collectors.toList());
+ .toList();
}
private List getMissingModules(Map> moduleVersions,
diff --git a/buildSrc/src/main/java/org/springframework/boot/build/bom/bomr/UpgradeDependencies.java b/buildSrc/src/main/java/org/springframework/boot/build/bom/bomr/UpgradeDependencies.java
index 04934445cd87..19e897cb823d 100644
--- a/buildSrc/src/main/java/org/springframework/boot/build/bom/bomr/UpgradeDependencies.java
+++ b/buildSrc/src/main/java/org/springframework/boot/build/bom/bomr/UpgradeDependencies.java
@@ -169,8 +169,9 @@ private List verifyLabels(GitHubRepository repository) {
if (!availableLabels.containsAll(issueLabels)) {
List unknownLabels = new ArrayList<>(issueLabels);
unknownLabels.removeAll(availableLabels);
+ String suffix = (unknownLabels.size() == 1) ? "" : "s";
throw new InvalidUserDataException(
- "Unknown label(s): " + StringUtils.collectionToCommaDelimitedString(unknownLabels));
+ "Unknown label" + suffix + ": " + StringUtils.collectionToCommaDelimitedString(unknownLabels));
}
return issueLabels;
}
@@ -193,7 +194,7 @@ private Milestone determineMilestone(GitHubRepository repository) {
java.util.Optional matchingMilestone = milestones.stream()
.filter((milestone) -> milestone.getName().equals(getMilestone().get()))
.findFirst();
- if (!matchingMilestone.isPresent()) {
+ if (matchingMilestone.isEmpty()) {
throw new InvalidUserDataException("Unknown milestone: " + getMilestone().get());
}
return matchingMilestone.get();
@@ -241,9 +242,9 @@ private boolean isAnUpgrade(Library library, DependencyVersion candidate) {
}
private boolean isNotProhibited(Library library, DependencyVersion candidate) {
- return !library.getProhibitedVersions()
+ return library.getProhibitedVersions()
.stream()
- .anyMatch((prohibited) -> prohibited.isProhibited(candidate.toString()));
+ .noneMatch((prohibited) -> prohibited.isProhibited(candidate.toString()));
}
private List matchingLibraries() {
diff --git a/buildSrc/src/main/java/org/springframework/boot/build/bom/bomr/version/AbstractDependencyVersion.java b/buildSrc/src/main/java/org/springframework/boot/build/bom/bomr/version/AbstractDependencyVersion.java
index ffb119efa9cc..c602347ef97c 100644
--- a/buildSrc/src/main/java/org/springframework/boot/build/bom/bomr/version/AbstractDependencyVersion.java
+++ b/buildSrc/src/main/java/org/springframework/boot/build/bom/bomr/version/AbstractDependencyVersion.java
@@ -57,10 +57,7 @@ public boolean equals(Object obj) {
return false;
}
AbstractDependencyVersion other = (AbstractDependencyVersion) obj;
- if (!this.comparableVersion.equals(other.comparableVersion)) {
- return false;
- }
- return true;
+ return this.comparableVersion.equals(other.comparableVersion);
}
@Override
diff --git a/buildSrc/src/main/java/org/springframework/boot/build/bom/bomr/version/ArtifactVersionDependencyVersion.java b/buildSrc/src/main/java/org/springframework/boot/build/bom/bomr/version/ArtifactVersionDependencyVersion.java
index 61e1d761e201..9986c12add4c 100644
--- a/buildSrc/src/main/java/org/springframework/boot/build/bom/bomr/version/ArtifactVersionDependencyVersion.java
+++ b/buildSrc/src/main/java/org/springframework/boot/build/bom/bomr/version/ArtifactVersionDependencyVersion.java
@@ -81,6 +81,9 @@ private boolean isSameMinor(ArtifactVersionDependencyVersion other) {
@Override
public boolean isUpgrade(DependencyVersion candidate, boolean movingToSnapshots) {
+ if (candidate instanceof MultipleComponentsDependencyVersion) {
+ return super.isUpgrade(candidate, movingToSnapshots);
+ }
if (!(candidate instanceof ArtifactVersionDependencyVersion)) {
return false;
}
diff --git a/buildSrc/src/main/java/org/springframework/boot/build/bom/bomr/version/DependencyVersion.java b/buildSrc/src/main/java/org/springframework/boot/build/bom/bomr/version/DependencyVersion.java
index f4b9b897a1ba..d82d5b8a50f5 100644
--- a/buildSrc/src/main/java/org/springframework/boot/build/bom/bomr/version/DependencyVersion.java
+++ b/buildSrc/src/main/java/org/springframework/boot/build/bom/bomr/version/DependencyVersion.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2012-2023 the original author or authors.
+ * Copyright 2012-2024 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -48,7 +48,7 @@ public interface DependencyVersion extends Comparable {
* Returns whether the given {@code candidate} is an upgrade of this version.
* @param candidate the version to consider
* @param movingToSnapshots whether the upgrade is to be considered as part of moving
- * to snaphots
+ * to snapshots
* @return {@code true} if the candidate is an upgrade, otherwise false
*/
boolean isUpgrade(DependencyVersion candidate, boolean movingToSnapshots);
diff --git a/buildSrc/src/main/java/org/springframework/boot/build/bom/bomr/version/ReleaseTrainDependencyVersion.java b/buildSrc/src/main/java/org/springframework/boot/build/bom/bomr/version/ReleaseTrainDependencyVersion.java
index c9c79bcdc69b..e43c1b05d9de 100644
--- a/buildSrc/src/main/java/org/springframework/boot/build/bom/bomr/version/ReleaseTrainDependencyVersion.java
+++ b/buildSrc/src/main/java/org/springframework/boot/build/bom/bomr/version/ReleaseTrainDependencyVersion.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2012-2023 the original author or authors.
+ * Copyright 2012-2024 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -64,22 +64,25 @@ public int compareTo(DependencyVersion other) {
@Override
public boolean isUpgrade(DependencyVersion candidate, boolean movingToSnapshots) {
- if (!(candidate instanceof ReleaseTrainDependencyVersion)) {
- return true;
+ if (candidate instanceof ReleaseTrainDependencyVersion candidateReleaseTrain) {
+ return isUpgrade(candidateReleaseTrain, movingToSnapshots);
}
- ReleaseTrainDependencyVersion candidateReleaseTrain = (ReleaseTrainDependencyVersion) candidate;
- int comparison = this.releaseTrain.compareTo(candidateReleaseTrain.releaseTrain);
+ return true;
+ }
+
+ private boolean isUpgrade(ReleaseTrainDependencyVersion candidate, boolean movingToSnapshots) {
+ int comparison = this.releaseTrain.compareTo(candidate.releaseTrain);
if (comparison != 0) {
return comparison < 0;
}
- if (movingToSnapshots && !isSnapshot() && candidateReleaseTrain.isSnapshot()) {
+ if (movingToSnapshots && !isSnapshot() && candidate.isSnapshot()) {
return true;
}
- comparison = this.type.compareTo(candidateReleaseTrain.type);
+ comparison = this.type.compareTo(candidate.type);
if (comparison != 0) {
return comparison < 0;
}
- return Integer.compare(this.version, candidateReleaseTrain.version) < 0;
+ return Integer.compare(this.version, candidate.version) < 0;
}
private boolean isSnapshot() {
@@ -88,10 +91,9 @@ private boolean isSnapshot() {
@Override
public boolean isSnapshotFor(DependencyVersion candidate) {
- if (!isSnapshot() || !(candidate instanceof ReleaseTrainDependencyVersion)) {
+ if (!isSnapshot() || !(candidate instanceof ReleaseTrainDependencyVersion candidateReleaseTrain)) {
return false;
}
- ReleaseTrainDependencyVersion candidateReleaseTrain = (ReleaseTrainDependencyVersion) candidate;
return this.releaseTrain.equals(candidateReleaseTrain.releaseTrain);
}
@@ -127,10 +129,7 @@ public boolean equals(Object obj) {
return false;
}
ReleaseTrainDependencyVersion other = (ReleaseTrainDependencyVersion) obj;
- if (!this.original.equals(other.original)) {
- return false;
- }
- return true;
+ return this.original.equals(other.original);
}
@Override
diff --git a/buildSrc/src/main/java/org/springframework/boot/build/classpath/CheckClasspathForConflicts.java b/buildSrc/src/main/java/org/springframework/boot/build/classpath/CheckClasspathForConflicts.java
index 72cdc0946129..3f30319aa362 100644
--- a/buildSrc/src/main/java/org/springframework/boot/build/classpath/CheckClasspathForConflicts.java
+++ b/buildSrc/src/main/java/org/springframework/boot/build/classpath/CheckClasspathForConflicts.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2012-2023 the original author or authors.
+ * Copyright 2012-2024 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -48,7 +48,7 @@
*
* @author Andy Wilkinson
*/
-public class CheckClasspathForConflicts extends DefaultTask {
+public abstract class CheckClasspathForConflicts extends DefaultTask {
private final List> ignores = new ArrayList<>();
diff --git a/buildSrc/src/main/java/org/springframework/boot/build/classpath/CheckClasspathForProhibitedDependencies.java b/buildSrc/src/main/java/org/springframework/boot/build/classpath/CheckClasspathForProhibitedDependencies.java
index 548344b731fd..70d39f019462 100644
--- a/buildSrc/src/main/java/org/springframework/boot/build/classpath/CheckClasspathForProhibitedDependencies.java
+++ b/buildSrc/src/main/java/org/springframework/boot/build/classpath/CheckClasspathForProhibitedDependencies.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2012-2023 the original author or authors.
+ * Copyright 2012-2024 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -16,6 +16,7 @@
package org.springframework.boot.build.classpath;
+import java.util.Set;
import java.util.TreeSet;
import java.util.stream.Collectors;
@@ -33,7 +34,12 @@
*
* @author Andy Wilkinson
*/
-public class CheckClasspathForProhibitedDependencies extends DefaultTask {
+public abstract class CheckClasspathForProhibitedDependencies extends DefaultTask {
+
+ private static final Set PROHIBITED_GROUPS = Set.of("org.codehaus.groovy", "org.eclipse.jetty.toolchain",
+ "commons-logging", "org.apache.geronimo.specs", "com.sun.activation");
+
+ private static final Set PERMITTED_JAVAX_GROUPS = Set.of("javax.batch", "javax.cache", "javax.money");
private Configuration classpath;
@@ -69,41 +75,20 @@ public void checkForProhibitedDependencies() {
}
private boolean prohibited(ModuleVersionIdentifier id) {
- String group = id.getGroup();
- if (group.equals("javax.batch")) {
- return false;
- }
- if (group.equals("javax.cache")) {
- return false;
- }
- if (group.equals("javax.money")) {
- return false;
- }
- if (group.equals("org.codehaus.groovy")) {
- return true;
- }
- if (group.equals("org.eclipse.jetty.toolchain")) {
- return true;
- }
- if (group.startsWith("javax")) {
- return true;
- }
- if (group.equals("commons-logging")) {
- return true;
- }
- if (group.equals("org.slf4j") && id.getName().equals("jcl-over-slf4j")) {
- return true;
- }
- if (group.startsWith("org.jboss.spec")) {
- return true;
- }
- if (group.equals("org.apache.geronimo.specs")) {
- return true;
- }
- if (group.equals("com.sun.activation")) {
- return true;
- }
- return false;
+ return PROHIBITED_GROUPS.contains(id.getGroup()) || prohibitedJavax(id) || prohibitedSlf4j(id)
+ || prohibitedJbossSpec(id);
+ }
+
+ private boolean prohibitedSlf4j(ModuleVersionIdentifier id) {
+ return id.getGroup().equals("org.slf4j") && id.getName().equals("jcl-over-slf4j");
+ }
+
+ private boolean prohibitedJbossSpec(ModuleVersionIdentifier id) {
+ return id.getGroup().startsWith("org.jboss.spec");
+ }
+
+ private boolean prohibitedJavax(ModuleVersionIdentifier id) {
+ return id.getGroup().startsWith("javax.") && !PERMITTED_JAVAX_GROUPS.contains(id.getGroup());
}
}
diff --git a/buildSrc/src/main/java/org/springframework/boot/build/classpath/CheckClasspathForUnconstrainedDirectDependencies.java b/buildSrc/src/main/java/org/springframework/boot/build/classpath/CheckClasspathForUnconstrainedDirectDependencies.java
index 543a33b772a1..6a846c2a7c70 100644
--- a/buildSrc/src/main/java/org/springframework/boot/build/classpath/CheckClasspathForUnconstrainedDirectDependencies.java
+++ b/buildSrc/src/main/java/org/springframework/boot/build/classpath/CheckClasspathForUnconstrainedDirectDependencies.java
@@ -34,7 +34,7 @@
*
* @author Andy Wilkinson
*/
-public class CheckClasspathForUnconstrainedDirectDependencies extends DefaultTask {
+public abstract class CheckClasspathForUnconstrainedDirectDependencies extends DefaultTask {
private Configuration classpath;
diff --git a/buildSrc/src/main/java/org/springframework/boot/build/classpath/CheckClasspathForUnnecessaryExclusions.java b/buildSrc/src/main/java/org/springframework/boot/build/classpath/CheckClasspathForUnnecessaryExclusions.java
index 511898299957..3fa6522cbb59 100644
--- a/buildSrc/src/main/java/org/springframework/boot/build/classpath/CheckClasspathForUnnecessaryExclusions.java
+++ b/buildSrc/src/main/java/org/springframework/boot/build/classpath/CheckClasspathForUnnecessaryExclusions.java
@@ -48,7 +48,7 @@
*
* @author Andy Wilkinson
*/
-public class CheckClasspathForUnnecessaryExclusions extends DefaultTask {
+public abstract class CheckClasspathForUnnecessaryExclusions extends DefaultTask {
private static final Map SPRING_BOOT_DEPENDENCIES_PROJECT = Collections.singletonMap("path",
":spring-boot-project:spring-boot-dependencies");
diff --git a/buildSrc/src/main/java/org/springframework/boot/build/cli/HomebrewFormula.java b/buildSrc/src/main/java/org/springframework/boot/build/cli/HomebrewFormula.java
index 62e790a31c06..8dc5dd709ce7 100644
--- a/buildSrc/src/main/java/org/springframework/boot/build/cli/HomebrewFormula.java
+++ b/buildSrc/src/main/java/org/springframework/boot/build/cli/HomebrewFormula.java
@@ -18,16 +18,15 @@
import java.io.File;
import java.security.MessageDigest;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.Map;
import org.apache.commons.codec.digest.DigestUtils;
import org.gradle.api.DefaultTask;
import org.gradle.api.Project;
import org.gradle.api.Task;
-import org.gradle.api.file.RegularFile;
-import org.gradle.api.provider.Provider;
+import org.gradle.api.file.DirectoryProperty;
+import org.gradle.api.file.RegularFileProperty;
+import org.gradle.api.provider.MapProperty;
+import org.gradle.api.tasks.Input;
import org.gradle.api.tasks.InputFile;
import org.gradle.api.tasks.OutputDirectory;
import org.gradle.api.tasks.PathSensitive;
@@ -42,62 +41,14 @@
*
* @author Andy Wilkinson
*/
-public class HomebrewFormula extends DefaultTask {
-
- private Provider archive;
-
- private File template;
-
- private File outputDir;
+public abstract class HomebrewFormula extends DefaultTask {
public HomebrewFormula() {
- getInputs().property("version", getProject().provider(getProject()::getVersion));
- }
-
- @InputFile
- @PathSensitive(PathSensitivity.RELATIVE)
- public RegularFile getArchive() {
- return this.archive.get();
- }
-
- public void setArchive(Provider archive) {
- this.archive = archive;
- }
-
- @InputFile
- @PathSensitive(PathSensitivity.RELATIVE)
- public File getTemplate() {
- return this.template;
- }
-
- public void setTemplate(File template) {
- this.template = template;
- }
-
- @OutputDirectory
- public File getOutputDir() {
- return this.outputDir;
- }
-
- public void setOutputDir(File outputDir) {
- this.outputDir = outputDir;
- }
-
- protected void createDescriptor(Map additionalProperties) {
- getProject().copy((copy) -> {
- copy.from(this.template);
- copy.into(this.outputDir);
- copy.expand(getProperties(additionalProperties));
- });
- }
-
- private Map getProperties(Map additionalProperties) {
- Map properties = new HashMap<>(additionalProperties);
Project project = getProject();
- properties.put("hash", sha256(this.archive.get().getAsFile()));
- properties.put("repo", ArtifactRelease.forProject(project).getDownloadRepo());
- properties.put("project", project);
- return properties;
+ MapProperty properties = getProperties();
+ properties.put("hash", getArchive().map((archive) -> sha256(archive.getAsFile())));
+ getProperties().put("repo", ArtifactRelease.forProject(project).getDownloadRepo());
+ getProperties().put("version", project.getVersion().toString());
}
private String sha256(File file) {
@@ -110,9 +61,27 @@ private String sha256(File file) {
}
}
+ @InputFile
+ @PathSensitive(PathSensitivity.RELATIVE)
+ public abstract RegularFileProperty getArchive();
+
+ @InputFile
+ @PathSensitive(PathSensitivity.RELATIVE)
+ public abstract RegularFileProperty getTemplate();
+
+ @OutputDirectory
+ public abstract DirectoryProperty getOutputDir();
+
+ @Input
+ abstract MapProperty getProperties();
+
@TaskAction
void createFormula() {
- createDescriptor(Collections.emptyMap());
+ getProject().copy((copy) -> {
+ copy.from(getTemplate());
+ copy.into(getOutputDir());
+ copy.expand(getProperties().get());
+ });
}
}
diff --git a/buildSrc/src/main/java/org/springframework/boot/build/constraints/DocumentConstrainedVersions.java b/buildSrc/src/main/java/org/springframework/boot/build/constraints/DocumentConstrainedVersions.java
index c4d9e05f59ea..e70502f785fc 100644
--- a/buildSrc/src/main/java/org/springframework/boot/build/constraints/DocumentConstrainedVersions.java
+++ b/buildSrc/src/main/java/org/springframework/boot/build/constraints/DocumentConstrainedVersions.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2012-2021 the original author or authors.
+ * Copyright 2012-2024 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -21,10 +21,8 @@
import java.io.IOException;
import java.io.PrintWriter;
-import javax.inject.Inject;
-
import org.gradle.api.DefaultTask;
-import org.gradle.api.model.ObjectFactory;
+import org.gradle.api.file.RegularFileProperty;
import org.gradle.api.provider.SetProperty;
import org.gradle.api.tasks.Input;
import org.gradle.api.tasks.OutputFile;
@@ -37,38 +35,22 @@
*
* @author Andy Wilkinson
*/
-public class DocumentConstrainedVersions extends DefaultTask {
-
- private final SetProperty constrainedVersions;
-
- private File outputFile;
-
- @Inject
- public DocumentConstrainedVersions(ObjectFactory objectFactory) {
- this.constrainedVersions = objectFactory.setProperty(ConstrainedVersion.class);
- }
+public abstract class DocumentConstrainedVersions extends DefaultTask {
@Input
- public SetProperty getConstrainedVersions() {
- return this.constrainedVersions;
- }
+ public abstract SetProperty getConstrainedVersions();
@OutputFile
- public File getOutputFile() {
- return this.outputFile;
- }
-
- public void setOutputFile(File outputFile) {
- this.outputFile = outputFile;
- }
+ public abstract RegularFileProperty getOutputFile();
@TaskAction
public void documentConstrainedVersions() throws IOException {
- this.outputFile.getParentFile().mkdirs();
- try (PrintWriter writer = new PrintWriter(new FileWriter(this.outputFile))) {
+ File outputFile = getOutputFile().get().getAsFile();
+ outputFile.getParentFile().mkdirs();
+ try (PrintWriter writer = new PrintWriter(new FileWriter(outputFile))) {
writer.println("|===");
writer.println("| Group ID | Artifact ID | Version");
- for (ConstrainedVersion constrainedVersion : this.constrainedVersions.get()) {
+ for (ConstrainedVersion constrainedVersion : getConstrainedVersions().get()) {
writer.println();
writer.printf("| `%s`%n", constrainedVersion.getGroup());
writer.printf("| `%s`%n", constrainedVersion.getArtifact());
diff --git a/buildSrc/src/main/java/org/springframework/boot/build/constraints/DocumentVersionProperties.java b/buildSrc/src/main/java/org/springframework/boot/build/constraints/DocumentVersionProperties.java
index e083b01277db..ef1c7c8647ad 100644
--- a/buildSrc/src/main/java/org/springframework/boot/build/constraints/DocumentVersionProperties.java
+++ b/buildSrc/src/main/java/org/springframework/boot/build/constraints/DocumentVersionProperties.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2012-2021 the original author or authors.
+ * Copyright 2012-2024 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -21,10 +21,8 @@
import java.io.IOException;
import java.io.PrintWriter;
-import javax.inject.Inject;
-
import org.gradle.api.DefaultTask;
-import org.gradle.api.model.ObjectFactory;
+import org.gradle.api.file.RegularFileProperty;
import org.gradle.api.provider.SetProperty;
import org.gradle.api.tasks.Input;
import org.gradle.api.tasks.OutputFile;
@@ -37,38 +35,22 @@
*
* @author Christoph Dreis
*/
-public class DocumentVersionProperties extends DefaultTask {
-
- private final SetProperty versionProperties;
-
- private File outputFile;
-
- @Inject
- public DocumentVersionProperties(ObjectFactory objectFactory) {
- this.versionProperties = objectFactory.setProperty(VersionProperty.class);
- }
+public abstract class DocumentVersionProperties extends DefaultTask {
@Input
- public SetProperty getVersionProperties() {
- return this.versionProperties;
- }
+ public abstract SetProperty getVersionProperties();
@OutputFile
- public File getOutputFile() {
- return this.outputFile;
- }
-
- public void setOutputFile(File outputFile) {
- this.outputFile = outputFile;
- }
+ public abstract RegularFileProperty getOutputFile();
@TaskAction
public void documentVersionProperties() throws IOException {
- this.outputFile.getParentFile().mkdirs();
- try (PrintWriter writer = new PrintWriter(new FileWriter(this.outputFile))) {
+ File outputFile = getOutputFile().getAsFile().get();
+ outputFile.getParentFile().mkdirs();
+ try (PrintWriter writer = new PrintWriter(new FileWriter(outputFile))) {
writer.println("|===");
writer.println("| Library | Version Property");
- for (VersionProperty versionProperty : this.versionProperties.get()) {
+ for (VersionProperty versionProperty : getVersionProperties().get()) {
writer.println();
writer.printf("| `%s`%n", versionProperty.getLibraryName());
writer.printf("| `%s`%n", versionProperty.getVersionProperty());
diff --git a/buildSrc/src/main/java/org/springframework/boot/build/constraints/ExtractVersionConstraints.java b/buildSrc/src/main/java/org/springframework/boot/build/constraints/ExtractVersionConstraints.java
index 4d14b2977d4e..bd6a57d11d55 100644
--- a/buildSrc/src/main/java/org/springframework/boot/build/constraints/ExtractVersionConstraints.java
+++ b/buildSrc/src/main/java/org/springframework/boot/build/constraints/ExtractVersionConstraints.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2012-2023 the original author or authors.
+ * Copyright 2012-2024 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -26,17 +26,20 @@
import java.util.TreeSet;
import org.gradle.api.DefaultTask;
+import org.gradle.api.Project;
import org.gradle.api.Task;
import org.gradle.api.artifacts.ComponentMetadataDetails;
import org.gradle.api.artifacts.Configuration;
import org.gradle.api.artifacts.DependencyConstraint;
import org.gradle.api.artifacts.DependencyConstraintMetadata;
+import org.gradle.api.artifacts.DependencyConstraintSet;
import org.gradle.api.artifacts.dsl.DependencyHandler;
import org.gradle.api.tasks.Internal;
import org.gradle.api.tasks.TaskAction;
import org.gradle.platform.base.Platform;
import org.springframework.boot.build.bom.BomExtension;
+import org.springframework.boot.build.bom.BomPlugin;
import org.springframework.boot.build.bom.Library;
/**
@@ -45,7 +48,7 @@
*
* @author Andy Wilkinson
*/
-public class ExtractVersionConstraints extends DefaultTask {
+public abstract class ExtractVersionConstraints extends DefaultTask {
private final Configuration configuration;
@@ -55,7 +58,9 @@ public class ExtractVersionConstraints extends DefaultTask {
private final Set versionProperties = new TreeSet<>();
- private final List projectPaths = new ArrayList<>();
+ private final List dependencyConstraintSets = new ArrayList<>();
+
+ private final List boms = new ArrayList<>();
public ExtractVersionConstraints() {
DependencyHandler dependencies = getProject().getDependencies();
@@ -68,7 +73,12 @@ public void enforcedPlatform(String projectPath) {
.add(getProject().getDependencies()
.enforcedPlatform(
getProject().getDependencies().project(Collections.singletonMap("path", projectPath))));
- this.projectPaths.add(projectPath);
+ Project project = getProject().project(projectPath);
+ project.getPlugins().withType(BomPlugin.class).all((plugin) -> {
+ this.boms.add(project.getExtensions().getByType(BomExtension.class));
+ this.dependencyConstraintSets
+ .add(project.getConfigurations().getByName("apiElements").getAllDependencyConstraints());
+ });
}
@Internal
@@ -89,12 +99,9 @@ public Set getVersionProperties() {
@TaskAction
void extractVersionConstraints() {
this.configuration.resolve();
- for (String projectPath : this.projectPaths) {
- extractVersionProperties(projectPath);
- for (DependencyConstraint constraint : getProject().project(projectPath)
- .getConfigurations()
- .getByName("apiElements")
- .getAllDependencyConstraints()) {
+ this.boms.forEach(this::extractVersionProperties);
+ for (DependencyConstraintSet constraints : this.dependencyConstraintSets) {
+ for (DependencyConstraint constraint : constraints) {
this.versionConstraints.put(constraint.getGroup() + ":" + constraint.getName(),
constraint.getVersionConstraint().toString());
this.constrainedVersions.add(new ConstrainedVersion(constraint.getGroup(), constraint.getName(),
@@ -103,9 +110,7 @@ void extractVersionConstraints() {
}
}
- private void extractVersionProperties(String projectPath) {
- Object bom = getProject().project(projectPath).getExtensions().getByName("bom");
- BomExtension bomExtension = (BomExtension) bom;
+ private void extractVersionProperties(BomExtension bomExtension) {
for (Library lib : bomExtension.getLibraries()) {
String versionProperty = lib.getVersionProperty();
if (versionProperty != null) {
diff --git a/buildSrc/src/main/java/org/springframework/boot/build/context/properties/CheckAdditionalSpringConfigurationMetadata.java b/buildSrc/src/main/java/org/springframework/boot/build/context/properties/CheckAdditionalSpringConfigurationMetadata.java
index a4c927e8b3cc..8405dc445f08 100644
--- a/buildSrc/src/main/java/org/springframework/boot/build/context/properties/CheckAdditionalSpringConfigurationMetadata.java
+++ b/buildSrc/src/main/java/org/springframework/boot/build/context/properties/CheckAdditionalSpringConfigurationMetadata.java
@@ -46,21 +46,16 @@
*
* @author Andy Wilkinson
*/
-public class CheckAdditionalSpringConfigurationMetadata extends SourceTask {
+public abstract class CheckAdditionalSpringConfigurationMetadata extends SourceTask {
private final File projectDir;
- private final RegularFileProperty reportLocation;
-
public CheckAdditionalSpringConfigurationMetadata() {
this.projectDir = getProject().getProjectDir();
- this.reportLocation = getProject().getObjects().fileProperty();
}
@OutputFile
- public RegularFileProperty getReportLocation() {
- return this.reportLocation;
- }
+ public abstract RegularFileProperty getReportLocation();
@Override
@InputFiles
@@ -96,7 +91,7 @@ private Report createReport() throws IOException, JsonParseException, JsonMappin
@SuppressWarnings("unchecked")
private void check(String key, Map json, Analysis analysis) {
- List> groups = (List>) json.get(key);
+ List> groups = (List>) json.getOrDefault(key, Collections.emptyList());
List names = groups.stream().map((group) -> (String) group.get("name")).toList();
List sortedNames = sortedCopy(names);
for (int i = 0; i < names.size(); i++) {
diff --git a/buildSrc/src/main/java/org/springframework/boot/build/context/properties/CheckSpringConfigurationMetadata.java b/buildSrc/src/main/java/org/springframework/boot/build/context/properties/CheckSpringConfigurationMetadata.java
index 048de4e9f5cc..f1bff685cd86 100644
--- a/buildSrc/src/main/java/org/springframework/boot/build/context/properties/CheckSpringConfigurationMetadata.java
+++ b/buildSrc/src/main/java/org/springframework/boot/build/context/properties/CheckSpringConfigurationMetadata.java
@@ -32,6 +32,7 @@
import org.gradle.api.DefaultTask;
import org.gradle.api.GradleException;
import org.gradle.api.file.RegularFileProperty;
+import org.gradle.api.provider.ListProperty;
import org.gradle.api.tasks.Input;
import org.gradle.api.tasks.InputFile;
import org.gradle.api.tasks.OutputFile;
@@ -45,41 +46,23 @@
*
* @author Andy Wilkinson
*/
-public class CheckSpringConfigurationMetadata extends DefaultTask {
+public abstract class CheckSpringConfigurationMetadata extends DefaultTask {
- private List exclusions = new ArrayList<>();
-
- private final File projectDir;
-
- private final RegularFileProperty reportLocation;
-
- private final RegularFileProperty metadataLocation;
+ private final Path projectRoot;
public CheckSpringConfigurationMetadata() {
- this.projectDir = getProject().getProjectDir();
- this.metadataLocation = getProject().getObjects().fileProperty();
- this.reportLocation = getProject().getObjects().fileProperty();
+ this.projectRoot = getProject().getProjectDir().toPath();
}
@OutputFile
- public RegularFileProperty getReportLocation() {
- return this.reportLocation;
- }
+ public abstract RegularFileProperty getReportLocation();
@InputFile
@PathSensitive(PathSensitivity.RELATIVE)
- public RegularFileProperty getMetadataLocation() {
- return this.metadataLocation;
- }
-
- public void setExclusions(List exclusions) {
- this.exclusions = exclusions;
- }
+ public abstract RegularFileProperty getMetadataLocation();
@Input
- public List getExclusions() {
- return this.exclusions;
- }
+ public abstract ListProperty getExclusions();
@TaskAction
void check() throws JsonParseException, IOException {
@@ -95,8 +78,8 @@ void check() throws JsonParseException, IOException {
@SuppressWarnings("unchecked")
private Report createReport() throws IOException, JsonParseException, JsonMappingException {
ObjectMapper objectMapper = new ObjectMapper();
- File file = this.metadataLocation.get().getAsFile();
- Report report = new Report(this.projectDir.toPath().relativize(file.toPath()));
+ File file = getMetadataLocation().get().getAsFile();
+ Report report = new Report(this.projectRoot.relativize(file.toPath()));
Map json = objectMapper.readValue(file, Map.class);
List> properties = (List>) json.get("properties");
for (Map property : properties) {
@@ -109,7 +92,7 @@ private Report createReport() throws IOException, JsonParseException, JsonMappin
}
private boolean isExcluded(String propertyName) {
- for (String exclusion : this.exclusions) {
+ for (String exclusion : getExclusions().get()) {
if (propertyName.equals(exclusion)) {
return true;
}
diff --git a/buildSrc/src/main/java/org/springframework/boot/build/context/properties/CompoundRow.java b/buildSrc/src/main/java/org/springframework/boot/build/context/properties/CompoundRow.java
index d322ce106290..ffa9f5687b5f 100644
--- a/buildSrc/src/main/java/org/springframework/boot/build/context/properties/CompoundRow.java
+++ b/buildSrc/src/main/java/org/springframework/boot/build/context/properties/CompoundRow.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2012-2021 the original author or authors.
+ * Copyright 2012-2024 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -24,6 +24,7 @@
*
* @author Brian Clozel
* @author Phillip Webb
+ * @author Moritz Halbritter
*/
class CompoundRow extends Row {
@@ -45,9 +46,9 @@ void addProperty(ConfigurationProperty property) {
void write(Asciidoc asciidoc) {
asciidoc.append("|");
asciidoc.append("[[" + getAnchor() + "]]");
- asciidoc.append("<<" + getAnchor() + ",");
+ asciidoc.append("xref:#" + getAnchor() + "[");
this.propertyNames.forEach(asciidoc::appendWithHardLineBreaks);
- asciidoc.appendln(">>");
+ asciidoc.appendln("]");
asciidoc.appendln("|+++", this.description, "+++");
asciidoc.appendln("|");
}
diff --git a/buildSrc/src/main/java/org/springframework/boot/build/context/properties/DocumentConfigurationProperties.java b/buildSrc/src/main/java/org/springframework/boot/build/context/properties/DocumentConfigurationProperties.java
index d7c8710e2cb4..a7ac94f60ced 100644
--- a/buildSrc/src/main/java/org/springframework/boot/build/context/properties/DocumentConfigurationProperties.java
+++ b/buildSrc/src/main/java/org/springframework/boot/build/context/properties/DocumentConfigurationProperties.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2012-2023 the original author or authors.
+ * Copyright 2012-2024 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -16,11 +16,11 @@
package org.springframework.boot.build.context.properties;
-import java.io.File;
import java.io.IOException;
import org.gradle.api.DefaultTask;
import org.gradle.api.Task;
+import org.gradle.api.file.DirectoryProperty;
import org.gradle.api.file.FileCollection;
import org.gradle.api.tasks.InputFiles;
import org.gradle.api.tasks.OutputDirectory;
@@ -36,12 +36,10 @@
* @author Andy Wilkinson
* @author Phillip Webb
*/
-public class DocumentConfigurationProperties extends DefaultTask {
+public abstract class DocumentConfigurationProperties extends DefaultTask {
private FileCollection configurationPropertyMetadata;
- private File outputDir;
-
@InputFiles
@PathSensitive(PathSensitivity.RELATIVE)
public FileCollection getConfigurationPropertyMetadata() {
@@ -53,13 +51,7 @@ public void setConfigurationPropertyMetadata(FileCollection configurationPropert
}
@OutputDirectory
- public File getOutputDir() {
- return this.outputDir;
- }
-
- public void setOutputDir(File outputDir) {
- this.outputDir = outputDir;
- }
+ public abstract DirectoryProperty getOutputDir();
@TaskAction
void documentConfigurationProperties() throws IOException {
@@ -78,10 +70,12 @@ void documentConfigurationProperties() throws IOException {
snippets.add("application-properties.security", "Security Properties", this::securityPrefixes);
snippets.add("application-properties.rsocket", "RSocket Properties", this::rsocketPrefixes);
snippets.add("application-properties.actuator", "Actuator Properties", this::actuatorPrefixes);
- snippets.add("application-properties.docker-compose", "Docker Compose Properties", this::dockerComposePrefixes);
snippets.add("application-properties.devtools", "Devtools Properties", this::devtoolsPrefixes);
+ snippets.add("application-properties.docker-compose", "Docker Compose Properties", this::dockerComposePrefixes);
+ snippets.add("application-properties.testcontainers", "Testcontainers Properties",
+ this::testcontainersPrefixes);
snippets.add("application-properties.testing", "Testing Properties", this::testingPrefixes);
- snippets.writeTo(this.outputDir.toPath());
+ snippets.writeTo(getOutputDir().getAsFile().get().toPath());
}
private void corePrefixes(Config config) {
@@ -106,6 +100,7 @@ private void corePrefixes(Config config) {
config.accept("spring.reactor");
config.accept("spring.ssl");
config.accept("spring.task");
+ config.accept("spring.threads");
config.accept("spring.mandatory-file-encoding");
config.accept("info");
config.accept("spring.output.ansi.enabled");
@@ -170,6 +165,7 @@ private void integrationPrefixes(Config prefix) {
prefix.accept("spring.integration");
prefix.accept("spring.jms");
prefix.accept("spring.kafka");
+ prefix.accept("spring.pulsar");
prefix.accept("spring.rabbitmq");
prefix.accept("spring.hazelcast");
prefix.accept("spring.webservices");
@@ -211,6 +207,7 @@ private void rsocketPrefixes(Config prefix) {
private void actuatorPrefixes(Config prefix) {
prefix.accept("management");
+ prefix.accept("micrometer");
}
private void dockerComposePrefixes(Config prefix) {
@@ -222,7 +219,11 @@ private void devtoolsPrefixes(Config prefix) {
}
private void testingPrefixes(Config prefix) {
- prefix.accept("spring.test");
+ prefix.accept("spring.test.");
+ }
+
+ private void testcontainersPrefixes(Config prefix) {
+ prefix.accept("spring.testcontainers.");
}
}
diff --git a/buildSrc/src/main/java/org/springframework/boot/build/context/properties/SingleRow.java b/buildSrc/src/main/java/org/springframework/boot/build/context/properties/SingleRow.java
index 65f6bb3625fa..c81f57c9f4e2 100644
--- a/buildSrc/src/main/java/org/springframework/boot/build/context/properties/SingleRow.java
+++ b/buildSrc/src/main/java/org/springframework/boot/build/context/properties/SingleRow.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2012-2023 the original author or authors.
+ * Copyright 2012-2024 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -24,6 +24,7 @@
*
* @author Brian Clozel
* @author Phillip Webb
+ * @author Moritz Halbritter
*/
class SingleRow extends Row {
@@ -56,7 +57,7 @@ private String getDefaultValue(Object defaultValue) {
void write(Asciidoc asciidoc) {
asciidoc.append("|");
asciidoc.append("[[" + getAnchor() + "]]");
- asciidoc.appendln("<<" + getAnchor() + ",`+", this.displayName, "+`>>");
+ asciidoc.appendln("xref:#" + getAnchor() + "[`+", this.displayName, "+`]");
writeDescription(asciidoc);
writeDefaultValue(asciidoc);
}
diff --git a/buildSrc/src/main/java/org/springframework/boot/build/context/properties/Snippets.java b/buildSrc/src/main/java/org/springframework/boot/build/context/properties/Snippets.java
index 3e7d7ebf199e..a86560c2d6a7 100644
--- a/buildSrc/src/main/java/org/springframework/boot/build/context/properties/Snippets.java
+++ b/buildSrc/src/main/java/org/springframework/boot/build/context/properties/Snippets.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2012-2023 the original author or authors.
+ * Copyright 2012-2024 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -102,11 +102,7 @@ private Asciidoc getAsciidoc(Snippet snippet, Table table) {
private void writeAsciidoc(Path outputDirectory, Snippet snippet, Asciidoc asciidoc) throws IOException {
String[] parts = (snippet.getAnchor()).split("\\.");
- Path path = outputDirectory;
- for (int i = 0; i < parts.length; i++) {
- String name = (i < parts.length - 1) ? parts[i] : parts[i] + ".adoc";
- path = path.resolve(name);
- }
+ Path path = outputDirectory.resolve(parts[parts.length - 1] + ".adoc");
createDirectory(path.getParent());
Files.deleteIfExists(path);
try (OutputStream outputStream = Files.newOutputStream(path)) {
diff --git a/buildSrc/src/main/java/org/springframework/boot/build/devtools/DocumentDevtoolsPropertyDefaults.java b/buildSrc/src/main/java/org/springframework/boot/build/devtools/DocumentDevtoolsPropertyDefaults.java
index 515228ce70ab..106e53465743 100644
--- a/buildSrc/src/main/java/org/springframework/boot/build/devtools/DocumentDevtoolsPropertyDefaults.java
+++ b/buildSrc/src/main/java/org/springframework/boot/build/devtools/DocumentDevtoolsPropertyDefaults.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2012-2023 the original author or authors.
+ * Copyright 2012-2024 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -39,18 +39,15 @@
*
* @author Andy Wilkinson
*/
-public class DocumentDevtoolsPropertyDefaults extends DefaultTask {
+public abstract class DocumentDevtoolsPropertyDefaults extends DefaultTask {
private final Configuration devtools;
- private final RegularFileProperty outputFile;
-
public DocumentDevtoolsPropertyDefaults() {
this.devtools = getProject().getConfigurations().create("devtools");
- this.outputFile = getProject().getObjects().fileProperty();
- this.outputFile.convention(getProject().getLayout()
+ getOutputFile().convention(getProject().getLayout()
.getBuildDirectory()
- .file("docs/generated/using/devtools-property-defaults.adoc"));
+ .file("generated/docs/using/devtools-property-defaults.adoc"));
Map dependency = new HashMap<>();
dependency.put("path", ":spring-boot-project:spring-boot-devtools");
dependency.put("configuration", "propertyDefaults");
@@ -63,9 +60,7 @@ public FileCollection getDevtools() {
}
@OutputFile
- public RegularFileProperty getOutputFile() {
- return this.outputFile;
- }
+ public abstract RegularFileProperty getOutputFile();
@TaskAction
void documentPropertyDefaults() throws IOException {
@@ -86,7 +81,7 @@ private Map loadProperties() throws IOException, FileNotFoundExc
}
private void documentProperties(Map properties) throws IOException {
- try (PrintWriter writer = new PrintWriter(new FileWriter(this.outputFile.getAsFile().get()))) {
+ try (PrintWriter writer = new PrintWriter(new FileWriter(getOutputFile().getAsFile().get()))) {
writer.println("[cols=\"3,1\"]");
writer.println("|===");
writer.println("| Name | Default Value");
diff --git a/buildSrc/src/main/java/org/springframework/boot/build/docs/ApplicationRunner.java b/buildSrc/src/main/java/org/springframework/boot/build/docs/ApplicationRunner.java
index 0f95d55d3d67..9f43c059d50e 100644
--- a/buildSrc/src/main/java/org/springframework/boot/build/docs/ApplicationRunner.java
+++ b/buildSrc/src/main/java/org/springframework/boot/build/docs/ApplicationRunner.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2012-2023 the original author or authors.
+ * Copyright 2012-2024 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -34,6 +34,7 @@
import org.gradle.api.file.FileCollection;
import org.gradle.api.file.RegularFileProperty;
import org.gradle.api.provider.ListProperty;
+import org.gradle.api.provider.MapProperty;
import org.gradle.api.provider.Property;
import org.gradle.api.tasks.Classpath;
import org.gradle.api.tasks.Input;
@@ -47,29 +48,17 @@
*
* @author Andy Wilkinson
*/
-public class ApplicationRunner extends DefaultTask {
-
- private final RegularFileProperty output = getProject().getObjects().fileProperty();
-
- private final ListProperty args = getProject().getObjects().listProperty(String.class);
-
- private final Property mainClass = getProject().getObjects().property(String.class);
-
- private final Property expectedLogging = getProject().getObjects().property(String.class);
-
- private final Property applicationJar = getProject().getObjects()
- .property(String.class)
- .convention("/opt/apps/myapp.jar");
-
- private final Map normalizations = new HashMap<>();
+public abstract class ApplicationRunner extends DefaultTask {
private FileCollection classpath;
- @OutputFile
- public RegularFileProperty getOutput() {
- return this.output;
+ public ApplicationRunner() {
+ getApplicationJar().convention("/opt/apps/myapp.jar");
}
+ @OutputFile
+ public abstract RegularFileProperty getOutput();
+
@Classpath
public FileCollection getClasspath() {
return this.classpath;
@@ -80,37 +69,27 @@ public void setClasspath(FileCollection classpath) {
}
@Input
- public ListProperty getArgs() {
- return this.args;
- }
+ public abstract ListProperty getArgs();
@Input
- public Property getMainClass() {
- return this.mainClass;
- }
+ public abstract Property getMainClass();
@Input
- public Property getExpectedLogging() {
- return this.expectedLogging;
- }
+ public abstract Property getExpectedLogging();
@Input
- Map getNormalizations() {
- return this.normalizations;
- }
+ abstract MapProperty getNormalizations();
@Input
- public Property getApplicationJar() {
- return this.applicationJar;
- }
+ abstract Property getApplicationJar();
public void normalizeTomcatPort() {
- this.normalizations.put("(Tomcat started on port\\(s\\): )[\\d]+( \\(http\\))", "$18080$2");
- this.normalizations.put("(Tomcat initialized with port\\(s\\): )[\\d]+( \\(http\\))", "$18080$2");
+ getNormalizations().put("(Tomcat started on port )[\\d]+( \\(http\\))", "$18080$2");
+ getNormalizations().put("(Tomcat initialized with port )[\\d]+( \\(http\\))", "$18080$2");
}
public void normalizeLiveReloadPort() {
- this.normalizations.put("(LiveReload server is running on port )[\\d]+", "$135729");
+ getNormalizations().put("(LiveReload server is running on port )[\\d]+", "$135729");
}
@TaskAction
@@ -123,9 +102,9 @@ void runApplication() throws IOException {
.stream()
.map(File::getAbsolutePath)
.collect(Collectors.joining(File.pathSeparator)));
- command.add(this.mainClass.get());
- command.addAll(this.args.get());
- File outputFile = this.output.getAsFile().get();
+ command.add(getMainClass().get());
+ command.addAll(getArgs().get());
+ File outputFile = getOutput().getAsFile().get();
Process process = new ProcessBuilder().redirectOutput(outputFile)
.redirectError(outputFile)
.command(command)
@@ -137,7 +116,7 @@ void runApplication() throws IOException {
private void awaitLogging(Process process) {
long end = System.currentTimeMillis() + 60000;
- String expectedLogging = this.expectedLogging.get();
+ String expectedLogging = getExpectedLogging().get();
while (System.currentTimeMillis() < end) {
for (String line : outputLines()) {
if (line.contains(expectedLogging)) {
@@ -152,7 +131,7 @@ private void awaitLogging(Process process) {
}
private List outputLines() {
- Path outputPath = this.output.get().getAsFile().toPath();
+ Path outputPath = getOutput().get().getAsFile().toPath();
try {
return Files.readAllLines(outputPath);
}
@@ -164,7 +143,7 @@ private List outputLines() {
private void normalizeLogging() {
List outputLines = outputLines();
List normalizedLines = normalize(outputLines);
- Path outputPath = this.output.get().getAsFile().toPath();
+ Path outputPath = getOutput().get().getAsFile().toPath();
try {
Files.write(outputPath, normalizedLines);
}
@@ -175,9 +154,9 @@ private void normalizeLogging() {
private List normalize(List lines) {
List normalizedLines = lines;
- Map normalizations = new HashMap<>(this.normalizations);
+ Map normalizations = new HashMap<>(getNormalizations().get());
normalizations.put("(Starting .* using Java .* with PID [\\d]+ \\().*( started by ).*( in ).*(\\))",
- "$1" + this.applicationJar.get() + "$2myuser$3/opt/apps/$4");
+ "$1" + getApplicationJar().get() + "$2myuser$3/opt/apps/$4");
for (Entry normalization : normalizations.entrySet()) {
Pattern pattern = Pattern.compile(normalization.getKey());
normalizedLines = normalize(normalizedLines, pattern, normalization.getValue());
diff --git a/buildSrc/src/main/java/org/springframework/boot/build/mavenplugin/DocumentPluginGoals.java b/buildSrc/src/main/java/org/springframework/boot/build/mavenplugin/DocumentPluginGoals.java
index f5256fc17c80..414ae1457007 100644
--- a/buildSrc/src/main/java/org/springframework/boot/build/mavenplugin/DocumentPluginGoals.java
+++ b/buildSrc/src/main/java/org/springframework/boot/build/mavenplugin/DocumentPluginGoals.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2012-2023 the original author or authors.
+ * Copyright 2012-2024 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -21,10 +21,12 @@
import java.io.IOException;
import java.io.PrintWriter;
import java.util.List;
-import java.util.Map;
import org.gradle.api.DefaultTask;
import org.gradle.api.Task;
+import org.gradle.api.file.DirectoryProperty;
+import org.gradle.api.file.RegularFileProperty;
+import org.gradle.api.provider.MapProperty;
import org.gradle.api.tasks.Input;
import org.gradle.api.tasks.InputFile;
import org.gradle.api.tasks.OutputDirectory;
@@ -39,46 +41,22 @@
*
* @author Andy Wilkinson
*/
-public class DocumentPluginGoals extends DefaultTask {
+public abstract class DocumentPluginGoals extends DefaultTask {
private final PluginXmlParser parser = new PluginXmlParser();
- private File pluginXml;
-
- private File outputDir;
-
- private Map goalSections;
-
@OutputDirectory
- public File getOutputDir() {
- return this.outputDir;
- }
-
- public void setOutputDir(File outputDir) {
- this.outputDir = outputDir;
- }
+ public abstract DirectoryProperty getOutputDir();
@Input
- public Map getGoalSections() {
- return this.goalSections;
- }
-
- public void setGoalSections(Map goalSections) {
- this.goalSections = goalSections;
- }
+ public abstract MapProperty getGoalSections();
@InputFile
- public File getPluginXml() {
- return this.pluginXml;
- }
-
- public void setPluginXml(File pluginXml) {
- this.pluginXml = pluginXml;
- }
+ public abstract RegularFileProperty getPluginXml();
@TaskAction
public void documentPluginGoals() throws IOException {
- Plugin plugin = this.parser.parse(this.pluginXml);
+ Plugin plugin = this.parser.parse(getPluginXml().getAsFile().get());
writeOverview(plugin);
for (Mojo mojo : plugin.getMojos()) {
documentMojo(plugin, mojo);
@@ -86,13 +64,14 @@ public void documentPluginGoals() throws IOException {
}
private void writeOverview(Plugin plugin) throws IOException {
- try (PrintWriter writer = new PrintWriter(new FileWriter(new File(this.outputDir, "overview.adoc")))) {
+ try (PrintWriter writer = new PrintWriter(
+ new FileWriter(new File(getOutputDir().getAsFile().get(), "overview.adoc")))) {
writer.println("[cols=\"1,3\"]");
writer.println("|===");
writer.println("| Goal | Description");
writer.println();
for (Mojo mojo : plugin.getMojos()) {
- writer.printf("| <<%s,%s:%s>>%n", goalSectionId(mojo), plugin.getGoalPrefix(), mojo.getGoal());
+ writer.printf("| xref:%s[%s:%s]%n", goalSectionId(mojo, false), plugin.getGoalPrefix(), mojo.getGoal());
writer.printf("| %s%n", mojo.getDescription());
writer.println();
}
@@ -101,12 +80,11 @@ private void writeOverview(Plugin plugin) throws IOException {
}
private void documentMojo(Plugin plugin, Mojo mojo) throws IOException {
- try (PrintWriter writer = new PrintWriter(new FileWriter(new File(this.outputDir, mojo.getGoal() + ".adoc")))) {
- String sectionId = goalSectionId(mojo);
- writer.println();
- writer.println();
+ try (PrintWriter writer = new PrintWriter(
+ new FileWriter(new File(getOutputDir().getAsFile().get(), mojo.getGoal() + ".adoc")))) {
+ String sectionId = goalSectionId(mojo, true);
writer.printf("[[%s]]%n", sectionId);
- writer.printf("= `%s:%s`%n", plugin.getGoalPrefix(), mojo.getGoal());
+ writer.printf("= `%s:%s`%n%n", plugin.getGoalPrefix(), mojo.getGoal());
writer.printf("`%s:%s:%s`%n", plugin.getGroupId(), plugin.getArtifactId(), plugin.getVersion());
writer.println();
writer.println(mojo.getDescription());
@@ -114,37 +92,43 @@ private void documentMojo(Plugin plugin, Mojo mojo) throws IOException {
List requiredParameters = parameters.stream().filter(Parameter::isRequired).toList();
String detailsSectionId = sectionId + ".parameter-details";
if (!requiredParameters.isEmpty()) {
+ writer.println();
writer.println();
writer.println();
writer.printf("[[%s.required-parameters]]%n", sectionId);
writer.println("== Required parameters");
+ writer.println();
writeParametersTable(writer, detailsSectionId, requiredParameters);
}
List optionalParameters = parameters.stream()
.filter((parameter) -> !parameter.isRequired())
.toList();
if (!optionalParameters.isEmpty()) {
+ writer.println();
writer.println();
writer.println();
writer.printf("[[%s.optional-parameters]]%n", sectionId);
writer.println("== Optional parameters");
+ writer.println();
writeParametersTable(writer, detailsSectionId, optionalParameters);
}
writer.println();
writer.println();
+ writer.println();
writer.printf("[[%s]]%n", detailsSectionId);
writer.println("== Parameter details");
+ writer.println();
writeParameterDetails(writer, parameters, detailsSectionId);
}
}
- private String goalSectionId(Mojo mojo) {
- String goalSection = this.goalSections.get(mojo.getGoal());
+ private String goalSectionId(Mojo mojo, boolean innerReference) {
+ String goalSection = getGoalSections().getting(mojo.getGoal()).get();
if (goalSection == null) {
throw new IllegalStateException("Goal '" + mojo.getGoal() + "' has not be assigned to a section");
}
String sectionId = goalSection + "." + mojo.getGoal() + "-goal";
- return sectionId;
+ return (!innerReference) ? goalSection + "#" + sectionId : sectionId;
}
private void writeParametersTable(PrintWriter writer, String detailsSectionId, List parameters) {
@@ -154,7 +138,7 @@ private void writeParametersTable(PrintWriter writer, String detailsSectionId, L
writer.println();
for (Parameter parameter : parameters) {
String name = parameter.getName();
- writer.printf("| <<%s.%s,%s>>%n", detailsSectionId, parameterId(name), name);
+ writer.printf("| xref:#%s.%s[%s]%n", detailsSectionId, parameterId(name), name);
writer.printf("| `%s`%n", typeNameToJavadocLink(shortTypeName(parameter.getType()), parameter.getType()));
String defaultValue = parameter.getDefaultValue();
if (defaultValue != null) {
@@ -236,10 +220,10 @@ private String typeNameToJavadocLink(String name) {
private String typeNameToJavadocLink(String shortName, String name) {
if (name.startsWith("org.springframework.boot.maven")) {
- return "{spring-boot-docs}/maven-plugin/api/" + typeNameToJavadocPath(name) + ".html[" + shortName + "]";
+ return "xref:maven-plugin:api/java/" + typeNameToJavadocPath(name) + ".html[" + shortName + "]";
}
if (name.startsWith("org.springframework.boot")) {
- return "{spring-boot-docs}/api/" + typeNameToJavadocPath(name) + ".html[" + shortName + "]";
+ return "xref:api:java/" + typeNameToJavadocPath(name) + ".html[" + shortName + "]";
}
return shortName;
}
diff --git a/buildSrc/src/main/java/org/springframework/boot/build/mavenplugin/MavenExec.java b/buildSrc/src/main/java/org/springframework/boot/build/mavenplugin/MavenExec.java
index fbbe5d651f6b..73ef436429ac 100644
--- a/buildSrc/src/main/java/org/springframework/boot/build/mavenplugin/MavenExec.java
+++ b/buildSrc/src/main/java/org/springframework/boot/build/mavenplugin/MavenExec.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2012-2023 the original author or authors.
+ * Copyright 2012-2024 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -24,8 +24,12 @@
import org.gradle.api.Project;
import org.gradle.api.Task;
import org.gradle.api.artifacts.Configuration;
+import org.gradle.api.file.DirectoryProperty;
+import org.gradle.api.file.RegularFileProperty;
+import org.gradle.api.tasks.InputFile;
import org.gradle.api.tasks.Internal;
import org.gradle.api.tasks.JavaExec;
+import org.gradle.api.tasks.PathSensitive;
import org.gradle.api.tasks.PathSensitivity;
import org.gradle.api.tasks.TaskExecutionException;
import org.gradle.process.internal.ExecException;
@@ -37,29 +41,29 @@
*
* @author Andy Wilkinson
*/
-public class MavenExec extends JavaExec {
+public abstract class MavenExec extends JavaExec {
private final Logger log = LoggerFactory.getLogger(MavenExec.class);
- private File projectDir;
-
public MavenExec() {
setClasspath(mavenConfiguration(getProject()));
args("--batch-mode");
getMainClass().set("org.apache.maven.cli.MavenCli");
+ getPom().set(getProjectDir().file("pom.xml"));
}
- public void setProjectDir(File projectDir) {
- this.projectDir = projectDir;
- getInputs().file(new File(projectDir, "pom.xml"))
- .withPathSensitivity(PathSensitivity.RELATIVE)
- .withPropertyName("pom");
- }
+ @Internal
+ public abstract DirectoryProperty getProjectDir();
+
+ @InputFile
+ @PathSensitive(PathSensitivity.RELATIVE)
+ abstract RegularFileProperty getPom();
@Override
public void exec() {
- workingDir(this.projectDir);
- systemProperty("maven.multiModuleProjectDirectory", this.projectDir.getAbsolutePath());
+ File workingDir = getProjectDir().getAsFile().get();
+ workingDir(workingDir);
+ systemProperty("maven.multiModuleProjectDirectory", workingDir.getAbsolutePath());
try {
Path logFile = Files.createTempFile(getName(), ".log");
try {
@@ -97,9 +101,4 @@ private Configuration mavenConfiguration(Project project) {
});
}
- @Internal
- public File getProjectDir() {
- return this.projectDir;
- }
-
}
diff --git a/buildSrc/src/main/java/org/springframework/boot/build/mavenplugin/MavenPluginPlugin.java b/buildSrc/src/main/java/org/springframework/boot/build/mavenplugin/MavenPluginPlugin.java
index 6301deb2b4b1..09eb5d333d45 100644
--- a/buildSrc/src/main/java/org/springframework/boot/build/mavenplugin/MavenPluginPlugin.java
+++ b/buildSrc/src/main/java/org/springframework/boot/build/mavenplugin/MavenPluginPlugin.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2012-2023 the original author or authors.
+ * Copyright 2012-2024 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -54,6 +54,8 @@
import org.gradle.api.artifacts.result.ResolvedArtifactResult;
import org.gradle.api.attributes.DocsType;
import org.gradle.api.attributes.Usage;
+import org.gradle.api.component.AdhocComponentWithVariants;
+import org.gradle.api.component.SoftwareComponent;
import org.gradle.api.file.CopySpec;
import org.gradle.api.file.DirectoryProperty;
import org.gradle.api.file.FileCollection;
@@ -65,6 +67,7 @@
import org.gradle.api.publish.PublishingExtension;
import org.gradle.api.publish.maven.MavenPublication;
import org.gradle.api.publish.maven.plugins.MavenPublishPlugin;
+import org.gradle.api.publish.tasks.GenerateModuleMetadata;
import org.gradle.api.tasks.Classpath;
import org.gradle.api.tasks.InputFiles;
import org.gradle.api.tasks.JavaExec;
@@ -82,11 +85,15 @@
import org.gradle.api.tasks.javadoc.Javadoc;
import org.gradle.external.javadoc.StandardJavadocDocletOptions;
import org.w3c.dom.Document;
+import org.w3c.dom.Element;
import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;
import org.springframework.boot.build.DeployedPlugin;
import org.springframework.boot.build.MavenRepositoryPlugin;
+import org.springframework.boot.build.optional.OptionalDependenciesPlugin;
+import org.springframework.boot.build.test.DockerTestPlugin;
import org.springframework.boot.build.test.IntegrationTestPlugin;
import org.springframework.core.CollectionFactory;
import org.springframework.util.Assert;
@@ -115,6 +122,33 @@ public void apply(Project project) {
addDocumentPluginGoalsTask(project, generatePluginDescriptorTask);
addPrepareMavenBinariesTask(project);
addExtractVersionPropertiesTask(project);
+ publishOptionalDependenciesInPom(project);
+ project.getTasks().withType(GenerateModuleMetadata.class).configureEach((task) -> task.setEnabled(false));
+ }
+
+ private void publishOptionalDependenciesInPom(Project project) {
+ project.getPlugins().withType(OptionalDependenciesPlugin.class, (optionalDependencies) -> {
+ SoftwareComponent component = project.getComponents().findByName("java");
+ if (component instanceof AdhocComponentWithVariants componentWithVariants) {
+ componentWithVariants.addVariantsFromConfiguration(
+ project.getConfigurations().getByName(OptionalDependenciesPlugin.OPTIONAL_CONFIGURATION_NAME),
+ (variant) -> variant.mapToOptional());
+ }
+ });
+ MavenPublication publication = (MavenPublication) project.getExtensions()
+ .getByType(PublishingExtension.class)
+ .getPublications()
+ .getByName("maven");
+ publication.getPom().withXml((xml) -> {
+ Element root = xml.asElement();
+ NodeList children = root.getChildNodes();
+ for (int i = 0; i < children.getLength(); i++) {
+ Node child = children.item(i);
+ if ("dependencyManagement".equals(child.getNodeName())) {
+ root.removeChild(child);
+ }
+ }
+ });
}
private void configurePomPackaging(Project project) {
@@ -134,15 +168,19 @@ private void addPopulateIntTestMavenRepositoryTask(Project project) {
project.getObjects().named(DocsType.class, "maven-repository")));
RuntimeClasspathMavenRepository runtimeClasspathMavenRepository = project.getTasks()
.create("runtimeClasspathMavenRepository", RuntimeClasspathMavenRepository.class);
- runtimeClasspathMavenRepository.getOutputDirectory()
+ runtimeClasspathMavenRepository.getOutputDir()
.set(new File(project.getBuildDir(), "runtime-classpath-repository"));
project.getDependencies()
.components((components) -> components.all(MavenRepositoryComponentMetadataRule.class));
- Sync task = project.getTasks().create("populateIntTestMavenRepository", Sync.class);
- task.setDestinationDir(new File(project.getBuildDir(), "int-test-maven-repository"));
+ Sync task = project.getTasks().create("populateTestMavenRepository", Sync.class);
+ task.setDestinationDir(new File(project.getBuildDir(), "test-maven-repository"));
task.with(copyIntTestMavenRepositoryFiles(project, runtimeClasspathMavenRepository));
task.dependsOn(project.getTasks().getByName(MavenRepositoryPlugin.PUBLISH_TO_PROJECT_REPOSITORY_TASK_NAME));
project.getTasks().getByName(IntegrationTestPlugin.INT_TEST_TASK_NAME).dependsOn(task);
+ project.getPlugins()
+ .withType(DockerTestPlugin.class)
+ .all((dockerTestPlugin) -> project.getTasks()
+ .named(DockerTestPlugin.DOCKER_TEST_TASK_NAME, (dockerTest) -> dockerTest.dependsOn(task)));
}
private CopySpec copyIntTestMavenRepositoryFiles(Project project,
@@ -157,8 +195,8 @@ private CopySpec copyIntTestMavenRepositoryFiles(Project project,
private void addDocumentPluginGoalsTask(Project project, MavenExec generatePluginDescriptorTask) {
DocumentPluginGoals task = project.getTasks().create("documentPluginGoals", DocumentPluginGoals.class);
File pluginXml = new File(generatePluginDescriptorTask.getOutputs().getFiles().getSingleFile(), "plugin.xml");
- task.setPluginXml(pluginXml);
- task.setOutputDir(new File(project.getBuildDir(), "docs/generated/goals/"));
+ task.getPluginXml().set(pluginXml);
+ task.getOutputDir().set(new File(project.getBuildDir(), "generated/docs/maven-plugin-goals/"));
task.dependsOn(generatePluginDescriptorTask);
}
@@ -172,7 +210,7 @@ private MavenExec addGenerateHelpMojoTask(Project project, Jar jarTask) {
private MavenExec createGenerateHelpMojoTask(Project project, File helpMojoDir) {
MavenExec task = project.getTasks().create("generateHelpMojo", MavenExec.class);
- task.setProjectDir(helpMojoDir);
+ task.getProjectDir().set(helpMojoDir);
task.args("org.apache.maven.plugins:maven-plugin-plugin:3.6.1:helpmojo");
task.getOutputs().dir(new File(helpMojoDir, "target/generated-sources/plugin"));
return task;
@@ -223,7 +261,7 @@ private FormatHelpMojoSource createFormatHelpMojoSource(Project project, MavenEx
FormatHelpMojoSource formatHelpMojoSource = project.getTasks()
.create("formatHelpMojoSource", FormatHelpMojoSource.class);
formatHelpMojoSource.setGenerator(generateHelpMojoTask);
- formatHelpMojoSource.setOutputDir(generatedHelpMojoDir);
+ formatHelpMojoSource.getOutputDir().set(generatedHelpMojoDir);
return formatHelpMojoSource;
}
@@ -246,7 +284,7 @@ private MavenExec createGeneratePluginDescriptorTask(Project project, File maven
.dir(new File(mavenDir, "target/classes/org"))
.withPathSensitivity(PathSensitivity.RELATIVE)
.withPropertyName("plugin classes");
- generatePluginDescriptor.setProjectDir(mavenDir);
+ generatePluginDescriptor.getProjectDir().set(mavenDir);
return generatePluginDescriptor;
}
@@ -257,8 +295,9 @@ private void includeDescriptorInJar(Jar jar, JavaExec generatePluginDescriptorTa
private void addPrepareMavenBinariesTask(Project project) {
TaskProvider task = project.getTasks()
- .register("prepareMavenBinaries", PrepareMavenBinaries.class, (prepareMavenBinaries) -> prepareMavenBinaries
- .setOutputDir(new File(project.getBuildDir(), "maven-binaries")));
+ .register("prepareMavenBinaries", PrepareMavenBinaries.class,
+ (prepareMavenBinaries) -> prepareMavenBinaries.getOutputDir()
+ .set(new File(project.getBuildDir(), "maven-binaries")));
project.getTasks()
.getByName(IntegrationTestPlugin.INT_TEST_TASK_NAME)
.getInputs()
@@ -286,12 +325,10 @@ private void addExtractVersionPropertiesTask(Project project) {
.map((dir) -> dir.file("extracted-versions.properties")));
}
- public static class FormatHelpMojoSource extends DefaultTask {
+ public abstract static class FormatHelpMojoSource extends DefaultTask {
private Task generator;
- private File outputDir;
-
void setGenerator(Task generator) {
this.generator = generator;
getInputs().files(this.generator)
@@ -300,13 +337,7 @@ void setGenerator(Task generator) {
}
@OutputDirectory
- public File getOutputDir() {
- return this.outputDir;
- }
-
- void setOutputDir(File outputDir) {
- this.outputDir = outputDir;
- }
+ public abstract DirectoryProperty getOutputDir();
@TaskAction
void syncAndFormat() {
@@ -319,7 +350,7 @@ void syncAndFormat() {
private void save(File output, FileEdit edit) {
Path relativePath = output.toPath().relativize(edit.getFile().toPath());
- Path outputLocation = this.outputDir.toPath().resolve(relativePath);
+ Path outputLocation = getOutputDir().getAsFile().get().toPath().resolve(relativePath);
try {
Files.createDirectories(outputLocation.getParent());
Files.writeString(outputLocation, edit.getFormattedContent());
@@ -363,21 +394,16 @@ private void configureVariant(ComponentMetadataContext context, VariantMetadata
}
- public static class RuntimeClasspathMavenRepository extends DefaultTask {
+ public abstract static class RuntimeClasspathMavenRepository extends DefaultTask {
private final Configuration runtimeClasspath;
- private final DirectoryProperty outputDirectory;
-
public RuntimeClasspathMavenRepository() {
this.runtimeClasspath = getProject().getConfigurations().getByName("runtimeClasspathWithMetadata");
- this.outputDirectory = getProject().getObjects().directoryProperty();
}
@OutputDirectory
- public DirectoryProperty getOutputDirectory() {
- return this.outputDirectory;
- }
+ public abstract DirectoryProperty getOutputDir();
@Classpath
public Configuration getRuntimeClasspath() {
@@ -391,7 +417,7 @@ public void createRepository() {
String fileName = result.getFile()
.getName()
.replace(identifier.getVersion() + "-" + identifier.getVersion(), identifier.getVersion());
- File repositoryLocation = this.outputDirectory
+ File repositoryLocation = getOutputDir()
.dir(identifier.getGroup().replace('.', '/') + "/" + identifier.getModule() + "/"
+ identifier.getVersion() + "/" + fileName)
.get()
@@ -410,16 +436,10 @@ public void createRepository() {
}
- public static class ExtractVersionProperties extends DefaultTask {
-
- private final RegularFileProperty destination;
+ public abstract static class ExtractVersionProperties extends DefaultTask {
private FileCollection effectiveBoms;
- public ExtractVersionProperties() {
- this.destination = getProject().getObjects().fileProperty();
- }
-
@InputFiles
@PathSensitive(PathSensitivity.RELATIVE)
public FileCollection getEffectiveBoms() {
@@ -431,9 +451,7 @@ public void setEffectiveBoms(FileCollection effectiveBoms) {
}
@OutputFile
- public RegularFileProperty getDestination() {
- return this.destination;
- }
+ public abstract RegularFileProperty getDestination();
@TaskAction
public void extractVersionProperties() {
@@ -443,7 +461,7 @@ public void extractVersionProperties() {
}
private void writeProperties(Properties versions) {
- File outputFile = this.destination.getAsFile().get();
+ File outputFile = getDestination().getAsFile().get();
outputFile.getParentFile().mkdirs();
try (Writer writer = new FileWriter(outputFile)) {
versions.store(writer, null);
diff --git a/buildSrc/src/main/java/org/springframework/boot/build/mavenplugin/PrepareMavenBinaries.java b/buildSrc/src/main/java/org/springframework/boot/build/mavenplugin/PrepareMavenBinaries.java
index 3ebc30a4e95e..69c741739d8b 100644
--- a/buildSrc/src/main/java/org/springframework/boot/build/mavenplugin/PrepareMavenBinaries.java
+++ b/buildSrc/src/main/java/org/springframework/boot/build/mavenplugin/PrepareMavenBinaries.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2012-2023 the original author or authors.
+ * Copyright 2012-2024 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -16,14 +16,11 @@
package org.springframework.boot.build.mavenplugin;
-import java.io.File;
-import java.util.Arrays;
-import java.util.LinkedHashSet;
-import java.util.Set;
-
import org.gradle.api.DefaultTask;
import org.gradle.api.Task;
import org.gradle.api.artifacts.Configuration;
+import org.gradle.api.file.DirectoryProperty;
+import org.gradle.api.provider.SetProperty;
import org.gradle.api.tasks.Input;
import org.gradle.api.tasks.OutputDirectory;
import org.gradle.api.tasks.TaskAction;
@@ -33,38 +30,22 @@
*
* @author Andy Wilkinson
*/
-public class PrepareMavenBinaries extends DefaultTask {
-
- private final Set versions = new LinkedHashSet<>();
-
- private File outputDir;
+public abstract class PrepareMavenBinaries extends DefaultTask {
@OutputDirectory
- public File getOutputDir() {
- return this.outputDir;
- }
-
- public void setOutputDir(File outputDir) {
- this.outputDir = outputDir;
- }
+ public abstract DirectoryProperty getOutputDir();
@Input
- public Set getVersions() {
- return this.versions;
- }
-
- public void versions(String... versions) {
- this.versions.addAll(Arrays.asList(versions));
- }
+ public abstract SetProperty getVersions();
@TaskAction
public void prepareBinaries() {
- for (String version : this.versions) {
+ for (String version : getVersions().get()) {
Configuration configuration = getProject().getConfigurations()
.detachedConfiguration(
getProject().getDependencies().create("org.apache.maven:apache-maven:" + version + ":bin@zip"));
getProject()
- .copy((copy) -> copy.into(this.outputDir).from(getProject().zipTree(configuration.getSingleFile())));
+ .copy((copy) -> copy.into(getOutputDir()).from(getProject().zipTree(configuration.getSingleFile())));
}
}
diff --git a/buildSrc/src/main/java/org/springframework/boot/build/starters/DocumentStarters.java b/buildSrc/src/main/java/org/springframework/boot/build/starters/DocumentStarters.java
index 669eeb40a0ba..fabbd7a93aad 100644
--- a/buildSrc/src/main/java/org/springframework/boot/build/starters/DocumentStarters.java
+++ b/buildSrc/src/main/java/org/springframework/boot/build/starters/DocumentStarters.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2012-2023 the original author or authors.
+ * Copyright 2012-2024 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -33,6 +33,7 @@
import org.gradle.api.DefaultTask;
import org.gradle.api.Task;
import org.gradle.api.artifacts.Configuration;
+import org.gradle.api.file.DirectoryProperty;
import org.gradle.api.file.FileCollection;
import org.gradle.api.tasks.InputFiles;
import org.gradle.api.tasks.OutputDirectory;
@@ -47,12 +48,10 @@
*
* @author Andy Wilkinson
*/
-public class DocumentStarters extends DefaultTask {
+public abstract class DocumentStarters extends DefaultTask {
private final Configuration starters;
- private File outputDir;
-
public DocumentStarters() {
this.starters = getProject().getConfigurations().create("starters");
getProject().getGradle().projectsEvaluated((gradle) -> {
@@ -68,13 +67,7 @@ public DocumentStarters() {
}
@OutputDirectory
- public File getOutputDir() {
- return this.outputDir;
- }
-
- public void setOutputDir(File outputDir) {
- this.outputDir = outputDir;
- }
+ public abstract DirectoryProperty getOutputDir();
@InputFiles
@PathSensitive(PathSensitivity.RELATIVE)
@@ -106,7 +99,7 @@ private Starter loadStarter(File metadata) {
}
private void writeTable(String name, Stream starters) {
- File output = new File(this.outputDir, name + ".adoc");
+ File output = new File(getOutputDir().getAsFile().get(), name + ".adoc");
output.getParentFile().mkdirs();
try (PrintWriter writer = new PrintWriter(new FileWriter(output))) {
writer.println("|===");
@@ -128,7 +121,7 @@ private String postProcessDescription(String description) {
}
private String addStarterCrossLinks(String input) {
- return input.replaceAll("(spring-boot-starter[A-Za-z-]*)", "<<$1,`$1`>>");
+ return input.replaceAll("(spring-boot-starter[A-Za-z-]*)", "xref:#$1[`$1`]");
}
private static final class Starter implements Comparable {
diff --git a/buildSrc/src/main/java/org/springframework/boot/build/test/DockerTestBuildService.java b/buildSrc/src/main/java/org/springframework/boot/build/test/DockerTestBuildService.java
new file mode 100644
index 000000000000..2f70a735513c
--- /dev/null
+++ b/buildSrc/src/main/java/org/springframework/boot/build/test/DockerTestBuildService.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2012-2024 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.boot.build.test;
+
+import org.gradle.api.Project;
+import org.gradle.api.provider.Provider;
+import org.gradle.api.services.BuildService;
+import org.gradle.api.services.BuildServiceParameters;
+
+/**
+ * Build service for Docker-based tests. Configured to only allow serial execution,
+ * thereby ensuring that Docker-based tests do not run in parallel.
+ *
+ * @author Andy Wilkinson
+ */
+abstract class DockerTestBuildService implements BuildService {
+
+ static Provider registerIfNecessary(Project project) {
+ return project.getGradle()
+ .getSharedServices()
+ .registerIfAbsent("dockerTest", DockerTestBuildService.class, (spec) -> spec.getMaxParallelUsages().set(1));
+ }
+
+}
diff --git a/buildSrc/src/main/java/org/springframework/boot/build/test/DockerTestPlugin.java b/buildSrc/src/main/java/org/springframework/boot/build/test/DockerTestPlugin.java
new file mode 100644
index 000000000000..017ca001a43b
--- /dev/null
+++ b/buildSrc/src/main/java/org/springframework/boot/build/test/DockerTestPlugin.java
@@ -0,0 +1,112 @@
+/*
+ * Copyright 2012-2024 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.boot.build.test;
+
+import org.gradle.api.Plugin;
+import org.gradle.api.Project;
+import org.gradle.api.plugins.JavaPlugin;
+import org.gradle.api.plugins.JavaPluginExtension;
+import org.gradle.api.provider.Provider;
+import org.gradle.api.services.BuildService;
+import org.gradle.api.tasks.SourceSet;
+import org.gradle.api.tasks.SourceSetContainer;
+import org.gradle.api.tasks.testing.Test;
+import org.gradle.language.base.plugins.LifecycleBasePlugin;
+import org.gradle.plugins.ide.eclipse.EclipsePlugin;
+import org.gradle.plugins.ide.eclipse.model.EclipseModel;
+
+/**
+ * Plugin for Docker-based tests. Creates a {@link SourceSet source set}, {@link Test
+ * test} task, and {@link BuildService shared service} named {@code dockerTest}. The build
+ * service is configured to only allow serial usage and the {@code dockerTest} task is
+ * configured to use the build service. In a parallel build, this ensures that only a
+ * single {@code dockerTest} task can run at any given time.
+ *
+ * @author Andy Wilkinson
+ */
+public class DockerTestPlugin implements Plugin {
+
+ /**
+ * Name of the {@code dockerTest} task.
+ */
+ public static String DOCKER_TEST_TASK_NAME = "dockerTest";
+
+ /**
+ * Name of the {@code dockerTest} source set.
+ */
+ public static String DOCKER_TEST_SOURCE_SET_NAME = "dockerTest";
+
+ /**
+ * Name of the {@code dockerTest} shared service.
+ */
+ public static String DOCKER_TEST_SERVICE_NAME = "dockerTest";
+
+ @Override
+ public void apply(Project project) {
+ project.getPlugins().withType(JavaPlugin.class, (javaPlugin) -> configureDockerTesting(project));
+ }
+
+ private void configureDockerTesting(Project project) {
+ Provider buildService = DockerTestBuildService.registerIfNecessary(project);
+ SourceSet dockerTestSourceSet = createSourceSet(project);
+ Provider dockerTest = createTestTask(project, dockerTestSourceSet, buildService);
+ project.getTasks().getByName(LifecycleBasePlugin.CHECK_TASK_NAME).dependsOn(dockerTest);
+ project.getPlugins().withType(EclipsePlugin.class, (eclipsePlugin) -> {
+ EclipseModel eclipse = project.getExtensions().getByType(EclipseModel.class);
+ eclipse.classpath((classpath) -> classpath.getPlusConfigurations()
+ .add(project.getConfigurations()
+ .getByName(dockerTestSourceSet.getRuntimeClasspathConfigurationName())));
+ });
+ }
+
+ private SourceSet createSourceSet(Project project) {
+ SourceSetContainer sourceSets = project.getExtensions().getByType(JavaPluginExtension.class).getSourceSets();
+ SourceSet dockerTestSourceSet = sourceSets.create(DOCKER_TEST_SOURCE_SET_NAME);
+ SourceSet main = sourceSets.getByName(SourceSet.MAIN_SOURCE_SET_NAME);
+ SourceSet test = sourceSets.getByName(SourceSet.TEST_SOURCE_SET_NAME);
+ dockerTestSourceSet.setCompileClasspath(dockerTestSourceSet.getCompileClasspath()
+ .plus(main.getOutput())
+ .plus(main.getCompileClasspath())
+ .plus(test.getOutput()));
+ dockerTestSourceSet.setRuntimeClasspath(dockerTestSourceSet.getRuntimeClasspath()
+ .plus(main.getOutput())
+ .plus(main.getRuntimeClasspath())
+ .plus(test.getOutput()));
+ project.getPlugins().withType(IntegrationTestPlugin.class, (integrationTestPlugin) -> {
+ SourceSet intTest = sourceSets.getByName(IntegrationTestPlugin.INT_TEST_SOURCE_SET_NAME);
+ dockerTestSourceSet
+ .setCompileClasspath(dockerTestSourceSet.getCompileClasspath().plus(intTest.getOutput()));
+ dockerTestSourceSet
+ .setRuntimeClasspath(dockerTestSourceSet.getRuntimeClasspath().plus(intTest.getOutput()));
+ });
+ return dockerTestSourceSet;
+ }
+
+ private Provider createTestTask(Project project, SourceSet dockerTestSourceSet,
+ Provider buildService) {
+ Provider dockerTest = project.getTasks().register(DOCKER_TEST_TASK_NAME, Test.class, (task) -> {
+ task.usesService(buildService);
+ task.setGroup(LifecycleBasePlugin.VERIFICATION_GROUP);
+ task.setDescription("Runs Docker-based tests.");
+ task.setTestClassesDirs(dockerTestSourceSet.getOutput().getClassesDirs());
+ task.setClasspath(dockerTestSourceSet.getRuntimeClasspath());
+ task.shouldRunAfter(JavaPlugin.TEST_TASK_NAME);
+ });
+ return dockerTest;
+ }
+
+}
diff --git a/buildSrc/src/main/java/org/springframework/boot/build/test/autoconfigure/DocumentTestSlices.java b/buildSrc/src/main/java/org/springframework/boot/build/test/autoconfigure/DocumentTestSlices.java
index 012790904704..939f425ab4db 100644
--- a/buildSrc/src/main/java/org/springframework/boot/build/test/autoconfigure/DocumentTestSlices.java
+++ b/buildSrc/src/main/java/org/springframework/boot/build/test/autoconfigure/DocumentTestSlices.java
@@ -32,6 +32,7 @@
import org.gradle.api.DefaultTask;
import org.gradle.api.Task;
import org.gradle.api.file.FileCollection;
+import org.gradle.api.file.RegularFileProperty;
import org.gradle.api.tasks.InputFiles;
import org.gradle.api.tasks.OutputFile;
import org.gradle.api.tasks.PathSensitive;
@@ -46,12 +47,10 @@
*
* @author Andy Wilkinson
*/
-public class DocumentTestSlices extends DefaultTask {
+public abstract class DocumentTestSlices extends DefaultTask {
private FileCollection testSlices;
- private File outputFile;
-
@InputFiles
@PathSensitive(PathSensitivity.RELATIVE)
public FileCollection getTestSlices() {
@@ -63,13 +62,7 @@ public void setTestSlices(FileCollection testSlices) {
}
@OutputFile
- public File getOutputFile() {
- return this.outputFile;
- }
-
- public void setOutputFile(File outputFile) {
- this.outputFile = outputFile;
- }
+ public abstract RegularFileProperty getOutputFile();
@TaskAction
void documentTestSlices() throws IOException {
@@ -94,8 +87,9 @@ private Set readTestSlices() throws IOException {
}
private void writeTable(Set testSlices) throws IOException {
- this.outputFile.getParentFile().mkdirs();
- try (PrintWriter writer = new PrintWriter(new FileWriter(this.outputFile))) {
+ File outputFile = getOutputFile().getAsFile().get();
+ outputFile.getParentFile().mkdirs();
+ try (PrintWriter writer = new PrintWriter(new FileWriter(outputFile))) {
writer.println("[cols=\"d,a\"]");
writer.println("|===");
writer.println("| Test slice | Imported auto-configuration");
diff --git a/buildSrc/src/main/java/org/springframework/boot/build/test/autoconfigure/TestSliceMetadata.java b/buildSrc/src/main/java/org/springframework/boot/build/test/autoconfigure/TestSliceMetadata.java
index 3c4c8a478d75..60ba288ec4c7 100644
--- a/buildSrc/src/main/java/org/springframework/boot/build/test/autoconfigure/TestSliceMetadata.java
+++ b/buildSrc/src/main/java/org/springframework/boot/build/test/autoconfigure/TestSliceMetadata.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2012-2023 the original author or authors.
+ * Copyright 2012-2024 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -32,7 +32,6 @@
import java.util.Properties;
import java.util.SortedSet;
import java.util.TreeSet;
-import java.util.concurrent.Callable;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;
@@ -41,7 +40,12 @@
import org.gradle.api.Task;
import org.gradle.api.artifacts.Configuration;
import org.gradle.api.file.FileCollection;
+import org.gradle.api.file.RegularFileProperty;
+import org.gradle.api.tasks.Classpath;
+import org.gradle.api.tasks.InputFile;
+import org.gradle.api.tasks.InputFiles;
import org.gradle.api.tasks.OutputFile;
+import org.gradle.api.tasks.PathSensitive;
import org.gradle.api.tasks.PathSensitivity;
import org.gradle.api.tasks.SourceSet;
import org.gradle.api.tasks.TaskAction;
@@ -59,44 +63,57 @@
*
* @author Andy Wilkinson
*/
-public class TestSliceMetadata extends DefaultTask {
+public abstract class TestSliceMetadata extends DefaultTask {
- private SourceSet sourceSet;
+ private FileCollection classpath;
- private File outputFile;
+ private FileCollection importsFiles;
+
+ private FileCollection classesDirs;
public TestSliceMetadata() {
- getInputs().dir((Callable) () -> this.sourceSet.getOutput().getResourcesDir())
- .withPathSensitivity(PathSensitivity.RELATIVE)
- .withPropertyName("resources");
- dependsOn((Callable) () -> this.sourceSet.getProcessResourcesTaskName());
- getInputs().files((Callable) () -> this.sourceSet.getOutput().getClassesDirs())
- .withPathSensitivity(PathSensitivity.RELATIVE)
- .withPropertyName("classes");
+ Configuration testSliceMetadata = getProject().getConfigurations().maybeCreate("testSliceMetadata");
+ getProject().afterEvaluate((evaluated) -> evaluated.getArtifacts()
+ .add(testSliceMetadata.getName(), getOutputFile(), (artifact) -> artifact.builtBy(this)));
}
public void setSourceSet(SourceSet sourceSet) {
- this.sourceSet = sourceSet;
+ this.classpath = sourceSet.getRuntimeClasspath();
+ this.importsFiles = getProject().fileTree(new File(sourceSet.getOutput().getResourcesDir(), "META-INF/spring"),
+ (tree) -> tree.filter((file) -> file.getName().endsWith(".imports")));
+ getSpringFactories().set(new File(sourceSet.getOutput().getResourcesDir(), "META-INF/spring.factories"));
+ this.classesDirs = sourceSet.getOutput().getClassesDirs();
}
@OutputFile
- public File getOutputFile() {
- return this.outputFile;
+ public abstract RegularFileProperty getOutputFile();
+
+ @InputFile
+ @PathSensitive(PathSensitivity.RELATIVE)
+ abstract RegularFileProperty getSpringFactories();
+
+ @Classpath
+ FileCollection getClasspath() {
+ return this.classpath;
}
- public void setOutputFile(File outputFile) {
- this.outputFile = outputFile;
- Configuration testSliceMetadata = getProject().getConfigurations().maybeCreate("testSliceMetadata");
- getProject().getArtifacts()
- .add(testSliceMetadata.getName(), getProject().provider((Callable) this::getOutputFile),
- (artifact) -> artifact.builtBy(this));
+ @InputFiles
+ @PathSensitive(PathSensitivity.RELATIVE)
+ FileCollection getImportFiles() {
+ return this.importsFiles;
+ }
+
+ @Classpath
+ FileCollection getClassesDirs() {
+ return this.classesDirs;
}
@TaskAction
void documentTestSlices() throws IOException {
Properties testSlices = readTestSlices();
- getOutputFile().getParentFile().mkdirs();
- try (FileWriter writer = new FileWriter(getOutputFile())) {
+ File outputFile = getOutputFile().getAsFile().get();
+ outputFile.getParentFile().mkdirs();
+ try (FileWriter writer = new FileWriter(outputFile)) {
testSlices.store(writer, null);
}
}
@@ -104,15 +121,11 @@ void documentTestSlices() throws IOException {
private Properties readTestSlices() throws IOException {
Properties testSlices = CollectionFactory.createSortedProperties(true);
try (URLClassLoader classLoader = new URLClassLoader(
- StreamSupport.stream(this.sourceSet.getRuntimeClasspath().spliterator(), false)
- .map(this::toURL)
- .toArray(URL[]::new))) {
+ StreamSupport.stream(this.classpath.spliterator(), false).map(this::toURL).toArray(URL[]::new))) {
MetadataReaderFactory metadataReaderFactory = new SimpleMetadataReaderFactory(classLoader);
- Properties springFactories = readSpringFactories(
- new File(this.sourceSet.getOutput().getResourcesDir(), "META-INF/spring.factories"));
- readTestSlicesDirectory(springFactories,
- new File(this.sourceSet.getOutput().getResourcesDir(), "META-INF/spring/"));
- for (File classesDir : this.sourceSet.getOutput().getClassesDirs()) {
+ Properties springFactories = readSpringFactories(getSpringFactories().getAsFile().get());
+ readImportsFiles(springFactories, this.importsFiles);
+ for (File classesDir : this.classesDirs) {
addTestSlices(testSlices, classesDir, metadataReaderFactory, springFactories);
}
}
@@ -120,18 +133,14 @@ private Properties readTestSlices() throws IOException {
}
/**
- * Reads files from the given directory and puts them in springFactories. The key is
- * the file name, the value is the file contents, split by line, delimited with comma.
- * This is done to mimic the spring.factories structure.
+ * Reads the given imports files and puts them in springFactories. The key is the file
+ * name, the value is the file contents, split by line, delimited with a comma. This
+ * is done to mimic the spring.factories structure.
* @param springFactories spring.factories parsed as properties
- * @param directory directory to scan
+ * @param importsFiles the imports files to read
*/
- private void readTestSlicesDirectory(Properties springFactories, File directory) {
- File[] files = directory.listFiles((dir, name) -> name.endsWith(".imports"));
- if (files == null) {
- return;
- }
- for (File file : files) {
+ private void readImportsFiles(Properties springFactories, FileCollection importsFiles) {
+ for (File file : importsFiles.getFiles()) {
try {
List lines = removeComments(Files.readAllLines(file.toPath()));
String fileNameWithoutExtension = file.getName()
diff --git a/buildSrc/src/main/java/org/springframework/boot/build/toolchain/ToolchainPlugin.java b/buildSrc/src/main/java/org/springframework/boot/build/toolchain/ToolchainPlugin.java
index 82abe1cd65d1..b5e602d7fa08 100644
--- a/buildSrc/src/main/java/org/springframework/boot/build/toolchain/ToolchainPlugin.java
+++ b/buildSrc/src/main/java/org/springframework/boot/build/toolchain/ToolchainPlugin.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2012-2023 the original author or authors.
+ * Copyright 2012-2024 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -71,8 +71,7 @@ private void disableToolchainTasks(Project project) {
}
private void configureTestToolchain(Project project, ToolchainExtension toolchain) {
- List jvmArgs = new ArrayList<>();
- jvmArgs.addAll(toolchain.getTestJvmArgs().getOrElse(Collections.emptyList()));
+ List jvmArgs = new ArrayList<>(toolchain.getTestJvmArgs().getOrElse(Collections.emptyList()));
project.getTasks().withType(Test.class, (test) -> test.jvmArgs(jvmArgs));
}
diff --git a/buildSrc/src/main/resources/org/springframework/boot/build/antora/antora-asciidoc-attributes.properties b/buildSrc/src/main/resources/org/springframework/boot/build/antora/antora-asciidoc-attributes.properties
new file mode 100644
index 000000000000..023a3473c5d3
--- /dev/null
+++ b/buildSrc/src/main/resources/org/springframework/boot/build/antora/antora-asciidoc-attributes.properties
@@ -0,0 +1,75 @@
+# === INCLUDE-CODE LOCATIONS ===
+
+include-java=ROOT:example$java/org/springframework/boot/docs
+include-kotlin= ROOT:example$kotlin/org/springframework/boot/docs
+
+# === URLs ===
+
+url-ant-docs=https://ant.apache.org/manual
+url-buildpacks-docs=https://buildpacks.io/docs
+url-dynatrace-docs=https://docs.dynatrace.com/docs
+url-dynatrace-docs-shortlink={url-dynatrace-docs}/shortlink
+url-github-raw=https://raw.githubusercontent.com/{github-repo}/{github-ref}
+url-github-issues=https://github.com/{github-repo}/issues
+url-github-wiki=https://github.com/{github-repo}/wiki
+url-github=https://github.com/{github-repo}
+url-graal-docs=https://www.graalvm.org/{version-graal}/reference-manual
+url-graal-docs-native-image={url-graal-docs}/native-image
+url-gradle-docs=https://docs.gradle.org/current/userguide
+url-gradle-docs-application-plugin={url-gradle-docs}/application_plugin.html
+url-gradle-docs-groovy-plugin={url-gradle-docs}/groovy_plugin.html
+url-gradle-docs-java-plugin={url-gradle-docs}/java_plugin.html
+url-gradle-docs-war-plugin={url-gradle-docs}/war_plugin.html
+url-gradle-dsl=https://docs.gradle.org/current/dsl
+url-gradle-javadoc=https://docs.gradle.org/current/javadoc
+url-kotlin-docs-kotlin-plugin={url-kotlin-docs}/using-gradle.html
+url-micrometer-docs-concepts={url-micrometer-docs}/concepts
+url-micrometer-docs-implementations={url-micrometer-docs}/implementations
+url-download-liberica-nik=https://bell-sw.com/pages/downloads/native-image-kit/#/nik-22-17
+url-native-build-tools-docs=https://graalvm.github.io/native-build-tools/{version-native-build-tools}
+url-native-build-tools-docs-gradle-plugin={url-native-build-tools-docs}/gradle-plugin.html
+url-native-build-tools-docs-maven-plugin={url-native-build-tools-docs}/maven-plugin.html
+url-paketo-docs=https://paketo.io/docs
+url-paketo-docs-java-buildpack={url-paketo-docs}/buildpacks/language-family-buildpacks/java
+url-spring-boot-for-apache-geode-docs=https://docs.spring.io/spring-boot-data-geode-build/2.0.x/reference/html5
+url-spring-boot-for-apache-geode-site=https://github.com/spring-projects/spring-boot-data-geode
+url-spring-data-cassandra-site=https://spring.io/projects/spring-data-cassandra
+url-spring-data-commons-javadoc=https://docs.spring.io/spring-data/commons/docs/{version-spring-data-commons}/api
+url-spring-data-couchbase-docs=https://docs.spring.io/spring-data/couchbase/reference/{version-spring-data-couchbase}
+url-spring-data-couchbase-site=https://spring.io/projects/spring-data-couchbase
+url-spring-data-elasticsearch-docs=https://docs.spring.io/spring-data/elasticsearch/reference/{version-spring-data-elasticsearch}
+url-spring-data-elasticsearch-site=https://spring.io/projects/spring-data-elasticsearch
+url-spring-data-envers-site=https://spring.io/projects/spring-data-envers
+url-spring-data-gemfire-site=https://spring.io/projects/spring-data-gemfire
+url-spring-data-geode-site=https://spring.io/projects/spring-data-geode
+url-spring-data-jdbc-docs=https://docs.spring.io/spring-data/relational/reference/{version-spring-data-jdbc}
+url-spring-data-jpa-javadoc=https://docs.spring.io/spring-data/jpa/docs/{version-spring-data-jpa}/api
+url-spring-data-jpa-site=https://spring.io/projects/spring-jpa
+url-spring-data-jpa-docs=https://docs.spring.io/spring-data/jpa/reference/{version-spring-data-jpa}
+url-spring-data-ldap-site=https://spring.io/projects/spring-data-ldap
+url-spring-data-mongodb-javadoc=https://docs.spring.io/spring-data/mongodb/docs/{version-spring-data-mongodb}/api
+url-spring-data-mongodb-site=https://spring.io/projects/spring-data-mongodb
+url-spring-data-mongodb-docs=https://docs.spring.io/spring-data/mongodb/reference/{version-spring-data-mongodb}
+url-spring-data-neo4j-docs=https://docs.spring.io/spring-data/neo4j/reference/{version-spring-data-neo4j}
+url-spring-data-neo4j-site=https://spring.io/projects/spring-data-neo4j
+url-spring-data-r2dbc-javadoc=https://docs.spring.io/spring-data/r2dbc/docs/{version-spring-data-r2dbc}/api
+url-spring-data-r2dbc-docs=https://docs.spring.io/spring-data/relational/reference/{version-spring-data-r2dbc}
+url-spring-data-redis-site=https://spring.io/projects/spring-data-redis
+url-spring-data-rest-javadoc=https://docs.spring.io/spring-data/rest/docs/{version-spring-data-rest}/api
+url-spring-data-site=https://spring.io/projects/spring-data
+
+# === API References ===
+
+apiref-gradle-plugin-boot-build-image=xref:gradle-plugin:api/java/org/springframework/boot/gradle/tasks/bundling/BootBuildImage.html
+apiref-gradle-plugin-boot-jar=xref:gradle-plugin:api/java/org/springframework/boot/gradle/tasks/bundling/BootJar.html
+apiref-gradle-plugin-boot-run=xref:gradle-plugin:api/java/org/springframework/boot/gradle/tasks/run/BootRun.html
+apiref-gradle-plugin-boot-war=xref:gradle-plugin:api/java/org/springframework/boot/gradle/tasks/bundling/BootWar.html
+apiref-gradle-plugin-boot-build-info=xref:gradle-plugin:api/java/org/springframework/boot/gradle/tasks/buildinfo/BuildInfo.html
+apiref-openjdk=https://docs.oracle.com/en/java/javase/17/docs/api
+
+# === Code Links ===
+
+code-spring-boot=https://github.com/{github-repo}/tree/{github-ref}
+code-spring-boot-autoconfigure-src={code-spring-boot}/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure
+code-spring-boot-latest=https://github.com/{github-repo}/tree/main
+
diff --git a/buildSrc/src/main/resources/org/springframework/boot/build/antora/antora-playbook-template.yml b/buildSrc/src/main/resources/org/springframework/boot/build/antora/antora-playbook-template.yml
new file mode 100644
index 000000000000..6960bc197928
--- /dev/null
+++ b/buildSrc/src/main/resources/org/springframework/boot/build/antora/antora-playbook-template.yml
@@ -0,0 +1,24 @@
+antora:
+ extensions:
+site:
+ title: Spring Boot
+content:
+ sources: []
+asciidoc:
+ sourcemap: true
+ attributes:
+ chomp: all
+ hide-uri-scheme: '@'
+ page-pagination: ''
+ page-stackoverflow-url: https://stackoverflow.com/tags/spring-boot
+ tabs-sync-option: '@'
+ extensions:
+ - '@asciidoctor/tabs'
+ - '@springio/asciidoctor-extensions'
+ - '@springio/asciidoctor-extensions/configuration-properties-extension'
+ - '@springio/asciidoctor-extensions/section-ids-extension'
+urls:
+ latest_version_segment: ''
+runtime:
+ log:
+ failure_level: warn
diff --git a/buildSrc/src/test/java/org/springframework/boot/build/ConventionsPluginTests.java b/buildSrc/src/test/java/org/springframework/boot/build/ConventionsPluginTests.java
index 15dda0d9336f..539cb3781795 100644
--- a/buildSrc/src/test/java/org/springframework/boot/build/ConventionsPluginTests.java
+++ b/buildSrc/src/test/java/org/springframework/boot/build/ConventionsPluginTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2012-2023 the original author or authors.
+ * Copyright 2012-2024 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/buildSrc/src/test/java/org/springframework/boot/build/antora/AntoraAsciidocAttributesTests.java b/buildSrc/src/test/java/org/springframework/boot/build/antora/AntoraAsciidocAttributesTests.java
new file mode 100644
index 000000000000..c197e3cefd40
--- /dev/null
+++ b/buildSrc/src/test/java/org/springframework/boot/build/antora/AntoraAsciidocAttributesTests.java
@@ -0,0 +1,172 @@
+/*
+ * Copyright 2012-2024 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.boot.build.antora;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.function.Function;
+
+import org.junit.jupiter.api.Test;
+
+import org.springframework.boot.build.bom.Library;
+import org.springframework.boot.build.bom.Library.Group;
+import org.springframework.boot.build.bom.Library.LibraryVersion;
+import org.springframework.boot.build.bom.Library.ProhibitedVersion;
+import org.springframework.boot.build.bom.Library.VersionAlignment;
+import org.springframework.boot.build.bom.bomr.version.DependencyVersion;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+/**
+ * Tests for {@link AntoraAsciidocAttributes}.
+ *
+ * @author Phillip Webb
+ */
+class AntoraAsciidocAttributesTests {
+
+ @Test
+ void githubRefWhenReleasedVersionIsTag() {
+ AntoraAsciidocAttributes attributes = new AntoraAsciidocAttributes("1.2.3", true, null,
+ mockDependencyVersions(), null);
+ assertThat(attributes.get()).containsEntry("github-ref", "v1.2.3");
+ }
+
+ @Test
+ void githubRefWhenLatestSnapshotVersionIsMainBranch() {
+ AntoraAsciidocAttributes attributes = new AntoraAsciidocAttributes("1.2.3-SNAPSHOT", true, null,
+ mockDependencyVersions(), null);
+ assertThat(attributes.get()).containsEntry("github-ref", "main");
+ }
+
+ @Test
+ void githubRefWhenOlderSnapshotVersionIsBranch() {
+ AntoraAsciidocAttributes attributes = new AntoraAsciidocAttributes("1.2.3-SNAPSHOT", false, null,
+ mockDependencyVersions(), null);
+ assertThat(attributes.get()).containsEntry("github-ref", "1.2.x");
+ }
+
+ @Test
+ void githubRefWhenOlderSnapshotHotFixVersionIsBranch() {
+ AntoraAsciidocAttributes attributes = new AntoraAsciidocAttributes("1.2.3.1-SNAPSHOT", false, null,
+ mockDependencyVersions(), null);
+ assertThat(attributes.get()).containsEntry("github-ref", "1.2.3.x");
+ }
+
+ @Test
+ void versionReferenceFromLibrary() {
+ Library library = mockLibrary(Collections.emptyMap());
+ AntoraAsciidocAttributes attributes = new AntoraAsciidocAttributes("1.2.3.1-SNAPSHOT", false, List.of(library),
+ mockDependencyVersions(), null);
+ assertThat(attributes.get()).containsEntry("version-spring-framework", "1.2.3");
+ }
+
+ @Test
+ void versionReferenceFromSpringDataDependencyVersion() {
+ AntoraAsciidocAttributes attributes = new AntoraAsciidocAttributes("1.2.3", true, null,
+ mockDependencyVersions(), null);
+ assertThat(attributes.get()).containsEntry("version-spring-data-mongodb", "1.2.3");
+ }
+
+ @Test
+ void versionNativeBuildTools() {
+ AntoraAsciidocAttributes attributes = new AntoraAsciidocAttributes("1.2.3", true, null,
+ mockDependencyVersions(), Map.of("nativeBuildToolsVersion", "3.4.5"));
+ assertThat(attributes.get()).containsEntry("version-native-build-tools", "3.4.5");
+ }
+
+ @Test
+ void urlArtifactRepositoryWhenRelease() {
+ AntoraAsciidocAttributes attributes = new AntoraAsciidocAttributes("1.2.3", true, null,
+ mockDependencyVersions(), null);
+ assertThat(attributes.get()).containsEntry("url-artifact-repository", "https://repo.maven.apache.org/maven2");
+ }
+
+ @Test
+ void urlArtifactRepositoryWhenMilestone() {
+ AntoraAsciidocAttributes attributes = new AntoraAsciidocAttributes("1.2.3-M1", true, null,
+ mockDependencyVersions(), null);
+ assertThat(attributes.get()).containsEntry("url-artifact-repository", "https://repo.spring.io/milestone");
+ }
+
+ @Test
+ void urlArtifactRepositoryWhenSnapshot() {
+ AntoraAsciidocAttributes attributes = new AntoraAsciidocAttributes("1.2.3-SNAPSHOT", true, null,
+ mockDependencyVersions(), null);
+ assertThat(attributes.get()).containsEntry("url-artifact-repository", "https://repo.spring.io/snapshot");
+ }
+
+ @Test
+ void urlLinksFromLibrary() {
+ Map> links = new LinkedHashMap<>();
+ links.put("site", (version) -> "https://example.com/site/" + version);
+ links.put("docs", (version) -> "https://example.com/docs/" + version);
+ Library library = mockLibrary(links);
+ AntoraAsciidocAttributes attributes = new AntoraAsciidocAttributes("1.2.3.1-SNAPSHOT", false, List.of(library),
+ mockDependencyVersions(), null);
+ assertThat(attributes.get()).containsEntry("url-spring-framework-site", "https://example.com/site/1.2.3")
+ .containsEntry("url-spring-framework-docs", "https://example.com/docs/1.2.3");
+ }
+
+ @Test
+ void linksFromProperties() {
+ Map attributes = new AntoraAsciidocAttributes("1.2.3-SNAPSHOT", true, null,
+ mockDependencyVersions(), null)
+ .get();
+ assertThat(attributes).containsEntry("include-java", "ROOT:example$java/org/springframework/boot/docs");
+ assertThat(attributes).containsEntry("url-spring-data-cassandra-site",
+ "https://spring.io/projects/spring-data-cassandra");
+ List keys = new ArrayList<>(attributes.keySet());
+ assertThat(keys.indexOf("include-java")).isLessThan(keys.indexOf("code-spring-boot-latest"));
+ }
+
+ private Library mockLibrary(Map> links) {
+ String name = "Spring Framework";
+ String calendarName = null;
+ LibraryVersion version = new LibraryVersion(DependencyVersion.parse("1.2.3"));
+ List groups = Collections.emptyList();
+ List prohibitedVersion = Collections.emptyList();
+ boolean considerSnapshots = false;
+ VersionAlignment versionAlignment = null;
+ String alignsWithBom = null;
+ String linkRootName = null;
+ Library library = new Library(name, calendarName, version, groups, prohibitedVersion, considerSnapshots,
+ versionAlignment, alignsWithBom, linkRootName, links);
+ return library;
+ }
+
+ private Map mockDependencyVersions() {
+ Map versions = new LinkedHashMap<>();
+ addMockSpringDataVersion(versions, "spring-data-commons");
+ addMockSpringDataVersion(versions, "spring-data-couchbase");
+ addMockSpringDataVersion(versions, "spring-data-elasticsearch");
+ addMockSpringDataVersion(versions, "spring-data-jdbc");
+ addMockSpringDataVersion(versions, "spring-data-jpa");
+ addMockSpringDataVersion(versions, "spring-data-mongodb");
+ addMockSpringDataVersion(versions, "spring-data-neo4j");
+ addMockSpringDataVersion(versions, "spring-data-r2dbc");
+ addMockSpringDataVersion(versions, "spring-data-rest-core");
+ return versions;
+ }
+
+ private void addMockSpringDataVersion(Map versions, String artifactId) {
+ versions.put("org.springframework.data:" + artifactId, "1.2.3");
+ }
+
+}
diff --git a/buildSrc/src/test/java/org/springframework/boot/build/antora/GenerateAntoraPlaybookTests.java b/buildSrc/src/test/java/org/springframework/boot/build/antora/GenerateAntoraPlaybookTests.java
new file mode 100644
index 000000000000..4bcaed2e2748
--- /dev/null
+++ b/buildSrc/src/test/java/org/springframework/boot/build/antora/GenerateAntoraPlaybookTests.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright 2012-2024 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.boot.build.antora;
+
+import java.io.File;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.Map;
+
+import org.gradle.api.Project;
+import org.gradle.testfixtures.ProjectBuilder;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.io.TempDir;
+
+import org.springframework.util.function.ThrowingConsumer;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+/**
+ * Tests for {@link GenerateAntoraPlaybook}.
+ *
+ * @author Phillip Webb
+ */
+class GenerateAntoraPlaybookTests {
+
+ @TempDir
+ File temp;
+
+ @Test
+ void writePlaybookGeneratesExpectedContent() throws Exception {
+ writePlaybookYml((task) -> {
+ task.getXrefStubs().addAll("appendix:.*", "api:.*", "reference:.*");
+ task.getAlwaysInclude().set(Map.of("name", "test", "classifier", "local-aggregate-content"));
+ });
+ String actual = Files.readString(this.temp.toPath()
+ .resolve("rootproject/project/build/generated/docs/antora-playbook/antora-playbook.yml"));
+ String expected = Files
+ .readString(Path.of("src/test/resources/org/springframework/boot/build/antora/expected-playbook.yml"));
+ System.out.println(actual);
+ assertThat(actual.replace('\\', '/')).isEqualToNormalizingNewlines(expected.replace('\\', '/'));
+ }
+
+ private void writePlaybookYml(ThrowingConsumer customizer) throws Exception {
+ File rootProjectDir = new File(this.temp, "rootproject").getCanonicalFile();
+ rootProjectDir.mkdirs();
+ Project rootProject = ProjectBuilder.builder().withProjectDir(rootProjectDir).build();
+ File projectDir = new File(rootProjectDir, "project");
+ projectDir.mkdirs();
+ Project project = ProjectBuilder.builder().withProjectDir(projectDir).withParent(rootProject).build();
+ GenerateAntoraPlaybook task = project.getTasks().create("generateAntoraPlaybook", GenerateAntoraPlaybook.class);
+ customizer.accept(task);
+ task.writePlaybookYml();
+ }
+
+}
diff --git a/buildSrc/src/test/java/org/springframework/boot/build/architecture/ArchitectureCheckTests.java b/buildSrc/src/test/java/org/springframework/boot/build/architecture/ArchitectureCheckTests.java
index 1294d6192975..11f15a8ade9c 100644
--- a/buildSrc/src/test/java/org/springframework/boot/build/architecture/ArchitectureCheckTests.java
+++ b/buildSrc/src/test/java/org/springframework/boot/build/architecture/ArchitectureCheckTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2012-2023 the original author or authors.
+ * Copyright 2012-2024 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -36,6 +36,7 @@
* Tests for {@link ArchitectureCheck}.
*
* @author Andy Wilkinson
+ * @author Scott Frederick
*/
class ArchitectureCheckTests {
@@ -121,6 +122,22 @@ void whenBeanFactoryPostProcessorBeanMethodIsStaticAndHasNoParametersTaskSucceed
});
}
+ @Test
+ void whenClassLoadsResourceUsingResourceUtilsTaskFailsAndWritesReport() throws Exception {
+ prepareTask("resources/loads", (architectureCheck) -> {
+ assertThatExceptionOfType(GradleException.class).isThrownBy(architectureCheck::checkArchitecture);
+ assertThat(failureReport(architectureCheck)).isNotEmpty();
+ });
+ }
+
+ @Test
+ void whenClassUsesResourceUtilsWithoutLoadingResourcesTaskSucceedsAndWritesAnEmptyReport() throws Exception {
+ prepareTask("resources/noloads", (architectureCheck) -> {
+ architectureCheck.checkArchitecture();
+ assertThat(failureReport(architectureCheck)).isEmpty();
+ });
+ }
+
private void prepareTask(String classes, Callback callback) throws Exception {
File projectDir = new File(this.temp, "project");
projectDir.mkdirs();
@@ -136,7 +153,6 @@ private void copyClasses(String name, File projectDir) throws IOException {
Resource root = resolver.getResource("classpath:org/springframework/boot/build/architecture/" + name);
FileSystemUtils.copyRecursively(root.getFile(),
new File(projectDir, "classes/org/springframework/boot/build/architecture/" + name));
-
}
private interface Callback {
diff --git a/buildSrc/src/test/java/org/springframework/boot/build/architecture/resources/loads/ResourceUtilsResourceLoader.java b/buildSrc/src/test/java/org/springframework/boot/build/architecture/resources/loads/ResourceUtilsResourceLoader.java
new file mode 100644
index 000000000000..ce5ff3f61bd5
--- /dev/null
+++ b/buildSrc/src/test/java/org/springframework/boot/build/architecture/resources/loads/ResourceUtilsResourceLoader.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2012-2024 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.boot.build.architecture.resources.loads;
+
+import java.io.FileNotFoundException;
+
+import org.springframework.util.ResourceUtils;
+
+public class ResourceUtilsResourceLoader {
+
+ void getResource() throws FileNotFoundException {
+ ResourceUtils.getURL("gradle.properties");
+ }
+
+}
diff --git a/buildSrc/src/test/java/org/springframework/boot/build/architecture/resources/noloads/ResourceUtilsWithoutLoading.java b/buildSrc/src/test/java/org/springframework/boot/build/architecture/resources/noloads/ResourceUtilsWithoutLoading.java
new file mode 100644
index 000000000000..98d41edad5d2
--- /dev/null
+++ b/buildSrc/src/test/java/org/springframework/boot/build/architecture/resources/noloads/ResourceUtilsWithoutLoading.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2012-2024 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.boot.build.architecture.resources.noloads;
+
+import java.net.MalformedURLException;
+import java.net.URL;
+
+import org.springframework.util.ResourceUtils;
+
+public class ResourceUtilsWithoutLoading {
+
+ void inspectResourceLocation() throws MalformedURLException {
+ ResourceUtils.isUrl("gradle.properties");
+ ResourceUtils.isFileURL(new URL("gradle.properties"));
+ "test".startsWith(ResourceUtils.FILE_URL_PREFIX);
+ }
+
+}
diff --git a/buildSrc/src/test/java/org/springframework/boot/build/bom/LibraryTests.java b/buildSrc/src/test/java/org/springframework/boot/build/bom/LibraryTests.java
new file mode 100644
index 000000000000..e3af38dc17a4
--- /dev/null
+++ b/buildSrc/src/test/java/org/springframework/boot/build/bom/LibraryTests.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright 2012-2024 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.boot.build.bom;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.function.Function;
+
+import org.junit.jupiter.api.Test;
+
+import org.springframework.boot.build.bom.Library.Group;
+import org.springframework.boot.build.bom.Library.LibraryVersion;
+import org.springframework.boot.build.bom.Library.ProhibitedVersion;
+import org.springframework.boot.build.bom.Library.VersionAlignment;
+import org.springframework.boot.build.bom.bomr.version.DependencyVersion;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+/**
+ * Tests for {@link Library}.
+ *
+ * @author Phillip Webb
+ */
+class LibraryTests {
+
+ @Test
+ void getLinkRootNameWhenNoneSpecified() {
+ String name = "Spring Framework";
+ String calendarName = null;
+ LibraryVersion version = new LibraryVersion(DependencyVersion.parse("1.2.3"));
+ List groups = Collections.emptyList();
+ List prohibitedVersion = Collections.emptyList();
+ boolean considerSnapshots = false;
+ VersionAlignment versionAlignment = null;
+ String alignsWithBom = null;
+ String linkRootName = null;
+ Map> links = Collections.emptyMap();
+ Library library = new Library(name, calendarName, version, groups, prohibitedVersion, considerSnapshots,
+ versionAlignment, alignsWithBom, linkRootName, links);
+ assertThat(library.getLinkRootName()).isEqualTo("spring-framework");
+ }
+
+ @Test
+ void getLinkRootNameWhenSpecified() {
+ String name = "Spring Data BOM";
+ String calendarName = null;
+ LibraryVersion version = new LibraryVersion(DependencyVersion.parse("1.2.3"));
+ List groups = Collections.emptyList();
+ List prohibitedVersion = Collections.emptyList();
+ boolean considerSnapshots = false;
+ VersionAlignment versionAlignment = null;
+ String alignsWithBom = null;
+ String linkRootName = "spring-data";
+ Map> links = Collections.emptyMap();
+ Library library = new Library(name, calendarName, version, groups, prohibitedVersion, considerSnapshots,
+ versionAlignment, alignsWithBom, linkRootName, links);
+ assertThat(library.getLinkRootName()).isEqualTo("spring-data");
+ }
+
+}
diff --git a/buildSrc/src/test/java/org/springframework/boot/build/bom/bomr/UpgradeApplicatorTests.java b/buildSrc/src/test/java/org/springframework/boot/build/bom/bomr/UpgradeApplicatorTests.java
index a074ca858ae0..b83742ad3691 100644
--- a/buildSrc/src/test/java/org/springframework/boot/build/bom/bomr/UpgradeApplicatorTests.java
+++ b/buildSrc/src/test/java/org/springframework/boot/build/bom/bomr/UpgradeApplicatorTests.java
@@ -21,6 +21,7 @@
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
+import java.util.Collections;
import java.util.Properties;
import org.junit.jupiter.api.Test;
@@ -51,9 +52,11 @@ void whenUpgradeIsAppliedToLibraryWithVersionThenBomIsUpdated() throws IOExcepti
String originalContents = Files.readString(bom.toPath());
File gradleProperties = new File(this.temp, "gradle.properties");
FileCopyUtils.copy(new File("src/test/resources/gradle.properties"), gradleProperties);
- new UpgradeApplicator(bom.toPath(), gradleProperties.toPath())
- .apply(new Upgrade(new Library("ActiveMQ", null, new LibraryVersion(DependencyVersion.parse("5.15.11")),
- null, null, false, null, null), DependencyVersion.parse("5.16")));
+ new UpgradeApplicator(bom.toPath(), gradleProperties.toPath()).apply(
+ new Upgrade(
+ new Library("ActiveMQ", null, new LibraryVersion(DependencyVersion.parse("5.15.11")), null,
+ null, false, null, null, null, Collections.emptyMap()),
+ DependencyVersion.parse("5.16")));
String bomContents = Files.readString(bom.toPath());
assertThat(bomContents).hasSize(originalContents.length() - 3);
}
@@ -66,7 +69,7 @@ void whenUpgradeIsAppliedToLibraryWithVersionPropertyThenGradlePropertiesIsUpdat
FileCopyUtils.copy(new File("src/test/resources/gradle.properties"), gradleProperties);
new UpgradeApplicator(bom.toPath(), gradleProperties.toPath())
.apply(new Upgrade(new Library("Kotlin", null, new LibraryVersion(DependencyVersion.parse("1.3.70")), null,
- null, false, null, null), DependencyVersion.parse("1.4")));
+ null, false, null, null, null, Collections.emptyMap()), DependencyVersion.parse("1.4")));
Properties properties = new Properties();
try (InputStream in = new FileInputStream(gradleProperties)) {
properties.load(in);
diff --git a/buildSrc/src/test/java/org/springframework/boot/build/context/properties/CompoundRowTests.java b/buildSrc/src/test/java/org/springframework/boot/build/context/properties/CompoundRowTests.java
index 887e01bf7557..4e6949e3f6d1 100644
--- a/buildSrc/src/test/java/org/springframework/boot/build/context/properties/CompoundRowTests.java
+++ b/buildSrc/src/test/java/org/springframework/boot/build/context/properties/CompoundRowTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2012-2023 the original author or authors.
+ * Copyright 2012-2024 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -24,6 +24,7 @@
* Tests for {@link CompoundRow}.
*
* @author Brian Clozel
+ * @author Moritz Halbritter
*/
class CompoundRowTests {
@@ -39,8 +40,8 @@ void simpleProperty() {
row.addProperty(new ConfigurationProperty("spring.test.third", "java.lang.String"));
Asciidoc asciidoc = new Asciidoc();
row.write(asciidoc);
- assertThat(asciidoc).hasToString("|[[my.spring.test]]<>" + NEWLINE
+ assertThat(asciidoc).hasToString("|[[my.spring.test]]xref:#my.spring.test[`+spring.test.first+` +" + NEWLINE
+ + "`+spring.test.second+` +" + NEWLINE + "`+spring.test.third+` +" + NEWLINE + "]" + NEWLINE
+ "|+++This is a description.+++" + NEWLINE + "|" + NEWLINE);
}
diff --git a/buildSrc/src/test/java/org/springframework/boot/build/context/properties/SingleRowTests.java b/buildSrc/src/test/java/org/springframework/boot/build/context/properties/SingleRowTests.java
index b1e48d8dff75..5d046a71efdb 100644
--- a/buildSrc/src/test/java/org/springframework/boot/build/context/properties/SingleRowTests.java
+++ b/buildSrc/src/test/java/org/springframework/boot/build/context/properties/SingleRowTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2012-2023 the original author or authors.
+ * Copyright 2012-2024 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -24,6 +24,7 @@
* Tests for {@link SingleRow}.
*
* @author Brian Clozel
+ * @author Moritz Halbritter
*/
class SingleRowTests {
@@ -38,7 +39,7 @@ void simpleProperty() {
SingleRow row = new SingleRow(SNIPPET, property);
Asciidoc asciidoc = new Asciidoc();
row.write(asciidoc);
- assertThat(asciidoc).hasToString("|[[my.spring.test.prop]]<>"
+ assertThat(asciidoc).hasToString("|[[my.spring.test.prop]]xref:#my.spring.test.prop[`+spring.test.prop+`]"
+ NEWLINE + "|+++This is a description.+++" + NEWLINE + "|`+something+`" + NEWLINE);
}
@@ -49,7 +50,7 @@ void noDefaultValue() {
SingleRow row = new SingleRow(SNIPPET, property);
Asciidoc asciidoc = new Asciidoc();
row.write(asciidoc);
- assertThat(asciidoc).hasToString("|[[my.spring.test.prop]]<>"
+ assertThat(asciidoc).hasToString("|[[my.spring.test.prop]]xref:#my.spring.test.prop[`+spring.test.prop+`]"
+ NEWLINE + "|+++This is a description.+++" + NEWLINE + "|" + NEWLINE);
}
@@ -60,7 +61,7 @@ void defaultValueWithPipes() {
SingleRow row = new SingleRow(SNIPPET, property);
Asciidoc asciidoc = new Asciidoc();
row.write(asciidoc);
- assertThat(asciidoc).hasToString("|[[my.spring.test.prop]]<>"
+ assertThat(asciidoc).hasToString("|[[my.spring.test.prop]]xref:#my.spring.test.prop[`+spring.test.prop+`]"
+ NEWLINE + "|+++This is a description.+++" + NEWLINE + "|`+first\\|second+`" + NEWLINE);
}
@@ -71,7 +72,7 @@ void defaultValueWithBackslash() {
SingleRow row = new SingleRow(SNIPPET, property);
Asciidoc asciidoc = new Asciidoc();
row.write(asciidoc);
- assertThat(asciidoc).hasToString("|[[my.spring.test.prop]]<>"
+ assertThat(asciidoc).hasToString("|[[my.spring.test.prop]]xref:#my.spring.test.prop[`+spring.test.prop+`]"
+ NEWLINE + "|+++This is a description.+++" + NEWLINE + "|`+first\\\\second+`" + NEWLINE);
}
@@ -82,7 +83,7 @@ void descriptionWithPipe() {
SingleRow row = new SingleRow(SNIPPET, property);
Asciidoc asciidoc = new Asciidoc();
row.write(asciidoc);
- assertThat(asciidoc).hasToString("|[[my.spring.test.prop]]<>"
+ assertThat(asciidoc).hasToString("|[[my.spring.test.prop]]xref:#my.spring.test.prop[`+spring.test.prop+`]"
+ NEWLINE + "|+++This is a description with a \\| pipe.+++" + NEWLINE + "|" + NEWLINE);
}
@@ -93,7 +94,7 @@ void mapProperty() {
SingleRow row = new SingleRow(SNIPPET, property);
Asciidoc asciidoc = new Asciidoc();
row.write(asciidoc);
- assertThat(asciidoc).hasToString("|[[my.spring.test.prop]]<