From 124b1af6ebbce5a48e96bb19764f9f660e720e22 Mon Sep 17 00:00:00 2001 From: alexander-yevsyukov Date: Thu, 15 Oct 2026 20:04:05 +0100 Subject: [PATCH 01/17] Update shared agent tooling and config (./config/pull) --- .claude/settings.json | 11 +- .github/workflows/publish.yml | 103 +- .gitignore | 28 +- .idea/copyright/CodeMatters_Open_Source.xml | 6 + buildSrc/build.gradle.kts | 75 +- buildSrc/quality/checkstyle-suppressions.xml | 26 +- buildSrc/quality/checkstyle.xml | 26 +- buildSrc/quality/pmd.xml | 26 +- buildSrc/settings.gradle.kts | 26 +- buildSrc/src/main/kotlin/BuildExtensions.kt | 26 +- buildSrc/src/main/kotlin/BuildSettings.kt | 26 +- .../src/main/kotlin/DependencyResolution.kt | 26 +- .../src/main/kotlin/DocumentationSettings.kt | 26 +- buildSrc/src/main/kotlin/DokkaExts.kt | 154 ++- buildSrc/src/main/kotlin/LicenseSettings.kt | 34 +- buildSrc/src/main/kotlin/Strings.kt | 26 +- .../src/main/kotlin/config-tester.gradle.kts | 26 +- .../kotlin/detekt-code-analysis.gradle.kts | 26 +- .../src/main/kotlin/dokka-setup.gradle.kts | 32 +- .../kotlin/io/spine/dependency/Dependency.kt | 26 +- .../kotlin/io/spine/dependency/boms/Boms.kt | 26 +- .../io/spine/dependency/boms/BomsPlugin.kt | 26 +- .../spine/dependency/build/AnimalSniffer.kt | 28 +- .../io/spine/dependency/build/CheckStyle.kt | 41 +- .../dependency/build/CheckerFramework.kt | 28 +- .../kotlin/io/spine/dependency/build/Dokka.kt | 42 +- .../io/spine/dependency/build/ErrorProne.kt | 28 +- .../io/spine/dependency/build/FindBugs.kt | 26 +- .../io/spine/dependency/build/GradleDoctor.kt | 26 +- .../io/spine/dependency/build/JSpecify.kt | 26 +- .../kotlin/io/spine/dependency/build/Ksp.kt | 59 +- .../io/spine/dependency/build/OsDetector.kt | 26 +- .../dependency/build/PluginPublishPlugin.kt | 28 +- .../kotlin/io/spine/dependency/build/Pmd.kt | 28 +- .../io/spine/dependency/kotlinx/AtomicFu.kt | 26 +- .../io/spine/dependency/kotlinx/Coroutines.kt | 26 +- .../io/spine/dependency/kotlinx/DateTime.kt | 26 +- .../io/spine/dependency/kotlinx/KotlinX.kt | 26 +- .../spine/dependency/kotlinx/Serialization.kt | 26 +- .../kotlin/io/spine/dependency/lib/Aedile.kt | 26 +- .../io/spine/dependency/lib/ApacheHttp.kt | 28 +- .../kotlin/io/spine/dependency/lib/Asm.kt | 28 +- .../kotlin/io/spine/dependency/lib/Auto.kt | 26 +- .../io/spine/dependency/lib/BouncyCastle.kt | 54 +- .../io/spine/dependency/lib/Caffeine.kt | 28 +- .../kotlin/io/spine/dependency/lib/Clikt.kt | 26 +- .../io/spine/dependency/lib/CommonsCli.kt | 26 +- .../io/spine/dependency/lib/CommonsCodec.kt | 28 +- .../io/spine/dependency/lib/CommonsLogging.kt | 26 +- .../io/spine/dependency/lib/Coroutines.kt | 26 +- .../io/spine/dependency/lib/Firebase.kt | 28 +- .../kotlin/io/spine/dependency/lib/Flogger.kt | 26 +- .../io/spine/dependency/lib/GoogleApis.kt | 40 +- .../io/spine/dependency/lib/GoogleCloud.kt | 34 +- .../kotlin/io/spine/dependency/lib/Grpc.kt | 28 +- .../io/spine/dependency/lib/GrpcKotlin.kt | 26 +- .../kotlin/io/spine/dependency/lib/Gson.kt | 26 +- .../kotlin/io/spine/dependency/lib/Guava.kt | 28 +- .../io/spine/dependency/lib/HttpClient.kt | 26 +- .../io/spine/dependency/lib/IntelliJ.kt | 29 +- .../kotlin/io/spine/dependency/lib/J2ObjC.kt | 26 +- .../kotlin/io/spine/dependency/lib/Jackson.kt | 55 +- .../io/spine/dependency/lib/JacksonV2.kt | 64 +- .../io/spine/dependency/lib/JavaDiffUtils.kt | 26 +- .../kotlin/io/spine/dependency/lib/JavaJwt.kt | 26 +- .../io/spine/dependency/lib/JavaPoet.kt | 26 +- .../kotlin/io/spine/dependency/lib/JavaX.kt | 28 +- .../dependency/lib/JetBrainsAnnotations.kt | 26 +- .../kotlin/io/spine/dependency/lib/Klaxon.kt | 26 +- .../kotlin/io/spine/dependency/lib/Kotlin.kt | 36 +- .../io/spine/dependency/lib/KotlinPoet.kt | 28 +- .../io/spine/dependency/lib/KotlinSemver.kt | 26 +- .../kotlin/io/spine/dependency/lib/KotlinX.kt | 26 +- .../kotlin/io/spine/dependency/lib/Log4j2.kt | 26 +- .../kotlin/io/spine/dependency/lib/Netty.kt | 28 +- .../kotlin/io/spine/dependency/lib/Okio.kt | 28 +- .../dependency/lib/PalantirJavaFormat.kt | 28 +- .../io/spine/dependency/lib/PerfMark.kt | 26 +- .../kotlin/io/spine/dependency/lib/Plexus.kt | 28 +- .../io/spine/dependency/lib/Protobuf.kt | 42 +- .../kotlin/io/spine/dependency/lib/Roaster.kt | 26 +- .../kotlin/io/spine/dependency/lib/Slf4J.kt | 28 +- .../kotlin/io/spine/dependency/local/Base.kt | 30 +- .../io/spine/dependency/local/BaseTypes.kt | 28 +- .../io/spine/dependency/local/Change.kt | 28 +- .../io/spine/dependency/local/Compiler.kt | 30 +- .../io/spine/dependency/local/CoreJvm.kt | 28 +- .../spine/dependency/local/CoreJvmCompiler.kt | 30 +- .../io/spine/dependency/local/DokkaTools.kt | 37 + .../io/spine/dependency/local/Logging.kt | 28 +- .../io/spine/dependency/local/ProtoTap.kt | 28 +- .../io/spine/dependency/local/Reflect.kt | 28 +- .../kotlin/io/spine/dependency/local/Spine.kt | 26 +- .../io/spine/dependency/local/TestLib.kt | 28 +- .../kotlin/io/spine/dependency/local/Time.kt | 28 +- .../io/spine/dependency/local/ToolBase.kt | 49 +- .../io/spine/dependency/local/Validation.kt | 28 +- .../kotlin/io/spine/dependency/storage/H2.kt | 28 +- .../io/spine/dependency/storage/Hikari.kt | 26 +- .../io/spine/dependency/storage/HsqlDb.kt | 26 +- .../io/spine/dependency/storage/MySql.kt | 26 +- .../io/spine/dependency/storage/PostgreSql.kt | 28 +- .../io/spine/dependency/storage/QueryDsl.kt | 26 +- .../io/spine/dependency/test/AssertK.kt | 26 +- .../io/spine/dependency/test/Hamcrest.kt | 26 +- .../kotlin/io/spine/dependency/test/JUnit.kt | 33 +- .../kotlin/io/spine/dependency/test/Jacoco.kt | 26 +- .../kotlin/io/spine/dependency/test/Kotest.kt | 28 +- .../dependency/test/KotlinCompileTesting.kt | 28 +- .../kotlin/io/spine/dependency/test/Kover.kt | 28 +- .../io/spine/dependency/test/OpenTest4J.kt | 26 +- .../io/spine/dependency/test/SystemLambda.kt | 26 +- .../io/spine/dependency/test/TestKitTruth.kt | 37 +- .../spine/dependency/test/Testcontainers.kt | 26 +- .../kotlin/io/spine/dependency/test/Truth.kt | 26 +- .../kotlin/io/spine/docs/MarkdownDocument.kt | 26 +- .../src/main/kotlin/io/spine/gradle/Build.kt | 26 +- .../src/main/kotlin/io/spine/gradle/Clean.kt | 26 +- .../src/main/kotlin/io/spine/gradle/Cli.kt | 26 +- .../kotlin/io/spine/gradle/ConfigTester.kt | 26 +- .../io/spine/gradle/ProjectExtensions.kt | 26 +- .../main/kotlin/io/spine/gradle/RunBuild.kt | 26 +- .../main/kotlin/io/spine/gradle/RunGradle.kt | 26 +- .../kotlin/io/spine/gradle/SpineTaskGroup.kt | 26 +- .../io/spine/gradle/StringExtensions.kt | 26 +- .../main/kotlin/io/spine/gradle/TaskName.kt | 26 +- .../io/spine/gradle/VersionComparator.kt | 26 +- .../io/spine/gradle/VersionGradleFile.kt | 26 +- .../main/kotlin/io/spine/gradle/base/Tasks.kt | 26 +- .../gradle/checkstyle/CheckStyleConfig.kt | 33 +- .../io/spine/gradle/dart/DartContext.kt | 26 +- .../io/spine/gradle/dart/DartEnvironment.kt | 26 +- .../io/spine/gradle/dart/DartExtension.kt | 26 +- .../spine/gradle/dart/plugin/DartPlugins.kt | 26 +- .../io/spine/gradle/dart/plugin/Protobuf.kt | 26 +- .../kotlin/io/spine/gradle/dart/task/Build.kt | 26 +- .../io/spine/gradle/dart/task/DartTasks.kt | 26 +- .../spine/gradle/dart/task/IntegrationTest.kt | 26 +- .../io/spine/gradle/dart/task/Publish.kt | 26 +- .../spine/gradle/docs/UpdatePluginVersion.kt | 26 +- .../kotlin/io/spine/gradle/fs/LazyTempPath.kt | 26 +- .../kotlin/io/spine/gradle/fs/SpineTempDir.kt | 26 +- .../main/kotlin/io/spine/gradle/git/Branch.kt | 26 +- .../kotlin/io/spine/gradle/git/Repository.kt | 26 +- .../kotlin/io/spine/gradle/git/UserInfo.kt | 26 +- .../spine/gradle/github/pages/AuthorEmail.kt | 26 +- .../github/pages/RepositoryExtensions.kt | 26 +- .../io/spine/gradle/github/pages/SshKey.kt | 26 +- .../io/spine/gradle/github/pages/TaskName.kt | 26 +- .../io/spine/gradle/github/pages/Update.kt | 26 +- .../gradle/github/pages/UpdateGitHubPages.kt | 26 +- .../pages/UpdateGitHubPagesExtension.kt | 26 +- .../kotlin/io/spine/gradle/java/Linters.kt | 26 +- .../main/kotlin/io/spine/gradle/java/Tasks.kt | 26 +- .../io/spine/gradle/javac/ErrorProne.kt | 26 +- .../kotlin/io/spine/gradle/javac/Javac.kt | 26 +- .../io/spine/gradle/javadoc/Encoding.kt | 26 +- .../gradle/javadoc/ExcludeInternalDoclet.kt | 26 +- .../io/spine/gradle/javadoc/JavadocConfig.kt | 26 +- .../io/spine/gradle/javadoc/JavadocTag.kt | 26 +- .../io/spine/gradle/javascript/JsContext.kt | 26 +- .../spine/gradle/javascript/JsEnvironment.kt | 26 +- .../io/spine/gradle/javascript/JsExtension.kt | 26 +- .../io/spine/gradle/javascript/plugin/Idea.kt | 26 +- .../gradle/javascript/plugin/JsPlugins.kt | 26 +- .../io/spine/gradle/javascript/plugin/McJs.kt | 26 +- .../gradle/javascript/plugin/Protobuf.kt | 26 +- .../spine/gradle/javascript/task/Assemble.kt | 26 +- .../io/spine/gradle/javascript/task/Check.kt | 26 +- .../io/spine/gradle/javascript/task/Clean.kt | 26 +- .../gradle/javascript/task/IntegrationTest.kt | 26 +- .../spine/gradle/javascript/task/JsTasks.kt | 26 +- .../gradle/javascript/task/LicenseReport.kt | 26 +- .../spine/gradle/javascript/task/Publish.kt | 26 +- .../spine/gradle/javascript/task/Webpack.kt | 26 +- .../io/spine/gradle/kotlin/KotlinConfig.kt | 43 +- .../gradle/publish/ArtifactComponents.kt | 257 ++++ .../gradle/publish/CheckVersionIncrement.kt | 183 ++- .../gradle/publish/CloudArtifactRegistry.kt | 26 +- .../io/spine/gradle/publish/CloudRepo.kt | 26 +- .../io/spine/gradle/publish/ComponentKey.kt | 89 ++ .../publish/CustomPublicationHandler.kt | 53 +- .../io/spine/gradle/publish/GitHubPackages.kt | 26 +- .../io/spine/gradle/publish/IncrementGuard.kt | 82 +- .../kotlin/io/spine/gradle/publish/JarDsl.kt | 26 +- .../io/spine/gradle/publish/MavenMetadata.kt | 31 +- .../io/spine/gradle/publish/ProtoExts.kt | 26 +- .../gradle/publish/PublicationChecksums.kt | 402 ++++++ .../gradle/publish/PublicationHandler.kt | 117 +- .../spine/gradle/publish/PublicationSbom.kt | 724 ++++++++++ .../gradle/publish/PublicationSbomTask.kt | 233 ++++ .../io/spine/gradle/publish/PublishingExts.kt | 58 +- .../spine/gradle/publish/PublishingRepos.kt | 26 +- .../io/spine/gradle/publish/SbomContent.kt | 167 +++ .../io/spine/gradle/publish/ShadowJarExts.kt | 26 +- .../io/spine/gradle/publish/SpdxField.kt | 44 + .../spine/gradle/publish/SpinePublishing.kt | 37 +- .../publish/StandardJavaPublicationHandler.kt | 26 +- .../io/spine/gradle/repo/Credentials.kt | 26 +- .../kotlin/io/spine/gradle/repo/RepoSlug.kt | 26 +- .../io/spine/gradle/repo/Repositories.kt | 45 +- .../kotlin/io/spine/gradle/repo/Repository.kt | 56 +- .../gradle/report/coverage/KoverConfig.kt | 26 +- .../gradle/report/coverage/SiblingCoverage.kt | 26 +- .../gradle/report/license/Configuration.kt | 26 +- .../gradle/report/license/LicenseReporter.kt | 26 +- .../report/license/MarkdownReportRenderer.kt | 26 +- .../report/license/ModuleDataExtensions.kt | 43 +- .../io/spine/gradle/report/license/Paths.kt | 26 +- .../report/license/ProjectDependencies.kt | 26 +- .../io/spine/gradle/report/license/Tasks.kt | 26 +- .../spine/gradle/report/license/Template.kt | 26 +- .../gradle/report/pom/DependencyScope.kt | 26 +- .../gradle/report/pom/DependencyWriter.kt | 26 +- .../spine/gradle/report/pom/InceptionYear.kt | 26 +- .../gradle/report/pom/MarkupExtensions.kt | 26 +- .../gradle/report/pom/ModuleDependency.kt | 26 +- .../spine/gradle/report/pom/PomFormatting.kt | 26 +- .../spine/gradle/report/pom/PomGenerator.kt | 26 +- .../spine/gradle/report/pom/PomXmlWriter.kt | 26 +- .../gradle/report/pom/ProjectMetadata.kt | 26 +- .../gradle/report/pom/ResolvedVersions.kt | 31 +- .../gradle/report/pom/ScopedDependency.kt | 26 +- .../spine/gradle/report/pom/SpineLicense.kt | 26 +- .../kotlin/io/spine/gradle/testing/Logging.kt | 26 +- .../io/spine/gradle/testing/Multiproject.kt | 26 +- .../gradle/testing/SpineCompilerCoverage.kt | 26 +- .../kotlin/io/spine/gradle/testing/Tasks.kt | 26 +- .../spine/gradle/testing/TestKitCoverage.kt | 26 +- .../src/main/kotlin/jvm-module.gradle.kts | 26 +- .../src/main/kotlin/kmp-module.gradle.kts | 26 +- .../src/main/kotlin/kmp-publish.gradle.kts | 26 +- .../src/main/kotlin/module-testing.gradle.kts | 26 +- .../src/main/kotlin/pmd-settings.gradle.kts | 26 +- .../src/main/kotlin/test-module.gradle.kts | 26 +- .../main/kotlin/uber-jar-module.gradle.kts | 30 +- .../src/main/kotlin/write-manifest.gradle.kts | 28 +- .../resources/dokka/styles/custom-styles.css | 26 +- .../io/spine/dependency/build/KspSpec.kt | 46 + .../io/spine/dependency/lib/JacksonSpec.kt | 51 + .../io/spine/dependency/lib/JacksonV2Spec.kt | 58 + .../io/spine/dependency/lib/KotlinSpec.kt | 43 + .../io/spine/dependency/lib/ProtobufSpec.kt | 41 + .../io/spine/gradle/VersionComparatorSpec.kt | 26 +- .../io/spine/gradle/VersionGradleFileSpec.kt | 26 +- .../gradle/checkstyle/CheckStyleConfigSpec.kt | 44 + .../io/spine/gradle/docs/DokkaSetupIgTest.kt | 295 ++++ .../gradle/docs/UpdatePluginVersionTest.kt | 26 +- .../io/spine/gradle/fs/LazyTempPathSpec.kt | 26 +- .../io/spine/gradle/fs/SpineTempDirSpec.kt | 26 +- .../gradle/publish/ArtifactComponentsSpec.kt | 411 ++++++ .../publish/CheckVersionIncrementIgTest.kt | 179 +++ .../publish/CustomPublicationHandlerIgTest.kt | 358 +++++ .../gradle/publish/IncrementGuardIgTest.kt | 201 +++ .../gradle/publish/IncrementGuardTest.kt | 376 +++++- .../spine/gradle/publish/MavenMetadataSpec.kt | 26 +- .../publish/PublicationChecksumsIgTest.kt | 290 ++++ ...blicationChecksumsReconfigurationIgTest.kt | 215 +++ .../gradle/publish/PublicationSbomIgTest.kt | 1183 +++++++++++++++++ .../publish/PublishingCredentialsIgTest.kt | 337 +++++ .../gradle/publish/SpinePublishingTest.kt | 74 +- .../io/spine/gradle/repo/RepositoriesSpec.kt | 51 + .../report/coverage/FileExtensionsTest.kt | 26 +- .../license/DependencyReportOutputTest.kt | 26 +- .../gradle/report/pom/DependencyWriterSpec.kt | 26 +- .../gradle/report/pom/PomGeneratorIgTest.kt | 35 +- config | 2 +- gradle.properties | 5 + gradle/wrapper/gradle-wrapper.jar | Bin 47505 -> 48749 bytes gradle/wrapper/gradle-wrapper.properties | 2 +- gradlew.bat | 52 +- init-submodules | 80 +- 272 files changed, 8786 insertions(+), 4854 deletions(-) create mode 100644 .idea/copyright/CodeMatters_Open_Source.xml create mode 100644 buildSrc/src/main/kotlin/io/spine/dependency/local/DokkaTools.kt create mode 100644 buildSrc/src/main/kotlin/io/spine/gradle/publish/ArtifactComponents.kt create mode 100644 buildSrc/src/main/kotlin/io/spine/gradle/publish/ComponentKey.kt create mode 100644 buildSrc/src/main/kotlin/io/spine/gradle/publish/PublicationChecksums.kt create mode 100644 buildSrc/src/main/kotlin/io/spine/gradle/publish/PublicationSbom.kt create mode 100644 buildSrc/src/main/kotlin/io/spine/gradle/publish/PublicationSbomTask.kt create mode 100644 buildSrc/src/main/kotlin/io/spine/gradle/publish/SbomContent.kt create mode 100644 buildSrc/src/main/kotlin/io/spine/gradle/publish/SpdxField.kt create mode 100644 buildSrc/src/test/kotlin/io/spine/dependency/build/KspSpec.kt create mode 100644 buildSrc/src/test/kotlin/io/spine/dependency/lib/JacksonSpec.kt create mode 100644 buildSrc/src/test/kotlin/io/spine/dependency/lib/JacksonV2Spec.kt create mode 100644 buildSrc/src/test/kotlin/io/spine/dependency/lib/KotlinSpec.kt create mode 100644 buildSrc/src/test/kotlin/io/spine/dependency/lib/ProtobufSpec.kt create mode 100644 buildSrc/src/test/kotlin/io/spine/gradle/checkstyle/CheckStyleConfigSpec.kt create mode 100644 buildSrc/src/test/kotlin/io/spine/gradle/docs/DokkaSetupIgTest.kt create mode 100644 buildSrc/src/test/kotlin/io/spine/gradle/publish/ArtifactComponentsSpec.kt create mode 100644 buildSrc/src/test/kotlin/io/spine/gradle/publish/CheckVersionIncrementIgTest.kt create mode 100644 buildSrc/src/test/kotlin/io/spine/gradle/publish/CustomPublicationHandlerIgTest.kt create mode 100644 buildSrc/src/test/kotlin/io/spine/gradle/publish/IncrementGuardIgTest.kt create mode 100644 buildSrc/src/test/kotlin/io/spine/gradle/publish/PublicationChecksumsIgTest.kt create mode 100644 buildSrc/src/test/kotlin/io/spine/gradle/publish/PublicationChecksumsReconfigurationIgTest.kt create mode 100644 buildSrc/src/test/kotlin/io/spine/gradle/publish/PublicationSbomIgTest.kt create mode 100644 buildSrc/src/test/kotlin/io/spine/gradle/publish/PublishingCredentialsIgTest.kt create mode 100644 buildSrc/src/test/kotlin/io/spine/gradle/repo/RepositoriesSpec.kt diff --git a/.claude/settings.json b/.claude/settings.json index 3c7da68..44a3ac2 100644 --- a/.claude/settings.json +++ b/.claude/settings.json @@ -14,6 +14,7 @@ "Bash(git switch:*)", "Bash(git checkout:*)", "Bash(git add:*)", + "Bash(git commit:*)", "Bash(git restore:*)", "Bash(git stash:*)", "Bash(git fetch:*)", @@ -48,7 +49,15 @@ "Bash(gh release create:*)" ], "ask": [ - "Bash(git commit:*)", + "Bash(git push --force*)", + "Bash(git push * --force*)", + "Bash(git push -f*)", + "Bash(git push * -f*)", + "Bash(git push -uf*)", + "Bash(git push * -uf*)", + "Bash(git push * +*)", + "Bash(git push --mirror*)", + "Bash(git push * --mirror*)", "Bash(git rebase:*)", "Bash(git merge:*)", "Bash(git cherry-pick:*)", diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 27c11c0..3bad11f 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -1,5 +1,28 @@ name: Publish +# A thin caller. The job body — checkout, credentials, the Gradle publication +# and the attestation — is the reusable `publishing.yml` hosted by `config`, +# which the `uses:` line below points at. Keeping the body out of this +# repository is what makes the attestation's signer `config` rather than this +# file (SLSA Build Level 3); the comments in `publishing.yml` explain the +# mechanism. +# +# `CONFIG_COMMIT` is a placeholder, not a ref: `migrate` replaces it on every +# `./config/pull` with the commit of `config` this repository pins as its +# submodule, so the workflow steps and `buildSrc` always come from the same +# commit. It is never edited by hand. +# +# The permission grant is the union of what the two called jobs declare — a +# called workflow can keep or reduce what it is given, never raise it — and +# `secrets: inherit` passes the repository secrets the decryption steps need. + +# Consumers verify an artifact against the branch it was published from +# (`gh attestation verify --source-ref`), which means something only while a +# ruleset protects that branch. Publishing from `v.x` release branches +# takes `'v*.x'` added to this trigger in the template in `config`, not in a +# consumer's copy, which `./config/pull` overwrites. The template reaches every +# repository that publishes, so first make each of their rulesets cover that +# pattern, including the creation of such branches. on: push: branches: [master] @@ -7,75 +30,11 @@ on: jobs: publish: name: Publish to Maven repositories - runs-on: ubuntu-latest - - steps: - - uses: actions/checkout@v6 - with: - submodules: 'true' - - - uses: actions/setup-java@v5 - with: - java-version: 17 - distribution: zulu - - - uses: gradle/actions/setup-gradle@v6 - - - name: Decrypt CloudRepo credentials - run: ./config/scripts/decrypt.sh "$CLOUDREPO_CREDENTIALS_KEY" ./.github/keys/cloudrepo.properties.gpg ./cloudrepo.properties - env: - CLOUDREPO_CREDENTIALS_KEY: ${{ secrets.CLOUDREPO_CREDENTIALS_KEY }} - - - name: Decrypt Git SSH credentials - run: ./config/scripts/decrypt.sh "$GIT_CREDENTIALS_KEY" ./.github/keys/deploy_key_rsa.gpg ./deploy_key_rsa - env: - GIT_CREDENTIALS_KEY: ${{ secrets.GIT_CREDENTIALS_KEY }} - - # Make sure the SSH key is not "too visible". SSH agent will not accept it otherwise. - - name: Set file system permissions - run: chmod 400 ./deploy_key_rsa && chmod +x ./config/scripts/register-ssh-key.sh - - - name: Decrypt GCS credentials - run: ./config/scripts/decrypt.sh "$GCS_CREDENTIALS_KEY" ./.github/keys/gcs-auth-key.json.gpg ./gcs-auth-key.json - env: - GCS_CREDENTIALS_KEY: ${{ secrets.GCS_CREDENTIALS_KEY }} - - - name: Decrypt GCAR credentials - run: ./config/scripts/decrypt.sh "$MAVEN_PUBLISHER_KEY" ./.github/keys/maven-publisher.json.gpg ./maven-publisher.json - env: - MAVEN_PUBLISHER_KEY: ${{ secrets.MAVEN_PUBLISHER_KEY }} - - - name: Decrypt Git SSH credentials - run: ./config/scripts/decrypt.sh "$GRADLE_PORTAL_CREDENTIALS_KEY" ./.github/keys/gradle-plugin-portal.secret.properties.gpg ./gradle-plugin-portal.secret.properties - env: - GRADLE_PORTAL_CREDENTIALS_KEY: ${{ secrets.GRADLE_PORTAL_CREDENTIALS_KEY }} - - - name: Append Gradle properties - run: cat ./gradle-plugin-portal.secret.properties >> ./gradle.properties - - - name: Publish artifacts to Maven - # Since we're in the `master` branch already, this means that tests of a PR passed. - # So, no need to run the tests again when publishing. - run: ./gradlew publish -x test --stacktrace - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - FORMAL_GIT_HUB_PAGES_AUTHOR: developers@spine.io - # https://docs.github.com/en/actions/reference/environment-variables - REPO_SLUG: ${{ github.repository }} # e.g. SpineEventEngine/core-jvm - GOOGLE_APPLICATION_CREDENTIALS: ./maven-publisher.json - NPM_TOKEN: ${{ secrets.NPM_SECRET }} - - # A failed publication on `master` is most often a version collision: a stale - # duplicate bump merged before `revalidate-versions.yml` could turn it red (the - # narrow auto-merge race). The artifact is safe — the registry rejects the - # overwrite — but the fix needs a human/agent, so make the failure loud and - # actionable instead of a quiet red run. - - name: Report a failed publication - if: failure() - shell: bash - run: | - echo "::error title=Publish failed::Publishing to Maven failed on the base branch. If this is a version collision, the version is already published (immutable). Bump 'version.gradle.kts' on the base branch (e.g. via a small PR) and re-run this workflow." - echo "Publish failed. If the cause is a version collision:" - echo " 1. Bump 'version.gradle.kts' on the base branch to the next free version." - echo " 2. Re-run this 'Publish' workflow." - echo "Stale duplicate bumps are normally caught before merge by 'revalidate-versions.yml'." + uses: SpineEventEngine/config/.github/workflows/publishing.yml@a0cbbbfe66c12475224563439fb6deb3da71ba58 + permissions: + contents: read + packages: write + id-token: write + attestations: write + artifact-metadata: write + secrets: inherit diff --git a/.gitignore b/.gitignore index b20cb79..ecc4f13 100644 --- a/.gitignore +++ b/.gitignore @@ -1,29 +1,15 @@ # >>> shared config (managed by ./config/pull -- do not edit inside this block) >>> +# Copyright 2026 CodeMatters, Lda. # -# Copyright 2025, TeamDev. All rights reserved. -# -# 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 +# 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 # -# Redistribution and use in source and/or binary forms, with or without -# modification, must retain the above copyright notice and the following -# disclaimer. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -# +# 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. # # This file is used for two purposes: diff --git a/.idea/copyright/CodeMatters_Open_Source.xml b/.idea/copyright/CodeMatters_Open_Source.xml new file mode 100644 index 0000000..cf5d713 --- /dev/null +++ b/.idea/copyright/CodeMatters_Open_Source.xml @@ -0,0 +1,6 @@ + + + + diff --git a/buildSrc/build.gradle.kts b/buildSrc/build.gradle.kts index c77a441..aeaa51d 100644 --- a/buildSrc/build.gradle.kts +++ b/buildSrc/build.gradle.kts @@ -1,27 +1,15 @@ /* - * Copyright 2026, TeamDev. All rights reserved. + * Copyright 2026 CodeMatters, Lda. * - * 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 + * 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 * - * Redistribution and use in source and/or binary forms, with or without - * modification, must retain the above copyright notice and the following - * disclaimer. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. */ import org.jetbrains.kotlin.gradle.dsl.JvmTarget @@ -50,10 +38,19 @@ repositories { * This value is deliberately decoupled from [io.spine.dependency.lib.Jackson.version], * which now points to Jackson 3.x. The `buildSrc` sources still use the Jackson 2.x API * (`com.fasterxml.jackson.*`), so they must stay on a 2.x version until they are migrated - * to `tools.jackson.*`. Any maintained 2.x release will do — bump this only when `buildSrc` - * itself needs a fix from a later 2.x, not to track the newest one. + * to `tools.jackson.*`. + * + * The floor is set by the SPDX Gradle Plugin (see [spdxPluginVersion]). Its JSON store + * depends on `jackson-bom`, which aligns every Jackson 2.x module on the runtime classpath + * of `buildSrc` with the version it requires. A lower version here would compile `buildSrc` + * against one Jackson and run it against another. Raise this together with the plugin, or + * when `buildSrc` itself needs a fix from a later 2.x — not to track the newest one. + * + * Whatever the reason for a change, `jackson-core` and `jackson-databind` below `2.18.9` + * are exposed to published advisories, three of them rated `high` — `GHSA-r7wm-3cxj-wff9`, + * `GHSA-rmj7-2vxq-3g9f`, and `GHSA-j3rv-43j4-c7qm`. */ -val jacksonVersion = "2.18.3" +val jacksonVersion = "2.22.0" /** * The version of Google Artifact Registry used by `buildSrc`. @@ -80,7 +77,7 @@ val grGitVersion = "5.3.3" * This version may change from the [version of Kotlin][io.spine.dependency.lib.Kotlin.version] * used by the project. */ -val kotlinEmbeddedVersion = "2.4.10" +val kotlinEmbeddedVersion = "2.4.21" /** * The version of Guava used in `buildSrc`. @@ -88,7 +85,7 @@ val kotlinEmbeddedVersion = "2.4.10" * Always use the same version as the one specified in [io.spine.dependency.lib.Guava]. * Otherwise, when testing Gradle plugins, clashes may occur. */ -val guavaVersion = "33.7.1-jre" +val guavaVersion = "33.7.2-jre" /** * The version of ErrorProne Gradle plugin. @@ -135,7 +132,7 @@ val kotestJvmPluginVersion = "0.4.11" /** * @see [io.spine.dependency.test.Kover] */ -val koverVersion = "0.9.9" +val koverVersion = "0.9.11" /** * The version of the Shadow Plugin. @@ -144,6 +141,28 @@ val koverVersion = "0.9.9" */ val shadowVersion = "9.6.1" +/** + * The version of the SPDX Gradle Plugin, which writes the SBOM published with each module. + * + * @see SPDX Gradle Plugin + */ +val spdxPluginVersion = "0.12.0" + +/** + * The version of Plexus XML used by `buildSrc`, pinned to the line made for Maven 3. + * + * The Shadow plugin brings the 4.x line, made for Maven 4. It merges XML through + * `maven-xml`, which finds its `XmlService` via the context class loader of the current + * thread — a loader that does not see `buildSrc` on the threads Gradle runs tasks on. + * The SPDX Gradle Plugin (see [spdxPluginVersion]) builds effective POMs with the Maven 3 + * model, which merges the plugin configuration of a POM with that of its parent. So with + * the 4.x line, the SBOM of a module fails for any dependency whose POM does that. + * + * The 3.x line implements the same API on its own. Shadow uses only its classic part, + * in `ComponentsXmlResourceTransformer`. Update this within the 3.x line only. + */ +val plexusXmlVersion = "3.1.0" + /** * The version of JUnit used to test the build scripts. * @@ -156,13 +175,14 @@ val junitVersion = "6.1.3" * * @see [io.spine.dependency.test.Kotest] */ -val kotestVersion = "6.2.4" +val kotestVersion = "6.2.5" configurations.all { resolutionStrategy { force( "com.google.guava:guava:${guavaVersion}", "com.google.protobuf:protobuf-gradle-plugin:$protobufPluginVersion", + "org.codehaus.plexus:plexus-xml:$plexusXmlVersion", // Force Kotlin lib versions avoiding using those bundled with Gradle. "org.jetbrains.kotlin:kotlin-stdlib:$kotlinEmbeddedVersion", @@ -205,7 +225,8 @@ dependencies { "org.jetbrains.dokka:dokka-gradle-plugin:$dokkaVersion", "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlinEmbeddedVersion", "org.jetbrains.kotlin:kotlin-reflect:$kotlinEmbeddedVersion", - "org.jetbrains.kotlinx:kover-gradle-plugin:$koverVersion" + "org.jetbrains.kotlinx:kover-gradle-plugin:$koverVersion", + "org.spdx:spdx-gradle-plugin:$spdxPluginVersion" ).forEach { implementation(it) } diff --git a/buildSrc/quality/checkstyle-suppressions.xml b/buildSrc/quality/checkstyle-suppressions.xml index 9d169de..073e8bf 100644 --- a/buildSrc/quality/checkstyle-suppressions.xml +++ b/buildSrc/quality/checkstyle-suppressions.xml @@ -1,29 +1,17 @@ diff --git a/buildSrc/settings.gradle.kts b/buildSrc/settings.gradle.kts index 51f4ab1..cfd05a9 100644 --- a/buildSrc/settings.gradle.kts +++ b/buildSrc/settings.gradle.kts @@ -1,27 +1,15 @@ /* - * Copyright 2026, TeamDev. All rights reserved. + * Copyright 2026 CodeMatters, Lda. * - * 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 + * 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 * - * Redistribution and use in source and/or binary forms, with or without - * modification, must retain the above copyright notice and the following - * disclaimer. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. */ pluginManagement { diff --git a/buildSrc/src/main/kotlin/BuildExtensions.kt b/buildSrc/src/main/kotlin/BuildExtensions.kt index 5c24dc3..a69dd1a 100644 --- a/buildSrc/src/main/kotlin/BuildExtensions.kt +++ b/buildSrc/src/main/kotlin/BuildExtensions.kt @@ -1,27 +1,15 @@ /* - * Copyright 2026, TeamDev. All rights reserved. + * Copyright 2026 CodeMatters, Lda. * - * 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 + * 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 * - * Redistribution and use in source and/or binary forms, with or without - * modification, must retain the above copyright notice and the following - * disclaimer. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. */ @file:Suppress("UnusedReceiverParameter", "unused", "TopLevelPropertyNaming", "ObjectPropertyName") diff --git a/buildSrc/src/main/kotlin/BuildSettings.kt b/buildSrc/src/main/kotlin/BuildSettings.kt index da4b928..a549c83 100644 --- a/buildSrc/src/main/kotlin/BuildSettings.kt +++ b/buildSrc/src/main/kotlin/BuildSettings.kt @@ -1,27 +1,15 @@ /* - * Copyright 2026, TeamDev. All rights reserved. + * Copyright 2026 CodeMatters, Lda. * - * 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 + * 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 * - * Redistribution and use in source and/or binary forms, with or without - * modification, must retain the above copyright notice and the following - * disclaimer. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. */ import org.gradle.api.JavaVersion diff --git a/buildSrc/src/main/kotlin/DependencyResolution.kt b/buildSrc/src/main/kotlin/DependencyResolution.kt index ce37859..a419949 100644 --- a/buildSrc/src/main/kotlin/DependencyResolution.kt +++ b/buildSrc/src/main/kotlin/DependencyResolution.kt @@ -1,27 +1,15 @@ /* - * Copyright 2026, TeamDev. All rights reserved. + * Copyright 2026 CodeMatters, Lda. * - * 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 + * 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 * - * Redistribution and use in source and/or binary forms, with or without - * modification, must retain the above copyright notice and the following - * disclaimer. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. */ import io.spine.dependency.build.AnimalSniffer diff --git a/buildSrc/src/main/kotlin/DocumentationSettings.kt b/buildSrc/src/main/kotlin/DocumentationSettings.kt index 7c728e4..68d253f 100644 --- a/buildSrc/src/main/kotlin/DocumentationSettings.kt +++ b/buildSrc/src/main/kotlin/DocumentationSettings.kt @@ -1,27 +1,15 @@ /* - * Copyright 2026, TeamDev. All rights reserved. + * Copyright 2026 CodeMatters, Lda. * - * 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 + * 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 * - * Redistribution and use in source and/or binary forms, with or without - * modification, must retain the above copyright notice and the following - * disclaimer. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. */ import org.gradle.api.Project diff --git a/buildSrc/src/main/kotlin/DokkaExts.kt b/buildSrc/src/main/kotlin/DokkaExts.kt index 2e3160b..d1483b6 100644 --- a/buildSrc/src/main/kotlin/DokkaExts.kt +++ b/buildSrc/src/main/kotlin/DokkaExts.kt @@ -1,31 +1,20 @@ /* - * Copyright 2026, TeamDev. All rights reserved. + * Copyright 2026 CodeMatters, Lda. * - * 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 + * 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 * - * Redistribution and use in source and/or binary forms, with or without - * modification, must retain the above copyright notice and the following - * disclaimer. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -import io.spine.dependency.build.Dokka + * 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. + */ + +import io.spine.dependency.local.DokkaTools import io.spine.gradle.SpineTaskGroup +import io.spine.gradle.github.pages.TaskName import io.spine.gradle.publish.getOrCreate import java.io.File import java.time.LocalDate @@ -33,14 +22,20 @@ import org.gradle.api.Project import org.gradle.api.Task import org.gradle.api.artifacts.Dependency import org.gradle.api.artifacts.dsl.DependencyHandler +import org.gradle.api.execution.TaskExecutionGraph +import org.gradle.api.publish.maven.tasks.PublishToMavenLocal +import org.gradle.api.publish.maven.tasks.PublishToMavenRepository import org.gradle.api.tasks.TaskContainer import org.gradle.api.tasks.TaskProvider import org.gradle.api.tasks.bundling.Jar import org.gradle.kotlin.dsl.DependencyHandlerScope +import org.gradle.kotlin.dsl.property +import org.gradle.kotlin.dsl.withType import org.jetbrains.dokka.gradle.DokkaExtension import org.jetbrains.dokka.gradle.engine.parameters.DokkaSourceSetSpec import org.jetbrains.dokka.gradle.engine.parameters.VisibilityModifier import org.jetbrains.dokka.gradle.engine.plugins.DokkaHtmlPluginParameters +import org.jetbrains.dokka.gradle.tasks.DokkaBaseTask /** * To exclude pieces of code annotated with `@Internal` from the documentation @@ -50,7 +45,7 @@ import org.jetbrains.dokka.gradle.engine.plugins.DokkaHtmlPluginParameters * Custom Dokka Plugins */ fun DependencyHandlerScope.useDokkaWithSpineExtensions() { - dokkaPlugin(Dokka.SpineExtensions.lib) + dokkaPlugin(DokkaTools.extensions) } private fun DependencyHandler.dokkaPlugin(dependencyNotation: Any): Dependency? = @@ -88,7 +83,7 @@ fun Project.dokkaConfigFile(file: String): File { fun DokkaHtmlPluginParameters.configureStyle(project: Project) { customAssets.from(project.dokkaConfigFile("assets/logo-icon.svg")) customStyleSheets.from(project.dokkaConfigFile("styles/custom-styles.css")) - footerMessage.set("Copyright ${LocalDate.now().year}, TeamDev") + footerMessage.set("Copyright ${LocalDate.now().year} CodeMatters, Lda.") separateInheritedMembers.set(true) mergeImplicitExpectActualDeclarations.set(false) } @@ -217,18 +212,127 @@ fun Project.htmlDocsJar(): TaskProvider = tasks.getOrCreate("htmlDocsJar") /** * Tells if this task belongs to the execution graph that contains - * the `publish` and `dokkaGenerate` tasks. + * the `publish` or `dokkaGenerate` tasks. * * This predicate could be useful for disabling publishing tasks * when doing, e.g., `publishToMavenLocal` for the purpose of the * integration tests that (of course) do not test the documentation * generation process and its results. + * + * The predicate reaches the task graph through [Task.getProject]. Called from an `onlyIf` + * spec or a task action, it does so at execution time, which Gradle deprecates and + * the configuration cache does not support. Also, the predicate holds whenever the graph + * contains a Dokka task, since Dokka 2.x names its tasks `dokkaGenerate…`. + * [skipDokkaWhenPublishingToMavenLocal] avoids both problems. */ +@Deprecated(message = "Please use `Project.skipDokkaWhenPublishingToMavenLocal()` instead.") fun Task.isInPublishingGraph(): Boolean = project.gradle.taskGraph.allTasks.any { it.name == "publish" || it.name.contains("dokkaGenerate") } +/** + * Configures the Dokka tasks of this project to be skipped in a build that publishes + * to Maven Local only. + * + * Such a build usually feeds integration tests, which need the published code, + * but not its documentation. So the Dokka tasks are skipped when the execution graph + * contains a [PublishToMavenLocal] task and no task that ships the documentation + * elsewhere: `publish`, a [PublishToMavenRepository] task, or `updateGitHubPages`. + * They still run if a task named on the command line selects a documentation task of + * the graph: one that has `dokka` in its name, ignoring case, or a documentation JAR, + * `javadocJar` or `htmlDocsJar`. The name may be the full one, e.g., `dokkaGenerate`, + * or a camel-case abbreviation, e.g., `dGPJ` for `dokkaGeneratePublicationJavadoc`. + * Without task names, a documentation request cannot be ruled out, so the tasks run too. + * This is the case of an included build, as Gradle does not pass it the tasks named + * on the command line. + * + * Any other build runs the Dokka tasks in its graph. When the tasks are skipped, + * the documentation JARs they feed, such as `javadocJar`, contain only a manifest, + * or the output of an earlier Dokka run. + * + * The `onlyIf` spec added to the tasks is evaluated at execution time, when it must not + * call [Task.getProject] to reach the task graph: Gradle deprecates that, and + * the configuration cache does not support it. So the graph is scanned at configuration + * time, once it is ready, and the spec reads the result from a property, which + * a configuration cache entry stores along with the tasks. + */ +fun Project.skipDokkaWhenPublishingToMavenLocal() { + // The project path is dropped, so that, e.g., `:dokka-extensions:build` + // is not taken for a Dokka request. + val requestedNames = gradle.startParameter.taskNames + .map { it.substringAfterLast(':') } + .filter { it.isNotEmpty() } + val docsNeeded = objects.property() + gradle.taskGraph.whenReady { + val docsRequested = requestedNames.isEmpty() || selectsDocsTask(requestedNames) + docsNeeded.set(docsRequested || !publishesToMavenLocalOnly()) + } + tasks.withType().configureEach { + onlyIf("documentation is needed beyond Maven Local") { docsNeeded.get() } + } +} + +/** + * The names of the lifecycle tasks that ship the documentation beyond Maven Local. + */ +private val docsShippingTaskNames = setOf("publish", TaskName.updateGitHubPages) + +/** + * Tells if this graph publishes to Maven Local and does not contain a task that ships + * the documentation elsewhere. + */ +private fun TaskExecutionGraph.publishesToMavenLocalOnly(): Boolean { + val tasks = allTasks + return tasks.any { it is PublishToMavenLocal } + && tasks.none { it is PublishToMavenRepository || it.name in docsShippingTaskNames } +} + +/** + * The names of the tasks that pack the documentation into JARs. + */ +private val docsJarTaskNames = setOf("javadocJar", "htmlDocsJar") + +/** + * Tells if any of the given names, taken from the command line, selects + * a documentation task of this graph. + * + * A documentation task is one that has `dokka` in its name, ignoring case, + * or a documentation JAR. The command line keeps a task name as typed, so the name + * may be a camel-case abbreviation that Gradle resolves, e.g., `dGPJ` + * for `dokkaGeneratePublicationJavadoc`. + */ +private fun TaskExecutionGraph.selectsDocsTask(names: List): Boolean { + val docsTaskNames = allTasks.map { it.name }.filter { + it.contains("dokka", ignoreCase = true) || it in docsJarTaskNames + } + return names.any { name -> + val pattern = abbreviationPattern(name) + docsTaskNames.any { pattern.containsMatchIn(it) } + } +} + +/** + * Creates the pattern for the task names that the given camel-case abbreviation selects. + * + * Follows the matching of Gradle: each word of the abbreviation starts a word of + * the task name, in the same order, and the task name may go on after the last one. + * Unlike Gradle, which prefers exact and case-sensitive matches, the pattern + * ignores case, so it may select more tasks, never fewer. + */ +private fun abbreviationPattern(abbreviation: String): Regex { + val words = abbreviation.split(wordStart).filter { it.isNotEmpty() } + val pattern = words.joinToString(separator = "[\\p{javaLowerCase}\\p{Digit}]*", prefix = "^") { + Regex.escape(it) + } + return Regex(pattern, RegexOption.IGNORE_CASE) +} + +/** + * Matches the position before an upper-case letter, where a word of a camel-case name starts. + */ +private val wordStart = Regex("(?=\\p{javaUpperCase})") + /** * Disables Dokka and Javadoc tasks in this `Project`. * diff --git a/buildSrc/src/main/kotlin/LicenseSettings.kt b/buildSrc/src/main/kotlin/LicenseSettings.kt index 3b49cb5..c46f7a0 100644 --- a/buildSrc/src/main/kotlin/LicenseSettings.kt +++ b/buildSrc/src/main/kotlin/LicenseSettings.kt @@ -1,27 +1,15 @@ /* - * Copyright 2026, TeamDev. All rights reserved. + * Copyright 2026 CodeMatters, Lda. * - * 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 + * 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 * - * Redistribution and use in source and/or binary forms, with or without - * modification, must retain the above copyright notice and the following - * disclaimer. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. */ /** @@ -40,4 +28,12 @@ object LicenseSettings { const val name = "The Apache License, Version 2.0" const val url = "https://www.apache.org/licenses/LICENSE-2.0.txt" + + /** + * The [SPDX identifier](https://spdx.org/licenses/) of the license, which the SBOM + * published with an artifact declares for the modules of this project. + * + * @see io.spine.gradle.publish.PublicationSbomTask + */ + const val spdxId = "Apache-2.0" } diff --git a/buildSrc/src/main/kotlin/Strings.kt b/buildSrc/src/main/kotlin/Strings.kt index 0c5b574..6d6863f 100644 --- a/buildSrc/src/main/kotlin/Strings.kt +++ b/buildSrc/src/main/kotlin/Strings.kt @@ -1,27 +1,15 @@ /* - * Copyright 2026, TeamDev. All rights reserved. + * Copyright 2026 CodeMatters, Lda. * - * 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 + * 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 * - * Redistribution and use in source and/or binary forms, with or without - * modification, must retain the above copyright notice and the following - * disclaimer. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. */ /** diff --git a/buildSrc/src/main/kotlin/config-tester.gradle.kts b/buildSrc/src/main/kotlin/config-tester.gradle.kts index 79eabac..22b2d90 100644 --- a/buildSrc/src/main/kotlin/config-tester.gradle.kts +++ b/buildSrc/src/main/kotlin/config-tester.gradle.kts @@ -1,27 +1,15 @@ /* - * Copyright 2026, TeamDev. All rights reserved. + * Copyright 2026 CodeMatters, Lda. * - * 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 + * 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 * - * Redistribution and use in source and/or binary forms, with or without - * modification, must retain the above copyright notice and the following - * disclaimer. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. */ import io.spine.gradle.ConfigTester diff --git a/buildSrc/src/main/kotlin/detekt-code-analysis.gradle.kts b/buildSrc/src/main/kotlin/detekt-code-analysis.gradle.kts index 15af844..2ce096f 100644 --- a/buildSrc/src/main/kotlin/detekt-code-analysis.gradle.kts +++ b/buildSrc/src/main/kotlin/detekt-code-analysis.gradle.kts @@ -1,27 +1,15 @@ /* - * Copyright 2026, TeamDev. All rights reserved. + * Copyright 2026 CodeMatters, Lda. * - * 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 + * 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 * - * Redistribution and use in source and/or binary forms, with or without - * modification, must retain the above copyright notice and the following - * disclaimer. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. */ import io.gitlab.arturbosch.detekt.Detekt diff --git a/buildSrc/src/main/kotlin/dokka-setup.gradle.kts b/buildSrc/src/main/kotlin/dokka-setup.gradle.kts index a1915cf..c66e9f2 100644 --- a/buildSrc/src/main/kotlin/dokka-setup.gradle.kts +++ b/buildSrc/src/main/kotlin/dokka-setup.gradle.kts @@ -1,27 +1,15 @@ /* - * Copyright 2026, TeamDev. All rights reserved. + * Copyright 2026 CodeMatters, Lda. * - * 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 + * 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 * - * Redistribution and use in source and/or binary forms, with or without - * modification, must retain the above copyright notice and the following - * disclaimer. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. */ import org.jetbrains.dokka.gradle.tasks.DokkaBaseTask @@ -35,11 +23,7 @@ dependencies { useDokkaWithSpineExtensions() } -tasks.withType().configureEach { - onlyIf { - isInPublishingGraph() - } -} +skipDokkaWhenPublishingToMavenLocal() // The Dokka Javadoc format does not support Kotlin Multiplatform source sets, so its // publication task fails for KMP modules ("No source set found for /jvmMain"). diff --git a/buildSrc/src/main/kotlin/io/spine/dependency/Dependency.kt b/buildSrc/src/main/kotlin/io/spine/dependency/Dependency.kt index 0b431c5..ac1cde2 100644 --- a/buildSrc/src/main/kotlin/io/spine/dependency/Dependency.kt +++ b/buildSrc/src/main/kotlin/io/spine/dependency/Dependency.kt @@ -1,27 +1,15 @@ /* - * Copyright 2026, TeamDev. All rights reserved. + * Copyright 2026 CodeMatters, Lda. * - * 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 + * 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 * - * Redistribution and use in source and/or binary forms, with or without - * modification, must retain the above copyright notice and the following - * disclaimer. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 io.spine.dependency diff --git a/buildSrc/src/main/kotlin/io/spine/dependency/boms/Boms.kt b/buildSrc/src/main/kotlin/io/spine/dependency/boms/Boms.kt index 266dd8d..5e07423 100644 --- a/buildSrc/src/main/kotlin/io/spine/dependency/boms/Boms.kt +++ b/buildSrc/src/main/kotlin/io/spine/dependency/boms/Boms.kt @@ -1,27 +1,15 @@ /* - * Copyright 2026, TeamDev. All rights reserved. + * Copyright 2026 CodeMatters, Lda. * - * 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 + * 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 * - * Redistribution and use in source and/or binary forms, with or without - * modification, must retain the above copyright notice and the following - * disclaimer. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 io.spine.dependency.boms diff --git a/buildSrc/src/main/kotlin/io/spine/dependency/boms/BomsPlugin.kt b/buildSrc/src/main/kotlin/io/spine/dependency/boms/BomsPlugin.kt index efe0783..c9811f8 100644 --- a/buildSrc/src/main/kotlin/io/spine/dependency/boms/BomsPlugin.kt +++ b/buildSrc/src/main/kotlin/io/spine/dependency/boms/BomsPlugin.kt @@ -1,27 +1,15 @@ /* - * Copyright 2026, TeamDev. All rights reserved. + * Copyright 2026 CodeMatters, Lda. * - * 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 + * 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 * - * Redistribution and use in source and/or binary forms, with or without - * modification, must retain the above copyright notice and the following - * disclaimer. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 io.spine.dependency.boms diff --git a/buildSrc/src/main/kotlin/io/spine/dependency/build/AnimalSniffer.kt b/buildSrc/src/main/kotlin/io/spine/dependency/build/AnimalSniffer.kt index 52349ef..4891a7d 100644 --- a/buildSrc/src/main/kotlin/io/spine/dependency/build/AnimalSniffer.kt +++ b/buildSrc/src/main/kotlin/io/spine/dependency/build/AnimalSniffer.kt @@ -1,27 +1,15 @@ /* - * Copyright 2026, TeamDev. All rights reserved. + * Copyright 2026 CodeMatters, Lda. * - * 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 + * 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 * - * Redistribution and use in source and/or binary forms, with or without - * modification, must retain the above copyright notice and the following - * disclaimer. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 io.spine.dependency.build @@ -29,6 +17,6 @@ package io.spine.dependency.build // https://www.mojohaus.org/animal-sniffer/animal-sniffer-maven-plugin/ @Suppress("unused", "ConstPropertyName") object AnimalSniffer { - private const val version = "1.27" + private const val version = "1.28" const val lib = "org.codehaus.mojo:animal-sniffer-annotations:$version" } diff --git a/buildSrc/src/main/kotlin/io/spine/dependency/build/CheckStyle.kt b/buildSrc/src/main/kotlin/io/spine/dependency/build/CheckStyle.kt index e1e3b28..b493760 100644 --- a/buildSrc/src/main/kotlin/io/spine/dependency/build/CheckStyle.kt +++ b/buildSrc/src/main/kotlin/io/spine/dependency/build/CheckStyle.kt @@ -1,27 +1,15 @@ /* - * Copyright 2025, TeamDev. All rights reserved. + * Copyright 2026 CodeMatters, Lda. * - * 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 + * 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 * - * Redistribution and use in source and/or binary forms, with or without - * modification, must retain the above copyright notice and the following - * disclaimer. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 io.spine.dependency.build @@ -37,10 +25,19 @@ object CheckStyle { /** * The version to be used in the project. * - * `10.12.1` is the last version in `10.12.0`, which does not introduce - * capability conflict over `google-collections` with Guava. + * `12.3.1` is the last release that runs on Java 17, which our builds use + * to run Checkstyle. `13.0.0` and later require Java 21. + * + * `12.3.1` depends on Doxia, which Checkstyle uses only to generate its own + * website. Through Doxia, it brings two versions each of `commons-lang3` and + * `httpcore`. `forceVersions()` enables `failOnVersionConflict()` in the + * `checkstyle` configuration too, so Gradle would reject the graph. + * [CheckStyleConfig][io.spine.gradle.checkstyle.CheckStyleConfig] therefore + * excludes the `org.apache.maven.doxia` group from the `checkstyle` configuration. + * Releases from `13.11.0` on no longer depend on Doxia, so the exclusion can go + * once we run Checkstyle on Java 21. * * @see Checkstyle */ - const val version = "10.12.1" + const val version = "12.3.1" } diff --git a/buildSrc/src/main/kotlin/io/spine/dependency/build/CheckerFramework.kt b/buildSrc/src/main/kotlin/io/spine/dependency/build/CheckerFramework.kt index fe76133..85f2603 100644 --- a/buildSrc/src/main/kotlin/io/spine/dependency/build/CheckerFramework.kt +++ b/buildSrc/src/main/kotlin/io/spine/dependency/build/CheckerFramework.kt @@ -1,27 +1,15 @@ /* - * Copyright 2026, TeamDev. All rights reserved. + * Copyright 2026 CodeMatters, Lda. * - * 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 + * 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 * - * Redistribution and use in source and/or binary forms, with or without - * modification, must retain the above copyright notice and the following - * disclaimer. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 io.spine.dependency.build @@ -29,7 +17,7 @@ package io.spine.dependency.build // https://checkerframework.org/ @Suppress("unused", "ConstPropertyName") object CheckerFramework { - private const val version = "4.2.2" + private const val version = "4.3.1" const val annotations = "org.checkerframework:checker-qual:$version" @Suppress("unused") val dataflow = listOf( diff --git a/buildSrc/src/main/kotlin/io/spine/dependency/build/Dokka.kt b/buildSrc/src/main/kotlin/io/spine/dependency/build/Dokka.kt index 6b4822d..7ef1b5e 100644 --- a/buildSrc/src/main/kotlin/io/spine/dependency/build/Dokka.kt +++ b/buildSrc/src/main/kotlin/io/spine/dependency/build/Dokka.kt @@ -1,33 +1,19 @@ /* - * Copyright 2025, TeamDev. All rights reserved. + * Copyright 2026 CodeMatters, Lda. * - * 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 + * 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 * - * Redistribution and use in source and/or binary forms, with or without - * modification, must retain the above copyright notice and the following - * disclaimer. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 io.spine.dependency.build -import io.spine.dependency.local.Spine - // https://github.com/Kotlin/dokka @Suppress("unused", "ConstPropertyName") object Dokka { @@ -69,18 +55,4 @@ object Dokka { object KotlinAsJavaPlugin { const val lib = "$group:kotlin-as-java-plugin:$version" } - - /** - * Custom Dokka plugins developed for Spine-specific needs like excluding by - * `@Internal` annotation. - * - * @see - * Custom Dokka Plugins - */ - object SpineExtensions { - private const val group = Spine.toolsGroup - - const val version = "2.0.0-SNAPSHOT.7" - const val lib = "$group:spine-dokka-extensions:$version" - } } diff --git a/buildSrc/src/main/kotlin/io/spine/dependency/build/ErrorProne.kt b/buildSrc/src/main/kotlin/io/spine/dependency/build/ErrorProne.kt index 698ca7e..c7b8f9b 100644 --- a/buildSrc/src/main/kotlin/io/spine/dependency/build/ErrorProne.kt +++ b/buildSrc/src/main/kotlin/io/spine/dependency/build/ErrorProne.kt @@ -1,27 +1,15 @@ /* - * Copyright 2026, TeamDev. All rights reserved. + * Copyright 2026 CodeMatters, Lda. * - * 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 + * 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 * - * Redistribution and use in source and/or binary forms, with or without - * modification, must retain the above copyright notice and the following - * disclaimer. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 io.spine.dependency.build @@ -30,7 +18,7 @@ package io.spine.dependency.build @Suppress("unused", "ConstPropertyName") object ErrorProne { /** - * This is the last version which is compatible with Java 17. + * This is the last version that is compatible with Java 17. * * The version 2.43.0 requires JDK 21. * https://github.com/google/error-prone/releases/tag/v2.43.0 diff --git a/buildSrc/src/main/kotlin/io/spine/dependency/build/FindBugs.kt b/buildSrc/src/main/kotlin/io/spine/dependency/build/FindBugs.kt index 98003b9..ab114d3 100644 --- a/buildSrc/src/main/kotlin/io/spine/dependency/build/FindBugs.kt +++ b/buildSrc/src/main/kotlin/io/spine/dependency/build/FindBugs.kt @@ -1,27 +1,15 @@ /* - * Copyright 2025, TeamDev. All rights reserved. + * Copyright 2026 CodeMatters, Lda. * - * 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 + * 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 * - * Redistribution and use in source and/or binary forms, with or without - * modification, must retain the above copyright notice and the following - * disclaimer. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 io.spine.dependency.build diff --git a/buildSrc/src/main/kotlin/io/spine/dependency/build/GradleDoctor.kt b/buildSrc/src/main/kotlin/io/spine/dependency/build/GradleDoctor.kt index 0915507..2cc4f0c 100644 --- a/buildSrc/src/main/kotlin/io/spine/dependency/build/GradleDoctor.kt +++ b/buildSrc/src/main/kotlin/io/spine/dependency/build/GradleDoctor.kt @@ -1,27 +1,15 @@ /* - * Copyright 2026, TeamDev. All rights reserved. + * Copyright 2026 CodeMatters, Lda. * - * 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 + * 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 * - * Redistribution and use in source and/or binary forms, with or without - * modification, must retain the above copyright notice and the following - * disclaimer. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 io.spine.dependency.build diff --git a/buildSrc/src/main/kotlin/io/spine/dependency/build/JSpecify.kt b/buildSrc/src/main/kotlin/io/spine/dependency/build/JSpecify.kt index 4c5d691..e5af07c 100644 --- a/buildSrc/src/main/kotlin/io/spine/dependency/build/JSpecify.kt +++ b/buildSrc/src/main/kotlin/io/spine/dependency/build/JSpecify.kt @@ -1,27 +1,15 @@ /* - * Copyright 2026, TeamDev. All rights reserved. + * Copyright 2026 CodeMatters, Lda. * - * 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 + * 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 * - * Redistribution and use in source and/or binary forms, with or without - * modification, must retain the above copyright notice and the following - * disclaimer. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 io.spine.dependency.build diff --git a/buildSrc/src/main/kotlin/io/spine/dependency/build/Ksp.kt b/buildSrc/src/main/kotlin/io/spine/dependency/build/Ksp.kt index 0032766..5f5f65c 100644 --- a/buildSrc/src/main/kotlin/io/spine/dependency/build/Ksp.kt +++ b/buildSrc/src/main/kotlin/io/spine/dependency/build/Ksp.kt @@ -1,27 +1,15 @@ /* - * Copyright 2026, TeamDev. All rights reserved. + * Copyright 2026 CodeMatters, Lda. * - * 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 + * 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 * - * Redistribution and use in source and/or binary forms, with or without - * modification, must retain the above copyright notice and the following - * disclaimer. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 io.spine.dependency.build @@ -35,19 +23,50 @@ import io.spine.dependency.Dependency */ @Suppress("unused") object Ksp : Dependency() { - override val version = "2.3.11" + override val version = "2.3.12" val dogfoodingVersion = version override val group = "com.google.devtools.ksp" const val id = "com.google.devtools.ksp" const val gradlePluginArtifactName = "com.google.devtools.ksp.gradle.plugin" + /** + * The plugin marker of the KSP Gradle plugin, through which Gradle resolves + * the plugin by its [id]. + * + * The marker is not among the [modules]: it is a POM without code, + * which points at [gradlePlugin]. + */ + val gradlePluginMarker = "$id:$gradlePluginArtifactName" + + /** Returns the coordinates of [gradlePluginMarker] with the [version]. */ + fun gradlePluginMarker(): String = artifact(gradlePluginMarker, version) + val symbolProcessingApi = "$group:symbol-processing-api" + + /** Returns the coordinates of [symbolProcessingApi] with the [version]. */ + fun symbolProcessingApi(): String = artifact(symbolProcessingApi) + val symbolProcessing = "$group:symbol-processing" + + /** Returns the coordinates of [symbolProcessing] with the [version]. */ + fun symbolProcessing(): String = artifact(symbolProcessing) + val symbolProcessingAaEmb = "$group:symbol-processing-aa-embeddable" + + /** Returns the coordinates of [symbolProcessingAaEmb] with the [version]. */ + fun symbolProcessingAaEmb(): String = artifact(symbolProcessingAaEmb) + val symbolProcessingCommonDeps = "$group:symbol-processing-common-deps" + + /** Returns the coordinates of [symbolProcessingCommonDeps] with the [version]. */ + fun symbolProcessingCommonDeps(): String = artifact(symbolProcessingCommonDeps) + val gradlePlugin = "$group:symbol-processing-gradle-plugin" + /** Returns the coordinates of [gradlePlugin] with the [version]. */ + fun gradlePlugin(): String = artifact(gradlePlugin) + override val modules = listOf( symbolProcessingApi, symbolProcessing, diff --git a/buildSrc/src/main/kotlin/io/spine/dependency/build/OsDetector.kt b/buildSrc/src/main/kotlin/io/spine/dependency/build/OsDetector.kt index 5b479bf..750a67c 100644 --- a/buildSrc/src/main/kotlin/io/spine/dependency/build/OsDetector.kt +++ b/buildSrc/src/main/kotlin/io/spine/dependency/build/OsDetector.kt @@ -1,27 +1,15 @@ /* - * Copyright 2025, TeamDev. All rights reserved. + * Copyright 2026 CodeMatters, Lda. * - * 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 + * 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 * - * Redistribution and use in source and/or binary forms, with or without - * modification, must retain the above copyright notice and the following - * disclaimer. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 io.spine.dependency.build diff --git a/buildSrc/src/main/kotlin/io/spine/dependency/build/PluginPublishPlugin.kt b/buildSrc/src/main/kotlin/io/spine/dependency/build/PluginPublishPlugin.kt index c0df889..5ebe6a4 100644 --- a/buildSrc/src/main/kotlin/io/spine/dependency/build/PluginPublishPlugin.kt +++ b/buildSrc/src/main/kotlin/io/spine/dependency/build/PluginPublishPlugin.kt @@ -1,27 +1,15 @@ /* - * Copyright 2026, TeamDev. All rights reserved. + * Copyright 2026 CodeMatters, Lda. * - * 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 + * 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 * - * Redistribution and use in source and/or binary forms, with or without - * modification, must retain the above copyright notice and the following - * disclaimer. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. */ @file:Suppress("unused") @@ -37,6 +25,6 @@ package io.spine.dependency.build */ @Suppress("ConstPropertyName") object PluginPublishPlugin { - const val version = "2.1.1" + const val version = "2.2.1" const val id = "com.gradle.plugin-publish" } diff --git a/buildSrc/src/main/kotlin/io/spine/dependency/build/Pmd.kt b/buildSrc/src/main/kotlin/io/spine/dependency/build/Pmd.kt index c538630..0ca4a21 100644 --- a/buildSrc/src/main/kotlin/io/spine/dependency/build/Pmd.kt +++ b/buildSrc/src/main/kotlin/io/spine/dependency/build/Pmd.kt @@ -1,27 +1,15 @@ /* - * Copyright 2026, TeamDev. All rights reserved. + * Copyright 2026 CodeMatters, Lda. * - * 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 + * 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 * - * Redistribution and use in source and/or binary forms, with or without - * modification, must retain the above copyright notice and the following - * disclaimer. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. */ @file:Suppress("MaxLineLength") @@ -31,5 +19,5 @@ package io.spine.dependency.build // https://github.com/pmd/pmd/releases @Suppress("unused", "ConstPropertyName") object Pmd { - const val version = "7.27.0" + const val version = "7.28.0" } diff --git a/buildSrc/src/main/kotlin/io/spine/dependency/kotlinx/AtomicFu.kt b/buildSrc/src/main/kotlin/io/spine/dependency/kotlinx/AtomicFu.kt index 7e51062..566114b 100644 --- a/buildSrc/src/main/kotlin/io/spine/dependency/kotlinx/AtomicFu.kt +++ b/buildSrc/src/main/kotlin/io/spine/dependency/kotlinx/AtomicFu.kt @@ -1,27 +1,15 @@ /* - * Copyright 2026, TeamDev. All rights reserved. + * Copyright 2026 CodeMatters, Lda. * - * 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 + * 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 * - * Redistribution and use in source and/or binary forms, with or without - * modification, must retain the above copyright notice and the following - * disclaimer. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 io.spine.dependency.kotlinx diff --git a/buildSrc/src/main/kotlin/io/spine/dependency/kotlinx/Coroutines.kt b/buildSrc/src/main/kotlin/io/spine/dependency/kotlinx/Coroutines.kt index 46c252d..fcbb18e 100644 --- a/buildSrc/src/main/kotlin/io/spine/dependency/kotlinx/Coroutines.kt +++ b/buildSrc/src/main/kotlin/io/spine/dependency/kotlinx/Coroutines.kt @@ -1,27 +1,15 @@ /* - * Copyright 2026, TeamDev. All rights reserved. + * Copyright 2026 CodeMatters, Lda. * - * 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 + * 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 * - * Redistribution and use in source and/or binary forms, with or without - * modification, must retain the above copyright notice and the following - * disclaimer. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 io.spine.dependency.kotlinx diff --git a/buildSrc/src/main/kotlin/io/spine/dependency/kotlinx/DateTime.kt b/buildSrc/src/main/kotlin/io/spine/dependency/kotlinx/DateTime.kt index b9b3224..dfbf5f6 100644 --- a/buildSrc/src/main/kotlin/io/spine/dependency/kotlinx/DateTime.kt +++ b/buildSrc/src/main/kotlin/io/spine/dependency/kotlinx/DateTime.kt @@ -1,27 +1,15 @@ /* - * Copyright 2026, TeamDev. All rights reserved. + * Copyright 2026 CodeMatters, Lda. * - * 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 + * 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 * - * Redistribution and use in source and/or binary forms, with or without - * modification, must retain the above copyright notice and the following - * disclaimer. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 io.spine.dependency.kotlinx diff --git a/buildSrc/src/main/kotlin/io/spine/dependency/kotlinx/KotlinX.kt b/buildSrc/src/main/kotlin/io/spine/dependency/kotlinx/KotlinX.kt index d2a9511..f34eee9 100644 --- a/buildSrc/src/main/kotlin/io/spine/dependency/kotlinx/KotlinX.kt +++ b/buildSrc/src/main/kotlin/io/spine/dependency/kotlinx/KotlinX.kt @@ -1,27 +1,15 @@ /* - * Copyright 2026, TeamDev. All rights reserved. + * Copyright 2026 CodeMatters, Lda. * - * 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 + * 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 * - * Redistribution and use in source and/or binary forms, with or without - * modification, must retain the above copyright notice and the following - * disclaimer. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 io.spine.dependency.kotlinx diff --git a/buildSrc/src/main/kotlin/io/spine/dependency/kotlinx/Serialization.kt b/buildSrc/src/main/kotlin/io/spine/dependency/kotlinx/Serialization.kt index b22190f..81e4303 100644 --- a/buildSrc/src/main/kotlin/io/spine/dependency/kotlinx/Serialization.kt +++ b/buildSrc/src/main/kotlin/io/spine/dependency/kotlinx/Serialization.kt @@ -1,27 +1,15 @@ /* - * Copyright 2026, TeamDev. All rights reserved. + * Copyright 2026 CodeMatters, Lda. * - * 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 + * 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 * - * Redistribution and use in source and/or binary forms, with or without - * modification, must retain the above copyright notice and the following - * disclaimer. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 io.spine.dependency.kotlinx diff --git a/buildSrc/src/main/kotlin/io/spine/dependency/lib/Aedile.kt b/buildSrc/src/main/kotlin/io/spine/dependency/lib/Aedile.kt index 5d4aac9..43dd1c8 100644 --- a/buildSrc/src/main/kotlin/io/spine/dependency/lib/Aedile.kt +++ b/buildSrc/src/main/kotlin/io/spine/dependency/lib/Aedile.kt @@ -1,27 +1,15 @@ /* - * Copyright 2026, TeamDev. All rights reserved. + * Copyright 2026 CodeMatters, Lda. * - * 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 + * 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 * - * Redistribution and use in source and/or binary forms, with or without - * modification, must retain the above copyright notice and the following - * disclaimer. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 io.spine.dependency.lib diff --git a/buildSrc/src/main/kotlin/io/spine/dependency/lib/ApacheHttp.kt b/buildSrc/src/main/kotlin/io/spine/dependency/lib/ApacheHttp.kt index 5b3c492..28b509e 100644 --- a/buildSrc/src/main/kotlin/io/spine/dependency/lib/ApacheHttp.kt +++ b/buildSrc/src/main/kotlin/io/spine/dependency/lib/ApacheHttp.kt @@ -1,27 +1,15 @@ /* - * Copyright 2026, TeamDev. All rights reserved. + * Copyright 2026 CodeMatters, Lda. * - * 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 + * 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 * - * Redistribution and use in source and/or binary forms, with or without - * modification, must retain the above copyright notice and the following - * disclaimer. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 io.spine.dependency.lib @@ -30,5 +18,5 @@ package io.spine.dependency.lib object ApacheHttp { // https://hc.apache.org/downloads.cgi - const val core = "org.apache.httpcomponents:httpcore:4.4.14" + const val core = "org.apache.httpcomponents:httpcore:4.4.16" } diff --git a/buildSrc/src/main/kotlin/io/spine/dependency/lib/Asm.kt b/buildSrc/src/main/kotlin/io/spine/dependency/lib/Asm.kt index 0b1958a..216e038 100644 --- a/buildSrc/src/main/kotlin/io/spine/dependency/lib/Asm.kt +++ b/buildSrc/src/main/kotlin/io/spine/dependency/lib/Asm.kt @@ -1,27 +1,15 @@ /* - * Copyright 2026, TeamDev. All rights reserved. + * Copyright 2026 CodeMatters, Lda. * - * 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 + * 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 * - * Redistribution and use in source and/or binary forms, with or without - * modification, must retain the above copyright notice and the following - * disclaimer. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 io.spine.dependency.lib @@ -29,7 +17,7 @@ package io.spine.dependency.lib // https://asm.ow2.io/ @Suppress("unused", "ConstPropertyName") object Asm { - private const val version = "9.10.1" + private const val version = "9.11" const val group = "org.ow2.asm" const val lib = "$group:asm:$version" diff --git a/buildSrc/src/main/kotlin/io/spine/dependency/lib/Auto.kt b/buildSrc/src/main/kotlin/io/spine/dependency/lib/Auto.kt index a094355..1164f3f 100644 --- a/buildSrc/src/main/kotlin/io/spine/dependency/lib/Auto.kt +++ b/buildSrc/src/main/kotlin/io/spine/dependency/lib/Auto.kt @@ -1,27 +1,15 @@ /* - * Copyright 2026, TeamDev. All rights reserved. + * Copyright 2026 CodeMatters, Lda. * - * 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 + * 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 * - * Redistribution and use in source and/or binary forms, with or without - * modification, must retain the above copyright notice and the following - * disclaimer. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. */ @file:Suppress("unused", "ConstPropertyName") diff --git a/buildSrc/src/main/kotlin/io/spine/dependency/lib/BouncyCastle.kt b/buildSrc/src/main/kotlin/io/spine/dependency/lib/BouncyCastle.kt index 82cc69e..88bea96 100644 --- a/buildSrc/src/main/kotlin/io/spine/dependency/lib/BouncyCastle.kt +++ b/buildSrc/src/main/kotlin/io/spine/dependency/lib/BouncyCastle.kt @@ -1,27 +1,15 @@ /* - * Copyright 2026, TeamDev. All rights reserved. + * Copyright 2026 CodeMatters, Lda. * - * 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 + * 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 * - * Redistribution and use in source and/or binary forms, with or without - * modification, must retain the above copyright notice and the following - * disclaimer. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 io.spine.dependency.lib @@ -29,5 +17,31 @@ package io.spine.dependency.lib // https://www.bouncycastle.org/java.html @Suppress("unused", "ConstPropertyName") object BouncyCastle { - const val libPkcsJdk15 = "org.bouncycastle:bcpkix-jdk15on:1.68" + + /** + * The PKIX library, pinned to `bcpkix-jdk15on:1.70`, the last release of + * the `-jdk15on` artifacts. + * + * Newer releases are published as `bcpkix-jdk18on`. They carry the same + * `org.bouncycastle` classes, yet Gradle sees them as a different module + * and resolves no conflict between the two. + * + * The [IntelliJ Platform][IntelliJ.version] stays at `213.7172.53` for now. + * Its `ide-impl` module depends on the `-jdk15on` artifacts through two paths: + * + * - `marketplace-zip-signer:0.1.3` requires `bcpkix-jdk15on:1.64`. + * - `remote-dev-util` requires `bcpg-jdk15on:1.69`, which requires + * `bcprov-jdk15on:1.69`. + * + * Staying on `-jdk15on` lets Gradle resolve `bcpkix-jdk15on` and + * `bcprov-jdk15on` to `1.70`, the version of this library. With + * `bcpkix-jdk18on` instead, a project that also has the IntelliJ Platform + * on its classpath would get two copies of the BouncyCastle classes. + * + * The two paths also disagree on the version. That is why `tool-base` + * leaves BouncyCastle out of the POM of its IntelliJ Platform uber JAR. + * + * Revisit this pin when [IntelliJ.version] changes. + */ + const val libPkcsJdk15 = "org.bouncycastle:bcpkix-jdk15on:1.70" } diff --git a/buildSrc/src/main/kotlin/io/spine/dependency/lib/Caffeine.kt b/buildSrc/src/main/kotlin/io/spine/dependency/lib/Caffeine.kt index a52919c..8e1d907 100644 --- a/buildSrc/src/main/kotlin/io/spine/dependency/lib/Caffeine.kt +++ b/buildSrc/src/main/kotlin/io/spine/dependency/lib/Caffeine.kt @@ -1,27 +1,15 @@ /* - * Copyright 2026, TeamDev. All rights reserved. + * Copyright 2026 CodeMatters, Lda. * - * 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 + * 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 * - * Redistribution and use in source and/or binary forms, with or without - * modification, must retain the above copyright notice and the following - * disclaimer. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 io.spine.dependency.lib @@ -38,6 +26,6 @@ package io.spine.dependency.lib */ @Suppress("unused") object Caffeine { - private const val version = "3.2.4" + private const val version = "3.3.1" const val lib = "com.github.ben-manes.caffeine:caffeine:$version" } diff --git a/buildSrc/src/main/kotlin/io/spine/dependency/lib/Clikt.kt b/buildSrc/src/main/kotlin/io/spine/dependency/lib/Clikt.kt index b08fc1b..0de2971 100644 --- a/buildSrc/src/main/kotlin/io/spine/dependency/lib/Clikt.kt +++ b/buildSrc/src/main/kotlin/io/spine/dependency/lib/Clikt.kt @@ -1,27 +1,15 @@ /* - * Copyright 2026, TeamDev. All rights reserved. + * Copyright 2026 CodeMatters, Lda. * - * 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 + * 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 * - * Redistribution and use in source and/or binary forms, with or without - * modification, must retain the above copyright notice and the following - * disclaimer. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 io.spine.dependency.lib diff --git a/buildSrc/src/main/kotlin/io/spine/dependency/lib/CommonsCli.kt b/buildSrc/src/main/kotlin/io/spine/dependency/lib/CommonsCli.kt index 701453d..4a54287 100644 --- a/buildSrc/src/main/kotlin/io/spine/dependency/lib/CommonsCli.kt +++ b/buildSrc/src/main/kotlin/io/spine/dependency/lib/CommonsCli.kt @@ -1,27 +1,15 @@ /* - * Copyright 2026, TeamDev. All rights reserved. + * Copyright 2026 CodeMatters, Lda. * - * 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 + * 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 * - * Redistribution and use in source and/or binary forms, with or without - * modification, must retain the above copyright notice and the following - * disclaimer. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 io.spine.dependency.lib diff --git a/buildSrc/src/main/kotlin/io/spine/dependency/lib/CommonsCodec.kt b/buildSrc/src/main/kotlin/io/spine/dependency/lib/CommonsCodec.kt index 80db86e..e2d45c2 100644 --- a/buildSrc/src/main/kotlin/io/spine/dependency/lib/CommonsCodec.kt +++ b/buildSrc/src/main/kotlin/io/spine/dependency/lib/CommonsCodec.kt @@ -1,27 +1,15 @@ /* - * Copyright 2026, TeamDev. All rights reserved. + * Copyright 2026 CodeMatters, Lda. * - * 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 + * 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 * - * Redistribution and use in source and/or binary forms, with or without - * modification, must retain the above copyright notice and the following - * disclaimer. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 io.spine.dependency.lib @@ -29,6 +17,6 @@ package io.spine.dependency.lib // https://commons.apache.org/proper/commons-codec/changes-report.html @Suppress("unused", "ConstPropertyName") object CommonsCodec { - private const val version = "1.22.1" + private const val version = "1.23.0" const val lib = "commons-codec:commons-codec:$version" } diff --git a/buildSrc/src/main/kotlin/io/spine/dependency/lib/CommonsLogging.kt b/buildSrc/src/main/kotlin/io/spine/dependency/lib/CommonsLogging.kt index f06c861..507d7ea 100644 --- a/buildSrc/src/main/kotlin/io/spine/dependency/lib/CommonsLogging.kt +++ b/buildSrc/src/main/kotlin/io/spine/dependency/lib/CommonsLogging.kt @@ -1,27 +1,15 @@ /* - * Copyright 2026, TeamDev. All rights reserved. + * Copyright 2026 CodeMatters, Lda. * - * 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 + * 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 * - * Redistribution and use in source and/or binary forms, with or without - * modification, must retain the above copyright notice and the following - * disclaimer. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 io.spine.dependency.lib diff --git a/buildSrc/src/main/kotlin/io/spine/dependency/lib/Coroutines.kt b/buildSrc/src/main/kotlin/io/spine/dependency/lib/Coroutines.kt index 76fcfa6..86a9bce 100644 --- a/buildSrc/src/main/kotlin/io/spine/dependency/lib/Coroutines.kt +++ b/buildSrc/src/main/kotlin/io/spine/dependency/lib/Coroutines.kt @@ -1,27 +1,15 @@ /* - * Copyright 2026, TeamDev. All rights reserved. + * Copyright 2026 CodeMatters, Lda. * - * 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 + * 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 * - * Redistribution and use in source and/or binary forms, with or without - * modification, must retain the above copyright notice and the following - * disclaimer. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 io.spine.dependency.lib diff --git a/buildSrc/src/main/kotlin/io/spine/dependency/lib/Firebase.kt b/buildSrc/src/main/kotlin/io/spine/dependency/lib/Firebase.kt index 3c02b6b..435861d 100644 --- a/buildSrc/src/main/kotlin/io/spine/dependency/lib/Firebase.kt +++ b/buildSrc/src/main/kotlin/io/spine/dependency/lib/Firebase.kt @@ -1,27 +1,15 @@ /* - * Copyright 2026, TeamDev. All rights reserved. + * Copyright 2026 CodeMatters, Lda. * - * 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 + * 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 * - * Redistribution and use in source and/or binary forms, with or without - * modification, must retain the above copyright notice and the following - * disclaimer. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 io.spine.dependency.lib @@ -29,6 +17,6 @@ package io.spine.dependency.lib // https://firebase.google.com/docs/admin/setup#java @Suppress("unused", "ConstPropertyName") object Firebase { - private const val adminVersion = "9.10.0" + private const val adminVersion = "9.11.0" const val admin = "com.google.firebase:firebase-admin:$adminVersion" } diff --git a/buildSrc/src/main/kotlin/io/spine/dependency/lib/Flogger.kt b/buildSrc/src/main/kotlin/io/spine/dependency/lib/Flogger.kt index f0134a2..0073296 100644 --- a/buildSrc/src/main/kotlin/io/spine/dependency/lib/Flogger.kt +++ b/buildSrc/src/main/kotlin/io/spine/dependency/lib/Flogger.kt @@ -1,27 +1,15 @@ /* - * Copyright 2026, TeamDev. All rights reserved. + * Copyright 2026 CodeMatters, Lda. * - * 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 + * 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 * - * Redistribution and use in source and/or binary forms, with or without - * modification, must retain the above copyright notice and the following - * disclaimer. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 io.spine.dependency.lib diff --git a/buildSrc/src/main/kotlin/io/spine/dependency/lib/GoogleApis.kt b/buildSrc/src/main/kotlin/io/spine/dependency/lib/GoogleApis.kt index bdc6234..8664637 100644 --- a/buildSrc/src/main/kotlin/io/spine/dependency/lib/GoogleApis.kt +++ b/buildSrc/src/main/kotlin/io/spine/dependency/lib/GoogleApis.kt @@ -1,27 +1,15 @@ /* - * Copyright 2026, TeamDev. All rights reserved. + * Copyright 2026 CodeMatters, Lda. * - * 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 + * 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 * - * Redistribution and use in source and/or binary forms, with or without - * modification, must retain the above copyright notice and the following - * disclaimer. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 io.spine.dependency.lib @@ -33,26 +21,26 @@ package io.spine.dependency.lib object GoogleApis { // https://github.com/googleapis/google-api-java-client - const val client = "com.google.api-client:google-api-client:1.32.2" + const val client = "com.google.api-client:google-api-client:2.9.1" // https://github.com/googleapis/api-common-java - const val common = "com.google.api:api-common:2.64.0" + const val common = "com.google.api:api-common:2.70.0" // https://github.com/googleapis/java-common-protos - const val commonProtos = "com.google.api.grpc:proto-google-common-protos:2.72.0" + const val commonProtos = "com.google.api.grpc:proto-google-common-protos:2.78.0" // https://github.com/googleapis/gax-java - const val gax = "com.google.api:gax:2.80.0" + const val gax = "com.google.api:gax:2.87.0" // https://github.com/googleapis/java-iam - const val protoAim = "com.google.api.grpc:proto-google-iam-v1:1.2.0" + const val protoAim = "com.google.api.grpc:proto-google-iam-v1:1.73.0" // https://github.com/googleapis/google-oauth-java-client - const val oAuthClient = "com.google.oauth-client:google-oauth-client:1.32.1" + const val oAuthClient = "com.google.oauth-client:google-oauth-client:1.39.0" // https://github.com/googleapis/google-auth-library-java object AuthLibrary { - const val version = "1.51.0" + const val version = "1.54.0" const val credentials = "com.google.auth:google-auth-library-credentials:$version" const val oAuth2Http = "com.google.auth:google-auth-library-oauth2-http:$version" } diff --git a/buildSrc/src/main/kotlin/io/spine/dependency/lib/GoogleCloud.kt b/buildSrc/src/main/kotlin/io/spine/dependency/lib/GoogleCloud.kt index 0aea867..4df086b 100644 --- a/buildSrc/src/main/kotlin/io/spine/dependency/lib/GoogleCloud.kt +++ b/buildSrc/src/main/kotlin/io/spine/dependency/lib/GoogleCloud.kt @@ -1,27 +1,15 @@ /* - * Copyright 2026, TeamDev. All rights reserved. + * Copyright 2026 CodeMatters, Lda. * - * 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 + * 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 * - * Redistribution and use in source and/or binary forms, with or without - * modification, must retain the above copyright notice and the following - * disclaimer. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 io.spine.dependency.lib @@ -33,14 +21,14 @@ package io.spine.dependency.lib object GoogleCloud { // https://github.com/googleapis/google-cloud-java/tree/main/sdk-platform-java/java-core - const val core = "com.google.cloud:google-cloud-core:2.71.0" + const val core = "com.google.cloud:google-cloud-core:2.77.0" // https://github.com/googleapis/google-cloud-java/tree/main/java-pubsub/proto-google-cloud-pubsub-v1 - const val pubSubGrpcApi = "com.google.api.grpc:proto-google-cloud-pubsub-v1:1.151.0" + const val pubSubGrpcApi = "com.google.api.grpc:proto-google-cloud-pubsub-v1:1.157.0" // https://github.com/googleapis/google-cloud-java/tree/main/java-trace - const val trace = "com.google.cloud:google-cloud-trace:2.93.0" + const val trace = "com.google.cloud:google-cloud-trace:2.99.0" // https://github.com/googleapis/google-cloud-java/tree/main/java-datastore - const val datastore = "com.google.cloud:google-cloud-datastore:2.31.2" + const val datastore = "com.google.cloud:google-cloud-datastore:3.7.0" } diff --git a/buildSrc/src/main/kotlin/io/spine/dependency/lib/Grpc.kt b/buildSrc/src/main/kotlin/io/spine/dependency/lib/Grpc.kt index a0eeec9..7f89c29 100644 --- a/buildSrc/src/main/kotlin/io/spine/dependency/lib/Grpc.kt +++ b/buildSrc/src/main/kotlin/io/spine/dependency/lib/Grpc.kt @@ -1,27 +1,15 @@ /* - * Copyright 2026, TeamDev. All rights reserved. + * Copyright 2026 CodeMatters, Lda. * - * 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 + * 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 * - * Redistribution and use in source and/or binary forms, with or without - * modification, must retain the above copyright notice and the following - * disclaimer. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 io.spine.dependency.lib @@ -32,7 +20,7 @@ import io.spine.dependency.DependencyWithBom @Suppress("unused") object Grpc : DependencyWithBom() { - override val version = "1.83.1" + override val version = "1.85.0" override val group = "io.grpc" override val bom = "$group:grpc-bom:$version" diff --git a/buildSrc/src/main/kotlin/io/spine/dependency/lib/GrpcKotlin.kt b/buildSrc/src/main/kotlin/io/spine/dependency/lib/GrpcKotlin.kt index 0355fc2..41bc533 100644 --- a/buildSrc/src/main/kotlin/io/spine/dependency/lib/GrpcKotlin.kt +++ b/buildSrc/src/main/kotlin/io/spine/dependency/lib/GrpcKotlin.kt @@ -1,27 +1,15 @@ /* - * Copyright 2026, TeamDev. All rights reserved. + * Copyright 2026 CodeMatters, Lda. * - * 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 + * 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 * - * Redistribution and use in source and/or binary forms, with or without - * modification, must retain the above copyright notice and the following - * disclaimer. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 io.spine.dependency.lib diff --git a/buildSrc/src/main/kotlin/io/spine/dependency/lib/Gson.kt b/buildSrc/src/main/kotlin/io/spine/dependency/lib/Gson.kt index bae7be0..faf4ef7 100644 --- a/buildSrc/src/main/kotlin/io/spine/dependency/lib/Gson.kt +++ b/buildSrc/src/main/kotlin/io/spine/dependency/lib/Gson.kt @@ -1,27 +1,15 @@ /* - * Copyright 2026, TeamDev. All rights reserved. + * Copyright 2026 CodeMatters, Lda. * - * 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 + * 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 * - * Redistribution and use in source and/or binary forms, with or without - * modification, must retain the above copyright notice and the following - * disclaimer. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 io.spine.dependency.lib diff --git a/buildSrc/src/main/kotlin/io/spine/dependency/lib/Guava.kt b/buildSrc/src/main/kotlin/io/spine/dependency/lib/Guava.kt index 2080060..8f9eb3b 100644 --- a/buildSrc/src/main/kotlin/io/spine/dependency/lib/Guava.kt +++ b/buildSrc/src/main/kotlin/io/spine/dependency/lib/Guava.kt @@ -1,27 +1,15 @@ /* - * Copyright 2026, TeamDev. All rights reserved. + * Copyright 2026 CodeMatters, Lda. * - * 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 + * 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 * - * Redistribution and use in source and/or binary forms, with or without - * modification, must retain the above copyright notice and the following - * disclaimer. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 io.spine.dependency.lib @@ -37,7 +25,7 @@ package io.spine.dependency.lib */ @Suppress("unused", "ConstPropertyName") object Guava { - private const val version = "33.7.1-jre" + private const val version = "33.7.2-jre" const val group = "com.google.guava" const val lib = "$group:guava:$version" const val testLib = "$group:guava-testlib:$version" diff --git a/buildSrc/src/main/kotlin/io/spine/dependency/lib/HttpClient.kt b/buildSrc/src/main/kotlin/io/spine/dependency/lib/HttpClient.kt index 07fc6eb..7c16105 100644 --- a/buildSrc/src/main/kotlin/io/spine/dependency/lib/HttpClient.kt +++ b/buildSrc/src/main/kotlin/io/spine/dependency/lib/HttpClient.kt @@ -1,27 +1,15 @@ /* - * Copyright 2026, TeamDev. All rights reserved. + * Copyright 2026 CodeMatters, Lda. * - * 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 + * 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 * - * Redistribution and use in source and/or binary forms, with or without - * modification, must retain the above copyright notice and the following - * disclaimer. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 io.spine.dependency.lib diff --git a/buildSrc/src/main/kotlin/io/spine/dependency/lib/IntelliJ.kt b/buildSrc/src/main/kotlin/io/spine/dependency/lib/IntelliJ.kt index cf2d6b0..ea3ce8e 100644 --- a/buildSrc/src/main/kotlin/io/spine/dependency/lib/IntelliJ.kt +++ b/buildSrc/src/main/kotlin/io/spine/dependency/lib/IntelliJ.kt @@ -1,27 +1,15 @@ /* - * Copyright 2026, TeamDev. All rights reserved. + * Copyright 2026 CodeMatters, Lda. * - * 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 + * 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 * - * Redistribution and use in source and/or binary forms, with or without - * modification, must retain the above copyright notice and the following - * disclaimer. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. */ @file:Suppress("ConstPropertyName") @@ -43,6 +31,9 @@ object IntelliJ { * This is the version used by Kotlin compiler `1.9.21`. * Advance this version with caution because it may break the setup of * IntelliJ platform standalone execution. + * + * This version also keeps [BouncyCastle.libPkcsJdk15] on the `-jdk15on` + * artifacts. Revisit that pin when changing this version. */ const val version = "213.7172.53" diff --git a/buildSrc/src/main/kotlin/io/spine/dependency/lib/J2ObjC.kt b/buildSrc/src/main/kotlin/io/spine/dependency/lib/J2ObjC.kt index 3d7deab..cd08a3c 100644 --- a/buildSrc/src/main/kotlin/io/spine/dependency/lib/J2ObjC.kt +++ b/buildSrc/src/main/kotlin/io/spine/dependency/lib/J2ObjC.kt @@ -1,27 +1,15 @@ /* - * Copyright 2026, TeamDev. All rights reserved. + * Copyright 2026 CodeMatters, Lda. * - * 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 + * 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 * - * Redistribution and use in source and/or binary forms, with or without - * modification, must retain the above copyright notice and the following - * disclaimer. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 io.spine.dependency.lib diff --git a/buildSrc/src/main/kotlin/io/spine/dependency/lib/Jackson.kt b/buildSrc/src/main/kotlin/io/spine/dependency/lib/Jackson.kt index 9011fb8..9d1f071 100644 --- a/buildSrc/src/main/kotlin/io/spine/dependency/lib/Jackson.kt +++ b/buildSrc/src/main/kotlin/io/spine/dependency/lib/Jackson.kt @@ -1,27 +1,15 @@ /* - * Copyright 2026, TeamDev. All rights reserved. + * Copyright 2026 CodeMatters, Lda. * - * 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 + * 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 * - * Redistribution and use in source and/or binary forms, with or without - * modification, must retain the above copyright notice and the following - * disclaimer. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 io.spine.dependency.lib @@ -48,7 +36,7 @@ import io.spine.dependency.DependencyWithBom @Suppress("unused", "ConstPropertyName") object Jackson : DependencyWithBom() { override val group = "tools.jackson" - override val version = "3.2.2" + override val version = "3.2.3" /** * The version of `jackson-annotations`, which Jackson 3.x deliberately keeps @@ -72,15 +60,24 @@ object Jackson : DependencyWithBom() { // https://github.com/FasterXML/jackson-core val core = "$coreGroup:jackson-core" + /** Returns the coordinates of [core] with the [version]. */ + fun core(): String = artifact(core) + // https://github.com/FasterXML/jackson-databind val databind = "$coreGroup:jackson-databind" + /** Returns the coordinates of [databind] with the [version]. */ + fun databind(): String = artifact(databind) + // https://github.com/FasterXML/jackson-annotations val annotations = "com.fasterxml.jackson.core:jackson-annotations:$annotationsVersion" // https://github.com/FasterXML/jackson-module-kotlin/releases val moduleKotlin = "$moduleGroup:jackson-module-kotlin" + /** Returns the coordinates of [moduleKotlin] with the [version]. */ + fun moduleKotlin(): String = artifact(moduleKotlin) + @Deprecated( "The module was merged into `jackson-databind` in Jackson 3.0" + " and is no longer published.", @@ -104,12 +101,21 @@ object Jackson : DependencyWithBom() { // https://github.com/FasterXML/jackson-dataformat-xml/releases val xml = "$group:$infix-xml" + /** Returns the coordinates of [xml] with the [version]. */ + fun xml(): String = artifact(xml) + // https://github.com/FasterXML/jackson-dataformats-text/releases val yaml = "$group:$infix-yaml" + /** Returns the coordinates of [yaml] with the [version]. */ + fun yaml(): String = artifact(yaml) + // https://github.com/FasterXML/jackson-dataformats-binary/tree/3.x/protobuf val protobuf = "$group:$infix-protobuf" + /** Returns the coordinates of [protobuf] with the [version]. */ + fun protobuf(): String = artifact(protobuf) + val xmlArtifact = "$xml:$version" val yamlArtifact = "$yaml:$version" @@ -141,6 +147,9 @@ object Jackson : DependencyWithBom() { // https://github.com/FasterXML/jackson-datatypes-collections/tree/3.x/guava val guava = "$group:$infix-guava" + /** Returns the coordinates of [guava] with the [version]. */ + fun guava(): String = artifact(guava) + @Deprecated( "Protobuf support is a data format, not a data type." + " The `$infix-protobuf` artifact has never been published.", @@ -152,9 +161,15 @@ object Jackson : DependencyWithBom() { // https://github.com/FasterXML/jackson-datatypes-misc/tree/3.x/javax-money val javaXMoney = "$group:$infix-javax-money" + /** Returns the coordinates of [javaXMoney] with the [version]. */ + fun javaXMoney(): String = artifact(javaXMoney) + // https://github.com/FasterXML/jackson-datatypes-misc/tree/3.x/moneta val moneta = "$group:$infix-moneta" + /** Returns the coordinates of [moneta] with the [version]. */ + fun moneta(): String = artifact(moneta) + override val modules = listOf( guava, javaXMoney, diff --git a/buildSrc/src/main/kotlin/io/spine/dependency/lib/JacksonV2.kt b/buildSrc/src/main/kotlin/io/spine/dependency/lib/JacksonV2.kt index 0286a76..f79deac 100644 --- a/buildSrc/src/main/kotlin/io/spine/dependency/lib/JacksonV2.kt +++ b/buildSrc/src/main/kotlin/io/spine/dependency/lib/JacksonV2.kt @@ -1,27 +1,15 @@ /* - * Copyright 2026, TeamDev. All rights reserved. + * Copyright 2026 CodeMatters, Lda. * - * 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 + * 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 * - * Redistribution and use in source and/or binary forms, with or without - * modification, must retain the above copyright notice and the following - * disclaimer. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 io.spine.dependency.lib @@ -50,7 +38,7 @@ import io.spine.dependency.DependencyWithBom @Suppress("unused") object JacksonV2 : DependencyWithBom() { override val group = "com.fasterxml.jackson" - override val version = "2.22.2" + override val version = "2.22.3" // https://github.com/FasterXML/jackson-bom override val bom = "$group:jackson-bom:$version" @@ -69,8 +57,16 @@ object JacksonV2 : DependencyWithBom() { @Suppress("MemberNameEqualsClassName") val core = "$group:jackson-core" + + /** Returns the coordinates of [core] with the [version]. */ + @Suppress("MemberNameEqualsClassName") + fun core(): String = artifact(core) + val databind = "$group:jackson-databind" + /** Returns the coordinates of [databind] with the [version]. */ + fun databind(): String = artifact(databind) + override val modules = listOf(core, databind) } @@ -79,9 +75,20 @@ object JacksonV2 : DependencyWithBom() { override val group = "$groupPrefix.datatype" val jdk8 = "$group:jackson-datatype-jdk8" + + /** Returns the coordinates of [jdk8] with the [version]. */ + fun jdk8(): String = artifact(jdk8) + val jsr310 = "$group:jackson-datatype-jsr310" + + /** Returns the coordinates of [jsr310] with the [version]. */ + fun jsr310(): String = artifact(jsr310) + val guava = "$group:jackson-datatype-guava" + /** Returns the coordinates of [guava] with the [version]. */ + fun guava(): String = artifact(guava) + override val modules = listOf(jdk8, jsr310, guava) } @@ -90,9 +97,20 @@ object JacksonV2 : DependencyWithBom() { override val group = "$groupPrefix.dataformat" val xml = "$group:jackson-dataformat-xml" + + /** Returns the coordinates of [xml] with the [version]. */ + fun xml(): String = artifact(xml) + val yaml = "$group:jackson-dataformat-yaml" + + /** Returns the coordinates of [yaml] with the [version]. */ + fun yaml(): String = artifact(yaml) + val protobuf = "$group:jackson-dataformat-protobuf" + /** Returns the coordinates of [protobuf] with the [version]. */ + fun protobuf(): String = artifact(protobuf) + override val modules = listOf(xml, yaml, protobuf) } @@ -102,9 +120,15 @@ object JacksonV2 : DependencyWithBom() { val parameterNames = "$group:jackson-module-parameter-names" + /** Returns the coordinates of [parameterNames] with the [version]. */ + fun parameterNames(): String = artifact(parameterNames) + // https://github.com/FasterXML/jackson-module-kotlin/releases val kotlin = "$group:jackson-module-kotlin" + /** Returns the coordinates of [kotlin] with the [version]. */ + fun kotlin(): String = artifact(kotlin) + override val modules = listOf(parameterNames, kotlin) } diff --git a/buildSrc/src/main/kotlin/io/spine/dependency/lib/JavaDiffUtils.kt b/buildSrc/src/main/kotlin/io/spine/dependency/lib/JavaDiffUtils.kt index a332bc2..fb1a99b 100644 --- a/buildSrc/src/main/kotlin/io/spine/dependency/lib/JavaDiffUtils.kt +++ b/buildSrc/src/main/kotlin/io/spine/dependency/lib/JavaDiffUtils.kt @@ -1,27 +1,15 @@ /* - * Copyright 2026, TeamDev. All rights reserved. + * Copyright 2026 CodeMatters, Lda. * - * 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 + * 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 * - * Redistribution and use in source and/or binary forms, with or without - * modification, must retain the above copyright notice and the following - * disclaimer. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 io.spine.dependency.lib diff --git a/buildSrc/src/main/kotlin/io/spine/dependency/lib/JavaJwt.kt b/buildSrc/src/main/kotlin/io/spine/dependency/lib/JavaJwt.kt index dda755c..ee97191 100644 --- a/buildSrc/src/main/kotlin/io/spine/dependency/lib/JavaJwt.kt +++ b/buildSrc/src/main/kotlin/io/spine/dependency/lib/JavaJwt.kt @@ -1,27 +1,15 @@ /* - * Copyright 2026, TeamDev. All rights reserved. + * Copyright 2026 CodeMatters, Lda. * - * 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 + * 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 * - * Redistribution and use in source and/or binary forms, with or without - * modification, must retain the above copyright notice and the following - * disclaimer. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 io.spine.dependency.lib diff --git a/buildSrc/src/main/kotlin/io/spine/dependency/lib/JavaPoet.kt b/buildSrc/src/main/kotlin/io/spine/dependency/lib/JavaPoet.kt index 341e532..f33cf23 100644 --- a/buildSrc/src/main/kotlin/io/spine/dependency/lib/JavaPoet.kt +++ b/buildSrc/src/main/kotlin/io/spine/dependency/lib/JavaPoet.kt @@ -1,27 +1,15 @@ /* - * Copyright 2026, TeamDev. All rights reserved. + * Copyright 2026 CodeMatters, Lda. * - * 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 + * 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 * - * Redistribution and use in source and/or binary forms, with or without - * modification, must retain the above copyright notice and the following - * disclaimer. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 io.spine.dependency.lib diff --git a/buildSrc/src/main/kotlin/io/spine/dependency/lib/JavaX.kt b/buildSrc/src/main/kotlin/io/spine/dependency/lib/JavaX.kt index d0b2a47..517b076 100644 --- a/buildSrc/src/main/kotlin/io/spine/dependency/lib/JavaX.kt +++ b/buildSrc/src/main/kotlin/io/spine/dependency/lib/JavaX.kt @@ -1,27 +1,15 @@ /* - * Copyright 2026, TeamDev. All rights reserved. + * Copyright 2026 CodeMatters, Lda. * - * 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 + * 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 * - * Redistribution and use in source and/or binary forms, with or without - * modification, must retain the above copyright notice and the following - * disclaimer. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 io.spine.dependency.lib @@ -33,5 +21,5 @@ object JavaX { const val annotationGroup = "javax.annotation" const val annotations = "$annotationGroup:javax.annotation-api:1.3.2" - const val servletApi = "javax.servlet:javax.servlet-api:3.1.0" + const val servletApi = "javax.servlet:javax.servlet-api:4.0.1" } diff --git a/buildSrc/src/main/kotlin/io/spine/dependency/lib/JetBrainsAnnotations.kt b/buildSrc/src/main/kotlin/io/spine/dependency/lib/JetBrainsAnnotations.kt index 14cac48..3c6de7d 100644 --- a/buildSrc/src/main/kotlin/io/spine/dependency/lib/JetBrainsAnnotations.kt +++ b/buildSrc/src/main/kotlin/io/spine/dependency/lib/JetBrainsAnnotations.kt @@ -1,27 +1,15 @@ /* - * Copyright 2026, TeamDev. All rights reserved. + * Copyright 2026 CodeMatters, Lda. * - * 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 + * 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 * - * Redistribution and use in source and/or binary forms, with or without - * modification, must retain the above copyright notice and the following - * disclaimer. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 io.spine.dependency.lib diff --git a/buildSrc/src/main/kotlin/io/spine/dependency/lib/Klaxon.kt b/buildSrc/src/main/kotlin/io/spine/dependency/lib/Klaxon.kt index 36999cc..4199bce 100644 --- a/buildSrc/src/main/kotlin/io/spine/dependency/lib/Klaxon.kt +++ b/buildSrc/src/main/kotlin/io/spine/dependency/lib/Klaxon.kt @@ -1,27 +1,15 @@ /* - * Copyright 2026, TeamDev. All rights reserved. + * Copyright 2026 CodeMatters, Lda. * - * 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 + * 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 * - * Redistribution and use in source and/or binary forms, with or without - * modification, must retain the above copyright notice and the following - * disclaimer. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 io.spine.dependency.lib diff --git a/buildSrc/src/main/kotlin/io/spine/dependency/lib/Kotlin.kt b/buildSrc/src/main/kotlin/io/spine/dependency/lib/Kotlin.kt index 661af94..4b49e3a 100644 --- a/buildSrc/src/main/kotlin/io/spine/dependency/lib/Kotlin.kt +++ b/buildSrc/src/main/kotlin/io/spine/dependency/lib/Kotlin.kt @@ -1,27 +1,15 @@ /* - * Copyright 2026, TeamDev. All rights reserved. + * Copyright 2026 CodeMatters, Lda. * - * 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 + * 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 * - * Redistribution and use in source and/or binary forms, with or without - * modification, must retain the above copyright notice and the following - * disclaimer. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 io.spine.dependency.lib @@ -38,7 +26,7 @@ object Kotlin : DependencyWithBom() { * This is the version of Kotlin we use for writing code that does not depend on Gradle. */ @Suppress("MemberVisibilityCanBePrivate") // used directly from the outside. - const val runtimeVersion = "2.4.10" + const val runtimeVersion = "2.4.21" override val version = runtimeVersion override val group = "org.jetbrains.kotlin" @@ -55,7 +43,7 @@ object Kotlin : DependencyWithBom() { * [embedded into Gradle](https://docs.gradle.org/current/userguide/compatibility.html#kotlin), * which the Gradle version determines on its own. */ - const val embeddedVersion = "2.4.10" + const val embeddedVersion = "2.4.21" /** * The version of the JetBrains annotations library, which is a transitive @@ -121,6 +109,10 @@ object Kotlin : DependencyWithBom() { val lib = "$group:kotlin-gradle-plugin:$version" val model = "$group:kotlin-gradle-model:$version" - override val modules = listOf(api, lib, model) + /** + * The coordinates of [api], [lib], and [model] without the version, + * which [artifacts] appends to each of them. + */ + override val modules = listOf(api, lib, model).map { it.substringBeforeLast(':') } } } diff --git a/buildSrc/src/main/kotlin/io/spine/dependency/lib/KotlinPoet.kt b/buildSrc/src/main/kotlin/io/spine/dependency/lib/KotlinPoet.kt index e5f8e0b..c7fcf35 100644 --- a/buildSrc/src/main/kotlin/io/spine/dependency/lib/KotlinPoet.kt +++ b/buildSrc/src/main/kotlin/io/spine/dependency/lib/KotlinPoet.kt @@ -1,27 +1,15 @@ /* - * Copyright 2026, TeamDev. All rights reserved. + * Copyright 2026 CodeMatters, Lda. * - * 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 + * 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 * - * Redistribution and use in source and/or binary forms, with or without - * modification, must retain the above copyright notice and the following - * disclaimer. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 io.spine.dependency.lib @@ -29,7 +17,7 @@ package io.spine.dependency.lib // https://github.com/square/kotlinpoet @Suppress("unused", "ConstPropertyName") object KotlinPoet { - private const val version = "2.3.0" + private const val version = "2.4.0" const val lib = "com.squareup:kotlinpoet:$version" const val ksp = "com.squareup:kotlinpoet-ksp:$version" } diff --git a/buildSrc/src/main/kotlin/io/spine/dependency/lib/KotlinSemver.kt b/buildSrc/src/main/kotlin/io/spine/dependency/lib/KotlinSemver.kt index 3964312..f5658a7 100644 --- a/buildSrc/src/main/kotlin/io/spine/dependency/lib/KotlinSemver.kt +++ b/buildSrc/src/main/kotlin/io/spine/dependency/lib/KotlinSemver.kt @@ -1,27 +1,15 @@ /* - * Copyright 2026, TeamDev. All rights reserved. + * Copyright 2026 CodeMatters, Lda. * - * 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 + * 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 * - * Redistribution and use in source and/or binary forms, with or without - * modification, must retain the above copyright notice and the following - * disclaimer. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 io.spine.dependency.lib diff --git a/buildSrc/src/main/kotlin/io/spine/dependency/lib/KotlinX.kt b/buildSrc/src/main/kotlin/io/spine/dependency/lib/KotlinX.kt index 8020436..77f10dc 100644 --- a/buildSrc/src/main/kotlin/io/spine/dependency/lib/KotlinX.kt +++ b/buildSrc/src/main/kotlin/io/spine/dependency/lib/KotlinX.kt @@ -1,27 +1,15 @@ /* - * Copyright 2026, TeamDev. All rights reserved. + * Copyright 2026 CodeMatters, Lda. * - * 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 + * 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 * - * Redistribution and use in source and/or binary forms, with or without - * modification, must retain the above copyright notice and the following - * disclaimer. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 io.spine.dependency.lib diff --git a/buildSrc/src/main/kotlin/io/spine/dependency/lib/Log4j2.kt b/buildSrc/src/main/kotlin/io/spine/dependency/lib/Log4j2.kt index 30b3dad..f36f5cb 100644 --- a/buildSrc/src/main/kotlin/io/spine/dependency/lib/Log4j2.kt +++ b/buildSrc/src/main/kotlin/io/spine/dependency/lib/Log4j2.kt @@ -1,27 +1,15 @@ /* - * Copyright 2026, TeamDev. All rights reserved. + * Copyright 2026 CodeMatters, Lda. * - * 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 + * 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 * - * Redistribution and use in source and/or binary forms, with or without - * modification, must retain the above copyright notice and the following - * disclaimer. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 io.spine.dependency.lib diff --git a/buildSrc/src/main/kotlin/io/spine/dependency/lib/Netty.kt b/buildSrc/src/main/kotlin/io/spine/dependency/lib/Netty.kt index d56e559..53f6b40 100644 --- a/buildSrc/src/main/kotlin/io/spine/dependency/lib/Netty.kt +++ b/buildSrc/src/main/kotlin/io/spine/dependency/lib/Netty.kt @@ -1,27 +1,15 @@ /* - * Copyright 2026, TeamDev. All rights reserved. + * Copyright 2026 CodeMatters, Lda. * - * 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 + * 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 * - * Redistribution and use in source and/or binary forms, with or without - * modification, must retain the above copyright notice and the following - * disclaimer. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 io.spine.dependency.lib @@ -29,7 +17,7 @@ package io.spine.dependency.lib @Suppress("unused", "ConstPropertyName") object Netty { // https://github.com/netty/netty/tags - private const val version = "4.2.17.Final" + private const val version = "4.2.19.Final" const val common = "io.netty:netty-common:$version" const val buffer = "io.netty:netty-buffer:$version" const val transport = "io.netty:netty-transport:$version" diff --git a/buildSrc/src/main/kotlin/io/spine/dependency/lib/Okio.kt b/buildSrc/src/main/kotlin/io/spine/dependency/lib/Okio.kt index 380b564..1487b5d 100644 --- a/buildSrc/src/main/kotlin/io/spine/dependency/lib/Okio.kt +++ b/buildSrc/src/main/kotlin/io/spine/dependency/lib/Okio.kt @@ -1,27 +1,15 @@ /* - * Copyright 2026, TeamDev. All rights reserved. + * Copyright 2026 CodeMatters, Lda. * - * 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 + * 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 * - * Redistribution and use in source and/or binary forms, with or without - * modification, must retain the above copyright notice and the following - * disclaimer. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 io.spine.dependency.lib @@ -33,6 +21,6 @@ package io.spine.dependency.lib */ @Suppress("unused", "ConstPropertyName") object Okio { - private const val version = "3.18.1" + private const val version = "3.18.2" const val lib = "com.squareup.okio:okio:$version" } diff --git a/buildSrc/src/main/kotlin/io/spine/dependency/lib/PalantirJavaFormat.kt b/buildSrc/src/main/kotlin/io/spine/dependency/lib/PalantirJavaFormat.kt index b8ec0f9..12e4630 100644 --- a/buildSrc/src/main/kotlin/io/spine/dependency/lib/PalantirJavaFormat.kt +++ b/buildSrc/src/main/kotlin/io/spine/dependency/lib/PalantirJavaFormat.kt @@ -1,27 +1,15 @@ /* - * Copyright 2026, TeamDev. All rights reserved. + * Copyright 2026 CodeMatters, Lda. * - * 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 + * 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 * - * Redistribution and use in source and/or binary forms, with or without - * modification, must retain the above copyright notice and the following - * disclaimer. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 io.spine.dependency.lib @@ -36,7 +24,7 @@ import io.spine.dependency.Dependency object PalantirJavaFormat : Dependency() { override val group = "com.palantir.javaformat" - override val version = "2.97.0" + override val version = "2.102.0" override val modules: List = listOf("$group:palantir-java-format") val lib = artifact(modules[0]) diff --git a/buildSrc/src/main/kotlin/io/spine/dependency/lib/PerfMark.kt b/buildSrc/src/main/kotlin/io/spine/dependency/lib/PerfMark.kt index 9a156c3..32efc33 100644 --- a/buildSrc/src/main/kotlin/io/spine/dependency/lib/PerfMark.kt +++ b/buildSrc/src/main/kotlin/io/spine/dependency/lib/PerfMark.kt @@ -1,27 +1,15 @@ /* - * Copyright 2026, TeamDev. All rights reserved. + * Copyright 2026 CodeMatters, Lda. * - * 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 + * 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 * - * Redistribution and use in source and/or binary forms, with or without - * modification, must retain the above copyright notice and the following - * disclaimer. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 io.spine.dependency.lib diff --git a/buildSrc/src/main/kotlin/io/spine/dependency/lib/Plexus.kt b/buildSrc/src/main/kotlin/io/spine/dependency/lib/Plexus.kt index 2ed4fb2..40f7c2a 100644 --- a/buildSrc/src/main/kotlin/io/spine/dependency/lib/Plexus.kt +++ b/buildSrc/src/main/kotlin/io/spine/dependency/lib/Plexus.kt @@ -1,27 +1,15 @@ /* - * Copyright 2026, TeamDev. All rights reserved. + * Copyright 2026 CodeMatters, Lda. * - * 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 + * 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 * - * Redistribution and use in source and/or binary forms, with or without - * modification, must retain the above copyright notice and the following - * disclaimer. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. */ @file:Suppress("MaxLineLength") @@ -39,7 +27,7 @@ object Plexus { /** * The version from the 4.x series. * - * @see plexus-utils-4.0.0 + * @see Releases */ private const val version = "4.1.0" const val utils = "org.codehaus.plexus:plexus-utils:$version" diff --git a/buildSrc/src/main/kotlin/io/spine/dependency/lib/Protobuf.kt b/buildSrc/src/main/kotlin/io/spine/dependency/lib/Protobuf.kt index 5548001..9478184 100644 --- a/buildSrc/src/main/kotlin/io/spine/dependency/lib/Protobuf.kt +++ b/buildSrc/src/main/kotlin/io/spine/dependency/lib/Protobuf.kt @@ -1,27 +1,15 @@ /* - * Copyright 2026, TeamDev. All rights reserved. + * Copyright 2026 CodeMatters, Lda. * - * 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 + * 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 * - * Redistribution and use in source and/or binary forms, with or without - * modification, must retain the above copyright notice and the following - * disclaimer. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 io.spine.dependency.lib @@ -33,13 +21,23 @@ package io.spine.dependency.lib ) object Protobuf { const val group = "com.google.protobuf" - const val version = "4.36.0" + const val version = "4.36.2" /** * The Java library with Protobuf data types. */ const val javaLib = "$group:protobuf-java:$version" + /** + * The Java library with utilities for Protobuf messages, such as `JsonFormat`. + */ + const val javaUtil = "$group:protobuf-java-util:$version" + + /** + * The Kotlin library with extensions for Protobuf messages. + */ + const val kotlin = "$group:protobuf-kotlin:$version" + /** * The Java library containing proto definitions of Google Protobuf types. */ @@ -51,8 +49,8 @@ object Protobuf { */ val libs = listOf( javaLib, - "$group:protobuf-java-util:$version", - "$group:protobuf-kotlin:$version" + javaUtil, + kotlin ) const val compiler = "$group:protoc:$version" diff --git a/buildSrc/src/main/kotlin/io/spine/dependency/lib/Roaster.kt b/buildSrc/src/main/kotlin/io/spine/dependency/lib/Roaster.kt index 2970e3c..3faa5ca 100644 --- a/buildSrc/src/main/kotlin/io/spine/dependency/lib/Roaster.kt +++ b/buildSrc/src/main/kotlin/io/spine/dependency/lib/Roaster.kt @@ -1,27 +1,15 @@ /* - * Copyright 2026, TeamDev. All rights reserved. + * Copyright 2026 CodeMatters, Lda. * - * 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 + * 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 * - * Redistribution and use in source and/or binary forms, with or without - * modification, must retain the above copyright notice and the following - * disclaimer. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 io.spine.dependency.lib diff --git a/buildSrc/src/main/kotlin/io/spine/dependency/lib/Slf4J.kt b/buildSrc/src/main/kotlin/io/spine/dependency/lib/Slf4J.kt index 34b15ac..c3478a5 100644 --- a/buildSrc/src/main/kotlin/io/spine/dependency/lib/Slf4J.kt +++ b/buildSrc/src/main/kotlin/io/spine/dependency/lib/Slf4J.kt @@ -1,27 +1,15 @@ /* - * Copyright 2026, TeamDev. All rights reserved. + * Copyright 2026 CodeMatters, Lda. * - * 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 + * 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 * - * Redistribution and use in source and/or binary forms, with or without - * modification, must retain the above copyright notice and the following - * disclaimer. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 io.spine.dependency.lib @@ -40,7 +28,7 @@ package io.spine.dependency.lib // https://search.maven.org/artifact/org.slf4j/slf4j-api @Suppress("unused", "ConstPropertyName") object Slf4J { - private const val version = "2.0.18" + private const val version = "2.0.20" const val lib = "org.slf4j:slf4j-api:$version" const val jdk14 = "org.slf4j:slf4j-jdk14:$version" const val reload4j = "org.slf4j:slf4j-reload4j:$version" diff --git a/buildSrc/src/main/kotlin/io/spine/dependency/local/Base.kt b/buildSrc/src/main/kotlin/io/spine/dependency/local/Base.kt index 5ec5cc2..aa06886 100644 --- a/buildSrc/src/main/kotlin/io/spine/dependency/local/Base.kt +++ b/buildSrc/src/main/kotlin/io/spine/dependency/local/Base.kt @@ -1,27 +1,15 @@ /* - * Copyright 2026, TeamDev. All rights reserved. + * Copyright 2026 CodeMatters, Lda. * - * 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 + * 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 * - * Redistribution and use in source and/or binary forms, with or without - * modification, must retain the above copyright notice and the following - * disclaimer. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 io.spine.dependency.local @@ -33,8 +21,8 @@ package io.spine.dependency.local */ @Suppress("ConstPropertyName", "unused") object Base { - const val version = "2.0.0-SNAPSHOT.442" - const val versionForBuildScript = "2.0.0-SNAPSHOT.441" + const val version = "2.0.0-SNAPSHOT.460" + const val versionForBuildScript = "2.0.0-SNAPSHOT.460" const val group = Spine.group private const val prefix = "spine" const val libModule = "$prefix-base" diff --git a/buildSrc/src/main/kotlin/io/spine/dependency/local/BaseTypes.kt b/buildSrc/src/main/kotlin/io/spine/dependency/local/BaseTypes.kt index f765df8..70fe77b 100644 --- a/buildSrc/src/main/kotlin/io/spine/dependency/local/BaseTypes.kt +++ b/buildSrc/src/main/kotlin/io/spine/dependency/local/BaseTypes.kt @@ -1,27 +1,15 @@ /* - * Copyright 2026, TeamDev. All rights reserved. + * Copyright 2026 CodeMatters, Lda. * - * 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 + * 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 * - * Redistribution and use in source and/or binary forms, with or without - * modification, must retain the above copyright notice and the following - * disclaimer. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 io.spine.dependency.local @@ -33,7 +21,7 @@ package io.spine.dependency.local */ @Suppress("ConstPropertyName") object BaseTypes { - const val version = "2.0.0-SNAPSHOT.224" + const val version = "2.0.0-SNAPSHOT.225" const val group = Spine.group const val artifact = "spine-base-types" const val lib = "$group:$artifact:$version" diff --git a/buildSrc/src/main/kotlin/io/spine/dependency/local/Change.kt b/buildSrc/src/main/kotlin/io/spine/dependency/local/Change.kt index 7c09493..228f96e 100644 --- a/buildSrc/src/main/kotlin/io/spine/dependency/local/Change.kt +++ b/buildSrc/src/main/kotlin/io/spine/dependency/local/Change.kt @@ -1,27 +1,15 @@ /* - * Copyright 2026, TeamDev. All rights reserved. + * Copyright 2026 CodeMatters, Lda. * - * 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 + * 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 * - * Redistribution and use in source and/or binary forms, with or without - * modification, must retain the above copyright notice and the following - * disclaimer. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 io.spine.dependency.local @@ -33,7 +21,7 @@ package io.spine.dependency.local */ @Suppress("ConstPropertyName") object Change { - const val version = "2.0.0-SNAPSHOT.207" + const val version = "2.0.0-SNAPSHOT.208" const val group = Spine.group const val artifact = "spine-change" const val lib = "$group:$artifact:$version" diff --git a/buildSrc/src/main/kotlin/io/spine/dependency/local/Compiler.kt b/buildSrc/src/main/kotlin/io/spine/dependency/local/Compiler.kt index 64673a9..137e830 100644 --- a/buildSrc/src/main/kotlin/io/spine/dependency/local/Compiler.kt +++ b/buildSrc/src/main/kotlin/io/spine/dependency/local/Compiler.kt @@ -1,27 +1,15 @@ /* - * Copyright 2026, TeamDev. All rights reserved. + * Copyright 2026 CodeMatters, Lda. * - * 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 + * 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 * - * Redistribution and use in source and/or binary forms, with or without - * modification, must retain the above copyright notice and the following - * disclaimer. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 io.spine.dependency.local @@ -72,7 +60,7 @@ object Compiler : Dependency() { * The version of the Compiler dependencies. */ override val version: String - private const val fallbackVersion = "2.0.0-SNAPSHOT.067" + private const val fallbackVersion = "2.0.0-SNAPSHOT.069" /** * The distinct version of the Compiler used by other build tools. @@ -81,7 +69,7 @@ object Compiler : Dependency() { * transitive dependencies, this is the version used to build the project itself. */ val dogfoodingVersion: String - private const val fallbackDfVersion = "2.0.0-SNAPSHOT.067" + private const val fallbackDfVersion = "2.0.0-SNAPSHOT.069" /** * The artifact for the Compiler Gradle plugin. diff --git a/buildSrc/src/main/kotlin/io/spine/dependency/local/CoreJvm.kt b/buildSrc/src/main/kotlin/io/spine/dependency/local/CoreJvm.kt index 1186453..bef7362 100644 --- a/buildSrc/src/main/kotlin/io/spine/dependency/local/CoreJvm.kt +++ b/buildSrc/src/main/kotlin/io/spine/dependency/local/CoreJvm.kt @@ -1,27 +1,15 @@ /* - * Copyright 2026, TeamDev. All rights reserved. + * Copyright 2026 CodeMatters, Lda. * - * 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 + * 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 * - * Redistribution and use in source and/or binary forms, with or without - * modification, must retain the above copyright notice and the following - * disclaimer. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 io.spine.dependency.local @@ -39,7 +27,7 @@ typealias CoreJava = CoreJvm @Suppress("ConstPropertyName", "unused") object CoreJvm { const val group = Spine.group - const val version = "2.0.0-SNAPSHOT.550" + const val version = "2.0.0-SNAPSHOT.567" const val coreArtifact = "spine-core" const val clientArtifact = "spine-client" diff --git a/buildSrc/src/main/kotlin/io/spine/dependency/local/CoreJvmCompiler.kt b/buildSrc/src/main/kotlin/io/spine/dependency/local/CoreJvmCompiler.kt index 46807c3..5db1a81 100644 --- a/buildSrc/src/main/kotlin/io/spine/dependency/local/CoreJvmCompiler.kt +++ b/buildSrc/src/main/kotlin/io/spine/dependency/local/CoreJvmCompiler.kt @@ -1,27 +1,15 @@ /* - * Copyright 2026, TeamDev. All rights reserved. + * Copyright 2026 CodeMatters, Lda. * - * 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 + * 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 * - * Redistribution and use in source and/or binary forms, with or without - * modification, must retain the above copyright notice and the following - * disclaimer. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 io.spine.dependency.local @@ -46,12 +34,12 @@ object CoreJvmCompiler { /** * The version used in the build classpath. */ - const val dogfoodingVersion = "2.0.0-SNAPSHOT.091" + const val dogfoodingVersion = "2.0.0-SNAPSHOT.097" /** * The version to be used for integration tests. */ - const val version = "2.0.0-SNAPSHOT.091" + const val version = "2.0.0-SNAPSHOT.097" /** * The ID of the Gradle plugin. diff --git a/buildSrc/src/main/kotlin/io/spine/dependency/local/DokkaTools.kt b/buildSrc/src/main/kotlin/io/spine/dependency/local/DokkaTools.kt new file mode 100644 index 0000000..5a64607 --- /dev/null +++ b/buildSrc/src/main/kotlin/io/spine/dependency/local/DokkaTools.kt @@ -0,0 +1,37 @@ +/* + * Copyright 2026 CodeMatters, Lda. + * + * 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 io.spine.dependency.local + +/** + * Custom Dokka plugins developed for Spine-specific needs like excluding by + * `@Internal` annotation. + * + * See [`SpineEventEngine/dokka-tools`](https://github.com/SpineEventEngine/dokka-tools/). + */ +@Suppress( + "unused" /* Some subprojects do not use the Dokka tools directly. */, + "ConstPropertyName" /* We use a custom convention for artifact properties. */, +) +object DokkaTools { + const val group = Spine.toolsGroup + const val version = "2.0.0-SNAPSHOT.10" + + /** + * The artifact dropped its `spine-` prefix in `2.0.0-SNAPSHOT.9`, to + * match the other tool artifacts. Earlier versions are published as + * `spine-dokka-extensions`. + */ + const val extensions = "$group:dokka-extensions:$version" +} diff --git a/buildSrc/src/main/kotlin/io/spine/dependency/local/Logging.kt b/buildSrc/src/main/kotlin/io/spine/dependency/local/Logging.kt index 182d713..e5be8ed 100644 --- a/buildSrc/src/main/kotlin/io/spine/dependency/local/Logging.kt +++ b/buildSrc/src/main/kotlin/io/spine/dependency/local/Logging.kt @@ -1,27 +1,15 @@ /* - * Copyright 2026, TeamDev. All rights reserved. + * Copyright 2026 CodeMatters, Lda. * - * 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 + * 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 * - * Redistribution and use in source and/or binary forms, with or without - * modification, must retain the above copyright notice and the following - * disclaimer. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 io.spine.dependency.local @@ -33,7 +21,7 @@ package io.spine.dependency.local */ @Suppress("ConstPropertyName", "unused") object Logging { - const val version = "2.0.0-SNAPSHOT.424" + const val version = "2.0.0-SNAPSHOT.425" const val group = Spine.group const val loggingArtifact = "spine-logging" diff --git a/buildSrc/src/main/kotlin/io/spine/dependency/local/ProtoTap.kt b/buildSrc/src/main/kotlin/io/spine/dependency/local/ProtoTap.kt index bc7de57..45e6792 100644 --- a/buildSrc/src/main/kotlin/io/spine/dependency/local/ProtoTap.kt +++ b/buildSrc/src/main/kotlin/io/spine/dependency/local/ProtoTap.kt @@ -1,27 +1,15 @@ /* - * Copyright 2026, TeamDev. All rights reserved. + * Copyright 2026 CodeMatters, Lda. * - * 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 + * 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 * - * Redistribution and use in source and/or binary forms, with or without - * modification, must retain the above copyright notice and the following - * disclaimer. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 io.spine.dependency.local @@ -38,7 +26,7 @@ package io.spine.dependency.local ) object ProtoTap { const val group = Spine.toolsGroup - const val version = "0.17.0" + const val version = "0.17.2" const val gradlePluginId = "io.spine.prototap" const val api = "$group:prototap-api:$version" const val gradlePlugin = "$group:prototap-gradle-plugin:$version" diff --git a/buildSrc/src/main/kotlin/io/spine/dependency/local/Reflect.kt b/buildSrc/src/main/kotlin/io/spine/dependency/local/Reflect.kt index 6980e2e..ae8e17f 100644 --- a/buildSrc/src/main/kotlin/io/spine/dependency/local/Reflect.kt +++ b/buildSrc/src/main/kotlin/io/spine/dependency/local/Reflect.kt @@ -1,27 +1,15 @@ /* - * Copyright 2026, TeamDev. All rights reserved. + * Copyright 2026 CodeMatters, Lda. * - * 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 + * 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 * - * Redistribution and use in source and/or binary forms, with or without - * modification, must retain the above copyright notice and the following - * disclaimer. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 io.spine.dependency.local @@ -33,7 +21,7 @@ package io.spine.dependency.local */ @Suppress("ConstPropertyName") object Reflect { - const val version = "2.0.0-SNAPSHOT.200" + const val version = "2.0.0-SNAPSHOT.201" const val group = Spine.group const val artifact = "spine-reflect" const val lib = "$group:$artifact:$version" diff --git a/buildSrc/src/main/kotlin/io/spine/dependency/local/Spine.kt b/buildSrc/src/main/kotlin/io/spine/dependency/local/Spine.kt index e7b96d6..6efbf78 100644 --- a/buildSrc/src/main/kotlin/io/spine/dependency/local/Spine.kt +++ b/buildSrc/src/main/kotlin/io/spine/dependency/local/Spine.kt @@ -1,27 +1,15 @@ /* - * Copyright 2026, TeamDev. All rights reserved. + * Copyright 2026 CodeMatters, Lda. * - * 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 + * 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 * - * Redistribution and use in source and/or binary forms, with or without - * modification, must retain the above copyright notice and the following - * disclaimer. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 io.spine.dependency.local diff --git a/buildSrc/src/main/kotlin/io/spine/dependency/local/TestLib.kt b/buildSrc/src/main/kotlin/io/spine/dependency/local/TestLib.kt index c4667d1..bf26e25 100644 --- a/buildSrc/src/main/kotlin/io/spine/dependency/local/TestLib.kt +++ b/buildSrc/src/main/kotlin/io/spine/dependency/local/TestLib.kt @@ -1,27 +1,15 @@ /* - * Copyright 2026, TeamDev. All rights reserved. + * Copyright 2026 CodeMatters, Lda. * - * 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 + * 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 * - * Redistribution and use in source and/or binary forms, with or without - * modification, must retain the above copyright notice and the following - * disclaimer. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 io.spine.dependency.local @@ -33,7 +21,7 @@ package io.spine.dependency.local */ @Suppress("ConstPropertyName") object TestLib { - const val version = "2.0.0-SNAPSHOT.213" + const val version = "2.0.0-SNAPSHOT.214" const val group = Spine.toolsGroup const val artifact = "base-testlib" const val lib = "$group:$artifact:$version" diff --git a/buildSrc/src/main/kotlin/io/spine/dependency/local/Time.kt b/buildSrc/src/main/kotlin/io/spine/dependency/local/Time.kt index 3b4fd0b..942333f 100644 --- a/buildSrc/src/main/kotlin/io/spine/dependency/local/Time.kt +++ b/buildSrc/src/main/kotlin/io/spine/dependency/local/Time.kt @@ -1,27 +1,15 @@ /* - * Copyright 2026, TeamDev. All rights reserved. + * Copyright 2026 CodeMatters, Lda. * - * 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 + * 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 * - * Redistribution and use in source and/or binary forms, with or without - * modification, must retain the above copyright notice and the following - * disclaimer. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 io.spine.dependency.local @@ -40,7 +28,7 @@ import io.spine.dependency.Dependency ) object Time : Dependency() { override val group = Spine.group - override val version = "2.0.0-SNAPSHOT.250" + override val version = "2.0.0-SNAPSHOT.251" private const val infix = "spine-time" fun lib(version: String): String = "$group:$infix:$version" diff --git a/buildSrc/src/main/kotlin/io/spine/dependency/local/ToolBase.kt b/buildSrc/src/main/kotlin/io/spine/dependency/local/ToolBase.kt index d8b00da..63ecfca 100644 --- a/buildSrc/src/main/kotlin/io/spine/dependency/local/ToolBase.kt +++ b/buildSrc/src/main/kotlin/io/spine/dependency/local/ToolBase.kt @@ -1,27 +1,15 @@ /* - * Copyright 2026, TeamDev. All rights reserved. + * Copyright 2026 CodeMatters, Lda. * - * 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 + * 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 * - * Redistribution and use in source and/or binary forms, with or without - * modification, must retain the above copyright notice and the following - * disclaimer. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 io.spine.dependency.local @@ -30,28 +18,19 @@ package io.spine.dependency.local * Artifacts of the `tool-base` repository. * * The repository no longer publishes a module of its own name. Its former - * contents are split across the focused modules declared below. + * contents are split across the focused modules declared below. The all-in-one + * `tool-base` artifact is no longer published as of `2.0.0-SNAPSHOT.420`. + * + * `io.spine.tools.OsFamily`, which that module also carried, now lives in + * Base Libraries as `io.spine.environment.OsFamily`. * * @see tool-base */ @Suppress("ConstPropertyName", "unused") object ToolBase { const val group = Spine.toolsGroup - const val version = "2.0.0-SNAPSHOT.421" - const val dogfoodingVersion = "2.0.0-SNAPSHOT.421" - - /** - * The former all-in-one module, split into the focused modules below. - * - * The artifact is no longer published as of `2.0.0-SNAPSHOT.420`. Replace it - * with the modules a project actually uses: [archive], [code], [fs], - * [javaCode], [kotlinCode], or [protoCode]. - * - * `io.spine.tools.OsFamily`, which this module also carried, now lives in - * Base Libraries as `io.spine.environment.OsFamily`. - */ - @Deprecated("The `tool-base` artifact is no longer published. Use the module you need.") - const val lib = "$group:tool-base:$version" + const val version = "2.0.0-SNAPSHOT.425" + const val dogfoodingVersion = "2.0.0-SNAPSHOT.425" const val archive = "$group:archive:$version" const val code = "$group:code:$version" diff --git a/buildSrc/src/main/kotlin/io/spine/dependency/local/Validation.kt b/buildSrc/src/main/kotlin/io/spine/dependency/local/Validation.kt index fdd0e11..b1069ce 100644 --- a/buildSrc/src/main/kotlin/io/spine/dependency/local/Validation.kt +++ b/buildSrc/src/main/kotlin/io/spine/dependency/local/Validation.kt @@ -1,27 +1,15 @@ /* - * Copyright 2026, TeamDev. All rights reserved. + * Copyright 2026 CodeMatters, Lda. * - * 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 + * 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 * - * Redistribution and use in source and/or binary forms, with or without - * modification, must retain the above copyright notice and the following - * disclaimer. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 io.spine.dependency.local @@ -36,7 +24,7 @@ object Validation { /** * The version of the Validation library artifacts. */ - const val version = "2.0.0-SNAPSHOT.463" + const val version = "2.0.0-SNAPSHOT.464" const val group = Spine.toolsGroup private const val prefix = "validation" diff --git a/buildSrc/src/main/kotlin/io/spine/dependency/storage/H2.kt b/buildSrc/src/main/kotlin/io/spine/dependency/storage/H2.kt index 5232e63..a7e81ff 100644 --- a/buildSrc/src/main/kotlin/io/spine/dependency/storage/H2.kt +++ b/buildSrc/src/main/kotlin/io/spine/dependency/storage/H2.kt @@ -1,27 +1,15 @@ /* - * Copyright 2026, TeamDev. All rights reserved. + * Copyright 2026 CodeMatters, Lda. * - * 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 + * 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 * - * Redistribution and use in source and/or binary forms, with or without - * modification, must retain the above copyright notice and the following - * disclaimer. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 io.spine.dependency.storage @@ -35,6 +23,6 @@ package io.spine.dependency.storage */ @Suppress("unused", "ConstPropertyName") object H2 { - private const val version = "2.4.240" + private const val version = "2.5.252" const val lib = "com.h2database:h2:$version" } diff --git a/buildSrc/src/main/kotlin/io/spine/dependency/storage/Hikari.kt b/buildSrc/src/main/kotlin/io/spine/dependency/storage/Hikari.kt index 5ab609e..f64ebf3 100644 --- a/buildSrc/src/main/kotlin/io/spine/dependency/storage/Hikari.kt +++ b/buildSrc/src/main/kotlin/io/spine/dependency/storage/Hikari.kt @@ -1,27 +1,15 @@ /* - * Copyright 2026, TeamDev. All rights reserved. + * Copyright 2026 CodeMatters, Lda. * - * 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 + * 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 * - * Redistribution and use in source and/or binary forms, with or without - * modification, must retain the above copyright notice and the following - * disclaimer. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 io.spine.dependency.storage diff --git a/buildSrc/src/main/kotlin/io/spine/dependency/storage/HsqlDb.kt b/buildSrc/src/main/kotlin/io/spine/dependency/storage/HsqlDb.kt index 3a6b509..fe0ea94 100644 --- a/buildSrc/src/main/kotlin/io/spine/dependency/storage/HsqlDb.kt +++ b/buildSrc/src/main/kotlin/io/spine/dependency/storage/HsqlDb.kt @@ -1,27 +1,15 @@ /* - * Copyright 2026, TeamDev. All rights reserved. + * Copyright 2026 CodeMatters, Lda. * - * 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 + * 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 * - * Redistribution and use in source and/or binary forms, with or without - * modification, must retain the above copyright notice and the following - * disclaimer. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 io.spine.dependency.storage diff --git a/buildSrc/src/main/kotlin/io/spine/dependency/storage/MySql.kt b/buildSrc/src/main/kotlin/io/spine/dependency/storage/MySql.kt index f7eb5ed..a120d03 100644 --- a/buildSrc/src/main/kotlin/io/spine/dependency/storage/MySql.kt +++ b/buildSrc/src/main/kotlin/io/spine/dependency/storage/MySql.kt @@ -1,27 +1,15 @@ /* - * Copyright 2026, TeamDev. All rights reserved. + * Copyright 2026 CodeMatters, Lda. * - * 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 + * 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 * - * Redistribution and use in source and/or binary forms, with or without - * modification, must retain the above copyright notice and the following - * disclaimer. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 io.spine.dependency.storage diff --git a/buildSrc/src/main/kotlin/io/spine/dependency/storage/PostgreSql.kt b/buildSrc/src/main/kotlin/io/spine/dependency/storage/PostgreSql.kt index d61131d..9f47ac8 100644 --- a/buildSrc/src/main/kotlin/io/spine/dependency/storage/PostgreSql.kt +++ b/buildSrc/src/main/kotlin/io/spine/dependency/storage/PostgreSql.kt @@ -1,27 +1,15 @@ /* - * Copyright 2026, TeamDev. All rights reserved. + * Copyright 2026 CodeMatters, Lda. * - * 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 + * 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 * - * Redistribution and use in source and/or binary forms, with or without - * modification, must retain the above copyright notice and the following - * disclaimer. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 io.spine.dependency.storage @@ -35,6 +23,6 @@ package io.spine.dependency.storage */ @Suppress("unused", "ConstPropertyName") object PostgreSql { - private const val version = "42.7.13" + private const val version = "42.7.14" const val connector = "org.postgresql:postgresql:$version" } diff --git a/buildSrc/src/main/kotlin/io/spine/dependency/storage/QueryDsl.kt b/buildSrc/src/main/kotlin/io/spine/dependency/storage/QueryDsl.kt index e22cd9a..ceeb412 100644 --- a/buildSrc/src/main/kotlin/io/spine/dependency/storage/QueryDsl.kt +++ b/buildSrc/src/main/kotlin/io/spine/dependency/storage/QueryDsl.kt @@ -1,27 +1,15 @@ /* - * Copyright 2026, TeamDev. All rights reserved. + * Copyright 2026 CodeMatters, Lda. * - * 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 + * 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 * - * Redistribution and use in source and/or binary forms, with or without - * modification, must retain the above copyright notice and the following - * disclaimer. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 io.spine.dependency.storage diff --git a/buildSrc/src/main/kotlin/io/spine/dependency/test/AssertK.kt b/buildSrc/src/main/kotlin/io/spine/dependency/test/AssertK.kt index da8ed60..1126595 100644 --- a/buildSrc/src/main/kotlin/io/spine/dependency/test/AssertK.kt +++ b/buildSrc/src/main/kotlin/io/spine/dependency/test/AssertK.kt @@ -1,27 +1,15 @@ /* - * Copyright 2026, TeamDev. All rights reserved. + * Copyright 2026 CodeMatters, Lda. * - * 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 + * 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 * - * Redistribution and use in source and/or binary forms, with or without - * modification, must retain the above copyright notice and the following - * disclaimer. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 io.spine.dependency.test diff --git a/buildSrc/src/main/kotlin/io/spine/dependency/test/Hamcrest.kt b/buildSrc/src/main/kotlin/io/spine/dependency/test/Hamcrest.kt index 2349f9f..9176adb 100644 --- a/buildSrc/src/main/kotlin/io/spine/dependency/test/Hamcrest.kt +++ b/buildSrc/src/main/kotlin/io/spine/dependency/test/Hamcrest.kt @@ -1,27 +1,15 @@ /* - * Copyright 2026, TeamDev. All rights reserved. + * Copyright 2026 CodeMatters, Lda. * - * 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 + * 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 * - * Redistribution and use in source and/or binary forms, with or without - * modification, must retain the above copyright notice and the following - * disclaimer. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 io.spine.dependency.test diff --git a/buildSrc/src/main/kotlin/io/spine/dependency/test/JUnit.kt b/buildSrc/src/main/kotlin/io/spine/dependency/test/JUnit.kt index aee3790..3a166fb 100644 --- a/buildSrc/src/main/kotlin/io/spine/dependency/test/JUnit.kt +++ b/buildSrc/src/main/kotlin/io/spine/dependency/test/JUnit.kt @@ -1,27 +1,15 @@ /* - * Copyright 2026, TeamDev. All rights reserved. + * Copyright 2026 CodeMatters, Lda. * - * 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 + * 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 * - * Redistribution and use in source and/or binary forms, with or without - * modification, must retain the above copyright notice and the following - * disclaimer. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 io.spine.dependency.test @@ -88,8 +76,13 @@ object JUnit : DependencyWithBom() { * * So when we use JUnit as a platform, this property should be picked up * for the dependencies automatically. + * + * Since JUnit 6 the platform shares the version line of JUnit itself, + * so this property mirrors [JUnit.version] rather than repeating it. + * Under JUnit 5 the two differed — the platform was `1.x` while + * Jupiter was `5.x`. */ - override val version: String = "6.1.3" + override val version: String = JUnit.version override val group = "org.junit.platform" private const val infix = "junit-platform" diff --git a/buildSrc/src/main/kotlin/io/spine/dependency/test/Jacoco.kt b/buildSrc/src/main/kotlin/io/spine/dependency/test/Jacoco.kt index 04a8888..e0946a1 100644 --- a/buildSrc/src/main/kotlin/io/spine/dependency/test/Jacoco.kt +++ b/buildSrc/src/main/kotlin/io/spine/dependency/test/Jacoco.kt @@ -1,27 +1,15 @@ /* - * Copyright 2026, TeamDev. All rights reserved. + * Copyright 2026 CodeMatters, Lda. * - * 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 + * 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 * - * Redistribution and use in source and/or binary forms, with or without - * modification, must retain the above copyright notice and the following - * disclaimer. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 io.spine.dependency.test diff --git a/buildSrc/src/main/kotlin/io/spine/dependency/test/Kotest.kt b/buildSrc/src/main/kotlin/io/spine/dependency/test/Kotest.kt index 56a52be..b0bb899 100644 --- a/buildSrc/src/main/kotlin/io/spine/dependency/test/Kotest.kt +++ b/buildSrc/src/main/kotlin/io/spine/dependency/test/Kotest.kt @@ -1,27 +1,15 @@ /* - * Copyright 2026, TeamDev. All rights reserved. + * Copyright 2026 CodeMatters, Lda. * - * 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 + * 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 * - * Redistribution and use in source and/or binary forms, with or without - * modification, must retain the above copyright notice and the following - * disclaimer. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. */ @file:Suppress("unused") @@ -35,7 +23,7 @@ package io.spine.dependency.test */ @Suppress("unused", "ConstPropertyName") object Kotest { - const val version = "6.2.4" + const val version = "6.2.5" const val group = "io.kotest" const val gradlePluginId = "io.kotest" const val assertions = "$group:kotest-assertions-core:$version" diff --git a/buildSrc/src/main/kotlin/io/spine/dependency/test/KotlinCompileTesting.kt b/buildSrc/src/main/kotlin/io/spine/dependency/test/KotlinCompileTesting.kt index b338189..1976493 100644 --- a/buildSrc/src/main/kotlin/io/spine/dependency/test/KotlinCompileTesting.kt +++ b/buildSrc/src/main/kotlin/io/spine/dependency/test/KotlinCompileTesting.kt @@ -1,27 +1,15 @@ /* - * Copyright 2026, TeamDev. All rights reserved. + * Copyright 2026 CodeMatters, Lda. * - * 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 + * 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 * - * Redistribution and use in source and/or binary forms, with or without - * modification, must retain the above copyright notice and the following - * disclaimer. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 io.spine.dependency.test @@ -33,7 +21,7 @@ package io.spine.dependency.test */ @Suppress("unused", "ConstPropertyName") object KotlinCompileTesting { - private const val version = "0.13.0" + private const val version = "0.14.0" private const val group = "dev.zacsweers.kctfork" const val libCore = "$group:core:$version" const val libKsp = "$group:ksp:$version" diff --git a/buildSrc/src/main/kotlin/io/spine/dependency/test/Kover.kt b/buildSrc/src/main/kotlin/io/spine/dependency/test/Kover.kt index 25c0066..9c984b4 100644 --- a/buildSrc/src/main/kotlin/io/spine/dependency/test/Kover.kt +++ b/buildSrc/src/main/kotlin/io/spine/dependency/test/Kover.kt @@ -1,27 +1,15 @@ /* - * Copyright 2026, TeamDev. All rights reserved. + * Copyright 2026 CodeMatters, Lda. * - * 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 + * 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 * - * Redistribution and use in source and/or binary forms, with or without - * modification, must retain the above copyright notice and the following - * disclaimer. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 io.spine.dependency.test @@ -29,7 +17,7 @@ package io.spine.dependency.test // https://github.com/Kotlin/kotlinx-kover @Suppress("unused", "ConstPropertyName") object Kover { - const val version = "0.9.9" + const val version = "0.9.11" const val id = "org.jetbrains.kotlinx.kover" const val classpath = "org.jetbrains.kotlinx:kover-gradle-plugin:$version" } diff --git a/buildSrc/src/main/kotlin/io/spine/dependency/test/OpenTest4J.kt b/buildSrc/src/main/kotlin/io/spine/dependency/test/OpenTest4J.kt index b7de5fb..22f3663 100644 --- a/buildSrc/src/main/kotlin/io/spine/dependency/test/OpenTest4J.kt +++ b/buildSrc/src/main/kotlin/io/spine/dependency/test/OpenTest4J.kt @@ -1,27 +1,15 @@ /* - * Copyright 2026, TeamDev. All rights reserved. + * Copyright 2026 CodeMatters, Lda. * - * 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 + * 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 * - * Redistribution and use in source and/or binary forms, with or without - * modification, must retain the above copyright notice and the following - * disclaimer. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 io.spine.dependency.test diff --git a/buildSrc/src/main/kotlin/io/spine/dependency/test/SystemLambda.kt b/buildSrc/src/main/kotlin/io/spine/dependency/test/SystemLambda.kt index bbc72e9..2dd1107 100644 --- a/buildSrc/src/main/kotlin/io/spine/dependency/test/SystemLambda.kt +++ b/buildSrc/src/main/kotlin/io/spine/dependency/test/SystemLambda.kt @@ -1,27 +1,15 @@ /* - * Copyright 2026, TeamDev. All rights reserved. + * Copyright 2026 CodeMatters, Lda. * - * 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 + * 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 * - * Redistribution and use in source and/or binary forms, with or without - * modification, must retain the above copyright notice and the following - * disclaimer. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 io.spine.dependency.test diff --git a/buildSrc/src/main/kotlin/io/spine/dependency/test/TestKitTruth.kt b/buildSrc/src/main/kotlin/io/spine/dependency/test/TestKitTruth.kt index eec21ed..69fabe7 100644 --- a/buildSrc/src/main/kotlin/io/spine/dependency/test/TestKitTruth.kt +++ b/buildSrc/src/main/kotlin/io/spine/dependency/test/TestKitTruth.kt @@ -1,27 +1,15 @@ /* - * Copyright 2026, TeamDev. All rights reserved. + * Copyright 2026 CodeMatters, Lda. * - * 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 + * 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 * - * Redistribution and use in source and/or binary forms, with or without - * modification, must retain the above copyright notice and the following - * disclaimer. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. */ @file:Suppress("MaxLineLength") @@ -31,11 +19,16 @@ package io.spine.dependency.test /** * Gradle TestKit extension for Google Truth. * - * @see TestKit source code + * @see TestKit source code * @see Usage description */ @Suppress("unused", "ConstPropertyName") object TestKitTruth { - private const val version = "1.20.0" - const val lib = "com.autonomousapps:testkit-truth:$version" + private const val version = "1.7.1" + + /** + * The artifact has been published as `gradle-testkit-truth` since `1.3`. + * Earlier versions, up to `1.1`, were published as `testkit-truth`. + */ + const val lib = "com.autonomousapps:gradle-testkit-truth:$version" } diff --git a/buildSrc/src/main/kotlin/io/spine/dependency/test/Testcontainers.kt b/buildSrc/src/main/kotlin/io/spine/dependency/test/Testcontainers.kt index 97124fb..91c3024 100644 --- a/buildSrc/src/main/kotlin/io/spine/dependency/test/Testcontainers.kt +++ b/buildSrc/src/main/kotlin/io/spine/dependency/test/Testcontainers.kt @@ -1,27 +1,15 @@ /* - * Copyright 2026, TeamDev. All rights reserved. + * Copyright 2026 CodeMatters, Lda. * - * 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 + * 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 * - * Redistribution and use in source and/or binary forms, with or without - * modification, must retain the above copyright notice and the following - * disclaimer. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 io.spine.dependency.test diff --git a/buildSrc/src/main/kotlin/io/spine/dependency/test/Truth.kt b/buildSrc/src/main/kotlin/io/spine/dependency/test/Truth.kt index 3fc5a5e..5cfc1bc 100644 --- a/buildSrc/src/main/kotlin/io/spine/dependency/test/Truth.kt +++ b/buildSrc/src/main/kotlin/io/spine/dependency/test/Truth.kt @@ -1,27 +1,15 @@ /* - * Copyright 2026, TeamDev. All rights reserved. + * Copyright 2026 CodeMatters, Lda. * - * 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 + * 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 * - * Redistribution and use in source and/or binary forms, with or without - * modification, must retain the above copyright notice and the following - * disclaimer. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 io.spine.dependency.test diff --git a/buildSrc/src/main/kotlin/io/spine/docs/MarkdownDocument.kt b/buildSrc/src/main/kotlin/io/spine/docs/MarkdownDocument.kt index 26dc2ef..ffeb948 100644 --- a/buildSrc/src/main/kotlin/io/spine/docs/MarkdownDocument.kt +++ b/buildSrc/src/main/kotlin/io/spine/docs/MarkdownDocument.kt @@ -1,27 +1,15 @@ /* - * Copyright 2026, TeamDev. All rights reserved. + * Copyright 2026 CodeMatters, Lda. * - * 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 + * 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 * - * Redistribution and use in source and/or binary forms, with or without - * modification, must retain the above copyright notice and the following - * disclaimer. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 io.spine.docs diff --git a/buildSrc/src/main/kotlin/io/spine/gradle/Build.kt b/buildSrc/src/main/kotlin/io/spine/gradle/Build.kt index d66fcaa..871681b 100644 --- a/buildSrc/src/main/kotlin/io/spine/gradle/Build.kt +++ b/buildSrc/src/main/kotlin/io/spine/gradle/Build.kt @@ -1,27 +1,15 @@ /* - * Copyright 2026, TeamDev. All rights reserved. + * Copyright 2026 CodeMatters, Lda. * - * 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 + * 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 * - * Redistribution and use in source and/or binary forms, with or without - * modification, must retain the above copyright notice and the following - * disclaimer. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 io.spine.gradle diff --git a/buildSrc/src/main/kotlin/io/spine/gradle/Clean.kt b/buildSrc/src/main/kotlin/io/spine/gradle/Clean.kt index 3ed4c1c..1869f72 100644 --- a/buildSrc/src/main/kotlin/io/spine/gradle/Clean.kt +++ b/buildSrc/src/main/kotlin/io/spine/gradle/Clean.kt @@ -1,27 +1,15 @@ /* - * Copyright 2026, TeamDev. All rights reserved. + * Copyright 2026 CodeMatters, Lda. * - * 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 + * 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 * - * Redistribution and use in source and/or binary forms, with or without - * modification, must retain the above copyright notice and the following - * disclaimer. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 io.spine.gradle diff --git a/buildSrc/src/main/kotlin/io/spine/gradle/Cli.kt b/buildSrc/src/main/kotlin/io/spine/gradle/Cli.kt index 9424ea1..0e43f3f 100644 --- a/buildSrc/src/main/kotlin/io/spine/gradle/Cli.kt +++ b/buildSrc/src/main/kotlin/io/spine/gradle/Cli.kt @@ -1,27 +1,15 @@ /* - * Copyright 2026, TeamDev. All rights reserved. + * Copyright 2026 CodeMatters, Lda. * - * 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 + * 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 * - * Redistribution and use in source and/or binary forms, with or without - * modification, must retain the above copyright notice and the following - * disclaimer. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. */ @file:Suppress("unused") diff --git a/buildSrc/src/main/kotlin/io/spine/gradle/ConfigTester.kt b/buildSrc/src/main/kotlin/io/spine/gradle/ConfigTester.kt index c2ab0f2..f364ccc 100644 --- a/buildSrc/src/main/kotlin/io/spine/gradle/ConfigTester.kt +++ b/buildSrc/src/main/kotlin/io/spine/gradle/ConfigTester.kt @@ -1,27 +1,15 @@ /* - * Copyright 2026, TeamDev. All rights reserved. + * Copyright 2026 CodeMatters, Lda. * - * 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 + * 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 * - * Redistribution and use in source and/or binary forms, with or without - * modification, must retain the above copyright notice and the following - * disclaimer. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. */ @file:Suppress("unused") /* Some constants may be used throughout the Spine repos. */ diff --git a/buildSrc/src/main/kotlin/io/spine/gradle/ProjectExtensions.kt b/buildSrc/src/main/kotlin/io/spine/gradle/ProjectExtensions.kt index 300d423..41cac88 100644 --- a/buildSrc/src/main/kotlin/io/spine/gradle/ProjectExtensions.kt +++ b/buildSrc/src/main/kotlin/io/spine/gradle/ProjectExtensions.kt @@ -1,27 +1,15 @@ /* - * Copyright 2026, TeamDev. All rights reserved. + * Copyright 2026 CodeMatters, Lda. * - * 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 + * 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 * - * Redistribution and use in source and/or binary forms, with or without - * modification, must retain the above copyright notice and the following - * disclaimer. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 io.spine.gradle diff --git a/buildSrc/src/main/kotlin/io/spine/gradle/RunBuild.kt b/buildSrc/src/main/kotlin/io/spine/gradle/RunBuild.kt index 32db367..33b7a63 100644 --- a/buildSrc/src/main/kotlin/io/spine/gradle/RunBuild.kt +++ b/buildSrc/src/main/kotlin/io/spine/gradle/RunBuild.kt @@ -1,27 +1,15 @@ /* - * Copyright 2026, TeamDev. All rights reserved. + * Copyright 2026 CodeMatters, Lda. * - * 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 + * 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 * - * Redistribution and use in source and/or binary forms, with or without - * modification, must retain the above copyright notice and the following - * disclaimer. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 io.spine.gradle diff --git a/buildSrc/src/main/kotlin/io/spine/gradle/RunGradle.kt b/buildSrc/src/main/kotlin/io/spine/gradle/RunGradle.kt index 4461ba5..3049c7b 100644 --- a/buildSrc/src/main/kotlin/io/spine/gradle/RunGradle.kt +++ b/buildSrc/src/main/kotlin/io/spine/gradle/RunGradle.kt @@ -1,27 +1,15 @@ /* - * Copyright 2026, TeamDev. All rights reserved. + * Copyright 2026 CodeMatters, Lda. * - * 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 + * 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 * - * Redistribution and use in source and/or binary forms, with or without - * modification, must retain the above copyright notice and the following - * disclaimer. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 io.spine.gradle diff --git a/buildSrc/src/main/kotlin/io/spine/gradle/SpineTaskGroup.kt b/buildSrc/src/main/kotlin/io/spine/gradle/SpineTaskGroup.kt index 073fe5d..9d7c86b 100644 --- a/buildSrc/src/main/kotlin/io/spine/gradle/SpineTaskGroup.kt +++ b/buildSrc/src/main/kotlin/io/spine/gradle/SpineTaskGroup.kt @@ -1,27 +1,15 @@ /* - * Copyright 2026, TeamDev. All rights reserved. + * Copyright 2026 CodeMatters, Lda. * - * 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 + * 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 * - * Redistribution and use in source and/or binary forms, with or without - * modification, must retain the above copyright notice and the following - * disclaimer. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 io.spine.gradle diff --git a/buildSrc/src/main/kotlin/io/spine/gradle/StringExtensions.kt b/buildSrc/src/main/kotlin/io/spine/gradle/StringExtensions.kt index b519179..d130d97 100644 --- a/buildSrc/src/main/kotlin/io/spine/gradle/StringExtensions.kt +++ b/buildSrc/src/main/kotlin/io/spine/gradle/StringExtensions.kt @@ -1,27 +1,15 @@ /* - * Copyright 2026, TeamDev. All rights reserved. + * Copyright 2026 CodeMatters, Lda. * - * 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 + * 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 * - * Redistribution and use in source and/or binary forms, with or without - * modification, must retain the above copyright notice and the following - * disclaimer. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 io.spine.gradle diff --git a/buildSrc/src/main/kotlin/io/spine/gradle/TaskName.kt b/buildSrc/src/main/kotlin/io/spine/gradle/TaskName.kt index 3197d15..0a595b3 100644 --- a/buildSrc/src/main/kotlin/io/spine/gradle/TaskName.kt +++ b/buildSrc/src/main/kotlin/io/spine/gradle/TaskName.kt @@ -1,27 +1,15 @@ /* - * Copyright 2026, TeamDev. All rights reserved. + * Copyright 2026 CodeMatters, Lda. * - * 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 + * 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 * - * Redistribution and use in source and/or binary forms, with or without - * modification, must retain the above copyright notice and the following - * disclaimer. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 io.spine.gradle diff --git a/buildSrc/src/main/kotlin/io/spine/gradle/VersionComparator.kt b/buildSrc/src/main/kotlin/io/spine/gradle/VersionComparator.kt index 58e8aea..983d339 100644 --- a/buildSrc/src/main/kotlin/io/spine/gradle/VersionComparator.kt +++ b/buildSrc/src/main/kotlin/io/spine/gradle/VersionComparator.kt @@ -1,27 +1,15 @@ /* - * Copyright 2026, TeamDev. All rights reserved. + * Copyright 2026 CodeMatters, Lda. * - * 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 + * 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 * - * Redistribution and use in source and/or binary forms, with or without - * modification, must retain the above copyright notice and the following - * disclaimer. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 io.spine.gradle diff --git a/buildSrc/src/main/kotlin/io/spine/gradle/VersionGradleFile.kt b/buildSrc/src/main/kotlin/io/spine/gradle/VersionGradleFile.kt index c84bb6e..e09032b 100644 --- a/buildSrc/src/main/kotlin/io/spine/gradle/VersionGradleFile.kt +++ b/buildSrc/src/main/kotlin/io/spine/gradle/VersionGradleFile.kt @@ -1,27 +1,15 @@ /* - * Copyright 2026, TeamDev. All rights reserved. + * Copyright 2026 CodeMatters, Lda. * - * 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 + * 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 * - * Redistribution and use in source and/or binary forms, with or without - * modification, must retain the above copyright notice and the following - * disclaimer. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 io.spine.gradle diff --git a/buildSrc/src/main/kotlin/io/spine/gradle/base/Tasks.kt b/buildSrc/src/main/kotlin/io/spine/gradle/base/Tasks.kt index 8f5e89a..43d3cf1 100644 --- a/buildSrc/src/main/kotlin/io/spine/gradle/base/Tasks.kt +++ b/buildSrc/src/main/kotlin/io/spine/gradle/base/Tasks.kt @@ -1,27 +1,15 @@ /* - * Copyright 2026, TeamDev. All rights reserved. + * Copyright 2026 CodeMatters, Lda. * - * 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 + * 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 * - * Redistribution and use in source and/or binary forms, with or without - * modification, must retain the above copyright notice and the following - * disclaimer. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 io.spine.gradle.base diff --git a/buildSrc/src/main/kotlin/io/spine/gradle/checkstyle/CheckStyleConfig.kt b/buildSrc/src/main/kotlin/io/spine/gradle/checkstyle/CheckStyleConfig.kt index cb9a959..b823268 100644 --- a/buildSrc/src/main/kotlin/io/spine/gradle/checkstyle/CheckStyleConfig.kt +++ b/buildSrc/src/main/kotlin/io/spine/gradle/checkstyle/CheckStyleConfig.kt @@ -1,27 +1,15 @@ /* - * Copyright 2026, TeamDev. All rights reserved. + * Copyright 2026 CodeMatters, Lda. * - * 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 + * 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 * - * Redistribution and use in source and/or binary forms, with or without - * modification, must retain the above copyright notice and the following - * disclaimer. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 io.spine.gradle.checkstyle @@ -30,6 +18,7 @@ import io.spine.dependency.build.CheckStyle import org.gradle.api.Project import org.gradle.api.plugins.quality.CheckstyleExtension import org.gradle.api.plugins.quality.CheckstylePlugin +import org.gradle.kotlin.dsl.exclude import org.gradle.kotlin.dsl.the /** @@ -63,6 +52,12 @@ object CheckStyleConfig { configDirectory.set(configDir) } + // Checkstyle needs Doxia only to generate its own website, and Doxia's + // dependencies conflict with the versions we force. See `CheckStyle.version`. + project.configurations.named("checkstyle") { + exclude(group = "org.apache.maven.doxia") + } + project.afterEvaluate { // Disables checking the test sources and test fixtures. arrayOf( diff --git a/buildSrc/src/main/kotlin/io/spine/gradle/dart/DartContext.kt b/buildSrc/src/main/kotlin/io/spine/gradle/dart/DartContext.kt index cb5ae17..342f6b1 100644 --- a/buildSrc/src/main/kotlin/io/spine/gradle/dart/DartContext.kt +++ b/buildSrc/src/main/kotlin/io/spine/gradle/dart/DartContext.kt @@ -1,27 +1,15 @@ /* - * Copyright 2026, TeamDev. All rights reserved. + * Copyright 2026 CodeMatters, Lda. * - * 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 + * 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 * - * Redistribution and use in source and/or binary forms, with or without - * modification, must retain the above copyright notice and the following - * disclaimer. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 io.spine.gradle.dart diff --git a/buildSrc/src/main/kotlin/io/spine/gradle/dart/DartEnvironment.kt b/buildSrc/src/main/kotlin/io/spine/gradle/dart/DartEnvironment.kt index 47b8d32..807fd1a 100644 --- a/buildSrc/src/main/kotlin/io/spine/gradle/dart/DartEnvironment.kt +++ b/buildSrc/src/main/kotlin/io/spine/gradle/dart/DartEnvironment.kt @@ -1,27 +1,15 @@ /* - * Copyright 2026, TeamDev. All rights reserved. + * Copyright 2026 CodeMatters, Lda. * - * 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 + * 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 * - * Redistribution and use in source and/or binary forms, with or without - * modification, must retain the above copyright notice and the following - * disclaimer. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 io.spine.gradle.dart diff --git a/buildSrc/src/main/kotlin/io/spine/gradle/dart/DartExtension.kt b/buildSrc/src/main/kotlin/io/spine/gradle/dart/DartExtension.kt index 4f89d34..bf1acd5 100644 --- a/buildSrc/src/main/kotlin/io/spine/gradle/dart/DartExtension.kt +++ b/buildSrc/src/main/kotlin/io/spine/gradle/dart/DartExtension.kt @@ -1,27 +1,15 @@ /* - * Copyright 2026, TeamDev. All rights reserved. + * Copyright 2026 CodeMatters, Lda. * - * 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 + * 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 * - * Redistribution and use in source and/or binary forms, with or without - * modification, must retain the above copyright notice and the following - * disclaimer. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 io.spine.gradle.dart diff --git a/buildSrc/src/main/kotlin/io/spine/gradle/dart/plugin/DartPlugins.kt b/buildSrc/src/main/kotlin/io/spine/gradle/dart/plugin/DartPlugins.kt index cbe4232..990884c 100644 --- a/buildSrc/src/main/kotlin/io/spine/gradle/dart/plugin/DartPlugins.kt +++ b/buildSrc/src/main/kotlin/io/spine/gradle/dart/plugin/DartPlugins.kt @@ -1,27 +1,15 @@ /* - * Copyright 2026, TeamDev. All rights reserved. + * Copyright 2026 CodeMatters, Lda. * - * 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 + * 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 * - * Redistribution and use in source and/or binary forms, with or without - * modification, must retain the above copyright notice and the following - * disclaimer. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 io.spine.gradle.dart.plugin diff --git a/buildSrc/src/main/kotlin/io/spine/gradle/dart/plugin/Protobuf.kt b/buildSrc/src/main/kotlin/io/spine/gradle/dart/plugin/Protobuf.kt index 568f1f9..2e4e0bc 100644 --- a/buildSrc/src/main/kotlin/io/spine/gradle/dart/plugin/Protobuf.kt +++ b/buildSrc/src/main/kotlin/io/spine/gradle/dart/plugin/Protobuf.kt @@ -1,27 +1,15 @@ /* - * Copyright 2026, TeamDev. All rights reserved. + * Copyright 2026 CodeMatters, Lda. * - * 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 + * 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 * - * Redistribution and use in source and/or binary forms, with or without - * modification, must retain the above copyright notice and the following - * disclaimer. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 io.spine.gradle.dart.plugin diff --git a/buildSrc/src/main/kotlin/io/spine/gradle/dart/task/Build.kt b/buildSrc/src/main/kotlin/io/spine/gradle/dart/task/Build.kt index 939963b..462463f 100644 --- a/buildSrc/src/main/kotlin/io/spine/gradle/dart/task/Build.kt +++ b/buildSrc/src/main/kotlin/io/spine/gradle/dart/task/Build.kt @@ -1,27 +1,15 @@ /* - * Copyright 2026, TeamDev. All rights reserved. + * Copyright 2026 CodeMatters, Lda. * - * 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 + * 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 * - * Redistribution and use in source and/or binary forms, with or without - * modification, must retain the above copyright notice and the following - * disclaimer. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 io.spine.gradle.dart.task diff --git a/buildSrc/src/main/kotlin/io/spine/gradle/dart/task/DartTasks.kt b/buildSrc/src/main/kotlin/io/spine/gradle/dart/task/DartTasks.kt index 1cea9d4..0afd8bf 100644 --- a/buildSrc/src/main/kotlin/io/spine/gradle/dart/task/DartTasks.kt +++ b/buildSrc/src/main/kotlin/io/spine/gradle/dart/task/DartTasks.kt @@ -1,27 +1,15 @@ /* - * Copyright 2026, TeamDev. All rights reserved. + * Copyright 2026 CodeMatters, Lda. * - * 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 + * 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 * - * Redistribution and use in source and/or binary forms, with or without - * modification, must retain the above copyright notice and the following - * disclaimer. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 io.spine.gradle.dart.task diff --git a/buildSrc/src/main/kotlin/io/spine/gradle/dart/task/IntegrationTest.kt b/buildSrc/src/main/kotlin/io/spine/gradle/dart/task/IntegrationTest.kt index 7c27558..36021a5 100644 --- a/buildSrc/src/main/kotlin/io/spine/gradle/dart/task/IntegrationTest.kt +++ b/buildSrc/src/main/kotlin/io/spine/gradle/dart/task/IntegrationTest.kt @@ -1,27 +1,15 @@ /* - * Copyright 2026, TeamDev. All rights reserved. + * Copyright 2026 CodeMatters, Lda. * - * 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 + * 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 * - * Redistribution and use in source and/or binary forms, with or without - * modification, must retain the above copyright notice and the following - * disclaimer. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 io.spine.gradle.dart.task diff --git a/buildSrc/src/main/kotlin/io/spine/gradle/dart/task/Publish.kt b/buildSrc/src/main/kotlin/io/spine/gradle/dart/task/Publish.kt index 0b33443..7239a4d 100644 --- a/buildSrc/src/main/kotlin/io/spine/gradle/dart/task/Publish.kt +++ b/buildSrc/src/main/kotlin/io/spine/gradle/dart/task/Publish.kt @@ -1,27 +1,15 @@ /* - * Copyright 2026, TeamDev. All rights reserved. + * Copyright 2026 CodeMatters, Lda. * - * 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 + * 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 * - * Redistribution and use in source and/or binary forms, with or without - * modification, must retain the above copyright notice and the following - * disclaimer. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 io.spine.gradle.dart.task diff --git a/buildSrc/src/main/kotlin/io/spine/gradle/docs/UpdatePluginVersion.kt b/buildSrc/src/main/kotlin/io/spine/gradle/docs/UpdatePluginVersion.kt index 0277bcd..5ec521f 100644 --- a/buildSrc/src/main/kotlin/io/spine/gradle/docs/UpdatePluginVersion.kt +++ b/buildSrc/src/main/kotlin/io/spine/gradle/docs/UpdatePluginVersion.kt @@ -1,27 +1,15 @@ /* - * Copyright 2026, TeamDev. All rights reserved. + * Copyright 2026 CodeMatters, Lda. * - * 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 + * 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 * - * Redistribution and use in source and/or binary forms, with or without - * modification, must retain the above copyright notice and the following - * disclaimer. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 io.spine.gradle.docs diff --git a/buildSrc/src/main/kotlin/io/spine/gradle/fs/LazyTempPath.kt b/buildSrc/src/main/kotlin/io/spine/gradle/fs/LazyTempPath.kt index b31cd30..73a95c1 100644 --- a/buildSrc/src/main/kotlin/io/spine/gradle/fs/LazyTempPath.kt +++ b/buildSrc/src/main/kotlin/io/spine/gradle/fs/LazyTempPath.kt @@ -1,27 +1,15 @@ /* - * Copyright 2026, TeamDev. All rights reserved. + * Copyright 2026 CodeMatters, Lda. * - * 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 + * 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 * - * Redistribution and use in source and/or binary forms, with or without - * modification, must retain the above copyright notice and the following - * disclaimer. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 io.spine.gradle.fs diff --git a/buildSrc/src/main/kotlin/io/spine/gradle/fs/SpineTempDir.kt b/buildSrc/src/main/kotlin/io/spine/gradle/fs/SpineTempDir.kt index d6e856e..ad7d5a8 100644 --- a/buildSrc/src/main/kotlin/io/spine/gradle/fs/SpineTempDir.kt +++ b/buildSrc/src/main/kotlin/io/spine/gradle/fs/SpineTempDir.kt @@ -1,27 +1,15 @@ /* - * Copyright 2026, TeamDev. All rights reserved. + * Copyright 2026 CodeMatters, Lda. * - * 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 + * 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 * - * Redistribution and use in source and/or binary forms, with or without - * modification, must retain the above copyright notice and the following - * disclaimer. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 io.spine.gradle.fs diff --git a/buildSrc/src/main/kotlin/io/spine/gradle/git/Branch.kt b/buildSrc/src/main/kotlin/io/spine/gradle/git/Branch.kt index dcac91e..2c3673e 100644 --- a/buildSrc/src/main/kotlin/io/spine/gradle/git/Branch.kt +++ b/buildSrc/src/main/kotlin/io/spine/gradle/git/Branch.kt @@ -1,27 +1,15 @@ /* - * Copyright 2026, TeamDev. All rights reserved. + * Copyright 2026 CodeMatters, Lda. * - * 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 + * 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 * - * Redistribution and use in source and/or binary forms, with or without - * modification, must retain the above copyright notice and the following - * disclaimer. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 io.spine.gradle.git diff --git a/buildSrc/src/main/kotlin/io/spine/gradle/git/Repository.kt b/buildSrc/src/main/kotlin/io/spine/gradle/git/Repository.kt index 4751ac1..1b7e09a 100644 --- a/buildSrc/src/main/kotlin/io/spine/gradle/git/Repository.kt +++ b/buildSrc/src/main/kotlin/io/spine/gradle/git/Repository.kt @@ -1,27 +1,15 @@ /* - * Copyright 2026, TeamDev. All rights reserved. + * Copyright 2026 CodeMatters, Lda. * - * 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 + * 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 * - * Redistribution and use in source and/or binary forms, with or without - * modification, must retain the above copyright notice and the following - * disclaimer. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 io.spine.gradle.git diff --git a/buildSrc/src/main/kotlin/io/spine/gradle/git/UserInfo.kt b/buildSrc/src/main/kotlin/io/spine/gradle/git/UserInfo.kt index 1a81177..f9ccb25 100644 --- a/buildSrc/src/main/kotlin/io/spine/gradle/git/UserInfo.kt +++ b/buildSrc/src/main/kotlin/io/spine/gradle/git/UserInfo.kt @@ -1,27 +1,15 @@ /* - * Copyright 2026, TeamDev. All rights reserved. + * Copyright 2026 CodeMatters, Lda. * - * 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 + * 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 * - * Redistribution and use in source and/or binary forms, with or without - * modification, must retain the above copyright notice and the following - * disclaimer. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 io.spine.gradle.git diff --git a/buildSrc/src/main/kotlin/io/spine/gradle/github/pages/AuthorEmail.kt b/buildSrc/src/main/kotlin/io/spine/gradle/github/pages/AuthorEmail.kt index 2914aec..39d16ac 100644 --- a/buildSrc/src/main/kotlin/io/spine/gradle/github/pages/AuthorEmail.kt +++ b/buildSrc/src/main/kotlin/io/spine/gradle/github/pages/AuthorEmail.kt @@ -1,27 +1,15 @@ /* - * Copyright 2026, TeamDev. All rights reserved. + * Copyright 2026 CodeMatters, Lda. * - * 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 + * 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 * - * Redistribution and use in source and/or binary forms, with or without - * modification, must retain the above copyright notice and the following - * disclaimer. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 io.spine.gradle.github.pages diff --git a/buildSrc/src/main/kotlin/io/spine/gradle/github/pages/RepositoryExtensions.kt b/buildSrc/src/main/kotlin/io/spine/gradle/github/pages/RepositoryExtensions.kt index 682d647..0be661d 100644 --- a/buildSrc/src/main/kotlin/io/spine/gradle/github/pages/RepositoryExtensions.kt +++ b/buildSrc/src/main/kotlin/io/spine/gradle/github/pages/RepositoryExtensions.kt @@ -1,27 +1,15 @@ /* - * Copyright 2026, TeamDev. All rights reserved. + * Copyright 2026 CodeMatters, Lda. * - * 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 + * 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 * - * Redistribution and use in source and/or binary forms, with or without - * modification, must retain the above copyright notice and the following - * disclaimer. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 io.spine.gradle.github.pages diff --git a/buildSrc/src/main/kotlin/io/spine/gradle/github/pages/SshKey.kt b/buildSrc/src/main/kotlin/io/spine/gradle/github/pages/SshKey.kt index 653a9f9..e396313 100644 --- a/buildSrc/src/main/kotlin/io/spine/gradle/github/pages/SshKey.kt +++ b/buildSrc/src/main/kotlin/io/spine/gradle/github/pages/SshKey.kt @@ -1,27 +1,15 @@ /* - * Copyright 2026, TeamDev. All rights reserved. + * Copyright 2026 CodeMatters, Lda. * - * 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 + * 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 * - * Redistribution and use in source and/or binary forms, with or without - * modification, must retain the above copyright notice and the following - * disclaimer. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 io.spine.gradle.github.pages diff --git a/buildSrc/src/main/kotlin/io/spine/gradle/github/pages/TaskName.kt b/buildSrc/src/main/kotlin/io/spine/gradle/github/pages/TaskName.kt index efea9e2..cc453f0 100644 --- a/buildSrc/src/main/kotlin/io/spine/gradle/github/pages/TaskName.kt +++ b/buildSrc/src/main/kotlin/io/spine/gradle/github/pages/TaskName.kt @@ -1,27 +1,15 @@ /* - * Copyright 2026, TeamDev. All rights reserved. + * Copyright 2026 CodeMatters, Lda. * - * 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 + * 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 * - * Redistribution and use in source and/or binary forms, with or without - * modification, must retain the above copyright notice and the following - * disclaimer. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 io.spine.gradle.github.pages diff --git a/buildSrc/src/main/kotlin/io/spine/gradle/github/pages/Update.kt b/buildSrc/src/main/kotlin/io/spine/gradle/github/pages/Update.kt index ebc3729..29896d1 100644 --- a/buildSrc/src/main/kotlin/io/spine/gradle/github/pages/Update.kt +++ b/buildSrc/src/main/kotlin/io/spine/gradle/github/pages/Update.kt @@ -1,27 +1,15 @@ /* - * Copyright 2026, TeamDev. All rights reserved. + * Copyright 2026 CodeMatters, Lda. * - * 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 + * 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 * - * Redistribution and use in source and/or binary forms, with or without - * modification, must retain the above copyright notice and the following - * disclaimer. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 io.spine.gradle.github.pages diff --git a/buildSrc/src/main/kotlin/io/spine/gradle/github/pages/UpdateGitHubPages.kt b/buildSrc/src/main/kotlin/io/spine/gradle/github/pages/UpdateGitHubPages.kt index 0214b50..e4960aa 100644 --- a/buildSrc/src/main/kotlin/io/spine/gradle/github/pages/UpdateGitHubPages.kt +++ b/buildSrc/src/main/kotlin/io/spine/gradle/github/pages/UpdateGitHubPages.kt @@ -1,27 +1,15 @@ /* - * Copyright 2026, TeamDev. All rights reserved. + * Copyright 2026 CodeMatters, Lda. * - * 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 + * 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 * - * Redistribution and use in source and/or binary forms, with or without - * modification, must retain the above copyright notice and the following - * disclaimer. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 io.spine.gradle.github.pages diff --git a/buildSrc/src/main/kotlin/io/spine/gradle/github/pages/UpdateGitHubPagesExtension.kt b/buildSrc/src/main/kotlin/io/spine/gradle/github/pages/UpdateGitHubPagesExtension.kt index bb086b8..5a7b1a8 100644 --- a/buildSrc/src/main/kotlin/io/spine/gradle/github/pages/UpdateGitHubPagesExtension.kt +++ b/buildSrc/src/main/kotlin/io/spine/gradle/github/pages/UpdateGitHubPagesExtension.kt @@ -1,27 +1,15 @@ /* - * Copyright 2026, TeamDev. All rights reserved. + * Copyright 2026 CodeMatters, Lda. * - * 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 + * 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 * - * Redistribution and use in source and/or binary forms, with or without - * modification, must retain the above copyright notice and the following - * disclaimer. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 io.spine.gradle.github.pages diff --git a/buildSrc/src/main/kotlin/io/spine/gradle/java/Linters.kt b/buildSrc/src/main/kotlin/io/spine/gradle/java/Linters.kt index 459237c..f386341 100644 --- a/buildSrc/src/main/kotlin/io/spine/gradle/java/Linters.kt +++ b/buildSrc/src/main/kotlin/io/spine/gradle/java/Linters.kt @@ -1,27 +1,15 @@ /* - * Copyright 2026, TeamDev. All rights reserved. + * Copyright 2026 CodeMatters, Lda. * - * 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 + * 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 * - * Redistribution and use in source and/or binary forms, with or without - * modification, must retain the above copyright notice and the following - * disclaimer. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 io.spine.gradle.java diff --git a/buildSrc/src/main/kotlin/io/spine/gradle/java/Tasks.kt b/buildSrc/src/main/kotlin/io/spine/gradle/java/Tasks.kt index 568e121..3ef8d0c 100644 --- a/buildSrc/src/main/kotlin/io/spine/gradle/java/Tasks.kt +++ b/buildSrc/src/main/kotlin/io/spine/gradle/java/Tasks.kt @@ -1,27 +1,15 @@ /* - * Copyright 2026, TeamDev. All rights reserved. + * Copyright 2026 CodeMatters, Lda. * - * 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 + * 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 * - * Redistribution and use in source and/or binary forms, with or without - * modification, must retain the above copyright notice and the following - * disclaimer. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 io.spine.gradle.java diff --git a/buildSrc/src/main/kotlin/io/spine/gradle/javac/ErrorProne.kt b/buildSrc/src/main/kotlin/io/spine/gradle/javac/ErrorProne.kt index 8221c72..897b691 100644 --- a/buildSrc/src/main/kotlin/io/spine/gradle/javac/ErrorProne.kt +++ b/buildSrc/src/main/kotlin/io/spine/gradle/javac/ErrorProne.kt @@ -1,27 +1,15 @@ /* - * Copyright 2026, TeamDev. All rights reserved. + * Copyright 2026 CodeMatters, Lda. * - * 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 + * 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 * - * Redistribution and use in source and/or binary forms, with or without - * modification, must retain the above copyright notice and the following - * disclaimer. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 io.spine.gradle.javac diff --git a/buildSrc/src/main/kotlin/io/spine/gradle/javac/Javac.kt b/buildSrc/src/main/kotlin/io/spine/gradle/javac/Javac.kt index 6ff5f9c..83cca2a 100644 --- a/buildSrc/src/main/kotlin/io/spine/gradle/javac/Javac.kt +++ b/buildSrc/src/main/kotlin/io/spine/gradle/javac/Javac.kt @@ -1,27 +1,15 @@ /* - * Copyright 2026, TeamDev. All rights reserved. + * Copyright 2026 CodeMatters, Lda. * - * 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 + * 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 * - * Redistribution and use in source and/or binary forms, with or without - * modification, must retain the above copyright notice and the following - * disclaimer. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 io.spine.gradle.javac diff --git a/buildSrc/src/main/kotlin/io/spine/gradle/javadoc/Encoding.kt b/buildSrc/src/main/kotlin/io/spine/gradle/javadoc/Encoding.kt index 1946b54..b925187 100644 --- a/buildSrc/src/main/kotlin/io/spine/gradle/javadoc/Encoding.kt +++ b/buildSrc/src/main/kotlin/io/spine/gradle/javadoc/Encoding.kt @@ -1,27 +1,15 @@ /* - * Copyright 2026, TeamDev. All rights reserved. + * Copyright 2026 CodeMatters, Lda. * - * 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 + * 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 * - * Redistribution and use in source and/or binary forms, with or without - * modification, must retain the above copyright notice and the following - * disclaimer. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 io.spine.gradle.javadoc diff --git a/buildSrc/src/main/kotlin/io/spine/gradle/javadoc/ExcludeInternalDoclet.kt b/buildSrc/src/main/kotlin/io/spine/gradle/javadoc/ExcludeInternalDoclet.kt index b3dce49..825d325 100644 --- a/buildSrc/src/main/kotlin/io/spine/gradle/javadoc/ExcludeInternalDoclet.kt +++ b/buildSrc/src/main/kotlin/io/spine/gradle/javadoc/ExcludeInternalDoclet.kt @@ -1,27 +1,15 @@ /* - * Copyright 2026, TeamDev. All rights reserved. + * Copyright 2026 CodeMatters, Lda. * - * 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 + * 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 * - * Redistribution and use in source and/or binary forms, with or without - * modification, must retain the above copyright notice and the following - * disclaimer. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 io.spine.gradle.javadoc diff --git a/buildSrc/src/main/kotlin/io/spine/gradle/javadoc/JavadocConfig.kt b/buildSrc/src/main/kotlin/io/spine/gradle/javadoc/JavadocConfig.kt index df80e8f..cb6998d 100644 --- a/buildSrc/src/main/kotlin/io/spine/gradle/javadoc/JavadocConfig.kt +++ b/buildSrc/src/main/kotlin/io/spine/gradle/javadoc/JavadocConfig.kt @@ -1,27 +1,15 @@ /* - * Copyright 2026, TeamDev. All rights reserved. + * Copyright 2026 CodeMatters, Lda. * - * 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 + * 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 * - * Redistribution and use in source and/or binary forms, with or without - * modification, must retain the above copyright notice and the following - * disclaimer. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 io.spine.gradle.javadoc diff --git a/buildSrc/src/main/kotlin/io/spine/gradle/javadoc/JavadocTag.kt b/buildSrc/src/main/kotlin/io/spine/gradle/javadoc/JavadocTag.kt index 987a8cc..8904deb 100644 --- a/buildSrc/src/main/kotlin/io/spine/gradle/javadoc/JavadocTag.kt +++ b/buildSrc/src/main/kotlin/io/spine/gradle/javadoc/JavadocTag.kt @@ -1,27 +1,15 @@ /* - * Copyright 2026, TeamDev. All rights reserved. + * Copyright 2026 CodeMatters, Lda. * - * 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 + * 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 * - * Redistribution and use in source and/or binary forms, with or without - * modification, must retain the above copyright notice and the following - * disclaimer. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 io.spine.gradle.javadoc diff --git a/buildSrc/src/main/kotlin/io/spine/gradle/javascript/JsContext.kt b/buildSrc/src/main/kotlin/io/spine/gradle/javascript/JsContext.kt index 8008ea6..7441dfd 100644 --- a/buildSrc/src/main/kotlin/io/spine/gradle/javascript/JsContext.kt +++ b/buildSrc/src/main/kotlin/io/spine/gradle/javascript/JsContext.kt @@ -1,27 +1,15 @@ /* - * Copyright 2026, TeamDev. All rights reserved. + * Copyright 2026 CodeMatters, Lda. * - * 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 + * 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 * - * Redistribution and use in source and/or binary forms, with or without - * modification, must retain the above copyright notice and the following - * disclaimer. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 io.spine.gradle.javascript diff --git a/buildSrc/src/main/kotlin/io/spine/gradle/javascript/JsEnvironment.kt b/buildSrc/src/main/kotlin/io/spine/gradle/javascript/JsEnvironment.kt index fdbd3e6..67b147d 100644 --- a/buildSrc/src/main/kotlin/io/spine/gradle/javascript/JsEnvironment.kt +++ b/buildSrc/src/main/kotlin/io/spine/gradle/javascript/JsEnvironment.kt @@ -1,27 +1,15 @@ /* - * Copyright 2026, TeamDev. All rights reserved. + * Copyright 2026 CodeMatters, Lda. * - * 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 + * 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 * - * Redistribution and use in source and/or binary forms, with or without - * modification, must retain the above copyright notice and the following - * disclaimer. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 io.spine.gradle.javascript diff --git a/buildSrc/src/main/kotlin/io/spine/gradle/javascript/JsExtension.kt b/buildSrc/src/main/kotlin/io/spine/gradle/javascript/JsExtension.kt index 9231d90..fe998a9 100644 --- a/buildSrc/src/main/kotlin/io/spine/gradle/javascript/JsExtension.kt +++ b/buildSrc/src/main/kotlin/io/spine/gradle/javascript/JsExtension.kt @@ -1,27 +1,15 @@ /* - * Copyright 2026, TeamDev. All rights reserved. + * Copyright 2026 CodeMatters, Lda. * - * 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 + * 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 * - * Redistribution and use in source and/or binary forms, with or without - * modification, must retain the above copyright notice and the following - * disclaimer. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 io.spine.gradle.javascript diff --git a/buildSrc/src/main/kotlin/io/spine/gradle/javascript/plugin/Idea.kt b/buildSrc/src/main/kotlin/io/spine/gradle/javascript/plugin/Idea.kt index 4219e5a..54f45e1 100644 --- a/buildSrc/src/main/kotlin/io/spine/gradle/javascript/plugin/Idea.kt +++ b/buildSrc/src/main/kotlin/io/spine/gradle/javascript/plugin/Idea.kt @@ -1,27 +1,15 @@ /* - * Copyright 2026, TeamDev. All rights reserved. + * Copyright 2026 CodeMatters, Lda. * - * 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 + * 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 * - * Redistribution and use in source and/or binary forms, with or without - * modification, must retain the above copyright notice and the following - * disclaimer. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 io.spine.gradle.javascript.plugin diff --git a/buildSrc/src/main/kotlin/io/spine/gradle/javascript/plugin/JsPlugins.kt b/buildSrc/src/main/kotlin/io/spine/gradle/javascript/plugin/JsPlugins.kt index 0b636ac..d6ce151 100644 --- a/buildSrc/src/main/kotlin/io/spine/gradle/javascript/plugin/JsPlugins.kt +++ b/buildSrc/src/main/kotlin/io/spine/gradle/javascript/plugin/JsPlugins.kt @@ -1,27 +1,15 @@ /* - * Copyright 2026, TeamDev. All rights reserved. + * Copyright 2026 CodeMatters, Lda. * - * 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 + * 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 * - * Redistribution and use in source and/or binary forms, with or without - * modification, must retain the above copyright notice and the following - * disclaimer. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 io.spine.gradle.javascript.plugin diff --git a/buildSrc/src/main/kotlin/io/spine/gradle/javascript/plugin/McJs.kt b/buildSrc/src/main/kotlin/io/spine/gradle/javascript/plugin/McJs.kt index b2a46ba..98c79e2 100644 --- a/buildSrc/src/main/kotlin/io/spine/gradle/javascript/plugin/McJs.kt +++ b/buildSrc/src/main/kotlin/io/spine/gradle/javascript/plugin/McJs.kt @@ -1,27 +1,15 @@ /* - * Copyright 2026, TeamDev. All rights reserved. + * Copyright 2026 CodeMatters, Lda. * - * 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 + * 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 * - * Redistribution and use in source and/or binary forms, with or without - * modification, must retain the above copyright notice and the following - * disclaimer. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 io.spine.gradle.javascript.plugin diff --git a/buildSrc/src/main/kotlin/io/spine/gradle/javascript/plugin/Protobuf.kt b/buildSrc/src/main/kotlin/io/spine/gradle/javascript/plugin/Protobuf.kt index 98b9263..6ed2a46 100644 --- a/buildSrc/src/main/kotlin/io/spine/gradle/javascript/plugin/Protobuf.kt +++ b/buildSrc/src/main/kotlin/io/spine/gradle/javascript/plugin/Protobuf.kt @@ -1,27 +1,15 @@ /* - * Copyright 2026, TeamDev. All rights reserved. + * Copyright 2026 CodeMatters, Lda. * - * 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 + * 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 * - * Redistribution and use in source and/or binary forms, with or without - * modification, must retain the above copyright notice and the following - * disclaimer. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 io.spine.gradle.javascript.plugin diff --git a/buildSrc/src/main/kotlin/io/spine/gradle/javascript/task/Assemble.kt b/buildSrc/src/main/kotlin/io/spine/gradle/javascript/task/Assemble.kt index 3bb1454..f050f85 100644 --- a/buildSrc/src/main/kotlin/io/spine/gradle/javascript/task/Assemble.kt +++ b/buildSrc/src/main/kotlin/io/spine/gradle/javascript/task/Assemble.kt @@ -1,27 +1,15 @@ /* - * Copyright 2026, TeamDev. All rights reserved. + * Copyright 2026 CodeMatters, Lda. * - * 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 + * 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 * - * Redistribution and use in source and/or binary forms, with or without - * modification, must retain the above copyright notice and the following - * disclaimer. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 io.spine.gradle.javascript.task diff --git a/buildSrc/src/main/kotlin/io/spine/gradle/javascript/task/Check.kt b/buildSrc/src/main/kotlin/io/spine/gradle/javascript/task/Check.kt index 9f46d84..da7dc94 100644 --- a/buildSrc/src/main/kotlin/io/spine/gradle/javascript/task/Check.kt +++ b/buildSrc/src/main/kotlin/io/spine/gradle/javascript/task/Check.kt @@ -1,27 +1,15 @@ /* - * Copyright 2026, TeamDev. All rights reserved. + * Copyright 2026 CodeMatters, Lda. * - * 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 + * 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 * - * Redistribution and use in source and/or binary forms, with or without - * modification, must retain the above copyright notice and the following - * disclaimer. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 io.spine.gradle.javascript.task diff --git a/buildSrc/src/main/kotlin/io/spine/gradle/javascript/task/Clean.kt b/buildSrc/src/main/kotlin/io/spine/gradle/javascript/task/Clean.kt index 6042128..f00ccea 100644 --- a/buildSrc/src/main/kotlin/io/spine/gradle/javascript/task/Clean.kt +++ b/buildSrc/src/main/kotlin/io/spine/gradle/javascript/task/Clean.kt @@ -1,27 +1,15 @@ /* - * Copyright 2026, TeamDev. All rights reserved. + * Copyright 2026 CodeMatters, Lda. * - * 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 + * 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 * - * Redistribution and use in source and/or binary forms, with or without - * modification, must retain the above copyright notice and the following - * disclaimer. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 io.spine.gradle.javascript.task diff --git a/buildSrc/src/main/kotlin/io/spine/gradle/javascript/task/IntegrationTest.kt b/buildSrc/src/main/kotlin/io/spine/gradle/javascript/task/IntegrationTest.kt index 475668c..6e3d82b 100644 --- a/buildSrc/src/main/kotlin/io/spine/gradle/javascript/task/IntegrationTest.kt +++ b/buildSrc/src/main/kotlin/io/spine/gradle/javascript/task/IntegrationTest.kt @@ -1,27 +1,15 @@ /* - * Copyright 2026, TeamDev. All rights reserved. + * Copyright 2026 CodeMatters, Lda. * - * 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 + * 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 * - * Redistribution and use in source and/or binary forms, with or without - * modification, must retain the above copyright notice and the following - * disclaimer. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 io.spine.gradle.javascript.task diff --git a/buildSrc/src/main/kotlin/io/spine/gradle/javascript/task/JsTasks.kt b/buildSrc/src/main/kotlin/io/spine/gradle/javascript/task/JsTasks.kt index 3b9d814..d41633c 100644 --- a/buildSrc/src/main/kotlin/io/spine/gradle/javascript/task/JsTasks.kt +++ b/buildSrc/src/main/kotlin/io/spine/gradle/javascript/task/JsTasks.kt @@ -1,27 +1,15 @@ /* - * Copyright 2026, TeamDev. All rights reserved. + * Copyright 2026 CodeMatters, Lda. * - * 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 + * 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 * - * Redistribution and use in source and/or binary forms, with or without - * modification, must retain the above copyright notice and the following - * disclaimer. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 io.spine.gradle.javascript.task diff --git a/buildSrc/src/main/kotlin/io/spine/gradle/javascript/task/LicenseReport.kt b/buildSrc/src/main/kotlin/io/spine/gradle/javascript/task/LicenseReport.kt index 8276bcc..a4856ce 100644 --- a/buildSrc/src/main/kotlin/io/spine/gradle/javascript/task/LicenseReport.kt +++ b/buildSrc/src/main/kotlin/io/spine/gradle/javascript/task/LicenseReport.kt @@ -1,27 +1,15 @@ /* - * Copyright 2026, TeamDev. All rights reserved. + * Copyright 2026 CodeMatters, Lda. * - * 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 + * 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 * - * Redistribution and use in source and/or binary forms, with or without - * modification, must retain the above copyright notice and the following - * disclaimer. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 io.spine.gradle.javascript.task diff --git a/buildSrc/src/main/kotlin/io/spine/gradle/javascript/task/Publish.kt b/buildSrc/src/main/kotlin/io/spine/gradle/javascript/task/Publish.kt index c07e7ba..cca2362 100644 --- a/buildSrc/src/main/kotlin/io/spine/gradle/javascript/task/Publish.kt +++ b/buildSrc/src/main/kotlin/io/spine/gradle/javascript/task/Publish.kt @@ -1,27 +1,15 @@ /* - * Copyright 2026, TeamDev. All rights reserved. + * Copyright 2026 CodeMatters, Lda. * - * 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 + * 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 * - * Redistribution and use in source and/or binary forms, with or without - * modification, must retain the above copyright notice and the following - * disclaimer. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 io.spine.gradle.javascript.task diff --git a/buildSrc/src/main/kotlin/io/spine/gradle/javascript/task/Webpack.kt b/buildSrc/src/main/kotlin/io/spine/gradle/javascript/task/Webpack.kt index 5609c90..f7b7295 100644 --- a/buildSrc/src/main/kotlin/io/spine/gradle/javascript/task/Webpack.kt +++ b/buildSrc/src/main/kotlin/io/spine/gradle/javascript/task/Webpack.kt @@ -1,27 +1,15 @@ /* - * Copyright 2026, TeamDev. All rights reserved. + * Copyright 2026 CodeMatters, Lda. * - * 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 + * 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 * - * Redistribution and use in source and/or binary forms, with or without - * modification, must retain the above copyright notice and the following - * disclaimer. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 io.spine.gradle.javascript.task diff --git a/buildSrc/src/main/kotlin/io/spine/gradle/kotlin/KotlinConfig.kt b/buildSrc/src/main/kotlin/io/spine/gradle/kotlin/KotlinConfig.kt index 0e5099a..dd56fac 100644 --- a/buildSrc/src/main/kotlin/io/spine/gradle/kotlin/KotlinConfig.kt +++ b/buildSrc/src/main/kotlin/io/spine/gradle/kotlin/KotlinConfig.kt @@ -1,27 +1,15 @@ /* - * Copyright 2026, TeamDev. All rights reserved. + * Copyright 2026 CodeMatters, Lda. * - * 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 + * 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 * - * Redistribution and use in source and/or binary forms, with or without - * modification, must retain the above copyright notice and the following - * disclaimer. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 io.spine.gradle.kotlin @@ -52,6 +40,9 @@ fun KotlinJvmProjectExtension.applyJvmToolchain(version: String) = /** * Opts-in to experimental features that we use in our codebase. + * + * One flag is deliberately withheld rather than passed — see the comment on + * `-Xcontext-parameters` in the body. */ @Suppress("unused") fun KotlinCommonCompilerOptions.setFreeCompilerArgs() { @@ -69,11 +60,23 @@ fun KotlinCommonCompilerOptions.setFreeCompilerArgs() { // Native code cannot use the API anyway. optIns.add("kotlin.io.path.ExperimentalPathApi") } + // `-Xcontext-parameters` is deliberately absent. Context parameters are + // no longer experimental in the Kotlin version we pin, so at its default + // language version (2.4) the flag only produces + // "The argument '-Xcontext-parameters' is redundant for the current + // language version 2.4." + // + // Re-add it if Kotlin is ever downgraded below 2.4, or if a compilation + // this function configures pins a lower language version while using the + // feature. (Precompiled script plugins compile against the Kotlin that + // Gradle embeds and are not configured here.) + // + // Re-check these flags on a Kotlin bump: when the compiler reports one as + // redundant, drop it. freeCompilerArgs.addAll( listOf( "-Xskip-prerelease-check", "-Xexpect-actual-classes", - "-Xcontext-parameters", "-opt-in=" + optIns.joinToString(separator = ","), ) ) diff --git a/buildSrc/src/main/kotlin/io/spine/gradle/publish/ArtifactComponents.kt b/buildSrc/src/main/kotlin/io/spine/gradle/publish/ArtifactComponents.kt new file mode 100644 index 0000000..88e6d91 --- /dev/null +++ b/buildSrc/src/main/kotlin/io/spine/gradle/publish/ArtifactComponents.kt @@ -0,0 +1,257 @@ +/* + * Copyright 2026 CodeMatters, Lda. + * + * 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. + */ + +// The rewrite of an SPDX document by the components of its artifact belongs together. +@file:Suppress("TooManyFunctions") + +package io.spine.gradle.publish + +import com.fasterxml.jackson.databind.JsonNode +import com.fasterxml.jackson.databind.node.ArrayNode +import com.fasterxml.jackson.databind.node.JsonNodeFactory +import com.fasterxml.jackson.databind.node.ObjectNode +import java.io.Serial +import java.io.Serializable +import org.gradle.api.logging.Logger + +/** + * The components an artifact depends on, and those bundled into it. + * + * They tell how the artifact relates to each package the SPDX Gradle Plugin lists + * for it, all of which the plugin relates to the artifact as its dependencies. + * + * @see PublicationSbomTask.artifactComponents + */ +internal data class ArtifactComponents( + + /** The components of the dependency graph of the artifact. */ + val dependencies: Set = emptySet(), + + /** The components bundled into the artifact. */ + val bundled: Set = emptySet(), +) : Serializable { + + private companion object { + @Serial + private const val serialVersionUID: Long = 0L + } +} + +/** + * Relates the artifact the given SPDX [document] describes to the packages it lists, + * as to its dependencies and to its content. + * + * The plugin walks the configurations of the SBOM one after another, from the + * module of the artifact, and relates each package it finds as a dependency of + * the first package through which it found it. The walk of a later configuration + * goes through the packages found before, so it can relate a package it finds on + * the way to the bundled ones to a dependency of the artifact. So, in the rewritten + * document: + * - the artifact contains each bundled package, rather than depending on it; + * - a package the artifact neither depends on nor bundles is left out, along with + * its relationships; + * - a dependency of the artifact does not depend on a bundled package that is not + * a dependency of the artifact; + * - a license text that only the packages left out refer to is left out too. + * + * A bundled package that another one already contains, such as a file of + * a component resolved to several, stays contained in that one alone. + * A package whose component cannot be told is left as it is. The plugin writes + * none such. + */ +internal fun ArtifactComponents.describeIn(document: ObjectNode, logger: Logger) { + val packages = document.arrayNamed(SpdxField.packages) + val relationships = document.arrayNamed(SpdxField.relationships) + val artifact = relationships.describedElement() + val allKeys = packages.componentKeys() + val keys = allKeys - artifact + val leftOut = keys.filterValues { it !in dependencies && it !in bundled }.keys + val content = keys.filterValues { it in bundled }.keys + val kept = relationships + .filterIsInstance() + .filterNot { it.spdxElementId in leftOut || it.relatedSpdxElement in leftOut } + .filterNot { it.bringsBundledIntoDependencies(this@describeIn, keys = keys) } + .map { it.asContainmentIfBundled(artifact = artifact, content = content) } + .distinctBy { Triple(it.spdxElementId, it.relationshipType, it.relatedSpdxElement) } + val contained = kept + .filter { it.relationshipType == CONTAINS } + .map { it.relatedSpdxElement } + .toSet() + val containment = (content - contained).map { + relationship(element = artifact, type = CONTAINS, related = it) + } + relationships.replaceWith(kept + containment) + packages.replaceWith(packages.filterNot { it.spdxId in leftOut }) + document.dropUnusedLicenses() + if (leftOut.isNotEmpty()) { + logger.info( + "The SBOM leaves out what the artifact neither depends on nor bundles: {}.", + leftOut.map { keys.getValue(it) }.sortedBy { it.toString() } + ) + } + val unlisted = bundled - allKeys.values.toSet() + if (unlisted.isNotEmpty()) { + logger.warn( + "The SBOM lists no package for these components bundled into the artifact: {}.", + unlisted.sortedBy { it.toString() } + ) + } +} + +/** + * Tells if this relationship makes a dependency of the artifact depend on + * a bundled component that is not a dependency of the artifact. + * + * Only the walk of a configuration listing bundled content makes such + * a relationship: the dependency graph of the artifact does not have it. + * + * @param components the components of the artifact. + * @param keys the keys of the components of the packages, by the SPDX IDs + * of the packages. + */ +private fun ObjectNode.bringsBundledIntoDependencies( + components: ArtifactComponents, + keys: Map +): Boolean { + val element = keys[spdxElementId] + val related = keys[relatedSpdxElement] + return relationshipType == DEPENDS_ON + && element != null && element !in components.bundled + && related != null && related !in components.dependencies +} + +/** + * Returns the containment of the package this relationship relates to by the [artifact], + * if the relationship makes the artifact depend on a package of its [content]. + * Otherwise, returns this relationship. + */ +private fun ObjectNode.asContainmentIfBundled( + artifact: String, + content: Set +): ObjectNode { + val bundledDependency = spdxElementId == artifact + && relationshipType == DEPENDS_ON + && relatedSpdxElement in content + return if (bundledDependency) { + relationship(element = artifact, type = CONTAINS, related = relatedSpdxElement) + } else { + this + } +} + +/** + * The type of the relationship of an SPDX element to one it depends on. + */ +internal const val DEPENDS_ON = "DEPENDS_ON" + +/** + * The type of the relationship of an SPDX element to one it contains. + */ +internal const val CONTAINS = "CONTAINS" + +/** + * The type of the relationship of an SPDX document to the element it describes. + */ +internal const val DESCRIBES = "DESCRIBES" + +/** + * The SPDX ID of the document itself. + */ +internal const val DOCUMENT_ID = "SPDXRef-DOCUMENT" + +private val JsonNode.spdxId: String + get() = text(SpdxField.spdxId) + +private val JsonNode.spdxElementId: String + get() = text(SpdxField.spdxElementId) + +private val JsonNode.relationshipType: String + get() = text(SpdxField.relationshipType) + +private val JsonNode.relatedSpdxElement: String + get() = text(SpdxField.relatedSpdxElement) + +/** + * Returns the text of the given [field] of this SPDX element. + */ +private fun JsonNode.text(field: String): String = + get(field)?.asText() ?: error("The SPDX element `$this` has no `$field`.") + +private fun relationship(element: String, type: String, related: String): ObjectNode = + JsonNodeFactory.instance.objectNode() + .put(SpdxField.spdxElementId, element) + .put(SpdxField.relationshipType, type) + .put(SpdxField.relatedSpdxElement, related) + +private fun ObjectNode.arrayNamed(name: String): ArrayNode = + get(name) as? ArrayNode ?: error("The SPDX document has no `$name` array.") + +private fun ArrayNode.replaceWith(elements: List) { + removeAll() + addAll(elements) +} + +/** + * Returns the SPDX ID of the package this array of relationships tells the document + * to describe. + */ +private fun ArrayNode.describedElement(): String { + val described = filter { it.spdxElementId == DOCUMENT_ID && it.relationshipType == DESCRIBES } + require(described.size == 1) { + "An SBOM describes the package of its artifact alone, but this one describes" + + " ${described.size} packages." + } + return described.single().relatedSpdxElement +} + +/** + * Returns the keys of the components the packages in this array stand for, by the SPDX + * IDs of the packages. A package whose component cannot be told is left out. + */ +private fun ArrayNode.componentKeys(): Map = + mapNotNull { pkg -> ComponentKey.ofPackage(pkg)?.let { pkg.spdxId to it } }.toMap() + +/** + * The fields of an SPDX package that hold license expressions. + */ +private val licenseFields = listOf( + SpdxField.licenseConcluded, + SpdxField.licenseDeclared, + SpdxField.licenseInfoFromFiles +) + +/** + * Matches a reference to a license text that the document holds. + */ +private val licenseReference = Regex("""LicenseRef-[A-Za-z0-9.\-]+""") + +/** + * Returns the references to the license texts of the document, such as + * `LicenseRef-gnrtd0`, that the license expressions of the given package make. + */ +internal fun licenseReferencesOf(pkg: JsonNode): Set = + licenseFields + // Not `asText()`: it returns an empty string for `licenseInfoFromFiles`, an array. + .mapNotNull { pkg[it]?.toString() } + .flatMap { expression -> licenseReference.findAll(expression).map { it.value } } + .toSet() + +/** + * Leaves out the license texts that no package of this document refers to. + */ +private fun ObjectNode.dropUnusedLicenses() { + val licenses = get(SpdxField.hasExtractedLicensingInfos) as? ArrayNode ?: return + val used = arrayNamed(SpdxField.packages).flatMap(::licenseReferencesOf).toSet() + licenses.replaceWith(licenses.filter { it[SpdxField.licenseId]?.asText() in used }) +} diff --git a/buildSrc/src/main/kotlin/io/spine/gradle/publish/CheckVersionIncrement.kt b/buildSrc/src/main/kotlin/io/spine/gradle/publish/CheckVersionIncrement.kt index 16897ff..f43f019 100644 --- a/buildSrc/src/main/kotlin/io/spine/gradle/publish/CheckVersionIncrement.kt +++ b/buildSrc/src/main/kotlin/io/spine/gradle/publish/CheckVersionIncrement.kt @@ -1,27 +1,15 @@ /* - * Copyright 2026, TeamDev. All rights reserved. + * Copyright 2026 CodeMatters, Lda. * - * 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 + * 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 * - * Redistribution and use in source and/or binary forms, with or without - * modification, must retain the above copyright notice and the following - * disclaimer. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 io.spine.gradle.publish @@ -32,9 +20,13 @@ import io.spine.gradle.repo.Repository import java.net.URI import org.gradle.api.DefaultTask import org.gradle.api.GradleException -import org.gradle.api.Project +import org.gradle.api.file.DirectoryProperty +import org.gradle.api.provider.Property +import org.gradle.api.provider.SetProperty import org.gradle.api.tasks.Input +import org.gradle.api.tasks.Internal import org.gradle.api.tasks.TaskAction +import org.gradle.work.DisableCachingByDefault /** * A task that verifies the project version is fit to be published. @@ -48,11 +40,19 @@ import org.gradle.api.tasks.TaskAction * parallel PRs that bumped to the same value, regardless of what is (or is not yet) * published. * 2. [checkNotPublished] — the [version] must not already exist in the target Maven - * repository, so a publication cannot overwrite an immutable artifact. + * repository for any of the [artifacts][artifactPaths] the project publishes, so + * a publication cannot overwrite an immutable artifact. * * The two checks are complementary; neither subsumes the other. + * + * Neither the task action nor the `onlyIf` spec that gates it may access + * [project][org.gradle.api.Task.getProject]: Gradle deprecates that at execution time, and + * the configuration cache does not support it. Therefore, [version] is captured when the + * task is created, [IncrementGuard] sets [rootDir] and [artifactPaths] when it registers + * the task, and it sets [publishesToMavenLocal] once the task graph is ready. */ -open class CheckVersionIncrement : DefaultTask() { +@DisableCachingByDefault(because = "Queries a remote Maven repository and produces no outputs.") +abstract class CheckVersionIncrement : DefaultTask() { /** * The Maven repository in which to look for published artifacts. @@ -66,6 +66,44 @@ open class CheckVersionIncrement : DefaultTask() { @Input val version: String = project.version as String + /** + * The root directory of the build, which holds `version.gradle.kts`. + * + * Only its location matters — the task reads `version.gradle.kts` and runs `git` there. + * Hence, it is not an [input directory][org.gradle.api.tasks.InputDirectory], which + * would fingerprint the whole build tree. + */ + @get:Internal + abstract val rootDir: DirectoryProperty + + /** + * The paths to the artifacts of the project in a Maven repository, such as + * `io/spine/spine-base`, one per Maven publication of the project. + * + * Empty for a project that publishes nothing. + */ + @get:Input + abstract val artifactPaths: SetProperty + + /** + * Tells whether the build is going to publish this task's project to Maven Local. + * + * Integration tests in this and sibling projects consume freshly built artifacts + * from `~/.m2`. Publishing them under a version that already exists would let those + * tests pick up a stale artifact, so a local build verifies the version increment + * before any local publication of the project runs. + * + * Only this task's own project counts: a sibling module's local publish in the same + * invocation must not trigger this module's check (see + * [IncrementGuard.localPublishPlanned]). + * + * [IncrementGuard] scans the task graph once it is ready and sets this property, which + * the `onlyIf` spec it adds to the task then reads. The value affects only whether + * the task runs, not what it verifies, so it is not an [input][Input]. + */ + @get:Internal + abstract val publishesToMavenLocal: Property + @TaskAction fun checkVersion() { checkIncrementedAgainstBase() @@ -144,7 +182,8 @@ open class CheckVersionIncrement : DefaultTask() { * [VersionGradleFile.contentInBase] when the base ref itself cannot be resolved. */ private fun baseVersionToCompare(baseRef: String): String? { - val headContent = VersionGradleFile.contentUnder(project.rootDir) + val root = rootDir.get().asFile + val headContent = VersionGradleFile.contentUnder(root) val key = headContent?.let { VersionGradleFile.keyForValue(it, version) } if (key == null) { logger.warn( @@ -153,7 +192,7 @@ open class CheckVersionIncrement : DefaultTask() { ) return null } - val baseContent = VersionGradleFile.contentInBase(project.rootDir, baseRef) + val baseContent = VersionGradleFile.contentInBase(root, baseRef) val baseVersion = baseContent?.let { VersionGradleFile.valueForKey(it, key) } if (baseVersion == null) { logger.info( @@ -166,29 +205,76 @@ open class CheckVersionIncrement : DefaultTask() { /** * Verifies that the current [version] has not been published to the target Maven - * repository yet. + * repository yet, for any of the [artifactPaths]. * * Both the `releases` and `snapshots` repositories are checked; artifacts in either * may not be overwritten. */ private fun checkNotPublished() { - val artifact = "${project.artifactPath()}/${MavenMetadata.FILE_NAME}" - val snapshots = repository.target(snapshots = true) - checkInRepo(snapshots, artifact) + val paths = artifactPaths.get() + if (paths.isEmpty()) { + logger.info( + "The project has no Maven publications; " + + "skipping the check for an already published version." + ) + return + } + paths.forEach(::checkArtifactNotPublished) + } + + /** + * Verifies that the current [version] of the artifact at the given [path] has not been + * published to the target Maven repository yet. + * + * Each repository is checked as soon as its metadata is fetched, so a failure to reach + * one repository does not hide the version found in another one checked before it. + * + * When no repository has the metadata of the artifact, the version cannot be verified, + * and a warning is logged. This is expected before the first publication of the artifact. + * For an artifact published before, it means that [path] does not match the published one. + */ + private fun checkArtifactNotPublished(path: String) { + val artifact = "$path/${MavenMetadata.FILE_NAME}" + val repositories = targetRepositories() + var found = false + for (repoUrl in repositories) { + val metadata = fetch(repoUrl, artifact) ?: continue + found = true + checkNotListed(path = path, repoUrl = repoUrl, metadata = metadata) + } + if (!found) { + logger.warn( + "No `${MavenMetadata.FILE_NAME}` is found for `$path` in " + + "${repositories.joinToString { "`$it`" }}. Either the artifact has never " + + "been published, or the path does not match the published artifact. " + + "`$name` cannot tell whether the version `$version` is already published." + ) + } + } - if (!repository.hasOneTarget()) { - checkInRepo(repository.target(snapshots = false), artifact) + /** + * Returns the URLs of the target repositories: the `snapshots` one, and + * the `releases` one unless it is the same destination. + */ + private fun targetRepositories(): List { + val snapshots = repository.target(snapshots = true) + if (repository.hasOneTarget()) { + return listOf(snapshots) } + return listOf(snapshots, repository.target(snapshots = false)) } - private fun checkInRepo(repoUrl: String, artifact: String) { - val metadata = fetch(repoUrl, artifact) - val versions = metadata?.versioning?.versions - val versionExists = versions?.contains(version) ?: false - if (versionExists) { + /** + * Throws if the [metadata] of the artifact at the given [path], fetched from [repoUrl], + * lists the current [version]. + */ + private fun checkNotListed(path: String, repoUrl: String, metadata: MavenMetadata) { + val versions = metadata.versioning.versions + if (version in versions) { throw GradleException( """ - The version `$version` is already published to the Maven repository `$repoUrl`. + The version `$version` of `$path` is already published + to the Maven repository `$repoUrl`. Try incrementing the library version. All available versions are: ${versions.joinToString(separator = ", ")}. @@ -202,29 +288,4 @@ open class CheckVersionIncrement : DefaultTask() { val url = URI.create("$repository/$artifact").toURL() return MavenMetadata.fetchAndParse(url) } - - private fun Project.artifactPath(): String { - val group = this.group as String - val name = "${artifactPrefix()}${this.name}" - - val pathElements = ArrayList(group.split('.')) - pathElements.add(name) - val path = pathElements.joinToString(separator = "/") - return path - } - - /** - * Returns the artifact prefix used for the publishing of this project. - * - * All current Spine modules should be using `SpinePublishing`. - * Therefore, the corresponding extension should be present in the root project. - * However, just in case, we define the "standard" prefix here as well. - * - * This value MUST be the same as defined by the defaults in `SpinePublishing`. - */ - private fun Project.artifactPrefix(): String { - val ext = rootProject.extensions.findByType(SpinePublishing::class.java) - val result = ext?.artifactPrefix ?: SpinePublishing.DEFAULT_PREFIX - return result - } } diff --git a/buildSrc/src/main/kotlin/io/spine/gradle/publish/CloudArtifactRegistry.kt b/buildSrc/src/main/kotlin/io/spine/gradle/publish/CloudArtifactRegistry.kt index f6fa12f..51344c2 100644 --- a/buildSrc/src/main/kotlin/io/spine/gradle/publish/CloudArtifactRegistry.kt +++ b/buildSrc/src/main/kotlin/io/spine/gradle/publish/CloudArtifactRegistry.kt @@ -1,27 +1,15 @@ /* - * Copyright 2026, TeamDev. All rights reserved. + * Copyright 2026 CodeMatters, Lda. * - * 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 + * 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 * - * Redistribution and use in source and/or binary forms, with or without - * modification, must retain the above copyright notice and the following - * disclaimer. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 io.spine.gradle.publish diff --git a/buildSrc/src/main/kotlin/io/spine/gradle/publish/CloudRepo.kt b/buildSrc/src/main/kotlin/io/spine/gradle/publish/CloudRepo.kt index f0c9857..4fa2233 100644 --- a/buildSrc/src/main/kotlin/io/spine/gradle/publish/CloudRepo.kt +++ b/buildSrc/src/main/kotlin/io/spine/gradle/publish/CloudRepo.kt @@ -1,27 +1,15 @@ /* - * Copyright 2026, TeamDev. All rights reserved. + * Copyright 2026 CodeMatters, Lda. * - * 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 + * 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 * - * Redistribution and use in source and/or binary forms, with or without - * modification, must retain the above copyright notice and the following - * disclaimer. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 io.spine.gradle.publish diff --git a/buildSrc/src/main/kotlin/io/spine/gradle/publish/ComponentKey.kt b/buildSrc/src/main/kotlin/io/spine/gradle/publish/ComponentKey.kt new file mode 100644 index 0000000..e4f769f --- /dev/null +++ b/buildSrc/src/main/kotlin/io/spine/gradle/publish/ComponentKey.kt @@ -0,0 +1,89 @@ +/* + * Copyright 2026 CodeMatters, Lda. + * + * 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 io.spine.gradle.publish + +import com.fasterxml.jackson.databind.JsonNode +import java.io.Serial +import java.io.Serializable +import org.gradle.api.artifacts.component.ComponentIdentifier +import org.gradle.api.artifacts.component.ModuleComponentIdentifier +import org.gradle.api.artifacts.component.ProjectComponentIdentifier + +/** + * Identifies a component — a project of this build, or a module — alike as Gradle + * resolves it and as the SPDX Gradle Plugin lists it in an SBOM. + * + * @see ArtifactComponents + */ +@JvmInline +internal value class ComponentKey(private val value: String) : Serializable { + + override fun toString(): String = value + + companion object { + + @Serial + private const val serialVersionUID: Long = 0L + + /** + * Returns the key of the project with the given [path]. + */ + fun ofProject(path: String): ComponentKey = ComponentKey("project:$path") + + /** + * Returns the key of the module with the given coordinates. + */ + fun ofModule(group: String, name: String, version: String): ComponentKey = + ComponentKey("module:$group:$name:$version") + + /** + * Returns the key of the component with the given [id], or `null` if + * the component is neither a project nor a module. + */ + fun of(id: ComponentIdentifier): ComponentKey? = when (id) { + is ProjectComponentIdentifier -> ofProject(id.projectPath) + is ModuleComponentIdentifier -> + ofModule(group = id.group, name = id.module, version = id.version) + else -> null + } + + /** + * Returns the key of the component the given SPDX package stands for, or `null` + * if the package tells neither the project nor the module it stands for. + * + * The SPDX Gradle Plugin tells the path of a project in the source information + * of its package, and names the package of a module as `group:name`, followed by + * the classifier of the file it describes, if any. + */ + fun ofPackage(pkg: JsonNode): ComponentKey? = + pkg[SpdxField.sourceInfo]?.asText()?.let(::projectPathIn)?.let(::ofProject) + ?: moduleOf(pkg) + + /** + * Returns the key of the module the given SPDX package stands for, or `null` if + * the name of the package does not start with `group:name`, or the package has + * no version. + */ + private fun moduleOf(pkg: JsonNode): ComponentKey? { + val coordinates = pkg[SpdxField.name]?.asText()?.split(':').orEmpty() + val version = pkg[SpdxField.versionInfo]?.asText() + return if (coordinates.size < 2 || version == null) { + null + } else { + ofModule(group = coordinates[0], name = coordinates[1], version = version) + } + } + } +} diff --git a/buildSrc/src/main/kotlin/io/spine/gradle/publish/CustomPublicationHandler.kt b/buildSrc/src/main/kotlin/io/spine/gradle/publish/CustomPublicationHandler.kt index 6791d21..e656f8c 100644 --- a/buildSrc/src/main/kotlin/io/spine/gradle/publish/CustomPublicationHandler.kt +++ b/buildSrc/src/main/kotlin/io/spine/gradle/publish/CustomPublicationHandler.kt @@ -1,27 +1,15 @@ /* - * Copyright 2026, TeamDev. All rights reserved. + * Copyright 2026 CodeMatters, Lda. * - * 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 + * 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 * - * Redistribution and use in source and/or binary forms, with or without - * modification, must retain the above copyright notice and the following - * disclaimer. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 io.spine.gradle.publish @@ -29,14 +17,16 @@ package io.spine.gradle.publish import io.spine.gradle.repo.Repository import org.gradle.api.Project import org.gradle.api.publish.maven.MavenPublication +import org.gradle.kotlin.dsl.withType /** * A handler for custom publications, which are declared under the [publications] * section of a module. * * Such publications should be treated differently than [StandardJavaPublicationHandler], - * which is created for a module. Instead, since the publications are already declared, - * this class only [assigns Maven coordinates][copyProjectAttributes]. + * which is created for a module. Instead, since the publications are declared + * by the module or by the plugins it applies, this class only + * [assigns Maven coordinates][copyProjectAttributes]. * * A module that declares custom publications must be specified in * the [SpinePublishing.modulesWithCustomPublishing] property. @@ -54,9 +44,26 @@ internal class CustomPublicationHandler private constructor( destinations: Set ) : PublicationHandler(project, destinations) { + /** + * Copies the project attributes to each Maven publication of the project, + * including the publications added after this handler is applied. + * + * The latter is the case for `java-gradle-plugin`, which creates the `pluginMaven` + * publication and the plugin markers in its own `afterEvaluate` action. For a module + * listed in [SpinePublishing.modulesWithCustomPublishing], this action runs after + * the one applying this handler. + * + * A plugin marker gets only the [project-wide attributes][copyProjectWideAttributes]. + * The coordinates of a marker are derived from the ID of the plugin, and its + * name and description are those of the plugin. + */ override fun handlePublications() { - project.publications.forEach { - (it as MavenPublication).copyProjectAttributes() + project.publications.withType().configureEach { + if (isPluginMarker) { + copyProjectWideAttributes() + } else { + copyProjectAttributes() + } } } diff --git a/buildSrc/src/main/kotlin/io/spine/gradle/publish/GitHubPackages.kt b/buildSrc/src/main/kotlin/io/spine/gradle/publish/GitHubPackages.kt index c25868f..184c821 100644 --- a/buildSrc/src/main/kotlin/io/spine/gradle/publish/GitHubPackages.kt +++ b/buildSrc/src/main/kotlin/io/spine/gradle/publish/GitHubPackages.kt @@ -1,27 +1,15 @@ /* - * Copyright 2026, TeamDev. All rights reserved. + * Copyright 2026 CodeMatters, Lda. * - * 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 + * 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 * - * Redistribution and use in source and/or binary forms, with or without - * modification, must retain the above copyright notice and the following - * disclaimer. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 io.spine.gradle.publish diff --git a/buildSrc/src/main/kotlin/io/spine/gradle/publish/IncrementGuard.kt b/buildSrc/src/main/kotlin/io/spine/gradle/publish/IncrementGuard.kt index ddda57e..121cc20 100644 --- a/buildSrc/src/main/kotlin/io/spine/gradle/publish/IncrementGuard.kt +++ b/buildSrc/src/main/kotlin/io/spine/gradle/publish/IncrementGuard.kt @@ -1,27 +1,15 @@ /* - * Copyright 2026, TeamDev. All rights reserved. + * Copyright 2026 CodeMatters, Lda. * - * 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 + * 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 * - * Redistribution and use in source and/or binary forms, with or without - * modification, must retain the above copyright notice and the following - * disclaimer. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. */ @file:Suppress("unused") @@ -33,6 +21,7 @@ import io.spine.gradle.SpineTaskGroup import org.gradle.api.Plugin import org.gradle.api.Project import org.gradle.api.Task +import org.gradle.api.publish.maven.MavenPublication import org.gradle.api.publish.maven.tasks.PublishToMavenLocal /** @@ -155,8 +144,27 @@ class IncrementGuard : Plugin { group = SpineTaskGroup.name description = "Verifies that the project version was incremented before publishing" repository = CloudArtifactRegistry.repository + rootDir.set(target.rootDir) + // Resolved lazily: publications and their coordinates are configured + // after the task is created, some of them in `afterEvaluate`. + artifactPaths.set(target.provider { target.publishedArtifactPaths() }) onlyIf { - mustVerify(shouldCheckVersion(), Build.ci, it.publishesToMavenLocal()) + mustVerify( + ciPullRequest = shouldCheckVersion(), + onCi = Build.ci, + localPublish = publishesToMavenLocal.get() + ) + } + } + + // The `onlyIf` spec above runs at execution time, when it must not call `Task.project` + // to reach the task graph. So the graph is scanned for this project's Maven Local + // publishing at configuration time, once it is known. The result is kept in a task + // property, which a configuration cache entry stores along with the task. + target.gradle.taskGraph.whenReady { + val graph = this + checkVersion.configure { + publishesToMavenLocal.set(localPublishPlanned(graph.allTasks, target)) } } @@ -193,18 +201,28 @@ class IncrementGuard : Plugin { } /** - * Tells whether the current build is going to publish this task's project to - * Maven Local. + * Obtains the paths in a Maven repository to the artifacts this project publishes, + * such as `io/spine/spine-base`. * - * Integration tests in this and sibling projects consume freshly built artifacts - * from `~/.m2`. Publishing them under a version that already exists would let those - * tests pick up a stale artifact, so the version increment must be verified before - * any local publication runs. + * The paths are taken from the coordinates of the Maven publications of the project, + * rather than computed from its name. So they cover the + * [tool artifact prefix][SpinePublishing.toolArtifactPrefix], an `artifactId` set by + * a module with [custom publishing][SpinePublishing.modulesWithCustomPublishing], and + * every publication of a module that has several, such as a Kotlin Multiplatform one. * - * Only this task's own project is considered: a sibling module's local publish in - * the same invocation must not trigger this module's check. The predicate is - * evaluated lazily as a task `onlyIf` spec, by which point the execution - * [task graph][org.gradle.api.execution.TaskExecutionGraph] is fully populated. + * Plugin markers are included. A marker is a publication of its own, which may be + * uploaded without the plugin it points to, e.g., by a publish that failed halfway. + * + * The result is empty for a project that publishes nothing. + */ +private fun Project.publishedArtifactPaths(): Set = + mavenPublications() + .map { it.repositoryPath } + .toSet() + +/** + * The path to the artifact of this publication in a Maven repository, + * such as `io/spine/spine-base`. */ -private fun Task.publishesToMavenLocal(): Boolean = - IncrementGuard.localPublishPlanned(project.gradle.taskGraph.allTasks, project) +private val MavenPublication.repositoryPath: String + get() = "${groupId.replace('.', '/')}/$artifactId" diff --git a/buildSrc/src/main/kotlin/io/spine/gradle/publish/JarDsl.kt b/buildSrc/src/main/kotlin/io/spine/gradle/publish/JarDsl.kt index 37b8bfb..14cb2aa 100644 --- a/buildSrc/src/main/kotlin/io/spine/gradle/publish/JarDsl.kt +++ b/buildSrc/src/main/kotlin/io/spine/gradle/publish/JarDsl.kt @@ -1,27 +1,15 @@ /* - * Copyright 2026, TeamDev. All rights reserved. + * Copyright 2026 CodeMatters, Lda. * - * 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 + * 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 * - * Redistribution and use in source and/or binary forms, with or without - * modification, must retain the above copyright notice and the following - * disclaimer. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 io.spine.gradle.publish diff --git a/buildSrc/src/main/kotlin/io/spine/gradle/publish/MavenMetadata.kt b/buildSrc/src/main/kotlin/io/spine/gradle/publish/MavenMetadata.kt index 3d4906d..532ee9e 100644 --- a/buildSrc/src/main/kotlin/io/spine/gradle/publish/MavenMetadata.kt +++ b/buildSrc/src/main/kotlin/io/spine/gradle/publish/MavenMetadata.kt @@ -1,27 +1,15 @@ /* - * Copyright 2026, TeamDev. All rights reserved. + * Copyright 2026 CodeMatters, Lda. * - * 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 + * 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 * - * Redistribution and use in source and/or binary forms, with or without - * modification, must retain the above copyright notice and the following - * disclaimer. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 io.spine.gradle.publish @@ -65,8 +53,9 @@ internal data class MavenMetadata(var versioning: Versioning = Versioning()) { */ fun fetchAndParse(url: URL): MavenMetadata? { return try { - val metadata = mapper.readValue(url, MavenMetadata::class.java) - metadata + url.openStream().use { stream -> + mapper.readValue(stream, MavenMetadata::class.java) + } } catch (_: FileNotFoundException) { null } diff --git a/buildSrc/src/main/kotlin/io/spine/gradle/publish/ProtoExts.kt b/buildSrc/src/main/kotlin/io/spine/gradle/publish/ProtoExts.kt index 580ecf5..fd5dba8 100644 --- a/buildSrc/src/main/kotlin/io/spine/gradle/publish/ProtoExts.kt +++ b/buildSrc/src/main/kotlin/io/spine/gradle/publish/ProtoExts.kt @@ -1,27 +1,15 @@ /* - * Copyright 2026, TeamDev. All rights reserved. + * Copyright 2026 CodeMatters, Lda. * - * 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 + * 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 * - * Redistribution and use in source and/or binary forms, with or without - * modification, must retain the above copyright notice and the following - * disclaimer. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 io.spine.gradle.publish diff --git a/buildSrc/src/main/kotlin/io/spine/gradle/publish/PublicationChecksums.kt b/buildSrc/src/main/kotlin/io/spine/gradle/publish/PublicationChecksums.kt new file mode 100644 index 0000000..a49f8a6 --- /dev/null +++ b/buildSrc/src/main/kotlin/io/spine/gradle/publish/PublicationChecksums.kt @@ -0,0 +1,402 @@ +/* + * Copyright 2026 CodeMatters, Lda. + * + * 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 io.spine.gradle.publish + +import io.spine.gradle.SpineTaskGroup +import java.io.File +import java.security.MessageDigest +import java.util.Locale +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.publish.maven.MavenPublication +import org.gradle.api.publish.maven.tasks.GenerateMavenPom +import org.gradle.api.publish.tasks.GenerateModuleMetadata +import org.gradle.api.tasks.TaskCollection +import org.gradle.api.tasks.TaskContainer +import org.gradle.api.tasks.TaskProvider + +/** + * Writes a manifest of the artifacts published by this build, so that GitHub + * Actions can attest their build provenance. + * + * Usage: + * ``` + * PublicationChecksums.registerTasks(project, projectsToPublish) + * ``` + * + * ## Why Gradle computes the manifest + * + * The `actions/attest` action identifies an attested artifact by its digest and + * by a name, both of which it takes **verbatim** from the manifest — it never + * re-reads the artifacts. So the manifest must name each artifact exactly as it + * is published, and cover all of them: an omission silently narrows a signed + * claim, and a wrong digest signs a claim about the wrong bytes. + * + * Neither is obtainable by globbing the build directory. The name of an artifact + * on disk is derived from the Gradle project name, while the published name uses + * [the artifact ID][SpinePublishing.artifactPrefix] — `client-2.0.0.jar` is + * published as `spine-client-2.0.0.jar`. The POM and the Gradle module metadata + * are not in `build/libs` at all; they are generated under `build/publications`, + * using the fixed names `pom-default.xml` and `module.json`. Only the publication + * knows how these map onto published names. + * + * ## Why a task per project + * + * A task of the root project may not reach into the state of another project. + * As with [the POM report][io.spine.gradle.report.pom.PomGenerator], a + * [collector task][registerCollectorIn] is therefore registered in every + * published project, describing only its own publications, and + * [an aggregator][registerAggregatorIn] merges their output. + * + * Neither task declares inputs or outputs, on purpose: both always run, so the + * manifest cannot describe a previous state of the build. + */ +internal object PublicationChecksums { + + /** + * The name of the per-project task registered by [registerCollectorIn]. + */ + const val collectorTaskName = "collectPublicationChecksums" + + /** + * The name of the task registered by [registerAggregatorIn]. + */ + const val aggregatorTaskName = "publicationChecksums" + + private const val collectorPath = "attestation/checksums.txt" + + private const val aggregatePath = "attestation/subject-checksums.txt" + + /** + * Separates a digest from the name of its subject, as `sha256sum` writes it. + * + * The action reads the name as everything after the first space, dropping one + * further `*` or space, so the two-space form leaves the name intact. + */ + private const val digestSeparator = " " + + /** + * Registers the [collector][registerCollectorIn] tasks in the given + * [published] projects, and the [aggregator][registerAggregatorIn] task in + * [host]. + * + * [host] is the project in which `spinePublishing { }` was opened. That is + * the root project of a multi-module build, which is where `publish.yml` + * expects the manifest. A module configuring the extension for itself also + * gets an aggregator of its own, describing only that module. + */ + fun registerTasks(host: Project, published: Set) { + val collectors = published.map { registerCollectorIn(it) } + registerAggregatorIn(host, published, collectors) + } + + /** + * Registers the [collectorTaskName] task in the given [project]. + * + * The task depends on everything that produces a published file: the + * artifacts of the publications of this project, and the tasks generating + * the POM and the Gradle module metadata. + * + * The task orders itself after `clean` — Gradle does not order the two + * otherwise, so in a `gradle clean build` invocation a late-running `clean` + * could delete a freshly written manifest. + * + * A version Maven would deploy under a timestamped name is rejected while + * the project is still being configured, rather than when this task runs. + * The distributed workflow asks for `publish` and `publicationChecksums` in + * one invocation, and Gradle may upload before it reaches the collector, so + * a check inside the task would fail only after the artifacts were already + * published — leaving exactly the published-but-unattested state the check + * exists to prevent. + */ + private fun registerCollectorIn(project: Project): TaskProvider { + project.afterEvaluate { + mavenPublications().forEach { it.rejectMavenSnapshot() } + } + return project.tasks.getOrRegister(collectorTaskName) { + group = SpineTaskGroup.name + description = "Computes the digests of the artifacts published by " + + "the `${project.name}` project" + mustRunAfter(project.tasks.cleanTask()) + dependsOn(project.provider { + project.mavenPublications().flatMap { publication -> + publication.artifacts.map { it.buildDependencies } + } + }) + dependsOn(project.tasks.withType(GenerateMavenPom::class.java)) + dependsOn(project.tasks.withType(GenerateModuleMetadata::class.java)) + doLast { + val file = collectorOutput(project).get().asFile + file.parentFile.mkdirs() + file.writeText(serialize(project.publishedArtifacts())) + } + } + } + + /** + * Registers the [aggregatorTaskName] task in [host]. + * + * The task merges the manifests written by the [collectors] into a single + * file in the `sha256sum` format, which `actions/attest` accepts as its + * `subject-checksums` input, ordered by subject name so that two runs of the + * same build produce a file that can be compared line by line. + * + * A manifest missing at merge time fails the task. Every collector writes + * unconditionally, so an absent one means the subject set is incomplete — + * and an attestation that silently covers less than it appears to is worse + * than none. Two digests published under one name fail it for the same + * reason: only one of them can describe what a consumer resolves. + * + * The task orders itself after `clean` for the reason given in + * [registerCollectorIn]: it writes under the build directory that `clean` + * removes. + */ + private fun registerAggregatorIn( + host: Project, + published: Set, + collectors: List> + ) { + // Resolved outside the task action: reading the layout of another project + // from `doLast` is the cross-project access this class is arranged to + // avoid, and it is what makes a task incompatible with the configuration + // cache. The providers stay lazy, so a project may still reconfigure its + // build directory afterwards. + // + // The list belongs to the project rather than to this call, because the + // task is registered once while `registerTasks` may run several times — + // see `getOrRegister`. Were the action to close over one call's projects, + // a later call adding a module would register its collector and still + // leave it out of the manifest. + val sources = host.attestationSources() + sources += published.map { collectorOutput(it) } + val target = host.layout.buildDirectory.file(aggregatePath) + val aggregator = host.tasks.getOrRegister(aggregatorTaskName) { + group = SpineTaskGroup.name + description = "Writes the digests of all published artifacts for attestation" + mustRunAfter(host.tasks.cleanTask()) + doLast { + val merged = sources + .map { it.get().asFile } + .onEach { + check(it.exists()) { + "No checksum manifest at `$it`." + + " The attestation would omit a published module." + } + } + .flatMap { it.readLines() } + .filter { it.isNotBlank() } + .distinct() + .sortedBy { it.subjectName() } + merged.ensureNamesUnique() + val file = target.get().asFile + file.parentFile.mkdirs() + file.writeText(merged.joinToString(separator = "\n", postfix = "\n")) + logger.lifecycle("Wrote ${merged.size} attestation subject(s) to `$file`.") + } + } + // Applied on every call, including the one that registered the task, so + // that collectors added by a later call are run before the merge reads + // the files they write. + aggregator.configure { + dependsOn(collectors) + } + } + + /** + * Returns the file under the build directory of [project] in which + * [the collector task][registerCollectorIn] describes that project. + */ + private fun collectorOutput(project: Project): Provider = + project.layout.buildDirectory.file(collectorPath) + + /** + * Renders the given artifacts as `sha256sum` records, ordered by name. + */ + private fun serialize(artifacts: Map): String = + artifacts.entries + .sortedBy { it.key } + .joinToString(separator = "\n", postfix = "\n") { (name, digest) -> + "$digest$digestSeparator$name" + } + + /** + * Returns the subject name of this `sha256sum` record. + */ + private fun String.subjectName(): String = substringAfter(digestSeparator) + + /** + * Fails unless every record in this list names a distinct subject. + * + * Byte-identical records are already gone by this point, so a name occurring + * twice carries two different digests. Attesting both would state that the + * same published file is two different things. + */ + private fun List.ensureNamesUnique() { + val duplicated = groupBy { it.subjectName() } + .filterValues { it.size > 1 } + .keys + check(duplicated.isEmpty()) { + "Different digests are published under the same name: " + + duplicated.joinToString { "`$it`" } + "." + } + } +} + +/** + * Returns the task named [name] in this container, registering it with [init] + * if it is not there yet. + * + * `spinePublishing { }` configures the extension anew on every call, and the + * same project can be reached by two such calls: the root extension lists a + * module in [SpinePublishing.modulesWithCustomPublishing], while the module + * itself opens the extension with `customPublishing = true` — which is what + * `uber-jar-module.gradle.kts` does. Plain registration fails on the second + * call, during configuration, so registration has to be idempotent. + */ +private fun TaskContainer.getOrRegister( + name: String, + init: Task.() -> Unit +): TaskProvider = + if (names.contains(name)) { + named(name) + } else { + register(name, init) + } + +/** + * Returns the `clean` task of this container, if it has one. + * + * Filtering by name alone keeps the lookup lazy. Matching on a task instance + * would instantiate every registered task in the project just to read its name. + */ +private fun TaskContainer.cleanTask(): TaskCollection = named { it == "clean" } + +/** + * Returns the manifests the aggregator of this project merges, accumulated + * across every call of [PublicationChecksums.registerTasks] for it. + * + * The list is attached to the project, so that it lives exactly as long as + * the build does. Holding it in the object registering the tasks would share + * it between builds, which reuse a Gradle daemon and its class loaders. + */ +@Suppress("UNCHECKED_CAST" /* The property is written here and nowhere else. */) +private fun Project.attestationSources(): MutableList> { + val key = "io.spine.gradle.publish.attestationSources" + val properties = extensions.extraProperties + if (!properties.has(key)) { + properties.set(key, mutableListOf>()) + } + return properties.get(key) as MutableList> +} + +/** + * Returns the digest of every file this project publishes, keyed by the name + * under which the file is published. + * + * Two artifacts of one project resolving to the same published name fail the + * build: keeping either one silently drops the other from the attestation. + */ +private fun Project.publishedArtifacts(): Map { + val result = mutableMapOf() + + fun record(name: String, file: File) { + val replaced = result.put(name, file.sha256()) + check(replaced == null) { + "The project `$path` publishes two artifacts as `$name`." + } + } + + mavenPublications().forEach { publication -> + publication.rejectMavenSnapshot() + val base = "${publication.artifactId}-${publication.version}" + publication.artifacts.forEach { artifact -> + val classifier = artifact.classifier?.takeIf { it.isNotEmpty() } + val suffix = classifier?.let { "-$it" } ?: "" + record("$base$suffix.${artifact.extension}", artifact.file) + } + pomFileOf(publication)?.let { record("$base.pom", it) } + moduleFileOf(publication)?.let { record("$base.module", it) } + } + return result +} + +/** + * Returns the generated POM of the given [publication], or `null` if the + * generating task has not written it. + */ +private fun Project.pomFileOf(publication: MavenPublication): File? = + tasks.withType(GenerateMavenPom::class.java) + .findByName("generatePomFileFor${publication.taskSuffix()}") + ?.destination + ?.takeIf { it.exists() } + +/** + * Returns the generated Gradle module metadata of the given [publication], or + * `null` if the metadata is disabled or its task has not written it. + */ +private fun Project.moduleFileOf(publication: MavenPublication): File? = + tasks.withType(GenerateModuleMetadata::class.java) + .findByName("generateMetadataFileFor${publication.taskSuffix()}") + ?.outputFile + ?.get() + ?.asFile + ?.takeIf { it.exists() } + +/** + * Fails if this publication has a Maven snapshot version. + * + * Maven treats a version ending in `-SNAPSHOT` as mutable and deploys it under + * a timestamped name — `spine-base-1.2.3-20260923.165835-1.jar` — assigned at + * upload time. The names derived here would then belong to no uploaded file, + * and the attestation would describe artifacts nobody can resolve. + * + * The version policy of the SDK does not produce such versions: an interim + * version is `MAJOR.MINOR.PATCH-SNAPSHOT.NUMBER`, which does not end in + * `-SNAPSHOT` and is published as an ordinary immutable release. This guards + * the case anyway, because the alternative to failing is a signed statement + * about files that were never published. + */ +private fun MavenPublication.rejectMavenSnapshot() { + check(!version.endsWith("-SNAPSHOT")) { + "Cannot attest `$artifactId`: Maven deploys the snapshot version" + + " `$version` under a timestamped name that this manifest cannot" + + " predict. Interim versions use the `-SNAPSHOT.` form." + } +} + +/** + * Returns the part of the name of a `generate...` task that identifies + * this publication. + */ +private fun MavenPublication.taskSuffix(): String = + "${name.replaceFirstChar { it.titlecase(Locale.ROOT) }}Publication" + +/** + * Returns the SHA-256 digest of this file as a lowercase hexadecimal string. + * + * The file is streamed, as published artifacts may be large. + */ +private fun File.sha256(): String { + check(exists()) { + "Cannot attest a missing artifact file: `$this`." + } + val digest = MessageDigest.getInstance("SHA-256") + forEachBlock { buffer, bytesRead -> + digest.update(buffer, 0, bytesRead) + } + return digest.digest().joinToString("") { "%02x".format(it) } +} diff --git a/buildSrc/src/main/kotlin/io/spine/gradle/publish/PublicationHandler.kt b/buildSrc/src/main/kotlin/io/spine/gradle/publish/PublicationHandler.kt index 0d52925..1d4bb96 100644 --- a/buildSrc/src/main/kotlin/io/spine/gradle/publish/PublicationHandler.kt +++ b/buildSrc/src/main/kotlin/io/spine/gradle/publish/PublicationHandler.kt @@ -1,43 +1,37 @@ /* - * Copyright 2026, TeamDev. All rights reserved. + * Copyright 2026 CodeMatters, Lda. * - * 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 + * 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 * - * Redistribution and use in source and/or binary forms, with or without - * modification, must retain the above copyright notice and the following - * disclaimer. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 io.spine.gradle.publish import DocumentationSettings import LicenseSettings +import io.spine.gradle.SpineTaskGroup import io.spine.gradle.artifactId import io.spine.gradle.isSnapshot import io.spine.gradle.repo.Repository import io.spine.gradle.report.pom.InceptionYear +import java.util.Locale +import java.util.concurrent.Callable import org.gradle.api.Project import org.gradle.api.artifacts.dsl.RepositoryHandler +import org.gradle.api.artifacts.repositories.MavenArtifactRepository import org.gradle.api.invocation.BuildInvocationDetails import org.gradle.api.publish.maven.MavenPublication +import org.gradle.api.publish.maven.tasks.PublishToMavenRepository import org.gradle.kotlin.dsl.apply import org.gradle.kotlin.dsl.support.serviceOf +import org.gradle.kotlin.dsl.withType /** * The name of the Maven Publishing Gradle plugin. @@ -110,7 +104,7 @@ sealed class PublicationHandler( } /** - * Either handles publications already declared in the associated [project] + * Either handles the publications of the associated [project] * or creates new ones. */ abstract fun handlePublications() @@ -143,13 +137,8 @@ sealed class PublicationHandler( * current artifact ID is `logging-jvm` (set by the KMP plugin), the resulting * artifact ID will be `spine-logging-jvm`. * - * The Apache Software License 2.0 is set as the only license - * under which the published artifact is distributed via [LicenseSettings]. - * - * The source control management attributes are obtained from [DocumentationSettings]. - * - * @see LicenseSettings - * @see DocumentationSettings + * The attributes describing the project as a whole are set + * by [copyProjectWideAttributes]. */ protected fun MavenPublication.copyProjectAttributes() { groupId = project.group.toString() @@ -173,6 +162,29 @@ sealed class PublicationHandler( } version = project.version.toString() pom.description.set(project.description) + copyProjectWideAttributes() + } + + /** + * Sets the POM attributes of this [MavenPublication] that describe + * the [project] as a whole, rather than the published artifact. + * + * The inception year of Spine is taken from [InceptionYear]. + * + * The Apache Software License 2.0 is set as the only license + * under which the published artifact is distributed via [LicenseSettings]. + * + * The source control management attributes are obtained from [DocumentationSettings]. + * + * Unlike [copyProjectAttributes], this function leaves the coordinates and + * the description of the publication intact. So, it also applies to a publication + * that identifies something other than the artifact of the project, + * such as a Gradle plugin marker. + * + * @see LicenseSettings + * @see DocumentationSettings + */ + protected fun MavenPublication.copyProjectWideAttributes() { pom.inceptionYear.set(InceptionYear.value) pom.licenses { license { @@ -270,18 +282,55 @@ sealed class PublicationHandler( } /** - * Adds a Maven repository to the project specifying credentials, if they are - * [available][Repository.credentials] from the root project. + * Adds a Maven repository to the project. + * + * The credentials of the repository, if they are [available][Repository.credentials] + * from the root project, are supplied only when a task publishing to it is about + * to run (see [supplyCredentials]). */ private fun RepositoryHandler.register(project: Project, repository: Repository) { val isSnapshot = project.version.toString().isSnapshot() - val credentials = repository.credentials(project.rootProject) - maven { + val target = maven { name = repository.name(isSnapshot) url = project.uri(repository.target(isSnapshot)) - credentials { - username = credentials?.username - password = credentials?.password + } + project.supplyCredentials(target, repository) +} + +/** + * Registers a supplier task that sets the credentials of the [target] repository + * to those of the [source] one, and makes each task publishing to [target] + * depend on the supplier task. + * + * Obtaining the credentials may start an external process, e.g., `gcloud` + * for [CloudArtifactRegistry]. Gradle deprecates starting one at configuration time, + * and builds that do not publish should not obtain the credentials at all. + * An action of the publishing task cannot supply them, either: the task validates + * them before running any of its actions. Hence, the publishing task depends on + * the supplier task, which sets them on the repository rather than producing an output. + */ +private fun Project.supplyCredentials(target: MavenArtifactRepository, source: Repository) { + // Captured at configuration time: the action must not reach the project + // through its task, as Gradle deprecates calling `Task.project` at execution time. + val rootProject = rootProject + val repoName = target.name.replaceFirstChar { it.titlecase(Locale.ROOT) } + val supplier = tasks.register("supply${repoName}Credentials") { + group = SpineTaskGroup.name + description = "Obtains the credentials for publishing to the `${target.name}` repository" + notCompatibleWithConfigurationCache( + "Gradle does not support explicit repository credentials with the configuration cache." + ) + doLast { + val credentials = source.credentials(rootProject) + target.credentials { + username = credentials?.username + password = credentials?.password + } } } + tasks.withType().configureEach { + // The `maven-publish` plugin may assign the repository after this action runs, + // so the dependency is resolved later, when Gradle builds the task graph. + dependsOn(Callable { if (repository === target) supplier else null }) + } } diff --git a/buildSrc/src/main/kotlin/io/spine/gradle/publish/PublicationSbom.kt b/buildSrc/src/main/kotlin/io/spine/gradle/publish/PublicationSbom.kt new file mode 100644 index 0000000..b6d3817 --- /dev/null +++ b/buildSrc/src/main/kotlin/io/spine/gradle/publish/PublicationSbom.kt @@ -0,0 +1,724 @@ +/* + * Copyright 2026 CodeMatters, Lda. + * + * 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. + */ + +// The steps of registering the SBOMs of the publications belong together. +@file:Suppress("TooManyFunctions") + +package io.spine.gradle.publish + +import DocumentationSettings +import io.spine.gradle.SpineTaskGroup +import java.io.File +import java.net.URI +import java.util.Locale +import org.gradle.api.Project +import org.gradle.api.artifacts.Configuration +import org.gradle.api.artifacts.ModuleVersionIdentifier +import org.gradle.api.artifacts.component.ComponentIdentifier +import org.gradle.api.artifacts.result.ResolvedComponentResult +import org.gradle.api.artifacts.result.ResolvedDependencyResult +import org.gradle.api.provider.Provider +import org.gradle.api.publish.maven.MavenPublication +import org.gradle.api.tasks.TaskProvider +import org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformExtension +import org.jetbrains.kotlin.gradle.plugin.KotlinPlatformType +import org.jetbrains.kotlin.gradle.plugin.KotlinTarget +import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinNativeTarget +import org.spdx.sbom.gradle.SpdxSbomExtension +import org.spdx.sbom.gradle.SpdxSbomPlugin +import org.spdx.sbom.gradle.SpdxSbomTask +import org.spdx.sbom.gradle.extensions.DefaultSpdxSbomTaskExtension + +/** + * Publishes a Software Bill of Materials (SBOM) with each artifact of this build. + * + * Usage: + * ``` + * PublicationSbom.registerTasks(project, projectsToPublish) + * ``` + * + * The SBOM is an SPDX 2.3 document, written by the + * [SPDX Gradle Plugin](https://github.com/spdx/spdx-gradle-plugin) and completed by + * [PublicationSbomTask]. It lists what an artifact depends on at runtime — never the + * build tooling, nor the libraries used only to test it. Being published next to the + * artifact, as `-.spdx.json`, it enters the manifest of + * [PublicationChecksums], so the provenance attestation covers it too. It leaves the + * packaging the POM declares as it is. + * + * ## One SBOM per published artifact + * + * Each publication gets an SBOM of its own, named after the artifact it publishes. The + * publications of a JVM module describe the same dependencies — its `runtimeClasspath` — + * unless one describes its SBOM itself, as the next section tells. + * A Kotlin Multiplatform module publishes an artifact per target, so the SBOM of each + * target publication describes the dependencies of that target — except for an Android + * target compiled per build variant, which gets none yet, with a warning. The + * `kotlinMultiplatform` umbrella publication has no runtime of its own, and gets none. + * A Kotlin/Native compilation has no runtime configuration either: its klibs are linked + * into the binary of the consumer, so the SBOM of a Native target describes the + * dependencies of its compilation instead. + * + * The Gradle Plugin Portal does not receive the SBOM: its upload skips files other than + * JARs, so the SBOM of a Gradle plugin is published to the Maven repositories only. + * A plugin marker publication consists of a POM alone, and gets no SBOM. + * + * ## Publications of files + * + * A publication made from a software component has the dependencies of its module, as + * its POM does. A publication of a file, made with `artifact(...)`, publishes what its + * module makes of it: a POM written by hand, other modules and libraries packed into + * a JAR. So its module [describes][MavenPublication.sbom] what the SBOM lists: which + * configuration holds the dependencies of the artifact, and what the artifact bundles. + * The SBOM relates the artifact to each of its dependencies by `DEPENDS_ON`, and to each + * component bundled into it by `CONTAINS`, leaving out what it neither depends on nor + * bundles. `uber-jar-module` describes its fat JAR this way. + * + * ## Naming the modules of this build + * + * The plugin lists a module of this build under the name of its Gradle project, with + * neither a license nor a package URL — `client` rather than `io.spine:spine-client`. + * [PublicationSbomTask] renames it after the publication of the module. The coordinates + * are collected once all projects are evaluated, when the publications no longer change, + * and handed to the tasks as plain values — so that no task reads the state of another + * project while it runs. + */ +internal object PublicationSbom { + + /** + * The name of the task writing every SBOM a module publishes. + * + * The SBOM of each publication is written by a task of its own, named by [taskNameFor]. + */ + const val taskName = "publicationSbom" + + /** + * The name of the SPDX target describing a JVM module. + */ + private const val moduleUnit = "publication" + + /** + * The extension of a published SBOM, as in `-.spdx.json`. + */ + private const val sbomExtension = "spdx.json" + + /** + * The [platform][KotlinTarget.platform] under which a JVM module looks up the modules + * it depends on. + * + * A JVM module resolves a multiplatform sibling to the artifact of its JVM target. + */ + private val jvmPlatform = KotlinPlatformType.jvm.name + + /** + * The organization supplying the published artifacts, as SPDX writes one. + * + * Matches the `Implementation-Vendor` in the manifest of each published JAR, + * which `write-manifest.gradle.kts` sets. + */ + private const val spineSupplier = "Organization: CodeMatters, Lda." + + /** + * The commit recorded in the SBOM of a local build. + * + * GitHub Actions supplies `GITHUB_SHA` to every workflow, so a published SBOM names + * the actual commit. A fixed value keeps the inputs of the SBOM task of a local build + * stable, so the task stays up to date from one commit to the next. + */ + private const val unknownCommit = "unknown" + + /** + * Returns the name of the task writing the SBOM published with the given [publication]. + * + * The publication of a Kotlin Multiplatform target is named after the target. + */ + fun taskNameFor(publication: String): String = + publication + taskName.replaceFirstChar { it.titlecase(Locale.ROOT) } + + /** + * Registers the tasks writing the SBOMs of the given [published] projects, and adds + * the SBOMs to their publications. + * + * [host] is the project in which `spinePublishing { }` was opened. + * + * Whether a project is a JVM or a multiplatform module is known only once it is + * evaluated, so the registration waits until then. It is idempotent, because + * `spinePublishing { }` may reach one project twice, as the documentation of + * `getOrRegister` in `PublicationChecksums.kt` explains. + */ + fun registerTasks(host: Project, published: Set) { + published.forEach { project -> + project.afterEvaluate { registerUnits() } + } + host.rootProject.publishSbomsOnceEvaluated() + } + + /** + * Registers the SBOMs of this project, now that its plugins are known. + */ + private fun Project.registerUnits() { + val kotlin = extensions.findByType(KotlinMultiplatformExtension::class.java) + when { + kotlin != null -> kotlin.targets + .matching { it.platformType != KotlinPlatformType.common } + .configureEach { this@registerUnits.registerTargetUnit(this) } + + pluginManager.hasPlugin("java") -> registerSbom( + SbomUnit( + name = moduleUnit, + configuration = "runtimeClasspath", + platform = jvmPlatform, + publishedWith = { !it.isPluginMarker } + ) + ) + + else -> logger.info( + "No SBOM for `$path`: it is neither a JVM nor a Kotlin Multiplatform module." + ) + } + } + + /** + * Registers the SBOM of the given Kotlin Multiplatform [target] of this project. + * + * A target without a `main` compilation gets none, with a warning. An Android target + * declared with `androidTarget()` is one: it compiles per build variant, and publishes + * a publication per variant. No Spine module publishes one, and describing its variants + * would take the Android Gradle Plugin to test, so it is left out for now. + */ + private fun Project.registerTargetUnit(target: KotlinTarget) { + val main = target.compilations.findByName("main") + if (main == null) { + logger.warn( + "No SBOM is published with the `${target.name}` target of `$path`: it has" + + " no `main` compilation." + ) + return + } + val targetName = target.name + registerSbom( + SbomUnit( + name = targetName, + configuration = main.runtimeDependencyConfigurationName + ?: main.compileDependencyConfigurationName, + platform = target.platform, + publishedWith = { it.name == targetName } + ) + ) + } + + /** + * Configures the SPDX Gradle Plugin to describe the given [unit], and records the unit + * so that its SBOMs are [published][publishSbomsOnceEvaluated]. + */ + private fun Project.registerSbom(unit: SbomUnit) { + pluginManager.apply(SpdxSbomPlugin::class.java) + val spdx = extensions.getByType(SpdxSbomExtension::class.java) + if (spdx.targets.findByName(unit.name) != null) { + return + } + spdx.onlyUseLocalLicenses.set(true) + registerSpdxTarget(name = unit.name, configurationNames = listOf(unit.configuration)) + registerLifecycleTask() + sbomUnits().add(unit) + } + + /** + * Registers the SPDX target with the given [name], describing the configurations with + * the given names, unless it is registered already, and returns the task writing + * its document. + * + * The configuration of the plugin does not depend on the coordinates of the artifact, + * which are final only after the publications are set up: [PublicationSbomTask] puts + * them into the document instead. + */ + private fun Project.registerSpdxTarget( + name: String, + configurationNames: List + ): TaskProvider { + val spdx = extensions.getByType(SpdxSbomExtension::class.java) + if (spdx.targets.findByName(name) == null) { + val repository = DocumentationSettings.repoUrl(this) + val commit = providers.environmentVariable("GITHUB_SHA").orElse(unknownCommit) + spdx.targets.create(name) { + configurations.set(configurationNames) + document { + creator.set(spineSupplier) + packageSupplier.set(spineSupplier) + } + scm { + uri.set(repository) + revision.set(commit) + } + } + spdxTaskOf(name).configure { + taskExtension.set(NoAssertionForLocalRepositories()) + } + } + return spdxTaskOf(name) + } + + /** + * Registers the task writing the SBOM of the given [publication] of the [unit], and + * adds the SBOM to the publication. + * + * The SBOM is written from the document of the unit, unless the publication + * [describes][MavenPublication.sbom] what its SBOM lists. + * + * The SBOM is published without a classifier, as the SPDX Maven Plugin publishes one. + * Gradle would count such an artifact when calculating the packaging of the POM, so the + * packaging is [pinned][pinPackaging] before the SBOM is added. The POM then declares + * what it would without the SBOM: `jar` for a JAR rather than `pom`, and `pom` for + * a publication without a main artifact, such as a JAR classified `all` alone, rather + * than `spdx.json`. + * + * [published] holds the coordinates of the publications of this build, keyed as + * [PublicationSbomTask.publishedCoordinates] describes. + */ + private fun Project.publishSbom( + publication: MavenPublication, + unit: SbomUnit, + published: Map + ) { + val sbomTaskName = taskNameFor(publication.name) + if (tasks.names.contains(sbomTaskName)) { + return + } + val projectPath = path + val coordinates = publication.coordinates + val described = publication.sbomContent?.let { + describedSbom(publication = publication, unit = unit, content = it) + } + val generated = described?.spdxTask ?: spdxTaskOf(unit.name) + val output = layout.buildDirectory.file("sbom/${publication.name}.$sbomExtension") + val sbom = tasks.register(sbomTaskName, PublicationSbomTask::class.java) { + group = SpineTaskGroup.name + description = "Writes the SBOM published with the `${publication.name}`" + + " publication of `$projectPath`" + source.set(generated.flatMap { it.outputFile }) + modulePath.set(projectPath) + artifactCoordinates.set(coordinates) + platform.set(unit.platform) + publishedCoordinates.set(published) + described?.let { artifactComponents.set(it.components) } + outputFile.set(output) + } + publication.pinPackaging() + publication.artifact(sbom.flatMap { it.outputFile }) { + extension = sbomExtension + } + } + + /** + * Returns the SPDX document that the SBOM of the given [publication] is written from, + * and the components of its artifact, as the publication describes them by [content]. + * + * The document describes the configuration holding the dependencies of the artifact, + * followed by those in which its bundled content is found. In this order, the plugin + * relates the dependencies of the artifact as their own graph does. If these are + * the configuration of the [unit] alone, as for a fat JAR of the runtime classpath, + * the document of the unit serves. Otherwise, the publication gets one of its own. + * + * Nothing is resolved here. The components are resolved as the task writing the SBOM + * runs, and so is each configuration, by a task of its own project. A Shadow task + * bundling content is realized, though, to tell the configurations it packs; see + * [sourceOf]. + */ + private fun Project.describedSbom( + publication: MavenPublication, + unit: SbomUnit, + content: SbomContent + ): DescribedSbom { + val dependencies = content.dependenciesFrom + ?.also { requireResolvable(it, publication) } + ?: configurations.getByName(unit.configuration) + val bundles = content.bundles.map { sourceOf(it, publication) } + val configurationNames = (listOf(dependencies) + bundles.flatMap { it.configurations }) + .map { it.name } + .distinct() + val spdxTask = if (configurationNames == listOf(unit.configuration)) { + spdxTaskOf(unit.name) + } else { + registerSpdxTarget( + name = "${publication.name}Publication", + configurationNames = configurationNames + ) + } + val own = ComponentKey.ofProject(path) + val bundleComponents = bundles.map { it.components } + val bundled = combined(bundleComponents, emptySet()) { all, next -> all + next } + val components = dependencies.componentKeys().zip(bundled) { dependencyKeys, bundleKeys -> + ArtifactComponents(dependencies = dependencyKeys - own, bundled = bundleKeys - own) + } + return DescribedSbom(spdxTask = spdxTask, components = components) + } + + /** + * Registers the task writing every SBOM this project publishes, unless it is + * registered already. + */ + private fun Project.registerLifecycleTask() { + if (tasks.names.contains(taskName)) { + return + } + val projectPath = path + val sboms = tasks.withType(PublicationSbomTask::class.java) + tasks.register(taskName) { + group = SpineTaskGroup.name + description = "Writes every SBOM `$projectPath` publishes" + dependsOn(sboms) + } + } + + /** + * Publishes the SBOMs of the recorded units of every project once all projects are + * evaluated, with each publication of a unit. + * + * Only then are the publications final. Until then, a publication may still come or + * go: `java-gradle-plugin` adds `pluginMaven` in an `afterEvaluate` of its own, which + * a build may then remove. A unit records itself instead of registering a hook of its + * own, because a multiplatform target is registered in a callback, where Gradle allows + * no listener to be added. + * + * Registered once per build, on the root project. The coordinates of the publications + * are handed to the tasks as plain values, so no task reads a provider, nor the state + * of another project, while it runs. + */ + private fun Project.publishSbomsOnceEvaluated() { + val key = "io.spine.gradle.publish.sbomsPublishedOnceEvaluated" + val properties = extensions.extraProperties + if (properties.has(key)) { + return + } + properties.set(key, true) + val root = this + gradle.projectsEvaluated { + val published = root.collectPublishedCoordinates() + root.allprojects.forEach { module -> + val publications = module.mavenPublications() + val units = module.sbomUnits() + units.forEach { unit -> + publications.filter(unit.publishedWith).forEach { + module.publishSbom(publication = it, unit = unit, published = published) + } + } + module.warnOfUnpublishedSbomContent(publications, units) + } + } + } +} + +/** + * Warns of each of the given [publications] that [describes][MavenPublication.sbom] its + * SBOM, but gets no SBOM published with it by any of the [units] of this project. + * + * Such is a plugin marker, the umbrella publication of a Kotlin Multiplatform module, + * or a publication of a module that `spinePublishing` does not publish. + */ +private fun Project.warnOfUnpublishedSbomContent( + publications: Collection, + units: List +) { + publications + .filter { it.sbomContent != null } + .filterNot { publication -> units.any { it.publishedWith(publication) } } + .forEach { + logger.warn( + "The `${it.name}` publication of `$path` describes its SBOM," + + " but no SBOM is published with it." + ) + } +} + +/** + * The SPDX document the SBOM of a publication is written from, and the components of + * the artifact, as the publication [describes][MavenPublication.sbom] them. + */ +private class DescribedSbom( + + /** The task writing the document. */ + val spdxTask: TaskProvider, + + /** The components the artifact depends on, and those bundled into it. */ + val components: Provider +) + +/** + * The configurations in which a part of the content of an artifact is found, + * and the components of them bundled into the artifact. + */ +private class BundleSource( + + /** The configurations holding the content. */ + val configurations: List, + + /** The components bundled into the artifact, by their keys. */ + val components: Provider> +) + +/** + * Returns the configurations in which the given [bundle] of the content of the + * [publication] is found, and the components of them bundled into the artifact. + * + * A Shadow task bundles the components whose files its dependency filter leaves + * among its included dependencies. + * + * The Shadow task is realized, rather than its values being mapped from its provider. + * A value derived from the provider of a task may carry the task as its producer, which + * would make the task writing the SBOM build the fat JAR first. Realizing the task only + * runs its configuration. + */ +private fun Project.sourceOf(bundle: Bundle, publication: MavenPublication): BundleSource = + when (bundle) { + is Bundle.Components -> { + val configuration = bundle.configuration + requireResolvable(configuration, publication) + BundleSource(listOf(configuration), configuration.componentKeys()) + } + + is Bundle.Shadowed -> { + val task = bundle.task.get() + require(task.project.path == path) { + "${sbomOf(publication)} describes what `${task.path}` bundles," + + " a task of another project." + } + val configurations = task.configurations.get().toList() + configurations.forEach { requireResolvable(it, publication) } + val componentsByFiles = configurations.map { it.componentsByFile() } + val byFile = combined(componentsByFiles, emptyMap()) { all, next -> all + next } + val components = task.includedDependencies.elements.zip(byFile) { files, keys -> + files.mapNotNull { keys[it.asFile] }.toSet() + } + BundleSource(configurations, components) + } + } + +/** + * Ensures that the given [configuration], which the [publication] names in the + * description of its SBOM, belongs to this project and can be resolved. + * + * The SPDX Gradle Plugin looks a configuration up by its name in the project of + * the SBOM, and resolves it. + */ +private fun Project.requireResolvable( + configuration: Configuration, + publication: MavenPublication +) { + val subject = sbomOf(publication) + require(configurations.findByName(configuration.name) === configuration) { + "$subject names `${configuration.name}`, a configuration of another project." + } + require(configuration.isCanBeResolved) { + "$subject names `${configuration.name}`, which cannot be resolved." + } +} + +/** + * Returns how a message names the SBOM of the given [publication] of this project. + */ +private fun Project.sbomOf(publication: MavenPublication): String = + "The SBOM of the `${publication.name}` publication of `$path`" + +/** + * Returns the keys of the components in the dependency graph of this configuration, + * which it resolves as the value of the provider is obtained. + */ +private fun Configuration.componentKeys(): Provider> = + incoming.resolutionResult.rootComponent.map(::componentKeysFrom) + +/** + * Returns the keys of the components in the dependency graph of the given [root]. + */ +private fun componentKeysFrom(root: ResolvedComponentResult): Set { + val visited = mutableSetOf() + val queue = ArrayDeque(listOf(root)) + return buildSet { + while (queue.isNotEmpty()) { + val component = queue.removeFirst() + if (visited.add(component.id)) { + ComponentKey.of(component.id)?.let(::add) + component.dependencies + .filterIsInstance() + .forEach { queue.add(it.selected) } + } + } + } +} + +/** + * Returns the keys of the components whose files this configuration resolves, + * by the files. + */ +private fun Configuration.componentsByFile(): Provider> = + incoming.artifacts.resolvedArtifacts.map { artifacts -> + artifacts + .mapNotNull { artifact -> + ComponentKey.of(artifact.id.componentIdentifier)?.let { artifact.file to it } + } + .toMap() + } + +/** + * Returns a provider of the given [values] combined with the [combine] function, + * starting with the [empty] value. + */ +private fun Project.combined( + values: List>, + empty: T, + combine: (T, T) -> T +): Provider = + values.fold(providers.provider { empty }) { all, next -> all.zip(next, combine) } + +/** + * The coordinates of this publication, as `group:artifactId:version`. + */ +private val MavenPublication.coordinates: String + get() = "$groupId:$artifactId:$version" + +/** + * Stores the packaging Gradle calculates for the POM of this publication as an explicit + * value, so that artifacts added later do not change it. + * + * Until it is set explicitly, the packaging has no value of its own: Gradle calculates it + * from the artifacts of the publication whenever it is read, taking the extension of + * the only artifact without a classifier, or `pom` for none or several. Adding an artifact + * without a classifier therefore changes the packaging, unless an explicit value is set. + * A packaging the build has set explicitly is read back unchanged, and so it is kept. + * + * The packaging is calculated from the artifacts the publication has when it is read. + * For a publication made from a software component, the first read also takes + * the artifacts of the component into the publication for good. So the publication + * must be final by the time this function is called, as it is once all projects are evaluated. + */ +private fun MavenPublication.pinPackaging() { + // The explicit type makes this fail to compile, rather than set the packaging + // to itself, once Gradle turns `MavenPom.getPackaging()` into a lazy property. + val calculated: String = pom.packaging + pom.packaging = calculated +} + +/** + * Returns the coordinates of the Maven publications of this build that a module can + * depend on, keyed as [PublicationSbomTask.publishedCoordinates] describes. + */ +private fun Project.collectPublishedCoordinates(): Map = buildMap { + allprojects.forEach { module -> + val publications = module.mavenPublications().filterNot { it.isPluginMarker } + publications.singleOrNull()?.let { put(module.path, it.coordinates) } + module.targetPublications(publications).forEach { (platform, publication) -> + put(publicationKey(module.path, platform), publication.coordinates) + } + } +} + +/** + * Returns the publications of the Kotlin Multiplatform targets of this project among the + * given ones, keyed by the [platform][KotlinTarget.platform] of each target. + * + * A platform with several targets is left out: which of them a dependency resolves to + * depends on attributes that the platform does not capture. + */ +private fun Project.targetPublications( + publications: Collection +): Map { + val kotlin = extensions.findByType(KotlinMultiplatformExtension::class.java) + ?: return emptyMap() + val byName = publications.associateBy { it.name } + return kotlin.targets + .filter { it.platformType != KotlinPlatformType.common } + .groupBy { it.platform } + .mapNotNull { (platform, targets) -> + targets.singleOrNull()?.let { byName[it.name] }?.let { platform to it } + } + .toMap() +} + +/** + * The platform this target compiles for: the name of its platform type, such as `jvm`, + * followed by the Kotlin/Native target of a native one, as in `native:macos_arm64`. + * + * Gradle resolves a dependency on a multiplatform module to the artifact of its target + * for the platform of the consumer, however either target is named. + */ +private val KotlinTarget.platform: String + get() { + val native = attributes.getAttribute(KotlinNativeTarget.konanTargetAttribute) + return if (native == null) platformType.name else "${platformType.name}:$native" + } + +/** + * Returns the task the SPDX Gradle Plugin registers for the target with the given [name]. + */ +private fun Project.spdxTaskOf(name: String): TaskProvider = + tasks.named( + "spdxSbomFor${name.replaceFirstChar { it.titlecase(Locale.ROOT) }}", + SpdxSbomTask::class.java + ) + +/** + * Returns the units whose SBOMs this project publishes, as recorded so far. + * + * The list is attached to the project, so that it lives exactly as long as the build does. + * Holding it in [PublicationSbom] would share it between builds, which reuse a Gradle + * daemon and its class loaders. + */ +@Suppress("UNCHECKED_CAST" /* The property is written here and nowhere else. */) +private fun Project.sbomUnits(): MutableList { + val key = "io.spine.gradle.publish.sbomUnits" + val properties = extensions.extraProperties + if (!properties.has(key)) { + properties.set(key, mutableListOf()) + } + return properties.get(key) as MutableList +} + +/** + * The dependencies described by one SPDX target, and the publications whose SBOMs + * are written from that description. + */ +private class SbomUnit( + + /** Names the SPDX target. */ + val name: String, + + /** The configuration holding the dependencies of the artifacts. */ + val configuration: String, + + /** + * The [platform][KotlinTarget.platform] under which the modules of this build + * are looked up. + */ + val platform: String, + + /** Tells whether an SBOM of this unit is published with the given publication. */ + val publishedWith: (MavenPublication) -> Boolean +) + +private val noAssertion = URI.create("NOASSERTION") + +/** + * Leaves the download location of a dependency resolved from a local repository + * unasserted, keeping its package URL. + * + * The SPDX Gradle Plugin copies the URL of the repository a dependency comes from into + * the download location of its package. SPDX 2 accepts no `file:` URL there, and since + * version 0.12.0 the plugin fails the build on one — see + * [spdx-gradle-plugin#192](https://github.com/spdx/spdx-gradle-plugin/issues/192). + * Spine builds resolve modules from Maven Local, so any build using a locally published + * one would fail. A local path means nothing to the reader of a published SBOM anyway. + */ +private class NoAssertionForLocalRepositories : DefaultSpdxSbomTaskExtension() { + + override fun mapRepoUri(original: URI?, moduleId: ModuleVersionIdentifier): URI? = + if (original?.scheme == "file") noAssertion else original +} diff --git a/buildSrc/src/main/kotlin/io/spine/gradle/publish/PublicationSbomTask.kt b/buildSrc/src/main/kotlin/io/spine/gradle/publish/PublicationSbomTask.kt new file mode 100644 index 0000000..6542ae8 --- /dev/null +++ b/buildSrc/src/main/kotlin/io/spine/gradle/publish/PublicationSbomTask.kt @@ -0,0 +1,233 @@ +/* + * Copyright 2026 CodeMatters, Lda. + * + * 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 io.spine.gradle.publish + +import LicenseSettings +import com.fasterxml.jackson.databind.ObjectMapper +import com.fasterxml.jackson.databind.node.ObjectNode +import org.gradle.api.DefaultTask +import org.gradle.api.file.RegularFileProperty +import org.gradle.api.provider.MapProperty +import org.gradle.api.provider.Property +import org.gradle.api.tasks.Input +import org.gradle.api.tasks.InputFile +import org.gradle.api.tasks.Optional +import org.gradle.api.tasks.OutputFile +import org.gradle.api.tasks.PathSensitive +import org.gradle.api.tasks.PathSensitivity +import org.gradle.api.tasks.TaskAction +import org.gradle.work.DisableCachingByDefault + +/** + * Writes the SBOM published with an artifact, naming the modules of this build by + * the coordinates they are published under. + * + * The task rewrites the document that the SPDX Gradle Plugin writes for the dependencies + * of the artifact — which the publications of a module share, unless one describes its + * SBOM itself — into the SBOM of one [artifact][artifactCoordinates]: + * + * - if the publication describes its SBOM, the artifact contains each package bundled + * into it, rather than depending on it, and the packages the artifact neither depends + * on nor bundles are left out, as [artifactComponents] tell; + * - the document is named after the artifact, and given a namespace derived from its + * coordinates, in place of the placeholder the plugin leaves there; + * - each package describing a module of this build — the artifact itself, and each + * sibling module it depends on — declares the [license][LicenseSettings.spdxId] of + * the modules of this build, is named `group:artifactId`, and gets the version and + * the package URL of the published artifact. The package URL replaces the external + * references the plugin wrote, if any. The plugin lists such a module under the name + * of its Gradle project, with neither a license nor a package URL. + * + * A module of this build is recognized by the source information the plugin gives it, + * which ends with the path of the Gradle project in brackets; no other package has it. + * A sibling without a single Maven publication to name it after — typically a module + * bundled into the artifact of another one, such as a fat JAR — has no coordinates of + * its own: it only gets the license, and keeps the name of its project. + * + * @see PublicationSbom + */ +@DisableCachingByDefault(because = "Rewrites a small document; caching it would not pay off.") +internal abstract class PublicationSbomTask : DefaultTask() { + + /** + * The document written by the SPDX Gradle Plugin. + */ + @get:InputFile + @get:PathSensitive(PathSensitivity.NONE) + abstract val source: RegularFileProperty + + /** + * The path of the project whose artifact the SBOM describes. + */ + @get:Input + abstract val modulePath: Property + + /** + * The coordinates of the artifact the SBOM is published with, as + * `group:artifactId:version`. + */ + @get:Input + abstract val artifactCoordinates: Property + + /** + * The platform the described artifact is built for, such as `jvm`, or + * `native:macos_arm64` for a Kotlin/Native target. + * + * A multiplatform module publishes an artifact per target, and a dependency on it + * resolves to the artifact of its target for the platform being built, however the + * targets are named. So a module of this build that the described one depends on is + * looked up by its publication for this platform first. + */ + @get:Input + abstract val platform: Property + + /** + * The coordinates of the Maven publications of this build that a module can depend on, + * as `group:artifactId:version`. + * + * The publication of a Kotlin Multiplatform target is keyed by [publicationKey], with + * the [platform] of the target. The only non-marker publication of a project is keyed + * by the path of that project alone. + */ + @get:Input + abstract val publishedCoordinates: MapProperty + + /** + * The components the artifact depends on, and those bundled into it, if its + * publication [describes][sbom] what its SBOM lists. + * + * Absent for any other publication, whose SBOM relates the artifact to the packages + * as the plugin does: to each as a dependency. + */ + @get:Optional + @get:Input + abstract val artifactComponents: Property + + /** + * The SBOM to publish. + */ + @get:OutputFile + abstract val outputFile: RegularFileProperty + + @TaskAction + fun writeSbom() { + val mapper = ObjectMapper() + val file = source.get().asFile + val document = mapper.readTree(file) as? ObjectNode + ?: error("`$file` is not an SPDX JSON document.") + artifactComponents.orNull?.describeIn(document, logger) + val published = publishedCoordinates.get() + val own = Coordinates.parse(artifactCoordinates.get()) + document.put(SpdxField.name, own.artifactId) + document.put(SpdxField.documentNamespace, own.namespace) + document[SpdxField.packages] + ?.filterIsInstance() + ?.forEach { describeModule(pkg = it, own = own, published = published) } + mapper.writerWithDefaultPrettyPrinter().writeValue(outputFile.get().asFile, document) + } + + /** + * Describes the given package as the module of this build it stands for, if it stands + * for one: by the license of this build and, if the module has a single Maven + * publication to name it after, by the coordinates of that publication. + * + * Any other package is left as the plugin wrote it. + */ + private fun describeModule( + pkg: ObjectNode, + own: Coordinates, + published: Map + ) { + val path = pkg[SpdxField.sourceInfo]?.asText()?.let(::projectPathIn) ?: return + pkg.put(SpdxField.licenseDeclared, LicenseSettings.spdxId) + val module = if (path == modulePath.get()) own else published.lookUp(path, platform.get()) + if (module == null) { + logger.info( + "The SBOM of `${modulePath.get()}` lists the project `$path` under its" + + " project name: the project has no single Maven publication" + + " to name it after." + ) + return + } + pkg.put(SpdxField.name, module.name) + pkg.put(SpdxField.versionInfo, module.version) + pkg.putArray(SpdxField.externalRefs).addObject().apply { + put(SpdxField.referenceCategory, "PACKAGE-MANAGER") + put(SpdxField.referenceLocator, module.purl) + put(SpdxField.referenceType, "purl") + } + } +} + +/** + * Returns the key under which [PublicationSbomTask.publishedCoordinates] holds the + * publication of the project with the given path for the given [platform]. + */ +internal fun publicationKey(projectPath: String, platform: String): String = + "$projectPath#$platform" + +/** + * Returns the coordinates of the project with the given [path], preferring its + * publication for the given [platform], or `null` if the project has neither that + * publication nor a single one. + */ +private fun Map.lookUp(path: String, platform: String): Coordinates? = + (get(publicationKey(path, platform)) ?: get(path))?.let(Coordinates::parse) + +/** + * Matches the path of a Gradle project at the end of the source information that the + * SPDX Gradle Plugin writes for a module of this build: `git+@#[]`. + */ +private val projectPathSuffix = Regex("""\[(:[^\[\]]*)]$""") + +/** + * Returns the path of the Gradle project named in the given source information, + * or `null` if the information does not name one. + */ +internal fun projectPathIn(sourceInfo: String): String? = + projectPathSuffix.find(sourceInfo)?.groupValues?.get(1) + +/** + * The Maven coordinates of a published artifact. + */ +private data class Coordinates(val group: String, val artifactId: String, val version: String) { + + /** The name of the SPDX package describing the artifact. */ + val name: String get() = "$group:$artifactId" + + /** The package URL of the artifact. */ + val purl: String get() = "pkg:maven/$group/$artifactId@$version" + + /** The namespace of the SPDX document describing the artifact. */ + val namespace: String get() = "https://spine.io/spdxdocs/$group/$artifactId/$version" + + companion object { + + /** The number of parts in `group:artifactId:version`. */ + private const val partCount = 3 + + /** + * Parses coordinates written as `group:artifactId:version`. + */ + fun parse(value: String): Coordinates { + val parts = value.split(':') + require(parts.size == partCount) { + "Expected Maven coordinates as `group:artifactId:version`, got `$value`." + } + val (group, artifactId, version) = parts + return Coordinates(group = group, artifactId = artifactId, version = version) + } + } +} diff --git a/buildSrc/src/main/kotlin/io/spine/gradle/publish/PublishingExts.kt b/buildSrc/src/main/kotlin/io/spine/gradle/publish/PublishingExts.kt index 279a68a..5a876d2 100644 --- a/buildSrc/src/main/kotlin/io/spine/gradle/publish/PublishingExts.kt +++ b/buildSrc/src/main/kotlin/io/spine/gradle/publish/PublishingExts.kt @@ -1,27 +1,15 @@ /* - * Copyright 2026, TeamDev. All rights reserved. + * Copyright 2026 CodeMatters, Lda. * - * 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 + * 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 * - * Redistribution and use in source and/or binary forms, with or without - * modification, must retain the above copyright notice and the following - * disclaimer. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 io.spine.gradle.publish @@ -61,6 +49,26 @@ internal val Project.publishingExtension: PublishingExtension internal val Project.publications: PublicationContainer get() = publishingExtension.publications +/** + * Returns the Maven publications of this project, or an empty collection if + * the project does not publish. + */ +internal fun Project.mavenPublications(): Collection { + val publishing = extensions.findByType(PublishingExtension::class.java) + ?: return emptyList() + return publishing.publications.withType(MavenPublication::class.java) +} + +/** + * Tells whether this publication is the marker of a Gradle plugin, which consists + * of a POM pointing at the publication of the plugin. + * + * Gradle's `java-gradle-plugin` creates a marker for each declared plugin, naming + * the publication after the plugin with the `PluginMarkerMaven` suffix. + */ +internal val MavenPublication.isPluginMarker: Boolean + get() = name.endsWith("PluginMarkerMaven") + /** * Obtains an instance, if available, of [SpinePublishing] extension * applied to this project. @@ -195,7 +203,19 @@ private fun TaskContainer.registerCheckCredentialsTask( } } +/** + * Adds an action that fails this task if any of the [destinations] has no credentials. + * + * The action obtains the credentials with the [Project] of this task. The project is + * captured when this function runs, at configuration time, because Gradle deprecates + * calling [Task.getProject] at execution time. The configuration cache cannot store + * a project, though, so the task is not compatible with it. + */ private fun Task.doLastCredentialsCheck(destinations: Set) { + val project = project + notCompatibleWithConfigurationCache( + "Obtaining the credentials of a repository requires the `Project`." + ) doLast { if (logger.isDebugEnabled) { val isSnapshot = project.version.toString().isSnapshot() diff --git a/buildSrc/src/main/kotlin/io/spine/gradle/publish/PublishingRepos.kt b/buildSrc/src/main/kotlin/io/spine/gradle/publish/PublishingRepos.kt index 87d3352..26c5533 100644 --- a/buildSrc/src/main/kotlin/io/spine/gradle/publish/PublishingRepos.kt +++ b/buildSrc/src/main/kotlin/io/spine/gradle/publish/PublishingRepos.kt @@ -1,27 +1,15 @@ /* - * Copyright 2026, TeamDev. All rights reserved. + * Copyright 2026 CodeMatters, Lda. * - * 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 + * 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 * - * Redistribution and use in source and/or binary forms, with or without - * modification, must retain the above copyright notice and the following - * disclaimer. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 io.spine.gradle.publish diff --git a/buildSrc/src/main/kotlin/io/spine/gradle/publish/SbomContent.kt b/buildSrc/src/main/kotlin/io/spine/gradle/publish/SbomContent.kt new file mode 100644 index 0000000..1bb153a --- /dev/null +++ b/buildSrc/src/main/kotlin/io/spine/gradle/publish/SbomContent.kt @@ -0,0 +1,167 @@ +/* + * Copyright 2026 CodeMatters, Lda. + * + * 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 io.spine.gradle.publish + +import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar +import org.gradle.api.artifacts.Configuration +import org.gradle.api.plugins.ExtensionAware +import org.gradle.api.publish.maven.MavenPublication +import org.gradle.api.tasks.TaskProvider + +/** + * Describes what the SBOM published with this publication lists. + * + * A publication made from a software component, such as `components["java"]`, needs + * no description: its SBOM lists the runtime dependencies of its module, as its POM + * does. A publication of a file made with `artifact(...)` publishes what its module + * makes of it — a POM written by hand, content packed into a JAR — and tells its SBOM + * the same: + * + * ```kotlin + * publishing { + * publications { + * create("fatJar") { + * artifact(tasks.shadowJar) + * sbom { + * dependencies(fatJarDependencies) + * bundled(tasks.shadowJar) + * } + * } + * } + * } + * ``` + * + * The SBOM describes each dependency of the artifact by a `DEPENDS_ON` relationship, + * and each component bundled into it by a `CONTAINS` one. A bundled component is not + * a dependency of the artifact, even if it is also among its + * [dependencies][SbomContent.dependencies]. + * + * A later call continues the description of the earlier ones: the content it tells to be + * [bundled][SbomContent.bundled] adds to theirs, while a configuration it gives to + * [dependencies][SbomContent.dependencies] replaces theirs. + * + * @see PublicationSbom + */ +fun MavenPublication.sbom(configure: SbomContent.() -> Unit) { + val extensions = (this as? ExtensionAware)?.extensions + ?: error("The publication `$name` cannot hold the description of its SBOM.") + val content = extensions.findByType(SbomContent::class.java) + ?: SbomContent().also { extensions.add(SbomContent::class.java, EXTENSION_NAME, it) } + content.configure() +} + +/** + * The description of the SBOM of this publication, or `null` if the publication + * has none. + */ +internal val MavenPublication.sbomContent: SbomContent? + get() = (this as? ExtensionAware)?.extensions?.findByType(SbomContent::class.java) + +/** + * The name under which a publication holds the description of its SBOM. + */ +private const val EXTENSION_NAME = "sbomContent" + +/** + * What the SBOM published with a publication lists, as described by + * [MavenPublication.sbom]. + */ +class SbomContent internal constructor() { + + /** + * The configuration whose dependency graph the artifact depends on, or `null` + * if it depends on the runtime classpath of its module. + */ + internal var dependenciesFrom: Configuration? = null + private set + + private val bundleList = mutableListOf() + + /** + * The parts of the content of the artifact, as given to [bundled]. + */ + internal val bundles: List + get() = bundleList + + /** + * Tells that the artifact depends on the dependency graph of the given + * [configuration], rather than on the runtime classpath of its module. + * + * The configuration must belong to the module of the publication, and be + * resolvable. It holds what the POM of the publication declares, so that the POM + * could be written from it. It needs the attributes of `runtimeClasspath`, so that + * it resolves the same variants of the modules it holds. + * + * A sibling module published as a fat JAR belongs in it non-transitively, as in + * `project(":fat") { isTransitive = false }`. Its own dependencies are bundled into + * its artifact, and not dependencies of the artifact depending on it. + * + * A later call replaces the configuration an earlier one gave. + */ + fun dependencies(configuration: Configuration) { + dependenciesFrom = configuration + } + + /** + * Tells that the artifact bundles each component of the given [configuration]. + * + * Suits a JAR packing the classes of other modules into itself, as + * `from(zipTree(...))` does. The configuration must belong to the module of + * the publication, and be resolvable. + * + * Adds to the content that earlier calls tell to be bundled. + */ + fun bundled(configuration: Configuration) { + bundleList.add(Bundle.Components(configuration)) + } + + /** + * Tells that the artifact bundles what the given Shadow [task] packs from its + * configurations: the dependencies its dependency filter leaves in. + * + * The SBOM learns what the task packs from those dependencies alone, so it + * does not see: + * - entries the task leaves out by their path — the modules they come from + * are still described as bundled; + * - classes that `minimize()` removes; + * - content added with `from(...)`; + * - file dependencies, which are not components. + * + * So a module that the POM declares, rather than the JAR bundling it, is to be + * excluded by the dependency filter of the task, and not by the paths of its + * entries. Otherwise, the SBOM describes the module as bundled. + * + * Adds to the content that earlier calls tell to be bundled. + */ + fun bundled(task: TaskProvider) { + bundleList.add(Bundle.Shadowed(task)) + } +} + +/** + * A part of the content of an artifact. + */ +internal sealed interface Bundle { + + /** + * Each component of the [configuration]. + */ + class Components(val configuration: Configuration) : Bundle + + /** + * What the Shadow [task] packs from its configurations. + */ + class Shadowed(val task: TaskProvider) : Bundle +} diff --git a/buildSrc/src/main/kotlin/io/spine/gradle/publish/ShadowJarExts.kt b/buildSrc/src/main/kotlin/io/spine/gradle/publish/ShadowJarExts.kt index 0fa60fd..a97955f 100644 --- a/buildSrc/src/main/kotlin/io/spine/gradle/publish/ShadowJarExts.kt +++ b/buildSrc/src/main/kotlin/io/spine/gradle/publish/ShadowJarExts.kt @@ -1,27 +1,15 @@ /* - * Copyright 2026, TeamDev. All rights reserved. + * Copyright 2026 CodeMatters, Lda. * - * 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 + * 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 * - * Redistribution and use in source and/or binary forms, with or without - * modification, must retain the above copyright notice and the following - * disclaimer. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. */ @file:Suppress("ConstPropertyName") diff --git a/buildSrc/src/main/kotlin/io/spine/gradle/publish/SpdxField.kt b/buildSrc/src/main/kotlin/io/spine/gradle/publish/SpdxField.kt new file mode 100644 index 0000000..418c44e --- /dev/null +++ b/buildSrc/src/main/kotlin/io/spine/gradle/publish/SpdxField.kt @@ -0,0 +1,44 @@ +/* + * Copyright 2026 CodeMatters, Lda. + * + * 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 io.spine.gradle.publish + +/** + * The names of the fields of an SPDX 2.3 JSON document that the SBOM published with + * an artifact is written by. + * + * @see PublicationSbomTask + */ +@Suppress("ConstPropertyName") // https://bit.ly/kotlin-prop-names +internal object SpdxField { + const val name = "name" + const val documentNamespace = "documentNamespace" + const val packages = "packages" + const val relationships = "relationships" + const val hasExtractedLicensingInfos = "hasExtractedLicensingInfos" + const val licenseId = "licenseId" + const val spdxId = "SPDXID" + const val sourceInfo = "sourceInfo" + const val versionInfo = "versionInfo" + const val licenseConcluded = "licenseConcluded" + const val licenseDeclared = "licenseDeclared" + const val licenseInfoFromFiles = "licenseInfoFromFiles" + const val externalRefs = "externalRefs" + const val referenceCategory = "referenceCategory" + const val referenceLocator = "referenceLocator" + const val referenceType = "referenceType" + const val spdxElementId = "spdxElementId" + const val relationshipType = "relationshipType" + const val relatedSpdxElement = "relatedSpdxElement" +} diff --git a/buildSrc/src/main/kotlin/io/spine/gradle/publish/SpinePublishing.kt b/buildSrc/src/main/kotlin/io/spine/gradle/publish/SpinePublishing.kt index 2d778a8..033df0c 100644 --- a/buildSrc/src/main/kotlin/io/spine/gradle/publish/SpinePublishing.kt +++ b/buildSrc/src/main/kotlin/io/spine/gradle/publish/SpinePublishing.kt @@ -1,27 +1,15 @@ /* - * Copyright 2026, TeamDev. All rights reserved. + * Copyright 2026 CodeMatters, Lda. * - * 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 + * 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 * - * Redistribution and use in source and/or binary forms, with or without - * modification, must retain the above copyright notice and the following - * disclaimer. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. */ @file:Suppress("TooManyFunctions") @@ -80,7 +68,6 @@ import org.gradle.kotlin.dsl.findByType * This code works for most of the projects. * * ### Arranging custom publishing for a module - * ```kotlin * * 1. Modify the list of standardly published modules in the root project like this: * @@ -99,6 +86,10 @@ import org.gradle.kotlin.dsl.findByType * ``` * 2. Arrange the custom publishing in the `my-custom-module` project. * + * 3. For a publication of a file made with `artifact(...)`, rather than of a software component, + * describe what its SBOM lists by calling [sbom] on the publication: the configuration holding + * the dependencies its POM declares, and what the artifact bundles. + * * ## Using in a single-module project * * When used with a single-module project, the extension should be opened in a project's build file. @@ -194,7 +185,7 @@ open class SpinePublishing(private val project: Project) { /** * The name of the extension registered in a Gradle project. */ - public val extensionName: String = SpinePublishing::class.java.simpleName + val extensionName: String = SpinePublishing::class.java.simpleName .replaceFirstChar { it.lowercase(Locale.ROOT) } } @@ -336,6 +327,8 @@ open class SpinePublishing(private val project: Project) { val jarFlags = JarFlags.create(project.name, testJar) project.setUpPublishing(jarFlags) } + PublicationChecksums.registerTasks(project, projectsToPublish) + PublicationSbom.registerTasks(project, projectsToPublish) } /** @@ -409,7 +402,7 @@ open class SpinePublishing(private val project: Project) { private fun Project.publishTo(): Set { val ext = localSpinePublishing if (ext != null && ext::destinations.isInitialized) { - return destinations + return ext.destinations } return parent?.publishTo() ?: emptySet() } diff --git a/buildSrc/src/main/kotlin/io/spine/gradle/publish/StandardJavaPublicationHandler.kt b/buildSrc/src/main/kotlin/io/spine/gradle/publish/StandardJavaPublicationHandler.kt index 178bf72..f17170a 100644 --- a/buildSrc/src/main/kotlin/io/spine/gradle/publish/StandardJavaPublicationHandler.kt +++ b/buildSrc/src/main/kotlin/io/spine/gradle/publish/StandardJavaPublicationHandler.kt @@ -1,27 +1,15 @@ /* - * Copyright 2026, TeamDev. All rights reserved. + * Copyright 2026 CodeMatters, Lda. * - * 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 + * 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 * - * Redistribution and use in source and/or binary forms, with or without - * modification, must retain the above copyright notice and the following - * disclaimer. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 io.spine.gradle.publish diff --git a/buildSrc/src/main/kotlin/io/spine/gradle/repo/Credentials.kt b/buildSrc/src/main/kotlin/io/spine/gradle/repo/Credentials.kt index c1e7f02..e253b00 100644 --- a/buildSrc/src/main/kotlin/io/spine/gradle/repo/Credentials.kt +++ b/buildSrc/src/main/kotlin/io/spine/gradle/repo/Credentials.kt @@ -1,27 +1,15 @@ /* - * Copyright 2026, TeamDev. All rights reserved. + * Copyright 2026 CodeMatters, Lda. * - * 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 + * 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 * - * Redistribution and use in source and/or binary forms, with or without - * modification, must retain the above copyright notice and the following - * disclaimer. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 io.spine.gradle.repo diff --git a/buildSrc/src/main/kotlin/io/spine/gradle/repo/RepoSlug.kt b/buildSrc/src/main/kotlin/io/spine/gradle/repo/RepoSlug.kt index 45f3c31..5f491f0 100644 --- a/buildSrc/src/main/kotlin/io/spine/gradle/repo/RepoSlug.kt +++ b/buildSrc/src/main/kotlin/io/spine/gradle/repo/RepoSlug.kt @@ -1,27 +1,15 @@ /* - * Copyright 2026, TeamDev. All rights reserved. + * Copyright 2026 CodeMatters, Lda. * - * 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 + * 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 * - * Redistribution and use in source and/or binary forms, with or without - * modification, must retain the above copyright notice and the following - * disclaimer. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 io.spine.gradle.repo diff --git a/buildSrc/src/main/kotlin/io/spine/gradle/repo/Repositories.kt b/buildSrc/src/main/kotlin/io/spine/gradle/repo/Repositories.kt index 8877dc6..c552dd4 100644 --- a/buildSrc/src/main/kotlin/io/spine/gradle/repo/Repositories.kt +++ b/buildSrc/src/main/kotlin/io/spine/gradle/repo/Repositories.kt @@ -1,27 +1,15 @@ /* - * Copyright 2026, TeamDev. All rights reserved. + * Copyright 2026 CodeMatters, Lda. * - * 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 + * 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 * - * Redistribution and use in source and/or binary forms, with or without - * modification, must retain the above copyright notice and the following - * disclaimer. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. */ @file:Suppress("TooManyFunctions") // Deprecated functions will be kept for a while. @@ -123,14 +111,21 @@ fun RepositoryHandler.standardToSpineSdk() { mavenCentral { excludeSpine() } gradlePluginPortal { excludeSpine() } - spineArtifacts() - + // + // Spine repositories. Gradle fetches a module's artifacts only from the repository + // that served its metadata. If that repository drops the artifacts after a build + // cached the metadata, later builds fail instead of falling through to the next one. + // + // Google Artifact Registry retains old versions, so it comes first. `CloudRepo` + // serves only earlier versions. GitHub Packages comes last: a scheduled workflow + // keeps only the newest snapshots of each package there. + // @Suppress("DEPRECATION") // Still use `CloudRepo` for earlier versions. val spineRepos = listOf( - Repos.spine, - Repos.spineSnapshots, Repos.artifactRegistry, - Repos.artifactRegistrySnapshots + Repos.artifactRegistrySnapshots, + Repos.spine, + Repos.spineSnapshots ) spineRepos @@ -142,6 +137,8 @@ fun RepositoryHandler.standardToSpineSdk() { } } + spineArtifacts() + // IntelliJ Platform repositories. `intellijReleases` serves the platform // artifacts (`com.jetbrains.intellij.*`); `intellijDependencies` serves the // repackaged third-party dependencies (`org.jetbrains.intellij.deps.*` and diff --git a/buildSrc/src/main/kotlin/io/spine/gradle/repo/Repository.kt b/buildSrc/src/main/kotlin/io/spine/gradle/repo/Repository.kt index d345725..8e747f3 100644 --- a/buildSrc/src/main/kotlin/io/spine/gradle/repo/Repository.kt +++ b/buildSrc/src/main/kotlin/io/spine/gradle/repo/Repository.kt @@ -1,27 +1,15 @@ /* - * Copyright 2026, TeamDev. All rights reserved. + * Copyright 2026 CodeMatters, Lda. * - * 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 + * 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 * - * Redistribution and use in source and/or binary forms, with or without - * modification, must retain the above copyright notice and the following - * disclaimer. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 io.spine.gradle.repo @@ -41,6 +29,10 @@ import org.gradle.api.Project * @param credentialsFile The path to the file that contains the credentials for the registry. * @param credentialValues The function to obtain an instance of [Credentials] from * a Gradle [Project], if [credentialsFile] is not specified. + * Publishing calls it only at execution time, so it may start an external process. + * It may be called several times for each published module, but never concurrently. + * It must not wait for the state of any project, e.g., resolve a configuration: + * the calls hold a lock that the tasks of all projects share. */ data class Repository( private val name: String, @@ -52,6 +44,11 @@ data class Repository( companion object { val regex = Regex("[A-Za-z0-9_\\-.]+") + + /** + * Serializes obtaining the credentials of all repositories (see [credentials]). + */ + private val credentialsLock = Any() } init { @@ -88,13 +85,22 @@ data class Repository( * If the credentials are represented by a `.properties` file, reads the file and parses * the credentials. The file must have properties `user.name` and `user.password`, which store * the username and the password for the Maven repository auth. + * + * Call this function from a task action rather than at configuration time: + * obtaining the credentials may start an external process, such as `gcloud`. + * + * The calls are serialized. Tasks of several projects may call it at once, and + * obtaining the credentials may write files that other calls share, e.g., + * the GitHub Packages token unpacked into the build directory of the given project. */ - fun credentials(project: Project): Credentials? = when { - credentialValues != null -> credentialValues.invoke(project) - credentialsFile != null -> credsFromFile(credentialsFile, project) - else -> throw IllegalArgumentException( - "Credentials file or a supplier function should be passed." - ) + fun credentials(project: Project): Credentials? = synchronized(credentialsLock) { + when { + credentialValues != null -> credentialValues.invoke(project) + credentialsFile != null -> credsFromFile(credentialsFile, project) + else -> throw IllegalArgumentException( + "Credentials file or a supplier function should be passed." + ) + } } private fun credsFromFile(fileName: String, project: Project): Credentials? { diff --git a/buildSrc/src/main/kotlin/io/spine/gradle/report/coverage/KoverConfig.kt b/buildSrc/src/main/kotlin/io/spine/gradle/report/coverage/KoverConfig.kt index ff5cb81..b2f1d16 100644 --- a/buildSrc/src/main/kotlin/io/spine/gradle/report/coverage/KoverConfig.kt +++ b/buildSrc/src/main/kotlin/io/spine/gradle/report/coverage/KoverConfig.kt @@ -1,27 +1,15 @@ /* - * Copyright 2026, TeamDev. All rights reserved. + * Copyright 2026 CodeMatters, Lda. * - * 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 + * 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 * - * Redistribution and use in source and/or binary forms, with or without - * modification, must retain the above copyright notice and the following - * disclaimer. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 io.spine.gradle.report.coverage diff --git a/buildSrc/src/main/kotlin/io/spine/gradle/report/coverage/SiblingCoverage.kt b/buildSrc/src/main/kotlin/io/spine/gradle/report/coverage/SiblingCoverage.kt index 69a42c5..7a2049a 100644 --- a/buildSrc/src/main/kotlin/io/spine/gradle/report/coverage/SiblingCoverage.kt +++ b/buildSrc/src/main/kotlin/io/spine/gradle/report/coverage/SiblingCoverage.kt @@ -1,27 +1,15 @@ /* - * Copyright 2026, TeamDev. All rights reserved. + * Copyright 2026 CodeMatters, Lda. * - * 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 + * 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 * - * Redistribution and use in source and/or binary forms, with or without - * modification, must retain the above copyright notice and the following - * disclaimer. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 io.spine.gradle.report.coverage diff --git a/buildSrc/src/main/kotlin/io/spine/gradle/report/license/Configuration.kt b/buildSrc/src/main/kotlin/io/spine/gradle/report/license/Configuration.kt index 32b7298..3fd7c59 100644 --- a/buildSrc/src/main/kotlin/io/spine/gradle/report/license/Configuration.kt +++ b/buildSrc/src/main/kotlin/io/spine/gradle/report/license/Configuration.kt @@ -1,27 +1,15 @@ /* - * Copyright 2026, TeamDev. All rights reserved. + * Copyright 2026 CodeMatters, Lda. * - * 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 + * 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 * - * Redistribution and use in source and/or binary forms, with or without - * modification, must retain the above copyright notice and the following - * disclaimer. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 io.spine.gradle.report.license diff --git a/buildSrc/src/main/kotlin/io/spine/gradle/report/license/LicenseReporter.kt b/buildSrc/src/main/kotlin/io/spine/gradle/report/license/LicenseReporter.kt index 7908b10..65d8d69 100644 --- a/buildSrc/src/main/kotlin/io/spine/gradle/report/license/LicenseReporter.kt +++ b/buildSrc/src/main/kotlin/io/spine/gradle/report/license/LicenseReporter.kt @@ -1,27 +1,15 @@ /* - * Copyright 2026, TeamDev. All rights reserved. + * Copyright 2026 CodeMatters, Lda. * - * 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 + * 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 * - * Redistribution and use in source and/or binary forms, with or without - * modification, must retain the above copyright notice and the following - * disclaimer. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 io.spine.gradle.report.license diff --git a/buildSrc/src/main/kotlin/io/spine/gradle/report/license/MarkdownReportRenderer.kt b/buildSrc/src/main/kotlin/io/spine/gradle/report/license/MarkdownReportRenderer.kt index 62fbf72..9d3a1c7 100644 --- a/buildSrc/src/main/kotlin/io/spine/gradle/report/license/MarkdownReportRenderer.kt +++ b/buildSrc/src/main/kotlin/io/spine/gradle/report/license/MarkdownReportRenderer.kt @@ -1,27 +1,15 @@ /* - * Copyright 2026, TeamDev. All rights reserved. + * Copyright 2026 CodeMatters, Lda. * - * 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 + * 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 * - * Redistribution and use in source and/or binary forms, with or without - * modification, must retain the above copyright notice and the following - * disclaimer. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 io.spine.gradle.report.license diff --git a/buildSrc/src/main/kotlin/io/spine/gradle/report/license/ModuleDataExtensions.kt b/buildSrc/src/main/kotlin/io/spine/gradle/report/license/ModuleDataExtensions.kt index e8518fd..cf75364 100644 --- a/buildSrc/src/main/kotlin/io/spine/gradle/report/license/ModuleDataExtensions.kt +++ b/buildSrc/src/main/kotlin/io/spine/gradle/report/license/ModuleDataExtensions.kt @@ -1,27 +1,15 @@ /* - * Copyright 2026, TeamDev. All rights reserved. + * Copyright 2026 CodeMatters, Lda. * - * 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 + * 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 * - * Redistribution and use in source and/or binary forms, with or without - * modification, must retain the above copyright notice and the following - * disclaimer. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 io.spine.gradle.report.license @@ -137,18 +125,15 @@ private fun ModuleData.projectUrl(): String? { private fun ModuleData.licenses(): Set { val result = mutableSetOf() - val manifestLicense: License? = manifests.firstOrNull()?.let { manifest -> - val value = manifest.license - if (!value.isNullOrBlank()) { - if (value.startsWith("http")) { - License(value, value) - } else { - License(value, manifest.url) - } + manifests.firstOrNull()?.licenses?.mapNotNullTo(result) { license -> + val name: String? = license.name + val url: String? = license.url + when { + name.isNullOrBlank() -> url?.takeIf { it.isNotBlank() }?.let { License(it, it) } + name.startsWith("http") -> License(name, url ?: name) + else -> License(name, url) } - null } - manifestLicense?.let { result.add(it) } val pomLicenses = poms.firstOrNull()?.licenses?.map { license -> License(license.name, license.url) diff --git a/buildSrc/src/main/kotlin/io/spine/gradle/report/license/Paths.kt b/buildSrc/src/main/kotlin/io/spine/gradle/report/license/Paths.kt index 3c750b3..c1540da 100644 --- a/buildSrc/src/main/kotlin/io/spine/gradle/report/license/Paths.kt +++ b/buildSrc/src/main/kotlin/io/spine/gradle/report/license/Paths.kt @@ -1,27 +1,15 @@ /* - * Copyright 2026, TeamDev. All rights reserved. + * Copyright 2026 CodeMatters, Lda. * - * 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 + * 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 * - * Redistribution and use in source and/or binary forms, with or without - * modification, must retain the above copyright notice and the following - * disclaimer. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 io.spine.gradle.report.license diff --git a/buildSrc/src/main/kotlin/io/spine/gradle/report/license/ProjectDependencies.kt b/buildSrc/src/main/kotlin/io/spine/gradle/report/license/ProjectDependencies.kt index a41152c..21de29c 100644 --- a/buildSrc/src/main/kotlin/io/spine/gradle/report/license/ProjectDependencies.kt +++ b/buildSrc/src/main/kotlin/io/spine/gradle/report/license/ProjectDependencies.kt @@ -1,27 +1,15 @@ /* - * Copyright 2026, TeamDev. All rights reserved. + * Copyright 2026 CodeMatters, Lda. * - * 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 + * 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 * - * Redistribution and use in source and/or binary forms, with or without - * modification, must retain the above copyright notice and the following - * disclaimer. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 io.spine.gradle.report.license diff --git a/buildSrc/src/main/kotlin/io/spine/gradle/report/license/Tasks.kt b/buildSrc/src/main/kotlin/io/spine/gradle/report/license/Tasks.kt index 23fd62a..f312f71 100644 --- a/buildSrc/src/main/kotlin/io/spine/gradle/report/license/Tasks.kt +++ b/buildSrc/src/main/kotlin/io/spine/gradle/report/license/Tasks.kt @@ -1,27 +1,15 @@ /* - * Copyright 2026, TeamDev. All rights reserved. + * Copyright 2026 CodeMatters, Lda. * - * 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 + * 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 * - * Redistribution and use in source and/or binary forms, with or without - * modification, must retain the above copyright notice and the following - * disclaimer. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 io.spine.gradle.report.license diff --git a/buildSrc/src/main/kotlin/io/spine/gradle/report/license/Template.kt b/buildSrc/src/main/kotlin/io/spine/gradle/report/license/Template.kt index d6632e6..a603871 100644 --- a/buildSrc/src/main/kotlin/io/spine/gradle/report/license/Template.kt +++ b/buildSrc/src/main/kotlin/io/spine/gradle/report/license/Template.kt @@ -1,27 +1,15 @@ /* - * Copyright 2026, TeamDev. All rights reserved. + * Copyright 2026 CodeMatters, Lda. * - * 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 + * 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 * - * Redistribution and use in source and/or binary forms, with or without - * modification, must retain the above copyright notice and the following - * disclaimer. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 io.spine.gradle.report.license diff --git a/buildSrc/src/main/kotlin/io/spine/gradle/report/pom/DependencyScope.kt b/buildSrc/src/main/kotlin/io/spine/gradle/report/pom/DependencyScope.kt index 080f806..7ddb341 100644 --- a/buildSrc/src/main/kotlin/io/spine/gradle/report/pom/DependencyScope.kt +++ b/buildSrc/src/main/kotlin/io/spine/gradle/report/pom/DependencyScope.kt @@ -1,27 +1,15 @@ /* - * Copyright 2026, TeamDev. All rights reserved. + * Copyright 2026 CodeMatters, Lda. * - * 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 + * 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 * - * Redistribution and use in source and/or binary forms, with or without - * modification, must retain the above copyright notice and the following - * disclaimer. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 io.spine.gradle.report.pom diff --git a/buildSrc/src/main/kotlin/io/spine/gradle/report/pom/DependencyWriter.kt b/buildSrc/src/main/kotlin/io/spine/gradle/report/pom/DependencyWriter.kt index 2b9e5e5..64f3c16 100644 --- a/buildSrc/src/main/kotlin/io/spine/gradle/report/pom/DependencyWriter.kt +++ b/buildSrc/src/main/kotlin/io/spine/gradle/report/pom/DependencyWriter.kt @@ -1,27 +1,15 @@ /* - * Copyright 2026, TeamDev. All rights reserved. + * Copyright 2026 CodeMatters, Lda. * - * 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 + * 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 * - * Redistribution and use in source and/or binary forms, with or without - * modification, must retain the above copyright notice and the following - * disclaimer. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 io.spine.gradle.report.pom diff --git a/buildSrc/src/main/kotlin/io/spine/gradle/report/pom/InceptionYear.kt b/buildSrc/src/main/kotlin/io/spine/gradle/report/pom/InceptionYear.kt index 2b7f31b..2861901 100644 --- a/buildSrc/src/main/kotlin/io/spine/gradle/report/pom/InceptionYear.kt +++ b/buildSrc/src/main/kotlin/io/spine/gradle/report/pom/InceptionYear.kt @@ -1,27 +1,15 @@ /* - * Copyright 2026, TeamDev. All rights reserved. + * Copyright 2026 CodeMatters, Lda. * - * 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 + * 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 * - * Redistribution and use in source and/or binary forms, with or without - * modification, must retain the above copyright notice and the following - * disclaimer. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 io.spine.gradle.report.pom diff --git a/buildSrc/src/main/kotlin/io/spine/gradle/report/pom/MarkupExtensions.kt b/buildSrc/src/main/kotlin/io/spine/gradle/report/pom/MarkupExtensions.kt index d855220..058023e 100644 --- a/buildSrc/src/main/kotlin/io/spine/gradle/report/pom/MarkupExtensions.kt +++ b/buildSrc/src/main/kotlin/io/spine/gradle/report/pom/MarkupExtensions.kt @@ -1,27 +1,15 @@ /* - * Copyright 2026, TeamDev. All rights reserved. + * Copyright 2026 CodeMatters, Lda. * - * 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 + * 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 * - * Redistribution and use in source and/or binary forms, with or without - * modification, must retain the above copyright notice and the following - * disclaimer. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 io.spine.gradle.report.pom diff --git a/buildSrc/src/main/kotlin/io/spine/gradle/report/pom/ModuleDependency.kt b/buildSrc/src/main/kotlin/io/spine/gradle/report/pom/ModuleDependency.kt index 5f3a372..3348101 100644 --- a/buildSrc/src/main/kotlin/io/spine/gradle/report/pom/ModuleDependency.kt +++ b/buildSrc/src/main/kotlin/io/spine/gradle/report/pom/ModuleDependency.kt @@ -1,27 +1,15 @@ /* - * Copyright 2026, TeamDev. All rights reserved. + * Copyright 2026 CodeMatters, Lda. * - * 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 + * 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 * - * Redistribution and use in source and/or binary forms, with or without - * modification, must retain the above copyright notice and the following - * disclaimer. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 io.spine.gradle.report.pom diff --git a/buildSrc/src/main/kotlin/io/spine/gradle/report/pom/PomFormatting.kt b/buildSrc/src/main/kotlin/io/spine/gradle/report/pom/PomFormatting.kt index f08028e..3a52738 100644 --- a/buildSrc/src/main/kotlin/io/spine/gradle/report/pom/PomFormatting.kt +++ b/buildSrc/src/main/kotlin/io/spine/gradle/report/pom/PomFormatting.kt @@ -1,27 +1,15 @@ /* - * Copyright 2026, TeamDev. All rights reserved. + * Copyright 2026 CodeMatters, Lda. * - * 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 + * 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 * - * Redistribution and use in source and/or binary forms, with or without - * modification, must retain the above copyright notice and the following - * disclaimer. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 io.spine.gradle.report.pom diff --git a/buildSrc/src/main/kotlin/io/spine/gradle/report/pom/PomGenerator.kt b/buildSrc/src/main/kotlin/io/spine/gradle/report/pom/PomGenerator.kt index 8f163e7..479e4f5 100644 --- a/buildSrc/src/main/kotlin/io/spine/gradle/report/pom/PomGenerator.kt +++ b/buildSrc/src/main/kotlin/io/spine/gradle/report/pom/PomGenerator.kt @@ -1,27 +1,15 @@ /* - * Copyright 2026, TeamDev. All rights reserved. + * Copyright 2026 CodeMatters, Lda. * - * 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 + * 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 * - * Redistribution and use in source and/or binary forms, with or without - * modification, must retain the above copyright notice and the following - * disclaimer. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 io.spine.gradle.report.pom diff --git a/buildSrc/src/main/kotlin/io/spine/gradle/report/pom/PomXmlWriter.kt b/buildSrc/src/main/kotlin/io/spine/gradle/report/pom/PomXmlWriter.kt index 25cb378..687b5ae 100644 --- a/buildSrc/src/main/kotlin/io/spine/gradle/report/pom/PomXmlWriter.kt +++ b/buildSrc/src/main/kotlin/io/spine/gradle/report/pom/PomXmlWriter.kt @@ -1,27 +1,15 @@ /* - * Copyright 2026, TeamDev. All rights reserved. + * Copyright 2026 CodeMatters, Lda. * - * 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 + * 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 * - * Redistribution and use in source and/or binary forms, with or without - * modification, must retain the above copyright notice and the following - * disclaimer. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 io.spine.gradle.report.pom diff --git a/buildSrc/src/main/kotlin/io/spine/gradle/report/pom/ProjectMetadata.kt b/buildSrc/src/main/kotlin/io/spine/gradle/report/pom/ProjectMetadata.kt index a72434a..4628018 100644 --- a/buildSrc/src/main/kotlin/io/spine/gradle/report/pom/ProjectMetadata.kt +++ b/buildSrc/src/main/kotlin/io/spine/gradle/report/pom/ProjectMetadata.kt @@ -1,27 +1,15 @@ /* - * Copyright 2026, TeamDev. All rights reserved. + * Copyright 2026 CodeMatters, Lda. * - * 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 + * 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 * - * Redistribution and use in source and/or binary forms, with or without - * modification, must retain the above copyright notice and the following - * disclaimer. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 io.spine.gradle.report.pom diff --git a/buildSrc/src/main/kotlin/io/spine/gradle/report/pom/ResolvedVersions.kt b/buildSrc/src/main/kotlin/io/spine/gradle/report/pom/ResolvedVersions.kt index 103b549..6bd213a 100644 --- a/buildSrc/src/main/kotlin/io/spine/gradle/report/pom/ResolvedVersions.kt +++ b/buildSrc/src/main/kotlin/io/spine/gradle/report/pom/ResolvedVersions.kt @@ -1,27 +1,15 @@ /* - * Copyright 2026, TeamDev. All rights reserved. + * Copyright 2026 CodeMatters, Lda. * - * 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 + * 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 * - * Redistribution and use in source and/or binary forms, with or without - * modification, must retain the above copyright notice and the following - * disclaimer. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 io.spine.gradle.report.pom @@ -85,7 +73,10 @@ internal object ResolvedVersions { group = SpineTaskGroup.name description = "Collects the versions of dependencies of " + "the `${project.name}` project selected by dependency resolution" - mustRunAfter(project.tasks.matching { it.name == "clean" }) + // Filtered by name rather than by task: `matching` tests a predicate + // against each task, so it has to instantiate every one registered in + // the project merely to read its name. + mustRunAfter(project.tasks.named { it == "clean" }) doLast { val file = outputFileIn(project) file.parentFile.mkdirs() diff --git a/buildSrc/src/main/kotlin/io/spine/gradle/report/pom/ScopedDependency.kt b/buildSrc/src/main/kotlin/io/spine/gradle/report/pom/ScopedDependency.kt index c969ce5..ffe22bd 100644 --- a/buildSrc/src/main/kotlin/io/spine/gradle/report/pom/ScopedDependency.kt +++ b/buildSrc/src/main/kotlin/io/spine/gradle/report/pom/ScopedDependency.kt @@ -1,27 +1,15 @@ /* - * Copyright 2026, TeamDev. All rights reserved. + * Copyright 2026 CodeMatters, Lda. * - * 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 + * 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 * - * Redistribution and use in source and/or binary forms, with or without - * modification, must retain the above copyright notice and the following - * disclaimer. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 io.spine.gradle.report.pom diff --git a/buildSrc/src/main/kotlin/io/spine/gradle/report/pom/SpineLicense.kt b/buildSrc/src/main/kotlin/io/spine/gradle/report/pom/SpineLicense.kt index 6a28cdb..2e5cd30 100644 --- a/buildSrc/src/main/kotlin/io/spine/gradle/report/pom/SpineLicense.kt +++ b/buildSrc/src/main/kotlin/io/spine/gradle/report/pom/SpineLicense.kt @@ -1,27 +1,15 @@ /* - * Copyright 2026, TeamDev. All rights reserved. + * Copyright 2026 CodeMatters, Lda. * - * 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 + * 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 * - * Redistribution and use in source and/or binary forms, with or without - * modification, must retain the above copyright notice and the following - * disclaimer. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 io.spine.gradle.report.pom diff --git a/buildSrc/src/main/kotlin/io/spine/gradle/testing/Logging.kt b/buildSrc/src/main/kotlin/io/spine/gradle/testing/Logging.kt index 6289af1..5a4b408 100644 --- a/buildSrc/src/main/kotlin/io/spine/gradle/testing/Logging.kt +++ b/buildSrc/src/main/kotlin/io/spine/gradle/testing/Logging.kt @@ -1,27 +1,15 @@ /* - * Copyright 2026, TeamDev. All rights reserved. + * Copyright 2026 CodeMatters, Lda. * - * 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 + * 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 * - * Redistribution and use in source and/or binary forms, with or without - * modification, must retain the above copyright notice and the following - * disclaimer. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 io.spine.gradle.testing diff --git a/buildSrc/src/main/kotlin/io/spine/gradle/testing/Multiproject.kt b/buildSrc/src/main/kotlin/io/spine/gradle/testing/Multiproject.kt index 6509a58..1cfd25c 100644 --- a/buildSrc/src/main/kotlin/io/spine/gradle/testing/Multiproject.kt +++ b/buildSrc/src/main/kotlin/io/spine/gradle/testing/Multiproject.kt @@ -1,27 +1,15 @@ /* - * Copyright 2026, TeamDev. All rights reserved. + * Copyright 2026 CodeMatters, Lda. * - * 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 + * 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 * - * Redistribution and use in source and/or binary forms, with or without - * modification, must retain the above copyright notice and the following - * disclaimer. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 io.spine.gradle.testing diff --git a/buildSrc/src/main/kotlin/io/spine/gradle/testing/SpineCompilerCoverage.kt b/buildSrc/src/main/kotlin/io/spine/gradle/testing/SpineCompilerCoverage.kt index af2bc06..02f880a 100644 --- a/buildSrc/src/main/kotlin/io/spine/gradle/testing/SpineCompilerCoverage.kt +++ b/buildSrc/src/main/kotlin/io/spine/gradle/testing/SpineCompilerCoverage.kt @@ -1,27 +1,15 @@ /* - * Copyright 2026, TeamDev. All rights reserved. + * Copyright 2026 CodeMatters, Lda. * - * 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 + * 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 * - * Redistribution and use in source and/or binary forms, with or without - * modification, must retain the above copyright notice and the following - * disclaimer. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 io.spine.gradle.testing diff --git a/buildSrc/src/main/kotlin/io/spine/gradle/testing/Tasks.kt b/buildSrc/src/main/kotlin/io/spine/gradle/testing/Tasks.kt index 41f07f0..8559bfd 100644 --- a/buildSrc/src/main/kotlin/io/spine/gradle/testing/Tasks.kt +++ b/buildSrc/src/main/kotlin/io/spine/gradle/testing/Tasks.kt @@ -1,27 +1,15 @@ /* - * Copyright 2026, TeamDev. All rights reserved. + * Copyright 2026 CodeMatters, Lda. * - * 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 + * 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 * - * Redistribution and use in source and/or binary forms, with or without - * modification, must retain the above copyright notice and the following - * disclaimer. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 io.spine.gradle.testing diff --git a/buildSrc/src/main/kotlin/io/spine/gradle/testing/TestKitCoverage.kt b/buildSrc/src/main/kotlin/io/spine/gradle/testing/TestKitCoverage.kt index 6c21a6b..52f6632 100644 --- a/buildSrc/src/main/kotlin/io/spine/gradle/testing/TestKitCoverage.kt +++ b/buildSrc/src/main/kotlin/io/spine/gradle/testing/TestKitCoverage.kt @@ -1,27 +1,15 @@ /* - * Copyright 2026, TeamDev. All rights reserved. + * Copyright 2026 CodeMatters, Lda. * - * 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 + * 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 * - * Redistribution and use in source and/or binary forms, with or without - * modification, must retain the above copyright notice and the following - * disclaimer. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 io.spine.gradle.testing diff --git a/buildSrc/src/main/kotlin/jvm-module.gradle.kts b/buildSrc/src/main/kotlin/jvm-module.gradle.kts index 1438116..830335f 100644 --- a/buildSrc/src/main/kotlin/jvm-module.gradle.kts +++ b/buildSrc/src/main/kotlin/jvm-module.gradle.kts @@ -1,27 +1,15 @@ /* - * Copyright 2026, TeamDev. All rights reserved. + * Copyright 2026 CodeMatters, Lda. * - * 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 + * 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 * - * Redistribution and use in source and/or binary forms, with or without - * modification, must retain the above copyright notice and the following - * disclaimer. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. */ import io.spine.dependency.boms.BomsPlugin diff --git a/buildSrc/src/main/kotlin/kmp-module.gradle.kts b/buildSrc/src/main/kotlin/kmp-module.gradle.kts index 0dfb233..0e84f04 100644 --- a/buildSrc/src/main/kotlin/kmp-module.gradle.kts +++ b/buildSrc/src/main/kotlin/kmp-module.gradle.kts @@ -1,27 +1,15 @@ /* - * Copyright 2026, TeamDev. All rights reserved. + * Copyright 2026 CodeMatters, Lda. * - * 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 + * 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 * - * Redistribution and use in source and/or binary forms, with or without - * modification, must retain the above copyright notice and the following - * disclaimer. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. */ import io.spine.dependency.boms.BomsPlugin diff --git a/buildSrc/src/main/kotlin/kmp-publish.gradle.kts b/buildSrc/src/main/kotlin/kmp-publish.gradle.kts index c7e679b..283af82 100644 --- a/buildSrc/src/main/kotlin/kmp-publish.gradle.kts +++ b/buildSrc/src/main/kotlin/kmp-publish.gradle.kts @@ -1,27 +1,15 @@ /* - * Copyright 2026, TeamDev. All rights reserved. + * Copyright 2026 CodeMatters, Lda. * - * 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 + * 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 * - * Redistribution and use in source and/or binary forms, with or without - * modification, must retain the above copyright notice and the following - * disclaimer. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. */ import org.gradle.api.publish.maven.MavenPublication diff --git a/buildSrc/src/main/kotlin/module-testing.gradle.kts b/buildSrc/src/main/kotlin/module-testing.gradle.kts index 5b839eb..add0178 100644 --- a/buildSrc/src/main/kotlin/module-testing.gradle.kts +++ b/buildSrc/src/main/kotlin/module-testing.gradle.kts @@ -1,27 +1,15 @@ /* - * Copyright 2026, TeamDev. All rights reserved. + * Copyright 2026 CodeMatters, Lda. * - * 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 + * 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 * - * Redistribution and use in source and/or binary forms, with or without - * modification, must retain the above copyright notice and the following - * disclaimer. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. */ import io.spine.dependency.lib.Guava diff --git a/buildSrc/src/main/kotlin/pmd-settings.gradle.kts b/buildSrc/src/main/kotlin/pmd-settings.gradle.kts index 42c6959..af0e2cc 100644 --- a/buildSrc/src/main/kotlin/pmd-settings.gradle.kts +++ b/buildSrc/src/main/kotlin/pmd-settings.gradle.kts @@ -1,27 +1,15 @@ /* - * Copyright 2026, TeamDev. All rights reserved. + * Copyright 2026 CodeMatters, Lda. * - * 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 + * 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 * - * Redistribution and use in source and/or binary forms, with or without - * modification, must retain the above copyright notice and the following - * disclaimer. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. */ import io.spine.dependency.build.Pmd diff --git a/buildSrc/src/main/kotlin/test-module.gradle.kts b/buildSrc/src/main/kotlin/test-module.gradle.kts index d779c97..03b4cb5 100644 --- a/buildSrc/src/main/kotlin/test-module.gradle.kts +++ b/buildSrc/src/main/kotlin/test-module.gradle.kts @@ -1,27 +1,15 @@ /* - * Copyright 2026, TeamDev. All rights reserved. + * Copyright 2026 CodeMatters, Lda. * - * 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 + * 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 * - * Redistribution and use in source and/or binary forms, with or without - * modification, must retain the above copyright notice and the following - * disclaimer. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. */ import io.spine.dependency.local.Base diff --git a/buildSrc/src/main/kotlin/uber-jar-module.gradle.kts b/buildSrc/src/main/kotlin/uber-jar-module.gradle.kts index f91b3b9..e62cf0a 100644 --- a/buildSrc/src/main/kotlin/uber-jar-module.gradle.kts +++ b/buildSrc/src/main/kotlin/uber-jar-module.gradle.kts @@ -1,34 +1,22 @@ /* - * Copyright 2026, TeamDev. All rights reserved. + * Copyright 2026 CodeMatters, Lda. * - * 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 + * 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 * - * Redistribution and use in source and/or binary forms, with or without - * modification, must retain the above copyright notice and the following - * disclaimer. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. */ @file:Suppress("UnstableApiUsage") // `configurations` block. import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar import io.spine.gradle.publish.IncrementGuard -import io.spine.gradle.publish.SpinePublishing +import io.spine.gradle.publish.sbom import io.spine.gradle.publish.setup import io.spine.gradle.publish.spinePublishing import io.spine.gradle.report.license.LicenseReporter @@ -49,7 +37,6 @@ spinePublishing { // to the `io.spine.tools` group, and therefore `toolArtifactPrefix` applies instead. artifactPrefix = "" toolArtifactPrefix = "NONE" - destinations = rootProject.the().destinations customPublishing = true } @@ -66,6 +53,7 @@ publishing { artifactId = projectArtifact version = versionName artifact(tasks.shadowJar) + sbom { bundled(tasks.shadowJar) } } } } diff --git a/buildSrc/src/main/kotlin/write-manifest.gradle.kts b/buildSrc/src/main/kotlin/write-manifest.gradle.kts index 4656ff4..d15d879 100644 --- a/buildSrc/src/main/kotlin/write-manifest.gradle.kts +++ b/buildSrc/src/main/kotlin/write-manifest.gradle.kts @@ -1,27 +1,15 @@ /* - * Copyright 2026, TeamDev. All rights reserved. + * Copyright 2026 CodeMatters, Lda. * - * 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 + * 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 * - * Redistribution and use in source and/or binary forms, with or without - * modification, must retain the above copyright notice and the following - * disclaimer. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. */ import io.spine.gradle.SpineTaskGroup @@ -92,7 +80,7 @@ val manifestAttributes = mapOf( "Build-OS" to buildOs(), IMPLEMENTATION_TITLE.toString() to implementationTitle(), IMPLEMENTATION_VERSION.toString() to project.version, - IMPLEMENTATION_VENDOR.toString() to "TeamDev", + IMPLEMENTATION_VENDOR.toString() to "CodeMatters, Lda.", "Bundle-License" to "https://www.apache.org/licenses/LICENSE-2.0.txt" ) diff --git a/buildSrc/src/main/resources/dokka/styles/custom-styles.css b/buildSrc/src/main/resources/dokka/styles/custom-styles.css index e036c12..2c9713a 100644 --- a/buildSrc/src/main/resources/dokka/styles/custom-styles.css +++ b/buildSrc/src/main/resources/dokka/styles/custom-styles.css @@ -1,27 +1,15 @@ /* - * Copyright 2026, TeamDev. All rights reserved. + * Copyright 2026 CodeMatters, Lda. * - * 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 + * 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 * - * Redistribution and use in source and/or binary forms, with or without - * modification, must retain the above copyright notice and the following - * disclaimer. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. */ :root, diff --git a/buildSrc/src/test/kotlin/io/spine/dependency/build/KspSpec.kt b/buildSrc/src/test/kotlin/io/spine/dependency/build/KspSpec.kt new file mode 100644 index 0000000..56ab03e --- /dev/null +++ b/buildSrc/src/test/kotlin/io/spine/dependency/build/KspSpec.kt @@ -0,0 +1,46 @@ +/* + * Copyright 2026 CodeMatters, Lda. + * + * 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 io.spine.dependency.build + +import io.kotest.assertions.assertSoftly +import io.kotest.matchers.shouldBe +import org.junit.jupiter.api.DisplayName +import org.junit.jupiter.api.Test + +@DisplayName("`Ksp` should") +internal class KspSpec { + + @Test + fun `return the coordinates of a module with the version`() { + assertSoftly(Ksp) { + symbolProcessingApi() shouldBe "$symbolProcessingApi:$version" + symbolProcessing() shouldBe "$symbolProcessing:$version" + symbolProcessingAaEmb() shouldBe "$symbolProcessingAaEmb:$version" + symbolProcessingCommonDeps() shouldBe "$symbolProcessingCommonDeps:$version" + gradlePlugin() shouldBe "$gradlePlugin:$version" + } + } + + /** + * Gradle resolves a plugin requested by its ID through the plugin marker + * `:.gradle.plugin`. + * + * See: https://docs.gradle.org/current/userguide/plugins_intermediate.html#sec:plugin_markers + */ + @Test + fun `return the coordinates of the plugin marker with the version`() { + Ksp.gradlePluginMarker() shouldBe "${Ksp.id}:${Ksp.id}.gradle.plugin:${Ksp.version}" + } +} diff --git a/buildSrc/src/test/kotlin/io/spine/dependency/lib/JacksonSpec.kt b/buildSrc/src/test/kotlin/io/spine/dependency/lib/JacksonSpec.kt new file mode 100644 index 0000000..affa892 --- /dev/null +++ b/buildSrc/src/test/kotlin/io/spine/dependency/lib/JacksonSpec.kt @@ -0,0 +1,51 @@ +/* + * Copyright 2026 CodeMatters, Lda. + * + * 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 io.spine.dependency.lib + +import io.kotest.assertions.assertSoftly +import io.kotest.matchers.shouldBe +import org.junit.jupiter.api.DisplayName +import org.junit.jupiter.api.Test + +@DisplayName("`Jackson` should") +internal class JacksonSpec { + + @Test + fun `return the coordinates of a module with the version`() { + assertSoftly(Jackson) { + core() shouldBe "$core:$version" + databind() shouldBe "$databind:$version" + moduleKotlin() shouldBe "$moduleKotlin:$version" + } + } + + @Test + fun `return the coordinates of a data format module with the version`() { + assertSoftly(Jackson.DataFormat) { + xml() shouldBe "$xml:$version" + yaml() shouldBe "$yaml:$version" + protobuf() shouldBe "$protobuf:$version" + } + } + + @Test + fun `return the coordinates of a data type module with the version`() { + assertSoftly(Jackson.DataType) { + guava() shouldBe "$guava:$version" + javaXMoney() shouldBe "$javaXMoney:$version" + moneta() shouldBe "$moneta:$version" + } + } +} diff --git a/buildSrc/src/test/kotlin/io/spine/dependency/lib/JacksonV2Spec.kt b/buildSrc/src/test/kotlin/io/spine/dependency/lib/JacksonV2Spec.kt new file mode 100644 index 0000000..bb8d797 --- /dev/null +++ b/buildSrc/src/test/kotlin/io/spine/dependency/lib/JacksonV2Spec.kt @@ -0,0 +1,58 @@ +/* + * Copyright 2026 CodeMatters, Lda. + * + * 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 io.spine.dependency.lib + +import io.kotest.assertions.assertSoftly +import io.kotest.matchers.shouldBe +import org.junit.jupiter.api.DisplayName +import org.junit.jupiter.api.Test + +@DisplayName("`JacksonV2` should") +internal class JacksonV2Spec { + + @Test + fun `return the coordinates of a core module with the version`() { + assertSoftly(JacksonV2.Core) { + core() shouldBe "$core:$version" + databind() shouldBe "$databind:$version" + } + } + + @Test + fun `return the coordinates of a data type module with the version`() { + assertSoftly(JacksonV2.DataType) { + jdk8() shouldBe "$jdk8:$version" + jsr310() shouldBe "$jsr310:$version" + guava() shouldBe "$guava:$version" + } + } + + @Test + fun `return the coordinates of a data format module with the version`() { + assertSoftly(JacksonV2.DataFormat) { + xml() shouldBe "$xml:$version" + yaml() shouldBe "$yaml:$version" + protobuf() shouldBe "$protobuf:$version" + } + } + + @Test + fun `return the coordinates of an extension module with the version`() { + assertSoftly(JacksonV2.Module) { + parameterNames() shouldBe "$parameterNames:$version" + kotlin() shouldBe "$kotlin:$version" + } + } +} diff --git a/buildSrc/src/test/kotlin/io/spine/dependency/lib/KotlinSpec.kt b/buildSrc/src/test/kotlin/io/spine/dependency/lib/KotlinSpec.kt new file mode 100644 index 0000000..559e463 --- /dev/null +++ b/buildSrc/src/test/kotlin/io/spine/dependency/lib/KotlinSpec.kt @@ -0,0 +1,43 @@ +/* + * Copyright 2026 CodeMatters, Lda. + * + * 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 io.spine.dependency.lib + +import io.kotest.inspectors.forAll +import io.kotest.matchers.collections.shouldContainExactly +import io.kotest.matchers.collections.shouldHaveSize +import io.kotest.matchers.string.shouldEndWith +import org.junit.jupiter.api.DisplayName +import org.junit.jupiter.api.Test + +@DisplayName("`Kotlin` should") +internal class KotlinSpec { + + @Test + fun `give the coordinates of a Gradle plugin module with a single version`() { + with(Kotlin.GradlePlugin) { + artifacts.values.forAll { + it.split(':') shouldHaveSize 3 + it shouldEndWith ":$version" + } + } + } + + @Test + fun `give the Gradle plugin artifacts declared by 'api', 'lib', and 'model'`() { + with(Kotlin.GradlePlugin) { + artifacts.values shouldContainExactly listOf(api, lib, model) + } + } +} diff --git a/buildSrc/src/test/kotlin/io/spine/dependency/lib/ProtobufSpec.kt b/buildSrc/src/test/kotlin/io/spine/dependency/lib/ProtobufSpec.kt new file mode 100644 index 0000000..b439b50 --- /dev/null +++ b/buildSrc/src/test/kotlin/io/spine/dependency/lib/ProtobufSpec.kt @@ -0,0 +1,41 @@ +/* + * Copyright 2026 CodeMatters, Lda. + * + * 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 io.spine.dependency.lib + +import io.kotest.assertions.assertSoftly +import io.kotest.matchers.collections.shouldContainExactly +import io.kotest.matchers.shouldBe +import org.junit.jupiter.api.DisplayName +import org.junit.jupiter.api.Test + +@DisplayName("`Protobuf` should") +internal class ProtobufSpec { + + @Test + fun `declare the coordinates of its Java and Kotlin libraries`() { + assertSoftly(Protobuf) { + javaLib shouldBe "$group:protobuf-java:$version" + javaUtil shouldBe "$group:protobuf-java-util:$version" + kotlin shouldBe "$group:protobuf-kotlin:$version" + } + } + + @Test + fun `list its Java and Kotlin libraries`() { + with(Protobuf) { + libs shouldContainExactly listOf(javaLib, javaUtil, kotlin) + } + } +} diff --git a/buildSrc/src/test/kotlin/io/spine/gradle/VersionComparatorSpec.kt b/buildSrc/src/test/kotlin/io/spine/gradle/VersionComparatorSpec.kt index c643645..57a7ecd 100644 --- a/buildSrc/src/test/kotlin/io/spine/gradle/VersionComparatorSpec.kt +++ b/buildSrc/src/test/kotlin/io/spine/gradle/VersionComparatorSpec.kt @@ -1,27 +1,15 @@ /* - * Copyright 2026, TeamDev. All rights reserved. + * Copyright 2026 CodeMatters, Lda. * - * 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 + * 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 * - * Redistribution and use in source and/or binary forms, with or without - * modification, must retain the above copyright notice and the following - * disclaimer. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 io.spine.gradle diff --git a/buildSrc/src/test/kotlin/io/spine/gradle/VersionGradleFileSpec.kt b/buildSrc/src/test/kotlin/io/spine/gradle/VersionGradleFileSpec.kt index dd5e279..b260088 100644 --- a/buildSrc/src/test/kotlin/io/spine/gradle/VersionGradleFileSpec.kt +++ b/buildSrc/src/test/kotlin/io/spine/gradle/VersionGradleFileSpec.kt @@ -1,27 +1,15 @@ /* - * Copyright 2026, TeamDev. All rights reserved. + * Copyright 2026 CodeMatters, Lda. * - * 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 + * 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 * - * Redistribution and use in source and/or binary forms, with or without - * modification, must retain the above copyright notice and the following - * disclaimer. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 io.spine.gradle diff --git a/buildSrc/src/test/kotlin/io/spine/gradle/checkstyle/CheckStyleConfigSpec.kt b/buildSrc/src/test/kotlin/io/spine/gradle/checkstyle/CheckStyleConfigSpec.kt new file mode 100644 index 0000000..8b7669f --- /dev/null +++ b/buildSrc/src/test/kotlin/io/spine/gradle/checkstyle/CheckStyleConfigSpec.kt @@ -0,0 +1,44 @@ +/* + * Copyright 2026 CodeMatters, Lda. + * + * 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 io.spine.gradle.checkstyle + +import io.kotest.matchers.collections.shouldContain +import io.kotest.matchers.shouldBe +import io.spine.dependency.build.CheckStyle +import org.gradle.api.Project +import org.gradle.api.plugins.quality.CheckstyleExtension +import org.gradle.kotlin.dsl.the +import org.gradle.testfixtures.ProjectBuilder +import org.junit.jupiter.api.DisplayName +import org.junit.jupiter.api.Test + +@DisplayName("`CheckStyleConfig` should") +internal class CheckStyleConfigSpec { + + private val project: Project = ProjectBuilder.builder().build().also { + CheckStyleConfig.applyTo(it) + } + + @Test + fun `use the declared Checkstyle version`() { + project.the().toolVersion shouldBe CheckStyle.version + } + + @Test + fun `exclude the whole Doxia group from the Checkstyle classpath`() { + val rules = project.configurations.getByName("checkstyle").excludeRules + rules.map { it.group to it.module } shouldContain ("org.apache.maven.doxia" to null) + } +} diff --git a/buildSrc/src/test/kotlin/io/spine/gradle/docs/DokkaSetupIgTest.kt b/buildSrc/src/test/kotlin/io/spine/gradle/docs/DokkaSetupIgTest.kt new file mode 100644 index 0000000..6ec5eff --- /dev/null +++ b/buildSrc/src/test/kotlin/io/spine/gradle/docs/DokkaSetupIgTest.kt @@ -0,0 +1,295 @@ +/* + * Copyright 2026 CodeMatters, Lda. + * + * 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 io.spine.gradle.docs + +import io.kotest.assertions.withClue +import io.kotest.matchers.file.shouldExist +import io.kotest.matchers.shouldBe +import io.kotest.matchers.string.shouldContain +import java.io.File +import org.gradle.testkit.runner.BuildResult +import org.gradle.testkit.runner.GradleRunner +import org.gradle.testkit.runner.TaskOutcome.SKIPPED +import org.gradle.testkit.runner.TaskOutcome.SUCCESS +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.DisplayName +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.io.TempDir + +/** + * The path of the probe task that the build under test declares. + */ +private const val PROBE_PATH = ":dokka-sample:dokkaGeneratePublicationProbe" + +/** + * Verifies when the `dokka-setup` plugin lets Dokka tasks run in a real build + * that uses the configuration cache. + * + * Every case runs the build twice: the first run stores the configuration cache entry, + * and the second one reuses it. The task must reach the same outcome both times, so the + * decision whether to run cannot rely on configuration that a reused entry skips. + * + * Dokka's own tasks resolve the Dokka engine from Maven Central, which an offline + * build cannot reach. So the build declares a probe task that extends + * [DokkaBaseTask][org.jetbrains.dokka.gradle.tasks.DokkaBaseTask] and does nothing. + * The plugin gates it like any other Dokka task. The probe is named like + * `dokkaGeneratePublicationJavadoc`: the Dokka 2.x tasks that generate documentation + * have `dokkaGenerate` in their names, so a gate that relied on task names would never + * skip them. + * + * The build publishes a `javadocJar` that depends on the probe, just as the `javadocJar` + * that `spinePublishing` creates depends on `dokkaGeneratePublicationJavadoc`. The build + * publishes to a file-based repository and to its own Maven Local repository, so it never + * touches `~/.m2`. The `updateGitHubPages` task of the build stands in for the one that + * copies the Dokka output to GitHub Pages. + * + * The project with the probe is named `dokka-sample`, like the modules of `dokka-tools`, + * so that the tests cover `dokka` in the path of a requested task, which must not count + * as a Dokka request. + */ +@DisplayName("`dokka-setup` should, with the configuration cache,") +internal class DokkaSetupIgTest { + + @TempDir + lateinit var projectDir: File + + @BeforeEach + fun createBuild() { + writeBuild(projectDir, "documented-sample") + } + + @Test + fun `skip a Dokka task when the build publishes to Maven Local only`() { + runStoringThenReusing(":dokka-sample:publishToMavenLocal") { + it.probeOutcome shouldBe SKIPPED + // The javadoc JAR is still published, which is enough for integration tests. + mavenLocal.resolve("io/spine/sample/dokka-sample/1.0.0/dokka-sample-1.0.0-javadoc.jar") + .shouldExist() + } + } + + @Test + fun `run a Dokka task when the build publishes to a remote repository`() { + runStoringThenReusing(":dokka-sample:publish") { + it.probeOutcome shouldBe SUCCESS + } + } + + @Test + fun `run a Dokka task when the build publishes to both Maven Local and a remote repository`() { + runStoringThenReusing(":dokka-sample:publishToMavenLocal", ":dokka-sample:publish") { + it.probeOutcome shouldBe SUCCESS + } + } + + @Test + fun `run a Dokka task when a repository publication task runs along with Maven Local`() { + runStoringThenReusing( + ":dokka-sample:publishToMavenLocal", + ":dokka-sample:publishDocsPublicationToRemoteRepository" + ) { + it.probeOutcome shouldBe SUCCESS + } + } + + @Test + fun `run a Dokka task when the build updates GitHub Pages and publishes to Maven Local`() { + runStoringThenReusing( + ":dokka-sample:publishToMavenLocal", + ":dokka-sample:updateGitHubPages" + ) { + it.probeOutcome shouldBe SUCCESS + } + } + + @Test + fun `run a Dokka task when it is requested along with publishing to Maven Local`() { + runStoringThenReusing(":dokka-sample:publishToMavenLocal", PROBE_PATH) { + it.probeOutcome shouldBe SUCCESS + } + } + + @Test + fun `run a Dokka task requested by an abbreviation along with publishing to Maven Local`() { + // Gradle selects `dokkaGeneratePublicationProbe` by this camel-case abbreviation. + runStoringThenReusing(":dokka-sample:publishToMavenLocal", ":dokka-sample:dGPP") { + it.probeOutcome shouldBe SUCCESS + } + } + + @Test + fun `run a Dokka task when a docs JAR is requested along with publishing to Maven Local`() { + runStoringThenReusing(":dokka-sample:publishToMavenLocal", ":dokka-sample:javadocJar") { + it.probeOutcome shouldBe SUCCESS + } + } + + @Test + fun `run a Dokka task requested from an included build along with Maven Local`() { + // Gradle passes an included build no task names, so it cannot see the request. + val included = "included" + writeBuild(file(included), included) + file("settings.gradle.kts").appendText("\nincludeBuild(\"$included\")\n") + val probe = ":$included$PROBE_PATH" + runStoringThenReusing(":$included:dokka-sample:publishToMavenLocal", probe) { + it.task(probe)?.outcome shouldBe SUCCESS + } + } + + @Test + fun `run a Dokka task when the build does not publish`() { + runStoringThenReusing(":dokka-sample:javadocJar") { + it.probeOutcome shouldBe SUCCESS + } + } + + @Test + fun `run a Dokka task when the build generates documentation`() { + runStoringThenReusing(PROBE_PATH) { + it.probeOutcome shouldBe SUCCESS + } + } + + /** + * Writes a build named [name] into [dir], with the probe in its `dokka-sample` project. + */ + private fun writeBuild(dir: File, name: String) { + dir.mkdirs() + dir.resolve("settings.gradle.kts").writeText( + """ + rootProject.name = "$name" + include("dokka-sample") + """.trimIndent() + ) + // The standard library would be resolved from Maven Central otherwise, + // which an offline build cannot reach. + dir.resolve("gradle.properties").writeText("kotlin.stdlib.default.dependency=false\n") + dir.resolve("build.gradle.kts").writeText( + """ + buildscript { + dependencies { + classpath(files( + ${buildSrcClasspath()} + )) + } + } + """.trimIndent() + ) + dir.resolve("dokka-sample").mkdirs() + dir.resolve("dokka-sample/build.gradle.kts").writeText( + """ + import org.jetbrains.dokka.gradle.internal.InternalDokkaGradlePluginApi + import org.jetbrains.dokka.gradle.tasks.DokkaBaseTask + + plugins { + kotlin("jvm") + `maven-publish` + id("dokka-setup") + } + + @OptIn(InternalDokkaGradlePluginApi::class) + abstract class DocsProbe : DokkaBaseTask() { + + @TaskAction + fun probe() = Unit + } + + group = "io.spine.sample" + version = "1.0.0" + + val docsProbe = tasks.register("dokkaGeneratePublicationProbe") + + val javadocJar = tasks.register("javadocJar") { + archiveClassifier.set("javadoc") + from(layout.buildDirectory.dir("docs-probe")) + dependsOn(docsProbe) + } + + publishing { + publications.create("docs") { + artifact(javadocJar) + } + repositories.maven { + name = "remote" + url = uri(rootDir.resolve("remote-repo")) + } + } + + tasks.register("updateGitHubPages") { + dependsOn(docsProbe) + } + """.trimIndent() + ) + } + + private val BuildResult.probeOutcome + get() = task(PROBE_PATH)?.outcome + + /** + * The Maven Local repository of the build, which replaces `~/.m2/repository`. + */ + private val mavenLocal: File + get() = file("maven-local") + + /** + * Runs the given [tasks] twice with the configuration cache, and checks the result of + * each run with [verify]. + * + * The first run stores the cache entry, and the second one reuses it. + */ + private fun runStoringThenReusing(vararg tasks: String, verify: (BuildResult) -> Unit) { + val stored = runGradle(tasks) + withClue("The run that stores the configuration cache entry") { + stored.output shouldContain "Configuration cache entry stored" + verify(stored) + } + val reused = runGradle(tasks) + withClue("The run that reuses the configuration cache entry") { + reused.output shouldContain "Reusing configuration cache" + verify(reused) + } + } + + private fun runGradle(tasks: Array): BuildResult = + GradleRunner.create() + .withProjectDir(projectDir) + .withArguments( + *tasks, + "--configuration-cache", + "--offline", + "--stacktrace", + "-Dmaven.repo.local=${mavenLocal.absolutePath}" + ) + .build() + + private fun file(relativePath: String): File = projectDir.resolve(relativePath) + + /** + * Renders the classpath with the production classes of `buildSrc` as + * arguments of `files(...)`, for injection into the build script classpath + * of the generated build. + * + * The classpath comes from the `test` task in `buildSrc/build.gradle.kts`. + */ + private fun buildSrcClasspath(): String { + val classpath = requireNotNull(System.getProperty("buildSrc.classpath")) { + "The `buildSrc.classpath` system property is not set." + + " It is supplied by the `test` task in `buildSrc/build.gradle.kts`." + } + return classpath.split(File.pathSeparator).joinToString(",\n") { + " \"${File(it).invariantSeparatorsPath}\"" + } + } +} diff --git a/buildSrc/src/test/kotlin/io/spine/gradle/docs/UpdatePluginVersionTest.kt b/buildSrc/src/test/kotlin/io/spine/gradle/docs/UpdatePluginVersionTest.kt index 1674b3d..d842079 100644 --- a/buildSrc/src/test/kotlin/io/spine/gradle/docs/UpdatePluginVersionTest.kt +++ b/buildSrc/src/test/kotlin/io/spine/gradle/docs/UpdatePluginVersionTest.kt @@ -1,27 +1,15 @@ /* - * Copyright 2026, TeamDev. All rights reserved. + * Copyright 2026 CodeMatters, Lda. * - * 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 + * 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 * - * Redistribution and use in source and/or binary forms, with or without - * modification, must retain the above copyright notice and the following - * disclaimer. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 io.spine.gradle.docs diff --git a/buildSrc/src/test/kotlin/io/spine/gradle/fs/LazyTempPathSpec.kt b/buildSrc/src/test/kotlin/io/spine/gradle/fs/LazyTempPathSpec.kt index 260e852..3a229ae 100644 --- a/buildSrc/src/test/kotlin/io/spine/gradle/fs/LazyTempPathSpec.kt +++ b/buildSrc/src/test/kotlin/io/spine/gradle/fs/LazyTempPathSpec.kt @@ -1,27 +1,15 @@ /* - * Copyright 2026, TeamDev. All rights reserved. + * Copyright 2026 CodeMatters, Lda. * - * 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 + * 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 * - * Redistribution and use in source and/or binary forms, with or without - * modification, must retain the above copyright notice and the following - * disclaimer. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 io.spine.gradle.fs diff --git a/buildSrc/src/test/kotlin/io/spine/gradle/fs/SpineTempDirSpec.kt b/buildSrc/src/test/kotlin/io/spine/gradle/fs/SpineTempDirSpec.kt index 8bf4250..9a947ac 100644 --- a/buildSrc/src/test/kotlin/io/spine/gradle/fs/SpineTempDirSpec.kt +++ b/buildSrc/src/test/kotlin/io/spine/gradle/fs/SpineTempDirSpec.kt @@ -1,27 +1,15 @@ /* - * Copyright 2026, TeamDev. All rights reserved. + * Copyright 2026 CodeMatters, Lda. * - * 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 + * 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 * - * Redistribution and use in source and/or binary forms, with or without - * modification, must retain the above copyright notice and the following - * disclaimer. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 io.spine.gradle.fs diff --git a/buildSrc/src/test/kotlin/io/spine/gradle/publish/ArtifactComponentsSpec.kt b/buildSrc/src/test/kotlin/io/spine/gradle/publish/ArtifactComponentsSpec.kt new file mode 100644 index 0000000..e430297 --- /dev/null +++ b/buildSrc/src/test/kotlin/io/spine/gradle/publish/ArtifactComponentsSpec.kt @@ -0,0 +1,411 @@ +/* + * Copyright 2026 CodeMatters, Lda. + * + * 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 io.spine.gradle.publish + +import com.fasterxml.jackson.databind.ObjectMapper +import com.fasterxml.jackson.databind.node.ObjectNode +import io.kotest.assertions.throwables.shouldThrow +import io.kotest.matchers.collections.shouldContainExactly +import io.kotest.matchers.collections.shouldContainExactlyInAnyOrder +import org.gradle.api.logging.Logging +import org.junit.jupiter.api.DisplayName +import org.junit.jupiter.api.Nested +import org.junit.jupiter.api.Test + +/** + * Verifies how [ArtifactComponents] rewrite the relationships of an SPDX document. + * + * The documents are written by hand, in the shape the SPDX Gradle Plugin gives them: + * the document describes the package of the artifact — the `root` — and each package is + * listed under the package it was found through. A relationship is written as + * `" "`, with the `SPDXRef-` prefix left out. + */ +@DisplayName("`ArtifactComponents` should") +internal class ArtifactComponentsSpec { + + @Nested + inner class `describe a bundled package` { + + @Test + fun `as contained in the artifact rather than a dependency of it`() { + val document = sbom( + "root DEPENDS_ON a", + packages = listOf(project("a", path = ":a")) + ) + + ArtifactComponents(bundled = setOf(ComponentKey.ofProject(":a"))).describeIn(document) + + document.relationships() shouldContainExactlyInAnyOrder listOf( + DESCRIBES_ROOT, + "root CONTAINS a", + ) + } + + @Test + fun `found below another one, keeping their dependency`() { + val document = sbom( + "root DEPENDS_ON a", + "a DEPENDS_ON b", + packages = listOf(module("a"), module("b")) + ) + + ArtifactComponents(bundled = keys("a", "b")).describeIn(document) + + document.relationships() shouldContainExactlyInAnyOrder listOf( + DESCRIBES_ROOT, + "root CONTAINS a", + "a DEPENDS_ON b", + "root CONTAINS b", + ) + } + + @Test + fun `whose only parent is left out`() { + val document = sbom( + "root DEPENDS_ON x", + "x DEPENDS_ON b", + packages = listOf(module("x"), module("b")) + ) + + ArtifactComponents(bundled = keys("b")).describeIn(document) + + document.packageIds() shouldContainExactly listOf(ROOT_ID, "b") + document.relationships() shouldContainExactlyInAnyOrder listOf( + DESCRIBES_ROOT, + "root CONTAINS b", + ) + } + + /** + * The plugin describes a component resolved to several files as a package + * containing a package per file. All of them belong to the same component. + */ + @Test + fun `made of several files through the package of the component`() { + val document = sbom( + "root DEPENDS_ON c", + *filesOfComponent, + packages = componentOfTwoFiles() + ) + + ArtifactComponents(bundled = keys("c")).describeIn(document) + + document.relationships() shouldContainExactlyInAnyOrder listOf( + DESCRIBES_ROOT, + "root CONTAINS c", + *filesOfComponent, + ) + } + + @Test + fun `that the artifact already contains, writing the containment once`() { + val document = sbom( + "root DEPENDS_ON a", + "root CONTAINS a", + packages = listOf(module("a")) + ) + + ArtifactComponents(bundled = keys("a")).describeIn(document) + + document.relationships() shouldContainExactly listOf(DESCRIBES_ROOT, "root CONTAINS a") + } + + /** + * A component bundled into the artifact, and also a dependency of a dependency, + * reaches the consumers of the artifact twice. The SBOM tells both. + */ + @Test + fun `that a dependency also depends on`() { + val document = sbom( + "root DEPENDS_ON d", + "d DEPENDS_ON g", + packages = listOf(module("d"), module("g")) + ) + + ArtifactComponents(dependencies = keys("d", "g"), bundled = keys("g")) + .describeIn(document) + + document.relationships() shouldContainExactlyInAnyOrder listOf( + DESCRIBES_ROOT, + "root DEPENDS_ON d", + "d DEPENDS_ON g", + "root CONTAINS g", + ) + } + + @Test + fun `other than the artifact itself`() { + val document = sbom("root DEPENDS_ON a", packages = listOf(module("a"))) + + ArtifactComponents(dependencies = keys("a"), bundled = setOf(rootKey)) + .describeIn(document) + + document.relationships() shouldContainExactly + listOf(DESCRIBES_ROOT, "root DEPENDS_ON a") + } + } + + @Nested + inner class `keep` { + + @Test + fun `the dependencies of the artifact as they are`() { + val document = sbom( + "root DEPENDS_ON d", + "d DEPENDS_ON e", + packages = listOf(module("d"), module("e")) + ) + + ArtifactComponents(dependencies = keys("d", "e")).describeIn(document) + + document.relationships() shouldContainExactly listOf( + DESCRIBES_ROOT, + "root DEPENDS_ON d", + "d DEPENDS_ON e", + ) + } + + @Test + fun `a package it cannot identify`() { + val document = sbom( + "root DEPENDS_ON u", + packages = listOf(module("u", name = "unidentified")) + ) + + ArtifactComponents().describeIn(document) + + document.packageIds() shouldContainExactly listOf(ROOT_ID, "u") + document.relationships() shouldContainExactly + listOf(DESCRIBES_ROOT, "root DEPENDS_ON u") + } + } + + @Nested + inner class `leave out` { + + @Test + fun `a package the artifact neither depends on nor bundles`() { + val document = sbom( + "root DEPENDS_ON d", + "root DEPENDS_ON x", + packages = listOf(module("d"), module("x")) + ) + + ArtifactComponents(dependencies = keys("d")).describeIn(document) + + document.packageIds() shouldContainExactly listOf(ROOT_ID, "d") + document.relationships() shouldContainExactly + listOf(DESCRIBES_ROOT, "root DEPENDS_ON d") + } + + @Test + fun `every file of a component it leaves out`() { + val document = sbom( + "root DEPENDS_ON c", + *filesOfComponent, + packages = componentOfTwoFiles() + ) + + ArtifactComponents().describeIn(document) + + document.packageIds() shouldContainExactly listOf(ROOT_ID) + document.relationships() shouldContainExactly listOf(DESCRIBES_ROOT) + } + + /** + * The plugin walks each configuration of an SBOM from its root, through the + * packages it already knows, and lists a package it has not seen yet under the + * package it was found through. So a component found while looking for the + * bundled ones can land under a dependency whose own dependencies the artifact + * narrowed, for example by an exclusion. + */ + @Test + fun `a dependency of a dependency that only the bundled content brought`() { + val document = sbom( + "root DEPENDS_ON d", + "d DEPENDS_ON b", + packages = listOf(module("d"), module("b")) + ) + + ArtifactComponents(dependencies = keys("d"), bundled = keys("b")) + .describeIn(document) + + document.relationships() shouldContainExactlyInAnyOrder listOf( + DESCRIBES_ROOT, + "root DEPENDS_ON d", + "root CONTAINS b", + ) + } + + @Test + fun `the license texts only the packages it leaves out refer to`() { + val kept = "LicenseRef-gnrtd0" + val leftOut = "LicenseRef-gnrtd1" + val document = sbom( + "root DEPENDS_ON d", + "root DEPENDS_ON x", + packages = listOf( + module("d", license = "($kept AND Apache-2.0)"), + module("x", license = leftOut), + ), + licenses = listOf(kept, leftOut) + ) + + ArtifactComponents(dependencies = keys("d")).describeIn(document) + + document.licenseIds() shouldContainExactly listOf(kept) + } + } + + @Nested + inner class `reject a document` { + + @Test + fun `describing no package`() { + val document = sbom(packages = emptyList(), describes = emptyList()) + + shouldThrow { + ArtifactComponents().describeIn(document) + } + } + + @Test + fun `describing several packages`() { + val document = sbom(packages = listOf(module("a")), describes = listOf(ROOT_ID, "a")) + + shouldThrow { + ArtifactComponents().describeIn(document) + } + } + } +} + +private val mapper = ObjectMapper() + +private val logger = Logging.getLogger(ArtifactComponentsSpec::class.java) + +/** The path of the project whose artifact the documents describe. */ +private const val ROOT_PATH = ":artifact" + +/** The ID of the package of the artifact, which the documents describe. */ +private const val ROOT_ID = "root" + +private val rootKey = ComponentKey.ofProject(ROOT_PATH) + +private const val DESCRIBES_ROOT = "DOCUMENT DESCRIBES root" + +private const val ID_PREFIX = "SPDXRef-" + +private fun ArtifactComponents.describeIn(document: ObjectNode) = describeIn(document, logger) + +/** + * Returns the keys of the modules that [module] creates under the given IDs. + */ +private fun keys(vararg ids: String): Set = + ids.map { ComponentKey.ofModule(group = MODULE_GROUP, name = it, version = MODULE_VERSION) } + .toSet() + +private const val MODULE_GROUP = "com.example" + +private const val MODULE_VERSION = "1.0" + +/** + * Creates an SPDX document describing the `root` package, with the given [packages] + * and [relationships]. + */ +private fun sbom( + vararg relationships: String, + packages: List, + licenses: List = emptyList(), + describes: List = listOf(ROOT_ID) +): ObjectNode = mapper.createObjectNode().apply { + put(SpdxField.spdxId, DOCUMENT_ID) + putArray(SpdxField.hasExtractedLicensingInfos).apply { + licenses.forEach { addObject().put(SpdxField.licenseId, it).put("extractedText", it) } + } + putArray(SpdxField.packages).apply { + add(project(ROOT_ID, path = ROOT_PATH)) + packages.forEach(::add) + } + putArray(SpdxField.relationships).apply { + describes.forEach { add(relationship("DOCUMENT DESCRIBES $it")) } + relationships.forEach { add(relationship(it)) } + } +} + +private fun relationship(text: String): ObjectNode { + val (element, type, related) = text.split(' ') + return mapper.createObjectNode() + .put(SpdxField.spdxElementId, ID_PREFIX + element) + .put(SpdxField.relationshipType, type) + .put(SpdxField.relatedSpdxElement, ID_PREFIX + related) +} + +/** + * Creates the packages the plugin writes for the component `c`, resolved to two files: + * the package of the component, and the package of each file. + */ +private fun componentOfTwoFiles(): List = listOf( + module("c"), + module("c-main", name = "$MODULE_GROUP:c"), + module("c-extra", name = "$MODULE_GROUP:c:extra"), +) + +/** + * The relationships of the package of the component `c` to the packages of its files. + */ +private val filesOfComponent = arrayOf("c CONTAINS c-main", "c CONTAINS c-extra") + +/** + * Creates the package the SPDX Gradle Plugin writes for the project with the given [path]. + */ +private fun project(id: String, path: String): ObjectNode = + mapper.createObjectNode() + .put(SpdxField.spdxId, ID_PREFIX + id) + .put(SpdxField.name, path.substringAfterLast(':')) + .put(SpdxField.versionInfo, "1.0.0") + .put(SpdxField.sourceInfo, "git+https://github.com/example/repo@unknown#$id[$path]") + .put(SpdxField.licenseDeclared, NO_ASSERTION) + +/** + * Creates the package the SPDX Gradle Plugin writes for a Maven module. + * + * The package is named `com.example:` unless another [name] is given. + */ +private fun module( + id: String, + name: String = "$MODULE_GROUP:$id", + license: String = NO_ASSERTION +): ObjectNode = + mapper.createObjectNode() + .put(SpdxField.spdxId, ID_PREFIX + id) + .put(SpdxField.name, name) + .put(SpdxField.versionInfo, MODULE_VERSION) + .put(SpdxField.licenseConcluded, NO_ASSERTION) + .put(SpdxField.licenseDeclared, license) + +private const val NO_ASSERTION = "NOASSERTION" + +private fun ObjectNode.relationships(): List = + this[SpdxField.relationships].map { relationship -> + listOf(SpdxField.spdxElementId, SpdxField.relationshipType, SpdxField.relatedSpdxElement) + .joinToString(" ") { relationship[it].asText().removePrefix(ID_PREFIX) } + } + +private fun ObjectNode.packageIds(): List = + this[SpdxField.packages].map { it[SpdxField.spdxId].asText().removePrefix(ID_PREFIX) } + +private fun ObjectNode.licenseIds(): List = + this[SpdxField.hasExtractedLicensingInfos].map { it[SpdxField.licenseId].asText() } diff --git a/buildSrc/src/test/kotlin/io/spine/gradle/publish/CheckVersionIncrementIgTest.kt b/buildSrc/src/test/kotlin/io/spine/gradle/publish/CheckVersionIncrementIgTest.kt new file mode 100644 index 0000000..2d440b0 --- /dev/null +++ b/buildSrc/src/test/kotlin/io/spine/gradle/publish/CheckVersionIncrementIgTest.kt @@ -0,0 +1,179 @@ +/* + * Copyright 2026 CodeMatters, Lda. + * + * 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 io.spine.gradle.publish + +import io.kotest.matchers.string.shouldContain +import io.kotest.matchers.string.shouldNotContain +import java.io.File +import org.gradle.testkit.runner.GradleRunner +import org.junit.jupiter.api.DisplayName +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.io.TempDir + +/** + * Runs `checkVersionIncrement` in a real build via Gradle TestKit. + * + * The build publishes a module under a custom `artifactId`, as `:compiler-plugins` of + * `core-jvm-compiler` does, and checks it against a Maven repository in a local directory. + * The environment of a pull request to `master` makes the task run. + * + * Unlike the tests built with `ProjectBuilder`, this one sees the output of the build, + * which carries the warnings of the task. + * + * The builds run without the [ciVariables] of the test JVM, like those of + * [IncrementGuardIgTest], which explains why a TestKit build must not see `CI`. + */ +@DisplayName("`checkVersionIncrement` should") +internal class CheckVersionIncrementIgTest { + + @TempDir + lateinit var projectDir: File + + @Test + fun `fail when the version of a publication is already published`() { + repoDir.writeMetadata(repository = "snapshots", path = artifactPath, version) + writeBuild() + + val output = runner().buildAndFail().output + + output shouldContain "The version `$version` of `$artifactPath` is already published" + } + + @Test + fun `pass without a warning when the version is not published yet`() { + repoDir.writeMetadata(repository = "snapshots", path = artifactPath, previousVersion) + writeBuild() + + val output = runner().build().output + + output shouldNotContain "No `${MavenMetadata.FILE_NAME}` is found" + } + + @Test + fun `warn when no repository has the metadata of a publication`() { + writeBuild() + + val output = runner().build().output + + output shouldContain "No `${MavenMetadata.FILE_NAME}` is found for `$artifactPath`" + output shouldContain + "cannot tell whether the version `$version` is already published" + } + + /** + * The directory holding the `snapshots` and `releases` repositories. + */ + private val repoDir: File + get() = projectDir.resolve("repo") + + private fun runner(): GradleRunner = + GradleRunner.create() + .withProjectDir(projectDir) + .withEnvironment(pullRequestEnvironment()) + .withArguments(IncrementGuard.taskName, "--stacktrace") + + /** + * Returns the environment of a build of a pull request to `master`, outside + * the `Version Guard` workflow, so that the task runs and skips the comparison + * with the base branch. + */ + private fun pullRequestEnvironment(): Map = + System.getenv() - ciVariables + mapOf( + "GITHUB_EVENT_NAME" to "pull_request", + "GITHUB_BASE_REF" to "master", + ) + + private fun writeBuild() { + val repoUrl = repoDir.toURI().toString().removeSuffix("/") + file("settings.gradle.kts").writeText( + """ + rootProject.name = "compiler-plugins" + """.trimIndent() + ) + file("build.gradle.kts").writeText( + """ + buildscript { + dependencies { + classpath(files( + ${buildSrcClasspath()} + )) + } + } + + import io.spine.gradle.publish.CheckVersionIncrement + import io.spine.gradle.publish.IncrementGuard + import io.spine.gradle.repo.Repository + + plugins { + `maven-publish` + } + + group = "$group" + version = "$version" + + apply() + + publishing { + publications { + create("fatJar") { + artifactId = "$artifactId" + } + } + } + + tasks.named(IncrementGuard.taskName) { + repository = Repository( + name = "local", + releases = "$repoUrl/releases", + snapshots = "$repoUrl/snapshots", + ) + } + """.trimIndent() + ) + } + + private fun file(relativePath: String): File = projectDir.resolve(relativePath) + + /** + * Renders the classpath with the production classes of `buildSrc` as + * arguments of `files(...)`, for injection into the build script classpath + * of the generated build. + * + * The classpath comes from the `test` task in `buildSrc/build.gradle.kts`. + */ + private fun buildSrcClasspath(): String { + val classpath = requireNotNull(System.getProperty("buildSrc.classpath")) { + "The `buildSrc.classpath` system property is not set." + + " It is supplied by the `test` task in `buildSrc/build.gradle.kts`." + } + return classpath.split(File.pathSeparator).joinToString(",\n") { + " \"${File(it).invariantSeparatorsPath}\"" + } + } + + private companion object { + + const val group = "io.spine.tools" + const val version = "2.0.0-SNAPSHOT.094" + const val previousVersion = "2.0.0-SNAPSHOT.093" + + /** + * The `artifactId` of the publication, unrelated to the name of the project. + */ + const val artifactId = "core-jvm-plugins" + + const val artifactPath = "io/spine/tools/$artifactId" + } +} diff --git a/buildSrc/src/test/kotlin/io/spine/gradle/publish/CustomPublicationHandlerIgTest.kt b/buildSrc/src/test/kotlin/io/spine/gradle/publish/CustomPublicationHandlerIgTest.kt new file mode 100644 index 0000000..1b624e1 --- /dev/null +++ b/buildSrc/src/test/kotlin/io/spine/gradle/publish/CustomPublicationHandlerIgTest.kt @@ -0,0 +1,358 @@ +/* + * Copyright 2026 CodeMatters, Lda. + * + * 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 io.spine.gradle.publish + +import LicenseSettings +import io.kotest.assertions.withClue +import io.kotest.matchers.shouldBe +import java.io.File +import javax.xml.parsers.DocumentBuilderFactory +import javax.xml.xpath.XPathFactory +import org.gradle.testkit.runner.GradleRunner +import org.junit.jupiter.api.DisplayName +import org.junit.jupiter.api.io.TempDir +import org.junit.jupiter.params.ParameterizedTest +import org.junit.jupiter.params.provider.EnumSource +import org.w3c.dom.Document + +/** + * Verifies the POMs of a module with custom publishing that applies + * `java-gradle-plugin`, against a real multi-module build run via Gradle TestKit. + * + * Gradle's `java-gradle-plugin` creates its publications in an `afterEvaluate` action + * of its own: `pluginMaven` for the plugin JAR, and a marker for each declared plugin. + * Whether that happens before or after the handler is applied depends on how + * the module is declared as one with custom publishing, so each test runs for + * every [Declaration]. + * + * The fixture also publishes a module in the standard way, so that the project-wide + * attributes in the POM of a custom publication are compared with those of + * a standard publication, rather than with a copy of the expected values. + */ +@DisplayName("`CustomPublicationHandler` should") +internal class CustomPublicationHandlerIgTest { + + @TempDir + lateinit var projectDir: File + + @ParameterizedTest + @EnumSource(Declaration::class) + fun `publish 'pluginMaven' with the POM of a standard publication`( + declaration: Declaration + ) { + build(declaration) + val standard = pom(library, standardPublication) + val plugin = pom(pluginModule, pluginPublication) + + plugin["/project/groupId"] shouldBe group + plugin["/project/artifactId"] shouldBe pluginArtifact + plugin["/project/version"] shouldBe version + plugin["/project/description"] shouldBe moduleDescription + plugin shouldDescribeTheProjectLike standard + } + + /** + * A marker is resolved by the ID of the plugin it points to, and describes + * that plugin. Both come from the plugin declaration and must not be replaced + * with the attributes of the module. + */ + @ParameterizedTest + @EnumSource(Declaration::class) + fun `keep the identity of a plugin marker, adding the project-wide attributes`( + declaration: Declaration + ) { + build(declaration) + val standard = pom(library, standardPublication) + val marker = pom(pluginModule, markerPublication) + + marker["/project/groupId"] shouldBe pluginId + marker["/project/artifactId"] shouldBe "$pluginId.gradle.plugin" + marker["/project/name"] shouldBe pluginName + marker["/project/description"] shouldBe pluginDescription + marker["/project/dependencies/dependency/artifactId"] shouldBe pluginArtifact + marker shouldDescribeTheProjectLike standard + } + + /** + * The ways to declare a module as one with custom publishing. + * + * Both the handler and `java-gradle-plugin` act in `afterEvaluate` of + * the module, which runs the actions in the order they were added. + * + * @property inRoot Tells if the root project lists the module + * in `modulesWithCustomPublishing`. + * @property inModule Tells if the module opens `spinePublishing` + * with `customPublishing = true`. + */ + enum class Declaration(val inRoot: Boolean, val inModule: Boolean) { + + /** + * The root project lists the module in `modulesWithCustomPublishing`. + * + * The root project is evaluated first, so the handler is applied + * before `java-gradle-plugin` creates its publications. + */ + IN_ROOT(inRoot = true, inModule = false), + + /** + * The module opens `spinePublishing` with `customPublishing = true` + * after applying `java-gradle-plugin`, so the handler is applied + * after the publications are created. + */ + IN_MODULE(inRoot = false, inModule = true), + + /** + * Both of the above, like a module that applies `uber-jar-module` + * and is listed by the root project. + * + * The module configures the same handler for the second time, which + * must not add the project-wide attributes to a publication twice. + */ + IN_BOTH(inRoot = true, inModule = true) + } + + private fun build(declaration: Declaration) { + writeSettings() + writeRootScript(declaration) + writeLibraryScript() + writePluginScript(declaration) + GradleRunner.create() + .withProjectDir(projectDir) + .withArguments( + pomTask(library, standardPublication), + pomTask(pluginModule, pluginPublication), + pomTask(pluginModule, markerPublication), + "--stacktrace" + ) + .build() + } + + private fun writeSettings() { + file("settings.gradle.kts").writeText( + """ + rootProject.name = "plugin-sample" + include("$library", "$pluginModule") + """.trimIndent() + ) + } + + private fun writeRootScript(declaration: Declaration) { + val customModules = if (declaration.inRoot) "setOf(\"$pluginModule\")" else "emptySet()" + file("build.gradle.kts").writeText( + """ + buildscript { + dependencies { + classpath(files( + ${buildSrcClasspath()} + )) + } + } + + import io.spine.gradle.publish.spinePublishing + + allprojects { + group = "$group" + version = "$version" + } + + spinePublishing { + modules = setOf("$library") + modulesWithCustomPublishing = $customModules + toolArtifactPrefix = "$toolPrefix" + destinations = emptySet() + } + """.trimIndent() + ) + } + + private fun writeLibraryScript() { + file("$library/build.gradle.kts").apply { + parentFile.mkdirs() + writeText( + """ + plugins { + `java-library` + } + + // `javadocJar` of `spinePublishing` is wired to Dokka, which + // this fixture does not apply: only the POMs are under test. + tasks.register("dokkaGeneratePublicationJavadoc") + """.trimIndent() + ) + } + } + + private fun writePluginScript(declaration: Declaration) { + val script = buildList { + if (declaration.inModule) { + add("import io.spine.gradle.publish.spinePublishing") + } + add( + """ + plugins { + `java-gradle-plugin` + `maven-publish` + } + + description = "$moduleDescription" + + gradlePlugin { + plugins { + create("$pluginDeclaration") { + id = "$pluginId" + implementationClass = "io.spine.sample.SamplePlugin" + displayName = "$pluginName" + description = "$pluginDescription" + } + } + } + """.trimIndent() + ) + if (declaration.inModule) { + add( + """ + spinePublishing { + customPublishing = true + toolArtifactPrefix = "$toolPrefix" + destinations = emptySet() + } + """.trimIndent() + ) + } + } + file("$pluginModule/build.gradle.kts").apply { + parentFile.mkdirs() + writeText(script.joinToString("\n\n")) + } + } + + private fun pom(module: String, publication: String): Pom = + Pom(file("$module/build/publications/$publication/pom-default.xml")) + + private fun file(relativePath: String): File = projectDir.resolve(relativePath) + + /** + * Renders the classpath with the production classes of `buildSrc` as + * arguments of `files(...)`, for injection into the build script classpath + * of the generated build. + * + * The classpath comes from the `test` task in `buildSrc/build.gradle.kts`. + */ + private fun buildSrcClasspath(): String { + val classpath = requireNotNull(System.getProperty("buildSrc.classpath")) { + "The `buildSrc.classpath` system property is not set." + + " It is supplied by the `test` task in `buildSrc/build.gradle.kts`." + } + return classpath.split(File.pathSeparator).joinToString(",\n") { + " \"${File(it).invariantSeparatorsPath}\"" + } + } + + private companion object { + + const val group = "io.spine.tools" + const val version = "1.0.0" + const val toolPrefix = "sample-" + + /** + * The module published in the standard way, to compare the POMs with. + */ + const val library = "library" + + /** + * The module applying `java-gradle-plugin`, published in a custom way. + */ + const val pluginModule = "plugin" + const val moduleDescription = "The module publishing the sample plugin." + + /** + * The artifact ID expected for the plugin JAR: the name of the module + * with the prefix of a tool module. + */ + const val pluginArtifact = "$toolPrefix$pluginModule" + + const val pluginDeclaration = "sample" + const val pluginId = "io.spine.sample" + const val pluginName = "Sample Plugin" + const val pluginDescription = "Does nothing, being a sample." + + /* + * The names of the publications, as given by the code that creates them. + */ + const val standardPublication = StandardJavaPublicationHandler.PUBLICATION_NAME + const val pluginPublication = "pluginMaven" + const val markerPublication = "${pluginDeclaration}PluginMarkerMaven" + + const val licenseNamePath = "/project/licenses/license/name" + + /** + * The POM elements that describe the project as a whole, + * and so are the same for every publication of the project. + * + * The number of licenses is compared as well, so that a license + * added twice to the same POM does not pass unnoticed. + */ + val projectWideAttributes = listOf( + "/project/inceptionYear", + "count(/project/licenses/license)", + licenseNamePath, + "/project/licenses/license/url", + "/project/licenses/license/distribution", + "/project/scm/url", + "/project/scm/connection", + "/project/scm/developerConnection", + ) + + fun pomTask(module: String, publication: String): String { + val name = publication.replaceFirstChar { it.uppercase() } + return ":$module:generatePomFileFor${name}Publication" + } + } + + /** + * Asserts that this POM describes the project in the same way as + * the [standard] one does. + * + * The license is also checked against [LicenseSettings], since two POMs + * with no license at all would describe the project in the same way, too. + */ + private infix fun Pom.shouldDescribeTheProjectLike(standard: Pom) { + standard[licenseNamePath] shouldBe LicenseSettings.name + projectWideAttributes.forEach { path -> + withClue(path) { + this[path] shouldBe standard[path] + } + } + } +} + +/** + * A POM file generated by the fixture, queried with XPath. + * + * The document is parsed without namespace awareness, so that the paths name + * the elements without the POM namespace prefix. + */ +private class Pom(file: File) { + + private val document: Document = + DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(file) + + /** + * Evaluates the given XPath [expression] against the POM, returning + * an empty string if the expression selects nothing. + */ + operator fun get(expression: String): String = + XPathFactory.newInstance().newXPath().evaluate(expression, document).trim() +} diff --git a/buildSrc/src/test/kotlin/io/spine/gradle/publish/IncrementGuardIgTest.kt b/buildSrc/src/test/kotlin/io/spine/gradle/publish/IncrementGuardIgTest.kt new file mode 100644 index 0000000..c4fea07 --- /dev/null +++ b/buildSrc/src/test/kotlin/io/spine/gradle/publish/IncrementGuardIgTest.kt @@ -0,0 +1,201 @@ +/* + * Copyright 2026 CodeMatters, Lda. + * + * 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 io.spine.gradle.publish + +import io.kotest.assertions.withClue +import io.kotest.matchers.shouldBe +import io.kotest.matchers.string.shouldContain +import java.io.File +import org.gradle.testkit.runner.BuildResult +import org.gradle.testkit.runner.GradleRunner +import org.gradle.testkit.runner.TaskOutcome.SKIPPED +import org.gradle.testkit.runner.TaskOutcome.SUCCESS +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.DisplayName +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.io.TempDir + +/** + * Verifies when `checkVersionIncrement` runs in a real build that uses the + * configuration cache. + * + * Every case runs the build twice: the first run stores the configuration cache entry, + * and the second one reuses it. The task must reach the same outcome both times, so the + * decision whether to run cannot rely on configuration that a reused entry skips. + * + * The builds run without the `CI` and GitHub Actions variables of the test JVM, so the + * outcome is the same on a workstation and on CI. The Maven repository the task queries + * is a missing local directory, so the task finds no published versions and passes + * without network access. + * + * [io.spine.gradle.Build.ci] is read once per class loader, and a TestKit daemon may reuse + * the build script class loader across builds. Therefore, any TestKit build in this test + * run that reads `Build.ci` with `CI` set — e.g., by running `checkVersionIncrement` + * without removing `CI` from its environment — would leak that value into these builds. + */ +@DisplayName("`checkVersionIncrement` should, with the configuration cache,") +internal class IncrementGuardIgTest { + + @TempDir + lateinit var projectDir: File + + @BeforeEach + fun createBuild() { + file("settings.gradle.kts").writeText( + """ + rootProject.name = "guarded-sample" + include("lib", "app") + """.trimIndent() + ) + file("lib").mkdirs() + file("app").mkdirs() + file("build.gradle.kts").writeText( + """ + buildscript { + dependencies { + classpath(files( + ${buildSrcClasspath()} + )) + } + } + + import io.spine.gradle.publish.CheckVersionIncrement + import io.spine.gradle.publish.IncrementGuard + import io.spine.gradle.repo.Repository + + allprojects { + group = "io.spine.sample" + version = "1.0.0" + } + + subprojects { + apply(plugin = "maven-publish") + apply() + configure { + publications { + create("maven") + } + } + val unpublished = rootDir.resolve("repository").toURI().toString() + tasks.withType().configureEach { + repository = Repository( + name = "unpublished", + releases = unpublished, + snapshots = unpublished + ) + } + } + """.trimIndent() + ) + } + + @Test + fun `run when its project publishes to Maven Local`() { + runStoringThenReusing(":lib:publishToMavenLocal") { + it.task(":lib:checkVersionIncrement")?.outcome shouldBe SUCCESS + } + } + + @Test + fun `skip when only a sibling project publishes to Maven Local`() { + runStoringThenReusing(":lib:checkVersionIncrement", ":app:publishToMavenLocal") { + it.task(":lib:checkVersionIncrement")?.outcome shouldBe SKIPPED + it.task(":app:checkVersionIncrement")?.outcome shouldBe SUCCESS + } + } + + @Test + fun `skip on a local build that does not publish`() { + runStoringThenReusing(":lib:checkVersionIncrement") { + it.task(":lib:checkVersionIncrement")?.outcome shouldBe SKIPPED + } + } + + @Test + fun `run on a pull request to a protected branch`() { + val pullRequest = mapOf( + "GITHUB_EVENT_NAME" to "pull_request", + "GITHUB_BASE_REF" to "master" + ) + + runStoringThenReusing(":lib:checkVersionIncrement", env = pullRequest) { + it.task(":lib:checkVersionIncrement")?.outcome shouldBe SUCCESS + } + } + + /** + * Runs the given [tasks] twice with the configuration cache, and checks the result of + * each run with [verify]. + * + * The first run stores the cache entry, and the second one reuses it. The [env] + * variables are added to the environment of the test JVM, from which the [ciVariables] + * are removed. + */ + private fun runStoringThenReusing( + vararg tasks: String, + env: Map = emptyMap(), + verify: (BuildResult) -> Unit + ) { + val stored = runGradle(tasks, env) + withClue("The run that stores the configuration cache entry") { + stored.output shouldContain "Configuration cache entry stored" + verify(stored) + } + val reused = runGradle(tasks, env) + withClue("The run that reuses the configuration cache entry") { + reused.output shouldContain "Reusing configuration cache" + verify(reused) + } + } + + private fun runGradle(tasks: Array, env: Map): BuildResult { + val environment = System.getenv() - ciVariables + env + return GradleRunner.create() + .withProjectDir(projectDir) + .withEnvironment(environment) + .withArguments( + *tasks, + "--configuration-cache", + "-Dmaven.repo.local=${file("m2").absolutePath}", + "--stacktrace" + ) + .build() + } + + private fun file(relativePath: String): File = projectDir.resolve(relativePath) + + /** + * Renders the classpath with the production classes of `buildSrc` as + * arguments of `files(...)`, for injection into the build script classpath + * of the generated build. + * + * The classpath comes from the `test` task in `buildSrc/build.gradle.kts`. + */ + private fun buildSrcClasspath(): String { + val classpath = requireNotNull(System.getProperty("buildSrc.classpath")) { + "The `buildSrc.classpath` system property is not set." + + " It is supplied by the `test` task in `buildSrc/build.gradle.kts`." + } + return classpath.split(File.pathSeparator).joinToString(",\n") { + " \"${File(it).invariantSeparatorsPath}\"" + } + } +} + +/** + * The environment variables that select the CI behavior of [IncrementGuard] + * and [CheckVersionIncrement]. + */ +internal val ciVariables = setOf("CI", "GITHUB_EVENT_NAME", "GITHUB_BASE_REF", "VERSION_GUARD") diff --git a/buildSrc/src/test/kotlin/io/spine/gradle/publish/IncrementGuardTest.kt b/buildSrc/src/test/kotlin/io/spine/gradle/publish/IncrementGuardTest.kt index 7b317c9..9bcbc4e 100644 --- a/buildSrc/src/test/kotlin/io/spine/gradle/publish/IncrementGuardTest.kt +++ b/buildSrc/src/test/kotlin/io/spine/gradle/publish/IncrementGuardTest.kt @@ -1,45 +1,44 @@ /* - * Copyright 2026, TeamDev. All rights reserved. + * Copyright 2026 CodeMatters, Lda. * - * 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 + * 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 * - * Redistribution and use in source and/or binary forms, with or without - * modification, must retain the above copyright notice and the following - * disclaimer. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 io.spine.gradle.publish +import io.kotest.assertions.throwables.shouldNotThrowAny +import io.kotest.assertions.throwables.shouldThrow +import io.kotest.matchers.collections.shouldBeEmpty import io.kotest.matchers.collections.shouldContain import io.kotest.matchers.collections.shouldNotContain import io.kotest.matchers.shouldBe +import io.kotest.matchers.string.shouldContain import io.spine.gradle.publish.IncrementGuard.Companion.localPublishPlanned import io.spine.gradle.publish.IncrementGuard.Companion.mustVerify import io.spine.gradle.publish.IncrementGuard.Companion.shouldCheckVersion import io.spine.gradle.publish.IncrementGuard.Companion.shouldCompareToBase +import io.spine.gradle.repo.Repository +import java.io.File +import org.gradle.api.GradleException import org.gradle.api.Project import org.gradle.api.Task +import org.gradle.api.publish.maven.MavenPublication import org.gradle.api.publish.maven.tasks.PublishToMavenLocal +import org.gradle.api.publish.maven.tasks.PublishToMavenRepository +import org.gradle.kotlin.dsl.create import org.gradle.testfixtures.ProjectBuilder import org.junit.jupiter.api.DisplayName import org.junit.jupiter.api.Nested import org.junit.jupiter.api.Test +import org.junit.jupiter.api.io.TempDir @DisplayName("`IncrementGuard` should") class IncrementGuardTest { @@ -168,6 +167,17 @@ class IncrementGuardTest { localPublishPlanned(listOf(appPublish), lib) shouldBe false } + + @Test + fun `but not when the project publishes only to a remote repository`() { + val project = guardedProject() + val remotePublish = project.tasks.register( + "publishFooPublicationToCloudRepository", + PublishToMavenRepository::class.java + ).get() + + localPublishPlanned(listOf(remotePublish), project) shouldBe false + } } @Nested @@ -200,8 +210,266 @@ class IncrementGuardTest { check.dependencyNames() shouldNotContain IncrementGuard.taskName } } + + @Nested + inner class `configure 'checkVersionIncrement' with` { + + @Test + fun `the root directory of the build`() { + val root = ProjectBuilder.builder().build() + val sub = ProjectBuilder.builder().withParent(root).withName("sub").build() + sub.pluginManager.apply(IncrementGuard::class.java) + + sub.checkVersionTask().rootDir.get().asFile shouldBe root.rootDir + } + + @Test + fun `the artifact path of each Maven publication`() { + val project = publishingProject() + project.publication( + "kotlinMultiplatform", + groupId = "io.spine", + artifactId = "spine-logging" + ) + project.publication("jvm", groupId = "io.spine", artifactId = "spine-logging-jvm") + + project.checkVersionTask().artifactPaths.get() shouldBe + setOf("io/spine/spine-logging", "io/spine/spine-logging-jvm") + } + + /** + * The case of `:compiler-plugins` in `core-jvm-compiler`, which publishes + * `core-jvm-plugins`. A path computed from the module name does not exist, + * so the check would pass even for an already published version. + */ + @Test + fun `the artifact path of a publication with a custom artifact ID`() { + val project = publishingProject("compiler-plugins") + project.publication( + "fatJar", + groupId = "io.spine.tools", + artifactId = "core-jvm-plugins" + ) + + project.checkVersionTask().artifactPaths.get() shouldBe + setOf("io/spine/tools/core-jvm-plugins") + } + + @Test + fun `the artifact path under the tool artifact prefix`() { + val root = ProjectBuilder.builder().build() + root.extensions.create(SpinePublishing.extensionName, root).run { + toolArtifactPrefix = "core-jvm-" + modulesWithCustomPublishing = setOf("guarded-tool") + } + val tool = ProjectBuilder.builder().withParent(root).withName("guarded-tool").build() + tool.group = "io.spine.tools" + tool.pluginManager.apply("maven-publish") + tool.pluginManager.apply(IncrementGuard::class.java) + val task = tool.checkVersionTask() + tool.publications.create("mavenJava") + CustomPublicationHandler.serving(tool, emptySet()).apply() + + task.artifactPaths.get() shouldBe + setOf("io/spine/tools/core-jvm-guarded-tool") + } + + @Test + fun `the coordinates set after the task is created`() { + val project = publishingProject() + val task = project.checkVersionTask() + val publication = project.publication( + "mavenJava", + groupId = "io.spine", + artifactId = "base" + ) + publication.artifactId = "spine-base" + + task.artifactPaths.get() shouldBe setOf("io/spine/spine-base") + } + + /** + * A marker may be uploaded without the plugin it points to, + * so it must be checked on its own. + */ + @Test + fun `the artifact path of a plugin marker`() { + val project = publishingProject() + project.publication( + "pluginMaven", + groupId = "io.spine.tools", + artifactId = "core-jvm-gradle-plugin" + ) + project.publication( + "coreJvmPluginMarkerMaven", + groupId = "io.spine.core-jvm", + artifactId = "io.spine.core-jvm.gradle.plugin" + ) + + project.checkVersionTask().artifactPaths.get() shouldBe setOf( + "io/spine/tools/core-jvm-gradle-plugin", + "io/spine/core-jvm/io.spine.core-jvm.gradle.plugin" + ) + } + + @Test + fun `no artifact paths for a project that does not publish`() { + val project = ProjectBuilder.builder().build() + project.pluginManager.apply(IncrementGuard::class.java) + + project.checkVersionTask().artifactPaths.get().shouldBeEmpty() + } + } + + @Nested + inner class `make 'checkVersionIncrement' fail` { + + @TempDir + lateinit var repoDir: File + + /** + * Only the publication checked last has the version published, so + * the task must look past the artifacts that do not. + */ + @Test + fun `when the version of any publication is already published`() { + val project = publishingProject() + project.version = publishedVersion + project.publication( + "fatJar", + groupId = "io.spine.tools", + artifactId = "core-jvm-plugins" + ) + project.publication( + "mavenJava", + groupId = "io.spine.tools", + artifactId = "core-jvm-gradle-plugin" + ) + repoDir.writeMetadata( + repository = "snapshots", + path = "io/spine/tools/core-jvm-plugins", + "2.0.0-SNAPSHOT.093" + ) + repoDir.writeMetadata( + repository = "snapshots", + path = "io/spine/tools/core-jvm-gradle-plugin", + publishedVersion + ) + val task = project.checkVersionTask() + task.repository = repoDir.asRepository() + + val exception = shouldThrow { task.checkVersion() } + + exception.message shouldContain "already published" + exception.message shouldContain "io/spine/tools/core-jvm-gradle-plugin" + } + + @Test + fun `when the version is already published to the releases repository`() { + val project = publishingProject() + project.version = "2.0.0" + project.publication("mavenJava", groupId = "io.spine", artifactId = "spine-base") + repoDir.writeMetadata(repository = "releases", path = "io/spine/spine-base", "2.0.0") + val task = project.checkVersionTask() + task.repository = repoDir.asRepository() + + val exception = shouldThrow { task.checkVersion() } + + exception.message shouldContain "already published" + } + + /** + * The unreadable metadata in `releases` stands for an unreachable repository, + * such as a response with the 401 or 5xx code. + */ + @Test + fun `when the version is published to a repository checked before a failing one`() { + val project = publishingProject() + project.version = publishedVersion + project.publication("mavenJava", groupId = "io.spine", artifactId = "spine-base") + repoDir.writeMetadata( + repository = "snapshots", + path = "io/spine/spine-base", + publishedVersion + ) + repoDir.resolve("releases/io/spine/spine-base/${MavenMetadata.FILE_NAME}").run { + parentFile.mkdirs() + writeText("Not a Maven metadata document.") + } + val task = project.checkVersionTask() + task.repository = repoDir.asRepository() + + val exception = shouldThrow { task.checkVersion() } + + exception.message shouldContain "already published" + } + } + + @Nested + inner class `make 'checkVersionIncrement' pass` { + + @TempDir + lateinit var repoDir: File + + @Test + fun `when the version is not published yet`() { + val project = publishingProject() + project.version = "2.0.0-SNAPSHOT.095" + project.publication( + "fatJar", + groupId = "io.spine.tools", + artifactId = "core-jvm-plugins" + ) + repoDir.writeMetadata( + repository = "snapshots", + path = "io/spine/tools/core-jvm-plugins", + publishedVersion + ) + val task = project.checkVersionTask() + task.repository = repoDir.asRepository() + + shouldNotThrowAny { task.checkVersion() } + } + + /** + * The task logs a warning in this case: it cannot tell a new artifact from + * a path that does not match the published one. + * + * @see CheckVersionIncrementIgTest for the check of the warning + */ + @Test + fun `when the artifact has never been published`() { + val project = publishingProject() + project.version = publishedVersion + project.publication( + "mavenJava", + groupId = "io.spine.tools", + artifactId = "core-jvm-new-module" + ) + val task = project.checkVersionTask() + task.repository = repoDir.asRepository() + + shouldNotThrowAny { task.checkVersion() } + } + + @Test + fun `for a project that does not publish`() { + val project = ProjectBuilder.builder().build() + project.version = publishedVersion + project.pluginManager.apply(IncrementGuard::class.java) + val task = project.checkVersionTask() + task.repository = repoDir.asRepository() + + shouldNotThrowAny { task.checkVersion() } + } + } } +/** + * The version listed as published by the metadata written with [writeMetadata]. + */ +private const val publishedVersion = "2.0.0-SNAPSHOT.094" + /** * Creates a project with the `base` plugin (for the `check` task), the * `maven-publish` plugin (for [PublishToMavenLocal] tasks), and [IncrementGuard] @@ -215,6 +483,76 @@ private fun guardedProject(): Project { return project } +/** + * Creates a project with the given [name], which has the `maven-publish` plugin and + * [IncrementGuard] applied. + */ +private fun publishingProject(name: String = "guarded"): Project { + val project = ProjectBuilder.builder().withName(name).build() + project.pluginManager.apply("maven-publish") + project.pluginManager.apply(IncrementGuard::class.java) + return project +} + +/** + * Creates a Maven publication with the given [name] and coordinates in this project. + */ +private fun Project.publication( + name: String, + groupId: String, + artifactId: String +): MavenPublication = publications.create(name) { + this.groupId = groupId + this.artifactId = artifactId +} + +/** + * Obtains the [CheckVersionIncrement] task that [IncrementGuard] registered in this project. + * + * The task captures the project version when it is created, so the version must be + * set before this call. + */ +private fun Project.checkVersionTask(): CheckVersionIncrement = + tasks.named(IncrementGuard.taskName, CheckVersionIncrement::class.java).get() + +/** + * Writes `maven-metadata.xml` listing the given [versions] of the artifact at [path] + * into the [repository] subdirectory of this directory. + * + * The [repository] is either `snapshots` or `releases`, as in [asRepository]. + */ +internal fun File.writeMetadata(repository: String, path: String, vararg versions: String) { + val (groupPath, artifactId) = path.split('/').let { it.dropLast(1) to it.last() } + val versionElements = versions.joinToString(separator = "") { "$it" } + val file = resolve("$repository/$path/${MavenMetadata.FILE_NAME}") + file.parentFile.mkdirs() + file.writeText( + """ + + + ${groupPath.joinToString(separator = ".")} + $artifactId + + $versionElements + + + """.trimIndent() + ) +} + +/** + * Represents this directory as a Maven repository with separate destinations + * for snapshots and releases, stored in the subdirectories of the same names. + */ +private fun File.asRepository(): Repository { + val url = toURI().toString().removeSuffix("/") + return Repository( + name = "local", + releases = "$url/releases", + snapshots = "$url/snapshots", + ) +} + /** * Obtains the names of the tasks this task directly depends on. */ diff --git a/buildSrc/src/test/kotlin/io/spine/gradle/publish/MavenMetadataSpec.kt b/buildSrc/src/test/kotlin/io/spine/gradle/publish/MavenMetadataSpec.kt index 39f8a51..69f21fb 100644 --- a/buildSrc/src/test/kotlin/io/spine/gradle/publish/MavenMetadataSpec.kt +++ b/buildSrc/src/test/kotlin/io/spine/gradle/publish/MavenMetadataSpec.kt @@ -1,27 +1,15 @@ /* - * Copyright 2026, TeamDev. All rights reserved. + * Copyright 2026 CodeMatters, Lda. * - * 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 + * 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 * - * Redistribution and use in source and/or binary forms, with or without - * modification, must retain the above copyright notice and the following - * disclaimer. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 io.spine.gradle.publish diff --git a/buildSrc/src/test/kotlin/io/spine/gradle/publish/PublicationChecksumsIgTest.kt b/buildSrc/src/test/kotlin/io/spine/gradle/publish/PublicationChecksumsIgTest.kt new file mode 100644 index 0000000..b27f6b5 --- /dev/null +++ b/buildSrc/src/test/kotlin/io/spine/gradle/publish/PublicationChecksumsIgTest.kt @@ -0,0 +1,290 @@ +/* + * Copyright 2026 CodeMatters, Lda. + * + * 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 io.spine.gradle.publish + +import io.kotest.matchers.collections.shouldContain +import io.kotest.matchers.collections.shouldContainExactly +import io.kotest.matchers.shouldBe +import io.kotest.matchers.string.shouldContain +import io.kotest.matchers.string.shouldStartWith +import java.io.File +import java.security.MessageDigest +import org.gradle.testkit.runner.BuildResult +import org.gradle.testkit.runner.GradleRunner +import org.gradle.testkit.runner.TaskOutcome +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.DisplayName +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.io.TempDir + +/** + * Verifies the `publicationChecksums` task against a real multi-module build + * run via Gradle TestKit. + * + * The manifest this task writes is the sole input by which `actions/attest` + * decides what to attest: it takes both the digest and the name from the file + * and never reads the artifacts. A missing entry therefore narrows a signed + * claim without any symptom, and a name that is merely close enough describes + * something nobody publishes. Both are invisible to a unit test over the + * derivation alone, so the fixture publishes to a local repository and compares + * the manifest against the files that actually arrive there. + */ +@DisplayName("`publicationChecksums` task should") +internal class PublicationChecksumsIgTest { + + @TempDir + lateinit var projectDir: File + + @BeforeEach + fun setUpProject() { + file("settings.gradle.kts").writeText( + """ + rootProject.name = "checksums-sample" + include("api", "backend") + """.trimIndent() + ) + file("build.gradle.kts").writeText( + """ + buildscript { + dependencies { + classpath(files( + ${buildSrcClasspath()} + )) + } + } + + import io.spine.gradle.publish.spinePublishing + + allprojects { + group = "io.spine.sample" + version = "$version" + } + + subprojects { + apply(plugin = "java-library") + apply(plugin = "maven-publish") + + // `javadocJar` of `spinePublishing` is wired to Dokka, which + // this fixture does not apply: the manifest is what is under + // test, not the documentation toolchain. + tasks.register("dokkaGeneratePublicationJavadoc") + } + + spinePublishing { + modules = setOf("api", "backend") + destinations = emptySet() + } + + subprojects { + the().repositories { + maven { + name = "stage" + url = uri("${'$'}{rootDir}/staged") + } + } + } + """.trimIndent() + ) + sourceFile("api") + sourceFile("backend") + } + + @Test + fun `list every published artifact under its published name`() { + val result = runGradle(aggregator, "publishAllPublicationsToStageRepository") + + result.task(":$aggregator")?.outcome shouldBe TaskOutcome.SUCCESS + + // The standard publication of a module without Proto or a test JAR: the + // compilation output, the three documentation and source archives added + // by `artifacts(JarFlags)`, the SBOM added by `PublicationSbom`, and the + // two metadata files. Spelled out rather than only compared with the + // staged files, because two empty lists also "contain exactly" each + // other — this suite must not be able to pass by describing nothing. + val expected = listOf("api", "backend").flatMap { module -> + listOf( + "spine-$module-$version.jar", + "spine-$module-$version-sources.jar", + "spine-$module-$version-javadoc.jar", + "spine-$module-$version-html-docs.jar", + "spine-$module-$version.spdx.json", + "spine-$module-$version.pom", + "spine-$module-$version.module", + ) + }.sorted() + + val manifest = manifestEntries().map { it.name }.sorted() + manifest shouldContainExactly expected + manifest shouldContainExactly publishedFileNames() + } + + /** + * Each line of the manifest starts with a 64-character digest, so ordering + * the raw lines orders them by that digest — which is to say, arbitrarily. + * The per-project collectors sort by name, and a manifest that two runs of + * the same build can be compared line by line has to do the same. + */ + @Test + fun `order the manifest by subject name`() { + runGradle(aggregator) + + val names = manifestEntries().map { it.name } + names shouldBe names.sorted() + } + + @Test + fun `record the digest of each published file`() { + runGradle(aggregator, "publishAllPublicationsToStageRepository") + + manifestEntries().forEach { entry -> + val published = stagedFile(entry.name) + entry.digest shouldBe published.sha256() + } + } + + @Test + fun `apply the artifact prefix to the published names`() { + runGradle(aggregator) + + val names = manifestEntries().map { it.name } + names.forEach { it shouldStartWith "spine-" } + names shouldContain "spine-api-$version.jar" + names shouldContain "spine-api-$version.pom" + names shouldContain "spine-api-$version.module" + names shouldContain "spine-api-$version-sources.jar" + } + + /** + * Maven deploys a version ending in `-SNAPSHOT` under a timestamped name + * assigned at upload time, so the names derived from the publication belong + * to no uploaded file. Naming files that were never published is the one + * outcome worse than not attesting at all, so the build stops instead. + * + * The run below asks to publish, not merely to collect, because that is the + * order the distributed workflow uses. Rejecting the version only once the + * collector runs would let the upload happen first and leave behind the + * published-but-unattested artifacts the check exists to prevent — so the + * assertion is that nothing reached the repository at all. + */ + @Test + fun `refuse a Maven snapshot version before anything is published`() { + val script = file("build.gradle.kts") + script.writeText( + script.readText().replace("version = \"$version\"", "version = \"1.0.0-SNAPSHOT\"") + ) + + val result = GradleRunner.create() + .withProjectDir(projectDir) + .withArguments( + "publishAllPublicationsToStageRepository", aggregator, "--stacktrace" + ) + .buildAndFail() + + result.output shouldContain "1.0.0-SNAPSHOT" + file("staged").exists() shouldBe false + } + + /** + * The names of the files that the build actually publishes, excluding the + * digest sidecars and the repository-level metadata, which the repository + * generates rather than the build. + */ + private fun publishedFileNames(): List = + file("staged").walkTopDown() + .filter { it.isFile } + .map { it.name } + .filterNot { it.startsWith("maven-metadata") } + .filterNot { sidecars.any(it::endsWith) } + .toList() + .sorted() + + private fun stagedFile(name: String): File = + file("staged").walkTopDown().firstOrNull { it.isFile && it.name == name } + ?: error("No staged file named `$name`.") + + private fun manifestEntries(): List = + file("build/attestation/subject-checksums.txt") + .readLines() + .filter { it.isNotBlank() } + .map { line -> + val digest = line.substringBefore(' ') + ManifestEntry(digest, line.substringAfter(' ').trim()) + } + + private fun sourceFile(module: String) { + file("$module/src/main/java/sample/$module/Stub.java").apply { + parentFile.mkdirs() + writeText( + """ + package sample.$module; + public class Stub {} + """.trimIndent() + ) + } + } + + private fun runGradle(vararg args: String): BuildResult = + GradleRunner.create() + .withProjectDir(projectDir) + .withArguments(*args, "--stacktrace") + .build() + + private fun file(relativePath: String): File = projectDir.resolve(relativePath) + + /** + * Renders the classpath with the production classes of `buildSrc` as + * arguments of `files(...)`, for injection into the build script classpath + * of the generated build. + * + * The classpath comes from the `test` task in `buildSrc/build.gradle.kts`. + * + * The indentation below is matched to the `classpath(files(` call in the + * generated script, which `trimIndent()` would otherwise flatten. + */ + private fun buildSrcClasspath(): String { + val classpath = requireNotNull(System.getProperty("buildSrc.classpath")) { + "The `buildSrc.classpath` system property is not set." + + " It is supplied by the `test` task in `buildSrc/build.gradle.kts`." + } + return classpath.split(File.pathSeparator).joinToString(",\n") { + " \"${File(it).invariantSeparatorsPath}\"" + } + } + + private data class ManifestEntry(val digest: String, val name: String) + + private companion object { + + /** The task under test, named by the code that registers it. */ + val aggregator = PublicationChecksums.aggregatorTaskName + + const val version = "1.0.0" + + val sidecars = listOf(".md5", ".sha1", ".sha256", ".sha512") + } +} + +/** + * Returns the SHA-256 digest of this file as a lowercase hexadecimal string. + * + * Deliberately a second implementation rather than the one the production code + * uses: the assertion compares a digest this test computed with a digest that + * code produced, and sharing the function would make it compare a value with + * itself. Test files are small, so this one reads the whole file. + */ +private fun File.sha256(): String { + val digest = MessageDigest.getInstance("SHA-256").digest(readBytes()) + return digest.joinToString("") { "%02x".format(it) } +} diff --git a/buildSrc/src/test/kotlin/io/spine/gradle/publish/PublicationChecksumsReconfigurationIgTest.kt b/buildSrc/src/test/kotlin/io/spine/gradle/publish/PublicationChecksumsReconfigurationIgTest.kt new file mode 100644 index 0000000..09756ea --- /dev/null +++ b/buildSrc/src/test/kotlin/io/spine/gradle/publish/PublicationChecksumsReconfigurationIgTest.kt @@ -0,0 +1,215 @@ +/* + * Copyright 2026 CodeMatters, Lda. + * + * 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 io.spine.gradle.publish + +import io.kotest.matchers.shouldBe +import java.io.File +import org.gradle.testkit.runner.GradleRunner +import org.gradle.testkit.runner.TaskOutcome +import org.junit.jupiter.api.DisplayName +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.io.TempDir + +/** + * Verifies the checksum tasks against builds that configure `spinePublishing` + * more than once. + * + * Repeated configuration is supported rather than exotic — the extension is + * reused across calls, and a module with a custom publication opens it on its + * own while still appearing in the root extension's `modulesWithCustomPublishing`. + * Each call runs `configured()` again, so the tasks are registered against a + * project that may already have them, with a set of published projects that may + * have grown. Neither failure shows up in a build that configures the extension + * once, which is every other fixture here. + */ +@DisplayName("`publicationChecksums` task should, on repeated configuration,") +internal class PublicationChecksumsReconfigurationIgTest { + + @TempDir + lateinit var projectDir: File + + /** + * Like `uber-jar-module.gradle.kts`, the module leaves `destinations` unset + * and inherits them from the root extension. + */ + @Test + fun `tolerate the extension configured in both the root and the module`() { + file("settings.gradle.kts").writeText( + """ + rootProject.name = "custom-sample" + include("uber") + """.trimIndent() + ) + file("build.gradle.kts").writeText( + """ + buildscript { + dependencies { + classpath(files( + ${buildSrcClasspath()} + )) + } + } + + import io.spine.gradle.publish.spinePublishing + + allprojects { + group = "io.spine.sample" + version = "1.0.0" + } + + subprojects { + apply(plugin = "java-library") + apply(plugin = "maven-publish") + tasks.register("dokkaGeneratePublicationJavadoc") + } + + spinePublishing { + modulesWithCustomPublishing = setOf("uber") + destinations = emptySet() + } + """.trimIndent() + ) + file("uber/build.gradle.kts").apply { + parentFile.mkdirs() + writeText( + """ + import io.spine.gradle.publish.spinePublishing + + spinePublishing { + customPublishing = true + } + """.trimIndent() + ) + } + file("uber/src/main/java/sample/Stub.java").apply { + parentFile.mkdirs() + writeText( + """ + package sample; + public class Stub {} + """.trimIndent() + ) + } + + val result = GradleRunner.create() + .withProjectDir(projectDir) + .withArguments("publicationChecksums", "--stacktrace") + .build() + + result.task(":publicationChecksums")?.outcome shouldBe TaskOutcome.SUCCESS + } + + /** + * A second call registers a collector for the module it adds, while the + * aggregator is already there. Unless the aggregator reads the projects it + * merges through something that outlives one call, that module is collected + * and then left out of the manifest — the silent narrowing this whole + * arrangement exists to prevent. + */ + @Test + fun `merge the modules added by a later call`() { + file("settings.gradle.kts").writeText( + """ + rootProject.name = "regrown-sample" + include("first", "second") + """.trimIndent() + ) + file("build.gradle.kts").writeText( + """ + buildscript { + dependencies { + classpath(files( + ${buildSrcClasspath()} + )) + } + } + + import io.spine.gradle.publish.spinePublishing + + allprojects { + group = "io.spine.sample" + version = "1.0.0" + } + + subprojects { + apply(plugin = "java-library") + apply(plugin = "maven-publish") + tasks.register("dokkaGeneratePublicationJavadoc") + } + + spinePublishing { + modules = setOf("first") + destinations = emptySet() + } + + spinePublishing { + modules = setOf("first", "second") + destinations = emptySet() + } + """.trimIndent() + ) + sourceFile("first") + sourceFile("second") + + runGradle(PublicationChecksums.aggregatorTaskName) + + val names = manifestNames() + names.any { it.startsWith("spine-first-") } shouldBe true + names.any { it.startsWith("spine-second-") } shouldBe true + } + + private fun manifestNames(): List = + file("build/attestation/subject-checksums.txt") + .readLines() + .filter { it.isNotBlank() } + .map { it.substringAfter(" ").trim() } + + private fun sourceFile(module: String) { + file("$module/src/main/java/sample/$module/Stub.java").apply { + parentFile.mkdirs() + writeText( + """ + package sample.$module; + public class Stub {} + """.trimIndent() + ) + } + } + + private fun runGradle(vararg args: String) = + GradleRunner.create() + .withProjectDir(projectDir) + .withArguments(*args, "--stacktrace") + .build() + + private fun file(relativePath: String): File = projectDir.resolve(relativePath) + + /** + * Renders the classpath with the production classes of `buildSrc` as + * arguments of `files(...)`, for injection into the build script classpath + * of the generated build. + * + * The classpath comes from the `test` task in `buildSrc/build.gradle.kts`. + */ + private fun buildSrcClasspath(): String { + val classpath = requireNotNull(System.getProperty("buildSrc.classpath")) { + "The `buildSrc.classpath` system property is not set." + + " It is supplied by the `test` task in `buildSrc/build.gradle.kts`." + } + return classpath.split(File.pathSeparator).joinToString(",\n") { + " \"${File(it).invariantSeparatorsPath}\"" + } + } +} diff --git a/buildSrc/src/test/kotlin/io/spine/gradle/publish/PublicationSbomIgTest.kt b/buildSrc/src/test/kotlin/io/spine/gradle/publish/PublicationSbomIgTest.kt new file mode 100644 index 0000000..d64306e --- /dev/null +++ b/buildSrc/src/test/kotlin/io/spine/gradle/publish/PublicationSbomIgTest.kt @@ -0,0 +1,1183 @@ +/* + * Copyright 2026 CodeMatters, Lda. + * + * 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 io.spine.gradle.publish + +import com.fasterxml.jackson.databind.JsonNode +import com.fasterxml.jackson.databind.ObjectMapper +import io.kotest.inspectors.forAll +import io.kotest.matchers.collections.shouldBeEmpty +import io.kotest.matchers.collections.shouldContain +import io.kotest.matchers.collections.shouldContainAll +import io.kotest.matchers.collections.shouldContainExactly +import io.kotest.matchers.collections.shouldContainExactlyInAnyOrder +import io.kotest.matchers.collections.shouldNotBeEmpty +import io.kotest.matchers.collections.shouldNotContain +import io.kotest.matchers.collections.shouldNotContainAnyOf +import io.kotest.matchers.file.shouldExist +import io.kotest.matchers.file.shouldNotExist +import io.kotest.matchers.nulls.shouldBeNull +import io.kotest.matchers.nulls.shouldNotBeNull +import io.kotest.matchers.shouldBe +import io.kotest.matchers.string.shouldNotContain +import java.io.File +import java.util.jar.JarOutputStream +import java.util.jar.Manifest +import javax.xml.parsers.DocumentBuilderFactory +import org.gradle.testkit.runner.BuildResult +import org.gradle.testkit.runner.GradleRunner +import org.junit.jupiter.api.BeforeAll +import org.junit.jupiter.api.DisplayName +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.TestInstance +import org.junit.jupiter.api.io.TempDir +import org.w3c.dom.Document +import org.w3c.dom.Element + +/** + * Verifies the SBOMs [PublicationSbom] adds to the publications of a real + * multi-module build, run via Gradle TestKit. + * + * The fixture is built once for the whole class, because a build applying + * Kotlin Multiplatform takes long to configure, and each case only inspects + * what that build left behind. It runs `--offline`, resolving from a local + * `file:` repository only — which also exercises the workaround for a plugin + * bug that fails the SBOM task for such repositories. + * + * The fixture has: + * - `api` and `impl` — standard JVM modules, `impl` depending on `api` and + * `bundled`, on `com.example:lib` at runtime, and on two libraries it only + * compiles or tests with; + * - `bundled` — a JVM module left unpublished, like one bundled into the + * artifact of another module, such as a fat JAR; + * - `plugin` — a Gradle plugin, whose marker publication must stay without + * an SBOM; + * - `kmp` — a Kotlin Multiplatform module with a JVM target named `desktop`, not + * after its platform, and an umbrella publication that must stay without an + * SBOM. It has no sources, so it builds + * without the Kotlin compiler, which an offline build cannot fetch. As + * modules of the `logging` repository do, it is listed with custom publishing + * by the root project and also opens `spinePublishing` itself, so its SBOM is + * registered twice; + * - `twin` — a JVM module with custom publishing, whose two publications + * publish different artifacts, so each needs an SBOM naming its own, and + * whose third publication is removed once the module is evaluated; + * - `consumer` — a JVM module depending on `kmp`, whose SBOM must name the + * artifact of the JVM target of `kmp`; + * - `thin` — a JVM module publishing a thin JAR with a hand-written POM, as + * a Gradle plugin shipping its code apart from its dependencies does. The POM + * declares `fat` and `com.example:lib`, not the rest of the runtime classpath, + * and the JAR packs `bundled`; + * - `fat` — a JVM module publishing a fat JAR with a hand-written POM. Shadow + * bundles `bundled` and `com.example:inner`, but neither `com.example:outer`, + * which the POM declares without `inner`, nor `com.example:annotations`, which + * the artifact leaves for its consumers to add. The JAR keeps the `all` + * classifier Shadow gives it, so the publication has no main artifact; + * - `uber` — a JVM module publishing a fat JAR of its whole runtime classpath + * as its main artifact, with an empty POM, as `uber-jar-module` does; + * - `archive` — a JVM module publishing a ZIP archive rather than a JAR, as + * a Kotlin/Native target publishes a klib; + * - `osgi` — a JVM module publishing its JAR as an OSGi bundle, whose build sets + * the `bundle` packaging of the POM. + */ +@DisplayName("`PublicationSbom` should") +@TestInstance(TestInstance.Lifecycle.PER_CLASS) +internal class PublicationSbomIgTest { + + private lateinit var projectDir: File + + private lateinit var result: BuildResult + + /** + * Builds the fixture in a directory that JUnit keeps for all cases of the class. + */ + @BeforeAll + fun buildFixture(@TempDir dir: File) { + projectDir = dir + writeRepository() + writeBuild() + result = GradleRunner.create() + .withProjectDir(projectDir) + .withArguments( + ":api:$publishTask", + ":impl:$publishTask", + ":plugin:$publishTask", + ":impl:${PublicationChecksums.collectorTaskName}", + ":kmp:${PublicationSbom.taskNameFor("desktop")}", + ":kmp:${pomTaskOf("desktop")}", + ":twin:${PublicationSbom.taskName}", + ":consumer:${PublicationSbom.taskName}", + ":thin:${PublicationSbom.taskName}", + ":thin:${pomTaskOf(pluginJar)}", + ":fat:${PublicationSbom.taskName}", + ":fat:${pomTaskOf(fatJar)}", + ":uber:${PublicationSbom.taskName}", + ":uber:${pomTaskOf(fatJar)}", + ":archive:${pomTaskOf(archive)}", + ":osgi:${pomTaskOf(osgiBundle)}", + "--offline", + "--stacktrace", + ) + .build() + } + + @Test + fun `publish the SBOM of a module next to its artifacts`() { + val files = stagedFiles("io/spine/test/spine-impl/$moduleVersion") + + files shouldContainAll listOf( + "spine-impl-$moduleVersion.jar", + "spine-impl-$moduleVersion.spdx.json" + ) + implSbom()["spdxVersion"].asText() shouldBe "SPDX-2.3" + } + + @Test + fun `list the SBOM among the subjects of the attestation`() { + val manifest = file("impl/build/attestation/checksums.txt").readLines() + + manifest.map { it.substringAfter(" ") } shouldContain + "spine-impl-$moduleVersion.spdx.json" + } + + /** + * The SBOM is published without a classifier, as the artifact itself is, and Gradle + * derives the packaging of a POM from such artifacts. A POM leaves out the packaging + * of a JAR, which is the default. + */ + @Test + fun `keep the packaging of a JAR published with an SBOM`() { + val jarPublications = listOf( + "impl" to "mavenJava", + "plugin" to "pluginMaven", + "kmp" to "desktop", + "thin" to pluginJar, + "uber" to fatJar, + ) + + jarPublications.forAll { (module, publication) -> + packagingOf(module, publication).shouldBeNull() + } + } + + /** + * Shadow classifies the fat JAR of `fat` as `all`, so the publication has no main + * artifact, and its POM declares the `pom` packaging. The SBOM, having no classifier, + * would otherwise become the main artifact, and `spdx.json` the packaging. + */ + @Test + fun `keep the packaging of a publication without a main artifact`() { + packagingOf("fat", fatJar) shouldBe "pom" + } + + /** + * The packaging is the extension of the main artifact, rather than always `jar`. + */ + @Test + fun `keep the packaging of an artifact other than a JAR published with an SBOM`() { + packagingOf("archive", archive) shouldBe "zip" + } + + /** + * The build of `osgi` sets the `bundle` packaging, as the POM of an OSGi bundle declares + * for its JAR. The packaging the build sets is kept, rather than calculated anew from + * the artifacts, which would give `jar`. + */ + @Test + fun `keep the packaging a build sets explicitly`() { + packagingOf("osgi", osgiBundle) shouldBe "bundle" + } + + @Test + fun `describe runtime dependencies only`() { + val names = implSbom().packageNames() + + names shouldContain "com.example:lib" + names shouldNotContain "com.example:testlib" + names shouldNotContain "com.example:annotations" + } + + /** + * The POM of `lib` declares no license and inherits one from its parent, + * and both POMs configure the same plugins. The SPDX plugin, running on the + * classpath of `buildSrc`, builds effective POMs that merge the configuration + * of those plugins — on a classpath that also carries the XML libraries of the + * Shadow plugin. Finding the license proves that the merge works there. + */ + @Test + fun `take the license of a dependency from its parent POM`() { + val lib = implSbom().packageNamed("com.example:lib") + + lib[SpdxField.licenseDeclared].asText() shouldBe "MIT" + } + + @Test + fun `leave the download location of a dependency from a local repository unasserted`() { + val lib = implSbom().packageNamed("com.example:lib") + + lib["downloadLocation"].asText() shouldBe "NOASSERTION" + lib.purl() shouldBe "pkg:maven/com.example/lib@1.0" + } + + @Test + fun `name the module and its siblings by their published coordinates`() { + val sbom = implSbom() + + sbom[SpdxField.name].asText() shouldBe "spine-impl" + sbom[SpdxField.documentNamespace].asText() shouldBe + "https://spine.io/spdxdocs/io.spine.test/spine-impl/$moduleVersion" + sbom.packageNames() shouldNotContainAnyOf listOf("impl", "api") + listOf("spine-impl", "spine-api").forEach { artifactId -> + val module = sbom.packageNamed("io.spine.test:$artifactId") + module.purl() shouldBe "pkg:maven/io.spine.test/$artifactId@$moduleVersion" + module[SpdxField.licenseDeclared].asText() shouldBe "Apache-2.0" + } + } + + /** + * An unpublished module has no coordinates to be named after, so it keeps the + * name the plugin gives it. It is still code of this build, under its license. + */ + @Test + fun `describe an unpublished sibling by its project and the license of the build`() { + val bundled = implSbom().packageNamed("bundled") + + bundled[SpdxField.versionInfo].asText() shouldBe moduleVersion + bundled[SpdxField.licenseDeclared].asText() shouldBe "Apache-2.0" + bundled.purl().shouldBeNull() + result.output shouldNotContain "`:bundled`" + } + + @Test + fun `attach an SBOM to every publication but plugin markers and the KMP umbrella`() { + val reported = result.output.lines() + .filter { it.startsWith(reportPrefix) } + .map { it.removePrefix(reportPrefix) } + + reported shouldContainAll listOf( + ":api mavenJava 1", + ":impl mavenJava 1", + ":consumer mavenJava 1", + ":plugin pluginMaven 1", + ":plugin samplePluginMarkerMaven 0", + ":kmp desktop 1", + ":kmp kotlinMultiplatform 0", + ":twin main 1", + ":twin extra 1", + ":thin pluginJar 1", + ":fat fatJar 1", + ":uber fatJar 1", + ":archive archive 1", + ":osgi osgiBundle 1", + ) + } + + /** + * `spinePublishing` prefixes the artifact ID of each publication, as it does that + * of the project. Neither artifact is named as the project, which an SBOM falls + * back to when it cannot find its publication. + */ + @Test + fun `name the SBOM of each publication after the artifact it is published with`() { + val artifacts = mapOf("main" to "spine-twin-main", "extra" to "spine-twin-extra") + artifacts.forEach { (publication, artifactId) -> + val sbom = file("twin/build/sbom/$publication.spdx.json").readJson() + + sbom[SpdxField.name].asText() shouldBe artifactId + sbom.packageNamed("io.spine.test:$artifactId").purl() shouldBe + "pkg:maven/io.spine.test/$artifactId@$moduleVersion" + } + } + + @Test + fun `write no SBOM for a publication the build removes`() { + file("twin/build/sbom/dropped.spdx.json").shouldNotExist() + } + + @Test + fun `describe the runtime of a KMP target`() { + val sbom = file("kmp/build/sbom/desktop.spdx.json").readJson() + + sbom[SpdxField.name].asText() shouldBe "spine-kmp-desktop" + sbom.packageNames() shouldContainAll listOf("com.example:lib", "io.spine.test:spine-api") + } + + /** + * Gradle resolves `consumer`'s dependency on `kmp` to the artifact of the JVM target + * of `kmp` by its platform — the target is named `desktop`. + */ + @Test + fun `name a multiplatform sibling after its artifact for the same platform`() { + val sbom = file("consumer/build/sbom/mavenJava.spdx.json").readJson() + + sbom.packageNamed("io.spine.test:spine-kmp-desktop").purl() shouldBe + "pkg:maven/io.spine.test/spine-kmp-desktop@$moduleVersion" + } + + @Test + fun `describe as dependencies of an artifact what its hand-written POM declares`() { + listOf("thin" to pluginJar, "fat" to fatJar).forEach { (module, publication) -> + val sbom = sbomOf(module, publication) + + sbom.relatedToArtifact(DEPENDS_ON) shouldContainAll + pomDependenciesOf(module, publication) + } + } + + @Test + fun `leave out the runtime classpath that a hand-written POM does not declare`() { + val sbom = sbomOf("thin", pluginJar) + + sbom.relatedToArtifact(DEPENDS_ON) shouldContainExactlyInAnyOrder + listOf("io.spine.test:spine-fat", "com.example:lib") + sbom.packageNames() shouldNotContain "com.example:testlib" + } + + /** + * `fat` is published as a fat JAR, so its SBOM describes what the JAR bundles. + * The artifact depending on it gets that content from the JAR, and not as + * dependencies of its own. + */ + @Test + fun `describe a sibling an artifact depends on by the artifact of the sibling alone`() { + val sbom = sbomOf("thin", pluginJar) + val fat = sbom.packageNamed("io.spine.test:spine-fat") + + fat.purl() shouldBe "pkg:maven/io.spine.test/spine-fat@$moduleVersion" + sbom.relatedTo(fat, DEPENDS_ON).shouldBeEmpty() + sbom.packageNames() shouldNotContain "com.example:inner" + } + + @Test + fun `describe the modules packed into a JAR as its content`() { + sbomOf("thin", pluginJar).relatedToArtifact(CONTAINS) shouldContainExactly + listOf("bundled") + } + + @Test + fun `describe what a fat JAR bundles as its content`() { + val sbom = sbomOf("fat", fatJar) + + sbom.relatedToArtifact(CONTAINS) shouldContainExactlyInAnyOrder + listOf("bundled", "com.example:inner") + sbom.relatedToArtifact(DEPENDS_ON) shouldContainExactly listOf("com.example:outer") + } + + @Test + fun `leave out what a fat JAR neither bundles nor declares`() { + sbomOf("fat", fatJar).packageNames() shouldNotContain "com.example:annotations" + } + + /** + * The runtime classpath of `fat` resolves `inner` as a dependency of `outer`, + * which the POM declares without it. + */ + @Test + fun `not describe what a fat JAR bundles as a dependency of what it declares`() { + sbomOf("fat", fatJar).dependencyTargets() shouldNotContain "com.example:inner" + } + + @Test + fun `describe a fat JAR with an empty POM by its content alone`() { + val sbom = sbomOf("uber", fatJar) + + sbom.relatedToArtifact(CONTAINS) shouldContainExactlyInAnyOrder + listOf("bundled", "com.example:testlib") + sbom.relatedToArtifact(DEPENDS_ON).shouldBeEmpty() + } + + /** + * `uber` bundles its runtime classpath, which the SPDX Gradle Plugin describes for + * the module anyway, so the SBOM of its fat JAR needs no document of its own. + */ + @Test + fun `describe a fat JAR of the runtime classpath from the document of the module`() { + file("uber/build/spdx/publication.spdx.json").shouldExist() + file("uber/build/spdx/${fatJar}Publication.spdx.json").shouldNotExist() + } + + @Test + fun `keep the SBOM of a publication made from a software component as it is`() { + val sbom = implSbom() + + sbom.relatedToArtifact(DEPENDS_ON) shouldContainExactlyInAnyOrder + listOf("io.spine.test:spine-api", "bundled", "com.example:lib") + sbom.relatedToArtifact(CONTAINS).shouldBeEmpty() + file("impl/build/spdx/publication.spdx.json").shouldExist() + } + + @Test + fun `write SBOMs whose relationships and licenses are complete`() { + listOf( + implSbom(), + sbomOf("thin", pluginJar), + sbomOf("fat", fatJar), + sbomOf("uber", fatJar), + ).forEach { it.shouldBeComplete() } + } + + private fun sbomOf(module: String, publication: String): JsonNode = + file("$module/build/sbom/$publication.spdx.json").readJson() + + /** + * Returns the dependencies the POM of the given [publication] declares, + * as `group:artifactId`. + */ + private fun pomDependenciesOf(module: String, publication: String): List { + val dependencies = pomOf(module, publication).getElementsByTagName("dependency") + return (0 until dependencies.length) + .map { dependencies.item(it) as Element } + .map { "${it.childText("groupId")}:${it.childText("artifactId")}" } + .shouldNotBeEmpty() + } + + /** + * Returns the packaging the POM of the given [publication] declares, or `null` if + * it declares none, which means `jar`. + */ + private fun packagingOf(module: String, publication: String): String? = + pomOf(module, publication).getElementsByTagName("packaging").item(0)?.textContent + + private fun pomOf(module: String, publication: String): Document { + val pom = file("$module/build/publications/$publication/pom-default.xml") + return DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(pom) + } + + private fun implSbom(): JsonNode { + val directory = "staged/io/spine/test/spine-impl/$moduleVersion" + return file("$directory/spine-impl-$moduleVersion.spdx.json").readJson() + } + + private fun stagedFiles(directory: String): List = + file("staged/$directory").listFiles()?.map { it.name }.orEmpty() + + /** + * Writes a Maven repository with the external dependencies of the fixture. + * + * `lib` takes its license from its parent POM, so that an SBOM naming it + * shows that the POM was built with its parent resolved. Both POMs configure + * the same plugins, as real POMs do, so building the effective one merges + * plugin configuration — once through the plugin management of the parent, + * and once through inheritance. + * + * `outer` depends on `inner`, so that an artifact can bundle a library it + * resolves as a dependency of another one. + */ + private fun writeRepository() { + pom( + groupId = "com.example", + artifactId = "parent", + version = "1.0", + body = listOf(parentHead, parentBuild).joinToString("\n") + ) + library(artifactId = "lib", body = listOf(libParent, libBuild).joinToString("\n")) + library(artifactId = "testlib") + library(artifactId = "annotations") + library(artifactId = "inner") + library(artifactId = "outer", body = outerDependencies) + } + + private fun library(artifactId: String, body: String = "") { + pom(groupId = "com.example", artifactId = artifactId, version = "1.0", body = body) + val jar = file("repository/com/example/$artifactId/1.0/$artifactId-1.0.jar") + JarOutputStream(jar.outputStream(), Manifest()).use { } + } + + private fun pom(groupId: String, artifactId: String, version: String, body: String) { + val path = "repository/${groupId.replace('.', '/')}/$artifactId/$version" + val lines = listOf( + """""", + """""", + " 4.0.0", + " $groupId", + " $artifactId", + " $version", + ) + body.lines().filter { it.isNotBlank() }.map { " $it" } + "" + write("$path/$artifactId-$version.pom", lines.joinToString("\n", postfix = "\n")) + } + + private fun writeBuild() { + write( + "settings.gradle.kts", + """ + rootProject.name = "sbom-sample" + include( + "api", "impl", "bundled", "plugin", "kmp", "twin", "consumer", + "thin", "fat", "uber", "archive", "osgi", + ) + """.trimIndent() + ) + // The standard library would be resolved from Maven Central otherwise, + // which an offline build cannot reach. + write("gradle.properties", "kotlin.stdlib.default.dependency=false\n") + write( + "build.gradle.kts", + """ + buildscript { + dependencies { + classpath(files( + ${buildSrcClasspath()} + )) + } + } + + import io.spine.gradle.publish.spinePublishing + + allprojects { + group = "io.spine.test" + version = "$moduleVersion" + repositories { + maven { url = uri("${'$'}{rootDir}/repository") } + } + } + + subprojects { + apply(plugin = "maven-publish") + + // `javadocJar` of `spinePublishing` is wired to Dokka, which + // this fixture does not apply. + tasks.register("dokkaGeneratePublicationJavadoc") + } + + spinePublishing { + modules = setOf("api", "impl", "consumer") + modulesWithCustomPublishing = setOf( + "plugin", "kmp", "twin", "thin", "fat", "uber", "archive", "osgi", + ) + destinations = emptySet() + } + + subprojects { + the().repositories { + maven { + name = "stage" + url = uri("${'$'}{rootDir}/staged") + } + } + } + + // The SBOMs are added once all projects are evaluated, so report afterwards. + gradle.taskGraph.whenReady { + subprojects { + the().publications + .withType() + .forEach { publication -> + val sboms = publication.artifacts.count { it.extension == "spdx.json" } + println("$reportPrefix${'$'}path ${'$'}{publication.name} ${'$'}sboms") + } + } + } + """.trimIndent() + ) + write("api/build.gradle.kts", "plugins { `java-library` }\n") + javaSource(module = "api", packageName = "sample.api", declaration = "class Api {}") + write( + "impl/build.gradle.kts", + """ + plugins { `java-library` } + + dependencies { + implementation(project(":api")) + implementation(project(":bundled")) + implementation("com.example:lib:1.0") + compileOnly("com.example:annotations:1.0") + testImplementation("com.example:testlib:1.0") + } + """.trimIndent() + ) + javaSource(module = "impl", packageName = "sample.impl", declaration = "class Impl {}") + write("bundled/build.gradle.kts", "plugins { `java-library` }\n") + javaSource( + module = "bundled", + packageName = "sample.bundled", + declaration = "class Bundled {}" + ) + write( + "plugin/build.gradle.kts", + """ + plugins { `java-gradle-plugin` } + + gradlePlugin { + plugins { + create("sample") { + id = "io.spine.test.sample" + implementationClass = "sample.plugin.SamplePlugin" + } + } + } + """.trimIndent() + ) + javaSource( + module = "plugin", + packageName = "sample.plugin", + declaration = """ + public class SamplePlugin implements org.gradle.api.Plugin { + @Override public void apply(org.gradle.api.Project project) {} + } + """.trimIndent() + ) + write( + "kmp/build.gradle.kts", + """ + import io.spine.gradle.publish.spinePublishing + + plugins { kotlin("multiplatform") } + + kotlin { + jvm("desktop") + sourceSets.getByName("desktopMain").dependencies { + implementation(project(":api")) + implementation("com.example:lib:1.0") + } + } + + spinePublishing { + customPublishing = true + destinations = emptySet() + } + """.trimIndent() + ) + write( + "twin/build.gradle.kts", + """ + plugins { + `java-library` + `maven-publish` + } + + publishing { + publications { + create("main") { + from(components["java"]) + artifactId = "twin-main" + } + create("extra") { + from(components["java"]) + artifactId = "twin-extra" + } + create("dropped") { + from(components["java"]) + artifactId = "twin-dropped" + } + } + } + + // As builds do with the `pluginMaven` publication `java-gradle-plugin` adds. + afterEvaluate { + publishing.publications.removeIf { it.name == "dropped" } + } + """.trimIndent() + ) + write( + "consumer/build.gradle.kts", + """ + plugins { `java-library` } + + dependencies { + implementation(project(":kmp")) + } + """.trimIndent() + ) + writeThinJarModule() + writeFatJarModule() + writeUberJarModule() + writeArchiveModule() + writeOsgiModule() + } + + /** + * Writes the `thin` module, whose JAR packs the classes of `bundled`, and whose + * hand-written POM declares what the `pomDependencies` configuration holds. + */ + private fun writeThinJarModule() { + val body = """ + dependencies { + implementation(project(":bundled")) + implementation("com.example:testlib:1.0") + pomDependencies(project(":fat")) { isTransitive = false } + pomDependencies("com.example:lib:1.0") + packed(project(":bundled")) + } + + tasks.jar { + from(packed.elements.map { jars -> jars.map { zipTree(it) } }) { + exclude("META-INF/MANIFEST.MF") + } + } + + publishing { + publications { + create("$pluginJar") { + artifact(tasks.jar) + declareInPom( + listOf("io.spine.test:spine-fat:$moduleVersion", "com.example:lib:1.0") + ) + sbom { + dependencies(pomDependencies) + bundled(packed) + } + } + } + } + """.trimIndent() + writeScript( + "thin", + "$sbomImport\n\nplugins { `java-library` }", + pomConfiguration, + resolvableConfiguration("packed", transitive = false), + pomDeclaration, + body + ) + } + + /** + * Writes the `fat` module, whose fat JAR bundles its runtime classpath but for + * what its Shadow filter excludes, and whose hand-written POM declares what + * the `pomDependencies` configuration holds. + */ + private fun writeFatJarModule() { + val body = """ + dependencies { + implementation(project(":bundled")) + implementation("com.example:outer:1.0") + implementation("com.example:annotations:1.0") + pomDependencies("com.example:outer:1.0") { + exclude(group = "com.example", module = "inner") + } + } + + tasks.shadowJar { + dependencies { + exclude(dependency("com.example:outer")) + exclude(dependency("com.example:annotations")) + } + } + + publishing { + publications { + create("$fatJar") { + artifact(tasks.shadowJar) + declareInPom( + listOf("com.example:outer:1.0"), + exclusions = mapOf("com.example:outer" to "com.example:inner") + ) + sbom { + dependencies(pomDependencies) + bundled(tasks.shadowJar) + } + } + } + } + """.trimIndent() + writeScript("fat", shadowModuleHead, pomConfiguration, pomDeclaration, body) + } + + /** + * Writes the `uber` module, whose fat JAR bundles its whole runtime classpath, + * and whose POM declares no dependencies. + * + * As in `uber-jar-module`, the fat JAR has no classifier, taking the name of the JAR + * of the module, whose task is disabled. So the fat JAR is the main artifact. + */ + private fun writeUberJarModule() { + val body = """ + dependencies { + implementation(project(":bundled")) + implementation("com.example:testlib:1.0") + } + + tasks.jar { + enabled = false + } + + tasks.shadowJar { + archiveClassifier.set("") + } + + publishing { + publications { + create("$fatJar") { + artifact(tasks.shadowJar) + sbom { bundled(tasks.shadowJar) } + } + } + } + """.trimIndent() + writeScript("uber", shadowModuleHead, body) + } + + /** + * Writes the `archive` module, which publishes a ZIP archive rather than a JAR. + */ + private fun writeArchiveModule() { + val body = """ + val zip = tasks.register("zip") { + from("build.gradle.kts") + } + + publishing { + publications { + create("$archive") { + artifact(zip) + } + } + } + """.trimIndent() + writeScript("archive", "plugins { `java-library` }", body) + } + + /** + * Writes the `osgi` module, which publishes its JAR as an OSGi bundle, setting + * the `bundle` packaging of the POM. + */ + private fun writeOsgiModule() { + val body = """ + publishing { + publications { + create("$osgiBundle") { + artifact(tasks.jar) + pom.packaging = "bundle" + } + } + } + """.trimIndent() + writeScript("osgi", "plugins { `java-library` }", body) + } + + /** + * Writes the build script of the given [module], made of the given [parts]. + */ + private fun writeScript(module: String, vararg parts: String) { + write("$module/build.gradle.kts", parts.joinToString("\n\n")) + } + + private fun javaSource(module: String, packageName: String, declaration: String) { + val className = declaration.substringAfter("class ").substringBefore(' ') + val path = "$module/src/main/java/${packageName.replace('.', '/')}/$className.java" + write(path, "package $packageName;\n\n$declaration\n") + } + + private fun file(relativePath: String): File = projectDir.resolve(relativePath) + + private fun write(relativePath: String, text: String) { + file(relativePath).apply { + parentFile.mkdirs() + writeText(text) + } + } + + /** + * Renders the classpath with the production classes of `buildSrc` as + * arguments of `files(...)`, for injection into the build script classpath + * of the generated build. + * + * The classpath comes from the `test` task in `buildSrc/build.gradle.kts`. + * + * Each entry after the first starts a line of the generated script, so each + * is prefixed with the indentation of the template it is inserted into, which + * `trimIndent()` then removes along with the rest. + */ + private fun buildSrcClasspath(): String { + val classpath = requireNotNull(System.getProperty("buildSrc.classpath")) { + "The `buildSrc.classpath` system property is not set." + + " It is supplied by the `test` task in `buildSrc/build.gradle.kts`." + } + return classpath.split(File.pathSeparator).joinToString(",\n") { + " \"${File(it).invariantSeparatorsPath}\"" + } + } + + private companion object { + + /** The version of the modules of the fixture. */ + const val moduleVersion = "1.0.0" + + const val publishTask = "publishAllPublicationsToStageRepository" + + /** Marks the lines in which the fixture reports the SBOMs of each publication. */ + const val reportPrefix = "SBOM-REPORT " + + /** The publication of a thin JAR with a hand-written POM. */ + const val pluginJar = "pluginJar" + + /** The publication of a fat JAR. */ + const val fatJar = "fatJar" + + /** The publication of a ZIP archive. */ + const val archive = "archive" + + /** The publication of a JAR as an OSGi bundle. */ + const val osgiBundle = "osgiBundle" + + /** Returns the name of the task writing the POM of the given [publication]. */ + fun pomTaskOf(publication: String): String = + "generatePomFileFor${publication.replaceFirstChar { it.uppercase() }}Publication" + + /** The dependency of `outer` on `inner`. */ + val outerDependencies = """ + + + com.example + inner + 1.0 + + + """.trimIndent() + + /** Imports the function describing the SBOM of a publication. */ + const val sbomImport = "import io.spine.gradle.publish.sbom" + + /** The start of the build script of a module publishing a fat JAR. */ + val shadowModuleHead = """ + $sbomImport + + plugins { + `java-library` + id("com.gradleup.shadow") + } + """.trimIndent() + + /** + * Declares the `pomDependencies` configuration in a build script, holding what + * the POM of a publication declares. + */ + val pomConfiguration = resolvableConfiguration("pomDependencies") + + /** + * Declares `declareInPom` in a build script: the function writing dependencies + * into the POM of a publication by hand. + */ + val pomDeclaration = """ + /** + * Declares the given [dependencies] in the POM of this publication, each as + * `group:artifactId:version`, in the `runtime` scope. A dependency whose + * `group:artifactId` is a key of [exclusions] excludes the module it maps to. + */ + fun MavenPublication.declareInPom( + dependencies: List, + exclusions: Map = emptyMap() + ) { + fun groovy.util.Node.identify(module: String) { + val (group, name) = module.split(':') + appendNode("groupId", group) + appendNode("artifactId", name) + } + pom.withXml { + val declared = asNode().appendNode("dependencies") + dependencies.forEach { coordinates -> + val module = coordinates.substringBeforeLast(':') + declared.appendNode("dependency").apply { + identify(module) + appendNode("version", coordinates.substringAfterLast(':')) + appendNode("scope", "runtime") + exclusions[module]?.let { + appendNode("exclusions").appendNode("exclusion").identify(it) + } + } + } + } + } + """.trimIndent() + + /** + * Returns the declaration of a configuration with the given [name], which resolves + * the runtime variants of what it holds, as `runtimeClasspath` does. + */ + fun resolvableConfiguration(name: String, transitive: Boolean = true): String = + """ + val $name = configurations.create("$name") { + isCanBeConsumed = false + isTransitive = $transitive + attributes { + attribute(Usage.USAGE_ATTRIBUTE, objects.named(Usage.JAVA_RUNTIME)) + attribute(Category.CATEGORY_ATTRIBUTE, objects.named(Category.LIBRARY)) + attribute(Bundling.BUNDLING_ATTRIBUTE, objects.named(Bundling.EXTERNAL)) + attribute( + LibraryElements.LIBRARY_ELEMENTS_ATTRIBUTE, + objects.named(LibraryElements.JAR) + ) + } + } + """.trimIndent() + + /** The packaging and the license of the parent POM of `lib`. */ + val parentHead = """ + pom + + + The MIT License + http://www.opensource.org/licenses/mit-license.php + + + """.trimIndent() + + /** The plugin configuration of the parent POM of `lib`. */ + val parentBuild = """ + + + + + org.apache.maven.plugins + maven-compiler-plugin + + 8 + + + + + + + org.apache.maven.plugins + maven-jar-plugin + + true + + + + + """.trimIndent() + + /** Makes `com.example:parent` the parent POM of `lib`. */ + val libParent = """ + + com.example + parent + 1.0 + + """.trimIndent() + + /** The plugin configuration of `lib`, merged with that of its parent. */ + val libBuild = """ + + + + org.apache.maven.plugins + maven-compiler-plugin + + true + + + + org.apache.maven.plugins + maven-jar-plugin + + true + + + + + """.trimIndent() + } +} + +private fun File.readJson(): JsonNode = ObjectMapper().readTree(this) + +private fun JsonNode.packageNames(): List = + this[SpdxField.packages].shouldNotBeNull().map { it[SpdxField.name].asText() } + +private fun JsonNode.packageNamed(name: String): JsonNode = + this[SpdxField.packages].shouldNotBeNull() + .firstOrNull { it[SpdxField.name].asText() == name } + .shouldNotBeNull() + +private fun JsonNode.purl(): String? = + this[SpdxField.externalRefs] + ?.firstOrNull { it[SpdxField.referenceType].asText() == "purl" } + ?.get(SpdxField.referenceLocator) + ?.asText() + +/** An SPDX relationship, `element` being of the given `type` to the `related` element. */ +private data class Relationship(val element: String, val type: String, val related: String) + +private fun JsonNode.relationships(): List = + this[SpdxField.relationships].shouldNotBeNull().map { + Relationship( + element = it[SpdxField.spdxElementId].asText(), + type = it[SpdxField.relationshipType].asText(), + related = it[SpdxField.relatedSpdxElement].asText() + ) + } + +private fun JsonNode.packagesById(): Map = + this[SpdxField.packages].shouldNotBeNull().associateBy { it[SpdxField.spdxId].asText() } + +/** Returns the SPDX ID of the package of the artifact, which the document describes. */ +private fun JsonNode.describedId(): String = + relationships().single { it.element == DOCUMENT_ID && it.type == DESCRIBES }.related + +/** Returns the names of the packages to which the artifact is related as [type] says. */ +private fun JsonNode.relatedToArtifact(type: String): List = + relatedTo(describedId(), type) + +/** Returns the names of the packages to which [pkg] is related as [type] says. */ +private fun JsonNode.relatedTo(pkg: JsonNode, type: String): List = + relatedTo(pkg[SpdxField.spdxId].asText(), type) + +private fun JsonNode.relatedTo(id: String, type: String): List { + val packages = packagesById() + return relationships() + .filter { it.element == id && it.type == type } + .map { packages.getValue(it.related)[SpdxField.name].asText() } +} + +/** Returns the names of the packages any package of the document depends on. */ +private fun JsonNode.dependencyTargets(): List { + val packages = packagesById() + return relationships() + .filter { it.type == DEPENDS_ON } + .map { packages.getValue(it.related)[SpdxField.name].asText() } +} + +/** + * Asserts that each relationship of this document relates its elements, and relates + * them once; that each license text a package refers to is in the document; and that + * each package is found from the package of the artifact. + */ +private fun JsonNode.shouldBeComplete() { + val packages = packagesById() + val relationships = relationships() + relationships.flatMap { listOf(it.element, it.related) } + .filterNot { it == DOCUMENT_ID } + .forEach { packages.keys shouldContain it } + relationships.distinct() shouldContainExactly relationships + val licenses = this[SpdxField.hasExtractedLicensingInfos] + ?.map { it[SpdxField.licenseId].asText() } + .orEmpty() + packages.values + .flatMap(::licenseReferencesOf) + .forEach { licenses shouldContain it } + reachableFrom(describedId(), relationships) shouldContainExactlyInAnyOrder packages.keys +} + +private fun reachableFrom(id: String, relationships: List): Set { + val reached = mutableSetOf(id) + val queue = ArrayDeque(listOf(id)) + while (queue.isNotEmpty()) { + val element = queue.removeFirst() + relationships.filter { it.element == element } + .map { it.related } + .filter(reached::add) + .forEach(queue::add) + } + return reached +} + +/** Returns the text of the child element of this one with the given [tag]. */ +private fun Element.childText(tag: String): String { + val children = childNodes + return (0 until children.length) + .map { children.item(it) } + .first { it is Element && it.tagName == tag } + .textContent +} diff --git a/buildSrc/src/test/kotlin/io/spine/gradle/publish/PublishingCredentialsIgTest.kt b/buildSrc/src/test/kotlin/io/spine/gradle/publish/PublishingCredentialsIgTest.kt new file mode 100644 index 0000000..bfb5e70 --- /dev/null +++ b/buildSrc/src/test/kotlin/io/spine/gradle/publish/PublishingCredentialsIgTest.kt @@ -0,0 +1,337 @@ +/* + * Copyright 2026 CodeMatters, Lda. + * + * 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 io.spine.gradle.publish + +import com.sun.net.httpserver.HttpExchange +import com.sun.net.httpserver.HttpServer +import io.kotest.assertions.withClue +import io.kotest.matchers.file.shouldExist +import io.kotest.matchers.file.shouldNotExist +import io.kotest.matchers.shouldBe +import io.kotest.matchers.string.shouldContain +import io.kotest.matchers.string.shouldNotContain +import java.io.File +import java.net.InetAddress +import java.net.InetSocketAddress +import java.net.URI +import java.util.Base64 +import java.util.concurrent.CopyOnWriteArrayList +import org.gradle.testkit.runner.BuildResult +import org.gradle.testkit.runner.GradleRunner +import org.junit.jupiter.api.AfterEach +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.DisplayName +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.io.TempDir + +/** + * Verifies when the credentials of a publishing destination are obtained, + * against a real build run via Gradle TestKit. + * + * Obtaining the credentials may start an external process — `gcloud` for + * [CloudArtifactRegistry]. Gradle deprecates starting one at configuration time, + * so the credentials must be obtained only by a build that publishes, and only + * when it is about to. + * + * Each [Destination] of the fixture obtains its own credentials with a function + * that records each call in a file, and points at its own [ProbeRepository], + * an HTTP server that accepts uploads only with credentials. + */ +@DisplayName("Credentials of a publishing destination should") +internal class PublishingCredentialsIgTest { + + @TempDir + lateinit var projectDir: File + + private val destinations = listOf( + Destination(name = "Probe", username = "publisher", password = "secret"), + Destination(name = "Other", username = "deployer", password = "token"), + ) + + @BeforeEach + fun createBuild() { + file("settings.gradle.kts").writeText( + """ + rootProject.name = "credentials-sample" + include("lib") + """.trimIndent() + ) + file("build.gradle.kts").writeText( + """ + buildscript { + dependencies { + classpath(files( + ${buildSrcClasspath()} + )) + } + } + + import io.spine.gradle.publish.spinePublishing + import io.spine.gradle.repo.Credentials + import io.spine.gradle.repo.Repository + + allprojects { + group = "io.spine.sample" + version = "1.0.0" + } + + subprojects { + apply(plugin = "java-library") + apply(plugin = "maven-publish") + + // `javadocJar` of `spinePublishing` is wired to Dokka, which + // this fixture does not apply: the credentials are under test. + tasks.register("dokkaGeneratePublicationJavadoc") + + // The probe repositories are served over plain HTTP. + the().repositories + .withType() + .configureEach { isAllowInsecureProtocol = true } + } + + spinePublishing { + modules = setOf("lib") + destinations = setOf( + ${destinations.joinToString(",\n") { it.declaration() }} + ) + } + """.trimIndent() + ) + file("lib/src/main/java/io/spine/sample/Sample.java").apply { + parentFile.mkdirs() + writeText("package io.spine.sample;\n\npublic class Sample {}\n") + } + } + + @AfterEach + fun stopRepositories() { + destinations.forEach { it.repository.close() } + } + + @Test + fun `not be obtained by a build that does not publish`() { + val stored = runGradle("help", "--configuration-cache") + withClue("The run that stores the configuration cache entry") { + stored.output shouldContain "Configuration cache entry stored" + } + val reused = runGradle("help", "--configuration-cache") + withClue("The run that reuses the configuration cache entry") { + reused.output shouldContain "Reusing configuration cache" + } + + file(requestLog).shouldNotExist() + } + + @Test + fun `be sent with each upload to its own repository`() { + runGradle(publishTask) + + shouldSendOwnCredentials() + } + + /** + * Gradle does not support explicit repository credentials with the configuration + * cache, so a build that publishes with them falls back to running without it + * instead of failing. + */ + @Test + fun `be sent with each upload when the configuration cache is requested`() { + runGradle(publishTask, "--configuration-cache") + + shouldSendOwnCredentials() + } + + /** + * Gradle deprecates calling `Task.project` at execution time, which is + * when the check obtains the credentials. + */ + @Test + fun `be checked by 'checkCredentials' without reaching the project through its task`() { + val result = runGradle(checkTask, "--warning-mode", "all") + + result.output shouldNotContain "Invocation of Task.project at execution time" + file(requestLog).shouldExist() + } + + /** + * Only the last destination lacks credentials, so a check that stops + * at the first one cannot pass. + */ + @Test + fun `be required by 'checkCredentials' for every destination`() { + val lacking = destinations.last().name + val result = gradle(checkTask, "-P$withoutCredentials=$lacking").buildAndFail() + + result.output shouldContain "No valid credentials for repository `$lacking`" + } + + /** + * Asserts that each repository accepted uploads only with the credentials + * of its own destination. + * + * Checking the log of credential requests here shows that the fixture writes it, + * so the `help` case, which expects no log, cannot pass vacuously. + */ + private fun shouldSendOwnCredentials() { + file(requestLog).shouldExist() + destinations.forEach { + withClue(it.name) { + it.repository.authorizations.toSet() shouldBe setOf(it.authorization) + } + } + } + + private fun runGradle(vararg arguments: String): BuildResult = gradle(*arguments).build() + + private fun gradle(vararg arguments: String): GradleRunner = + GradleRunner.create() + .withProjectDir(projectDir) + .withArguments(*arguments, "--stacktrace") + + private fun file(relativePath: String): File = projectDir.resolve(relativePath) + + /** + * Renders the classpath with the production classes of `buildSrc` as + * arguments of `files(...)`, for injection into the build script classpath + * of the generated build. + * + * The classpath comes from the `test` task in `buildSrc/build.gradle.kts`. + */ + private fun buildSrcClasspath(): String { + val classpath = requireNotNull(System.getProperty("buildSrc.classpath")) { + "The `buildSrc.classpath` system property is not set." + + " It is supplied by the `test` task in `buildSrc/build.gradle.kts`." + } + return classpath.split(File.pathSeparator).joinToString(",\n") { + " \"${File(it).invariantSeparatorsPath}\"" + } + } + + /** + * A publishing destination of the fixture, served by its own [repository]. + */ + private class Destination(val name: String, val username: String, val password: String) { + + val repository = ProbeRepository() + + /** + * The `Authorization` header that carries the credentials of this destination. + */ + val authorization: String = + "Basic " + Base64.getEncoder().encodeToString("$username:$password".toByteArray()) + + /** + * Declares this destination in the build script of the fixture. + * + * The lines are indented like those of [buildSrcClasspath], so that + * the build script keeps its indentation once it is trimmed. + */ + fun declaration(): String = + """ + Repository( + name = "$name", + releases = "${repository.url}", + snapshots = "${repository.url}", + credentialValues = { project -> + project.rootDir.resolve("$requestLog").appendText("$name\n") + if (project.findProperty("$withoutCredentials") == "$name") null + else Credentials("$username", "$password") + } + ) + """.trimIndent().prependIndent(" ") + } + + private companion object { + + /** + * The file to which the credentials functions of the fixture append + * a line each time they are called. + */ + const val requestLog = "credential-requests.log" + + /** + * The project property that names the destination whose credentials function + * finds no credentials. + */ + const val withoutCredentials = "withoutCredentials" + + /** + * Publishes to every destination and checks their credentials. + */ + const val publishTask = ":lib:publish" + + /** + * Checks that every destination has credentials. + */ + const val checkTask = ":lib:checkCredentials" + } +} + +/** + * A Maven repository that accepts an upload only with credentials. + * It is served over HTTP from the loopback interface. + * + * Gradle does not send the credentials until challenged, so the repository answers + * an upload without them with `401`, asking for Basic authentication. + * It has no artifacts to serve, so it answers any other request with `404`. + */ +private class ProbeRepository : AutoCloseable { + + private val server: HttpServer = + HttpServer.create(InetSocketAddress(InetAddress.getLoopbackAddress(), 0), 0) + + private val accepted = CopyOnWriteArrayList() + + /** + * The `Authorization` headers of the accepted uploads. + */ + val authorizations: List + get() = accepted.toList() + + /** + * The URL of this repository. + * + * The loopback address may be an IPv6 one, which [URI] encloses in square brackets. + */ + val url: String + get() { + val address = server.address + return URI("http", null, address.hostString, address.port, "/maven", null, null) + .toString() + } + + init { + server.createContext("/") { exchange -> exchange.use { respond(it) } } + server.start() + } + + private fun respond(exchange: HttpExchange) { + exchange.requestBody.readBytes() + val authorization = exchange.requestHeaders.getFirst("Authorization") + when { + exchange.requestMethod != "PUT" -> exchange.sendResponseHeaders(404, -1) + authorization == null -> { + exchange.responseHeaders.add("WWW-Authenticate", "Basic realm=\"probe\"") + exchange.sendResponseHeaders(401, -1) + } + else -> { + accepted.add(authorization) + exchange.sendResponseHeaders(201, -1) + } + } + } + + override fun close() = server.stop(0) +} diff --git a/buildSrc/src/test/kotlin/io/spine/gradle/publish/SpinePublishingTest.kt b/buildSrc/src/test/kotlin/io/spine/gradle/publish/SpinePublishingTest.kt index 52663c2..c97f30f 100644 --- a/buildSrc/src/test/kotlin/io/spine/gradle/publish/SpinePublishingTest.kt +++ b/buildSrc/src/test/kotlin/io/spine/gradle/publish/SpinePublishingTest.kt @@ -1,27 +1,15 @@ /* - * Copyright 2026, TeamDev. All rights reserved. + * Copyright 2026 CodeMatters, Lda. * - * 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 + * 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 * - * Redistribution and use in source and/or binary forms, with or without - * modification, must retain the above copyright notice and the following - * disclaimer. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 io.spine.gradle.publish @@ -239,6 +227,54 @@ class SpinePublishingTest { repos shouldHaveSize 1 repos shouldContain repo } + + @Test + fun `from the parent project if the local extension does not set them`() { + val repo = Repository( + "parent-repo", + "https://example.com/release", + "https://example.com/snapshot" + ) + // Root project has its extension named 'spinePublishing' from setUp. + extension.destinations = setOf(repo) + + val subproject = ProjectBuilder.builder().withParent(project).withName("sub").build() + // Subproject opens its own extension, leaving `destinations` uninitialized. + val extensionName = SpinePublishing.extensionName + val subExtension = + subproject.extensions.create(extensionName, subproject) + + val repos = subproject.invokePublishTo(subExtension) + repos shouldHaveSize 1 + repos shouldContain repo + } + + @Test + fun `from the local extension even if called through the root one`() { + val rootRepo = Repository( + "root-repo", + "https://example.com/root/release", + "https://example.com/root/snapshot" + ) + // Root project has its extension named 'spinePublishing' from setUp. + extension.destinations = setOf(rootRepo) + + val subproject = ProjectBuilder.builder().withParent(project).withName("sub").build() + val subRepo = Repository( + "sub-repo", + "https://example.com/sub/release", + "https://example.com/sub/snapshot" + ) + // Subproject opens its own extension with different destinations. + val extensionName = SpinePublishing.extensionName + val subExtension = + subproject.extensions.create(extensionName, subproject) + subExtension.destinations = setOf(subRepo) + + val repos = subproject.invokePublishTo(extension) + repos shouldHaveSize 1 + repos shouldContain subRepo + } } } diff --git a/buildSrc/src/test/kotlin/io/spine/gradle/repo/RepositoriesSpec.kt b/buildSrc/src/test/kotlin/io/spine/gradle/repo/RepositoriesSpec.kt new file mode 100644 index 0000000..df120ff --- /dev/null +++ b/buildSrc/src/test/kotlin/io/spine/gradle/repo/RepositoriesSpec.kt @@ -0,0 +1,51 @@ +/* + * Copyright 2026 CodeMatters, Lda. + * + * 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 io.spine.gradle.repo + +import io.kotest.matchers.collections.shouldContainExactly +import io.spine.gradle.publish.CloudRepo +import io.spine.gradle.publish.PublishingRepos +import java.net.URI +import org.gradle.api.artifacts.repositories.MavenArtifactRepository +import org.gradle.testfixtures.ProjectBuilder +import org.junit.jupiter.api.DisplayName +import org.junit.jupiter.api.Test + +@DisplayName("`standardToSpineSdk()` should") +internal class RepositoriesSpec { + + @Test + fun `query Spine repositories from Artifact Registry to GitHub Packages`() { + val project = ProjectBuilder.builder().build() + project.repositories.standardToSpineSdk() + + val registry = PublishingRepos.cloudArtifactRegistry + @Suppress("DEPRECATION") // Still queried for earlier versions. + val cloudRepo = CloudRepo.published + val spineRepos = listOf( + registry.target(snapshots = false), + registry.target(snapshots = true), + cloudRepo.target(snapshots = false), + cloudRepo.target(snapshots = true), + "https://maven.pkg.github.com/SpineEventEngine/*" + ).map { URI(it) } + + val queried = project.repositories + .filterIsInstance() + .map { it.url } + .filter { it in spineRepos } + queried shouldContainExactly spineRepos + } +} diff --git a/buildSrc/src/test/kotlin/io/spine/gradle/report/coverage/FileExtensionsTest.kt b/buildSrc/src/test/kotlin/io/spine/gradle/report/coverage/FileExtensionsTest.kt index c53d802..c457bfa 100644 --- a/buildSrc/src/test/kotlin/io/spine/gradle/report/coverage/FileExtensionsTest.kt +++ b/buildSrc/src/test/kotlin/io/spine/gradle/report/coverage/FileExtensionsTest.kt @@ -1,27 +1,15 @@ /* - * Copyright 2026, TeamDev. All rights reserved. + * Copyright 2026 CodeMatters, Lda. * - * 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 + * 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 * - * Redistribution and use in source and/or binary forms, with or without - * modification, must retain the above copyright notice and the following - * disclaimer. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 io.spine.gradle.report.coverage diff --git a/buildSrc/src/test/kotlin/io/spine/gradle/report/license/DependencyReportOutputTest.kt b/buildSrc/src/test/kotlin/io/spine/gradle/report/license/DependencyReportOutputTest.kt index 9c36b21..a6213ab 100644 --- a/buildSrc/src/test/kotlin/io/spine/gradle/report/license/DependencyReportOutputTest.kt +++ b/buildSrc/src/test/kotlin/io/spine/gradle/report/license/DependencyReportOutputTest.kt @@ -1,27 +1,15 @@ /* - * Copyright 2026, TeamDev. All rights reserved. + * Copyright 2026 CodeMatters, Lda. * - * 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 + * 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 * - * Redistribution and use in source and/or binary forms, with or without - * modification, must retain the above copyright notice and the following - * disclaimer. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 io.spine.gradle.report.license diff --git a/buildSrc/src/test/kotlin/io/spine/gradle/report/pom/DependencyWriterSpec.kt b/buildSrc/src/test/kotlin/io/spine/gradle/report/pom/DependencyWriterSpec.kt index ad5ebad..5187690 100644 --- a/buildSrc/src/test/kotlin/io/spine/gradle/report/pom/DependencyWriterSpec.kt +++ b/buildSrc/src/test/kotlin/io/spine/gradle/report/pom/DependencyWriterSpec.kt @@ -1,27 +1,15 @@ /* - * Copyright 2026, TeamDev. All rights reserved. + * Copyright 2026 CodeMatters, Lda. * - * 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 + * 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 * - * Redistribution and use in source and/or binary forms, with or without - * modification, must retain the above copyright notice and the following - * disclaimer. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 io.spine.gradle.report.pom diff --git a/buildSrc/src/test/kotlin/io/spine/gradle/report/pom/PomGeneratorIgTest.kt b/buildSrc/src/test/kotlin/io/spine/gradle/report/pom/PomGeneratorIgTest.kt index cc5c83b..cd0ac5d 100644 --- a/buildSrc/src/test/kotlin/io/spine/gradle/report/pom/PomGeneratorIgTest.kt +++ b/buildSrc/src/test/kotlin/io/spine/gradle/report/pom/PomGeneratorIgTest.kt @@ -1,27 +1,15 @@ /* - * Copyright 2026, TeamDev. All rights reserved. + * Copyright 2026 CodeMatters, Lda. * - * 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 + * 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 * - * Redistribution and use in source and/or binary forms, with or without - * modification, must retain the above copyright notice and the following - * disclaimer. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 io.spine.gradle.report.pom @@ -219,7 +207,14 @@ internal class PomGeneratorIgTest { } """.trimIndent() val unresolvable = """ - val unresolvable by configurations.creating + // `isCanBeResolved` is stated rather than inherited: the legacy + // role it would otherwise get is a deprecation candidate, and if + // the default changes this configuration would be skipped by the + // `isCanBeResolved` filter in `resolvedVersions()` — the fixture + // would stop covering the failing-configuration case while the + // test still passed. + val unresolvable = + configurations.create("unresolvable") { isCanBeResolved = true } unresolvable.resolutionStrategy.failOnVersionConflict() """.trimIndent() val dependencies = buildString { diff --git a/config b/config index 2cd0e3b..a0cbbbf 160000 --- a/config +++ b/config @@ -1 +1 @@ -Subproject commit 2cd0e3b1bfc860e66a1b9b0866cfb9ecea522f0c +Subproject commit a0cbbbfe66c12475224563439fb6deb3da71ba58 diff --git a/gradle.properties b/gradle.properties index 7c2bb5f..78a5789 100644 --- a/gradle.properties +++ b/gradle.properties @@ -43,3 +43,8 @@ kotlin.tests.individualTaskReports=true # For details please see: # https://kotlinlang.org/docs/dokka-migration.html#enable-migration-helpers org.jetbrains.dokka.experimental.gradle.pluginMode=V2EnabledWithHelpers + +# Let the IDE fetch the project models in parallel during a Gradle sync. +# Since Gradle 9.4, `org.gradle.parallel` above covers only the build execution. +# This affects only the models built for an IDE, not the tasks of a build. +org.gradle.tooling.parallel=true diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index eddabd2eef8d94a5437d6168ff9c87a78ff725b3..9fa7f288283f81eec4952784c271abd7e0938dee 100644 GIT binary patch delta 40003 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 delta 38903 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 diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index ad7845b..2e7bb9f 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-9.7.1-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-9.8.1-bin.zip networkTimeout=10000 retries=0 retryBackOffMs=500 diff --git a/gradlew.bat b/gradlew.bat index a51ec4f..3185a43 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -26,6 +26,33 @@ @rem Set local scope for the variables, and ensure extensions are enabled setlocal EnableExtensions +@rem Catch executions from older scripts and ensure they exit cleanly. +@rem This can be removed once we can be reasonably confident that few people +@rem will be migrating directly to this new wrapper. +goto afterSafetyNet +:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: +:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: +:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: +:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: +:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: +:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: +:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: +:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: +:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: +:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: +:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: +:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: +:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: +:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: +:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: +:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: +:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: +:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: +:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: +:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: +goto exitWithErrorLevel +:afterSafetyNet + set DIRNAME=%~dp0 if "%DIRNAME%"=="" set DIRNAME=. @rem This is normally unused @@ -45,13 +72,14 @@ set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 if %ERRORLEVEL% equ 0 goto execute -echo. 1>&2 -echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2 -echo. 1>&2 -echo Please set the JAVA_HOME variable in your environment to match the 1>&2 -echo location of your Java installation. 1>&2 +1>&2 echo. +1>&2 echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +1>&2 echo. +1>&2 echo Please set the JAVA_HOME variable in your environment to match the +1>&2 echo location of your Java installation. "%COMSPEC%" /c exit 1 +goto exitWithErrorLevel :findJavaFromJavaHome set JAVA_HOME=%JAVA_HOME:"=% @@ -59,13 +87,14 @@ set JAVA_EXE=%JAVA_HOME%/bin/java.exe if exist "%JAVA_EXE%" goto execute -echo. 1>&2 -echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2 -echo. 1>&2 -echo Please set the JAVA_HOME variable in your environment to match the 1>&2 -echo location of your Java installation. 1>&2 +1>&2 echo. +1>&2 echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +1>&2 echo. +1>&2 echo Please set the JAVA_HOME variable in your environment to match the +1>&2 echo location of your Java installation. "%COMSPEC%" /c exit 1 +goto exitWithErrorLevel :execute @rem Setup the command line @@ -75,8 +104,9 @@ echo location of your Java installation. 1>&2 @rem Execute gradlew @rem endlocal doesn't take effect until after the line is parsed and variables are expanded @rem which allows us to clear the local environment before executing the java command -endlocal & "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %* & call :exitWithErrorLevel +endlocal & "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %* & call :exitWithErrorLevel & goto exitWithErrorLevel +@rem This label must not be changed. We rely on old scripts being able to jump to this point. :exitWithErrorLevel @rem Use "%COMSPEC%" /c exit to allow operators to work properly in scripts "%COMSPEC%" /c exit %ERRORLEVEL% diff --git a/init-submodules b/init-submodules index 2ae143d..95b916b 100755 --- a/init-submodules +++ b/init-submodules @@ -49,7 +49,85 @@ set -u -root=$(git rev-parse --show-toplevel 2>/dev/null) || exit 0 +# Ignore an inherited `CDPATH`: it would redirect a relative `cd`, such as into +# the `.git` that `git rev-parse --git-common-dir` prints in a main checkout, +# and make `cd` print the directory it enters. +unset CDPATH + +# Decode the JSON string escapes that a path can hold: `\\` (each backslash of a +# Windows path), `\"`, and `\/`. Fail on any other escape, such as `\n`. +json_unescape() { + local rest=$1 out="" next + while :; do + case $rest in + *\\*) ;; + *) printf '%s' "$out$rest"; return 0 ;; + esac + out=$out${rest%%\\*} + rest=${rest#*\\} + next=${rest%"${rest#?}"} + case $next in + \\ | \" | /) out=$out$next ;; + *) return 1 ;; + esac + rest=${rest#?} + done +} + +# Act on the work tree the session is in. Claude Code runs this script as a +# `SessionStart` hook and passes the hook input JSON on stdin. The `cwd` field +# of that JSON is the session's working directory. In a worktree session, that +# directory is inside the worktree, while this process and `$CLAUDE_PROJECT_DIR` +# stay in the main checkout. Read stdin only when Claude Code started the script +# (it exports `CLAUDE_PROJECT_DIR` to hooks) and stdin is not a terminal, so that +# a manual run never waits for input. +# +# Parse the input with `jq` when it is installed. The bootstrap cannot require +# `jq`, so without it a pattern match reads the first `cwd` member, and +# `json_unescape` decodes it; a value it cannot decode falls back as described +# below. Unlike `jq`, the pattern does not validate the rest of the input, which +# Claude Code writes. Either way, the path must belong to the project, as checked +# below. +session_dir="" +if [ -n "${CLAUDE_PROJECT_DIR:-}" ] && [ ! -t 0 ]; then + if command -v jq >/dev/null 2>&1; then + session_dir=$(jq -r '.cwd // empty' 2>/dev/null) || session_dir="" + else + input=$(cat) + cwd_pattern='"cwd"[[:space:]]*:[[:space:]]*"(([^"\\]|\\.)*)"' + if [[ $input =~ $cwd_pattern ]]; then + session_dir=$(json_unescape "${BASH_REMATCH[1]}") || session_dir="" + fi + fi +fi + +# The physical path of the Git directory that a repository's main checkout and +# linked worktrees share; empty outside a work tree. Each `git` result is checked +# before use, because `cd ""` succeeds. +common_git_dir() { + (cd "$1" && top=$(git rev-parse --show-toplevel) && cd "$top" \ + && common=$(git rev-parse --git-common-dir) && cd "$common" && pwd -P) 2>/dev/null +} + +# From the session directory, climb out of any submodule (`config`, +# `.agents/shared`) to the first work tree of the project's own repository — its +# main checkout or a linked worktree. Anything else (no `cwd`, one that does not +# resolve, an unrelated repository) falls back to the current directory, as +# before: this script changes repository configuration, so it must not act on a +# repository the project does not own. +root="" +if [ -n "$session_dir" ]; then + project=$(common_git_dir "$CLAUDE_PROJECT_DIR") + tree=$(git -C "$session_dir" rev-parse --show-toplevel 2>/dev/null) + while [ -n "$tree" ] && [ -n "$project" ]; do + if [ "$(common_git_dir "$tree")" = "$project" ]; then + root=$tree + break + fi + tree=$(git -C "$tree" rev-parse --show-superproject-working-tree 2>/dev/null) + done +fi +[ -n "$root" ] || root=$(git rev-parse --show-toplevel 2>/dev/null) || exit 0 cd "$root" || exit 0 # Nothing to do in a repo without submodules. From 2dbe6909c652356dc7d2b839d04f1964fee977dc Mon Sep 17 00:00:00 2001 From: alexander-yevsyukov Date: Thu, 15 Oct 2026 20:04:17 +0100 Subject: [PATCH 02/17] Update local dependency pins --- buildSrc/src/main/kotlin/io/spine/dependency/local/Base.kt | 2 +- buildSrc/src/main/kotlin/io/spine/dependency/local/Compiler.kt | 2 +- .../main/kotlin/io/spine/dependency/local/CoreJvmCompiler.kt | 2 +- .../src/main/kotlin/io/spine/dependency/local/Validation.kt | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/buildSrc/src/main/kotlin/io/spine/dependency/local/Base.kt b/buildSrc/src/main/kotlin/io/spine/dependency/local/Base.kt index aa06886..c310c7d 100644 --- a/buildSrc/src/main/kotlin/io/spine/dependency/local/Base.kt +++ b/buildSrc/src/main/kotlin/io/spine/dependency/local/Base.kt @@ -21,7 +21,7 @@ package io.spine.dependency.local */ @Suppress("ConstPropertyName", "unused") object Base { - const val version = "2.0.0-SNAPSHOT.460" + const val version = "2.0.0-SNAPSHOT.461" const val versionForBuildScript = "2.0.0-SNAPSHOT.460" const val group = Spine.group private const val prefix = "spine" diff --git a/buildSrc/src/main/kotlin/io/spine/dependency/local/Compiler.kt b/buildSrc/src/main/kotlin/io/spine/dependency/local/Compiler.kt index 137e830..646bbbf 100644 --- a/buildSrc/src/main/kotlin/io/spine/dependency/local/Compiler.kt +++ b/buildSrc/src/main/kotlin/io/spine/dependency/local/Compiler.kt @@ -60,7 +60,7 @@ object Compiler : Dependency() { * The version of the Compiler dependencies. */ override val version: String - private const val fallbackVersion = "2.0.0-SNAPSHOT.069" + private const val fallbackVersion = "2.0.0-SNAPSHOT.070" /** * The distinct version of the Compiler used by other build tools. diff --git a/buildSrc/src/main/kotlin/io/spine/dependency/local/CoreJvmCompiler.kt b/buildSrc/src/main/kotlin/io/spine/dependency/local/CoreJvmCompiler.kt index 5db1a81..6a64e8a 100644 --- a/buildSrc/src/main/kotlin/io/spine/dependency/local/CoreJvmCompiler.kt +++ b/buildSrc/src/main/kotlin/io/spine/dependency/local/CoreJvmCompiler.kt @@ -39,7 +39,7 @@ object CoreJvmCompiler { /** * The version to be used for integration tests. */ - const val version = "2.0.0-SNAPSHOT.097" + const val version = "2.0.0-SNAPSHOT.098" /** * The ID of the Gradle plugin. diff --git a/buildSrc/src/main/kotlin/io/spine/dependency/local/Validation.kt b/buildSrc/src/main/kotlin/io/spine/dependency/local/Validation.kt index b1069ce..c08b6db 100644 --- a/buildSrc/src/main/kotlin/io/spine/dependency/local/Validation.kt +++ b/buildSrc/src/main/kotlin/io/spine/dependency/local/Validation.kt @@ -24,7 +24,7 @@ object Validation { /** * The version of the Validation library artifacts. */ - const val version = "2.0.0-SNAPSHOT.464" + const val version = "2.0.0-SNAPSHOT.465" const val group = Spine.toolsGroup private const val prefix = "validation" From 5b29dd3bbfc4ac7f39f069462363814ba1c8b66f Mon Sep 17 00:00:00 2001 From: alexander-yevsyukov Date: Thu, 15 Oct 2026 20:04:17 +0100 Subject: [PATCH 03/17] Bump version -> `2.0.0-SNAPSHOT.209` --- version.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.gradle.kts b/version.gradle.kts index 0f2e15d..f7b43a8 100644 --- a/version.gradle.kts +++ b/version.gradle.kts @@ -27,4 +27,4 @@ /** * The version of this library. */ -extra.set("versionToPublish", "2.0.0-SNAPSHOT.208") +extra.set("versionToPublish", "2.0.0-SNAPSHOT.209") From 6dcc847582ac3b084fdb376921e1d4a8fc753608 Mon Sep 17 00:00:00 2001 From: alexander-yevsyukov Date: Fri, 16 Oct 2026 14:48:55 +0100 Subject: [PATCH 04/17] Adapt to refreshed dependencies `ToolBase.lib` is gone from `config`: the `tool-base` artifact is no longer published, so forcing its coordinates had no effect. Co-Authored-By: Claude Opus 5.5 --- buildSrc/src/main/kotlin/module.gradle.kts | 2 -- 1 file changed, 2 deletions(-) diff --git a/buildSrc/src/main/kotlin/module.gradle.kts b/buildSrc/src/main/kotlin/module.gradle.kts index 5ff0787..c8abf4a 100644 --- a/buildSrc/src/main/kotlin/module.gradle.kts +++ b/buildSrc/src/main/kotlin/module.gradle.kts @@ -35,7 +35,6 @@ import io.spine.dependency.local.Base import io.spine.dependency.local.CoreJvm import io.spine.dependency.local.Logging import io.spine.dependency.local.Time -import io.spine.dependency.local.ToolBase import io.spine.dependency.local.Validation import io.spine.dependency.test.Jacoco import io.spine.gradle.checkstyle.CheckStyleConfig @@ -141,7 +140,6 @@ private fun Project.forceDependencies() { Kotlin.bom, KotlinPoet.lib, Protobuf.javaLib, - ToolBase.lib, Base.lib, Base.annotations, Base.environment, From 77d365c2bb8de72817d12b8983010b7bc7439126 Mon Sep 17 00:00:00 2001 From: alexander-yevsyukov Date: Fri, 16 Oct 2026 14:50:05 +0100 Subject: [PATCH 05/17] Adapt to refreshed dependencies Force Reflect: the refreshed Base and the published CoreJvm Compiler floor request different versions of it. Co-Authored-By: Claude Opus 5.5 --- buildSrc/src/main/kotlin/module.gradle.kts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/buildSrc/src/main/kotlin/module.gradle.kts b/buildSrc/src/main/kotlin/module.gradle.kts index c8abf4a..d4bf06e 100644 --- a/buildSrc/src/main/kotlin/module.gradle.kts +++ b/buildSrc/src/main/kotlin/module.gradle.kts @@ -34,6 +34,7 @@ import io.spine.dependency.lib.Protobuf import io.spine.dependency.local.Base import io.spine.dependency.local.CoreJvm import io.spine.dependency.local.Logging +import io.spine.dependency.local.Reflect import io.spine.dependency.local.Time import io.spine.dependency.local.Validation import io.spine.dependency.test.Jacoco @@ -144,6 +145,7 @@ private fun Project.forceDependencies() { Base.annotations, Base.environment, Base.format, + Reflect.lib, Validation.runtime, Validation.javaBundle, Logging.lib, From 6d15a7d9caa8e9ecddbe9f0dca2a394be78a16db Mon Sep 17 00:00:00 2001 From: alexander-yevsyukov Date: Fri, 16 Oct 2026 14:50:17 +0100 Subject: [PATCH 06/17] Update dependency reports --- docs/dependencies/dependencies.md | 268 +++++++++++++++++------------- docs/dependencies/pom.xml | 52 +++--- 2 files changed, 174 insertions(+), 146 deletions(-) diff --git a/docs/dependencies/dependencies.md b/docs/dependencies/dependencies.md index 21500cb..7525999 100644 --- a/docs/dependencies/dependencies.md +++ b/docs/dependencies/dependencies.md @@ -1,10 +1,11 @@ -# Dependencies of `io.spine:spine-change:2.0.0-SNAPSHOT.208` +# Dependencies of `io.spine:spine-change:2.0.0-SNAPSHOT.209` ## Runtime 1. **Group** : com.google.code.findbugs. **Name** : jsr305. **Version** : 3.0.2. * **Project URL:** [http://findbugs.sourceforge.net/](http://findbugs.sourceforge.net/) + * **License:** [http://www.apache.org/licenses/LICENSE-2.0.txt](http://www.apache.org/licenses/LICENSE-2.0.txt) * **License:** [The Apache Software License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) 1. **Group** : com.google.code.gson. **Name** : gson. **Version** : 2.14.0. @@ -17,10 +18,12 @@ 1. **Group** : com.google.guava. **Name** : failureaccess. **Version** : 1.0.3. * **Project URL:** [https://github.com/google/guava/](https://github.com/google/guava/) + * **License:** [http://www.apache.org/licenses/LICENSE-2.0.txt](http://www.apache.org/licenses/LICENSE-2.0.txt) * **License:** [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) -1. **Group** : com.google.guava. **Name** : guava. **Version** : 33.7.1-jre. +1. **Group** : com.google.guava. **Name** : guava. **Version** : 33.7.2-jre. * **Project URL:** [https://github.com/google/guava](https://github.com/google/guava) + * **License:** [http://www.apache.org/licenses/LICENSE-2.0.txt](http://www.apache.org/licenses/LICENSE-2.0.txt) * **License:** [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) 1. **Group** : com.google.guava. **Name** : listenablefuture. **Version** : 9999.0-empty-to-avoid-conflict-with-guava. @@ -30,31 +33,34 @@ * **Project URL:** [https://github.com/google/j2objc/](https://github.com/google/j2objc/) * **License:** [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) -1. **Group** : com.google.protobuf. **Name** : protobuf-java. **Version** : 4.36.0. +1. **Group** : com.google.protobuf. **Name** : protobuf-java. **Version** : 4.36.2. * **Project URL:** [https://developers.google.com/protocol-buffers/](https://developers.google.com/protocol-buffers/) + * **License:** [https://opensource.org/licenses/BSD-3-Clause](https://opensource.org/licenses/BSD-3-Clause) * **License:** [BSD-3-Clause](https://opensource.org/licenses/BSD-3-Clause) -1. **Group** : com.google.protobuf. **Name** : protobuf-java-util. **Version** : 4.36.0. +1. **Group** : com.google.protobuf. **Name** : protobuf-java-util. **Version** : 4.36.2. * **Project URL:** [https://developers.google.com/protocol-buffers/](https://developers.google.com/protocol-buffers/) + * **License:** [https://opensource.org/licenses/BSD-3-Clause](https://opensource.org/licenses/BSD-3-Clause) * **License:** [BSD-3-Clause](https://opensource.org/licenses/BSD-3-Clause) -1. **Group** : com.google.protobuf. **Name** : protobuf-kotlin. **Version** : 4.36.0. +1. **Group** : com.google.protobuf. **Name** : protobuf-kotlin. **Version** : 4.36.2. * **Project URL:** [https://developers.google.com/protocol-buffers/](https://developers.google.com/protocol-buffers/) + * **License:** [https://opensource.org/licenses/BSD-3-Clause](https://opensource.org/licenses/BSD-3-Clause) * **License:** [BSD-3-Clause](https://opensource.org/licenses/BSD-3-Clause) 1. **Group** : org.jetbrains. **Name** : annotations. **Version** : 26.1.0. * **Project URL:** [https://github.com/JetBrains/java-annotations](https://github.com/JetBrains/java-annotations) * **License:** [The Apache Software License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) -1. **Group** : org.jetbrains.kotlin. **Name** : kotlin-bom. **Version** : 2.4.10. +1. **Group** : org.jetbrains.kotlin. **Name** : kotlin-bom. **Version** : 2.4.21. * **Project URL:** [https://kotlinlang.org/](https://kotlinlang.org/) * **License:** [The Apache Software License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) -1. **Group** : org.jetbrains.kotlin. **Name** : kotlin-reflect. **Version** : 2.4.10. +1. **Group** : org.jetbrains.kotlin. **Name** : kotlin-reflect. **Version** : 2.4.21. * **Project URL:** [https://kotlinlang.org/](https://kotlinlang.org/) * **License:** [Apache-2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) -1. **Group** : org.jetbrains.kotlin. **Name** : kotlin-stdlib. **Version** : 2.4.10. +1. **Group** : org.jetbrains.kotlin. **Name** : kotlin-stdlib. **Version** : 2.4.21. * **Project URL:** [https://kotlinlang.org/](https://kotlinlang.org/) * **License:** [Apache-2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) @@ -64,6 +70,7 @@ 1. **Group** : org.jspecify. **Name** : jspecify. **Version** : 1.0.1. * **Project URL:** [https://jspecify.dev/](https://jspecify.dev/) + * **License:** [https://www.apache.org/licenses/LICENSE-2.0](https://www.apache.org/licenses/LICENSE-2.0) * **License:** [The Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) ## Compile, tests, and tooling @@ -72,72 +79,85 @@ * **License:** [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) * **License:** [The Apache Software License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) -1. **Group** : com.fasterxml.jackson. **Name** : jackson-bom. **Version** : 2.22.2. +1. **Group** : com.fasterxml.jackson. **Name** : jackson-bom. **Version** : 2.22.3. * **Project URL:** [https://github.com/FasterXML/jackson-bom](https://github.com/FasterXML/jackson-bom) * **License:** [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) * **License:** [The Apache Software License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) 1. **Group** : com.fasterxml.jackson.core. **Name** : jackson-annotations. **Version** : 2.22. * **Project URL:** [https://github.com/FasterXML/jackson](https://github.com/FasterXML/jackson) + * **License:** [https://www.apache.org/licenses/LICENSE-2.0.txt](https://www.apache.org/licenses/LICENSE-2.0.txt) * **License:** [The Apache Software License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) 1. **Group** : com.fasterxml.jackson.core. **Name** : jackson-core. **Version** : 2.15.3. * **Project URL:** [https://github.com/FasterXML/jackson-core](https://github.com/FasterXML/jackson-core) + * **License:** [https://www.apache.org/licenses/LICENSE-2.0.txt](https://www.apache.org/licenses/LICENSE-2.0.txt) * **License:** [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) * **License:** [The Apache Software License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) -1. **Group** : com.fasterxml.jackson.core. **Name** : jackson-core. **Version** : 2.22.2. +1. **Group** : com.fasterxml.jackson.core. **Name** : jackson-core. **Version** : 2.22.3. * **Project URL:** [https://github.com/FasterXML/jackson-core](https://github.com/FasterXML/jackson-core) + * **License:** [https://www.apache.org/licenses/LICENSE-2.0.txt](https://www.apache.org/licenses/LICENSE-2.0.txt) * **License:** [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) * **License:** [The Apache Software License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) 1. **Group** : com.fasterxml.jackson.core. **Name** : jackson-databind. **Version** : 2.15.3. * **Project URL:** [https://github.com/FasterXML/jackson](https://github.com/FasterXML/jackson) + * **License:** [https://www.apache.org/licenses/LICENSE-2.0.txt](https://www.apache.org/licenses/LICENSE-2.0.txt) * **License:** [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) * **License:** [The Apache Software License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) -1. **Group** : com.fasterxml.jackson.core. **Name** : jackson-databind. **Version** : 2.22.2. +1. **Group** : com.fasterxml.jackson.core. **Name** : jackson-databind. **Version** : 2.22.3. * **Project URL:** [https://github.com/FasterXML/jackson](https://github.com/FasterXML/jackson) + * **License:** [https://www.apache.org/licenses/LICENSE-2.0.txt](https://www.apache.org/licenses/LICENSE-2.0.txt) * **License:** [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) * **License:** [The Apache Software License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) 1. **Group** : com.fasterxml.jackson.dataformat. **Name** : jackson-dataformat-xml. **Version** : 2.15.3. * **Project URL:** [https://github.com/FasterXML/jackson-dataformat-xml](https://github.com/FasterXML/jackson-dataformat-xml) + * **License:** [http://www.apache.org/licenses/LICENSE-2.0.txt](http://www.apache.org/licenses/LICENSE-2.0.txt) * **License:** [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) * **License:** [The Apache Software License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) -1. **Group** : com.fasterxml.jackson.dataformat. **Name** : jackson-dataformat-yaml. **Version** : 2.22.2. +1. **Group** : com.fasterxml.jackson.dataformat. **Name** : jackson-dataformat-yaml. **Version** : 2.22.3. * **Project URL:** [https://github.com/FasterXML/jackson-dataformats-text](https://github.com/FasterXML/jackson-dataformats-text) + * **License:** [https://www.apache.org/licenses/LICENSE-2.0.txt](https://www.apache.org/licenses/LICENSE-2.0.txt) * **License:** [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) * **License:** [The Apache Software License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) -1. **Group** : com.fasterxml.jackson.datatype. **Name** : jackson-datatype-guava. **Version** : 2.22.2. +1. **Group** : com.fasterxml.jackson.datatype. **Name** : jackson-datatype-guava. **Version** : 2.22.3. * **Project URL:** [https://github.com/FasterXML/jackson-datatypes-collections](https://github.com/FasterXML/jackson-datatypes-collections) + * **License:** [https://www.apache.org/licenses/LICENSE-2.0.txt](https://www.apache.org/licenses/LICENSE-2.0.txt) * **License:** [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) * **License:** [The Apache Software License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) -1. **Group** : com.fasterxml.jackson.datatype. **Name** : jackson-datatype-jdk8. **Version** : 2.22.2. +1. **Group** : com.fasterxml.jackson.datatype. **Name** : jackson-datatype-jdk8. **Version** : 2.22.3. * **Project URL:** [https://github.com/FasterXML/jackson-modules-java8/jackson-datatype-jdk8](https://github.com/FasterXML/jackson-modules-java8/jackson-datatype-jdk8) + * **License:** [http://www.apache.org/licenses/LICENSE-2.0.txt](http://www.apache.org/licenses/LICENSE-2.0.txt) * **License:** [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) * **License:** [The Apache Software License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) 1. **Group** : com.fasterxml.jackson.module. **Name** : jackson-module-kotlin. **Version** : 2.15.3. * **Project URL:** [https://github.com/FasterXML/jackson-module-kotlin](https://github.com/FasterXML/jackson-module-kotlin) + * **License:** [https://www.apache.org/licenses/LICENSE-2.0.txt](https://www.apache.org/licenses/LICENSE-2.0.txt) * **License:** [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) * **License:** [The Apache Software License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) -1. **Group** : com.fasterxml.jackson.module. **Name** : jackson-module-parameter-names. **Version** : 2.22.2. +1. **Group** : com.fasterxml.jackson.module. **Name** : jackson-module-parameter-names. **Version** : 2.22.3. * **Project URL:** [https://github.com/FasterXML/jackson-modules-java8/jackson-module-parameter-names](https://github.com/FasterXML/jackson-modules-java8/jackson-module-parameter-names) + * **License:** [http://www.apache.org/licenses/LICENSE-2.0.txt](http://www.apache.org/licenses/LICENSE-2.0.txt) * **License:** [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) * **License:** [The Apache Software License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) 1. **Group** : com.fasterxml.woodstox. **Name** : woodstox-core. **Version** : 6.5.1. * **Project URL:** [https://github.com/FasterXML/woodstox](https://github.com/FasterXML/woodstox) + * **License:** [http://www.apache.org/licenses/LICENSE-2.0.txt](http://www.apache.org/licenses/LICENSE-2.0.txt) * **License:** [The Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) * **License:** [The Apache Software License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) -1. **Group** : com.github.ben-manes.caffeine. **Name** : caffeine. **Version** : 3.2.4. +1. **Group** : com.github.ben-manes.caffeine. **Name** : caffeine. **Version** : 3.3.1. * **Project URL:** [https://github.com/ben-manes/caffeine](https://github.com/ben-manes/caffeine) + * **License:** [https://www.apache.org/licenses/LICENSE-2.0](https://www.apache.org/licenses/LICENSE-2.0) * **License:** [Apache License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) 1. **Group** : com.github.kevinstern. **Name** : software-and-algorithms. **Version** : 1.0. @@ -170,29 +190,26 @@ 1. **Group** : com.google.code.findbugs. **Name** : jsr305. **Version** : 3.0.2. * **Project URL:** [http://findbugs.sourceforge.net/](http://findbugs.sourceforge.net/) + * **License:** [http://www.apache.org/licenses/LICENSE-2.0.txt](http://www.apache.org/licenses/LICENSE-2.0.txt) * **License:** [The Apache Software License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) 1. **Group** : com.google.code.gson. **Name** : gson. **Version** : 2.14.0. * **Project URL:** [https://github.com/google/gson](https://github.com/google/gson) * **License:** [Apache-2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) -1. **Group** : com.google.code.gson. **Name** : gson. **Version** : 2.8.9. - * **Project URL:** [https://github.com/google/gson/gson](https://github.com/google/gson/gson) - * **License:** [Apache-2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) - -1. **Group** : com.google.devtools.ksp. **Name** : com.google.devtools.ksp.gradle.plugin. **Version** : 2.3.9. +1. **Group** : com.google.devtools.ksp. **Name** : com.google.devtools.ksp.gradle.plugin. **Version** : 2.3.11. * **Project URL:** [https://goo.gle/ksp](https://goo.gle/ksp) * **License:** [The Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) -1. **Group** : com.google.devtools.ksp. **Name** : symbol-processing-api. **Version** : 2.3.9. +1. **Group** : com.google.devtools.ksp. **Name** : symbol-processing-api. **Version** : 2.3.11. * **Project URL:** [https://goo.gle/ksp](https://goo.gle/ksp) * **License:** [The Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) -1. **Group** : com.google.devtools.ksp. **Name** : symbol-processing-common-deps. **Version** : 2.3.9. +1. **Group** : com.google.devtools.ksp. **Name** : symbol-processing-common-deps. **Version** : 2.3.11. * **Project URL:** [https://goo.gle/ksp](https://goo.gle/ksp) * **License:** [The Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) -1. **Group** : com.google.devtools.ksp. **Name** : symbol-processing-gradle-plugin. **Version** : 2.3.9. +1. **Group** : com.google.devtools.ksp. **Name** : symbol-processing-gradle-plugin. **Version** : 2.3.11. * **Project URL:** [https://goo.gle/ksp](https://goo.gle/ksp) * **License:** [The Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) @@ -204,10 +221,6 @@ * **Project URL:** [https://errorprone.info/error_prone_annotations](https://errorprone.info/error_prone_annotations) * **License:** [Apache 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) -1. **Group** : com.google.errorprone. **Name** : error_prone_annotations. **Version** : 2.50.0. - * **Project URL:** [https://errorprone.info/error_prone_annotations](https://errorprone.info/error_prone_annotations) - * **License:** [Apache 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) - 1. **Group** : com.google.errorprone. **Name** : error_prone_check_api. **Version** : 2.42.0. * **Project URL:** [https://errorprone.info/error_prone_check_api](https://errorprone.info/error_prone_check_api) * **License:** [Apache 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) @@ -219,11 +232,11 @@ 1. **Group** : com.google.errorprone. **Name** : error_prone_type_annotations. **Version** : 2.42.0. * **License:** [Apache 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) -1. **Group** : com.google.flogger. **Name** : flogger. **Version** : 0.7.4. +1. **Group** : com.google.flogger. **Name** : flogger. **Version** : 0.9. * **Project URL:** [https://github.com/google/flogger](https://github.com/google/flogger) * **License:** [Apache 2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) -1. **Group** : com.google.flogger. **Name** : flogger-system-backend. **Version** : 0.7.4. +1. **Group** : com.google.flogger. **Name** : flogger-system-backend. **Version** : 0.9. * **Project URL:** [https://github.com/google/flogger](https://github.com/google/flogger) * **License:** [Apache 2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) @@ -236,13 +249,15 @@ 1. **Group** : com.google.guava. **Name** : failureaccess. **Version** : 1.0.3. * **Project URL:** [https://github.com/google/guava/](https://github.com/google/guava/) + * **License:** [http://www.apache.org/licenses/LICENSE-2.0.txt](http://www.apache.org/licenses/LICENSE-2.0.txt) * **License:** [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) -1. **Group** : com.google.guava. **Name** : guava. **Version** : 33.7.1-jre. +1. **Group** : com.google.guava. **Name** : guava. **Version** : 33.7.2-jre. * **Project URL:** [https://github.com/google/guava](https://github.com/google/guava) + * **License:** [http://www.apache.org/licenses/LICENSE-2.0.txt](http://www.apache.org/licenses/LICENSE-2.0.txt) * **License:** [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) -1. **Group** : com.google.guava. **Name** : guava-testlib. **Version** : 33.7.1-jre. +1. **Group** : com.google.guava. **Name** : guava-testlib. **Version** : 33.7.2-jre. * **License:** [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) 1. **Group** : com.google.guava. **Name** : listenablefuture. **Version** : 9999.0-empty-to-avoid-conflict-with-guava. @@ -256,19 +271,22 @@ * **Project URL:** [https://github.com/google/protobuf-gradle-plugin](https://github.com/google/protobuf-gradle-plugin) * **License:** [BSD 3-Clause](http://opensource.org/licenses/BSD-3-Clause) -1. **Group** : com.google.protobuf. **Name** : protobuf-java. **Version** : 4.36.0. +1. **Group** : com.google.protobuf. **Name** : protobuf-java. **Version** : 4.36.2. * **Project URL:** [https://developers.google.com/protocol-buffers/](https://developers.google.com/protocol-buffers/) + * **License:** [https://opensource.org/licenses/BSD-3-Clause](https://opensource.org/licenses/BSD-3-Clause) * **License:** [BSD-3-Clause](https://opensource.org/licenses/BSD-3-Clause) -1. **Group** : com.google.protobuf. **Name** : protobuf-java-util. **Version** : 4.36.0. +1. **Group** : com.google.protobuf. **Name** : protobuf-java-util. **Version** : 4.36.2. * **Project URL:** [https://developers.google.com/protocol-buffers/](https://developers.google.com/protocol-buffers/) + * **License:** [https://opensource.org/licenses/BSD-3-Clause](https://opensource.org/licenses/BSD-3-Clause) * **License:** [BSD-3-Clause](https://opensource.org/licenses/BSD-3-Clause) -1. **Group** : com.google.protobuf. **Name** : protobuf-kotlin. **Version** : 4.36.0. +1. **Group** : com.google.protobuf. **Name** : protobuf-kotlin. **Version** : 4.36.2. * **Project URL:** [https://developers.google.com/protocol-buffers/](https://developers.google.com/protocol-buffers/) + * **License:** [https://opensource.org/licenses/BSD-3-Clause](https://opensource.org/licenses/BSD-3-Clause) * **License:** [BSD-3-Clause](https://opensource.org/licenses/BSD-3-Clause) -1. **Group** : com.google.protobuf. **Name** : protoc. **Version** : 4.36.0. +1. **Group** : com.google.protobuf. **Name** : protoc. **Version** : 4.36.2. * **Project URL:** [https://developers.google.com/protocol-buffers/](https://developers.google.com/protocol-buffers/) * **License:** [BSD-3-Clause](https://opensource.org/licenses/BSD-3-Clause) * **License:** [The Apache Software License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) @@ -293,9 +311,9 @@ * **Project URL:** [https://github.com/palantir/palantir-java-format](https://github.com/palantir/palantir-java-format) * **License:** [The Apache License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0) -1. **Group** : com.puppycrawl.tools. **Name** : checkstyle. **Version** : 10.12.1. +1. **Group** : com.puppycrawl.tools. **Name** : checkstyle. **Version** : 12.3.1. * **Project URL:** [https://checkstyle.org/](https://checkstyle.org/) - * **License:** [LGPL-2.1+](http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt) + * **License:** [LGPL-2.1-or-later](https://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt) 1. **Group** : com.sksamuel.aedile. **Name** : aedile-core. **Version** : 3.0.4. * **Project URL:** [https://www.github.com/sksamuel/aedile](https://www.github.com/sksamuel/aedile) @@ -305,11 +323,11 @@ * **Project URL:** [https://github.com/korlibs/korge-next](https://github.com/korlibs/korge-next) * **License:** [MIT](https://raw.githubusercontent.com/korlibs/korge-next/master/korge/LICENSE.txt) -1. **Group** : com.squareup. **Name** : kotlinpoet. **Version** : 2.3.0. +1. **Group** : com.squareup. **Name** : kotlinpoet. **Version** : 2.4.0. * **Project URL:** [https://github.com/square/kotlinpoet](https://github.com/square/kotlinpoet) * **License:** [The Apache Software License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) -1. **Group** : com.squareup. **Name** : kotlinpoet-jvm. **Version** : 2.3.0. +1. **Group** : com.squareup. **Name** : kotlinpoet-jvm. **Version** : 2.4.0. * **Project URL:** [https://github.com/square/kotlinpoet](https://github.com/square/kotlinpoet) * **License:** [The Apache Software License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) @@ -317,16 +335,14 @@ * **Project URL:** [https://github.com/square/kotlinpoet](https://github.com/square/kotlinpoet) * **License:** [The Apache Software License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) -1. **Group** : commons-beanutils. **Name** : commons-beanutils. **Version** : 1.9.4. - * **Project URL:** [https://commons.apache.org/proper/commons-beanutils/](https://commons.apache.org/proper/commons-beanutils/) - * **License:** [Apache License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) - -1. **Group** : commons-codec. **Name** : commons-codec. **Version** : 1.22.1. - * **Project URL:** [https://commons.apache.org/proper/commons-codec/](https://commons.apache.org/proper/commons-codec/) +1. **Group** : commons-beanutils. **Name** : commons-beanutils. **Version** : 1.11.0. + * **Project URL:** [https://commons.apache.org/proper/commons-beanutils](https://commons.apache.org/proper/commons-beanutils) + * **License:** [https://www.apache.org/licenses/LICENSE-2.0.txt](https://www.apache.org/licenses/LICENSE-2.0.txt) * **License:** [Apache-2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) 1. **Group** : commons-collections. **Name** : commons-collections. **Version** : 3.2.2. * **Project URL:** [http://commons.apache.org/collections/](http://commons.apache.org/collections/) + * **License:** [http://www.apache.org/licenses/LICENSE-2.0.txt](http://www.apache.org/licenses/LICENSE-2.0.txt) * **License:** [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) 1. **Group** : dev.drewhamilton.poko. **Name** : poko-annotations. **Version** : 0.17.1. @@ -341,7 +357,7 @@ * **Project URL:** [https://github.com/ZacSweers/auto-service-ksp](https://github.com/ZacSweers/auto-service-ksp) * **License:** [The Apache Software License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) -1. **Group** : info.picocli. **Name** : picocli. **Version** : 4.7.4. +1. **Group** : info.picocli. **Name** : picocli. **Version** : 4.7.7. * **Project URL:** [https://picocli.info](https://picocli.info) * **License:** [The Apache Software License, version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) @@ -359,9 +375,11 @@ 1. **Group** : io.github.eisop. **Name** : dataflow-errorprone. **Version** : 3.41.0-eisop1. * **Project URL:** [https://eisop.github.io/](https://eisop.github.io/) + * **License:** (GPL-2.0-only WITH Classpath-exception-2.0) * **License:** [GNU General Public License, version 2 (GPL2), with the classpath exception](http://www.gnu.org/software/classpath/license.html) 1. **Group** : io.github.java-diff-utils. **Name** : java-diff-utils. **Version** : 4.17. + * **License:** [http://www.apache.org/licenses/LICENSE-2.0.txt](http://www.apache.org/licenses/LICENSE-2.0.txt) * **License:** [The Apache Software License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) 1. **Group** : io.gitlab.arturbosch.detekt. **Name** : detekt-api. **Version** : 1.23.8. @@ -456,23 +474,23 @@ * **Project URL:** [https://detekt.dev](https://detekt.dev) * **License:** [The Apache Software License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) -1. **Group** : io.grpc. **Name** : grpc-api. **Version** : 1.83.1. +1. **Group** : io.grpc. **Name** : grpc-api. **Version** : 1.85.0. * **Project URL:** [https://github.com/grpc/grpc-java](https://github.com/grpc/grpc-java) * **License:** [Apache 2.0](https://opensource.org/licenses/Apache-2.0) -1. **Group** : io.grpc. **Name** : grpc-bom. **Version** : 1.83.1. +1. **Group** : io.grpc. **Name** : grpc-bom. **Version** : 1.85.0. * **Project URL:** [https://github.com/grpc/grpc-java](https://github.com/grpc/grpc-java) * **License:** [Apache 2.0](https://opensource.org/licenses/Apache-2.0) -1. **Group** : io.grpc. **Name** : grpc-context. **Version** : 1.83.1. +1. **Group** : io.grpc. **Name** : grpc-context. **Version** : 1.85.0. * **Project URL:** [https://github.com/grpc/grpc-java](https://github.com/grpc/grpc-java) * **License:** [Apache 2.0](https://opensource.org/licenses/Apache-2.0) -1. **Group** : io.grpc. **Name** : grpc-core. **Version** : 1.83.1. +1. **Group** : io.grpc. **Name** : grpc-core. **Version** : 1.85.0. * **Project URL:** [https://github.com/grpc/grpc-java](https://github.com/grpc/grpc-java) * **License:** [Apache 2.0](https://opensource.org/licenses/Apache-2.0) -1. **Group** : io.grpc. **Name** : grpc-inprocess. **Version** : 1.83.1. +1. **Group** : io.grpc. **Name** : grpc-inprocess. **Version** : 1.85.0. * **Project URL:** [https://github.com/grpc/grpc-java](https://github.com/grpc/grpc-java) * **License:** [Apache 2.0](https://opensource.org/licenses/Apache-2.0) @@ -480,39 +498,39 @@ * **Project URL:** [https://github.com/grpc/grpc-kotlin](https://github.com/grpc/grpc-kotlin) * **License:** [Apache 2.0](https://opensource.org/licenses/Apache-2.0) -1. **Group** : io.grpc. **Name** : grpc-protobuf. **Version** : 1.83.1. +1. **Group** : io.grpc. **Name** : grpc-protobuf. **Version** : 1.85.0. * **Project URL:** [https://github.com/grpc/grpc-java](https://github.com/grpc/grpc-java) * **License:** [Apache 2.0](https://opensource.org/licenses/Apache-2.0) -1. **Group** : io.grpc. **Name** : grpc-protobuf-lite. **Version** : 1.83.1. +1. **Group** : io.grpc. **Name** : grpc-protobuf-lite. **Version** : 1.85.0. * **Project URL:** [https://github.com/grpc/grpc-java](https://github.com/grpc/grpc-java) * **License:** [Apache 2.0](https://opensource.org/licenses/Apache-2.0) -1. **Group** : io.grpc. **Name** : grpc-stub. **Version** : 1.83.1. +1. **Group** : io.grpc. **Name** : grpc-stub. **Version** : 1.85.0. * **Project URL:** [https://github.com/grpc/grpc-java](https://github.com/grpc/grpc-java) * **License:** [Apache 2.0](https://opensource.org/licenses/Apache-2.0) -1. **Group** : io.kotest. **Name** : kotest-assertions-core. **Version** : 6.2.4. +1. **Group** : io.kotest. **Name** : kotest-assertions-core. **Version** : 6.2.5. * **Project URL:** [https://github.com/kotest/kotest](https://github.com/kotest/kotest) * **License:** [Apache-2.0](https://opensource.org/licenses/Apache-2.0) -1. **Group** : io.kotest. **Name** : kotest-assertions-core-jvm. **Version** : 6.2.4. +1. **Group** : io.kotest. **Name** : kotest-assertions-core-jvm. **Version** : 6.2.5. * **Project URL:** [https://github.com/kotest/kotest](https://github.com/kotest/kotest) * **License:** [Apache-2.0](https://opensource.org/licenses/Apache-2.0) -1. **Group** : io.kotest. **Name** : kotest-assertions-shared. **Version** : 6.2.4. +1. **Group** : io.kotest. **Name** : kotest-assertions-shared. **Version** : 6.2.5. * **Project URL:** [https://github.com/kotest/kotest](https://github.com/kotest/kotest) * **License:** [Apache-2.0](https://opensource.org/licenses/Apache-2.0) -1. **Group** : io.kotest. **Name** : kotest-assertions-shared-jvm. **Version** : 6.2.4. +1. **Group** : io.kotest. **Name** : kotest-assertions-shared-jvm. **Version** : 6.2.5. * **Project URL:** [https://github.com/kotest/kotest](https://github.com/kotest/kotest) * **License:** [Apache-2.0](https://opensource.org/licenses/Apache-2.0) -1. **Group** : io.kotest. **Name** : kotest-common. **Version** : 6.2.4. +1. **Group** : io.kotest. **Name** : kotest-common. **Version** : 6.2.5. * **Project URL:** [https://github.com/kotest/kotest](https://github.com/kotest/kotest) * **License:** [Apache-2.0](https://opensource.org/licenses/Apache-2.0) -1. **Group** : io.kotest. **Name** : kotest-common-jvm. **Version** : 6.2.4. +1. **Group** : io.kotest. **Name** : kotest-common-jvm. **Version** : 6.2.5. * **Project URL:** [https://github.com/kotest/kotest](https://github.com/kotest/kotest) * **License:** [Apache-2.0](https://opensource.org/licenses/Apache-2.0) @@ -522,6 +540,7 @@ 1. **Group** : javax.annotation. **Name** : javax.annotation-api. **Version** : 1.3.2. * **Project URL:** [http://jcp.org/en/jsr/detail?id=250](http://jcp.org/en/jsr/detail?id=250) + * **License:** [https://github.com/javaee/javax.annotation/blob/master/LICENSE](https://github.com/javaee/javax.annotation/blob/master/LICENSE) * **License:** [CDDL + GPLv2 with classpath exception](https://github.com/javaee/javax.annotation/blob/master/LICENSE) 1. **Group** : javax.inject. **Name** : javax.inject. **Version** : 1. @@ -540,64 +559,51 @@ * **Project URL:** [http://www.saxonica.com/](http://www.saxonica.com/) * **License:** [Mozilla Public License Version 2.0](http://www.mozilla.org/MPL/2.0/) -1. **Group** : net.sf.saxon. **Name** : Saxon-HE. **Version** : 12.2. +1. **Group** : net.sf.saxon. **Name** : Saxon-HE. **Version** : 12.9. * **Project URL:** [http://www.saxonica.com/](http://www.saxonica.com/) * **License:** [Mozilla Public License Version 2.0](http://www.mozilla.org/MPL/2.0/) -1. **Group** : net.sourceforge.pmd. **Name** : pmd-ant. **Version** : 7.27.0. +1. **Group** : net.sourceforge.pmd. **Name** : pmd-ant. **Version** : 7.28.0. * **License:** [BSD-style](http://pmd.sourceforge.net/license.html) -1. **Group** : net.sourceforge.pmd. **Name** : pmd-core. **Version** : 7.27.0. +1. **Group** : net.sourceforge.pmd. **Name** : pmd-core. **Version** : 7.28.0. * **License:** [BSD-style](http://pmd.sourceforge.net/license.html) -1. **Group** : net.sourceforge.pmd. **Name** : pmd-java. **Version** : 7.27.0. +1. **Group** : net.sourceforge.pmd. **Name** : pmd-java. **Version** : 7.28.0. * **License:** [BSD-style](http://pmd.sourceforge.net/license.html) -1. **Group** : org.antlr. **Name** : antlr4-runtime. **Version** : 4.11.1. - * **Project URL:** [https://www.antlr.org/](https://www.antlr.org/) - * **License:** [BSD-3-Clause](https://www.antlr.org/license.html) - 1. **Group** : org.antlr. **Name** : antlr4-runtime. **Version** : 4.13.2. * **Project URL:** [https://www.antlr.org/](https://www.antlr.org/) + * **License:** [https://www.antlr.org/license.html](https://www.antlr.org/license.html) * **License:** [BSD-3-Clause](https://www.antlr.org/license.html) 1. **Group** : org.apache.commons. **Name** : commons-lang3. **Version** : 3.20.0. * **Project URL:** [https://commons.apache.org/proper/commons-lang/](https://commons.apache.org/proper/commons-lang/) + * **License:** [https://www.apache.org/licenses/LICENSE-2.0.txt](https://www.apache.org/licenses/LICENSE-2.0.txt) * **License:** [Apache-2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) -1. **Group** : org.apache.httpcomponents.client5. **Name** : httpclient5. **Version** : 5.1.3. - * **License:** [Apache License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) - -1. **Group** : org.apache.httpcomponents.core5. **Name** : httpcore5. **Version** : 5.1.3. - * **License:** [Apache License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) - -1. **Group** : org.apache.httpcomponents.core5. **Name** : httpcore5-h2. **Version** : 5.1.3. - * **License:** [Apache License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) - 1. **Group** : org.apiguardian. **Name** : apiguardian-api. **Version** : 1.1.2. * **Project URL:** [https://github.com/apiguardian-team/apiguardian](https://github.com/apiguardian-team/apiguardian) * **License:** [The Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) -1. **Group** : org.checkerframework. **Name** : checker-compat-qual. **Version** : 2.5.3. - * **Project URL:** [https://checkerframework.org](https://checkerframework.org) - * **License:** [GNU General Public License, version 2 (GPL2), with the classpath exception](http://www.gnu.org/software/classpath/license.html) - * **License:** [The MIT License](http://opensource.org/licenses/MIT) - -1. **Group** : org.checkerframework. **Name** : checker-qual. **Version** : 4.2.2. +1. **Group** : org.checkerframework. **Name** : checker-qual. **Version** : 4.3.1. * **Project URL:** [https://checkerframework.org/](https://checkerframework.org/) + * **License:** MIT * **License:** [The MIT License](https://opensource.org/licenses/MIT) -1. **Group** : org.codehaus.mojo. **Name** : animal-sniffer-annotations. **Version** : 1.27. +1. **Group** : org.codehaus.mojo. **Name** : animal-sniffer-annotations. **Version** : 1.28. * **License:** [Apache-2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) * **License:** [MIT license](https://spdx.org/licenses/MIT.txt) 1. **Group** : org.codehaus.woodstox. **Name** : stax2-api. **Version** : 4.2.1. * **Project URL:** [http://github.com/FasterXML/stax2-api](http://github.com/FasterXML/stax2-api) + * **License:** [http://www.opensource.org/licenses/bsd-license.php](http://www.opensource.org/licenses/bsd-license.php) * **License:** [The Apache Software License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) * **License:** [The BSD License](http://www.opensource.org/licenses/bsd-license.php) 1. **Group** : org.freemarker. **Name** : freemarker. **Version** : 2.3.32. * **Project URL:** [https://freemarker.apache.org/](https://freemarker.apache.org/) + * **License:** Apache License, Version 2.0; see: http://www.apache.org/licenses/LICENSE-2.0.txt * **License:** [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) 1. **Group** : org.functionaljava. **Name** : functionaljava. **Version** : 5.0. @@ -606,6 +612,7 @@ 1. **Group** : org.hamcrest. **Name** : hamcrest. **Version** : 3.0. * **Project URL:** [http://hamcrest.org/JavaHamcrest/](http://hamcrest.org/JavaHamcrest/) + * **License:** BSD-3-Clause * **License:** [BSD-3-Clause](https://raw.githubusercontent.com/hamcrest/JavaHamcrest/master/LICENSE) 1. **Group** : org.hamcrest. **Name** : hamcrest-core. **Version** : 3.0. @@ -613,22 +620,27 @@ * **License:** [BSD-3-Clause](https://raw.githubusercontent.com/hamcrest/JavaHamcrest/master/LICENSE) 1. **Group** : org.jacoco. **Name** : org.jacoco.agent. **Version** : 0.8.15. + * **License:** [https://www.eclipse.org/legal/epl-2.0/](https://www.eclipse.org/legal/epl-2.0/) * **License:** [EPL-2.0](https://www.eclipse.org/legal/epl-2.0/) 1. **Group** : org.jacoco. **Name** : org.jacoco.core. **Version** : 0.8.15. + * **License:** [https://www.eclipse.org/legal/epl-2.0/](https://www.eclipse.org/legal/epl-2.0/) * **License:** [EPL-2.0](https://www.eclipse.org/legal/epl-2.0/) 1. **Group** : org.jacoco. **Name** : org.jacoco.report. **Version** : 0.8.15. + * **License:** [https://www.eclipse.org/legal/epl-2.0/](https://www.eclipse.org/legal/epl-2.0/) * **License:** [EPL-2.0](https://www.eclipse.org/legal/epl-2.0/) 1. **Group** : org.javassist. **Name** : javassist. **Version** : 3.28.0-GA. * **Project URL:** [http://www.javassist.org/](http://www.javassist.org/) + * **License:** [http://www.mozilla.org/MPL/MPL-1.1.html](http://www.mozilla.org/MPL/MPL-1.1.html) * **License:** [Apache License 2.0](http://www.apache.org/licenses/) * **License:** [LGPL 2.1](http://www.gnu.org/licenses/lgpl-2.1.html) * **License:** [MPL 1.1](http://www.mozilla.org/MPL/MPL-1.1.html) 1. **Group** : org.jcommander. **Name** : jcommander. **Version** : 1.85. * **Project URL:** [https://jcommander.org](https://jcommander.org) + * **License:** [http://www.apache.org/licenses/LICENSE-2.0.txt](http://www.apache.org/licenses/LICENSE-2.0.txt) * **License:** [Apache License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) 1. **Group** : org.jetbrains. **Name** : annotations. **Version** : 23.0.0. @@ -679,7 +691,7 @@ * **Project URL:** [https://github.com/JetBrains/intellij-deps-trove4j](https://github.com/JetBrains/intellij-deps-trove4j) * **License:** [GNU LESSER GENERAL PUBLIC LICENSE 2.1](https://www.gnu.org/licenses/old-licenses/lgpl-2.1.en.html) -1. **Group** : org.jetbrains.kotlin. **Name** : kotlin-bom. **Version** : 2.4.10. +1. **Group** : org.jetbrains.kotlin. **Name** : kotlin-bom. **Version** : 2.4.21. * **Project URL:** [https://kotlinlang.org/](https://kotlinlang.org/) * **License:** [The Apache Software License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) @@ -687,11 +699,11 @@ * **Project URL:** [https://kotlinlang.org/](https://kotlinlang.org/) * **License:** [Apache-2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) -1. **Group** : org.jetbrains.kotlin. **Name** : kotlin-build-tools-api. **Version** : 2.4.10. +1. **Group** : org.jetbrains.kotlin. **Name** : kotlin-build-tools-api. **Version** : 2.4.21. * **Project URL:** [https://kotlinlang.org/](https://kotlinlang.org/) * **License:** [Apache-2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) -1. **Group** : org.jetbrains.kotlin. **Name** : kotlin-build-tools-compat. **Version** : 2.4.10. +1. **Group** : org.jetbrains.kotlin. **Name** : kotlin-build-tools-compat. **Version** : 2.4.21. * **Project URL:** [https://kotlinlang.org/](https://kotlinlang.org/) * **License:** [Apache-2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) @@ -699,7 +711,7 @@ * **Project URL:** [https://kotlinlang.org/](https://kotlinlang.org/) * **License:** [Apache-2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) -1. **Group** : org.jetbrains.kotlin. **Name** : kotlin-build-tools-cri-impl. **Version** : 2.4.10. +1. **Group** : org.jetbrains.kotlin. **Name** : kotlin-build-tools-cri-impl. **Version** : 2.4.21. * **Project URL:** [https://kotlinlang.org/](https://kotlinlang.org/) * **License:** [Apache-2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) @@ -707,7 +719,7 @@ * **Project URL:** [https://kotlinlang.org/](https://kotlinlang.org/) * **License:** [Apache-2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) -1. **Group** : org.jetbrains.kotlin. **Name** : kotlin-build-tools-impl. **Version** : 2.4.10. +1. **Group** : org.jetbrains.kotlin. **Name** : kotlin-build-tools-impl. **Version** : 2.4.21. * **Project URL:** [https://kotlinlang.org/](https://kotlinlang.org/) * **License:** [Apache-2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) @@ -719,7 +731,7 @@ * **Project URL:** [https://kotlinlang.org/](https://kotlinlang.org/) * **License:** [Apache-2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) -1. **Group** : org.jetbrains.kotlin. **Name** : kotlin-compiler-embeddable. **Version** : 2.4.10. +1. **Group** : org.jetbrains.kotlin. **Name** : kotlin-compiler-embeddable. **Version** : 2.4.21. * **Project URL:** [https://kotlinlang.org/](https://kotlinlang.org/) * **License:** [Apache-2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) @@ -727,7 +739,7 @@ * **Project URL:** [https://kotlinlang.org/](https://kotlinlang.org/) * **License:** [Apache-2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) -1. **Group** : org.jetbrains.kotlin. **Name** : kotlin-compiler-runner. **Version** : 2.4.10. +1. **Group** : org.jetbrains.kotlin. **Name** : kotlin-compiler-runner. **Version** : 2.4.21. * **Project URL:** [https://kotlinlang.org/](https://kotlinlang.org/) * **License:** [Apache-2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) @@ -735,7 +747,7 @@ * **Project URL:** [https://kotlinlang.org/](https://kotlinlang.org/) * **License:** [Apache-2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) -1. **Group** : org.jetbrains.kotlin. **Name** : kotlin-daemon-client. **Version** : 2.4.10. +1. **Group** : org.jetbrains.kotlin. **Name** : kotlin-daemon-client. **Version** : 2.4.21. * **Project URL:** [https://kotlinlang.org/](https://kotlinlang.org/) * **License:** [Apache-2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) @@ -747,15 +759,15 @@ * **Project URL:** [https://kotlinlang.org/](https://kotlinlang.org/) * **License:** [Apache-2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) -1. **Group** : org.jetbrains.kotlin. **Name** : kotlin-daemon-embeddable. **Version** : 2.4.10. +1. **Group** : org.jetbrains.kotlin. **Name** : kotlin-daemon-embeddable. **Version** : 2.4.21. * **Project URL:** [https://kotlinlang.org/](https://kotlinlang.org/) * **License:** [Apache-2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) -1. **Group** : org.jetbrains.kotlin. **Name** : kotlin-klib-commonizer-embeddable. **Version** : 2.4.10. +1. **Group** : org.jetbrains.kotlin. **Name** : kotlin-klib-commonizer-embeddable. **Version** : 2.4.21. * **Project URL:** [https://kotlinlang.org/](https://kotlinlang.org/) * **License:** [Apache-2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) -1. **Group** : org.jetbrains.kotlin. **Name** : kotlin-reflect. **Version** : 2.4.10. +1. **Group** : org.jetbrains.kotlin. **Name** : kotlin-reflect. **Version** : 2.4.21. * **Project URL:** [https://kotlinlang.org/](https://kotlinlang.org/) * **License:** [Apache-2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) @@ -767,43 +779,43 @@ * **Project URL:** [https://kotlinlang.org/](https://kotlinlang.org/) * **License:** [Apache-2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) -1. **Group** : org.jetbrains.kotlin. **Name** : kotlin-script-runtime. **Version** : 2.4.10. +1. **Group** : org.jetbrains.kotlin. **Name** : kotlin-script-runtime. **Version** : 2.4.21. * **Project URL:** [https://kotlinlang.org/](https://kotlinlang.org/) * **License:** [Apache-2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) -1. **Group** : org.jetbrains.kotlin. **Name** : kotlin-scripting-common. **Version** : 2.4.10. +1. **Group** : org.jetbrains.kotlin. **Name** : kotlin-scripting-common. **Version** : 2.4.21. * **Project URL:** [https://kotlinlang.org/](https://kotlinlang.org/) * **License:** [Apache-2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) -1. **Group** : org.jetbrains.kotlin. **Name** : kotlin-scripting-compiler-embeddable. **Version** : 2.4.10. +1. **Group** : org.jetbrains.kotlin. **Name** : kotlin-scripting-compiler-embeddable. **Version** : 2.4.21. * **Project URL:** [https://kotlinlang.org/](https://kotlinlang.org/) * **License:** [Apache-2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) -1. **Group** : org.jetbrains.kotlin. **Name** : kotlin-scripting-compiler-impl-embeddable. **Version** : 2.4.10. +1. **Group** : org.jetbrains.kotlin. **Name** : kotlin-scripting-compiler-impl-embeddable. **Version** : 2.4.21. * **Project URL:** [https://kotlinlang.org/](https://kotlinlang.org/) * **License:** [Apache-2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) -1. **Group** : org.jetbrains.kotlin. **Name** : kotlin-scripting-jvm. **Version** : 2.4.10. +1. **Group** : org.jetbrains.kotlin. **Name** : kotlin-scripting-jvm. **Version** : 2.4.21. * **Project URL:** [https://kotlinlang.org/](https://kotlinlang.org/) * **License:** [Apache-2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) -1. **Group** : org.jetbrains.kotlin. **Name** : kotlin-stdlib. **Version** : 2.4.10. +1. **Group** : org.jetbrains.kotlin. **Name** : kotlin-stdlib. **Version** : 2.4.21. * **Project URL:** [https://kotlinlang.org/](https://kotlinlang.org/) * **License:** [Apache-2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) -1. **Group** : org.jetbrains.kotlin. **Name** : kotlin-stdlib-common. **Version** : 2.4.10. +1. **Group** : org.jetbrains.kotlin. **Name** : kotlin-stdlib-common. **Version** : 2.4.21. * **Project URL:** [https://kotlinlang.org/](https://kotlinlang.org/) * **License:** [Apache-2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) -1. **Group** : org.jetbrains.kotlin. **Name** : kotlin-stdlib-jdk7. **Version** : 2.4.10. +1. **Group** : org.jetbrains.kotlin. **Name** : kotlin-stdlib-jdk7. **Version** : 2.4.21. * **Project URL:** [https://kotlinlang.org/](https://kotlinlang.org/) * **License:** [Apache-2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) -1. **Group** : org.jetbrains.kotlin. **Name** : kotlin-stdlib-jdk8. **Version** : 2.4.10. +1. **Group** : org.jetbrains.kotlin. **Name** : kotlin-stdlib-jdk8. **Version** : 2.4.21. * **Project URL:** [https://kotlinlang.org/](https://kotlinlang.org/) * **License:** [Apache-2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) -1. **Group** : org.jetbrains.kotlin. **Name** : kotlin-tooling-core. **Version** : 2.4.10. +1. **Group** : org.jetbrains.kotlin. **Name** : kotlin-tooling-core. **Version** : 2.4.21. * **Project URL:** [https://kotlinlang.org/](https://kotlinlang.org/) * **License:** [Apache-2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) @@ -873,10 +885,12 @@ 1. **Group** : org.jsoup. **Name** : jsoup. **Version** : 1.16.1. * **Project URL:** [https://jsoup.org/](https://jsoup.org/) + * **License:** [https://jsoup.org/license](https://jsoup.org/license) * **License:** [The MIT License](https://jsoup.org/license) 1. **Group** : org.jspecify. **Name** : jspecify. **Version** : 1.0.1. * **Project URL:** [https://jspecify.dev/](https://jspecify.dev/) + * **License:** [https://www.apache.org/licenses/LICENSE-2.0](https://www.apache.org/licenses/LICENSE-2.0) * **License:** [The Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) 1. **Group** : org.junit. **Name** : junit-bom. **Version** : 6.1.3. @@ -913,20 +927,24 @@ 1. **Group** : org.opentest4j. **Name** : opentest4j. **Version** : 1.3.0. * **Project URL:** [https://github.com/ota4j-team/opentest4j](https://github.com/ota4j-team/opentest4j) + * **License:** The Apache License, Version 2.0 * **License:** [The Apache License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) -1. **Group** : org.ow2.asm. **Name** : asm. **Version** : 9.10.1. +1. **Group** : org.ow2.asm. **Name** : asm. **Version** : 9.11. * **Project URL:** [http://asm.ow2.io/](http://asm.ow2.io/) + * **License:** [BSD-3-Clause](https://asm.ow2.io/LICENSE.txt) * **License:** [BSD-3-Clause](https://asm.ow2.io/license.html) * **License:** [The Apache Software License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) -1. **Group** : org.ow2.asm. **Name** : asm-commons. **Version** : 9.10.1. +1. **Group** : org.ow2.asm. **Name** : asm-commons. **Version** : 9.11. * **Project URL:** [http://asm.ow2.io/](http://asm.ow2.io/) + * **License:** [BSD-3-Clause](https://asm.ow2.io/LICENSE.txt) * **License:** [BSD-3-Clause](https://asm.ow2.io/license.html) * **License:** [The Apache Software License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) -1. **Group** : org.ow2.asm. **Name** : asm-tree. **Version** : 9.10.1. +1. **Group** : org.ow2.asm. **Name** : asm-tree. **Version** : 9.11. * **Project URL:** [http://asm.ow2.io/](http://asm.ow2.io/) + * **License:** [BSD-3-Clause](https://asm.ow2.io/LICENSE.txt) * **License:** [BSD-3-Clause](https://asm.ow2.io/license.html) * **License:** [The Apache Software License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) @@ -940,6 +958,7 @@ 1. **Group** : org.reflections. **Name** : reflections. **Version** : 0.10.2. * **Project URL:** [http://github.com/ronmamo/reflections](http://github.com/ronmamo/reflections) + * **License:** [http://www.wtfpl.net/](http://www.wtfpl.net/) * **License:** [The Apache Software License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) * **License:** [WTFPL](http://www.wtfpl.net/) @@ -947,59 +966,68 @@ * **Project URL:** [http://www.slf4j.org](http://www.slf4j.org) * **License:** [MIT License](http://www.opensource.org/licenses/mit-license.php) +1. **Group** : org.slf4j. **Name** : slf4j-simple. **Version** : 2.0.17. + * **Project URL:** [http://www.slf4j.org](http://www.slf4j.org) + * **License:** [https://opensource.org/license/mit](https://opensource.org/license/mit) + * **License:** [MIT](https://opensource.org/license/mit) + 1. **Group** : org.snakeyaml. **Name** : snakeyaml-engine. **Version** : 2.7. * **Project URL:** [https://bitbucket.org/snakeyaml/snakeyaml-engine](https://bitbucket.org/snakeyaml/snakeyaml-engine) + * **License:** [http://www.apache.org/licenses/LICENSE-2.0.txt](http://www.apache.org/licenses/LICENSE-2.0.txt) * **License:** [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) 1. **Group** : org.snakeyaml. **Name** : snakeyaml-engine. **Version** : 3.0.1. * **Project URL:** [https://bitbucket.org/snakeyaml/snakeyaml-engine](https://bitbucket.org/snakeyaml/snakeyaml-engine) + * **License:** [http://www.apache.org/licenses/LICENSE-2.0.txt](http://www.apache.org/licenses/LICENSE-2.0.txt) * **License:** [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) -1. **Group** : org.xmlresolver. **Name** : xmlresolver. **Version** : 5.1.2. - * **Project URL:** [https://github.com/xmlresolver/xmlresolver](https://github.com/xmlresolver/xmlresolver) - * **License:** [Apache License version 2.0](https://www.apache.org/licenses/LICENSE-2.0) - 1. **Group** : org.xmlresolver. **Name** : xmlresolver. **Version** : 5.3.3. * **Project URL:** [https://github.com/xmlresolver/xmlresolver](https://github.com/xmlresolver/xmlresolver) * **License:** [Apache License version 2.0](https://www.apache.org/licenses/LICENSE-2.0) 1. **Group** : org.yaml. **Name** : snakeyaml. **Version** : 2.5. * **Project URL:** [https://bitbucket.org/snakeyaml/snakeyaml](https://bitbucket.org/snakeyaml/snakeyaml) + * **License:** [http://www.apache.org/licenses/LICENSE-2.0.txt](http://www.apache.org/licenses/LICENSE-2.0.txt) * **License:** [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) -1. **Group** : tools.jackson. **Name** : jackson-bom. **Version** : 3.2.2. +1. **Group** : tools.jackson. **Name** : jackson-bom. **Version** : 3.2.3. * **Project URL:** [https://github.com/FasterXML/jackson-bom](https://github.com/FasterXML/jackson-bom) * **License:** [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) * **License:** [The Apache Software License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) -1. **Group** : tools.jackson.core. **Name** : jackson-core. **Version** : 3.2.2. +1. **Group** : tools.jackson.core. **Name** : jackson-core. **Version** : 3.2.3. * **Project URL:** [https://github.com/FasterXML/jackson-core](https://github.com/FasterXML/jackson-core) + * **License:** [https://www.apache.org/licenses/LICENSE-2.0.txt](https://www.apache.org/licenses/LICENSE-2.0.txt) * **License:** [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) * **License:** [The Apache Software License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) -1. **Group** : tools.jackson.core. **Name** : jackson-databind. **Version** : 3.2.2. +1. **Group** : tools.jackson.core. **Name** : jackson-databind. **Version** : 3.2.3. * **Project URL:** [https://github.com/FasterXML/jackson](https://github.com/FasterXML/jackson) + * **License:** [https://www.apache.org/licenses/LICENSE-2.0.txt](https://www.apache.org/licenses/LICENSE-2.0.txt) * **License:** [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) * **License:** [The Apache Software License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) -1. **Group** : tools.jackson.dataformat. **Name** : jackson-dataformat-yaml. **Version** : 3.2.2. +1. **Group** : tools.jackson.dataformat. **Name** : jackson-dataformat-yaml. **Version** : 3.2.3. * **Project URL:** [https://github.com/FasterXML/jackson-dataformats-text](https://github.com/FasterXML/jackson-dataformats-text) + * **License:** [https://www.apache.org/licenses/LICENSE-2.0.txt](https://www.apache.org/licenses/LICENSE-2.0.txt) * **License:** [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) * **License:** [The Apache Software License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) -1. **Group** : tools.jackson.datatype. **Name** : jackson-datatype-guava. **Version** : 3.2.2. +1. **Group** : tools.jackson.datatype. **Name** : jackson-datatype-guava. **Version** : 3.2.3. * **Project URL:** [https://github.com/FasterXML/jackson-datatypes-collections](https://github.com/FasterXML/jackson-datatypes-collections) + * **License:** [http://www.apache.org/licenses/LICENSE-2.0.txt](http://www.apache.org/licenses/LICENSE-2.0.txt) * **License:** [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) * **License:** [The Apache Software License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) -1. **Group** : tools.jackson.module. **Name** : jackson-module-kotlin. **Version** : 3.2.2. +1. **Group** : tools.jackson.module. **Name** : jackson-module-kotlin. **Version** : 3.2.3. * **Project URL:** [https://github.com/FasterXML/jackson-module-kotlin](https://github.com/FasterXML/jackson-module-kotlin) + * **License:** [http://www.apache.org/licenses/LICENSE-2.0.txt](http://www.apache.org/licenses/LICENSE-2.0.txt) * **License:** [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) * **License:** [The Apache Software License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) The dependencies distributed under several licenses, are used according their commercial-use-friendly license. -This report was generated on **Sun Aug 30 17:27:33 WEST 2026** using +This report was generated on **Fri Oct 16 14:50:08 WEST 2026** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). \ No newline at end of file diff --git a/docs/dependencies/pom.xml b/docs/dependencies/pom.xml index 2cccc0b..bf4e8ba 100644 --- a/docs/dependencies/pom.xml +++ b/docs/dependencies/pom.xml @@ -10,7 +10,7 @@ all modules and does not describe the project structure per-subproject. --> io.spine change -2.0.0-SNAPSHOT.208 +2.0.0-SNAPSHOT.209 2015 @@ -26,25 +26,25 @@ all modules and does not describe the project structure per-subproject. io.spine spine-base - 2.0.0-SNAPSHOT.442 + 2.0.0-SNAPSHOT.461 compile io.spine spine-time - 2.0.0-SNAPSHOT.250 + 2.0.0-SNAPSHOT.251 compile io.spine spine-validation-jvm-runtime - 2.0.0-SNAPSHOT.463 + 2.0.0-SNAPSHOT.465 compile org.jetbrains.kotlin kotlin-stdlib - 2.4.10 + 2.4.21 compile @@ -56,25 +56,25 @@ all modules and does not describe the project structure per-subproject. com.google.guava guava-testlib - 33.7.1-jre + 33.7.2-jre test io.kotest kotest-assertions-core - 6.2.4 + 6.2.5 test io.spine.tools base-testlib - 2.0.0-SNAPSHOT.213 + 2.0.0-SNAPSHOT.214 test io.spine.tools time-testlib - 2.0.0-SNAPSHOT.250 + 2.0.0-SNAPSHOT.251 test @@ -110,7 +110,7 @@ all modules and does not describe the project structure per-subproject. com.google.devtools.ksp symbol-processing-api - 2.3.9 + 2.3.11 com.google.errorprone @@ -120,12 +120,12 @@ all modules and does not describe the project structure per-subproject. com.google.protobuf protoc - 4.36.0 + 4.36.2 com.puppycrawl.tools checkstyle - 10.12.1 + 12.3.1 dev.zacsweers.autoservice @@ -140,47 +140,47 @@ all modules and does not describe the project structure per-subproject. io.spine.tools compiler-cli-all - 2.0.0-SNAPSHOT.067 + 2.0.0-SNAPSHOT.070 io.spine.tools compiler-protoc-plugin - 2.0.0-SNAPSHOT.067 + 2.0.0-SNAPSHOT.070 io.spine.tools core-jvm-gradle-plugin - 2.0.0-SNAPSHOT.091 + 2.0.0-SNAPSHOT.097 io.spine.tools core-jvm-plugins - 2.0.0-SNAPSHOT.091 + 2.0.0-SNAPSHOT.097 io.spine.tools - spine-dokka-extensions - 2.0.0-SNAPSHOT.7 + dokka-extensions + 2.0.0-SNAPSHOT.10 io.spine.tools time-validation - 2.0.0-SNAPSHOT.250 + 2.0.0-SNAPSHOT.251 io.spine.tools validation-java-bundle - 2.0.0-SNAPSHOT.463 + 2.0.0-SNAPSHOT.465 net.sourceforge.pmd pmd-ant - 7.27.0 + 7.28.0 net.sourceforge.pmd pmd-java - 7.27.0 + 7.28.0 org.jacoco @@ -225,22 +225,22 @@ all modules and does not describe the project structure per-subproject. org.jetbrains.kotlin kotlin-build-tools-compat - 2.4.10 + 2.4.21 org.jetbrains.kotlin kotlin-build-tools-impl - 2.4.10 + 2.4.21 org.jetbrains.kotlin kotlin-klib-commonizer-embeddable - 2.4.10 + 2.4.21 org.jetbrains.kotlin kotlin-scripting-compiler-embeddable - 2.4.10 + 2.4.21 From b695aeab8ef2a4d2188e0520fde3266e49a4a878 Mon Sep 17 00:00:00 2001 From: alexander-yevsyukov Date: Fri, 16 Oct 2026 17:42:40 +0100 Subject: [PATCH 07/17] Update local dependency pins --- buildSrc/src/main/kotlin/io/spine/dependency/local/Compiler.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/buildSrc/src/main/kotlin/io/spine/dependency/local/Compiler.kt b/buildSrc/src/main/kotlin/io/spine/dependency/local/Compiler.kt index 646bbbf..79884b7 100644 --- a/buildSrc/src/main/kotlin/io/spine/dependency/local/Compiler.kt +++ b/buildSrc/src/main/kotlin/io/spine/dependency/local/Compiler.kt @@ -60,7 +60,7 @@ object Compiler : Dependency() { * The version of the Compiler dependencies. */ override val version: String - private const val fallbackVersion = "2.0.0-SNAPSHOT.070" + private const val fallbackVersion = "2.0.0-SNAPSHOT.072" /** * The distinct version of the Compiler used by other build tools. From 41c092c16c96484e05afd02dc4baf2afd4f8884e Mon Sep 17 00:00:00 2001 From: alexander-yevsyukov Date: Fri, 16 Oct 2026 17:50:12 +0100 Subject: [PATCH 08/17] Update dependency reports --- docs/dependencies/dependencies.md | 2 +- docs/dependencies/pom.xml | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/dependencies/dependencies.md b/docs/dependencies/dependencies.md index 7525999..1249d6b 100644 --- a/docs/dependencies/dependencies.md +++ b/docs/dependencies/dependencies.md @@ -1028,6 +1028,6 @@ The dependencies distributed under several licenses, are used according their commercial-use-friendly license. -This report was generated on **Fri Oct 16 14:50:08 WEST 2026** using +This report was generated on **Fri Oct 16 17:49:47 WEST 2026** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). \ No newline at end of file diff --git a/docs/dependencies/pom.xml b/docs/dependencies/pom.xml index bf4e8ba..91e2821 100644 --- a/docs/dependencies/pom.xml +++ b/docs/dependencies/pom.xml @@ -140,12 +140,12 @@ all modules and does not describe the project structure per-subproject. io.spine.tools compiler-cli-all - 2.0.0-SNAPSHOT.070 + 2.0.0-SNAPSHOT.072 io.spine.tools compiler-protoc-plugin - 2.0.0-SNAPSHOT.070 + 2.0.0-SNAPSHOT.072 io.spine.tools From ff9fad8bf7191cf6cd19758f424c1f14cd0c1ca8 Mon Sep 17 00:00:00 2001 From: alexander-yevsyukov Date: Fri, 16 Oct 2026 22:39:39 +0100 Subject: [PATCH 09/17] Update local dependency pins --- buildSrc/src/main/kotlin/io/spine/dependency/local/Compiler.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/buildSrc/src/main/kotlin/io/spine/dependency/local/Compiler.kt b/buildSrc/src/main/kotlin/io/spine/dependency/local/Compiler.kt index 79884b7..7e838fc 100644 --- a/buildSrc/src/main/kotlin/io/spine/dependency/local/Compiler.kt +++ b/buildSrc/src/main/kotlin/io/spine/dependency/local/Compiler.kt @@ -60,7 +60,7 @@ object Compiler : Dependency() { * The version of the Compiler dependencies. */ override val version: String - private const val fallbackVersion = "2.0.0-SNAPSHOT.072" + private const val fallbackVersion = "2.0.0-SNAPSHOT.074" /** * The distinct version of the Compiler used by other build tools. From 6f74f8b6afbb88088cd04b5d003df2048d90d086 Mon Sep 17 00:00:00 2001 From: alexander-yevsyukov Date: Fri, 16 Oct 2026 23:37:21 +0100 Subject: [PATCH 10/17] Update dependency reports --- docs/dependencies/dependencies.md | 2 +- docs/dependencies/pom.xml | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/dependencies/dependencies.md b/docs/dependencies/dependencies.md index 1249d6b..dd4e213 100644 --- a/docs/dependencies/dependencies.md +++ b/docs/dependencies/dependencies.md @@ -1028,6 +1028,6 @@ The dependencies distributed under several licenses, are used according their commercial-use-friendly license. -This report was generated on **Fri Oct 16 17:49:47 WEST 2026** using +This report was generated on **Fri Oct 16 23:36:52 WEST 2026** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). \ No newline at end of file diff --git a/docs/dependencies/pom.xml b/docs/dependencies/pom.xml index 91e2821..ae599d7 100644 --- a/docs/dependencies/pom.xml +++ b/docs/dependencies/pom.xml @@ -140,12 +140,12 @@ all modules and does not describe the project structure per-subproject. io.spine.tools compiler-cli-all - 2.0.0-SNAPSHOT.072 + 2.0.0-SNAPSHOT.074 io.spine.tools compiler-protoc-plugin - 2.0.0-SNAPSHOT.072 + 2.0.0-SNAPSHOT.074 io.spine.tools From 5eeda9098c486731085b2884e3ca51aa2d9d28ea Mon Sep 17 00:00:00 2001 From: alexander-yevsyukov Date: Wed, 21 Oct 2026 16:26:45 +0100 Subject: [PATCH 11/17] Update shared agent tooling and config (./config/pull) Co-Authored-By: Claude Opus 5.5 --- .github/workflows/build-on-ubuntu.yml | 19 + .github/workflows/publish.yml | 2 +- AGENTS.md | 34 +- buildSrc/build.gradle.kts | 2 +- buildSrc/src/main/kotlin/DokkaExts.kt | 32 +- .../src/main/kotlin/config-tester.gradle.kts | 10 +- .../kotlin/io/spine/dependency/lib/Kotlin.kt | 4 +- .../io/spine/dependency/lib/KotlinPoet.kt | 2 +- .../dependency/lib/OpenTelemetryKotlin.kt | 87 +++ .../kotlin/io/spine/dependency/local/Base.kt | 7 +- .../io/spine/dependency/local/BaseTypes.kt | 4 +- .../io/spine/dependency/local/Change.kt | 4 +- .../io/spine/dependency/local/Compiler.kt | 2 +- .../io/spine/dependency/local/CoreJvm.kt | 7 +- .../spine/dependency/local/CoreJvmCompiler.kt | 4 +- .../io/spine/dependency/local/DokkaTools.kt | 1 - .../io/spine/dependency/local/Logging.kt | 7 +- .../io/spine/dependency/local/ProtoTap.kt | 2 +- .../io/spine/dependency/local/Reflect.kt | 6 +- .../kotlin/io/spine/dependency/local/Spine.kt | 4 +- .../io/spine/dependency/local/TestLib.kt | 6 +- .../kotlin/io/spine/dependency/local/Time.kt | 2 +- .../io/spine/dependency/local/ToolBase.kt | 9 +- .../io/spine/dependency/local/Validation.kt | 7 +- .../dependency/test/KotlinCompileTesting.kt | 2 +- .../kotlin/io/spine/gradle/ConfigTester.kt | 203 ++++++- .../spine/gradle/publish/ProtobufRuntime.kt | 173 ++++++ .../gradle/publish/PublicationHandler.kt | 27 + .../kotlin/io/spine/gradle/ClonedRepoSpec.kt | 158 ++++++ .../io/spine/gradle/GitRepositorySpec.kt | 158 ++++++ .../test/kotlin/io/spine/gradle/PathExts.kt | 29 + .../gradle/publish/ProtobufRuntimeIgTest.kt | 519 ++++++++++++++++++ .../publish/PublicationChecksumsIgTest.kt | 40 +- .../publish/PublicationHandlerIgTest.kt | 226 ++++++++ config | 2 +- gradle/wrapper/gradle-wrapper.properties | 2 +- init-submodules | 168 +++++- 37 files changed, 1869 insertions(+), 102 deletions(-) create mode 100644 buildSrc/src/main/kotlin/io/spine/dependency/lib/OpenTelemetryKotlin.kt create mode 100644 buildSrc/src/main/kotlin/io/spine/gradle/publish/ProtobufRuntime.kt create mode 100644 buildSrc/src/test/kotlin/io/spine/gradle/ClonedRepoSpec.kt create mode 100644 buildSrc/src/test/kotlin/io/spine/gradle/GitRepositorySpec.kt create mode 100644 buildSrc/src/test/kotlin/io/spine/gradle/PathExts.kt create mode 100644 buildSrc/src/test/kotlin/io/spine/gradle/publish/ProtobufRuntimeIgTest.kt create mode 100644 buildSrc/src/test/kotlin/io/spine/gradle/publish/PublicationHandlerIgTest.kt diff --git a/.github/workflows/build-on-ubuntu.yml b/.github/workflows/build-on-ubuntu.yml index b07bf0f..1f0540a 100644 --- a/.github/workflows/build-on-ubuntu.yml +++ b/.github/workflows/build-on-ubuntu.yml @@ -92,3 +92,22 @@ jobs: token: ${{ secrets.CODECOV_TOKEN }} fail_ci_if_error: true verbose: true + + # The Codecov CLI ships a set of "file fixes" with every upload. For + # `.kt` files — never `.java` — they mark each line holding nothing + # but a brace or a parenthesis as non-code. JaCoCo, however, does + # measure one such line: it attributes a Kotlin lambda body's + # instructions to the body's closing `}`, through the synthetic + # `$lambda$N` that an `invokedynamic` lambda compiles to. The fixes + # thus discard roughly a tenth of the measured lines, which would be + # harmless if every ingestion applied them. Not every one does: when + # Codecov re-processes a stored upload, the second pass leaves them + # unapplied, so one and the same report can be ingested on either + # line basis. That switch moves the `src/main/**` project status by + # about 0.7 percentage points, fourteen times the threshold in + # `.codecov.yml`, and it has been seen on `master`, whose commits + # are the `target: auto` baselines — so it can shift a pull + # request's delta either way. Sending no fixes makes both ingestion + # paths agree, at the price of counting a lambda-closing brace as a + # coverable line. + disable_file_fixes: true diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 3bad11f..aacee78 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -30,7 +30,7 @@ on: jobs: publish: name: Publish to Maven repositories - uses: SpineEventEngine/config/.github/workflows/publishing.yml@a0cbbbfe66c12475224563439fb6deb3da71ba58 + uses: SpineEventEngine/config/.github/workflows/publishing.yml@604420cd7eab82b382c9a5c1d812be454552c27c permissions: contents: read packages: write diff --git a/AGENTS.md b/AGENTS.md index 8c5f619..dc6927f 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -20,17 +20,29 @@ Shared skills, scripts, and guidelines come from the `.agents/shared` submodule (and some shallow clones / cloud checkouts) start with NO submodules checked out, so those symlinks dangle and no skills are found. Bootstrap such a tree with **`./init-submodules`** — a root script that materializes the missing -*config-managed* submodules at their pinned commits: `config` itself, plus every -submodule that declares a tracked `branch` in `.gitmodules` (`.agents/shared`, and -any shared submodule added later) — the same rule `./config/pull` uses to decide -what it floats. Submodules the consumer owns (a Hugo theme, a vendored library, -doc-example submodules, …) declare no tracked branch and are left untouched, so the -automatic `SessionStart` run never tries to clone — or fail on credentials for — a -submodule this project does not manage. It depends on no pre-existing `config` -submodule, so it works before `./config/pull` (which lives inside the `config` -submodule) can. Claude Code runs it automatically via a `SessionStart` hook; other -agents and humans run it by hand, then `./config/pull` to float the shared submodules -to their branch tips. +*config-managed* submodules at the tip of their branch (`master` for `config`, the +tracked `branch` for the rest): `config` itself, plus every submodule that declares +a tracked `branch` in `.gitmodules` (`.agents/shared`, and any shared submodule +added later) — the same rule `./config/pull` uses to decide what it floats. It +deliberately does not stop at the commit the superproject pins for such a +submodule: nothing keeps that pin current — `ignore = all` hides the submodule from +`git status`, and `./config/pull` floats the on-disk copy without committing the +moved gitlink — so materializing the pin as-is means months-old hook scripts, +skills, and guidelines. If the float fails — a branch the remote does not have, +say — a warning is printed and the submodule is left wherever the steps that +did succeed put it, at worst the pin, so a session still starts with a usable +tree; it is not retried on a later run, which is why that warning points at +`./config/pull`. With no network at all the clone itself fails and the +submodule is left uninitialized, as it was before. Submodules the consumer owns +(a Hugo theme, a vendored library, doc-example submodules, …) declare no tracked +branch and are left untouched, so the automatic `SessionStart` run never tries +to clone — or fail on credentials for — a submodule this project does not +manage. A submodule that is already checked out is left exactly as it is, which +keeps repeated runs cheap and offline-safe and never rewinds a tree someone +parked on a particular commit; run `./config/pull` to float those. It depends on +no pre-existing `config` submodule, so it works before `./config/pull` (which +lives inside the `config` submodule) can. Claude Code runs it automatically via +a `SessionStart` hook; other agents and humans run it by hand. ## Commit and history safety diff --git a/buildSrc/build.gradle.kts b/buildSrc/build.gradle.kts index aeaa51d..f1666ed 100644 --- a/buildSrc/build.gradle.kts +++ b/buildSrc/build.gradle.kts @@ -77,7 +77,7 @@ val grGitVersion = "5.3.3" * This version may change from the [version of Kotlin][io.spine.dependency.lib.Kotlin.version] * used by the project. */ -val kotlinEmbeddedVersion = "2.4.21" +val kotlinEmbeddedVersion = "2.4.10" /** * The version of Guava used in `buildSrc`. diff --git a/buildSrc/src/main/kotlin/DokkaExts.kt b/buildSrc/src/main/kotlin/DokkaExts.kt index d1483b6..5aeba8d 100644 --- a/buildSrc/src/main/kotlin/DokkaExts.kt +++ b/buildSrc/src/main/kotlin/DokkaExts.kt @@ -334,19 +334,45 @@ private fun abbreviationPattern(abbreviation: String): Regex { private val wordStart = Regex("(?=\\p{javaUpperCase})") /** - * Disables Dokka and Javadoc tasks in this `Project`. + * Disables the Dokka and Javadoc tasks generating the documentation of this `Project`. * * This function could be useful to improve build speed when building subprojects containing * test environments or integration test projects. + * + * The JARs packing the documentation stay enabled, as they do under + * [skipDokkaWhenPublishingToMavenLocal]. A publication declares one artifact + * file per JAR, and a JAR that a disabled task never writes would be missing + * both when publishing and when the published files are attested. With nothing + * generated to pack, such a JAR costs almost nothing: it contains only + * a manifest, or the output of an earlier Dokka run. */ @Suppress("unused") fun Project.disableDocumentationTasks() { gradle.taskGraph.whenReady { tasks.forEach { task -> - val lowercaseName = task.name.lowercase() - if (lowercaseName.contains("dokka") || lowercaseName.contains("javadoc")) { + if (task.generatesDocumentation()) { task.enabled = false } } } } + +/** + * Tells if this task generates documentation, rather than packing already generated + * documentation into a JAR. + * + * A [Jar] task is recognized by its type rather than by its name, so that + * `javadocJar` and `htmlDocsJar` are treated alike — as is any documentation JAR + * added later, whatever it is called. Any other task generates documentation if + * `dokka` or `javadoc` occurs in its name, ignoring case. + * + * [selectsDocsTask] keeps matching the same JARs by name, because the names it + * is given come from the command line rather than from the task graph. + */ +private fun Task.generatesDocumentation(): Boolean { + if (this is Jar) { + return false + } + return name.contains("dokka", ignoreCase = true) + || name.contains("javadoc", ignoreCase = true) +} diff --git a/buildSrc/src/main/kotlin/config-tester.gradle.kts b/buildSrc/src/main/kotlin/config-tester.gradle.kts index 22b2d90..d7f3af9 100644 --- a/buildSrc/src/main/kotlin/config-tester.gradle.kts +++ b/buildSrc/src/main/kotlin/config-tester.gradle.kts @@ -17,17 +17,19 @@ import io.spine.gradle.SpineRepos import io.spine.gradle.SpineTaskGroup import io.spine.gradle.cleanFolder import java.nio.file.Path -import java.nio.file.Paths // A reference to `config` to use along with the `ConfigTester`. -val config: Path = Paths.get("./") +// +// Both paths below are resolved against the project directory, because a relative path +// would be resolved against the working directory of the Gradle daemon instead. +val config: Path = layout.projectDirectory.asFile.toPath() // A temp folder to use to check out the sources of other repositories with the `ConfigTester`. -val tempFolder = File("./tmp") +val tempFolder = layout.projectDirectory.dir("tmp").asFile // Creates a Gradle task that checks out and builds the selected Spine repositories // with the local version of `config` and `config/buildSrc`. -ConfigTester(config, tasks, tempFolder) +ConfigTester(config = config, tasks = tasks, tempFolder = tempFolder) .addRepo(SpineRepos.baseTypes) // Builds `base-types` at `master`. .addRepo(SpineRepos.base) // Builds `base` at `master`. .addRepo(SpineRepos.coreJvm) // Builds `core-jvm` at `master`. diff --git a/buildSrc/src/main/kotlin/io/spine/dependency/lib/Kotlin.kt b/buildSrc/src/main/kotlin/io/spine/dependency/lib/Kotlin.kt index 4b49e3a..5f63d1f 100644 --- a/buildSrc/src/main/kotlin/io/spine/dependency/lib/Kotlin.kt +++ b/buildSrc/src/main/kotlin/io/spine/dependency/lib/Kotlin.kt @@ -26,7 +26,7 @@ object Kotlin : DependencyWithBom() { * This is the version of Kotlin we use for writing code that does not depend on Gradle. */ @Suppress("MemberVisibilityCanBePrivate") // used directly from the outside. - const val runtimeVersion = "2.4.21" + const val runtimeVersion = "2.4.10" override val version = runtimeVersion override val group = "org.jetbrains.kotlin" @@ -43,7 +43,7 @@ object Kotlin : DependencyWithBom() { * [embedded into Gradle](https://docs.gradle.org/current/userguide/compatibility.html#kotlin), * which the Gradle version determines on its own. */ - const val embeddedVersion = "2.4.21" + const val embeddedVersion = "2.4.10" /** * The version of the JetBrains annotations library, which is a transitive diff --git a/buildSrc/src/main/kotlin/io/spine/dependency/lib/KotlinPoet.kt b/buildSrc/src/main/kotlin/io/spine/dependency/lib/KotlinPoet.kt index c7fcf35..9cd9664 100644 --- a/buildSrc/src/main/kotlin/io/spine/dependency/lib/KotlinPoet.kt +++ b/buildSrc/src/main/kotlin/io/spine/dependency/lib/KotlinPoet.kt @@ -17,7 +17,7 @@ package io.spine.dependency.lib // https://github.com/square/kotlinpoet @Suppress("unused", "ConstPropertyName") object KotlinPoet { - private const val version = "2.4.0" + private const val version = "2.3.0" const val lib = "com.squareup:kotlinpoet:$version" const val ksp = "com.squareup:kotlinpoet-ksp:$version" } diff --git a/buildSrc/src/main/kotlin/io/spine/dependency/lib/OpenTelemetryKotlin.kt b/buildSrc/src/main/kotlin/io/spine/dependency/lib/OpenTelemetryKotlin.kt new file mode 100644 index 0000000..b473fdc --- /dev/null +++ b/buildSrc/src/main/kotlin/io/spine/dependency/lib/OpenTelemetryKotlin.kt @@ -0,0 +1,87 @@ +/* + * Copyright 2026 CodeMatters, Lda. + * + * 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 io.spine.dependency.lib + +import io.spine.dependency.Dependency + +/** + * The Kotlin Multiplatform API and SDK for OpenTelemetry. + * + * The project is currently in the alpha stage, and its API is marked + * with `@io.opentelemetry.kotlin.ExperimentalApi`. Modules using these artifacts + * must opt in to that marker. + * + * The project does not publish a BOM, so the version is embedded in each + * artifact coordinate below. + * + * @see GitHub project + * @see Kotlin documentation + */ +@Suppress("unused") +object OpenTelemetryKotlin : Dependency() { + + // https://central.sonatype.com/artifact/io.opentelemetry.kotlin/api + // + // The project is in the alpha stage, so bump this version only together + // with the code that consumes it. + override val version = "0.4.0" + override val group = "io.opentelemetry.kotlin" + + /** + * The Kotlin Multiplatform API surface (traces, metrics, logs). + * + * This is the artifact production code compiles against; the SDK artifacts + * below are for applications and tests. + */ + val api = "$group:api:$version" + + /** + * A no-op implementation of the [api] artifact. + */ + val noop = "$group:noop:$version" + + /** + * The Kotlin SDK API: span processors, exporters, samplers, and the + * configuration DSL. + * + * This artifact exposes the SDK types on the compile classpath, while the + * `createOpenTelemetry { }` entry point that instantiates them lives in + * [implementation]. Applications and tests configure an `OpenTelemetry` + * instance using these two artifacts; production code needs only + * the [api] artifact. + */ + val core = "$group:core:$version" + + /** + * The Kotlin SDK implementation, including the `createOpenTelemetry { }` + * entry point. + * + * Use it together with [core]. + */ + val implementation = "$group:implementation:$version" + + /** + * The compatibility bridge to the OpenTelemetry Java SDK. + */ + val compat = "$group:compat:$version" + + override val modules: List = listOf( + "$group:api", + "$group:noop", + "$group:core", + "$group:implementation", + "$group:compat", + ) +} diff --git a/buildSrc/src/main/kotlin/io/spine/dependency/local/Base.kt b/buildSrc/src/main/kotlin/io/spine/dependency/local/Base.kt index c310c7d..45c1d2f 100644 --- a/buildSrc/src/main/kotlin/io/spine/dependency/local/Base.kt +++ b/buildSrc/src/main/kotlin/io/spine/dependency/local/Base.kt @@ -19,10 +19,13 @@ package io.spine.dependency.local * * @see spine-base-libraries */ -@Suppress("ConstPropertyName", "unused") +@Suppress( + "ConstPropertyName" /* We use a custom convention for artifact properties. */, + "unused" /* Some subprojects do not use all Base artifacts. */, +) object Base { const val version = "2.0.0-SNAPSHOT.461" - const val versionForBuildScript = "2.0.0-SNAPSHOT.460" + const val versionForBuildScript = "2.0.0-SNAPSHOT.461" const val group = Spine.group private const val prefix = "spine" const val libModule = "$prefix-base" diff --git a/buildSrc/src/main/kotlin/io/spine/dependency/local/BaseTypes.kt b/buildSrc/src/main/kotlin/io/spine/dependency/local/BaseTypes.kt index 70fe77b..e0a8280 100644 --- a/buildSrc/src/main/kotlin/io/spine/dependency/local/BaseTypes.kt +++ b/buildSrc/src/main/kotlin/io/spine/dependency/local/BaseTypes.kt @@ -19,7 +19,9 @@ package io.spine.dependency.local * * @see spine-base-types */ -@Suppress("ConstPropertyName") +@Suppress( + "ConstPropertyName" /* We use a custom convention for artifact properties. */, +) object BaseTypes { const val version = "2.0.0-SNAPSHOT.225" const val group = Spine.group diff --git a/buildSrc/src/main/kotlin/io/spine/dependency/local/Change.kt b/buildSrc/src/main/kotlin/io/spine/dependency/local/Change.kt index 228f96e..1f6ebe1 100644 --- a/buildSrc/src/main/kotlin/io/spine/dependency/local/Change.kt +++ b/buildSrc/src/main/kotlin/io/spine/dependency/local/Change.kt @@ -19,7 +19,9 @@ package io.spine.dependency.local * * @see spine-change */ -@Suppress("ConstPropertyName") +@Suppress( + "ConstPropertyName" /* We use a custom convention for artifact properties. */, +) object Change { const val version = "2.0.0-SNAPSHOT.208" const val group = Spine.group diff --git a/buildSrc/src/main/kotlin/io/spine/dependency/local/Compiler.kt b/buildSrc/src/main/kotlin/io/spine/dependency/local/Compiler.kt index 7e838fc..137e830 100644 --- a/buildSrc/src/main/kotlin/io/spine/dependency/local/Compiler.kt +++ b/buildSrc/src/main/kotlin/io/spine/dependency/local/Compiler.kt @@ -60,7 +60,7 @@ object Compiler : Dependency() { * The version of the Compiler dependencies. */ override val version: String - private const val fallbackVersion = "2.0.0-SNAPSHOT.074" + private const val fallbackVersion = "2.0.0-SNAPSHOT.069" /** * The distinct version of the Compiler used by other build tools. diff --git a/buildSrc/src/main/kotlin/io/spine/dependency/local/CoreJvm.kt b/buildSrc/src/main/kotlin/io/spine/dependency/local/CoreJvm.kt index bef7362..35246a7 100644 --- a/buildSrc/src/main/kotlin/io/spine/dependency/local/CoreJvm.kt +++ b/buildSrc/src/main/kotlin/io/spine/dependency/local/CoreJvm.kt @@ -24,10 +24,13 @@ typealias CoreJava = CoreJvm * * See [`SpineEventEngine/core-jvm`](https://github.com/SpineEventEngine/core-jvm/). */ -@Suppress("ConstPropertyName", "unused") +@Suppress( + "ConstPropertyName" /* We use a custom convention for artifact properties. */, + "unused" /* Some subprojects do not use all CoreJvm artifacts. */, +) object CoreJvm { const val group = Spine.group - const val version = "2.0.0-SNAPSHOT.567" + const val version = "2.0.0-SNAPSHOT.571" const val coreArtifact = "spine-core" const val clientArtifact = "spine-client" diff --git a/buildSrc/src/main/kotlin/io/spine/dependency/local/CoreJvmCompiler.kt b/buildSrc/src/main/kotlin/io/spine/dependency/local/CoreJvmCompiler.kt index 6a64e8a..1af2694 100644 --- a/buildSrc/src/main/kotlin/io/spine/dependency/local/CoreJvmCompiler.kt +++ b/buildSrc/src/main/kotlin/io/spine/dependency/local/CoreJvmCompiler.kt @@ -22,7 +22,7 @@ package io.spine.dependency.local @Suppress( "MemberVisibilityCanBePrivate" /* The properties are used directly by other subprojects. */, "ConstPropertyName" /* We use a custom convention for artifact properties. */, - "unused" + "unused" /* Some subprojects do not use the CoreJvm Compiler directly. */, ) object CoreJvmCompiler { @@ -39,7 +39,7 @@ object CoreJvmCompiler { /** * The version to be used for integration tests. */ - const val version = "2.0.0-SNAPSHOT.098" + const val version = "2.0.0-SNAPSHOT.097" /** * The ID of the Gradle plugin. diff --git a/buildSrc/src/main/kotlin/io/spine/dependency/local/DokkaTools.kt b/buildSrc/src/main/kotlin/io/spine/dependency/local/DokkaTools.kt index 5a64607..6026d49 100644 --- a/buildSrc/src/main/kotlin/io/spine/dependency/local/DokkaTools.kt +++ b/buildSrc/src/main/kotlin/io/spine/dependency/local/DokkaTools.kt @@ -21,7 +21,6 @@ package io.spine.dependency.local * See [`SpineEventEngine/dokka-tools`](https://github.com/SpineEventEngine/dokka-tools/). */ @Suppress( - "unused" /* Some subprojects do not use the Dokka tools directly. */, "ConstPropertyName" /* We use a custom convention for artifact properties. */, ) object DokkaTools { diff --git a/buildSrc/src/main/kotlin/io/spine/dependency/local/Logging.kt b/buildSrc/src/main/kotlin/io/spine/dependency/local/Logging.kt index e5be8ed..6d5f5b7 100644 --- a/buildSrc/src/main/kotlin/io/spine/dependency/local/Logging.kt +++ b/buildSrc/src/main/kotlin/io/spine/dependency/local/Logging.kt @@ -19,9 +19,12 @@ package io.spine.dependency.local * * @see spine-logging */ -@Suppress("ConstPropertyName", "unused") +@Suppress( + "ConstPropertyName" /* We use a custom convention for artifact properties. */, + "unused" /* Some subprojects do not use all Logging artifacts. */, +) object Logging { - const val version = "2.0.0-SNAPSHOT.425" + const val version = "2.0.0-SNAPSHOT.426" const val group = Spine.group const val loggingArtifact = "spine-logging" diff --git a/buildSrc/src/main/kotlin/io/spine/dependency/local/ProtoTap.kt b/buildSrc/src/main/kotlin/io/spine/dependency/local/ProtoTap.kt index 45e6792..55154c6 100644 --- a/buildSrc/src/main/kotlin/io/spine/dependency/local/ProtoTap.kt +++ b/buildSrc/src/main/kotlin/io/spine/dependency/local/ProtoTap.kt @@ -26,7 +26,7 @@ package io.spine.dependency.local ) object ProtoTap { const val group = Spine.toolsGroup - const val version = "0.17.2" + const val version = "0.17.3" const val gradlePluginId = "io.spine.prototap" const val api = "$group:prototap-api:$version" const val gradlePlugin = "$group:prototap-gradle-plugin:$version" diff --git a/buildSrc/src/main/kotlin/io/spine/dependency/local/Reflect.kt b/buildSrc/src/main/kotlin/io/spine/dependency/local/Reflect.kt index ae8e17f..c07fd2f 100644 --- a/buildSrc/src/main/kotlin/io/spine/dependency/local/Reflect.kt +++ b/buildSrc/src/main/kotlin/io/spine/dependency/local/Reflect.kt @@ -19,9 +19,11 @@ package io.spine.dependency.local * * @see spine-reflect */ -@Suppress("ConstPropertyName") +@Suppress( + "ConstPropertyName" /* We use a custom convention for artifact properties. */, +) object Reflect { - const val version = "2.0.0-SNAPSHOT.201" + const val version = "2.0.0-SNAPSHOT.202" const val group = Spine.group const val artifact = "spine-reflect" const val lib = "$group:$artifact:$version" diff --git a/buildSrc/src/main/kotlin/io/spine/dependency/local/Spine.kt b/buildSrc/src/main/kotlin/io/spine/dependency/local/Spine.kt index 6efbf78..c4e6c2d 100644 --- a/buildSrc/src/main/kotlin/io/spine/dependency/local/Spine.kt +++ b/buildSrc/src/main/kotlin/io/spine/dependency/local/Spine.kt @@ -17,7 +17,9 @@ package io.spine.dependency.local /** * Defines Maven groups for the Spine SDK artifacts. */ -@Suppress("unused", "ConstPropertyName") +@Suppress( + "ConstPropertyName" /* We use a custom convention for artifact properties. */, +) object Spine { const val group = "io.spine" const val toolsGroup = "io.spine.tools" diff --git a/buildSrc/src/main/kotlin/io/spine/dependency/local/TestLib.kt b/buildSrc/src/main/kotlin/io/spine/dependency/local/TestLib.kt index bf26e25..324a493 100644 --- a/buildSrc/src/main/kotlin/io/spine/dependency/local/TestLib.kt +++ b/buildSrc/src/main/kotlin/io/spine/dependency/local/TestLib.kt @@ -19,9 +19,11 @@ package io.spine.dependency.local * * @see spine-testlib */ -@Suppress("ConstPropertyName") +@Suppress( + "ConstPropertyName" /* We use a custom convention for artifact properties. */, +) object TestLib { - const val version = "2.0.0-SNAPSHOT.214" + const val version = "2.0.0-SNAPSHOT.215" const val group = Spine.toolsGroup const val artifact = "base-testlib" const val lib = "$group:$artifact:$version" diff --git a/buildSrc/src/main/kotlin/io/spine/dependency/local/Time.kt b/buildSrc/src/main/kotlin/io/spine/dependency/local/Time.kt index 942333f..3e8e399 100644 --- a/buildSrc/src/main/kotlin/io/spine/dependency/local/Time.kt +++ b/buildSrc/src/main/kotlin/io/spine/dependency/local/Time.kt @@ -23,7 +23,7 @@ import io.spine.dependency.Dependency */ @Suppress( "unused" /* Some subprojects do not use all Time artifacts. */, - "ConstPropertyName" /* We use custom convention for artifact properties. */, + "ConstPropertyName" /* We use a custom convention for artifact properties. */, "MemberVisibilityCanBePrivate" /* The properties are used directly by other subprojects. */, ) object Time : Dependency() { diff --git a/buildSrc/src/main/kotlin/io/spine/dependency/local/ToolBase.kt b/buildSrc/src/main/kotlin/io/spine/dependency/local/ToolBase.kt index 63ecfca..2a8a255 100644 --- a/buildSrc/src/main/kotlin/io/spine/dependency/local/ToolBase.kt +++ b/buildSrc/src/main/kotlin/io/spine/dependency/local/ToolBase.kt @@ -26,11 +26,14 @@ package io.spine.dependency.local * * @see tool-base */ -@Suppress("ConstPropertyName", "unused") +@Suppress( + "ConstPropertyName" /* We use a custom convention for artifact properties. */, + "unused" /* Some subprojects do not use all ToolBase artifacts. */, +) object ToolBase { const val group = Spine.toolsGroup - const val version = "2.0.0-SNAPSHOT.425" - const val dogfoodingVersion = "2.0.0-SNAPSHOT.425" + const val version = "2.0.0-SNAPSHOT.426" + const val dogfoodingVersion = "2.0.0-SNAPSHOT.426" const val archive = "$group:archive:$version" const val code = "$group:code:$version" diff --git a/buildSrc/src/main/kotlin/io/spine/dependency/local/Validation.kt b/buildSrc/src/main/kotlin/io/spine/dependency/local/Validation.kt index c08b6db..155cbbc 100644 --- a/buildSrc/src/main/kotlin/io/spine/dependency/local/Validation.kt +++ b/buildSrc/src/main/kotlin/io/spine/dependency/local/Validation.kt @@ -19,12 +19,15 @@ package io.spine.dependency.local * * See [`SpineEventEngine/validation`](https://github.com/SpineEventEngine/validation/). */ -@Suppress("ConstPropertyName", "unused") +@Suppress( + "ConstPropertyName" /* We use a custom convention for artifact properties. */, + "unused" /* Some subprojects do not use all Validation artifacts. */, +) object Validation { /** * The version of the Validation library artifacts. */ - const val version = "2.0.0-SNAPSHOT.465" + const val version = "2.0.0-SNAPSHOT.464" const val group = Spine.toolsGroup private const val prefix = "validation" diff --git a/buildSrc/src/main/kotlin/io/spine/dependency/test/KotlinCompileTesting.kt b/buildSrc/src/main/kotlin/io/spine/dependency/test/KotlinCompileTesting.kt index 1976493..4d54ce0 100644 --- a/buildSrc/src/main/kotlin/io/spine/dependency/test/KotlinCompileTesting.kt +++ b/buildSrc/src/main/kotlin/io/spine/dependency/test/KotlinCompileTesting.kt @@ -21,7 +21,7 @@ package io.spine.dependency.test */ @Suppress("unused", "ConstPropertyName") object KotlinCompileTesting { - private const val version = "0.14.0" + private const val version = "0.13.0" private const val group = "dev.zacsweers.kctfork" const val libCore = "$group:core:$version" const val libKsp = "$group:ksp:$version" diff --git a/buildSrc/src/main/kotlin/io/spine/gradle/ConfigTester.kt b/buildSrc/src/main/kotlin/io/spine/gradle/ConfigTester.kt index f364ccc..de954af 100644 --- a/buildSrc/src/main/kotlin/io/spine/gradle/ConfigTester.kt +++ b/buildSrc/src/main/kotlin/io/spine/gradle/ConfigTester.kt @@ -18,17 +18,36 @@ package io.spine.gradle import java.io.File import java.net.URI +import java.nio.file.FileVisitResult +import java.nio.file.FileVisitResult.CONTINUE +import java.nio.file.FileVisitResult.SKIP_SUBTREE import java.nio.file.Files import java.nio.file.Path +import java.nio.file.SimpleFileVisitor +import java.nio.file.attribute.BasicFileAttributes +import kotlin.io.path.copyTo +import kotlin.io.path.createDirectories +import kotlin.io.path.exists +import kotlin.io.path.name +import kotlin.io.path.notExists import org.ajoberstar.grgit.Grgit import org.gradle.api.tasks.TaskContainer +/** + * The name of the folder with the Gradle build logic of a project. + */ +private const val BUILD_SRC = "buildSrc" + /** * A tool to execute the Gradle `build` task in selected Git repositories * with the local version of [config] contents. * * Checks out the content of selected repositories into the specified [tempFolder]. - * The folder is created if it does not exist. By default, uses `./tmp` as a temp folder. + * The folder is created if it does not exist. + * + * Both [config] and [tempFolder] must be absolute paths, e.g. obtained from + * `layout.projectDirectory`. A relative path is resolved against the working directory + * of the Gradle daemon, which is unrelated to the project directory. * * Replaces the `config` and `buildSrc` folders in the checked-out repository by the local versions * of code. If the repository-under-test already contains its own `buildSrc` or `config` folders, @@ -46,7 +65,7 @@ import org.gradle.api.tasks.TaskContainer class ConfigTester( private val config: Path, private val tasks: TaskContainer, - private val tempFolder: File = File("./tmp") + private val tempFolder: File ) { companion object { @@ -57,7 +76,16 @@ class ConfigTester( private const val BUILD_TIMEOUT_MINUTES = 30L } - private val buildSrc: Path = config.resolve("buildSrc") + init { + require(config.isAbsolute) { + "The path to `config` must be absolute. Encountered: `$config`." + } + require(tempFolder.isAbsolute) { + "The path to the temp folder must be absolute. Encountered: `$tempFolder`." + } + } + + private val buildSrc: Path = config.resolve(BUILD_SRC) /** * Git repositories to test. @@ -75,7 +103,8 @@ class ConfigTester( } /** - * Adds a test. + * Adds a Git [repo] into the test build by its URI, to be checked out + * at the given [branch]. */ fun addRepo(repo: URI, branch: Branch): ConfigTester { repos.add(GitRepository(repo, branch)) @@ -159,7 +188,9 @@ class GitRepository( private val uri: URI, /** - * A branch to checkout. + * A branch to check out. + * + * May be any branch of the repository, not only the default one. * * By default, points to `master`. */ @@ -193,6 +224,9 @@ class GitRepository( * the `destinationFolder/foobar` folder. * * If the supplied folder does not exist, it is created. + * + * The [branch] is checked out as a local branch tracking its remote counterpart. + * A [branch] the remote does not advertise fails the checkout. */ fun checkout(destinationFolder: File): ClonedRepo { val preparedFolder = prepareCheckout(destinationFolder).toPath() @@ -201,16 +235,21 @@ class GitRepository( "to `${preparedFolder.toAbsolutePath()}`." ) + // The branch is checked out by the `clone` itself, rather than by a subsequent + // `checkout`. A fresh clone has only the default branch among its local refs, + // so `checkout` cannot resolve any other branch by its plain name, while + // `refToCheckout` is resolved against the refs advertised by the remote, + // where every branch of the repository is present. + // + // Only the checked-out files are of interest further on, so the Git repository + // the clone opens is closed right away. Grgit.clone( mapOf( "dir" to preparedFolder, - "uri" to uri + "uri" to uri, + "refToCheckout" to branch.name ) - ).checkout( - mapOf( - "branch" to branch.name - ) - ) + ).close() return ClonedRepo(this, preparedFolder) } @@ -260,14 +299,37 @@ class ClonedRepo( * Optionally, takes an [ignoredFolder] that will be excluded from the [source] paths * when copying. * + * Build output and Git metadata of the [source] are not copied. If the original + * `buildSrc` has its own `module.gradle.kts`, the script is preserved. * * Returns this instance of `ClonedRepo`, for call chaining. */ fun replaceBuildSrc(source: Path, ignoredFolder: Path?): ClonedRepo { - replaceFolder("buildSrc", source, ignoredFolder) + replaceFolder(BUILD_SRC, source, ignoredFolder)?.let(::restoreModuleScript) return this } + /** + * Restores the `module.gradle.kts` script of this repository, if it has one. + * + * `config` ships this script as an empty template that each project replaces + * by its own. The `config/migrate` script preserves the script of a project + * when installing `buildSrc` into it, and so must the test build. + * + * @param originalBuildSrc + * the folder into which the original `buildSrc` of this repository was renamed. + */ + private fun restoreModuleScript(originalBuildSrc: Path) { + val ownScript = originalBuildSrc.resolve(MODULE_SCRIPT_PATH) + if (!ownScript.exists()) { + return + } + println("Preserving the `$MODULE_SCRIPT_PATH` of `${repo.name}`.") + val destination = location.resolve(BUILD_SRC).resolve(MODULE_SCRIPT_PATH) + destination.parent.createDirectories() + ownScript.copyTo(destination, overwrite = true) + } + /** * Replaces the `config` folder in this cloned repository by the contents * of the folder defined by the [source]. @@ -280,6 +342,8 @@ class ClonedRepo( * Optionally, takes an [ignoredFolder] that will be excluded from the [source] paths * when copying. * + * Build output and Git metadata of the [source] are not copied. + * * Returns this instance of `ClonedRepo`, for call chaining. */ fun replaceConfig(source: Path, ignoredFolder: Path?): ClonedRepo { @@ -287,19 +351,30 @@ class ClonedRepo( return this } - private fun replaceFolder(folderName: String, source: Path, ignoredFolder: Path?) { + /** + * Replaces the [folderName] folder of this repository by the contents of the [source]. + * + * The original folder, if any, is renamed into `-original`. + * + * Returns the path to which the original folder was renamed, or `null` + * if this repository has no such folder. + */ + private fun replaceFolder(folderName: String, source: Path, ignoredFolder: Path?): Path? { val folder = location.resolve(folderName) val rawFolder = folder.toFile() + var renamedInto: Path? = null if (rawFolder.exists() && rawFolder.isDirectory) { - val toRenameInto = location.resolve(folderName + "-original") + val toRenameInto = location.resolve("$folderName-original") println("Renaming ${folder.toAbsolutePath()} into ${toRenameInto.toAbsolutePath()}.") - rawFolder.renameTo(toRenameInto.toFile()) + Files.move(folder, toRenameInto) + renamedInto = toRenameInto } println( "Copying the files from ${source.toAbsolutePath()} " + "into ${folder.toAbsolutePath()}." ) copyFolder(source, ignoredFolder, folder) + return renamedInto } @Suppress("TooGenericExceptionCaught") @@ -313,22 +388,93 @@ class ClonedRepo( } } + /** + * Copies the [sourceFolder] into the [destinationFolder], skipping the [ignoredFolder] + * along with the build output and the Git metadata. + * + * A symbolic link to a folder is copied as an empty folder, as the tree is walked + * without following the links. A link that does not resolve is skipped: `config` + * has such links when its `.agents/shared` submodule is not checked out. + */ private fun copyRecursively(sourceFolder: Path, ignoredFolder: Path?, destinationFolder: Path) { - fun Path.isIgnored(): Boolean = ignoredFolder - ?.let { toAbsolutePath().startsWith(it.toAbsolutePath()) } - ?: false - - val flattenedTree = Files.walk(sourceFolder).filter { it.isIgnored().not() } - val filesToDestinations = flattenedTree.map { file -> - val destination = destinationFolder.resolve(sourceFolder.relativize(file)) - file to destination + val ignored = ignoredFolder?.toAbsolutePath() + + fun Path.isIgnored(): Boolean = + ignored?.let { toAbsolutePath().startsWith(it) } ?: false + + fun Path.destination(): Path = destinationFolder.resolve(sourceFolder.relativize(this)) + + // The tree is walked rather than streamed, so that an entry which is not copied + // is not descended into either. During the test build the `tmp` folder alone holds + // the full clones of all the tested repositories. + Files.walkFileTree(sourceFolder, object : SimpleFileVisitor() { + + override fun preVisitDirectory(dir: Path, attrs: BasicFileAttributes): FileVisitResult { + if (dir != sourceFolder && (dir.isIgnored() || dir.isNonSource())) { + return SKIP_SUBTREE + } + dir.destination().createDirectories() + return CONTINUE + } + + override fun visitFile(file: Path, attrs: BasicFileAttributes): FileVisitResult { + val danglingLink = attrs.isSymbolicLink && file.notExists() + if (!danglingLink && !file.isIgnored() && !file.isNonSource()) { + file.copyTo(file.destination()) + } + return CONTINUE + } + }) + } + + /** + * Tells if this entry holds the output of a build or the Git metadata, + * and hence must not be copied. + * + * The build output of the local `config` is unrelated to the repository under test. + * Git metadata additionally holds the IPC sockets of the Git file system monitor; + * these cannot be copied at all. + * + * A `build` folder is recognized only next to a Gradle build script, so that + * the source packages named `build` are copied as usual. + */ + private fun Path.isNonSource(): Boolean { + if (name in NON_SOURCE_ENTRIES) { + return true } + return name == BUILD_OUTPUT && parent?.holdsGradleBuild() == true + } + + private fun Path.holdsGradleBuild(): Boolean = BUILD_SCRIPTS.any { resolve(it).exists() } + + private companion object { + + /** + * Names of the entries that never hold sources, at any depth of a project. + * + * @see ClonedRepo.isNonSource + */ + val NON_SOURCE_ENTRIES = setOf(".git", ".gradle", ".kotlin") + + /** + * The name of the folder that holds the output of a Gradle build. + * + * @see ClonedRepo.isNonSource + */ + const val BUILD_OUTPUT = "build" - val directories = filesToDestinations.filter { Files.isDirectory(it.first) } - directories.forEach { Files.createDirectories(it.second) } + /** + * The names of the scripts by which a folder is recognized as a Gradle build. + */ + val BUILD_SCRIPTS = setOf("build.gradle.kts", "settings.gradle.kts") - val files = filesToDestinations.filter { Files.isDirectory(it.first).not() } - files.forEach { Files.copy(it.first, it.second) } + /** + * The path, relative to `buildSrc`, to the script that each project + * defines for itself. + * + * @see ClonedRepo.restoreModuleScript + */ + const val MODULE_SCRIPT_PATH = "src/main/kotlin/module.gradle.kts" } } @@ -353,5 +499,8 @@ object SpineRepos { /** * A name of a Git branch. + * + * The [name] is a plain branch name, such as `master` or `grpc-concurrency-fixes`. + * Neither the `refs/heads/` prefix nor the name of a remote is expected. */ data class Branch(val name: String) diff --git a/buildSrc/src/main/kotlin/io/spine/gradle/publish/ProtobufRuntime.kt b/buildSrc/src/main/kotlin/io/spine/gradle/publish/ProtobufRuntime.kt new file mode 100644 index 0000000..715a199 --- /dev/null +++ b/buildSrc/src/main/kotlin/io/spine/gradle/publish/ProtobufRuntime.kt @@ -0,0 +1,173 @@ +/* + * Copyright 2026 CodeMatters, Lda. + * + * 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 io.spine.gradle.publish + +import com.github.jengelman.gradle.plugins.shadow.ShadowJavaPlugin +import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar +import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar.Companion.SHADOW_JAR_TASK_NAME +import groovy.util.Node +import io.spine.dependency.lib.Protobuf +import org.gradle.api.Project +import org.gradle.api.publish.maven.MavenPublication +import org.gradle.kotlin.dsl.add +import org.gradle.kotlin.dsl.named + +/** + * Leaves the Protobuf runtime ([Protobuf.libs]) out of the fat JAR built by + * the `shadowJar` task of this project, declaring it as a `runtime` dependency of + * the published artifacts instead. + * + * A bundled copy of the runtime cannot be relocated, as the runtime depends on + * the names of its classes. Left unrelocated, it shadows the Protobuf runtime that + * a consumer resolves for its own classpath, and no `force(...)` can replace it: + * the copy is bytecode inside another artifact, not a dependency. Should the copy + * be older than the code generated for the consumer, loading that code fails with + * `ProtobufRuntimeVersionException`. Declared as a dependency, the runtime takes part + * in the dependency resolution of the consumer, so the version it resolves wins. + * + * The libraries are declared: + * 1. in the `protobufRuntime` configuration, which the `shadowRuntimeElements` + * configuration of the Shadow plugin extends, so that the Gradle module metadata + * of a publication of the shadowed variant, such as the publication of a Gradle + * plugin, lists them; + * 2. in the POM of the given [publication], which publishes the fat JAR with + * `artifact(...)` and so receives no dependencies from Gradle. + * + * All the libraries of [Protobuf.libs] are declared, whichever of them the fat JAR + * used to bundle. They are declared in the `runtime` scope, so they no longer reach + * the compile classpath of the consumers of the fat JAR, which suits the tools and + * plugins published as fat JARs. + * + * The `shadow` configuration is not used for this purpose: Shadow writes the files of + * that configuration into the `Class-Path` attribute of the JAR manifest. Such entries + * are relative to the JAR and carry the Protobuf version the build resolved, so in + * a directory holding the JAR along with other Protobuf JARs, they would put that + * version first again. + * + * Each library is declared non-transitively, so only the libraries themselves are + * declared, `protobuf-java` among them. The rest of their dependencies stays where + * it was: bundled into the fat JAR (Guava, Gson), or provided where the JAR runs, + * as Gradle provides the Kotlin standard library to plugins. So consumers get + * the same classes as before, except that those of the Protobuf runtime come from + * genuine artifacts. + * + * The libraries are excluded by the dependency filter of the `shadowJar` task rather + * than by the paths of their entries, so that everything they contribute, classes and + * resources alike, is left out, and the SBOM published with the fat JAR does not + * describe them as [bundled][SbomContent.bundled]. + * + * Call this function after applying the Shadow and `maven-publish` plugins and + * creating the publication of the fat JAR, and after any code writing dependencies + * into the POM of the publication, so that the POM keeps a single `dependencies` + * element: + * ```kotlin + * unbundleProtobufRuntime() // The `fatJar` of `uber-jar-module`. + * unbundleProtobufRuntime(publication = "cliFatJar") // A publication of its own. + * ``` + * A project publishing its fat JAR in several publications calls the function + * once for each of them. + * + * @param publication The name of the publication of the fat JAR. Defaults to + * `fatJar`, the publication created by `uber-jar-module`. + */ +fun Project.unbundleProtobufRuntime(publication: String = "fatJar") { + if (configurations.findByName(PROTOBUF_RUNTIME) == null) { + declareProtobufRuntime() + } + publications.named(publication) { + declareRuntimeDependencies(Protobuf.libs) + } +} + +/** + * Declares the Protobuf runtime in the `protobufRuntime` configuration, which + * the `shadowRuntimeElements` configuration extends, and leaves it out of + * the fat JAR built by the `shadowJar` task. + */ +private fun Project.declareProtobufRuntime() { + val protobufRuntime = configurations.create(PROTOBUF_RUNTIME) { + description = "The Protobuf runtime, which the published artifacts declare" + + " rather than bundle." + isCanBeConsumed = false + isCanBeResolved = false + } + Protobuf.libs.forEach { + dependencies.add(protobufRuntime.name, it) { + isTransitive = false + } + } + configurations.named(ShadowJavaPlugin.SHADOW_RUNTIME_ELEMENTS_CONFIGURATION_NAME) { + extendsFrom(protobufRuntime) + } + tasks.named(SHADOW_JAR_TASK_NAME) { + dependencies { + exclude { "${it.moduleGroup}:${it.moduleName}" in protobufRuntimeModules } + } + } +} + +/** + * The name of the configuration holding the Protobuf runtime, which the published + * artifacts declare rather than bundle. + */ +private const val PROTOBUF_RUNTIME = "protobufRuntime" + +/** + * The `group:name` coordinates of the Protobuf runtime libraries. + */ +private val protobufRuntimeModules: Set = + Protobuf.libs.mapTo(mutableSetOf()) { it.substringBeforeLast(':') } + +/** + * Declares the dependencies on the given `group:name:version` [coordinates] + * in the POM of this publication, in the `runtime` scope and without + * transitive dependencies. + * + * The dependencies are added to the `dependencies` element of the POM, + * which is created if the POM has none. + */ +private fun MavenPublication.declareRuntimeDependencies(coordinates: List) { + pom.withXml { + val root = asNode() + val dependencies = root.children() + .filterIsInstance() + .firstOrNull { it.localName == "dependencies" } + ?: root.appendNode("dependencies") + coordinates.forEach { + // Prefixed with `lib`, as plain `name` and `version` would hide those + // of the publication. + val (libGroup, libName, libVersion) = it.split(':') + with(dependencies.appendNode("dependency")) { + appendNode("groupId", libGroup) + appendNode("artifactId", libName) + appendNode("version", libVersion) + appendNode("scope", "runtime") + with(appendNode("exclusions").appendNode("exclusion")) { + appendNode("groupId", "*") + appendNode("artifactId", "*") + } + } + } + } +} + +/** + * The name of this node without its namespace. + * + * The name is a `QName` for a node parsed with namespaces, as the nodes of a POM are. + * It renders as `{namespace}localName`. + */ +private val Node.localName: String + get() = name().toString().substringAfterLast('}') diff --git a/buildSrc/src/main/kotlin/io/spine/gradle/publish/PublicationHandler.kt b/buildSrc/src/main/kotlin/io/spine/gradle/publish/PublicationHandler.kt index 1d4bb96..22d7d73 100644 --- a/buildSrc/src/main/kotlin/io/spine/gradle/publish/PublicationHandler.kt +++ b/buildSrc/src/main/kotlin/io/spine/gradle/publish/PublicationHandler.kt @@ -38,6 +38,11 @@ import org.gradle.kotlin.dsl.withType */ private const val MAVEN_PUBLISH = "maven-publish" +/** + * The name of the Gradle plugin that adds test fixtures to a project. + */ +private const val JAVA_TEST_FIXTURES = "java-test-fixtures" + /** * Abstract base for handlers of publications in a project * with [spinePublishing] settings declared. @@ -95,6 +100,7 @@ sealed class PublicationHandler( // is applied. pluginManager.withPlugin(MAVEN_PUBLISH) { handlePublications() + suppressTestFixturesPomWarnings() registerDestinations() configurePublishTask(destinations) applied = true @@ -109,6 +115,27 @@ sealed class PublicationHandler( */ abstract fun handlePublications() + /** + * Silences the warnings that Gradle prints about the test fixtures variants + * when it generates the POM of a Maven publication of the [project]. + * + * The `java-test-fixtures` plugin adds the test fixtures to the `java` component + * as variants with a capability of their own. Gradle Module Metadata (`.module`) + * keeps them, while a POM cannot describe a capability, so Gradle leaves them + * out of it by design. Hence, the warnings carry no information. + * + * The publications added after this handler is applied, such as `pluginMaven` + * of `java-gradle-plugin`, are silenced as well. + */ + private fun suppressTestFixturesPomWarnings() { + project.pluginManager.withPlugin(JAVA_TEST_FIXTURES) { + project.publications.withType().configureEach { + suppressPomMetadataWarningsFor("testFixturesApiElements") + suppressPomMetadataWarningsFor("testFixturesRuntimeElements") + } + } + } + /** * Goes through the [destinations] and registers each as a repository for publishing * in the given Gradle project. diff --git a/buildSrc/src/test/kotlin/io/spine/gradle/ClonedRepoSpec.kt b/buildSrc/src/test/kotlin/io/spine/gradle/ClonedRepoSpec.kt new file mode 100644 index 0000000..c9f102c --- /dev/null +++ b/buildSrc/src/test/kotlin/io/spine/gradle/ClonedRepoSpec.kt @@ -0,0 +1,158 @@ +/* + * Copyright 2026 CodeMatters, Lda. + * + * 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 io.spine.gradle + +import io.kotest.matchers.shouldBe +import java.net.URI +import java.nio.file.Path +import kotlin.io.path.createSymbolicLinkPointingTo +import kotlin.io.path.exists +import kotlin.io.path.readText +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.DisplayName +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.io.TempDir + +@DisplayName("`ClonedRepo` should") +internal class ClonedRepoSpec { + + @TempDir + lateinit var tempDir: Path + + /** The `buildSrc` of the local `config` to be copied. */ + private lateinit var source: Path + + /** The root of the repository under test. */ + private lateinit var location: Path + + @BeforeEach + fun prepareFolders() { + source = tempDir.resolve("config").resolve(BUILD_SRC) + location = tempDir.resolve("repo") + } + + @Test + fun `copy the files, and not only the folders`() { + source.createFile("quality/detekt-config.yml", "The quality settings.") + source.createFile("src/main/kotlin/io/spine/dependency/build/Ksp.kt", "object Ksp") + + replaceBuildSrc() + + val copied = location.resolve(BUILD_SRC) + copied.resolve("quality/detekt-config.yml").readText() shouldBe "The quality settings." + copied.resolve("src/main/kotlin/io/spine/dependency/build/Ksp.kt") + .readText() shouldBe "object Ksp" + } + + @Test + fun `skip the build output and the Git metadata`() { + source.createFile(BUILD_SCRIPT, "The build script.") + source.createFile("src/main/kotlin/Deps.kt", "object Deps") + source.createFile("build/classes/Deps.class", "The compiled code.") + source.createFile(".gradle/file-system.probe", "The probe.") + source.createFile(".kotlin/sessions/session.salive", "The session.") + source.createFile(".git/HEAD", "ref: refs/heads/master") + + replaceBuildSrc() + + val copied = location.resolve(BUILD_SRC) + copied.resolve("src/main/kotlin/Deps.kt").exists() shouldBe true + copied.resolve("build").exists() shouldBe false + copied.resolve(".gradle").exists() shouldBe false + copied.resolve(".kotlin").exists() shouldBe false + copied.resolve(".git").exists() shouldBe false + } + + @Test + fun `skip the build output of a nested Gradle project`() { + val config = tempDir.resolve("config") + config.createFile(BUILD_SCRIPT, "The build script.") + config.createFile("$BUILD_SRC/settings.gradle.kts", "The settings of `buildSrc`.") + config.createFile("$BUILD_SRC/build/classes/Deps.class", "The compiled code.") + config.createFile("$BUILD_SRC/.gradle/file-system.probe", "The probe.") + config.createFile("$BUILD_SRC/src/main/kotlin/io/spine/dependency/build/Ksp.kt", "object Ksp") + + val repo = GitRepository(URI("https://github.com/SpineEventEngine/base")) + ClonedRepo(repo, location).replaceConfig(config, null) + + val copied = location.resolve("config") + copied.resolve("$BUILD_SRC/build").exists() shouldBe false + copied.resolve("$BUILD_SRC/.gradle").exists() shouldBe false + copied.resolve("$BUILD_SRC/src/main/kotlin/io/spine/dependency/build/Ksp.kt") + .readText() shouldBe "object Ksp" + } + + @Test + fun `preserve the 'module gradle kts' of the repository under test`() { + source.createFile(MODULE_SCRIPT, TEMPLATE_MODULE_SCRIPT) + location.resolve(BUILD_SRC).createFile(MODULE_SCRIPT, OWN_MODULE_SCRIPT) + + replaceBuildSrc() + + location.resolve(BUILD_SRC).resolve(MODULE_SCRIPT) + .readText() shouldBe OWN_MODULE_SCRIPT + location.resolve("$BUILD_SRC-original").resolve(MODULE_SCRIPT) + .readText() shouldBe OWN_MODULE_SCRIPT + } + + @Test + fun `take the template 'module gradle kts' when the repository has none`() { + source.createFile(MODULE_SCRIPT, TEMPLATE_MODULE_SCRIPT) + + replaceBuildSrc() + + location.resolve(BUILD_SRC).resolve(MODULE_SCRIPT) + .readText() shouldBe TEMPLATE_MODULE_SCRIPT + } + + @Test + fun `skip a link that does not resolve`() { + source.createFile("src/main/kotlin/Deps.kt", "object Deps") + val link = source.resolve("guidelines") + link.createSymbolicLinkPointingTo(source.resolve("shared/guidelines")) + + replaceBuildSrc() + + val copied = location.resolve(BUILD_SRC) + copied.resolve("src/main/kotlin/Deps.kt").exists() shouldBe true + copied.resolve("guidelines").exists() shouldBe false + } + + @Test + fun `skip the ignored folder`() { + source.createFile("src/main/kotlin/Deps.kt", "object Deps") + source.createFile("tmp/base/README.md", "The checked out sources.") + + replaceBuildSrc(ignoredFolder = source.resolve("tmp")) + + val copied = location.resolve(BUILD_SRC) + copied.resolve("src/main/kotlin/Deps.kt").exists() shouldBe true + copied.resolve("tmp").exists() shouldBe false + } + + private fun replaceBuildSrc(ignoredFolder: Path? = null) { + val repo = GitRepository(URI("https://github.com/SpineEventEngine/base")) + ClonedRepo(repo, location).replaceBuildSrc(source, ignoredFolder) + } + + private companion object { + + const val BUILD_SRC = "buildSrc" + const val BUILD_SCRIPT = "build.gradle.kts" + const val MODULE_SCRIPT = "src/main/kotlin/module.gradle.kts" + const val TEMPLATE_MODULE_SCRIPT = "// A template to be defined by a project." + const val OWN_MODULE_SCRIPT = "plugins { `java-library` }" + } +} diff --git a/buildSrc/src/test/kotlin/io/spine/gradle/GitRepositorySpec.kt b/buildSrc/src/test/kotlin/io/spine/gradle/GitRepositorySpec.kt new file mode 100644 index 0000000..791a9ca --- /dev/null +++ b/buildSrc/src/test/kotlin/io/spine/gradle/GitRepositorySpec.kt @@ -0,0 +1,158 @@ +/* + * Copyright 2026 CodeMatters, Lda. + * + * 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 io.spine.gradle + +import io.kotest.assertions.throwables.shouldThrow +import io.kotest.matchers.paths.shouldNotExist +import io.kotest.matchers.shouldBe +import io.kotest.matchers.string.shouldContain +import java.io.File +import java.nio.file.Path +import kotlin.io.path.createDirectories +import kotlin.io.path.readText +import org.ajoberstar.grgit.Grgit +import org.eclipse.jgit.api.errors.GitAPIException +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.DisplayName +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.io.TempDir + +@DisplayName("`GitRepository` should") +internal class GitRepositorySpec { + + @TempDir + lateinit var tempDir: Path + + /** The repository to be cloned, playing the role of a remote. */ + private lateinit var origin: Path + + /** The folder the repository is checked out into. */ + private lateinit var destination: File + + /** The root of the checked-out repository. */ + private val clone: Path + get() = destination.toPath().resolve(REPO_NAME) + + /** + * Creates the repository to be cloned, with two branches. + * + * Both branches carry [SHARED_FILE]. Only [FEATURE] carries [FEATURE_FILE], + * which thus tells the branches apart in the clone. + * + * The created repository is left at [MASTER], so that this is the branch + * a clone checks out by default. + */ + @BeforeEach + fun createOrigin() { + origin = tempDir.resolve(REPO_NAME).createDirectories() + destination = tempDir.resolve("checkout").toFile() + Grgit.init(mapOf("dir" to origin)).use { git -> + origin.createFile(SHARED_FILE, SHARED_TEXT) + git.commitAll("Add the file shared by all branches.") + + // Git does not mandate the name of the branch a repository starts with, + // and JGit honors `init.defaultBranch`, so make sure `master` exists. + if (git.branch.current().name != MASTER) { + git.checkout(mapOf("branch" to MASTER, "createBranch" to true)) + } + + git.checkout(mapOf("branch" to FEATURE, "createBranch" to true)) + origin.createFile(FEATURE_FILE, FEATURE_TEXT) + git.commitAll("Add the file of the feature branch.") + + git.checkout(mapOf("branch" to MASTER)) + } + } + + @Test + fun `check out the default branch`() { + GitRepository(origin.toUri()).checkout(destination) + + clone.resolve(SHARED_FILE).readText() shouldBe SHARED_TEXT + clone.resolve(FEATURE_FILE).shouldNotExist() + headOfClone() shouldBe "$MASTER -> origin/$MASTER" + } + + /** + * Verifies that a branch is resolved by its plain name and is checked out + * as a local branch rather than as a detached `HEAD`. + * + * A fresh clone has only the default branch among its local refs, so the branch + * has to be resolved against the refs advertised by the remote. `HEAD` detached + * at `origin/` would hold the right files just as well, which is why + * the `HEAD` of the clone is asserted too. + */ + @Test + fun `check out a branch other than the default one`() { + GitRepository(origin.toUri(), Branch(FEATURE)).checkout(destination) + + clone.resolve(FEATURE_FILE).readText() shouldBe FEATURE_TEXT + headOfClone() shouldBe "$FEATURE -> origin/$FEATURE" + } + + /** + * Verifies that a missing branch fails the checkout right away. + * + * Were the clone to succeed and leave an empty working tree behind, the Gradle + * build of the repository would fail later on with a far less obvious message. + */ + @Test + fun `fail to check out a branch that does not exist`() { + val repo = GitRepository(origin.toUri(), Branch(MISSING)) + + val error = shouldThrow { repo.checkout(destination) } + + // `GitAPIException` roots the whole JGit error hierarchy, so the branch + // has to be named for this to pin the branch resolution rather than, + // say, an unreadable `origin`. + error.message shouldContain MISSING + } + + /** + * Returns the current branch of the clone, along with the branch it tracks, + * as ` -> `. + * + * A detached `HEAD` reads as `HEAD -> null`. + */ + private fun headOfClone(): String = + Grgit.open(mapOf("dir" to clone)).use { + val head = it.branch.current() + "${head.name} -> ${head.trackingBranch?.name}" + } + + private companion object { + + /** The name of the folder the repository is cloned into. */ + const val REPO_NAME = "acme-lib" + + const val MASTER = "master" + const val FEATURE = "grpc-concurrency-fixes" + const val MISSING = "no-such-branch" + + const val SHARED_FILE = "README.md" + const val SHARED_TEXT = "The file shared by all branches." + + const val FEATURE_FILE = "src/main/kotlin/Concurrency.kt" + const val FEATURE_TEXT = "object Concurrency" + + /** + * Commits all the files of this repository, including the new ones. + */ + fun Grgit.commitAll(message: String) { + add(mapOf("patterns" to setOf("."))) + commit(mapOf("message" to message)) + } + } +} diff --git a/buildSrc/src/test/kotlin/io/spine/gradle/PathExts.kt b/buildSrc/src/test/kotlin/io/spine/gradle/PathExts.kt new file mode 100644 index 0000000..c0ae947 --- /dev/null +++ b/buildSrc/src/test/kotlin/io/spine/gradle/PathExts.kt @@ -0,0 +1,29 @@ +/* + * Copyright 2026 CodeMatters, Lda. + * + * 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 io.spine.gradle + +import java.nio.file.Path +import kotlin.io.path.createDirectories +import kotlin.io.path.writeText + +/** + * Creates a file under this folder, along with the folders leading to it. + */ +internal fun Path.createFile(relativePath: String, content: String): Path { + val file = resolve(relativePath) + file.parent.createDirectories() + file.writeText(content) + return file +} diff --git a/buildSrc/src/test/kotlin/io/spine/gradle/publish/ProtobufRuntimeIgTest.kt b/buildSrc/src/test/kotlin/io/spine/gradle/publish/ProtobufRuntimeIgTest.kt new file mode 100644 index 0000000..f6a7d20 --- /dev/null +++ b/buildSrc/src/test/kotlin/io/spine/gradle/publish/ProtobufRuntimeIgTest.kt @@ -0,0 +1,519 @@ +/* + * Copyright 2026 CodeMatters, Lda. + * + * 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 io.spine.gradle.publish + +import com.fasterxml.jackson.databind.JsonNode +import com.fasterxml.jackson.databind.ObjectMapper +import io.kotest.inspectors.forAll +import io.kotest.matchers.collections.shouldBeEmpty +import io.kotest.matchers.collections.shouldBeSingleton +import io.kotest.matchers.collections.shouldContainAll +import io.kotest.matchers.collections.shouldContainExactly +import io.kotest.matchers.collections.shouldContainExactlyInAnyOrder +import io.kotest.matchers.collections.shouldNotContain +import io.kotest.matchers.nulls.shouldBeNull +import io.kotest.matchers.nulls.shouldNotBeNull +import io.kotest.matchers.shouldBe +import io.spine.dependency.lib.Protobuf +import java.io.File +import java.util.jar.JarFile +import java.util.jar.JarOutputStream +import java.util.jar.Manifest +import java.util.zip.ZipEntry +import javax.xml.parsers.DocumentBuilderFactory +import org.gradle.testkit.runner.GradleRunner +import org.junit.jupiter.api.BeforeAll +import org.junit.jupiter.api.DisplayName +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.TestInstance +import org.junit.jupiter.api.io.TempDir +import org.w3c.dom.Element + +/** + * Verifies [unbundleProtobufRuntime] in a real build of fat JARs, run via Gradle TestKit. + * + * The fixture is built once for the whole class, and each case inspects what + * the build left behind. The build runs with `--offline`, resolving from a local + * `file:` repository, which holds stand-ins for the Protobuf runtime libraries. + * `protobuf-java-util` depends on `com.example:gson`, as the genuine one depends + * on Gson. The build also runs with the configuration cache. + * + * All the modules of the fixture apply Shadow and depend on `com.example:lib`. + * The fixture has: + * - `fat` — a module depending on the Protobuf runtime. It publishes its fat JAR + * in the `cliFatJar` publication, with `artifact(...)`, as the Compiler CLI does, + * and its Java component, which carries the shadowed variant, in the `library` + * publication; + * - `component` — a module whose `library` publication of its Java component is + * given to the function, so that the POM the function adds to already has + * the `dependencies` element Gradle writes; + * - `twin` — a module depending on the Protobuf runtime. It publishes its fat JAR + * in two publications: `fatJar`, as `uber-jar-module` does, and `extra`, whose POM + * gets a `dependencies` element written by hand before the function adds to it. + * The function is called once for each publication. + */ +@DisplayName("`unbundleProtobufRuntime` should") +@TestInstance(TestInstance.Lifecycle.PER_CLASS) +internal class ProtobufRuntimeIgTest { + + private lateinit var projectDir: File + + @BeforeAll + fun buildFixture(@TempDir dir: File) { + projectDir = dir + writeRepository() + writeBuild() + GradleRunner.create() + .withProjectDir(projectDir) + .withArguments( + ":fat:shadowJar", + ":fat:${pomTaskOf(cliFatJar)}", + ":fat:generateMetadataFileForLibraryPublication", + ":fat:$listIncludedTask", + ":component:${pomTaskOf(library)}", + ":twin:${pomTaskOf(defaultFatJar)}", + ":twin:${pomTaskOf(extra)}", + "--offline", + "--configuration-cache", + "--stacktrace", + ) + .build() + } + + @Test + fun `leave the Protobuf runtime out of the fat JAR`() { + val entries = fatJarEntries() + + entries.filter { it.startsWith("com/google/protobuf/") }.shouldBeEmpty() + entries shouldNotContain "META-INF/protobuf-kotlin.kotlin_module" + } + + @Test + fun `keep bundling the other dependencies, including those of the runtime`() { + fatJarEntries() shouldContainAll listOf( + "com/example/Lib.class", + "com/example/gson/Gson.class", + ) + } + + @Test + fun `exclude the runtime by the dependency filter of the fat JAR`() { + val included = file("fat/build/included.txt").readLines() + + included shouldContainExactlyInAnyOrder listOf("lib-1.0.jar", "gson-1.0.jar") + } + + @Test + fun `not name the runtime in the manifest of the fat JAR`() { + JarFile(fatJarFile()).use { jar -> + val manifest = jar.manifest.shouldNotBeNull() + manifest.mainAttributes.getValue("Class-Path").shouldBeNull() + } + } + + @Test + fun `declare the runtime in the POM of the fat JAR`() { + val dependencies = pomDependencies("fat", cliFatJar) + val artifactIds = dependencies.map { it.childText("artifactId") } + + artifactIds shouldContainExactlyInAnyOrder runtimeLibraries + dependencies.forAll { it.shouldBeRuntimeLibrary() } + } + + @Test + fun `declare the runtime in the shadowed variant`() { + val metadata = ObjectMapper().readTree(file("fat/build/publications/library/module.json")) + val variants = metadata["variants"].shouldNotBeNull() + .filter { it["name"]?.asText() == shadowedVariant } + variants.shouldBeSingleton() + val dependencies = variants.single()["dependencies"].shouldNotBeNull().toList() + val modules = dependencies.map { it["module"]?.asText() } + + modules shouldContainExactlyInAnyOrder runtimeLibraries + dependencies.forAll { + it["group"]?.asText() shouldBe Protobuf.group + it["version"]?.get("requires")?.asText() shouldBe Protobuf.version + it.excludes() shouldContainExactly listOf("*" to "*") + } + } + + @Test + fun `add to the dependencies which Gradle writes into the POM`() { + // The shadowed variant of the Java component adds the runtime as optional. + val dependencies = pomDependencies("component", library) + .filter { it.childTextOrNull("optional") == null } + val artifactIds = dependencies.map { it.childText("artifactId") } + + artifactIds shouldContainExactly listOf("lib") + runtimeLibraries + dependencies.drop(1).forAll { it.shouldBeRuntimeLibrary() } + } + + @Test + fun `add to the dependencies written into the POM by hand`() { + val dependencies = pomDependencies("twin", extra) + val artifactIds = dependencies.map { it.childText("artifactId") } + + artifactIds shouldContainExactly listOf("lib") + runtimeLibraries + dependencies.drop(1).forAll { it.shouldBeRuntimeLibrary() } + } + + @Test + fun `declare the runtime in each publication it is called for`() { + val dependencies = pomDependencies("twin", defaultFatJar) + val artifactIds = dependencies.map { it.childText("artifactId") } + + artifactIds shouldContainExactlyInAnyOrder runtimeLibraries + dependencies.forAll { it.shouldBeRuntimeLibrary() } + } + + private fun fatJarFile(): File = file("fat/build/libs/fat-$moduleVersion-all.jar") + + private fun fatJarEntries(): List = + JarFile(fatJarFile()).use { jar -> jar.entries().toList().map { it.name } } + + /** + * Returns the `dependency` elements of the POM of the given [publication] of + * the given [module], ensuring the POM has a single `dependencies` element. + */ + private fun pomDependencies(module: String, publication: String): List { + val pom = file("$module/build/publications/$publication/pom-default.xml") + val project = DocumentBuilderFactory.newInstance() + .newDocumentBuilder() + .parse(pom) + .documentElement + val dependencies = project.childElements("dependencies") + dependencies.shouldBeSingleton() + return dependencies.single().childElements("dependency") + } + + /** + * Writes the local repository with the stand-ins for the Protobuf runtime + * and the other libraries of the fixture. + */ + private fun writeRepository() { + library( + Protobuf.javaLib, + entries = listOf("com/google/protobuf/RuntimeVersion.class"), + ) + library( + Protobuf.javaUtil, + entries = listOf("com/google/protobuf/util/JsonFormat.class"), + dependencies = listOf(Protobuf.javaLib, gson), + ) + library( + Protobuf.kotlin, + entries = listOf( + "com/google/protobuf/kotlin/DslList.class", + "META-INF/protobuf-kotlin.kotlin_module", + ), + dependencies = listOf(Protobuf.javaLib), + ) + library(lib, entries = listOf("com/example/Lib.class")) + library(gson, entries = listOf("com/example/gson/Gson.class")) + } + + /** + * Writes the POM and the JAR of the library with the given `group:name:version` + * [coordinates] into the local repository. + * + * @param entries The paths of the empty entries of the JAR. + * @param dependencies The `group:name:version` coordinates of the dependencies + * the POM declares. + */ + private fun library( + coordinates: String, + entries: List, + dependencies: List = emptyList(), + ) { + val (groupId, artifactId, version) = coordinates.split(':') + val path = "repository/${groupId.replace('.', '/')}/$artifactId/$version" + val declared = dependencies.joinToString("\n") { dependency -> + val (depGroup, depArtifact, depVersion) = dependency.split(':') + """ + | + | $depGroup + | $depArtifact + | $depVersion + | + """.trimMargin() + } + val dependenciesElement = if (dependencies.isEmpty()) "" else + " \n$declared\n " + write( + "$path/$artifactId-$version.pom", + """ + | + | + | 4.0.0 + | $groupId + | $artifactId + | $version + |$dependenciesElement + | + |""".trimMargin() + ) + val jar = file("$path/$artifactId-$version.jar") + JarOutputStream(jar.outputStream(), Manifest()).use { out -> + entries.forEach { + out.putNextEntry(ZipEntry(it)) + out.closeEntry() + } + } + } + + private fun writeBuild() { + write( + "settings.gradle.kts", + """ + rootProject.name = "protobuf-runtime-sample" + include("fat", "component", "twin") + """.trimIndent() + ) + write( + "build.gradle.kts", + """ + buildscript { + dependencies { + classpath(files( + ${buildSrcClasspath()} + )) + } + } + + allprojects { + group = "io.spine.test" + version = "$moduleVersion" + repositories { + maven { url = uri("${'$'}{rootDir}/repository") } + } + } + """.trimIndent() + ) + writeFatModule() + writeComponentModule() + writeTwinModule() + } + + private fun writeFatModule() { + val body = """ + |publishing { + | publications { + | create("$cliFatJar") { + | artifactId = "fat-all" + | artifact(tasks.shadowJar) + | } + | create("$library") { + | from(components["java"]) + | } + | } + |} + | + |unbundleProtobufRuntime(publication = "$cliFatJar") + | + |// Lists the files of the dependencies the fat JAR bundles, which the SBOM + |// of a fat JAR describes as bundled. + |tasks.register("$listIncludedTask") { + | val included = files(tasks.shadowJar.map { it.includedDependencies }) + | val listing = layout.buildDirectory.file("included.txt") + | inputs.files(included) + | outputs.file(listing) + | doLast { + | listing.get().asFile.writeText(included.files.joinToString("\n") { it.name }) + | } + |} + |""".trimMargin() + writeModule("fat", body) + } + + private fun writeComponentModule() { + val body = """ + |publishing { + | publications { + | create("$library") { + | from(components["java"]) + | } + | } + |} + | + |unbundleProtobufRuntime(publication = "$library") + |""".trimMargin() + writeModule("component", body, dependOnRuntime = false) + } + + private fun writeTwinModule() { + val body = """ + |publishing { + | publications { + | create("$defaultFatJar") { + | artifactId = "twin-all" + | artifact(tasks.shadowJar) + | } + | create("$extra") { + | artifactId = "twin-extra" + | artifact(tasks.shadowJar) + | pom.withXml { + | val dependency = asNode() + | .appendNode("dependencies") + | .appendNode("dependency") + | dependency.appendNode("groupId", "com.example") + | dependency.appendNode("artifactId", "lib") + | dependency.appendNode("version", "1.0") + | } + | } + | } + |} + | + |unbundleProtobufRuntime() + |unbundleProtobufRuntime(publication = "$extra") + |""".trimMargin() + writeModule("twin", body) + } + + /** + * Writes the build script of the given [module], which applies Shadow, + * depends on `com.example:lib` and, unless told otherwise, on the Protobuf runtime, + * and ends with the given [body]. + */ + private fun writeModule(module: String, body: String, dependOnRuntime: Boolean = true) { + val libs = if (dependOnRuntime) Protobuf.libs else emptyList() + val runtime = libs.joinToString("\n") { "| implementation(\"$it\")" } + val head = """ + |import io.spine.gradle.publish.unbundleProtobufRuntime + | + |plugins { + | `java-library` + | `maven-publish` + | id("com.gradleup.shadow") + |} + | + |dependencies { + | implementation("$lib") + $runtime + |} + |""".trimMargin() + write("$module/build.gradle.kts", "$head\n$body") + } + + private fun file(relativePath: String): File = projectDir.resolve(relativePath) + + private fun write(relativePath: String, text: String) { + file(relativePath).apply { + parentFile.mkdirs() + writeText(text) + } + } + + /** + * Renders the classpath with the production classes of `buildSrc` as + * arguments of `files(...)`, for injection into the build script classpath + * of the generated build. + * + * The classpath comes from the `test` task in `buildSrc/build.gradle.kts`. + * + * Each entry after the first starts a line of the generated script, so each + * is prefixed with the indentation of the template it is inserted into, which + * `trimIndent()` then removes along with the rest. + */ + private fun buildSrcClasspath(): String { + val classpath = requireNotNull(System.getProperty("buildSrc.classpath")) { + "The `buildSrc.classpath` system property is not set." + + " It is supplied by the `test` task in `buildSrc/build.gradle.kts`." + } + return classpath.split(File.pathSeparator).joinToString(",\n") { + " \"${File(it).invariantSeparatorsPath}\"" + } + } + + private companion object { + + /** The version of the modules of the fixture. */ + const val moduleVersion = "1.0.0" + + /** The name of a publication of a fat JAR, other than the default one. */ + const val cliFatJar = "cliFatJar" + + /** The name of the publication of a fat JAR, which the function uses by default. */ + const val defaultFatJar = "fatJar" + + /** The name of the publication of a fat JAR whose POM declares a dependency. */ + const val extra = "extra" + + /** The name of a publication of a Java component. */ + const val library = "library" + + /** The name of the variant of the Java component published by the Shadow plugin. */ + const val shadowedVariant = "shadowRuntimeElements" + + /** The name of the task listing the dependencies the fat JAR bundles. */ + const val listIncludedTask = "listIncluded" + + /** The library the modules of the fixture bundle. */ + const val lib = "com.example:lib:1.0" + + /** The library `protobuf-java-util` depends on, as the genuine one depends on Gson. */ + const val gson = "com.example:gson:1.0" + + /** The artifact IDs of the Protobuf runtime libraries. */ + val runtimeLibraries: List = + Protobuf.libs.map { it.substringBeforeLast(':').substringAfter(':') } + + /** Returns the name of the task writing the POM of the given [publication]. */ + fun pomTaskOf(publication: String): String = + "generatePomFileFor${publication.replaceFirstChar { it.uppercase() }}Publication" + } +} + +/** + * Asserts that this `dependency` element of a POM declares a Protobuf runtime + * library in the `runtime` scope and without transitive dependencies. + */ +private fun Element.shouldBeRuntimeLibrary() { + childText("groupId") shouldBe Protobuf.group + childText("version") shouldBe Protobuf.version + childText("scope") shouldBe "runtime" + val exclusions = childElements("exclusions") + exclusions.shouldBeSingleton() + val exclusion = exclusions.single().childElements("exclusion") + exclusion.shouldBeSingleton() + exclusion.single().childText("groupId") shouldBe "*" + exclusion.single().childText("artifactId") shouldBe "*" +} + +/** Returns the child elements of this one with the given [tag]. */ +private fun Element.childElements(tag: String): List { + val children = childNodes + return (0 until children.length) + .map { children.item(it) } + .filterIsInstance() + .filter { it.tagName == tag } +} + +/** Returns the text of the child element of this one with the given [tag]. */ +private fun Element.childText(tag: String): String = + childTextOrNull(tag).shouldNotBeNull() + +/** + * Returns the text of the child element of this one with the given [tag], + * or `null` if there is none. + */ +private fun Element.childTextOrNull(tag: String): String? = + childElements(tag).firstOrNull()?.textContent + +/** + * Returns the `group` and `module` of each exclusion of this dependency of + * the Gradle module metadata. + */ +private fun JsonNode.excludes(): List> = + this["excludes"]?.map { it["group"]?.asText() to it["module"]?.asText() }.orEmpty() diff --git a/buildSrc/src/test/kotlin/io/spine/gradle/publish/PublicationChecksumsIgTest.kt b/buildSrc/src/test/kotlin/io/spine/gradle/publish/PublicationChecksumsIgTest.kt index b27f6b5..48a1b66 100644 --- a/buildSrc/src/test/kotlin/io/spine/gradle/publish/PublicationChecksumsIgTest.kt +++ b/buildSrc/src/test/kotlin/io/spine/gradle/publish/PublicationChecksumsIgTest.kt @@ -79,7 +79,7 @@ internal class PublicationChecksumsIgTest { // `javadocJar` of `spinePublishing` is wired to Dokka, which // this fixture does not apply: the manifest is what is under // test, not the documentation toolchain. - tasks.register("dokkaGeneratePublicationJavadoc") + $generatorStub } spinePublishing { @@ -166,6 +166,34 @@ internal class PublicationChecksumsIgTest { names shouldContain "spine-api-$version-sources.jar" } + /** + * A module that generates no documentation still publishes the JARs that + * would hold it: `disableDocumentationTasks()` stops the generators, not + * the JARs, so each is published containing only a manifest. + * + * Were a JAR stopped along with its generator, the publication would go on + * declaring a file that nothing writes. Publishing to Maven Local tolerates + * that today, so `collectPublicationChecksums` — the first task to read + * every declared file — is where such a module fails the build. + */ + @Test + fun `cover a module that generates no documentation`() { + val script = file("build.gradle.kts") + script.writeText( + script.readText().replace( + generatorStub, + "$generatorStub\n disableDocumentationTasks()" + ) + ) + + runGradle(aggregator, "publishAllPublicationsToStageRepository") + + val names = manifestEntries().map { it.name }.sorted() + names shouldContain "spine-api-$version-javadoc.jar" + names shouldContain "spine-api-$version-html-docs.jar" + names shouldContainExactly publishedFileNames() + } + /** * Maven deploys a version ending in `-SNAPSHOT` under a timestamped name * assigned at upload time, so the names derived from the publication belong @@ -272,6 +300,16 @@ internal class PublicationChecksumsIgTest { const val version = "1.0.0" + /** + * The statement of the fixture that registers a stub of the Dokka task + * feeding `javadocJar`. + * + * It anchors the per-test additions to the configuration shared by + * the modules. The fixture is written from this constant too, so that + * an edit of one cannot leave the other matching nothing. + */ + const val generatorStub = """tasks.register("dokkaGeneratePublicationJavadoc")""" + val sidecars = listOf(".md5", ".sha1", ".sha256", ".sha512") } } diff --git a/buildSrc/src/test/kotlin/io/spine/gradle/publish/PublicationHandlerIgTest.kt b/buildSrc/src/test/kotlin/io/spine/gradle/publish/PublicationHandlerIgTest.kt new file mode 100644 index 0000000..67f5572 --- /dev/null +++ b/buildSrc/src/test/kotlin/io/spine/gradle/publish/PublicationHandlerIgTest.kt @@ -0,0 +1,226 @@ +/* + * Copyright 2026 CodeMatters, Lda. + * + * 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 io.spine.gradle.publish + +import io.kotest.matchers.string.shouldContain +import io.kotest.matchers.string.shouldNotContain +import java.io.File +import org.gradle.testkit.runner.GradleRunner +import org.junit.jupiter.api.BeforeAll +import org.junit.jupiter.api.DisplayName +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.TestInstance +import org.junit.jupiter.api.io.TempDir + +/** + * Verifies that [PublicationHandler] silences the warnings that Gradle prints when + * it generates the POMs of modules applying `java-test-fixtures`, in a real + * multi-module build run via Gradle TestKit. + * + * The fixture is built once for the whole class, and each case inspects the output + * of the build. All the modules of the fixture apply `java-test-fixtures`. + * The fixture has: + * - `library` — a module published in the standard way. + * - `plugin` — a module applying `java-gradle-plugin`, listed by the root project + * in `modulesWithCustomPublishing`. Its `pluginMaven` publication is created + * after the handler is applied. + * - `unhandled` — a module that `spinePublishing` does not publish. It declares + * a publication of the `java` component itself, so that the fixture shows + * the warnings the other modules would print. + */ +@DisplayName("`PublicationHandler` should") +@TestInstance(TestInstance.Lifecycle.PER_CLASS) +internal class PublicationHandlerIgTest { + + private lateinit var projectDir: File + private lateinit var output: String + + @BeforeAll + fun buildFixture(@TempDir dir: File) { + projectDir = dir + writeBuild() + output = GradleRunner.create() + .withProjectDir(projectDir) + .withArguments( + pomTask(library, standardPublication), + pomTask(pluginModule, pluginPublication), + pomTask(unhandled, unhandledPublication), + "--stacktrace", + ) + .build() + .output + } + + @Test + fun `silence the warnings about test fixtures for a standard publication`() { + output shouldNotContain warningsHeader(standardPublication) + } + + @Test + fun `silence the warnings about test fixtures for a publication added by a plugin`() { + output shouldNotContain warningsHeader(pluginPublication) + } + + @Test + fun `leave the warnings for a publication of a module it does not handle`() { + val header = warningsHeader(unhandledPublication) + output shouldContain header + val warnings = output.substringAfter(header) + warnings shouldContain "Variant testFixturesApiElements" + warnings shouldContain "Variant testFixturesRuntimeElements" + } + + private fun writeBuild() { + write( + "settings.gradle.kts", + """ + rootProject.name = "test-fixtures-sample" + include("$library", "$pluginModule", "$unhandled") + """.trimIndent() + ) + write( + "build.gradle.kts", + """ + buildscript { + dependencies { + classpath(files( + ${buildSrcClasspath()} + )) + } + } + + import io.spine.gradle.publish.spinePublishing + + allprojects { + group = "io.spine.test" + version = "1.0.0" + } + + spinePublishing { + modules = setOf("$library") + modulesWithCustomPublishing = setOf("$pluginModule") + destinations = emptySet() + } + """.trimIndent() + ) + write( + "$library/build.gradle.kts", + """ + plugins { + `java-library` + `java-test-fixtures` + } + + // `javadocJar` of `spinePublishing` is wired to Dokka, which + // this fixture does not apply: only the POMs are under test. + tasks.register("dokkaGeneratePublicationJavadoc") + """.trimIndent() + ) + write( + "$pluginModule/build.gradle.kts", + """ + plugins { + `java-gradle-plugin` + `maven-publish` + `java-test-fixtures` + } + + gradlePlugin { + plugins { + create("sample") { + id = "io.spine.sample" + implementationClass = "io.spine.sample.SamplePlugin" + } + } + } + """.trimIndent() + ) + write( + "$unhandled/build.gradle.kts", + """ + plugins { + `java-library` + `maven-publish` + `java-test-fixtures` + } + + publishing { + publications { + create("$unhandledPublication") { + from(components["java"]) + } + } + } + """.trimIndent() + ) + } + + private fun file(relativePath: String): File = projectDir.resolve(relativePath) + + private fun write(relativePath: String, text: String) { + file(relativePath).apply { + parentFile.mkdirs() + writeText(text) + } + } + + /** + * Renders the classpath with the production classes of `buildSrc` as + * arguments of `files(...)`, for injection into the build script classpath + * of the generated build. + * + * The classpath comes from the `test` task in `buildSrc/build.gradle.kts`. + */ + private fun buildSrcClasspath(): String { + val classpath = requireNotNull(System.getProperty("buildSrc.classpath")) { + "The `buildSrc.classpath` system property is not set." + + " It is supplied by the `test` task in `buildSrc/build.gradle.kts`." + } + return classpath.split(File.pathSeparator).joinToString(",\n") { + " \"${File(it).invariantSeparatorsPath}\"" + } + } + + private companion object { + + /** The module published in the standard way. */ + const val library = "library" + + /** The module applying `java-gradle-plugin`, published in a custom way. */ + const val pluginModule = "plugin" + + /** The module not published by `spinePublishing`. */ + const val unhandled = "unhandled" + + /* + * The names of the publications, as given by the code that creates them. + */ + const val standardPublication = StandardJavaPublicationHandler.PUBLICATION_NAME + const val pluginPublication = "pluginMaven" + const val unhandledPublication = "unhandled" + + fun pomTask(module: String, publication: String): String { + val name = publication.replaceFirstChar { it.uppercase() } + return ":$module:generatePomFileFor${name}Publication" + } + + /** + * Returns the line with which Gradle starts the POM warnings + * for the given [publication]. + */ + fun warningsHeader(publication: String): String = + "Maven publication '$publication' pom metadata warnings" + } +} diff --git a/config b/config index a0cbbbf..604420c 160000 --- a/config +++ b/config @@ -1 +1 @@ -Subproject commit a0cbbbfe66c12475224563439fb6deb3da71ba58 +Subproject commit 604420cd7eab82b382c9a5c1d812be454552c27c diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 2e7bb9f..91c4fc6 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-9.8.1-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-9.8.2-bin.zip networkTimeout=10000 retries=0 retryBackOffMs=500 diff --git a/init-submodules b/init-submodules index 95b916b..64bb085 100755 --- a/init-submodules +++ b/init-submodules @@ -17,10 +17,10 @@ # (distributed by `config`), so `git worktree add` always checks it out — it can # therefore bring `config` itself into existence. # -# It initializes ONLY submodules that are BOTH: +# It acts ONLY on submodules that are BOTH: # -# * not yet checked out — those `git submodule status` marks with a leading `-`, -# at the commit the branch pins; and +# * not yet checked out — those `git submodule status` marks with a leading +# `-`; and # # * config-managed — `config` itself (the bootstrap target `pull` lives inside, # which carries no tracked `branch` in a consumer's `.gitmodules`), plus every @@ -28,6 +28,33 @@ # the rule `./config/pull` uses to decide what it floats, so the two scripts # can never disagree about what is shared. # +# Such a submodule is initialized and then advanced to the tip of its tracked +# branch, the way `./config/pull` floats it — NOT left at the commit the +# superproject pins. That pin is not a version anyone maintains: `.gitmodules` +# declares `ignore = all` for `.agents/shared`, which hides the submodule from +# `git status` and `git diff`, and `./config/pull` floats the on-disk copy without +# ever committing the moved gitlink. The pin therefore still holds the value it +# had on the day the submodule was adopted; an audit of all 19 Spine consumer +# repositories on 2026-10-16 found every one of them months stale. Materializing +# it hands a fresh worktree, CI checkout, or cloud session hook scripts, skills, +# and guidelines that are months out of date. +# +# A submodule may declare `branch = .`, which gitmodules(5) defines as the branch +# the superproject is on rather than a branch name. It is resolved before it +# reaches a refspec, because `git fetch origin .` is a `fatal: invalid refspec`. +# Nothing in Spine declares it today — `.agents/shared` tracks `agents`' `master` +# whatever branch the consumer is on — but it is valid in any `.gitmodules`. +# +# Neither the clone nor the float can fail the session start. With no network at +# all the clone is what fails: the submodule is left uninitialized and the +# symlinks keep dangling until a run that has a network, exactly as before this +# script floated anything. A float that fails after a successful clone — a branch +# the remote does not have, a fetch that dies midway, a local branch that is not +# a fast-forward — warns and leaves the submodule wherever the steps that did +# succeed put it: at worst the pin, a usable, if older, tree. The submodule is +# checked out by then, so later runs no longer see a `-` line for it and never +# retry the float — which is why the warning points at `./config/pull`. +# # Consumer-owned submodules (a Hugo theme, a vendored library, documentation # examples, ...) declare no tracked branch and are deliberately left untouched. # Because a `SessionStart` hook runs this script automatically on every session, @@ -35,15 +62,14 @@ # a submodule this project does not manage, on every single start. They are # skipped (noted on stderr). # -# Submodules already present are left exactly as they are, so a tree that floated -# `config` / `.agents/shared` to a branch tip via `./config/pull` is never -# silently rewound to the pin. That makes the script idempotent and safe to run on -# every session start. +# Submodules already present are left exactly as they are, neither rewound to the +# pin nor advanced. That keeps the script idempotent, keeps the runs that find +# nothing missing free of network access, and never disturbs a tree whose +# submodules someone deliberately parked on a particular commit. Run +# `./config/pull` to float those. # -# It does NOT float submodules to their branch tips — run `./config/pull` -# afterwards for that. Unlike `pull`, it depends on no pre-existing `config` -# submodule, so it can bootstrap a bare worktree where `./config/pull` does not -# yet exist. +# Unlike `pull`, this script depends on no pre-existing `config` submodule, so it +# can bootstrap a bare worktree where `./config/pull` does not yet exist. # ################################################################################ @@ -133,19 +159,29 @@ cd "$root" || exit 0 # Nothing to do in a repo without submodules. [ -f .gitmodules ] || exit 0 -# The set of config-managed submodule paths: `config` itself (handled specially — -# it carries no tracked branch, exactly as in `./config/pull`), plus every -# submodule declaring a tracked `branch` in `.gitmodules`. Mirrors `pull`'s rule. -config_managed_paths() { - printf '%s\n' 'config' +# The config-managed submodules, as `pathbranch` lines: every submodule that +# declares a tracked `branch` in `.gitmodules`, plus `config` itself — which +# carries no tracked branch in a consumer's `.gitmodules`, and which +# `./config/pull` floats to `master` in its step 1. Mirrors `pull`'s rule. The +# declared entries come first, so a `.gitmodules` that does give `config` a +# tracked branch wins over that default. +config_managed() { git config -f .gitmodules --get-regexp '^submodule\..*\.branch$' 2>/dev/null \ - | while read -r key _branch; do + | while read -r key branch; do name=${key#submodule.}; name=${name%.branch} - git config -f .gitmodules --get "submodule.$name.path" 2>/dev/null + path=$(git config -f .gitmodules --get "submodule.$name.path" 2>/dev/null) || continue + printf '%s\t%s\n' "$path" "$branch" done + printf '%s\t%s\n' 'config' 'master' } -managed=$(config_managed_paths | sort -u) +managed=$(config_managed) + +# The branch the submodule at `$1` tracks; empty when that path is not +# config-managed at all. The first match wins, as noted above. +tracked_branch() { + printf '%s\n' "$managed" | awk -F'\t' -v path="$1" '$1 == path { print $2; exit }' +} # `git submodule status` prefixes each uninitialized submodule with `-`; an # initialized one starts with a space (at the pinned commit) or `+` (ahead of it). @@ -153,13 +189,97 @@ managed=$(config_managed_paths | sort -u) # that path is config-managed. git submodule status 2>/dev/null | awk '$1 ~ /^-/ { print $2 }' | while read -r path; do [ -n "$path" ] || continue - if printf '%s\n' "$managed" | grep -qxF -- "$path"; then - echo "init-submodules: initializing '$path'" - git submodule update --init --recursive -- "$path" \ - || echo "init-submodules: WARNING — could not initialize '$path' (offline?)." >&2 - else + branch=$(tracked_branch "$path") + if [ -z "$branch" ]; then echo "init-submodules: skipping consumer-owned '$path' (not config-managed)." >&2 + continue + fi + echo "init-submodules: initializing '$path'" + git submodule update --init --recursive -- "$path" &2 + continue + } + # `.gitmodules` may declare `branch = .`, which gitmodules(5) defines as the + # branch the superproject itself is on. That is a sentinel, not a ref: passed + # through, it dies with `fatal: invalid refspec '.'`, and because the clone + # has already succeeded by then the submodule would keep the pin and never be + # retried. Resolve it to the current branch name. A detached superproject has + # no name to inherit, so the float is skipped and the pin kept — the one case + # where `./config/pull` is the only way forward, once on a branch. + if [ "$branch" = "." ]; then + # `git branch --show-current` prints the name exactly, and prints nothing + # when `HEAD` is detached. `git rev-parse --abbrev-ref HEAD` cannot stand + # in: it shortens to a *non-ambiguous* name, so a superproject carrying + # both a branch and a tag called `foo` yields `heads/foo`; the fetch + # then succeeds but the checkout fails, leaving this freshly + # initialized submodule stale and never retried. `./config/pull` + # resolves it the same way, for the same reason. + branch=$(git branch --show-current 2>/dev/null) + if [ -z "$branch" ]; then + echo "init-submodules: WARNING — '$path' tracks the superproject's" \ + "branch ('.'), which is detached here; left at the pin. Run" \ + "'./config/pull' from a branch to float it." >&2 + continue + fi fi + # What that just checked out is the superproject's pin, which nobody + # maintains (see the header). Advance the fresh checkout to the tip of its + # tracked branch, leaving it ON the branch rather than in a detached `HEAD` — + # the same three steps `./config/pull` takes in its step 2, both scripts + # naming the fetch destination and the checkout start point, for the two + # reasons below. A failure leaves the submodule wherever the steps that did + # succeed put it, so the warning promises no particular commit, as `pull`'s + # does not. + # + # The fetch names its destination. A bare `git fetch origin ` relies + # on the refspec configured for the remote to update + # `refs/remotes/origin/` opportunistically as well, which a full + # clone's does. But a submodule declaring `shallow = true` in `.gitmodules` + # is cloned single-branch (a shallow clone implies `--single-branch`), as + # `+refs/heads/:refs/remotes/origin/`, so any other tracked + # branch lands in `FETCH_HEAD` alone, `refs/remotes/origin/` never + # appears, and the checkout below fails. Spelling the refspec out makes the + # float work whatever refspec the clone carries, and the leading `+` matches + # what a default clone configures. + # + # The checkout asks whether the branch exists locally rather than letting Git + # work it out, because both answers are otherwise wrong in a reachable case. + # A fresh clone has a local branch only for the default branch, so `-b` alone + # would fail with `already exists` on the common path. And plain + # `git checkout ` is not a reliable substitute: with no local branch + # of that name it guesses one from a remote-tracking ref, considering only + # refs the remote's fetch refspec covers — so in the single-branch clone + # above it fails even though the explicit fetch did create + # `refs/remotes/origin/` — and if the submodule carries a *tag* of + # that name it quietly resolves the tag and detaches `HEAD` instead, which + # the `--ff-only` below then fast-forwards to the right commit on no branch + # at all. Naming the start point avoids both. + # + # `merge --ff-only` is kept after either path: a local branch that has + # diverged from `origin/` is reported rather than overwritten. + # Nothing here force-moves a ref except the remote-tracking ref the fetch + # owns, which a default clone force-updates anyway. + # + # It merges `refs/remotes/origin/`, not the `origin/` + # shorthand, for the reason the checkout above spells a ref out too. + # gitrevisions(7) resolves a bare name through `refs/tags/` BEFORE + # `refs/remotes/`, so a tag literally named `origin/` wins the + # shorthand — and then this merge would fast-forward the branch the + # checkout just placed exactly onto whatever that tag points at, reporting + # success. Every ref in the chain is therefore fully qualified. + echo "init-submodules: floating '$path' -> origin/$branch" + ( cd "$path" \ + && git fetch --quiet origin \ + "+refs/heads/$branch:refs/remotes/origin/$branch" \ + && if git show-ref --verify --quiet "refs/heads/$branch"; then \ + git checkout --quiet "$branch"; \ + else \ + git checkout --quiet -b "$branch" \ + "refs/remotes/origin/$branch"; \ + fi \ + && git merge --quiet --ff-only "refs/remotes/origin/$branch" ) &2 done # Route Git hooks to the shared hooks directory so the secret-scan `pre-commit` From 9e2596ee131cf2be478719e6b685430b601a8471 Mon Sep 17 00:00:00 2001 From: alexander-yevsyukov Date: Wed, 21 Oct 2026 16:37:17 +0100 Subject: [PATCH 12/17] Update local dependency pins --- buildSrc/src/main/kotlin/io/spine/dependency/local/Base.kt | 2 +- buildSrc/src/main/kotlin/io/spine/dependency/local/Compiler.kt | 2 +- .../main/kotlin/io/spine/dependency/local/CoreJvmCompiler.kt | 2 +- .../src/main/kotlin/io/spine/dependency/local/Validation.kt | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/buildSrc/src/main/kotlin/io/spine/dependency/local/Base.kt b/buildSrc/src/main/kotlin/io/spine/dependency/local/Base.kt index 45c1d2f..baaf5c7 100644 --- a/buildSrc/src/main/kotlin/io/spine/dependency/local/Base.kt +++ b/buildSrc/src/main/kotlin/io/spine/dependency/local/Base.kt @@ -24,7 +24,7 @@ package io.spine.dependency.local "unused" /* Some subprojects do not use all Base artifacts. */, ) object Base { - const val version = "2.0.0-SNAPSHOT.461" + const val version = "2.0.0-SNAPSHOT.462" const val versionForBuildScript = "2.0.0-SNAPSHOT.461" const val group = Spine.group private const val prefix = "spine" diff --git a/buildSrc/src/main/kotlin/io/spine/dependency/local/Compiler.kt b/buildSrc/src/main/kotlin/io/spine/dependency/local/Compiler.kt index 137e830..1582193 100644 --- a/buildSrc/src/main/kotlin/io/spine/dependency/local/Compiler.kt +++ b/buildSrc/src/main/kotlin/io/spine/dependency/local/Compiler.kt @@ -60,7 +60,7 @@ object Compiler : Dependency() { * The version of the Compiler dependencies. */ override val version: String - private const val fallbackVersion = "2.0.0-SNAPSHOT.069" + private const val fallbackVersion = "2.0.0-SNAPSHOT.080" /** * The distinct version of the Compiler used by other build tools. diff --git a/buildSrc/src/main/kotlin/io/spine/dependency/local/CoreJvmCompiler.kt b/buildSrc/src/main/kotlin/io/spine/dependency/local/CoreJvmCompiler.kt index 1af2694..087a2fa 100644 --- a/buildSrc/src/main/kotlin/io/spine/dependency/local/CoreJvmCompiler.kt +++ b/buildSrc/src/main/kotlin/io/spine/dependency/local/CoreJvmCompiler.kt @@ -39,7 +39,7 @@ object CoreJvmCompiler { /** * The version to be used for integration tests. */ - const val version = "2.0.0-SNAPSHOT.097" + const val version = "2.0.0-SNAPSHOT.099" /** * The ID of the Gradle plugin. diff --git a/buildSrc/src/main/kotlin/io/spine/dependency/local/Validation.kt b/buildSrc/src/main/kotlin/io/spine/dependency/local/Validation.kt index 155cbbc..1be9aff 100644 --- a/buildSrc/src/main/kotlin/io/spine/dependency/local/Validation.kt +++ b/buildSrc/src/main/kotlin/io/spine/dependency/local/Validation.kt @@ -27,7 +27,7 @@ object Validation { /** * The version of the Validation library artifacts. */ - const val version = "2.0.0-SNAPSHOT.464" + const val version = "2.0.0-SNAPSHOT.469" const val group = Spine.toolsGroup private const val prefix = "validation" From 1a0ede3d66ec34b7c26ad2c1992327cef18ae2cd Mon Sep 17 00:00:00 2001 From: alexander-yevsyukov Date: Wed, 21 Oct 2026 17:39:55 +0100 Subject: [PATCH 13/17] Update dependency reports --- docs/dependencies/dependencies.md | 54 +++++++++++++++---------------- docs/dependencies/pom.xml | 22 ++++++------- 2 files changed, 38 insertions(+), 38 deletions(-) diff --git a/docs/dependencies/dependencies.md b/docs/dependencies/dependencies.md index dd4e213..f13c21e 100644 --- a/docs/dependencies/dependencies.md +++ b/docs/dependencies/dependencies.md @@ -52,15 +52,15 @@ * **Project URL:** [https://github.com/JetBrains/java-annotations](https://github.com/JetBrains/java-annotations) * **License:** [The Apache Software License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) -1. **Group** : org.jetbrains.kotlin. **Name** : kotlin-bom. **Version** : 2.4.21. +1. **Group** : org.jetbrains.kotlin. **Name** : kotlin-bom. **Version** : 2.4.10. * **Project URL:** [https://kotlinlang.org/](https://kotlinlang.org/) * **License:** [The Apache Software License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) -1. **Group** : org.jetbrains.kotlin. **Name** : kotlin-reflect. **Version** : 2.4.21. +1. **Group** : org.jetbrains.kotlin. **Name** : kotlin-reflect. **Version** : 2.4.10. * **Project URL:** [https://kotlinlang.org/](https://kotlinlang.org/) * **License:** [Apache-2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) -1. **Group** : org.jetbrains.kotlin. **Name** : kotlin-stdlib. **Version** : 2.4.21. +1. **Group** : org.jetbrains.kotlin. **Name** : kotlin-stdlib. **Version** : 2.4.10. * **Project URL:** [https://kotlinlang.org/](https://kotlinlang.org/) * **License:** [Apache-2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) @@ -323,11 +323,11 @@ * **Project URL:** [https://github.com/korlibs/korge-next](https://github.com/korlibs/korge-next) * **License:** [MIT](https://raw.githubusercontent.com/korlibs/korge-next/master/korge/LICENSE.txt) -1. **Group** : com.squareup. **Name** : kotlinpoet. **Version** : 2.4.0. +1. **Group** : com.squareup. **Name** : kotlinpoet. **Version** : 2.3.0. * **Project URL:** [https://github.com/square/kotlinpoet](https://github.com/square/kotlinpoet) * **License:** [The Apache Software License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) -1. **Group** : com.squareup. **Name** : kotlinpoet-jvm. **Version** : 2.4.0. +1. **Group** : com.squareup. **Name** : kotlinpoet-jvm. **Version** : 2.3.0. * **Project URL:** [https://github.com/square/kotlinpoet](https://github.com/square/kotlinpoet) * **License:** [The Apache Software License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) @@ -691,7 +691,7 @@ * **Project URL:** [https://github.com/JetBrains/intellij-deps-trove4j](https://github.com/JetBrains/intellij-deps-trove4j) * **License:** [GNU LESSER GENERAL PUBLIC LICENSE 2.1](https://www.gnu.org/licenses/old-licenses/lgpl-2.1.en.html) -1. **Group** : org.jetbrains.kotlin. **Name** : kotlin-bom. **Version** : 2.4.21. +1. **Group** : org.jetbrains.kotlin. **Name** : kotlin-bom. **Version** : 2.4.10. * **Project URL:** [https://kotlinlang.org/](https://kotlinlang.org/) * **License:** [The Apache Software License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) @@ -699,11 +699,11 @@ * **Project URL:** [https://kotlinlang.org/](https://kotlinlang.org/) * **License:** [Apache-2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) -1. **Group** : org.jetbrains.kotlin. **Name** : kotlin-build-tools-api. **Version** : 2.4.21. +1. **Group** : org.jetbrains.kotlin. **Name** : kotlin-build-tools-api. **Version** : 2.4.10. * **Project URL:** [https://kotlinlang.org/](https://kotlinlang.org/) * **License:** [Apache-2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) -1. **Group** : org.jetbrains.kotlin. **Name** : kotlin-build-tools-compat. **Version** : 2.4.21. +1. **Group** : org.jetbrains.kotlin. **Name** : kotlin-build-tools-compat. **Version** : 2.4.10. * **Project URL:** [https://kotlinlang.org/](https://kotlinlang.org/) * **License:** [Apache-2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) @@ -711,7 +711,7 @@ * **Project URL:** [https://kotlinlang.org/](https://kotlinlang.org/) * **License:** [Apache-2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) -1. **Group** : org.jetbrains.kotlin. **Name** : kotlin-build-tools-cri-impl. **Version** : 2.4.21. +1. **Group** : org.jetbrains.kotlin. **Name** : kotlin-build-tools-cri-impl. **Version** : 2.4.10. * **Project URL:** [https://kotlinlang.org/](https://kotlinlang.org/) * **License:** [Apache-2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) @@ -719,7 +719,7 @@ * **Project URL:** [https://kotlinlang.org/](https://kotlinlang.org/) * **License:** [Apache-2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) -1. **Group** : org.jetbrains.kotlin. **Name** : kotlin-build-tools-impl. **Version** : 2.4.21. +1. **Group** : org.jetbrains.kotlin. **Name** : kotlin-build-tools-impl. **Version** : 2.4.10. * **Project URL:** [https://kotlinlang.org/](https://kotlinlang.org/) * **License:** [Apache-2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) @@ -731,7 +731,7 @@ * **Project URL:** [https://kotlinlang.org/](https://kotlinlang.org/) * **License:** [Apache-2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) -1. **Group** : org.jetbrains.kotlin. **Name** : kotlin-compiler-embeddable. **Version** : 2.4.21. +1. **Group** : org.jetbrains.kotlin. **Name** : kotlin-compiler-embeddable. **Version** : 2.4.10. * **Project URL:** [https://kotlinlang.org/](https://kotlinlang.org/) * **License:** [Apache-2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) @@ -739,7 +739,7 @@ * **Project URL:** [https://kotlinlang.org/](https://kotlinlang.org/) * **License:** [Apache-2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) -1. **Group** : org.jetbrains.kotlin. **Name** : kotlin-compiler-runner. **Version** : 2.4.21. +1. **Group** : org.jetbrains.kotlin. **Name** : kotlin-compiler-runner. **Version** : 2.4.10. * **Project URL:** [https://kotlinlang.org/](https://kotlinlang.org/) * **License:** [Apache-2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) @@ -747,7 +747,7 @@ * **Project URL:** [https://kotlinlang.org/](https://kotlinlang.org/) * **License:** [Apache-2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) -1. **Group** : org.jetbrains.kotlin. **Name** : kotlin-daemon-client. **Version** : 2.4.21. +1. **Group** : org.jetbrains.kotlin. **Name** : kotlin-daemon-client. **Version** : 2.4.10. * **Project URL:** [https://kotlinlang.org/](https://kotlinlang.org/) * **License:** [Apache-2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) @@ -759,15 +759,15 @@ * **Project URL:** [https://kotlinlang.org/](https://kotlinlang.org/) * **License:** [Apache-2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) -1. **Group** : org.jetbrains.kotlin. **Name** : kotlin-daemon-embeddable. **Version** : 2.4.21. +1. **Group** : org.jetbrains.kotlin. **Name** : kotlin-daemon-embeddable. **Version** : 2.4.10. * **Project URL:** [https://kotlinlang.org/](https://kotlinlang.org/) * **License:** [Apache-2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) -1. **Group** : org.jetbrains.kotlin. **Name** : kotlin-klib-commonizer-embeddable. **Version** : 2.4.21. +1. **Group** : org.jetbrains.kotlin. **Name** : kotlin-klib-commonizer-embeddable. **Version** : 2.4.10. * **Project URL:** [https://kotlinlang.org/](https://kotlinlang.org/) * **License:** [Apache-2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) -1. **Group** : org.jetbrains.kotlin. **Name** : kotlin-reflect. **Version** : 2.4.21. +1. **Group** : org.jetbrains.kotlin. **Name** : kotlin-reflect. **Version** : 2.4.10. * **Project URL:** [https://kotlinlang.org/](https://kotlinlang.org/) * **License:** [Apache-2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) @@ -779,43 +779,43 @@ * **Project URL:** [https://kotlinlang.org/](https://kotlinlang.org/) * **License:** [Apache-2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) -1. **Group** : org.jetbrains.kotlin. **Name** : kotlin-script-runtime. **Version** : 2.4.21. +1. **Group** : org.jetbrains.kotlin. **Name** : kotlin-script-runtime. **Version** : 2.4.10. * **Project URL:** [https://kotlinlang.org/](https://kotlinlang.org/) * **License:** [Apache-2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) -1. **Group** : org.jetbrains.kotlin. **Name** : kotlin-scripting-common. **Version** : 2.4.21. +1. **Group** : org.jetbrains.kotlin. **Name** : kotlin-scripting-common. **Version** : 2.4.10. * **Project URL:** [https://kotlinlang.org/](https://kotlinlang.org/) * **License:** [Apache-2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) -1. **Group** : org.jetbrains.kotlin. **Name** : kotlin-scripting-compiler-embeddable. **Version** : 2.4.21. +1. **Group** : org.jetbrains.kotlin. **Name** : kotlin-scripting-compiler-embeddable. **Version** : 2.4.10. * **Project URL:** [https://kotlinlang.org/](https://kotlinlang.org/) * **License:** [Apache-2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) -1. **Group** : org.jetbrains.kotlin. **Name** : kotlin-scripting-compiler-impl-embeddable. **Version** : 2.4.21. +1. **Group** : org.jetbrains.kotlin. **Name** : kotlin-scripting-compiler-impl-embeddable. **Version** : 2.4.10. * **Project URL:** [https://kotlinlang.org/](https://kotlinlang.org/) * **License:** [Apache-2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) -1. **Group** : org.jetbrains.kotlin. **Name** : kotlin-scripting-jvm. **Version** : 2.4.21. +1. **Group** : org.jetbrains.kotlin. **Name** : kotlin-scripting-jvm. **Version** : 2.4.10. * **Project URL:** [https://kotlinlang.org/](https://kotlinlang.org/) * **License:** [Apache-2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) -1. **Group** : org.jetbrains.kotlin. **Name** : kotlin-stdlib. **Version** : 2.4.21. +1. **Group** : org.jetbrains.kotlin. **Name** : kotlin-stdlib. **Version** : 2.4.10. * **Project URL:** [https://kotlinlang.org/](https://kotlinlang.org/) * **License:** [Apache-2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) -1. **Group** : org.jetbrains.kotlin. **Name** : kotlin-stdlib-common. **Version** : 2.4.21. +1. **Group** : org.jetbrains.kotlin. **Name** : kotlin-stdlib-common. **Version** : 2.4.10. * **Project URL:** [https://kotlinlang.org/](https://kotlinlang.org/) * **License:** [Apache-2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) -1. **Group** : org.jetbrains.kotlin. **Name** : kotlin-stdlib-jdk7. **Version** : 2.4.21. +1. **Group** : org.jetbrains.kotlin. **Name** : kotlin-stdlib-jdk7. **Version** : 2.4.10. * **Project URL:** [https://kotlinlang.org/](https://kotlinlang.org/) * **License:** [Apache-2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) -1. **Group** : org.jetbrains.kotlin. **Name** : kotlin-stdlib-jdk8. **Version** : 2.4.21. +1. **Group** : org.jetbrains.kotlin. **Name** : kotlin-stdlib-jdk8. **Version** : 2.4.10. * **Project URL:** [https://kotlinlang.org/](https://kotlinlang.org/) * **License:** [Apache-2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) -1. **Group** : org.jetbrains.kotlin. **Name** : kotlin-tooling-core. **Version** : 2.4.21. +1. **Group** : org.jetbrains.kotlin. **Name** : kotlin-tooling-core. **Version** : 2.4.10. * **Project URL:** [https://kotlinlang.org/](https://kotlinlang.org/) * **License:** [Apache-2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) @@ -1028,6 +1028,6 @@ The dependencies distributed under several licenses, are used according their commercial-use-friendly license. -This report was generated on **Fri Oct 16 23:36:52 WEST 2026** using +This report was generated on **Wed Oct 21 17:39:24 WEST 2026** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). \ No newline at end of file diff --git a/docs/dependencies/pom.xml b/docs/dependencies/pom.xml index ae599d7..68605fb 100644 --- a/docs/dependencies/pom.xml +++ b/docs/dependencies/pom.xml @@ -26,7 +26,7 @@ all modules and does not describe the project structure per-subproject. io.spine spine-base - 2.0.0-SNAPSHOT.461 + 2.0.0-SNAPSHOT.462 compile @@ -38,13 +38,13 @@ all modules and does not describe the project structure per-subproject. io.spine spine-validation-jvm-runtime - 2.0.0-SNAPSHOT.465 + 2.0.0-SNAPSHOT.469 compile org.jetbrains.kotlin kotlin-stdlib - 2.4.21 + 2.4.10 compile @@ -68,7 +68,7 @@ all modules and does not describe the project structure per-subproject. io.spine.tools base-testlib - 2.0.0-SNAPSHOT.214 + 2.0.0-SNAPSHOT.215 test @@ -140,12 +140,12 @@ all modules and does not describe the project structure per-subproject. io.spine.tools compiler-cli-all - 2.0.0-SNAPSHOT.074 + 2.0.0-SNAPSHOT.080 io.spine.tools compiler-protoc-plugin - 2.0.0-SNAPSHOT.074 + 2.0.0-SNAPSHOT.080 io.spine.tools @@ -170,7 +170,7 @@ all modules and does not describe the project structure per-subproject. io.spine.tools validation-java-bundle - 2.0.0-SNAPSHOT.465 + 2.0.0-SNAPSHOT.469 net.sourceforge.pmd @@ -225,22 +225,22 @@ all modules and does not describe the project structure per-subproject. org.jetbrains.kotlin kotlin-build-tools-compat - 2.4.21 + 2.4.10 org.jetbrains.kotlin kotlin-build-tools-impl - 2.4.21 + 2.4.10 org.jetbrains.kotlin kotlin-klib-commonizer-embeddable - 2.4.21 + 2.4.10 org.jetbrains.kotlin kotlin-scripting-compiler-embeddable - 2.4.21 + 2.4.10 From f07c3de9079126e820f0d244b0a17c1d9767c702 Mon Sep 17 00:00:00 2001 From: alexander-yevsyukov Date: Thu, 22 Oct 2026 15:04:16 +0100 Subject: [PATCH 14/17] Update shared agent tooling and config (./config/pull) Co-Authored-By: Claude Opus 5.5 --- .github/workflows/publish.yml | 2 +- .../dependency/lib/OpenTelemetryKotlin.kt | 20 + .../kotlin/io/spine/dependency/local/Base.kt | 2 +- .../io/spine/dependency/local/Compiler.kt | 2 +- .../spine/dependency/local/CoreJvmCompiler.kt | 2 +- .../io/spine/dependency/local/Validation.kt | 2 +- .../gradle/publish/CheckVersionIncrement.kt | 14 +- .../io/spine/gradle/publish/GitHubPackages.kt | 37 +- .../io/spine/gradle/publish/IncrementGuard.kt | 8 - .../io/spine/gradle/publish/MavenMetadata.kt | 19 +- .../gradle/publish/PublicationChecksums.kt | 17 +- .../spine/gradle/publish/PublicationSbom.kt | 2 +- .../spine/gradle/publish/PublicationState.kt | 672 ++++++++++++++++++ .../io/spine/gradle/publish/PublishingExts.kt | 18 + .../spine/gradle/publish/PublishingRepos.kt | 7 +- .../io/spine/gradle/publish/RemoteFile.kt | 356 ++++++++++ .../spine/gradle/publish/SpinePublishing.kt | 3 + .../kotlin/io/spine/gradle/repo/Repository.kt | 19 +- .../gradle/publish/ArtifactComponentsSpec.kt | 16 +- .../gradle/publish/IncrementGuardTest.kt | 48 +- .../gradle/publish/PublicationStateIgTest.kt | 531 ++++++++++++++ .../gradle/publish/PublicationStateSpec.kt | 350 +++++++++ .../io/spine/gradle/publish/RemoteFileSpec.kt | 405 +++++++++++ .../gradle/publish/SpinePublishingTest.kt | 16 +- .../report/coverage/FileExtensionsTest.kt | 16 +- config | 2 +- 26 files changed, 2486 insertions(+), 100 deletions(-) create mode 100644 buildSrc/src/main/kotlin/io/spine/gradle/publish/PublicationState.kt create mode 100644 buildSrc/src/main/kotlin/io/spine/gradle/publish/RemoteFile.kt create mode 100644 buildSrc/src/test/kotlin/io/spine/gradle/publish/PublicationStateIgTest.kt create mode 100644 buildSrc/src/test/kotlin/io/spine/gradle/publish/PublicationStateSpec.kt create mode 100644 buildSrc/src/test/kotlin/io/spine/gradle/publish/RemoteFileSpec.kt diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index aacee78..8dc7c91 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -30,7 +30,7 @@ on: jobs: publish: name: Publish to Maven repositories - uses: SpineEventEngine/config/.github/workflows/publishing.yml@604420cd7eab82b382c9a5c1d812be454552c27c + uses: SpineEventEngine/config/.github/workflows/publishing.yml@ad3dff0890c7716cbba3fe2ce17bf4fe5905a318 permissions: contents: read packages: write diff --git a/buildSrc/src/main/kotlin/io/spine/dependency/lib/OpenTelemetryKotlin.kt b/buildSrc/src/main/kotlin/io/spine/dependency/lib/OpenTelemetryKotlin.kt index b473fdc..63b3f44 100644 --- a/buildSrc/src/main/kotlin/io/spine/dependency/lib/OpenTelemetryKotlin.kt +++ b/buildSrc/src/main/kotlin/io/spine/dependency/lib/OpenTelemetryKotlin.kt @@ -77,11 +77,31 @@ object OpenTelemetryKotlin : Dependency() { */ val compat = "$group:compat:$version" + /** + * The export machinery of the Kotlin SDK, including the `batchLogRecordProcessor` + * builder. + * + * Use it together with [implementation] and an exporter artifact, such as + * [exportersOtlp]. Like [core] and [implementation], it is for applications + * and tests. + */ + val exportersCore = "$group:exporters-core:$version" + + /** + * The OTLP exporters of the Kotlin SDK, such as `otlpHttpLogRecordExporter`, + * which send data over HTTP using Ktor. + * + * Use it together with [exportersCore]. + */ + val exportersOtlp = "$group:exporters-otlp:$version" + override val modules: List = listOf( "$group:api", "$group:noop", "$group:core", "$group:implementation", "$group:compat", + "$group:exporters-core", + "$group:exporters-otlp", ) } diff --git a/buildSrc/src/main/kotlin/io/spine/dependency/local/Base.kt b/buildSrc/src/main/kotlin/io/spine/dependency/local/Base.kt index baaf5c7..45c1d2f 100644 --- a/buildSrc/src/main/kotlin/io/spine/dependency/local/Base.kt +++ b/buildSrc/src/main/kotlin/io/spine/dependency/local/Base.kt @@ -24,7 +24,7 @@ package io.spine.dependency.local "unused" /* Some subprojects do not use all Base artifacts. */, ) object Base { - const val version = "2.0.0-SNAPSHOT.462" + const val version = "2.0.0-SNAPSHOT.461" const val versionForBuildScript = "2.0.0-SNAPSHOT.461" const val group = Spine.group private const val prefix = "spine" diff --git a/buildSrc/src/main/kotlin/io/spine/dependency/local/Compiler.kt b/buildSrc/src/main/kotlin/io/spine/dependency/local/Compiler.kt index 1582193..137e830 100644 --- a/buildSrc/src/main/kotlin/io/spine/dependency/local/Compiler.kt +++ b/buildSrc/src/main/kotlin/io/spine/dependency/local/Compiler.kt @@ -60,7 +60,7 @@ object Compiler : Dependency() { * The version of the Compiler dependencies. */ override val version: String - private const val fallbackVersion = "2.0.0-SNAPSHOT.080" + private const val fallbackVersion = "2.0.0-SNAPSHOT.069" /** * The distinct version of the Compiler used by other build tools. diff --git a/buildSrc/src/main/kotlin/io/spine/dependency/local/CoreJvmCompiler.kt b/buildSrc/src/main/kotlin/io/spine/dependency/local/CoreJvmCompiler.kt index 087a2fa..1af2694 100644 --- a/buildSrc/src/main/kotlin/io/spine/dependency/local/CoreJvmCompiler.kt +++ b/buildSrc/src/main/kotlin/io/spine/dependency/local/CoreJvmCompiler.kt @@ -39,7 +39,7 @@ object CoreJvmCompiler { /** * The version to be used for integration tests. */ - const val version = "2.0.0-SNAPSHOT.099" + const val version = "2.0.0-SNAPSHOT.097" /** * The ID of the Gradle plugin. diff --git a/buildSrc/src/main/kotlin/io/spine/dependency/local/Validation.kt b/buildSrc/src/main/kotlin/io/spine/dependency/local/Validation.kt index 1be9aff..155cbbc 100644 --- a/buildSrc/src/main/kotlin/io/spine/dependency/local/Validation.kt +++ b/buildSrc/src/main/kotlin/io/spine/dependency/local/Validation.kt @@ -27,7 +27,7 @@ object Validation { /** * The version of the Validation library artifacts. */ - const val version = "2.0.0-SNAPSHOT.469" + const val version = "2.0.0-SNAPSHOT.464" const val group = Spine.toolsGroup private const val prefix = "validation" diff --git a/buildSrc/src/main/kotlin/io/spine/gradle/publish/CheckVersionIncrement.kt b/buildSrc/src/main/kotlin/io/spine/gradle/publish/CheckVersionIncrement.kt index f43f019..cfb0fa0 100644 --- a/buildSrc/src/main/kotlin/io/spine/gradle/publish/CheckVersionIncrement.kt +++ b/buildSrc/src/main/kotlin/io/spine/gradle/publish/CheckVersionIncrement.kt @@ -235,7 +235,7 @@ abstract class CheckVersionIncrement : DefaultTask() { */ private fun checkArtifactNotPublished(path: String) { val artifact = "$path/${MavenMetadata.FILE_NAME}" - val repositories = targetRepositories() + val repositories = repository.targets() var found = false for (repoUrl in repositories) { val metadata = fetch(repoUrl, artifact) ?: continue @@ -252,18 +252,6 @@ abstract class CheckVersionIncrement : DefaultTask() { } } - /** - * Returns the URLs of the target repositories: the `snapshots` one, and - * the `releases` one unless it is the same destination. - */ - private fun targetRepositories(): List { - val snapshots = repository.target(snapshots = true) - if (repository.hasOneTarget()) { - return listOf(snapshots) - } - return listOf(snapshots, repository.target(snapshots = false)) - } - /** * Throws if the [metadata] of the artifact at the given [path], fetched from [repoUrl], * lists the current [version]. diff --git a/buildSrc/src/main/kotlin/io/spine/gradle/publish/GitHubPackages.kt b/buildSrc/src/main/kotlin/io/spine/gradle/publish/GitHubPackages.kt index 184c821..3bf8dd0 100644 --- a/buildSrc/src/main/kotlin/io/spine/gradle/publish/GitHubPackages.kt +++ b/buildSrc/src/main/kotlin/io/spine/gradle/publish/GitHubPackages.kt @@ -19,6 +19,7 @@ import io.spine.gradle.repo.Repository import io.spine.gradle.buildDirectory import net.lingala.zip4j.ZipFile import org.gradle.api.Project +import org.gradle.api.artifacts.repositories.MavenArtifactRepository /** * Maven repositories of Spine Event Engine projects hosted at GitHub Packages. @@ -26,19 +27,45 @@ import org.gradle.api.Project internal object GitHubPackages { /** - * Obtains an instance of the GitHub Packages repository with the given name. + * The name of the GitHub Packages repository. + * + * The Maven repository that a project publishes to is named after it: + * `GitHub-Packages` for releases, and `GitHub-Packages-snapshots` for snapshots + * (see `Repository.name(snapshots)`). */ - fun repository(repoName: String): Repository { + const val repositoryName = "GitHub-Packages" + + /** + * Obtains an instance of the GitHub Packages repository of the given GitHub repository. + * + * @param slug The name of the GitHub repository of Spine Event Engine, without + * the organization, such as `core-jvm`. + */ + fun repository(slug: String): Repository { val githubActor: String = actor() - val url = "https://maven.pkg.github.com/SpineEventEngine/$repoName" + val url = "https://maven.pkg.github.com/SpineEventEngine/$slug" return Repository( - name = "GitHub-Packages", + name = repositoryName, releases = url, snapshots = url ) { project -> project.credentialsWithToken(githubActor) } } - private fun actor(): String { + /** + * Tells whether the given Maven repository is a GitHub Packages one, as registered + * for publishing by [repository]. + * + * The name tells it, whichever repository at GitHub Packages the [candidate] is. + */ + fun isRepository(candidate: MavenArtifactRepository): Boolean = + candidate.name in listOf(false, true).map { snapshots -> + Repository.publishingName(name = repositoryName, snapshots = snapshots) + } + + /** + * Obtains the user to authenticate with at GitHub Packages, along with a token. + */ + fun actor(): String { var githubActor: String? = System.getenv("GITHUB_ACTOR") githubActor = if (githubActor.isNullOrEmpty()) { "developers@spine.io" diff --git a/buildSrc/src/main/kotlin/io/spine/gradle/publish/IncrementGuard.kt b/buildSrc/src/main/kotlin/io/spine/gradle/publish/IncrementGuard.kt index 121cc20..52415b4 100644 --- a/buildSrc/src/main/kotlin/io/spine/gradle/publish/IncrementGuard.kt +++ b/buildSrc/src/main/kotlin/io/spine/gradle/publish/IncrementGuard.kt @@ -21,7 +21,6 @@ import io.spine.gradle.SpineTaskGroup import org.gradle.api.Plugin import org.gradle.api.Project import org.gradle.api.Task -import org.gradle.api.publish.maven.MavenPublication import org.gradle.api.publish.maven.tasks.PublishToMavenLocal /** @@ -219,10 +218,3 @@ private fun Project.publishedArtifactPaths(): Set = mavenPublications() .map { it.repositoryPath } .toSet() - -/** - * The path to the artifact of this publication in a Maven repository, - * such as `io/spine/spine-base`. - */ -private val MavenPublication.repositoryPath: String - get() = "${groupId.replace('.', '/')}/$artifactId" diff --git a/buildSrc/src/main/kotlin/io/spine/gradle/publish/MavenMetadata.kt b/buildSrc/src/main/kotlin/io/spine/gradle/publish/MavenMetadata.kt index 532ee9e..2f9c779 100644 --- a/buildSrc/src/main/kotlin/io/spine/gradle/publish/MavenMetadata.kt +++ b/buildSrc/src/main/kotlin/io/spine/gradle/publish/MavenMetadata.kt @@ -16,7 +16,6 @@ package io.spine.gradle.publish import com.fasterxml.jackson.databind.DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES import com.fasterxml.jackson.dataformat.xml.XmlMapper -import java.io.FileNotFoundException import java.net.URL /** @@ -50,16 +49,16 @@ internal data class MavenMetadata(var versioning: Versioning = Versioning()) { * * If the document could not be found, assumes that the module was never * released and thus has no metadata. + * + * The document is read by [RemoteFile], which bounds the read with timeouts + * and retries it after a transient failure. + * + * @param url The URL of the document. + * @param authorization The value of the `Authorization` header to send, if any. */ - fun fetchAndParse(url: URL): MavenMetadata? { - return try { - url.openStream().use { stream -> - mapper.readValue(stream, MavenMetadata::class.java) - } - } catch (_: FileNotFoundException) { - null - } - } + fun fetchAndParse(url: URL, authorization: String? = null): MavenMetadata? = + RemoteFile.readText(url, authorization) + ?.let { mapper.readValue(it, MavenMetadata::class.java) } } } diff --git a/buildSrc/src/main/kotlin/io/spine/gradle/publish/PublicationChecksums.kt b/buildSrc/src/main/kotlin/io/spine/gradle/publish/PublicationChecksums.kt index a49f8a6..7d6cf7e 100644 --- a/buildSrc/src/main/kotlin/io/spine/gradle/publish/PublicationChecksums.kt +++ b/buildSrc/src/main/kotlin/io/spine/gradle/publish/PublicationChecksums.kt @@ -322,14 +322,19 @@ private fun Project.publishedArtifacts(): Map { mavenPublications().forEach { publication -> publication.rejectMavenSnapshot() - val base = "${publication.artifactId}-${publication.version}" publication.artifacts.forEach { artifact -> - val classifier = artifact.classifier?.takeIf { it.isNotEmpty() } - val suffix = classifier?.let { "-$it" } ?: "" - record("$base$suffix.${artifact.extension}", artifact.file) + val name = publication.publishedName( + classifier = artifact.classifier, + extension = artifact.extension + ) + record(name, artifact.file) + } + pomFileOf(publication)?.let { + record(publication.publishedName(classifier = null, extension = "pom"), it) + } + moduleFileOf(publication)?.let { + record(publication.publishedName(classifier = null, extension = "module"), it) } - pomFileOf(publication)?.let { record("$base.pom", it) } - moduleFileOf(publication)?.let { record("$base.module", it) } } return result } diff --git a/buildSrc/src/main/kotlin/io/spine/gradle/publish/PublicationSbom.kt b/buildSrc/src/main/kotlin/io/spine/gradle/publish/PublicationSbom.kt index b6d3817..e32c622 100644 --- a/buildSrc/src/main/kotlin/io/spine/gradle/publish/PublicationSbom.kt +++ b/buildSrc/src/main/kotlin/io/spine/gradle/publish/PublicationSbom.kt @@ -110,7 +110,7 @@ internal object PublicationSbom { /** * The extension of a published SBOM, as in `-.spdx.json`. */ - private const val sbomExtension = "spdx.json" + const val sbomExtension = "spdx.json" /** * The [platform][KotlinTarget.platform] under which a JVM module looks up the modules diff --git a/buildSrc/src/main/kotlin/io/spine/gradle/publish/PublicationState.kt b/buildSrc/src/main/kotlin/io/spine/gradle/publish/PublicationState.kt new file mode 100644 index 0000000..4384ea4 --- /dev/null +++ b/buildSrc/src/main/kotlin/io/spine/gradle/publish/PublicationState.kt @@ -0,0 +1,672 @@ +/* + * Copyright 2026 CodeMatters, Lda. + * + * 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 io.spine.gradle.publish + +import io.spine.gradle.SpineTaskGroup +import java.net.URI +import java.net.URL +import java.util.Base64 +import java.util.concurrent.Callable +import java.util.concurrent.ExecutionException +import java.util.concurrent.Executors +import java.util.concurrent.Future +import org.gradle.api.DefaultTask +import org.gradle.api.GradleException +import org.gradle.api.Project +import org.gradle.api.artifacts.repositories.MavenArtifactRepository +import org.gradle.api.file.RegularFileProperty +import org.gradle.api.provider.MapProperty +import org.gradle.api.provider.Property +import org.gradle.api.provider.SetProperty +import org.gradle.api.publish.PublishingExtension +import org.gradle.api.publish.maven.MavenPublication +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.gradle.api.tasks.UntrackedTask + +/** + * Tells whether the Maven publications of the build are already published. + * + * The `Publish` workflow runs this task before it builds anything. Every version is + * immutable in the registries, which reject any overwrite, so a run can upload only + * a version that nobody has uploaded before. The task looks for the files of each + * publication in each of its destinations — the remote repositories its project + * publishes to, such as Artifact Registry and GitHub Packages — and decides: + * + * - no file of any publication is there — `unpublished`, the run publishes; + * - every publication is complete in every destination, and every copy of the SBOMs + * published next to the artifacts names the [commit] — `published`: an earlier run of + * the same commit uploaded the version, e.g. a duplicate run of one push, and this + * run has nothing to do; + * - any other state fails the task, before a single upload. A gap anywhere — a file + * or a whole publication missing from a destination — is left over from a failed + * run, or from GitHub Packages pruning the version. A version published from another + * commit, in any destination, is a collision. A version with an SBOM copy naming no + * commit, or with no commit to compare, cannot be confirmed as this run's. No run can + * publish any of these. + * + * The state is written to the [stateFile] as `unpublished` or `published`. + * + * A publication is complete in a destination when the destination lists its version in + * `maven-metadata.xml`, and has each of its [files]. The Gradle module metadata + * (`.module`) is not among them, as no public API tells at configuration time whether + * a publication has it. It is required only to be in all destinations of a publication, + * or in none. + * + * Repositories not served over HTTP(S), such as a directory on disk, are not searched: + * a CI build starts with them empty, so they never hold a version published before. + * GitHub Packages is read with a token (see [gitHubPackages]); any other repository is + * read anonymously, so a repository that needs credentials to be read fails the task. + * + * An SBOM is the evidence of the commit because it records the revision it was built + * from (see [PublicationSbom]), and no other published file does. A publication without + * an SBOM, such as a Gradle plugin marker, takes no part in the decision about the commit. + */ +@UntrackedTask(because = "The state lives in remote repositories, not in local outputs.") +abstract class PublicationState : DefaultTask() { + + /** + * The versions of the publications to look up, keyed by the path to the artifact in + * a Maven repository, such as `io/spine/spine-base`. + */ + @get:Input + abstract val publications: MapProperty + + /** + * The names of the files of each publication, keyed by the path to the artifact. + * + * The names are those of the artifacts and the POM, such as + * `spine-base-2.0.0.jar` or `spine-base-2.0.0.pom`. + */ + @get:Input + abstract val files: MapProperty> + + /** + * The URLs of the destinations of each publication, keyed by the path to the artifact. + */ + @get:Input + abstract val destinations: MapProperty> + + /** + * The URLs of the [destinations] that are GitHub Packages repositories. + * + * GitHub Packages serves nothing without a token, so the task reads these with + * the one in the `GITHUB_TOKEN` environment variable, and sends it nowhere else. + */ + @get:Input + abstract val gitHubPackages: SetProperty + + /** + * The commit being published. + * + * Absent outside GitHub Actions, where `GITHUB_SHA` is not set. In that case, + * a version that is already published cannot be attributed to any commit, and + * fails the task. + */ + @get:Input + @get:Optional + abstract val commit: Property + + /** + * The file to write the state to. + * + * The task deletes the file when it starts, so a failed task leaves none. + */ + @get:OutputFile + abstract val stateFile: RegularFileProperty + + @TaskAction + fun lookUp() { + val file = stateFile.get().asFile + file.delete() + val versions = publications.get() + if (versions.isEmpty()) { + logger.warn( + "No project publishes to a remote repository," + + " so there is no publication to look up." + ) + } + val inspector = Inspector( + files = files.get(), + destinations = destinations.get(), + gitHubPackages = gitHubPackages.get(), + gitHubAuthorization = gitHubAuthorization() + ) + val findings = inspector.inspectAll(versions) + findings.forEach { logger.lifecycle(it.describe()) } + val currentCommit = commit.orNull + val decision = Verdict.of(findings = findings, commit = currentCommit) + val state = decision.state ?: throw GradleException( + explain(decision = decision, findings = findings, commit = currentCommit) + ) + file.parentFile.mkdirs() + file.writeText("$state\n") + logger.lifecycle("The publication state is `$state`.") + } + + /** + * Obtains the `Authorization` header for reading the [gitHubPackages], if there are + * any, with the token in the `GITHUB_TOKEN` environment variable. + * + * @throws GradleException if there is a GitHub Packages repository to read, but + * no token. + */ + private fun gitHubAuthorization(): String? { + val repositories = gitHubPackages.get() + if (repositories.isEmpty()) { + return null + } + val token = System.getenv("GITHUB_TOKEN") + if (token.isNullOrBlank()) { + throw GradleException( + "Reading the GitHub Packages repository " + + repositories.joinToString { "`$it`" } + + " requires a token in the `GITHUB_TOKEN` environment variable." + ) + } + val credentials = "${GitHubPackages.actor()}:$token" + return "Basic " + Base64.getEncoder().encodeToString(credentials.toByteArray()) + } + + private fun explain(decision: Verdict, findings: List, commit: String?): String { + val reason = when (decision) { + Verdict.PARTIAL -> explainPartial(findings) + Verdict.COLLISION -> { + val others = findings.flatMap { it.commits }.toSet() - commit + val from = if (others.size == 1) "another commit" else "other commits" + """ + The version is published from $from: ${others.joinToString { "`$it`" }}, + while this build publishes `$commit`. + """.trimIndent() + } + Verdict.UNCONFIRMED -> if (commit == null) { + "The version is published, but this build cannot tell which commit" + + " it publishes: `GITHUB_SHA` is not set." + } else { + "The version is published, but a published SBOM does not name the commit" + + " it was published from." + } + Verdict.UNPUBLISHED, Verdict.PUBLISHED -> + error("The verdict `$decision` needs no explanation.") + } + return reason + "\n" + + """ + The registries reject overwrites, so no run can publish this version. + Bump the version in `version.gradle.kts`: the run of that merge publishes + the new version. + """.trimIndent() + } + + private fun explainPartial(findings: List): String { + val incomplete = findings.filter { it.presence != Presence.COMPLETE } + val gaps = incomplete.flatMap { finding -> + when (finding.presence) { + Presence.ABSENT -> listOf("${finding.label}: the whole publication") + Presence.PARTIAL, Presence.COMPLETE -> + finding.gaps.map { "${finding.label}: $it" } + } + } + val gitHub = gitHubPackages.get() + val gitHubOnly = incomplete.all { finding -> + finding.presence == Presence.PARTIAL && finding.incomplete.all { it in gitHub } + } + val pruned = if (gitHubOnly) { + "\nEvery gap is in GitHub Packages, which keeps only the latest snapshot versions" + + " of a package. If the version is an old one, it was pruned from there," + + " and the failure needs no action; if it is the latest, follow the advice" + + " below." + } else { + "" + } + return "The version is partially published. Missing:\n" + + gaps.joinToString(separator = "\n") { " - $it" } + + pruned + } + + /** + * The files of a publication held by one of its destinations. + * + * @property destination The URL of the repository. + * @property listed Tells whether the repository lists the version of the publication. + * @property present The names of the files of the publication in the repository. + */ + internal data class Holding( + val destination: String, + val listed: Boolean, + val present: Set + ) + + /** + * How much of a publication is published. + */ + internal enum class Presence { + + /** + * Every destination lists the version and has every file, and the Gradle module + * metadata is in all of them or in none. + */ + COMPLETE, + + /** No destination lists the version or has any file. */ + ABSENT, + + /** + * Anything else: a file or the listing missing from some destination, or + * the module metadata in some destinations only. + */ + PARTIAL + } + + /** + * The published state of a Maven publication. + * + * @property path The path to the artifact in a Maven repository. + * @property version The version of the publication. + * @property presence How much of the publication is published. + * @property commits The commits named by the copies of the SBOM of the publication in + * its destinations, if it is [complete][Presence.COMPLETE]. Empty otherwise, or if it + * has no SBOM. + * @property gaps What is missing from each destination, if anything. + * @property incomplete The destinations missing anything of the publication. + * @property unconfirmed Tells whether the publication has an SBOM, and a copy of it in + * some destination names no commit, as one built outside GitHub Actions does. + */ + internal data class Finding( + val path: String, + val version: String, + val presence: Presence, + val commits: Set = emptySet(), + val gaps: List = emptyList(), + val incomplete: Set = emptySet(), + val unconfirmed: Boolean = false + ) { + + /** + * The coordinates of the publication for the messages of the task. + */ + val label: String + get() = "`$path:$version`" + + /** + * Describes the finding for the build log. + */ + fun describe(): String = when (presence) { + Presence.ABSENT -> "$label is not published." + Presence.PARTIAL -> "$label is partially published; missing: ${gaps.joinToString()}." + Presence.COMPLETE -> { + val from = commits.joinToString { "`$it`" } + when { + commits.isEmpty() -> "$label is published, with no SBOM naming its commit." + unconfirmed -> "$label is published from $from, but a copy of its SBOM" + + " names no commit." + else -> "$label is published from $from." + } + } + } + } + + /** + * The decision about the publications of a build. + * + * @property state The state written for the `Publish` workflow, or `null` if the + * version cannot be published, in which case the task fails. + */ + internal enum class Verdict(val state: String?) { + + /** No publication is published, or there is none to look up. */ + UNPUBLISHED("unpublished"), + + /** + * Every publication is complete in every destination, and every copy of the SBOMs + * names the commit being published. + */ + PUBLISHED("published"), + + /** + * Some publications, or some of their files, are missing from some destinations, + * and the rest is published. + */ + PARTIAL(null), + + /** Every publication is published, but a copy of an SBOM names another commit. */ + COLLISION(null), + + /** + * Every publication is published, but the commit cannot be compared: the commit + * being published is unknown, or a copy of an SBOM names no commit. + */ + UNCONFIRMED(null); + + companion object { + + /** + * Decides on the verdict for the [findings] of a build that publishes + * the given [commit]. + * + * @param findings The published states of all publications of the build. + * @param commit The commit being published, or `null` if it is unknown. + */ + fun of(findings: Collection, commit: String?): Verdict { + val commits = findings.flatMap { it.commits }.toSet() + return when { + findings.all { it.presence == Presence.ABSENT } -> UNPUBLISHED + findings.any { it.presence != Presence.COMPLETE } -> PARTIAL + commit == null || commits.isEmpty() -> UNCONFIRMED + commits != setOf(commit) -> COLLISION + findings.any { it.unconfirmed } -> UNCONFIRMED + else -> PUBLISHED + } + } + } + } + + companion object { + + /** + * The name of the task, registered in the root project. + */ + const val taskName = "publicationState" + + private const val stateFilePath = "publication/state.txt" + + /** + * Matches the revision in the source information that the SPDX Gradle Plugin + * writes for a module of this build: `git+@#[]`. + * + * The revision is a full commit hash: 40 hexadecimal digits of SHA-1, or 64 of SHA-256. + */ + private val scmRevision = Regex("""git\+[^"\s]+?@([0-9a-f]{64}|[0-9a-f]{40})#""") + + /** + * Obtains the revisions named in the source information of the given SBOM text. + * + * A revision that is not a full commit hash, such as the `unknown` written for + * a build outside GitHub Actions, is not matched. + */ + internal fun sbomRevisions(text: String): Set = + scmRevision.findAll(text).map { it.groupValues[1] }.toSet() + + /** + * Decides how much of a publication is published, from the [holdings] of its + * destinations, the [names] of its files, and the name of its [module] metadata. + */ + internal fun presenceOf( + holdings: List, + names: List, + module: String + ): Presence { + val modules = holdings.map { module in it.present }.toSet() + return when { + holdings.all { !it.listed && it.present.isEmpty() } -> Presence.ABSENT + holdings.all { it.listed && it.present.containsAll(names) } && + modules.size == 1 -> Presence.COMPLETE + else -> Presence.PARTIAL + } + } + + /** + * Describes what is missing from each of the [holdings] to complete + * the publication at the given [path]. + * + * @return the descriptions of the gaps keyed by the destination, for each + * destination missing anything. + */ + internal fun gapsOf( + holdings: List, + path: String, + names: List, + module: String + ): Map> { + val expected = if (holdings.any { module in it.present }) names + module else names + return holdings.associate { holding -> + val metadata = "${holding.destination}/$path/${MavenMetadata.FILE_NAME}" + val unlisted = if (holding.listed) { + emptyList() + } else { + listOf("the version in `$metadata`") + } + val absent = (expected - holding.present).map { + "`$it` in `${holding.destination}`" + } + holding.destination to unlisted + absent + }.filterValues { it.isNotEmpty() } + } + + /** + * Registers the task in the given [root] project, unless it is registered already. + * + * The publications are collected from every project of the build once all of + * them are evaluated, since the publishing handlers configure the coordinates and + * the artifacts in `afterEvaluate`. They are handed to the task as plain values, + * so that the task reads the state of no other project while it runs. + * + * Call it after [PublicationSbom.registerTasks]: both collect in `projectsEvaluated` + * callbacks, which run in the order of registration, and this task must see + * the SBOM artifacts that the other one adds to the publications. + */ + internal fun registerOn(root: Project) { + if (root.tasks.names.contains(taskName)) { + return + } + val task = root.tasks.register(taskName, PublicationState::class.java) { + group = SpineTaskGroup.name + description = "Tells whether the version of the Maven publications is published" + commit.set( + root.providers.environmentVariable("GITHUB_SHA").filter { it.isNotBlank() } + ) + stateFile.convention(root.layout.buildDirectory.file(stateFilePath)) + } + root.gradle.projectsEvaluated { + task.configure { + root.allprojects.forEach { collect(it) } + } + } + } + + /** + * Adds the publications of the given [project] to the inputs of this task, if + * the project publishes to a remote repository. + */ + private fun PublicationState.collect(project: Project) { + val repositories = project.remoteRepositories() + if (repositories.isEmpty()) { + return + } + project.mavenPublications().forEach { publication -> + val path = publication.repositoryPath + publications.put(path, publication.version) + files.put(path, publication.fileNames()) + destinations.put(path, repositories.map { it.location() }) + } + gitHubPackages.addAll( + repositories + .filter { GitHubPackages.isRepository(it) && it.carriesTokenSafely() } + .map { it.location() } + ) + } + } +} + +/** + * Looks up the files of publications in their destinations. + * + * Publications are looked up [in parallel][parallelism], as a build may have dozens of + * them, and each one takes a request per file per destination. + * + * @property files The names of the files of each publication. + * @property destinations The URLs of the destinations of each publication. + * @property gitHubPackages The destinations to read with the [gitHubAuthorization]. + * @property gitHubAuthorization The `Authorization` header for reading GitHub Packages. + */ +private class Inspector( + private val files: Map>, + private val destinations: Map>, + private val gitHubPackages: Set, + private val gitHubAuthorization: String? +) { + + /** + * Looks up the publications of the given versions, keyed by the paths to the artifacts. + */ + fun inspectAll(versions: Map): List { + val pool = Executors.newFixedThreadPool(parallelism) + try { + val lookups = versions.map { (path, version) -> + Callable { inspect(path = path, version = version) } + } + return pool.invokeAll(lookups).map { it.result() } + } finally { + pool.shutdownNow() + } + } + + private fun inspect(path: String, version: String): PublicationState.Finding { + val names = files[path].orEmpty() + val module = "${path.substringAfterLast('/')}-$version.module" + val holdings = destinations[path].orEmpty().map { destination -> + PublicationState.Holding( + destination = destination, + listed = lists(destination = destination, path = path, version = version), + present = (names + module) + .filter { has(destination = destination, file = "$path/$version/$it") } + .toSet() + ) + } + val presence = PublicationState.presenceOf( + holdings = holdings, + names = names, + module = module + ) + val sbomCopies = if (presence == PublicationState.Presence.COMPLETE) { + sbomCommits(holdings = holdings, path = path, version = version, names = names) + } else { + emptyList() + } + val gaps = PublicationState.gapsOf( + holdings = holdings, + path = path, + names = names, + module = module + ) + return PublicationState.Finding( + path = path, + version = version, + presence = presence, + commits = sbomCopies.flatten().toSet(), + gaps = gaps.values.flatten(), + incomplete = gaps.keys, + unconfirmed = sbomCopies.any { it.isEmpty() } + ) + } + + private fun lists(destination: String, path: String, version: String): Boolean { + val metadataUrl = url(destination, "$path/${MavenMetadata.FILE_NAME}") + val metadata = MavenMetadata.fetchAndParse(metadataUrl, authorization(destination)) + return metadata != null && version in metadata.versioning.versions + } + + private fun has(destination: String, file: String): Boolean = + RemoteFile.exists(url(destination, file), authorization(destination)) + + /** + * Obtains the commits named by each copy of the SBOM of a complete publication, one + * set for each of its [holdings]. + * + * Every copy is read, as each destination may hold a copy uploaded by another run. + * A copy naming no commit gives an empty set, and so does one that cannot be read. + * + * Returns an empty list if the publication has no SBOM. + */ + private fun sbomCommits( + holdings: List, + path: String, + version: String, + names: List + ): List> { + val sbom = names.firstOrNull { it.endsWith(".${PublicationSbom.sbomExtension}") } + ?: return emptyList() + return holdings.map { holding -> + val sbomUrl = url(holding.destination, "$path/$version/$sbom") + RemoteFile.readText(sbomUrl, authorization(holding.destination)) + ?.let(PublicationState::sbomRevisions) + ?: emptySet() + } + } + + private fun authorization(destination: String): String? = + gitHubAuthorization.takeIf { destination in gitHubPackages } + + private fun url(repository: String, path: String): URL = + URI.create("${repository.removeSuffix("/")}/$path").toURL() + + private fun Future.result(): T = + try { + get() + } catch (e: ExecutionException) { + throw e.cause ?: IllegalStateException(e) + } + + private companion object { + + /** + * The number of publications looked up at a time. + */ + const val parallelism = 4 + } +} + +/** + * The schemes of the URLs of remote repositories. + */ +private val remoteSchemes = setOf("http", "https") + +/** + * Obtains the remote Maven repositories this project publishes to. + * + * A repository with no URL is left out, as Gradle would fail to publish to it anyway. + */ +private fun Project.remoteRepositories(): List = + extensions.findByType(PublishingExtension::class.java) + ?.repositories + ?.withType(MavenArtifactRepository::class.java) + ?.filter { repository -> + // `getUrl()` returns `null` for an unset URL. + repository.url != null && repository.url.scheme in remoteSchemes + } + .orEmpty() + +/** + * Obtains the URL of this repository with no trailing slash. + */ +private fun MavenArtifactRepository.location(): String = url.toString().removeSuffix("/") + +/** + * Tells whether a token may be sent to this repository: over HTTPS, or to the loopback + * address of a test. + */ +private fun MavenArtifactRepository.carriesTokenSafely(): Boolean = + url.scheme == "https" || url.host in setOf("localhost", "127.0.0.1", "[::1]", "::1") + +/** + * Obtains the names of the files of this publication: its artifacts and the POM. + */ +private fun MavenPublication.fileNames(): List { + val artifactNames = artifacts.map { + publishedName(classifier = it.classifier, extension = it.extension) + } + return (artifactNames + publishedName(classifier = null, extension = "pom")).distinct() +} diff --git a/buildSrc/src/main/kotlin/io/spine/gradle/publish/PublishingExts.kt b/buildSrc/src/main/kotlin/io/spine/gradle/publish/PublishingExts.kt index 5a876d2..d7b616b 100644 --- a/buildSrc/src/main/kotlin/io/spine/gradle/publish/PublishingExts.kt +++ b/buildSrc/src/main/kotlin/io/spine/gradle/publish/PublishingExts.kt @@ -69,6 +69,24 @@ internal fun Project.mavenPublications(): Collection { internal val MavenPublication.isPluginMarker: Boolean get() = name.endsWith("PluginMarkerMaven") +/** + * The path to the artifact of this publication in a Maven repository, + * such as `io/spine/spine-base`. + */ +internal val MavenPublication.repositoryPath: String + get() = "${groupId.replace('.', '/')}/$artifactId" + +/** + * Obtains the name under which a file of this publication with the given [classifier] + * and [extension] is published, such as `spine-base-2.0.0-javadoc.jar`. + * + * A `null` or empty [classifier] means the file has none, as the POM. + */ +internal fun MavenPublication.publishedName(classifier: String?, extension: String): String { + val suffix = classifier?.takeIf { it.isNotEmpty() }?.let { "-$it" } ?: "" + return "$artifactId-$version$suffix.$extension" +} + /** * Obtains an instance, if available, of [SpinePublishing] extension * applied to this project. diff --git a/buildSrc/src/main/kotlin/io/spine/gradle/publish/PublishingRepos.kt b/buildSrc/src/main/kotlin/io/spine/gradle/publish/PublishingRepos.kt index 26c5533..aac49f8 100644 --- a/buildSrc/src/main/kotlin/io/spine/gradle/publish/PublishingRepos.kt +++ b/buildSrc/src/main/kotlin/io/spine/gradle/publish/PublishingRepos.kt @@ -24,7 +24,10 @@ object PublishingRepos { val cloudArtifactRegistry = CloudArtifactRegistry.repository /** - * Obtains a GitHub repository by the given name. + * Obtains the GitHub Packages repository of the given GitHub repository. + * + * @param slug The name of the GitHub repository of Spine Event Engine, without + * the organization, such as `core-jvm`. */ - fun gitHub(repoName: String): Repository = GitHubPackages.repository(repoName) + fun gitHub(slug: String): Repository = GitHubPackages.repository(slug) } diff --git a/buildSrc/src/main/kotlin/io/spine/gradle/publish/RemoteFile.kt b/buildSrc/src/main/kotlin/io/spine/gradle/publish/RemoteFile.kt new file mode 100644 index 0000000..e1e4e9a --- /dev/null +++ b/buildSrc/src/main/kotlin/io/spine/gradle/publish/RemoteFile.kt @@ -0,0 +1,356 @@ +/* + * Copyright 2026 CodeMatters, Lda. + * + * 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 io.spine.gradle.publish + +import java.io.FileNotFoundException +import java.io.IOException +import java.net.HttpURLConnection +import java.net.MalformedURLException +import java.net.URI +import java.net.URISyntaxException +import java.net.URL +import java.net.URLConnection +import java.time.Instant +import java.time.ZonedDateTime +import java.time.format.DateTimeFormatter +import java.time.format.DateTimeParseException +import kotlin.time.Duration +import kotlin.time.Duration.Companion.seconds +import kotlin.time.toKotlinDuration + +/** + * Reads the files of a remote Maven repository, such as `maven-metadata.xml`. + * + * Each request is bounded by timeouts, so that an unresponsive registry fails the build + * instead of stalling it. A request that fails with an I/O error, a server error, + * a [transient] client error, or a rate-limit `403 Forbidden` is retried, up to three + * attempts in all, with the delay doubling from one second. A response with + * a `Retry-After` header makes the next attempt wait at least as long as it asks, + * up to a minute. A missing file is not an error, and a request the server refuses + * for good, such as one answered with `401 Unauthorized` or a plain `403 Forbidden`, + * is not retried. + * + * An `Authorization` header passed with a request is sent to the origin of the given URL + * only. A redirect to another origin, such as the storage GitHub Packages redirects + * a download to, is followed without it. A redirect is followed to an HTTP(S) URL only, + * and never from HTTPS to plain HTTP. + */ +internal object RemoteFile { + + private const val attempts = 3 + private const val maxRedirects = 5 + private val connectTimeout = 10.seconds + private val readTimeout = 30.seconds + private val initialBackoff = 1.seconds + + /** + * The longest wait before another attempt that a `Retry-After` header may impose. + */ + private val maxRetryAfter = 60.seconds + + /** + * `429 Too Many Requests`, which `HttpURLConnection` has no constant for. + */ + private const val tooManyRequests = 429 + + /** + * The HTTP statuses of successful responses, `2xx`. + */ + private val successes = HttpURLConnection.HTTP_OK.. withRetries(request: () -> T): T { + var backoff = initialBackoff + // All attempts but the last one, whose failure propagates. + repeat(attempts - 1) { + try { + return request() + } catch (e: IOException) { + val asked = (e as? RetryLaterException)?.delay ?: Duration.ZERO + Thread.sleep(maxOf(backoff, asked).inWholeMilliseconds) + backoff *= 2 + } + } + return request() + } + + private fun readOnce(url: URL, authorization: String?, redirectsLeft: Int): String? { + val connection = open(url, authorization) + return try { + if (connection is HttpURLConnection) { + connection.read(authorization = authorization, redirectsLeft = redirectsLeft) + } else { + connection.getInputStream().bufferedReader().use { it.readText() } + } + } catch (_: FileNotFoundException) { + // A `file:` URL to a missing file. + null + } finally { + (connection as? HttpURLConnection)?.errorStream?.close() + } + } + + /** + * Reads the response to this connection, following a redirect. + */ + private fun HttpURLConnection.read(authorization: String?, redirectsLeft: Int): String? = + when (status()) { + in missing -> null + in redirects -> { + check(redirectsLeft > 0) { "Too many redirects reading `${url.shown()}`." } + val next = target() + inputStream.close() + readOnce( + url = next, + authorization = authorization.takeIf { url.sameOrigin(next) }, + redirectsLeft = redirectsLeft - 1 + ) + } + else -> inputStream.bufferedReader().use { it.readText() } + } + + private fun existsOnce(url: URL, authorization: String?, redirectsLeft: Int): Boolean { + val connection = open(url, authorization) + return try { + if (connection is HttpURLConnection) { + connection.requestMethod = "HEAD" + connection.exists(authorization = authorization, redirectsLeft = redirectsLeft) + } else { + connection.getInputStream().close() + true + } + } catch (_: FileNotFoundException) { + // A `file:` URL to a missing file. + false + } finally { + (connection as? HttpURLConnection)?.errorStream?.close() + } + } + + /** + * Tells whether the response to this `HEAD` request finds a file, following + * a redirect with no `Authorization` header if it leads to another origin. + */ + private fun HttpURLConnection.exists(authorization: String?, redirectsLeft: Int): Boolean { + val status = status() + return when { + status in missing -> false + status in successes -> true + status in redirects -> { + check(redirectsLeft > 0) { "Too many redirects asking for `${url.shown()}`." } + val next = target() + existsOnce( + url = next, + authorization = authorization.takeIf { url.sameOrigin(next) }, + redirectsLeft = redirectsLeft - 1 + ) + } + else -> throw IOException("`${url.shown()}` answered with `$status`.") + } + } + + private fun open(url: URL, authorization: String?): URLConnection { + val connection = url.openConnection() + connection.connectTimeout = connectTimeout.inWholeMilliseconds.toInt() + connection.readTimeout = readTimeout.inWholeMilliseconds.toInt() + if (connection is HttpURLConnection) { + connection.instanceFollowRedirects = false + } + authorization?.let { connection.setRequestProperty("Authorization", it) } + return connection + } + + /** + * Obtains the status of the response if it is a success, a redirect, or a sign that + * there is no such file. + * + * @throws IOException for a server error, a [transient] client error, or a rate limit, + * which may go away on another attempt; a [RetryLaterException] if the response + * tells how long to wait before it. + * @throws IllegalStateException for any other client error. + */ + private fun HttpURLConnection.status(): Int { + val status = responseCode + if (status >= HttpURLConnection.HTTP_INTERNAL_ERROR || status in transient || + isRateLimited(status)) { + val message = "`${url.shown()}` answered with `$status $responseMessage`." + val delay = retryAfter(maxRetryAfter) + throw if (delay == null) IOException(message) else RetryLaterException(message, delay) + } + check(status !in clientErrors || status in missing) { + "Cannot read `${url.shown()}`: the server answered with `$status $responseMessage`." + } + return status + } + + /** + * Obtains the URL that this connection redirects to. + * + * @throws IllegalStateException if there is no such URL, or it may not be followed: + * a URL that is not HTTP(S), or a plain HTTP one redirected to from HTTPS. + */ + private fun HttpURLConnection.target(): URL { + val location = checkNotNull(getHeaderField("Location")) { + "`${url.shown()}` redirects with no `Location`." + } + // The cause is left out of the message: it would quote the location, whose query + // may carry a signature. + val target = resolve(location) + ?: error("`${url.shown()}` redirects to an invalid location.") + val allowed = target.protocol == url.protocol || + (url.protocol == "http" && target.protocol == "https") + check(allowed) { + "`${url.shown()}` redirects to `${target.shown()}`, which may not be followed." + } + return target + } +} + +/** + * Resolves the given redirect [location] against the URL of this connection. + * + * @return the resolved URL, or `null` if the location is not a valid URL. + */ +private fun HttpURLConnection.resolve(location: String): URL? = + try { + url.toURI().resolve(URI.create(location)).toURL() + } catch (_: IllegalArgumentException) { + null + } catch (_: URISyntaxException) { + null + } catch (_: MalformedURLException) { + null + } + +/** + * An I/O failure whose response asks to wait for the given [delay] before trying again. + */ +private class RetryLaterException(message: String, val delay: Duration) : IOException(message) + +/** + * Obtains how long this response asks to wait before trying again, by its `Retry-After` + * header in seconds or as an HTTP date, but no longer than the given [limit]. + * + * @return the delay, or `null` if the response has no such header, or it cannot be parsed. + */ +private fun HttpURLConnection.retryAfter(limit: Duration): Duration? { + val value = getHeaderField("Retry-After")?.trim() ?: return null + val delay = value.toLongOrNull()?.seconds ?: untilHttpDate(value) + return delay?.coerceIn(Duration.ZERO, limit) +} + +/** + * Obtains the time from now until the given HTTP date, such as + * `Wed, 21 Oct 2026 07:28:00 GMT`. + * + * @return the time until the date, or `null` if [value] is not an HTTP date. + */ +private fun untilHttpDate(value: String): Duration? = + try { + val date = ZonedDateTime.parse(value, DateTimeFormatter.RFC_1123_DATE_TIME) + java.time.Duration.between(Instant.now(), date.toInstant()).toKotlinDuration() + } catch (_: DateTimeParseException) { + null + } + +/** + * Tells whether this response with the given [status] refuses the request for exceeding + * a rate limit, as GitHub does with `403 Forbidden` and either a `Retry-After` header or + * an `X-RateLimit-Remaining: 0` header. + */ +private fun HttpURLConnection.isRateLimited(status: Int): Boolean = + status == HttpURLConnection.HTTP_FORBIDDEN && + (getHeaderField("Retry-After") != null || + getHeaderField("X-RateLimit-Remaining") == "0") + +/** + * Tells whether the given URL has the origin of this one: the protocol, the host, + * and the port. + */ +private fun URL.sameOrigin(other: URL): Boolean = + protocol == other.protocol && host.equals(other.host, ignoreCase = true) && + effectivePort() == other.effectivePort() + +private fun URL.effectivePort(): Int = if (port == -1) defaultPort else port + +/** + * Shows this URL with no query, which may carry a signature, as a redirect + * to a storage service does. + */ +private fun URL.shown(): String = "$protocol://$authority$path" diff --git a/buildSrc/src/main/kotlin/io/spine/gradle/publish/SpinePublishing.kt b/buildSrc/src/main/kotlin/io/spine/gradle/publish/SpinePublishing.kt index 033df0c..4af48a5 100644 --- a/buildSrc/src/main/kotlin/io/spine/gradle/publish/SpinePublishing.kt +++ b/buildSrc/src/main/kotlin/io/spine/gradle/publish/SpinePublishing.kt @@ -329,6 +329,9 @@ open class SpinePublishing(private val project: Project) { } PublicationChecksums.registerTasks(project, projectsToPublish) PublicationSbom.registerTasks(project, projectsToPublish) + // After `PublicationSbom`: its `projectsEvaluated` callback adds the SBOM artifacts + // that the one of `PublicationState` collects. + PublicationState.registerOn(project.rootProject) } /** diff --git a/buildSrc/src/main/kotlin/io/spine/gradle/repo/Repository.kt b/buildSrc/src/main/kotlin/io/spine/gradle/repo/Repository.kt index 8e747f3..e2f80d2 100644 --- a/buildSrc/src/main/kotlin/io/spine/gradle/repo/Repository.kt +++ b/buildSrc/src/main/kotlin/io/spine/gradle/repo/Repository.kt @@ -49,6 +49,17 @@ data class Repository( * Serializes obtaining the credentials of all repositories (see [credentials]). */ private val credentialsLock = Any() + + /** + * Obtains the name used for publishing to a repository with the given [name]. + * + * @param snapshots If `true` the repository is used for publishing snapshots, + * and the suffix `-snapshots` is added to the given [name]. + * Otherwise, the function returns just [name]. + * @see Repository.name + */ + fun publishingName(name: String, snapshots: Boolean): String = + name + if (snapshots) "-snapshots" else "" } init { @@ -66,7 +77,7 @@ data class Repository( * and the suffix `-snapshots` will be added to the value of the [name] property. * Otherwise, the function returns just [name]. */ - fun name(snapshots: Boolean): String = name + if (snapshots) "-snapshots" else "" + fun name(snapshots: Boolean): String = publishingName(name, snapshots) /** * Obtains the target URL of the repository for publishing. @@ -79,6 +90,12 @@ data class Repository( */ fun hasOneTarget() = snapshots == releases + /** + * Obtains the URLs of the destinations of this repository: the `snapshots` one, and + * the `releases` one unless it is the same destination. + */ + fun targets(): List = listOf(snapshots, releases).distinct() + /** * Obtains the publishing password credentials to this repository. * diff --git a/buildSrc/src/test/kotlin/io/spine/gradle/publish/ArtifactComponentsSpec.kt b/buildSrc/src/test/kotlin/io/spine/gradle/publish/ArtifactComponentsSpec.kt index e430297..8beb827 100644 --- a/buildSrc/src/test/kotlin/io/spine/gradle/publish/ArtifactComponentsSpec.kt +++ b/buildSrc/src/test/kotlin/io/spine/gradle/publish/ArtifactComponentsSpec.kt @@ -35,8 +35,8 @@ import org.junit.jupiter.api.Test @DisplayName("`ArtifactComponents` should") internal class ArtifactComponentsSpec { - @Nested - inner class `describe a bundled package` { + @Nested inner class + `describe a bundled package` { @Test fun `as contained in the artifact rather than a dependency of it`() { @@ -157,8 +157,8 @@ internal class ArtifactComponentsSpec { } } - @Nested - inner class `keep` { + @Nested inner class + keep { @Test fun `the dependencies of the artifact as they are`() { @@ -192,8 +192,8 @@ internal class ArtifactComponentsSpec { } } - @Nested - inner class `leave out` { + @Nested inner class + `leave out` { @Test fun `a package the artifact neither depends on nor bundles`() { @@ -269,8 +269,8 @@ internal class ArtifactComponentsSpec { } } - @Nested - inner class `reject a document` { + @Nested inner class + `reject a document` { @Test fun `describing no package`() { diff --git a/buildSrc/src/test/kotlin/io/spine/gradle/publish/IncrementGuardTest.kt b/buildSrc/src/test/kotlin/io/spine/gradle/publish/IncrementGuardTest.kt index 9bcbc4e..d315b58 100644 --- a/buildSrc/src/test/kotlin/io/spine/gradle/publish/IncrementGuardTest.kt +++ b/buildSrc/src/test/kotlin/io/spine/gradle/publish/IncrementGuardTest.kt @@ -43,8 +43,8 @@ import org.junit.jupiter.api.io.TempDir @DisplayName("`IncrementGuard` should") class IncrementGuardTest { - @Nested - inner class `require the version check` { + @Nested inner class + `require the version check` { @Test fun `for pull requests targeting default branches`() { @@ -59,8 +59,8 @@ class IncrementGuardTest { } } - @Nested - inner class `not require the version check` { + @Nested inner class + `not require the version check` { @Test fun `for pull requests targeting auxiliary branches`() { @@ -85,8 +85,8 @@ class IncrementGuardTest { } } - @Nested - inner class `actually run the check` { + @Nested inner class + `actually run the check` { @Test fun `on a CI pull request to a protected branch`() { @@ -99,8 +99,8 @@ class IncrementGuardTest { } } - @Nested - inner class `skip the check` { + @Nested inner class + `skip the check` { @Test fun `on a local build that does not publish`() { @@ -115,8 +115,8 @@ class IncrementGuardTest { } } - @Nested - inner class `compare against the base branch` { + @Nested inner class + `compare against the base branch` { @Test fun `inside the Version Guard workflow with a base branch`() { @@ -125,8 +125,8 @@ class IncrementGuardTest { } } - @Nested - inner class `not compare against the base branch` { + @Nested inner class + `not compare against the base branch` { @Test fun `outside the Version Guard workflow`() { @@ -142,8 +142,8 @@ class IncrementGuardTest { } } - @Nested - inner class `detect a Maven Local publish` { + @Nested inner class + `detect a Maven Local publish` { @Test fun `for the task's own project`() { @@ -180,8 +180,8 @@ class IncrementGuardTest { } } - @Nested - inner class `make 'checkVersionIncrement' a dependency of` { + @Nested inner class + `make 'checkVersionIncrement' a dependency of` { @Test fun `every Maven Local publishing task`() { @@ -195,8 +195,8 @@ class IncrementGuardTest { } } - @Nested - inner class `keep 'checkVersionIncrement' out of` { + @Nested inner class + `keep 'checkVersionIncrement' out of` { @Test fun `the 'check' lifecycle task`() { @@ -211,8 +211,8 @@ class IncrementGuardTest { } } - @Nested - inner class `configure 'checkVersionIncrement' with` { + @Nested inner class + `configure 'checkVersionIncrement' with` { @Test fun `the root directory of the build`() { @@ -321,8 +321,8 @@ class IncrementGuardTest { } } - @Nested - inner class `make 'checkVersionIncrement' fail` { + @Nested inner class + `make 'checkVersionIncrement' fail` { @TempDir lateinit var repoDir: File @@ -405,8 +405,8 @@ class IncrementGuardTest { } } - @Nested - inner class `make 'checkVersionIncrement' pass` { + @Nested inner class + `make 'checkVersionIncrement' pass` { @TempDir lateinit var repoDir: File diff --git a/buildSrc/src/test/kotlin/io/spine/gradle/publish/PublicationStateIgTest.kt b/buildSrc/src/test/kotlin/io/spine/gradle/publish/PublicationStateIgTest.kt new file mode 100644 index 0000000..cc62750 --- /dev/null +++ b/buildSrc/src/test/kotlin/io/spine/gradle/publish/PublicationStateIgTest.kt @@ -0,0 +1,531 @@ +/* + * Copyright 2026 CodeMatters, Lda. + * + * 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 io.spine.gradle.publish + +import com.sun.net.httpserver.HttpExchange +import com.sun.net.httpserver.HttpServer +import io.kotest.matchers.shouldBe +import io.kotest.matchers.string.shouldContain +import io.kotest.matchers.string.shouldNotContain +import java.io.File +import java.net.InetAddress +import java.net.InetSocketAddress +import java.net.URI +import java.util.Base64 +import java.util.concurrent.TimeUnit +import java.util.concurrent.atomic.AtomicInteger +import org.gradle.testkit.runner.GradleRunner +import org.junit.jupiter.api.AfterAll +import org.junit.jupiter.api.BeforeAll +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.DisplayName +import org.junit.jupiter.api.Nested +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.TestInstance +import org.junit.jupiter.api.Timeout +import org.junit.jupiter.api.io.TempDir + +/** + * Runs `publicationState` in a build that really publishes to a loopback registry. + * + * `api` and `backend` are the modules of `spinePublishing`. The [registry] has two remote + * repositories: one like Artifact Registry, which serves anyone, and one like GitHub + * Packages, which serves nothing without the token and redirects the downloads of files + * to storage of its own. `api` publishes to both and to a local repository, `backend` + * to GitHub Packages only, and `docs` to a local repository only. No local repository + * may be searched. + * + * The build publishes once for the whole suite, after the check of the unpublished + * version. Each test then looks at a copy of what the build published, so that it may + * take files away from it. + */ +@TestInstance(TestInstance.Lifecycle.PER_CLASS) +@Timeout(value = 5, unit = TimeUnit.MINUTES) +@DisplayName("`publicationState` task should") +internal class PublicationStateIgTest { + + /** + * The directory of the suite, holding the project and the repositories. + */ + private lateinit var workDir: File + + private lateinit var registry: Registry + + /** + * The repositories as the build published them. + */ + private lateinit var published: File + + /** + * The state written before anything was published, and the output of that build. + */ + private lateinit var unpublished: Pair + + private val copies = AtomicInteger() + + @BeforeAll + fun publish(@TempDir dir: File) { + workDir = dir + registry = Registry(root = workDir.resolve("registry").apply { mkdirs() }, token = token) + writeBuild() + val output = runner().build().output + unpublished = stateFile.readText().trim() to output + runner(task = "publish").build() + published = registry.root + } + + @BeforeEach + fun serveCopy() { + val copy = workDir.resolve("served-${copies.incrementAndGet()}") + published.copyRecursively(copy) + registry.root = copy + registry.leakedTokens.set(0) + } + + @AfterAll + fun stopRegistry() { + if (::registry.isInitialized) { + registry.close() + } + } + + @Test + fun `report the version unpublished before anything is published`() { + val (state, output) = unpublished + + state shouldBe "unpublished" + output shouldContain "`$api:$version` is not published." + } + + @Test + fun `report the version published when its SBOMs name the commit being published`() { + val output = runner().build().output + + stateFile.readText().trim() shouldBe "published" + output shouldContain "`$backend:$version` is published from `$commit`." + registry.leakedTokens.get() shouldBe 0 + } + + @Test + fun `not look in local repositories`() { + val local = project.resolve("local-repo") + val aside = workDir.resolve("local-repo-aside") + check(local.renameTo(aside)) + try { + val output = runner().build().output + + stateFile.readText().trim() shouldBe "published" + output shouldNotContain docs + } finally { + check(aside.renameTo(local)) + } + } + + @Nested inner class + `fail when missing from a repository` { + + @Test + fun `a classified artifact`() { + val jar = "spine-backend-$version-sources.jar" + registry.root.resolve("github/sample/$backend/$version/$jar").delete() + + val output = runner().buildAndFail().output + + output shouldContain "The version is partially published" + output shouldContain "`$jar` in `${registry.url}/github/sample`" + } + + @Test + fun `the artifact of the component`() { + val jar = "spine-api-$version.jar" + registry.root.resolve("ar/snapshots/$api/$version/$jar").delete() + + val output = runner().buildAndFail().output + + output shouldContain "`$jar` in `${registry.url}/ar/snapshots`" + } + + @Test + fun `the SBOM`() { + val sbom = "spine-api-$version.spdx.json" + registry.root.resolve("ar/snapshots/$api/$version/$sbom").delete() + + val output = runner().buildAndFail().output + + output shouldContain "`$sbom` in `${registry.url}/ar/snapshots`" + } + + @Test + fun `the module metadata`() { + val module = "spine-api-$version.module" + registry.root.resolve("ar/snapshots/$api/$version/$module").delete() + + val output = runner().buildAndFail().output + + output shouldContain "`$module` in `${registry.url}/ar/snapshots`" + output shouldNotContain "pruned" + } + + @Test + fun `a whole publication, telling that GitHub Packages may have pruned it`() { + registry.root.resolve("github/sample/$api").deleteRecursively() + + val output = runner().buildAndFail().output + + output shouldContain "The version is partially published" + output shouldContain "`$api:$version`: the version in " + + "`${registry.url}/github/sample/$api/maven-metadata.xml`" + output shouldContain "it was pruned from there" + } + } + + @Test + fun `fail when the version is published from another commit`() { + val output = runner(commit = otherCommit).buildAndFail().output + + output shouldContain "The version is published from another commit" + output shouldContain "`$commit`" + } + + @Test + fun `fail when a copy of an SBOM in one repository names another commit`() { + rewriteSbom(repository = "github/sample", path = api, revision = otherCommit) + + val output = runner().buildAndFail().output + + output shouldContain "The version is published from another commit: `$otherCommit`" + } + + @Test + fun `fail when a copy of an SBOM names no commit`() { + rewriteSbom(repository = "github/sample", path = backend, revision = "unknown") + + val output = runner().buildAndFail().output + + output shouldContain "a published SBOM does not name the commit" + } + + @Test + fun `fail when the commit being published is unknown`() { + val output = runner(commit = null).buildAndFail().output + + output shouldContain "this build cannot tell which commit it publishes" + output shouldContain "`GITHUB_SHA` is not set" + } + + @Test + fun `fail when there is no token to read GitHub Packages with`() { + val output = runner(token = null).buildAndFail().output + + output shouldContain "requires a token in the `GITHUB_TOKEN` environment variable" + } + + @Test + fun `fail when GitHub Packages refuses the token`() { + val output = runner(token = "wrong-token").buildAndFail().output + + output shouldContain "the server answered with `401" + registry.leakedTokens.get() shouldBe 0 + } + + @Test + fun `look the state up again when reusing the configuration cache`() { + val publishedCopy = registry.root + registry.root = workDir.resolve("nothing").apply { mkdirs() } + runner().withArguments(runner().arguments + "--configuration-cache").build() + stateFile.readText().trim() shouldBe "unpublished" + registry.root = publishedCopy + + val output = runner() + .withArguments(runner().arguments + "--configuration-cache") + .build() + .output + + output shouldContain "Reusing configuration cache." + stateFile.readText().trim() shouldBe "published" + } + + /** + * Rewrites the copy of the SBOM of the artifact at the given [path] in the given + * [repository] of the registry, so that it names the given [revision] instead of + * the commit the build published. + */ + private fun rewriteSbom(repository: String, path: String, revision: String) { + val artifactId = path.substringAfterLast('/') + val sbom = registry.root.resolve( + "$repository/$path/$version/$artifactId-$version.spdx.json" + ) + val text = sbom.readText() + check(commit in text) { "The SBOM `$sbom` does not name the commit `$commit`." } + sbom.writeText(text.replace(commit, revision)) + } + + private val project: File + get() = workDir.resolve("project") + + private val stateFile: File + get() = project.resolve("build/publication/state.txt") + + /** + * Creates a runner of the given [task], with the given [commit] as `GITHUB_SHA` and + * the given [token] as `GITHUB_TOKEN`. A `null` value leaves the variable unset, + * as outside GitHub Actions. + */ + private fun runner( + task: String = ":${PublicationState.taskName}", + commit: String? = Companion.commit, + token: String? = Companion.token + ): GradleRunner { + val environment = System.getenv() - ciVariables - "GITHUB_SHA" - "GITHUB_TOKEN" + + listOfNotNull( + commit?.let { "GITHUB_SHA" to it }, + token?.let { "GITHUB_TOKEN" to it } + ) + return GradleRunner.create() + .withProjectDir(project) + .withEnvironment(environment) + .withArguments(task, "--stacktrace") + } + + private fun writeBuild() { + listOf("api", "backend", "docs").forEach { module -> + project.resolve("$module/src/main/java/sample/$module/Stub.java").apply { + parentFile.mkdirs() + writeText("package sample.$module;\npublic class Stub {}\n") + } + } + project.resolve("settings.gradle.kts").writeText( + """ + rootProject.name = "state-sample" + include("api", "backend", "docs") + """.trimIndent() + ) + project.resolve("build.gradle.kts").writeText( + """ + buildscript { + dependencies { + classpath(files( + ${buildSrcClasspath()} + )) + } + } + + import io.spine.gradle.publish.spinePublishing + + allprojects { + group = "io.spine.sample" + version = "$version" + } + + subprojects { + apply(plugin = "java-library") + apply(plugin = "maven-publish") + $generatorStub + } + + spinePublishing { + modules = setOf("api", "backend") + destinations = emptySet() + } + + fun PublishingExtension.toRegistry() = repositories.maven { + name = "CloudArtifactRegistry-snapshots" + url = uri("${registry.url}/ar/snapshots") + } + + fun PublishingExtension.toGitHub() = repositories.maven { + name = "GitHub-Packages-snapshots" + url = uri("${registry.url}/github/sample") + credentials { + username = "spine" + password = "$token" + } + } + + fun PublishingExtension.toLocal() = repositories.maven { + name = "local" + url = uri("${'$'}{rootDir}/local-repo") + } + + project("api").the().apply { + toRegistry() + toGitHub() + toLocal() + } + + // GitHub Packages only, so that the SBOM is read from there, through a redirect. + project("backend").the().apply { + toGitHub() + } + + project("docs").the().apply { + publications { + create("docs") { + from(project("docs").components["java"]) + } + } + toLocal() + } + """.trimIndent() + ) + } + + /** + * Renders the classpath with the production classes of `buildSrc` as + * arguments of `files(...)`, for injection into the build script classpath + * of the generated build. + * + * The classpath comes from the `test` task in `buildSrc/build.gradle.kts`. + */ + private fun buildSrcClasspath(): String { + val classpath = requireNotNull(System.getProperty("buildSrc.classpath")) { + "The `buildSrc.classpath` system property is not set." + + " It is supplied by the `test` task in `buildSrc/build.gradle.kts`." + } + return classpath.split(File.pathSeparator).joinToString(",\n") { + " \"${File(it).invariantSeparatorsPath}\"" + } + } + + private companion object { + + const val version = "2.0.0-SNAPSHOT.575" + const val commit = "35054d78dfce2a0ead2ca79347ad57f74508977c" + const val otherCommit = "2b98e1801a0b3c4d5e6f708192a3b4c5d6e7f809" + const val token = "test-token" + + /** The artifacts of `api` and `backend`, named with the default prefix. */ + const val api = "io/spine/sample/spine-api" + const val backend = "io/spine/sample/spine-backend" + + /** The artifact of `docs`, named after the project by `maven-publish`. */ + const val docs = "io/spine/sample/docs" + + /** + * A task standing in for the Dokka one that `javadocJar` of `spinePublishing` + * depends on; the fixture does not apply Dokka. + */ + const val generatorStub = """tasks.register("dokkaGeneratePublicationJavadoc")""" + } +} + +/** + * A loopback Maven registry storing the uploaded files under its [root]. + * + * The files under `/ar` are served to anyone. Like GitHub Packages, the registry serves + * the files under `/github` only to a request carrying the [token], and redirects + * the download of any of them but `maven-metadata.xml` to storage of another origin. + * A token sent to `/ar` or to the storage counts as a [leaked one][leakedTokens]. + */ +private class Registry(@Volatile var root: File, private val token: String) : AutoCloseable { + + private val server = loopbackServer() + + /** + * The storage that the downloads from `/github` are redirected to. + */ + private val storage = loopbackServer() + + /** + * The number of requests that carried a token to where it does not belong. + */ + val leakedTokens = AtomicInteger() + + /** + * The URL of this registry. + */ + val url: String + get() = server.url() + + init { + server.createContext("/") { exchange -> exchange.use { respond(it) } } + storage.createContext("/") { exchange -> + exchange.use { + it.authorization()?.let { leakedTokens.incrementAndGet() } + serve(it, root.resolve(it.requestURI.path.removePrefix("/"))) + } + } + server.start() + storage.start() + } + + private fun respond(exchange: HttpExchange) { + val path = exchange.requestURI.path + val authorization = exchange.authorization() + val file = root.resolve(path.removePrefix("/")) + val gitHub = path.startsWith("/github/") + if (!gitHub && authorization != null) { + leakedTokens.incrementAndGet() + } + when { + gitHub && !authorization.carriesToken() -> { + exchange.requestBody.readBytes() + exchange.responseHeaders.add("WWW-Authenticate", "Basic realm=\"github\"") + exchange.sendResponseHeaders(401, -1) + } + exchange.requestMethod == "PUT" -> { + file.parentFile.mkdirs() + file.writeBytes(exchange.requestBody.readBytes()) + exchange.sendResponseHeaders(201, -1) + } + exchange.requestMethod == "HEAD" -> + exchange.sendResponseHeaders(if (file.isFile) 200 else 404, -1) + gitHub && file.isFile && file.name != MavenMetadata.FILE_NAME -> { + exchange.responseHeaders.add("Location", "${storage.url()}$path") + exchange.sendResponseHeaders(302, -1) + } + else -> serve(exchange, file) + } + } + + private fun serve(exchange: HttpExchange, file: File) { + if (!file.isFile) { + exchange.sendResponseHeaders(404, -1) + return + } + val bytes = file.readBytes() + exchange.sendResponseHeaders(200, bytes.size.toLong()) + exchange.responseBody.write(bytes) + } + + private fun String?.carriesToken(): Boolean { + val credentials = this?.takeIf { it.startsWith("Basic ") }?.removePrefix("Basic ") + ?: return false + val decoded = try { + String(Base64.getDecoder().decode(credentials)) + } catch (_: IllegalArgumentException) { + return false + } + return decoded.endsWith(":$token") + } + + override fun close() { + server.stop(0) + storage.stop(0) + } +} + +private fun loopbackServer(): HttpServer = + HttpServer.create(InetSocketAddress(InetAddress.getLoopbackAddress(), 0), 0) + +/** + * Obtains the URL of this server. + * + * The loopback address may be an IPv6 one, which [URI] encloses in square brackets. + */ +private fun HttpServer.url(): String = + URI("http", null, address.hostString, address.port, null, null, null).toString() + +private fun HttpExchange.authorization(): String? = requestHeaders.getFirst("Authorization") diff --git a/buildSrc/src/test/kotlin/io/spine/gradle/publish/PublicationStateSpec.kt b/buildSrc/src/test/kotlin/io/spine/gradle/publish/PublicationStateSpec.kt new file mode 100644 index 0000000..844d245 --- /dev/null +++ b/buildSrc/src/test/kotlin/io/spine/gradle/publish/PublicationStateSpec.kt @@ -0,0 +1,350 @@ +/* + * Copyright 2026 CodeMatters, Lda. + * + * 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 io.spine.gradle.publish + +import io.kotest.matchers.collections.shouldBeEmpty +import io.kotest.matchers.collections.shouldContainExactly +import io.kotest.matchers.collections.shouldContainExactlyInAnyOrder +import io.kotest.matchers.shouldBe +import io.spine.gradle.publish.PublicationState.Finding +import io.spine.gradle.publish.PublicationState.Holding +import io.spine.gradle.publish.PublicationState.Presence +import io.spine.gradle.publish.PublicationState.Verdict +import org.junit.jupiter.api.DisplayName +import org.junit.jupiter.api.Nested +import org.junit.jupiter.api.Test + +@DisplayName("`PublicationState` should") +internal class PublicationStateSpec { + + @Nested inner class + `find the version unpublished` { + + @Test + fun `when there is no publication to look up`() { + Verdict.of(emptyList(), commit) shouldBe Verdict.UNPUBLISHED + } + + @Test + fun `when no publication is published anywhere`() { + Verdict.of(listOf(absent(api), absent(backend)), commit) shouldBe + Verdict.UNPUBLISHED + } + } + + @Test + fun `find the version published when every SBOM names the commit being published`() { + val findings = listOf(complete(api, commit), complete(backend, commit), marker()) + + Verdict.of(findings, commit) shouldBe Verdict.PUBLISHED + } + + @Nested inner class + `find the version partially published` { + + @Test + fun `when some publications are not published`() { + Verdict.of(listOf(complete(api, commit), absent(backend)), commit) shouldBe + Verdict.PARTIAL + } + + @Test + fun `when a publication is partially published`() { + Verdict.of(listOf(complete(api, commit), partial(backend)), commit) shouldBe + Verdict.PARTIAL + } + + @Test + fun `even when the published ones name another commit`() { + val findings = listOf(complete(api, otherCommit), absent(backend)) + + Verdict.of(findings, commit) shouldBe Verdict.PARTIAL + } + + @Test + fun `even when the commit being published is unknown`() { + val findings = listOf(complete(api, commit), partial(backend)) + + Verdict.of(findings, commit = null) shouldBe Verdict.PARTIAL + } + } + + @Nested inner class + `find a collision` { + + @Test + fun `when an SBOM names another commit`() { + Verdict.of(listOf(complete(api, otherCommit)), commit) shouldBe Verdict.COLLISION + } + + @Test + fun `when SBOMs name both the commit being published and another one`() { + val findings = listOf(complete(api, commit), complete(backend, otherCommit)) + + Verdict.of(findings, commit) shouldBe Verdict.COLLISION + } + + @Test + fun `when the copies of one SBOM in its destinations name different commits`() { + val findings = listOf( + Finding( + path = api, + version = version, + presence = Presence.COMPLETE, + commits = setOf(commit, otherCommit) + ) + ) + + Verdict.of(findings, commit) shouldBe Verdict.COLLISION + } + } + + @Nested inner class + `leave the publisher unconfirmed` { + + @Test + fun `when no published SBOM names a commit`() { + Verdict.of(listOf(marker()), commit) shouldBe Verdict.UNCONFIRMED + } + + @Test + fun `when the commit being published is unknown`() { + Verdict.of(listOf(complete(api, commit)), commit = null) shouldBe + Verdict.UNCONFIRMED + } + + @Test + fun `when a copy of an SBOM names no commit, beside a confirmed publication`() { + val unknownRevision = Finding( + path = backend, + version = version, + presence = Presence.COMPLETE, + unconfirmed = true + ) + val findings = listOf(complete(api, commit), unknownRevision) + + Verdict.of(findings, commit) shouldBe Verdict.UNCONFIRMED + } + } + + @Nested inner class + `find a publication` { + + @Test + fun `absent when no repository has anything of it`() { + val holdings = listOf(holding(registry), holding(gitHub)) + + presence(holdings) shouldBe Presence.ABSENT + } + + @Test + fun `complete when every repository lists it and has every file`() { + val holdings = listOf( + holding(registry, listed = true, present = names + module), + holding(gitHub, listed = true, present = names + module) + ) + + presence(holdings) shouldBe Presence.COMPLETE + } + + @Test + fun `complete without module metadata in any repository`() { + val holdings = listOf( + holding(registry, listed = true, present = names), + holding(gitHub, listed = true, present = names) + ) + + presence(holdings) shouldBe Presence.COMPLETE + } + + @Test + fun `partial when a repository has nothing of it`() { + val holdings = listOf(holding(registry, listed = true, present = names), holding(gitHub)) + + presence(holdings) shouldBe Presence.PARTIAL + } + + @Test + fun `partial when a repository lacks a file`() { + val holdings = listOf( + holding(registry, listed = true, present = names), + holding(gitHub, listed = true, present = names - sources) + ) + + presence(holdings) shouldBe Presence.PARTIAL + } + + @Test + fun `partial when only some repositories have the module metadata`() { + val holdings = listOf( + holding(registry, listed = true, present = names + module), + holding(gitHub, listed = true, present = names) + ) + + presence(holdings) shouldBe Presence.PARTIAL + } + + @Test + fun `partial when a repository has its files but does not list it`() { + val holdings = listOf(holding(registry, listed = false, present = names)) + + presence(holdings) shouldBe Presence.PARTIAL + } + + @Test + fun `partial when a repository lists it but has none of its files`() { + val holdings = listOf(holding(registry, listed = true)) + + presence(holdings) shouldBe Presence.PARTIAL + } + } + + @Nested inner class + `tell what is missing from` { + + @Test + fun `each repository that lacks anything`() { + val holdings = listOf( + holding(registry, listed = true, present = names + module), + holding(gitHub, listed = false, present = names - sources) + ) + + val gaps = PublicationState.gapsOf( + holdings = holdings, + path = api, + names = names, + module = module + ) + + gaps.keys shouldContainExactly setOf(gitHub) + gaps.getValue(gitHub) shouldContainExactly listOf( + "the version in `$gitHub/$api/maven-metadata.xml`", + "`$sources` in `$gitHub`", + "`$module` in `$gitHub`" + ) + } + + @Test + fun `no repository when the publication has no module metadata anywhere`() { + val holdings = listOf( + holding(registry, listed = true, present = names), + holding(gitHub, listed = true, present = names) + ) + + val gaps = PublicationState.gapsOf( + holdings = holdings, + path = api, + names = names, + module = module + ) + + gaps.keys.shouldBeEmpty() + } + } + + @Nested inner class + `read the revisions of an SBOM` { + + @Test + fun `of every module of the build`() { + val text = """ + { "packages": [ + { "sourceInfo": "git+https://github.com/o/r@$commit#core[:core]" }, + { "sourceInfo": "git+https://github.com/o/r@$commit#client[:client]" } + ] } + """.trimIndent() + + PublicationState.sbomRevisions(text) shouldContainExactlyInAnyOrder setOf(commit) + } + + @Test + fun `from a URI with a user`() { + val text = """"sourceInfo": "git+ssh://git@github.com/o/r@$otherCommit#m[:m]"""" + + PublicationState.sbomRevisions(text) shouldContainExactlyInAnyOrder + setOf(otherCommit) + } + + @Test + fun `of SHA-256 commits`() { + val sha256 = "ab".repeat(32) + val text = """"sourceInfo": "git+https://github.com/o/r@$sha256#m[:m]"""" + + PublicationState.sbomRevisions(text) shouldContainExactlyInAnyOrder setOf(sha256) + } + + @Test + fun `ignoring a revision that is not a full commit hash`() { + val text = """ + { "sourceInfo": "git+https://github.com/o/r@unknown#m[:m]" } + { "sourceInfo": "git+https://github.com/o/r@35054d78#m[:m]" } + { "sourceInfo": "git+https://github.com/o/r@${commit}0#m[:m]" } + """.trimIndent() + + PublicationState.sbomRevisions(text).shouldBeEmpty() + } + } + + private companion object { + + const val version = "2.0.0-SNAPSHOT.575" + const val api = "io/spine/sample/api" + const val backend = "io/spine/sample/backend" + const val commit = "35054d78dfce2a0ead2ca79347ad57f74508977c" + const val otherCommit = "2b98e1801a0b3c4d5e6f708192a3b4c5d6e7f809" + + const val registry = "https://europe-maven.pkg.dev/spine-event-engine/snapshots" + const val gitHub = "https://maven.pkg.github.com/SpineEventEngine/sample" + const val sources = "api-$version-sources.jar" + const val module = "api-$version.module" + val names = listOf("api-$version.jar", sources, "api-$version.pom") + + fun absent(path: String) = + Finding(path = path, version = version, presence = Presence.ABSENT) + + fun partial(path: String) = + Finding(path = path, version = version, presence = Presence.PARTIAL) + + fun complete(path: String, sbomCommit: String) = + Finding( + path = path, + version = version, + presence = Presence.COMPLETE, + commits = setOf(sbomCommit) + ) + + /** + * The marker of a Gradle plugin, which is published with no SBOM. + */ + fun marker() = Finding( + path = "io/spine/sample/io.spine.sample.gradle.plugin", + version = version, + presence = Presence.COMPLETE + ) + + fun holding( + destination: String, + listed: Boolean = false, + present: Collection = emptyList() + ) = Holding(destination = destination, listed = listed, present = present.toSet()) + + /** + * Decides how much of the publication with the [names] and the [module] metadata + * the given [holdings] have. + */ + fun presence(holdings: List) = + PublicationState.presenceOf(holdings = holdings, names = names, module = module) + } +} diff --git a/buildSrc/src/test/kotlin/io/spine/gradle/publish/RemoteFileSpec.kt b/buildSrc/src/test/kotlin/io/spine/gradle/publish/RemoteFileSpec.kt new file mode 100644 index 0000000..ce6131c --- /dev/null +++ b/buildSrc/src/test/kotlin/io/spine/gradle/publish/RemoteFileSpec.kt @@ -0,0 +1,405 @@ +/* + * Copyright 2026 CodeMatters, Lda. + * + * 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 io.spine.gradle.publish + +import com.sun.net.httpserver.HttpExchange +import com.sun.net.httpserver.HttpServer +import io.kotest.assertions.throwables.shouldThrow +import io.kotest.matchers.collections.shouldContainExactly +import io.kotest.matchers.comparables.shouldBeGreaterThanOrEqualTo +import io.kotest.matchers.nulls.shouldBeNull +import io.kotest.matchers.shouldBe +import io.kotest.matchers.string.shouldContain +import io.kotest.matchers.string.shouldNotContain +import java.io.File +import java.io.IOException +import java.net.InetAddress +import java.net.InetSocketAddress +import java.net.URI +import java.net.URL +import java.util.concurrent.CopyOnWriteArrayList +import kotlin.time.Duration.Companion.seconds +import kotlin.time.measureTime +import org.junit.jupiter.api.AfterEach +import org.junit.jupiter.api.DisplayName +import org.junit.jupiter.api.Nested +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.io.TempDir + +@DisplayName("`RemoteFile` should") +internal class RemoteFileSpec { + + private val server = Server() + + /** + * Another origin, such as the storage that GitHub Packages redirects a download to. + */ + private val storage = Server() + + @AfterEach + fun stopServers() { + server.close() + storage.close() + } + + @Nested inner class + `read a file` { + + @Test + fun `answered with its text`() { + server.answer(200) + + RemoteFile.readText(server.url("file.txt")) shouldBe body + } + + @Test + fun `telling at once that there is no file`() { + server.answer(404) + + RemoteFile.readText(server.url("file.txt")).shouldBeNull() + server.requests.size shouldBe 1 + } + + @Test + fun `retrying after a server error`() { + server.answer(503, 200) + + RemoteFile.readText(server.url("file.txt")) shouldBe body + server.requests.size shouldBe 2 + } + + @Test + fun `retrying after throttling`() { + server.answer(429, 200) + + RemoteFile.readText(server.url("file.txt")) shouldBe body + server.requests.size shouldBe 2 + } + + @Test + fun `retrying after a rate limit`() { + server.rateLimit(then = 200) + + RemoteFile.readText(server.url("file.txt")) shouldBe body + server.requests.size shouldBe 2 + } + + @Test + fun `waiting before a retry as long as the server asks`() { + server.throttle(retryAfter = "2", then = 200) + + val elapsed = measureTime { + RemoteFile.readText(server.url("file.txt")) shouldBe body + } + + elapsed shouldBeGreaterThanOrEqualTo 2.seconds + server.requests.size shouldBe 2 + } + + @Test + fun `failing after the last attempt`() { + server.answer(500) + + shouldThrow { RemoteFile.readText(server.url("file.txt")) } + server.requests.size shouldBe 3 + } + + @Test + fun `not retrying a request the server refuses`() { + server.answer(403) + + val error = shouldThrow { + RemoteFile.readText(server.url("file.txt")) + } + + error.message shouldContain "403" + server.requests.size shouldBe 1 + } + + @Test + fun `on disk, telling that there is no such file`(@TempDir dir: File) { + val url = dir.resolve("missing.xml").toURI().toURL() + + RemoteFile.readText(url).shouldBeNull() + } + } + + @Nested inner class + `follow a redirect` { + + @Test + fun `to another origin, without the authorization`() { + server.redirect(storage.url("blob/file.txt").toString()) + storage.answer(200) + + RemoteFile.readText(server.url("file.txt"), authorization) shouldBe body + + server.requests.map { it.authorization } shouldContainExactly listOf(authorization) + storage.requests.map { it.authorization } shouldContainExactly listOf(null) + } + + @Test + fun `within the origin, with the authorization`() { + server.redirect("/moved/file.txt", then = 200) + + RemoteFile.readText(server.url("file.txt"), authorization) shouldBe body + + server.requests.map { it.path } shouldContainExactly + listOf("/file.txt", "/moved/file.txt") + server.requests.map { it.authorization } shouldContainExactly + listOf(authorization, authorization) + } + + @Test + fun `only a few times`() { + server.redirect("/file.txt") + + val error = shouldThrow { + RemoteFile.readText(server.url("file.txt")) + } + + error.message shouldContain "Too many redirects" + } + + @Test + fun `only to a location given`() { + server.redirect(location = null) + + val error = shouldThrow { + RemoteFile.readText(server.url("file.txt")) + } + + error.message shouldContain "no `Location`" + } + + @Test + fun `only to an HTTP location`() { + server.redirect("file:///etc/hosts") + + val error = shouldThrow { + RemoteFile.readText(server.url("file.txt")) + } + + error.message shouldContain "may not be followed" + } + + @Test + fun `showing no query in a message`() { + server.redirect("${storage.url("blob/file.txt")}?signature=secret") + storage.answer(403) + + val error = shouldThrow { + RemoteFile.readText(server.url("file.txt")) + } + + error.message shouldNotContain "secret" + } + } + + @Nested inner class + `tell whether there is a file` { + + @Test + fun `answered with a success`() { + server.answer(200) + + RemoteFile.exists(server.url("file.txt")) shouldBe true + server.requests.map { it.method } shouldContainExactly listOf("HEAD") + } + + @Test + fun `answered with no such file`() { + server.answer(404) + + RemoteFile.exists(server.url("file.txt")) shouldBe false + } + + @Test + fun `answered with a gone file`() { + server.answer(410) + + RemoteFile.exists(server.url("file.txt")) shouldBe false + } + + @Test + fun `redirected to another origin, following without the authorization`() { + server.redirect(storage.url("blob/file.txt").toString()) + storage.answer(200) + + RemoteFile.exists(server.url("file.txt"), authorization) shouldBe true + storage.requests shouldContainExactly + listOf(Request(method = "HEAD", path = "/blob/file.txt", authorization = null)) + } + + @Test + fun `redirected to another origin that has no such file`() { + server.redirect(storage.url("blob/file.txt").toString()) + storage.answer(404) + + RemoteFile.exists(server.url("file.txt")) shouldBe false + } + + @Test + fun `redirected within the origin, following`() { + server.redirect("/moved/file.txt", then = 404) + + RemoteFile.exists(server.url("file.txt")) shouldBe false + server.requests.size shouldBe 2 + } + + @Test + fun `retrying after a request timeout`() { + server.answer(408, 200) + + RemoteFile.exists(server.url("file.txt")) shouldBe true + server.requests.size shouldBe 2 + } + + @Test + fun `not retrying a request the server refuses`() { + server.answer(401) + + shouldThrow { RemoteFile.exists(server.url("file.txt")) } + server.requests.size shouldBe 1 + } + + @Test + fun `on disk`(@TempDir dir: File) { + val file = dir.resolve("file.txt").apply { writeText(body) } + + RemoteFile.exists(file.toURI().toURL()) shouldBe true + RemoteFile.exists(dir.resolve("missing.txt").toURI().toURL()) shouldBe false + } + } + + private companion object { + const val body = "" + const val authorization = "Bearer test-token" + } +} + +/** + * A request received by a [Server]. + */ +private data class Request(val method: String, val path: String, val authorization: String?) + +/** + * A loopback HTTP server, which answers each request as told, and records the requests. + */ +private class Server : AutoCloseable { + + private val server: HttpServer = + HttpServer.create(InetSocketAddress(InetAddress.getLoopbackAddress(), 0), 0) + + /** + * The requests received so far. + */ + val requests = CopyOnWriteArrayList() + + @Volatile + private var respond: (HttpExchange, Int) -> Unit = { exchange, _ -> exchange.reply(404) } + + init { + server.createContext("/") { exchange -> + exchange.use { + requests.add( + Request( + method = it.requestMethod, + path = it.requestURI.path, + authorization = it.requestHeaders.getFirst("Authorization") + ) + ) + respond(it, requests.size - 1) + } + } + server.start() + } + + /** + * Obtains the URL of the given [path] at this server. + * + * The loopback address may be an IPv6 one, which [URI] encloses in square brackets. + */ + fun url(path: String): URL { + val address = server.address + return URI("http", null, address.hostString, address.port, "/$path", null, null) + .toURL() + } + + /** + * Answers each request with the next of the given [statuses], repeating the last one. + */ + fun answer(vararg statuses: Int) { + respond = { exchange, index -> exchange.reply(statuses[minOf(index, statuses.lastIndex)]) } + } + + /** + * Redirects the first request to the given [location], or with no `Location` if it is + * `null`, and answers the next ones with the given status, or with the same redirect. + */ + fun redirect(location: String?, then: Int? = null) { + respond = { exchange, index -> + if (index == 0 || then == null) { + location?.let { exchange.responseHeaders.add("Location", it) } + exchange.sendResponseHeaders(302, -1) + } else { + exchange.reply(then) + } + } + } + + /** + * Refuses the first request for exceeding a rate limit, as GitHub does with + * `403 Forbidden` and a `Retry-After` header, and answers the next ones with + * the given status. + */ + fun rateLimit(then: Int) { + respond = { exchange, index -> + if (index == 0) { + exchange.responseHeaders.add("Retry-After", "1") + exchange.sendResponseHeaders(403, -1) + } else { + exchange.reply(then) + } + } + } + + /** + * Answers the first request with `429 Too Many Requests` and the given `Retry-After` + * header, and the next ones with the given status. + */ + fun throttle(retryAfter: String, then: Int) { + respond = { exchange, index -> + if (index == 0) { + exchange.responseHeaders.add("Retry-After", retryAfter) + exchange.sendResponseHeaders(429, -1) + } else { + exchange.reply(then) + } + } + } + + override fun close() = server.stop(0) + + private fun HttpExchange.reply(status: Int) { + val bytes = if (status == 200 && requestMethod != "HEAD") { + "".toByteArray() + } else { + byteArrayOf() + } + sendResponseHeaders(status, if (bytes.isEmpty()) -1 else bytes.size.toLong()) + responseBody.write(bytes) + } +} diff --git a/buildSrc/src/test/kotlin/io/spine/gradle/publish/SpinePublishingTest.kt b/buildSrc/src/test/kotlin/io/spine/gradle/publish/SpinePublishingTest.kt index c97f30f..3e40704 100644 --- a/buildSrc/src/test/kotlin/io/spine/gradle/publish/SpinePublishingTest.kt +++ b/buildSrc/src/test/kotlin/io/spine/gradle/publish/SpinePublishingTest.kt @@ -40,8 +40,8 @@ class SpinePublishingTest { extension = project.spinePublishing { } } - @Nested - inner class `calculate 'artifactId'` { + @Nested inner class + `calculate 'artifactId'` { @Test fun `with default prefix for non-tool projects`() { @@ -105,8 +105,8 @@ class SpinePublishingTest { } } - @Nested - inner class `validate configuration` { + @Nested inner class + `validate configuration` { @Test fun `ensuring 'testJar' inclusions are published`() { @@ -155,8 +155,8 @@ class SpinePublishingTest { } } - @Nested - inner class `identify 'projectsToPublish'` { + @Nested inner class + `identify 'projectsToPublish'` { @Test fun `as the project itself if no modules are specified`() { @@ -193,8 +193,8 @@ class SpinePublishingTest { } } - @Nested - inner class `resolve 'publishTo' repositories` { + @Nested inner class + `resolve 'publishTo' repositories` { @Test fun `from the extension itself if destinations are initialized`() { diff --git a/buildSrc/src/test/kotlin/io/spine/gradle/report/coverage/FileExtensionsTest.kt b/buildSrc/src/test/kotlin/io/spine/gradle/report/coverage/FileExtensionsTest.kt index c457bfa..6890411 100644 --- a/buildSrc/src/test/kotlin/io/spine/gradle/report/coverage/FileExtensionsTest.kt +++ b/buildSrc/src/test/kotlin/io/spine/gradle/report/coverage/FileExtensionsTest.kt @@ -28,8 +28,8 @@ class FileExtensionsTest { @TempDir lateinit var sourceRoot: File - @Nested - inner class `for Java sources` { + @Nested inner class + `for Java sources` { @Test fun `return a single FQN`() { @@ -46,8 +46,8 @@ class FileExtensionsTest { } } - @Nested - inner class `for Kotlin sources` { + @Nested inner class + `for Kotlin sources` { @Test fun `return both the declared class and the synthetic file class`() { @@ -70,8 +70,8 @@ class FileExtensionsTest { } } - @Nested - inner class `for proto-file-scoped Kotlin sources` { + @Nested inner class + `for proto-file-scoped Kotlin sources` { @Test fun `strip the two-part 'proto-kt' suffix`() { @@ -84,8 +84,8 @@ class FileExtensionsTest { } } - @Nested - inner class `for unsupported inputs` { + @Nested inner class + `for unsupported inputs` { @Test fun `return an empty list for non-source files`() { diff --git a/config b/config index 604420c..ad3dff0 160000 --- a/config +++ b/config @@ -1 +1 @@ -Subproject commit 604420cd7eab82b382c9a5c1d812be454552c27c +Subproject commit ad3dff0890c7716cbba3fe2ce17bf4fe5905a318 From 178d633619709ea272c6e28cf1ae594ccf15f559 Mon Sep 17 00:00:00 2001 From: alexander-yevsyukov Date: Thu, 22 Oct 2026 15:05:20 +0100 Subject: [PATCH 15/17] Restore the local pins `./config/pull` lowered The pull of `config` `ad3dff08` brought its older pins back. `config`'s `dependency/local` has not changed since the wave's `604420cd`, so the pins from before the pull are the wave's. Co-Authored-By: Claude Opus 5.5 --- buildSrc/src/main/kotlin/io/spine/dependency/local/Base.kt | 2 +- buildSrc/src/main/kotlin/io/spine/dependency/local/Compiler.kt | 2 +- .../main/kotlin/io/spine/dependency/local/CoreJvmCompiler.kt | 2 +- .../src/main/kotlin/io/spine/dependency/local/Validation.kt | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/buildSrc/src/main/kotlin/io/spine/dependency/local/Base.kt b/buildSrc/src/main/kotlin/io/spine/dependency/local/Base.kt index 45c1d2f..baaf5c7 100644 --- a/buildSrc/src/main/kotlin/io/spine/dependency/local/Base.kt +++ b/buildSrc/src/main/kotlin/io/spine/dependency/local/Base.kt @@ -24,7 +24,7 @@ package io.spine.dependency.local "unused" /* Some subprojects do not use all Base artifacts. */, ) object Base { - const val version = "2.0.0-SNAPSHOT.461" + const val version = "2.0.0-SNAPSHOT.462" const val versionForBuildScript = "2.0.0-SNAPSHOT.461" const val group = Spine.group private const val prefix = "spine" diff --git a/buildSrc/src/main/kotlin/io/spine/dependency/local/Compiler.kt b/buildSrc/src/main/kotlin/io/spine/dependency/local/Compiler.kt index 137e830..1582193 100644 --- a/buildSrc/src/main/kotlin/io/spine/dependency/local/Compiler.kt +++ b/buildSrc/src/main/kotlin/io/spine/dependency/local/Compiler.kt @@ -60,7 +60,7 @@ object Compiler : Dependency() { * The version of the Compiler dependencies. */ override val version: String - private const val fallbackVersion = "2.0.0-SNAPSHOT.069" + private const val fallbackVersion = "2.0.0-SNAPSHOT.080" /** * The distinct version of the Compiler used by other build tools. diff --git a/buildSrc/src/main/kotlin/io/spine/dependency/local/CoreJvmCompiler.kt b/buildSrc/src/main/kotlin/io/spine/dependency/local/CoreJvmCompiler.kt index 1af2694..087a2fa 100644 --- a/buildSrc/src/main/kotlin/io/spine/dependency/local/CoreJvmCompiler.kt +++ b/buildSrc/src/main/kotlin/io/spine/dependency/local/CoreJvmCompiler.kt @@ -39,7 +39,7 @@ object CoreJvmCompiler { /** * The version to be used for integration tests. */ - const val version = "2.0.0-SNAPSHOT.097" + const val version = "2.0.0-SNAPSHOT.099" /** * The ID of the Gradle plugin. diff --git a/buildSrc/src/main/kotlin/io/spine/dependency/local/Validation.kt b/buildSrc/src/main/kotlin/io/spine/dependency/local/Validation.kt index 155cbbc..1be9aff 100644 --- a/buildSrc/src/main/kotlin/io/spine/dependency/local/Validation.kt +++ b/buildSrc/src/main/kotlin/io/spine/dependency/local/Validation.kt @@ -27,7 +27,7 @@ object Validation { /** * The version of the Validation library artifacts. */ - const val version = "2.0.0-SNAPSHOT.464" + const val version = "2.0.0-SNAPSHOT.469" const val group = Spine.toolsGroup private const val prefix = "validation" From 0da863d90bf04a0b44f683b66dbdb65b25c200c9 Mon Sep 17 00:00:00 2001 From: alexander-yevsyukov Date: Thu, 22 Oct 2026 15:05:49 +0100 Subject: [PATCH 16/17] Update local dependency pins --- buildSrc/src/main/kotlin/io/spine/dependency/local/Compiler.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/buildSrc/src/main/kotlin/io/spine/dependency/local/Compiler.kt b/buildSrc/src/main/kotlin/io/spine/dependency/local/Compiler.kt index 1582193..66a3e8c 100644 --- a/buildSrc/src/main/kotlin/io/spine/dependency/local/Compiler.kt +++ b/buildSrc/src/main/kotlin/io/spine/dependency/local/Compiler.kt @@ -60,7 +60,7 @@ object Compiler : Dependency() { * The version of the Compiler dependencies. */ override val version: String - private const val fallbackVersion = "2.0.0-SNAPSHOT.080" + private const val fallbackVersion = "2.0.0-SNAPSHOT.081" /** * The distinct version of the Compiler used by other build tools. From bc59e6ed9ee2b39459472e6882fc09d35212fce6 Mon Sep 17 00:00:00 2001 From: alexander-yevsyukov Date: Thu, 22 Oct 2026 15:24:06 +0100 Subject: [PATCH 17/17] Update dependency reports --- docs/dependencies/dependencies.md | 2 +- docs/dependencies/pom.xml | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/dependencies/dependencies.md b/docs/dependencies/dependencies.md index f13c21e..a16665b 100644 --- a/docs/dependencies/dependencies.md +++ b/docs/dependencies/dependencies.md @@ -1028,6 +1028,6 @@ The dependencies distributed under several licenses, are used according their commercial-use-friendly license. -This report was generated on **Wed Oct 21 17:39:24 WEST 2026** using +This report was generated on **Thu Oct 22 15:23:43 WEST 2026** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). \ No newline at end of file diff --git a/docs/dependencies/pom.xml b/docs/dependencies/pom.xml index 68605fb..33136e4 100644 --- a/docs/dependencies/pom.xml +++ b/docs/dependencies/pom.xml @@ -140,12 +140,12 @@ all modules and does not describe the project structure per-subproject. io.spine.tools compiler-cli-all - 2.0.0-SNAPSHOT.080 + 2.0.0-SNAPSHOT.081 io.spine.tools compiler-protoc-plugin - 2.0.0-SNAPSHOT.080 + 2.0.0-SNAPSHOT.081 io.spine.tools