diff --git a/.agents/tasks/de-event-sourcing-rollout.md b/.agents/tasks/de-event-sourcing-rollout.md new file mode 100644 index 000000000..e9f79ed37 --- /dev/null +++ b/.agents/tasks/de-event-sourcing-rollout.md @@ -0,0 +1,115 @@ +# Adopt the de-event-sourcing storage API of core-jvm (Phase H rollout) + +Upstream plan: `core-jvm/.agents/tasks/de-event-sourcing-plan.md`, Phase H. +Branch: `de-event-sourcing`. Depends on core-jvm `2.0.0-SNAPSHOT.522`. +Reference implementation: `jdbc-storage@de-event-sourcing` (PR #181 train), +which settled the vendor conventions with the product owner on 2026-08-04. + +## Problem + +Event-sourced aggregate loading is removed in `core-jvm`. For storage vendors: + +- `AggregateStorage`, `StorageFactory.createAggregateStorage`, and the + published `AggregateStorageTest`/`AggregateHistoryTruncationTest` fixtures + are **removed**. Aggregate latest state arrives via + `createEntityRecordStorage`/`createRecordStorage` with `group == null`. +- `createRecordStorage` gained a `@Nullable StorageGroup group` parameter and + is now the factory's only abstract method. Non-null groups arrive from the + per-entity histories (`EntityEventStorage`, `EntityStateHistoryStorage`), + both named after the entity state type. The vendor must allocate physical + storage by the **(source type, record type, group)** triple. +- `createEntityStateHistoryStorage` may be invoked concurrently (delivery + worker threads); the factory must tolerate that. +- The published `RecordStorageDelegateTest` base is now `DelegatingRecordStorageTest`. + +Without honoring the group, Datastore kind identity (derived from +`RecordSpec.sourceType()` alone via `RecordLayout` → `Kind.of(domainType)`) +conflates: all event journals with each other **and** with the event log +(`sourceType == Event` everywhere), and an entity's state history with its +latest-state kind (both `sourceType == the state class`, +records stored as `EntityRecord`s). + +## Fix + +Mechanical half: + +- 3-arg `createRecordStorage` in `DatastoreStorageFactory`. +- `DsRecordStorageTest` retargeted at `DelegatingRecordStorageTest`. +- Obsolete `DsAggregateStorageTest`, `DsAggregateStorageTruncationTest` + deleted (their published bases are gone). +- Compile-driven fallout fixes across `datastore` and `testlib`. + +Substantive half: + +- Grouped kind naming follows the jdbc rule (generic rule over semantic + suffixes): grouped kind = group name + `-` + record type simple name, + e.g. `spine.test.storage.StgProject-Event`. Implemented as a new + `Kind.of(recordType, group)` factory method. +- `DatastoreStorageFactory.configurationWith(...)` threads the group into + the layout choice: grouped storages always take a `FlatLayout` with the + grouped kind. Custom layouts (`organizeRecords`) and custom storages + (`useRecordStorage`/`useEntityStorage`) keep applying to **ungrouped** + storages only — honoring either for a grouped storage would re-create the + collision (or hand the history to a storage meant for latest state). +- `TxSettings` stay keyed by `sourceType` and therefore also serve grouped + storages (mirrors jdbc's decision that source-type-keyed settings extend + to grouped tables). +- `DatastoreStorageFactory.wrapperFor(...)` becomes `computeIfAbsent` — + the check-then-put race matters now that the state history storage is + created lazily on delivery worker threads. + +New Kotlin specs (Datastore emulator, mirroring jdbc's suite): + +- `GroupedKindAllocationSpec` — the vendor allocation contract: distinct + kinds per (source type, record type, group); `null` group unchanged. +- `DsEntityEventStorageSpec` — journal round-trip, `historyBackward` window, `truncate`. +- `DsEntityStateHistoryStorageSpec` — round-trips incl. the `EntityStateKey` + Message ID, upsert overwrite on same version, `stateAt`, `trim`, `truncate`. +- `ConcurrentHistoryCreationSpec` — concurrent + `createEntityStateHistoryStorage` tolerance. + +## Settled while implementing + +- Grouped kind naming: `Kind.of(recordType, group)` → group name + `-` + + record type simple name (`spine.test.storage.StgProject-Event`), following + the jdbc "group + record type" rule (product owner, 2026-08-04). The joiner + is a dash — a character illegal in Protobuf type names — so a grouped kind + never collides with a type-name-derived ungrouped kind, even for sibling + types like `Order` and `Order_Event` (Codex review of PR #204; jdbc's `_` + joiner retains that ambiguity under SQL identifier constraints). +- `RecordLayout`/`FlatLayout` gained `Kind`-accepting constructors, so a + grouped storage can carry a kind not derived from a record type alone. +- The two dead suites (`DsAggregateStorageTest`, + `DsAggregateStorageTruncationTest`) are deleted; + `DsRecordStorageTest` retargeted at `DelegatingRecordStorageTest`. +- The branch's `Update config` had reverted the Testcontainers `2.0.5` pin + (PR #202) back to config's `1.21.4`, breaking `testlib` compilation. + The pin is re-applied, now in `config`'s KDoc style with the 2.x + `testcontainers-` artifact renames spelled out — the shape intended for + the `config` repo, where the lasting fix belongs (flagged as + a separate task). + +- Custom naming/layout for grouped kinds (the Datastore analog of jdbc's + `setTableName(stateType, recordType, name)` overload, requested for jdbc + in the review of its PR #181): the new + `organizeRecords(stateType, recordType, layout)` builder overload + registers a `RecordLayout` — carrying a custom kind, an ancestor + structure, or both — for the grouped storage addressed by the storage + group (named by the framework after the entity state type) paired with + the record type. Registrations live in `RecordLayouts` keyed by + `(group name, record type)`; the single-type `organizeRecords` keeps + applying to ungrouped storages only. `EntityGroupLayout` gained + a `Kind`-accepting constructor for parity with `FlatLayout`. + +## Follow-ups (out of scope) + +- `DsRecordStorage.deleteRecord()` always returns `true` (documented: telling + would take another Datastore request), deviating from the + `RecordStorage.delete` contract ("`false` if not found") that + `HistoryStorage.delete` re-exposes. Decide whether the backend should pay + the existence check, or the framework KDoc should allow the deviation. + +## Status + +Implemented; the four history specs (30 cases) pass against the emulator. +Delete this file on merge to master. diff --git a/.claude/settings.json b/.claude/settings.json index 84a0e53d2..3c7da68c3 100644 --- a/.claude/settings.json +++ b/.claude/settings.json @@ -1,7 +1,9 @@ { "$schema": "https://json.schemastore.org/claude-code-settings.json", + "plansDirectory": ".claude/plans", "permissions": { "allow": [ + "Edit(version.gradle.kts)", "Bash(./gradlew:*)", "Bash(./config/gradlew:*)", "Bash(git status:*)", @@ -31,8 +33,11 @@ "Bash(mkdir:*)", "Bash(touch:*)", "Bash(python3 .agents/skills/update-copyright/scripts/update_copyright.py:*)", + "Bash(.agents/skills/version-bumped/scripts/version-bumped.sh)", "Bash(./config/pull)", - "Bash(./config/migrate)" + "Bash(./config/migrate)", + "Skill(pre-pr)", + "Skill(pre-pr:*)" ], "deny": [ "Bash(git reset --hard:*)", diff --git a/.github/workflows/gradle-wrapper-validation.yml b/.github/workflows/gradle-wrapper-validation.yml index fc0872b4c..44e65e4d3 100644 --- a/.github/workflows/gradle-wrapper-validation.yml +++ b/.github/workflows/gradle-wrapper-validation.yml @@ -16,4 +16,4 @@ jobs: uses: actions/checkout@v6 - name: Validate Gradle Wrapper - uses: gradle/actions/wrapper-validation@v4 + uses: gradle/actions/wrapper-validation@v6 diff --git a/.github/workflows/increment-guard.yml b/.github/workflows/increment-guard.yml index f20b4bed6..9a6333f0f 100644 --- a/.github/workflows/increment-guard.yml +++ b/.github/workflows/increment-guard.yml @@ -1,5 +1,9 @@ -# Ensures that the current lib version is not yet published by executing the Gradle -# `checkVersionIncrement` task. +# Guards the project version by executing the Gradle `checkVersionIncrement` task, +# which verifies that the version is both (a) strictly greater than the base branch +# version in `version.gradle.kts` and (b) not already published. The result is +# published as the `Version Guard` commit status — the context required by branch +# protection and re-published by `revalidate-versions.yml` on the heads of other open +# PRs when the base branch advances (so a stale duplicate bump turns red before merge). # # The check runs only for pull requests targeting a default (`master`/`main`) or # a release-line (e.g. `2.x-jdk8-master`) branch. It is the responsibility of a branch @@ -15,19 +19,45 @@ name: Version Guard on: pull_request: + # Beyond the default activity types (`opened`, `synchronize`, `reopened`), two more are + # needed because they change what the guard must compare against without a new head SHA, + # which would otherwise leave a stale-green `Version Guard` status mergeable: + # * `ready_for_review` — a draft that went stale while in draft becomes ready; and + # * `edited` — the base branch is retargeted (e.g. a release line -> `master`), so the + # strict comparison must be recomputed against the new base. + types: [opened, synchronize, reopened, ready_for_review, edited] jobs: check: name: Check version increment runs-on: ubuntu-latest - # Default and release-line branches, e.g. `master`, `main`, `2.x-jdk8-master`. - if: endsWith(github.base_ref, 'master') || endsWith(github.base_ref, 'main') + # Default and release-line branches, e.g. `master`, `main`, `2.x-jdk8-master`. For an + # `edited` event, run only when the base actually changed (a retarget carries + # `changes.base.ref.from`); title/body edits carry no `changes.base` and are skipped, so + # the guard is not rebuilt needlessly. + if: >- + (endsWith(github.base_ref, 'master') || endsWith(github.base_ref, 'main')) + && (github.event.action != 'edited' || github.event.changes.base.ref.from != '') + + # `statuses: write` lets the job publish the `Version Guard` commit status that + # branch protection requires. + permissions: + contents: read + statuses: write steps: - uses: actions/checkout@v6 with: submodules: 'true' + # `checkVersionIncrement` reads `origin/:version.gradle.kts`. The pull request + # checkout does not include the base branch, so fetch its tip into the expected ref. + - name: Fetch the base branch + shell: bash + run: | + git fetch --no-tags --depth=1 \ + origin "+refs/heads/${GITHUB_BASE_REF}:refs/remotes/origin/${GITHUB_BASE_REF}" + - uses: actions/setup-java@v5 with: java-version: 17 @@ -35,6 +65,36 @@ jobs: - uses: gradle/actions/setup-gradle@v6 - - name: Check version is not yet published + - name: Check version increment + id: guard shell: bash + # `VERSION_GUARD` enables the strict base-branch comparison in `checkVersionIncrement`. + # Only this workflow fetches the base ref (the step above), so the comparison is gated + # to it: other CI builds pull the task in via `publishToMavenLocal` on a shallow + # checkout and must not attempt to read `origin/`. + env: + VERSION_GUARD: "true" run: ./gradlew checkVersionIncrement --stacktrace + + # Publish the verdict as the `Version Guard` commit status on the PR head. Posting it + # on every run (success or failure) is what lets a later re-bump clear a failure that + # `revalidate-versions.yml` set when the base branch advanced. + # + # Skipped for fork PRs: `GITHUB_TOKEN` is read-only for them, so the status cannot be + # posted (and a fork head SHA is not in this repo). The Spine agent workflow pushes PR + # branches to the same repository; fork contributions are handled by a maintainer, who + # owns the version bump. + - name: Report the Version Guard status + if: always() && github.event.pull_request.head.repo.fork == false + shell: bash + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + state=failure + if [ "${{ steps.guard.outcome }}" = "success" ]; then + state=success + fi + gh api -X POST "repos/${{ github.repository }}/statuses/${{ github.event.pull_request.head.sha }}" \ + -f state="${state}" \ + -f context="Version Guard" \ + -f description="Version increment check" diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index df8f6cd01..27c11c0f8 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -64,3 +64,18 @@ jobs: 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'." diff --git a/.github/workflows/revalidate-versions.yml b/.github/workflows/revalidate-versions.yml new file mode 100644 index 000000000..2d2ecb9c6 --- /dev/null +++ b/.github/workflows/revalidate-versions.yml @@ -0,0 +1,57 @@ +# Re-judges every other open pull request when the base branch advances. +# +# Publishing runs on every push to a release base branch, so once one pull request merges +# and bumps the version, any other open PR that bumped to the same (or a lower) value is +# now stale: its publish would collide. GitHub does not re-run a PR's checks when its base +# advances, so this workflow does it actively — for each other open PR whose +# `version.gradle.kts` version is `<=` the new base version, it posts a failing +# `Version Guard` commit status on the PR head, blocking the merge until the author +# re-bumps. The status self-clears: the re-bump push runs `increment-guard.yml`, which +# posts a fresh `success` on the new head. +# +# This narrows, but does not close, the race against auto-merge. A PR that is already +# mergeable can merge in the seconds before this fan-out marks it stale; that late merge +# produces a publish collision which the immutable Maven registry rejects (a loud, +# recoverable red Publish), never an overwrite. The deterministic guarantee is the +# registry's immutability, not this signal. + +name: Revalidate Versions + +on: + push: + # Matches the PR guard's `endsWith(base_ref, 'master'|'main')` and the same scope as + # `build-on-ubuntu.yml`. `**` (unlike `*`) also crosses `/`, so slash-named release + # lines such as `release/2.x-master` are covered. Keeping these definitions identical + # ensures every branch guarded on the PR side is also revalidated here. + branches: + - '**master' + - '**main' + +permissions: + contents: read + statuses: write + pull-requests: read + +concurrency: + # Only the newest tip of a given base matters; a later push to the same ref cancels an + # in-flight fan-out for it. Different bases run independently. + group: revalidate-versions-${{ github.ref }} + cancel-in-progress: true + +jobs: + revalidate: + name: Revalidate open PRs + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v6 + with: + submodules: 'true' + + - name: Revalidate open PRs against the new base version + shell: bash + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + REPO: ${{ github.repository }} + BASE_REF: ${{ github.ref_name }} + # Invoked via `bash` so it does not depend on the script's committed executable bit. + run: bash ./config/scripts/revalidate-versions.sh diff --git a/.gitignore b/.gitignore index bce75e6ed..86fc94c51 100644 --- a/.gitignore +++ b/.gitignore @@ -54,8 +54,12 @@ .idea/modules .idea/shelf +# `.idea/misc.xml` is intentionally NOT re-included below. It is project-local — +# it holds the per-project JDK name and IDEA's own churn (entry-point list +# indices, external-storage toggles) — so `.idea/*.xml` above keeps it ignored. +# `./config/pull` (via `migrate`) untracks any copy an earlier pull committed. + # Do not ignore the following IDEA settings -!.idea/misc.xml !.idea/codeStyleSettings.xml !.idea/codeStyles/ !.idea/copyright/ @@ -173,6 +177,12 @@ __pycache__/ # Claude working files /.claude/worktrees/ +# Ephemeral plan-mode scratch (durable task docs live in `.agents/tasks/`). +/.claude/plans/ + +# Personal, per-developer Claude Code settings overrides (never committed; +# the distributed `.claude/settings.json` is the shared, committed layer). +/.claude/settings.local.json # Auto-downloaded Lychee binary used by the `check-links` skill. /.agents/skills/check-links/.cache/ @@ -191,7 +201,6 @@ docs/_preview/resources/ # >>> repo-local entries (preserved across ./config/pull) >>> # Copyright 2026, TeamDev. All rights reserved. -!.idea/misc.xml !.idea/codeStyleSettings.xml !.idea/codeStyles/ !.idea/copyright/ diff --git a/.idea/live-templates/README.md b/.idea/live-templates/README.md index 950066731..267008ad1 100644 --- a/.idea/live-templates/README.md +++ b/.idea/live-templates/README.md @@ -22,6 +22,6 @@ In order to add these templates, perform the following steps: 1. Open the corresponding template: `Preferences -> Editor -> Live Templates -> User.todo`. 2. Click on `Edit variables`. -3. Set `USER` variable to your domain email address without `@teamdev.com` ending. For example, +3. Set `USER` variable to your domain email address without `@teamdev.com` ending. For example, for `jack.sparrow@teamdev.com` use the following expression `"jack.sparrow"`. 4. Verify that the template generates expected comments: `// TODO:2022-11-03:jack.sparrow: <...>`. diff --git a/.idea/misc.xml b/.idea/misc.xml deleted file mode 100644 index 90e8d8808..000000000 --- a/.idea/misc.xml +++ /dev/null @@ -1,58 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/build.gradle.kts b/build.gradle.kts index db0dc7a2b..e8c466ee3 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -461,7 +461,7 @@ fun Project.setupTestTasks() { } } - val copyCredentials by registering(Copy::class) { + val copyCredentials = register("copyCredentials") { val resourceDir = "$projectDir/src/test/resources" val fileName = "spine-dev.json" val sourceFile = file("$rootDir/$fileName") diff --git a/buildSrc/build.gradle.kts b/buildSrc/build.gradle.kts index a61d839f8..5b377272e 100644 --- a/buildSrc/build.gradle.kts +++ b/buildSrc/build.gradle.kts @@ -132,7 +132,7 @@ val kotestJvmPluginVersion = "0.4.10" /** * @see [io.spine.dependency.test.Kover] */ -val koverVersion = "0.9.8" +val koverVersion = "0.9.9" /** * The version of the Shadow Plugin. @@ -222,7 +222,7 @@ dependOnBuildSrcJar() /** * Adds a dependency on a `buildSrc.jar`, iff: * 1) the `src` folder is missing, and - * 2) `buildSrc.jar` is present in `buildSrc/` folder instead. + * 2) `buildSrc.jar` is present in the `buildSrc/` folder instead. * * This approach is used in the scope of integration testing. */ @@ -241,7 +241,7 @@ fun Project.dependOnBuildSrcJar() { * Includes the `implementation` dependency on `artifactregistry-auth-common`, * with the version defined in [googleAuthToolVersion]. * - * `artifactregistry-auth-common` has transitive dependency on Gson and Apache `commons-codec`. + * `artifactregistry-auth-common` has a transitive dependency on Gson and Apache `commons-codec`. * Gson from version `2.8.6` until `2.8.9` is vulnerable to Deserialization of Untrusted Data * (https://devhub.checkmarx.com/cve-details/CVE-2022-25647/). * diff --git a/buildSrc/quality/checkstyle-suppressions.xml b/buildSrc/quality/checkstyle-suppressions.xml index a761fca35..9d169de7f 100644 --- a/buildSrc/quality/checkstyle-suppressions.xml +++ b/buildSrc/quality/checkstyle-suppressions.xml @@ -1,7 +1,7 @@ io.spine.gcloud gcloud-jvm -2.0.0-SNAPSHOT.214 +2.0.0-SNAPSHOT.220 2015 @@ -38,37 +38,37 @@ all modules and does not describe the project structure per-subproject. io.spine spine-base - 2.0.0-SNAPSHOT.421 + 2.0.0-SNAPSHOT.426 compile io.spine spine-base-types - 2.0.0-SNAPSHOT.223 + 2.0.0-SNAPSHOT.224 compile io.spine spine-logging - 2.0.0-SNAPSHOT.417 + 2.0.0-SNAPSHOT.423 compile io.spine spine-server - 2.0.0-SNAPSHOT.381 + 2.0.0-SNAPSHOT.522 compile io.spine spine-time - 2.0.0-SNAPSHOT.242 + 2.0.0-SNAPSHOT.250 compile io.spine spine-validation-jvm-runtime - 2.0.0-SNAPSHOT.446 + 2.0.0-SNAPSHOT.462 compile @@ -134,7 +134,7 @@ all modules and does not describe the project structure per-subproject. io.spine.tools server-testlib - 2.0.0-SNAPSHOT.381 + 2.0.0-SNAPSHOT.522 test @@ -146,6 +146,7 @@ all modules and does not describe the project structure per-subproject. org.junit.platform junit-platform-launcher + 6.1.0 test @@ -162,7 +163,7 @@ all modules and does not describe the project structure per-subproject. com.google.errorprone error_prone_core - 2.36.0 + 2.42.0 com.google.protobuf @@ -182,17 +183,17 @@ all modules and does not describe the project structure per-subproject. io.spine.tools compiler-cli-all - 2.0.0-SNAPSHOT.054 + 2.0.0-SNAPSHOT.065 io.spine.tools compiler-protoc-plugin - 2.0.0-SNAPSHOT.054 + 2.0.0-SNAPSHOT.065 io.spine.tools core-jvm-plugins - 2.0.0-SNAPSHOT.080 + 2.0.0-SNAPSHOT.081 io.spine.tools @@ -202,12 +203,12 @@ all modules and does not describe the project structure per-subproject. io.spine.tools time-validation - 2.0.0-SNAPSHOT.242 + 2.0.0-SNAPSHOT.250 io.spine.tools validation-java-bundle - 2.0.0-SNAPSHOT.446 + 2.0.0-SNAPSHOT.462 net.sourceforge.pmd diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index df6a6ad76..a9db11550 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.5.1-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-9.6.1-bin.zip networkTimeout=10000 retries=0 retryBackOffMs=500 diff --git a/gradlew b/gradlew index b9bb139f7..249efbb03 100755 --- a/gradlew +++ b/gradlew @@ -20,7 +20,7 @@ ############################################################################## # -# Gradle start up script for POSIX generated by Gradle. +# gradlew start up script for POSIX generated by Gradle. # # Important for running: # @@ -29,7 +29,7 @@ # bash, then to run this script, type that shell name before the whole # command line, like: # -# ksh Gradle +# ksh gradlew # # Busybox and similar reduced shells will NOT work, because this script # requires all of these POSIX shell features: diff --git a/gradlew.bat b/gradlew.bat index 24c62d56f..a51ec4f58 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -19,7 +19,7 @@ @if "%DEBUG%"=="" @echo off @rem ########################################################################## @rem -@rem Gradle startup script for Windows +@rem gradlew startup script for Windows @rem @rem ########################################################################## @@ -72,7 +72,7 @@ echo location of your Java installation. 1>&2 -@rem Execute Gradle +@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 diff --git a/pom.xml b/pom.xml deleted file mode 100644 index e71136cc1..000000000 --- a/pom.xml +++ /dev/null @@ -1,284 +0,0 @@ - - -4.0.0 - -io.spine.gcloud -spine-gcloud-java -2.0.0-SNAPSHOT.174 - -2015 - - - - Apache License, Version 2.0 - https://www.apache.org/licenses/LICENSE-2.0.txt - repo - - - - - - com.google.api.grpc - proto-google-cloud-pubsub-v1 - 1.97.0 - compile - - - com.google.cloud - google-cloud-datastore - 2.2.1 - compile - - - com.google.cloud - google-cloud-trace - 2.1.0 - compile - - - io.spine - spine-base - 2.0.0-SNAPSHOT.192 - compile - - - io.spine - spine-base-types - 2.0.0-SNAPSHOT.125 - compile - - - io.spine - spine-logging - 2.0.0-SNAPSHOT.233 - compile - - - io.spine - spine-server - 2.0.0-SNAPSHOT.174 - compile - - - io.spine.validation - spine-validation-java-runtime - 2.0.0-SNAPSHOT.110 - compile - - - org.apiguardian - apiguardian-api - 1.1.2 - compile - - - org.jetbrains.kotlin - kotlin-stdlib-jdk8 - 1.8.22 - compile - - - org.junit.jupiter - junit-jupiter-api - 5.10.0 - compile - - - org.junit.jupiter - junit-jupiter-params - 5.10.0 - compile - - - org.testcontainers - gcloud - 1.19.0 - compile - - - org.testcontainers - testcontainers - 1.19.0 - compile - - - com.google.auth - google-auth-library-oauth2-http - 1.3.0 - test - - - io.grpc - grpc-auth - 1.59.0 - test - - - io.grpc - grpc-inprocess - 1.59.0 - test - - - io.spine.tools - spine-testlib - 2.0.0-SNAPSHOT.184 - test - - - io.spine.tools - spine-testutil-server - 2.0.0-SNAPSHOT.174 - test - - - org.junit.jupiter - junit-jupiter-engine - 5.10.0 - test - - - com.google.errorprone - error_prone_core - 2.23.0 - - - com.google.errorprone - javac - 9+181-r4173-1 - - - com.google.protobuf - protoc - 3.24.1 - - - com.puppycrawl.tools - checkstyle - 10.12.1 - - - io.grpc - protoc-gen-grpc-java - 1.57.2 - - - io.spine.protodata - protodata-fat-cli - 0.13.1 - - - io.spine.protodata - protodata-protoc - 0.13.1 - - - io.spine.tools - spine-dokka-extensions - 2.0.0-SNAPSHOT.4 - - - io.spine.tools - spine-mc-java-annotation - 2.0.0-SNAPSHOT.172 - - - io.spine.tools - spine-mc-java-base - 2.0.0-SNAPSHOT.172 - - - io.spine.tools - spine-mc-java-checks - 2.0.0-SNAPSHOT.172 - provided - - - io.spine.tools - spine-mc-java-plugins - 2.0.0-SNAPSHOT.172 - - - io.spine.tools - spine-mc-java-rejection - 2.0.0-SNAPSHOT.172 - - - io.spine.tools - spine-tool-base - 2.0.0-SNAPSHOT.186 - - - io.spine.validation - spine-validation-java - 2.0.0-SNAPSHOT.110 - - - io.spine.validation - spine-validation-java-bundle - 2.0.0-SNAPSHOT.110 - - - net.sourceforge.pmd - pmd-java - 6.55.0 - - - org.jacoco - org.jacoco.agent - 0.8.8 - - - org.jacoco - org.jacoco.ant - 0.8.8 - - - org.jetbrains.dokka - analysis-kotlin-descriptors - 1.9.10 - - - org.jetbrains.dokka - dokka-base - 1.9.10 - - - org.jetbrains.dokka - dokka-core - 1.9.10 - - - org.jetbrains.dokka - javadoc-plugin - 1.9.10 - - - org.jetbrains.dokka - kotlin-as-java-plugin - 1.9.10 - - - org.jetbrains.kotlin - kotlin-compiler-embeddable - 1.8.22 - - - org.jetbrains.kotlin - kotlin-klib-commonizer-embeddable - 1.8.22 - - - org.jetbrains.kotlin - kotlin-scripting-compiler-embeddable - 1.8.22 - - - - \ No newline at end of file diff --git a/testlib/src/main/java/io/spine/testing/server/storage/datastore/TestDatastoreStorageFactory.java b/testlib/src/main/java/io/spine/testing/server/storage/datastore/TestDatastoreStorageFactory.java index f2d8838bd..1645a1e44 100644 --- a/testlib/src/main/java/io/spine/testing/server/storage/datastore/TestDatastoreStorageFactory.java +++ b/testlib/src/main/java/io/spine/testing/server/storage/datastore/TestDatastoreStorageFactory.java @@ -1,11 +1,11 @@ /* - * Copyright 2023, TeamDev. All rights reserved. + * Copyright 2026, 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 * - * http://www.apache.org/licenses/LICENSE-2.0 + * 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 @@ -35,7 +35,7 @@ import io.spine.server.storage.datastore.DatastoreWrapper; import java.util.Collection; -import java.util.HashSet; +import java.util.concurrent.ConcurrentHashMap; import static com.google.common.base.Preconditions.checkNotNull; import static java.lang.String.format; @@ -48,7 +48,14 @@ */ public class TestDatastoreStorageFactory extends DatastoreStorageFactory { - private final Collection allCreatedWrappers = new HashSet<>(); + /** + * All the wrappers created by this factory. + * + *

Kept in a concurrent set: a storage — and so its wrapper — may be created + * lazily on a delivery worker thread; + * see {@code StorageFactory.createEntityStateHistoryStorage}. + */ + private final Collection allCreatedWrappers = ConcurrentHashMap.newKeySet(); protected TestDatastoreStorageFactory(Datastore datastore) { super(newBuilderWithDefaults(datastore)); diff --git a/version.gradle.kts b/version.gradle.kts index afe59e037..33accc31a 100644 --- a/version.gradle.kts +++ b/version.gradle.kts @@ -24,4 +24,4 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -val versionToPublish: String by extra("2.0.0-SNAPSHOT.214") +extra.set("versionToPublish", "2.0.0-SNAPSHOT.220")