diff --git a/.agents/memory/MEMORY.md b/.agents/memory/MEMORY.md index 10b91905f..bd335ea36 100644 --- a/.agents/memory/MEMORY.md +++ b/.agents/memory/MEMORY.md @@ -15,6 +15,7 @@ See [README.md](README.md) for the format and routing rules. - [porting-buildsrc-from-consumer-repos](project/porting-buildsrc-from-consumer-repos.md) — To back-port buildSrc improvements from a consumer repo, diff after its last "Update `config`" commit; consumer-owned files never port. - [config-build-verification](project/config-build-verification.md) — config root has no `build` task; verify buildSrc via `./gradlew :buildSrc:test detekt` with JAVA_HOME exported. - [plugin-testkit-assertions-live-in-tool-base](project/plugin-testkit-assertions-live-in-tool-base.md) — Generic Gradle-plugin functional-test assertions (testkit-truth) belong in tool-base/plugin-testlib, not per-plugin `*-testlib` modules. +- [gradle-10-third-party-deprecations](project/gradle-10-third-party-deprecations.md) — Two Gradle 9.6 deprecation nags come from Detekt and Gradle Doctor (not our build logic) — don't chase them in `buildSrc`; Kover's was fixed by bumping to 0.9.9. ## Reference (external systems) diff --git a/.agents/memory/project/gradle-10-third-party-deprecations.md b/.agents/memory/project/gradle-10-third-party-deprecations.md new file mode 100644 index 000000000..e9563eea3 --- /dev/null +++ b/.agents/memory/project/gradle-10-third-party-deprecations.md @@ -0,0 +1,44 @@ +--- +name: gradle-10-third-party-deprecations +description: Two Gradle 9.6 deprecation nags come from Detekt and Gradle Doctor, not our build logic — don't chase them in `buildSrc`. (Kover's was fixed by bumping to 0.9.9.) +metadata: + type: project + since: 2026-07-02 +--- + +Building with `--warning-mode all` on Gradle 9.6.1 still prints two +deprecation warnings that originate in third-party plugins, not in +`buildSrc`. Both become hard errors in Gradle 10: + +- `ReportingExtension.file(String)` — Detekt 1.23.8 + (`DetektPlugin.apply`). Fixed on `main`, but maintainers state no + further 1.23.x releases are planned; the fix ships with Detekt 2.0 + (alpha as of 2026-07, new plugin ID `dev.detekt`). + See [detekt#8452][detekt-8452]. +- `Project.getProperties` — Gradle Doctor 0.12.1 + (`RemoteCacheEstimation`); no newer release available and no upstream + issue filed as of 2026-07. + +A third nag — Kover's "Using a Project object as a dependency notation" +(`PrepareKover.kt`) — is **resolved**: Kover 0.9.9 fixes it +([kotlinx-kover#818][kover-818], released 2026-07-17), and this branch +bumped `Kover.version` 0.9.8 → 0.9.9. Verified by building `buildSrc` +with `--warning-mode all`: the warning is present at 0.9.8 and gone at +0.9.9. + +**Why:** branch `address-gradle-deprecations` removed every deprecated +usage from our own build logic (Kotlin DSL delegated accessors, +`PropertyDelegate`). The residual nags mislead agents into "fixing" our +scripts or bumping plugins to pre-releases. Safety rules forbid +auto-updating dependencies outside a dedicated update task, and the +`dependency-update` skill rejects pre-releases. + +**How to apply:** treat these two warnings as known and out of our hands +at the versions currently pinned; do not chase them in `buildSrc`. +Re-check upstream during each `dependency-update` run: Detekt 2.0 final +(mind the plugin ID change and config migration) and Gradle Doctor +> 0.12.1. Remove this memory once both are resolved. Before Gradle 10, +these must be resolved or the plugins dropped. + +[detekt-8452]: https://github.com/detekt/detekt/issues/8452 +[kover-818]: https://github.com/Kotlin/kotlinx-kover/issues/818 diff --git a/.agents/memory/reference/cache-warm-window.md b/.agents/memory/reference/cache-warm-window.md index 796dd4d30..b57ca218c 100644 --- a/.agents/memory/reference/cache-warm-window.md +++ b/.agents/memory/reference/cache-warm-window.md @@ -18,7 +18,7 @@ same cache slot — provided they fall within the TTL. Developers must have `ENABLE_PROMPT_CACHING_1H=1` set, otherwise the window is too short for cross-session hits to occur reliably. This setting will work ONLY for Claude Code which runs the CLI binary. -It will not work for JetBrains Air or any other IDE plugin which does not +It will not work for JetBrains Air or any other IDE plugin that does not run the Claude Code CLI binary. **Cache is per Anthropic workspace.** All developers authenticated via the diff --git a/.agents/tasks/archive/api-discovery.md b/.agents/tasks/archive/api-discovery.md deleted file mode 100644 index 1671f5eac..000000000 --- a/.agents/tasks/archive/api-discovery.md +++ /dev/null @@ -1,156 +0,0 @@ ---- -slug: api-discovery -branch: improve-api-discovery -owner: claude -status: in-review -started: 2026-05-21 ---- - -## Goal - -Make Spine API discovery fast and token-efficient by directing agents -to read library sources from local sibling clones first, and from a -one-time-extracted sources-JAR cache otherwise — never via repeated -`unzip` against Gradle-cache JARs. - -## Context - -Investigation transcripts (see -`~/Desktop/gradle-caches-scanning-by-claude.png`) show agents running -dozens of `find ~/.gradle/caches` + `unzip -l` + `unzip -p` calls per -query. Each call decompresses the JAR; token usage is dominated by -path noise and JAR listings. The user keeps every Spine repo cloned -as a sibling under `/Users/sanders/Projects/Spine/`, so the raw -sources are already on disk for ~14 of the 16 Spine local deps and -just need to be reached directly. - -Detailed design in `~/.claude/plans/mellow-juggling-yeti.md`. - -## Plan - -- [x] Draft plan + design review (Plan agent) -- [x] Write task file -- [x] Implement `lib/common.sh` (shared bash helpers) -- [x] Implement `discover` (main entry) -- [x] Implement `extract-sources` (one-shot JAR extraction, race-safe) -- [x] Implement `clean-cache` (manual pruning) -- [x] Write `README.md` + `.gitignore` for `.agents/scripts/api-discovery/` -- [x] Write `SKILL.md` for `.agents/skills/api-discovery/` -- [x] Add one bullet to `CLAUDE.md` under Workflow Rules -- [x] Smoke tests (#1–#7 from plan) -- [x] Code-review fixes (six findings, see Log) -- [x] **Follow-up:** `update-sibling` script + skill workflow for STALE -- [ ] Human review / merge; delete file on merge to master - -## Follow-up: sibling auto-update on STALE - -Originally deferred under "Out of scope" in the plan. User asked for -it: when STALE fires, the agent should offer to refresh the sibling -clone so api-discovery returns up-to-date sources. Constraints from -the user's reply: - -- Pull only when the sibling is on its default branch (`master` or - `main`) — they explicitly use checked-out feature branches as a - staging area for "advancing multiple subprojects at the same time", - so a feature branch is *intentional* local state and must be left - alone. -- The action must be confirmed by the user, never autonomous. - -Design: - -- New script `update-sibling`: - - Resolves a sibling by bare name (under ``) or by - absolute path. - - Branch ∈ {`master`,`main`} + clean tree + tracked upstream - → `git pull --ff-only`. - - Any other branch → no-op, exit 0 with "using local code as-is". - - Detached HEAD / dirty tree / no upstream → distinct exit codes - (3 / 4 / 5) with descriptive stderr. - - Pull failure → exit 6. - - Never switches branches, never `--rebase`, never `--force`, never - fetches a branch the user does not track. -- SKILL.md gains a "When STALE fires" section: surface the warning, - ask the user, run `update-sibling` on consent, re-run `discover` - if a pull happened. -- README.md documents the new script + adds it to the Layout table. - -## Log - -- 2026-05-21 — drafted plan; Plan-agent reviewed and pushed back on - over-engineering (manifest, sibling repo, exit codes). Adopted - simplifications. -- 2026-05-21 — cache location: `/.agents/caches/api-discovery/` - with first-use bootstrap prompt (approve / alt root / non-cached). - Scripts and skill live in the consumer repo's `.agents/`. -- 2026-05-21 — implementation begins. -- 2026-05-21 — implementation complete. All 7 smoke tests pass. - Resolved all 24 Spine artifacts end-to-end (Base/Change/Logging KMP/ - multi-module ProtoData/Validation/Tool-base/Mc-java). Extension-cache - path tested with Jackson and Guava — concurrent extractions race - safely on atomic `mv` with no `.tmp.*` leftovers. `STALE` warning - fires for validation-java (declared .433 vs sibling .440). KMP - source sets (`src/commonMain`, `src/jvmMain`, …) recognized in - addition to plain `src/main`. Status flipped to `in-review` for - human merge; task file will be deleted on merge to `master`. -- 2026-05-21 — added `update-sibling` follow-up: a guarded - `git pull --ff-only` for stale Spine siblings. Branch ∈ - {`master`,`main`} + clean tracked tree + tracked upstream → pull; - any other branch → no-op exit 0 ("intentional local state"); - detached / dirty / no-upstream → distinct refusals (exit 3/4/5); - pull failure → exit 6. Uses `--untracked-files=no` so build - artifacts and editor scratch don't block pulls. SKILL.md and - scripts/README.md document the workflow; the agent must ask the - user before invoking. Verified all 8 paths: successful FF on a - synthetic master + upstream, no-op on `validation` (`address-issues` - branch), exit 4 on `base-libraries` (dirty), exit 1 on missing, - exit 2 on non-repo, exit 3 on detached HEAD, exit 5 on no upstream, - exit 1 on missing args. The `main` default branch is also accepted. -- 2026-05-21 — `update-sibling` code-review pass applied five fixes: - (a) README exit-0 row was missing the `already up-to-date` outcome. - (b) `usage()` exited `EX_FAIL` (1), conflating "bad invocation" with - "sibling not on disk". Added `EX_USAGE=64` (BSD `sysexits(3)`) - and routed `usage()` to it; `sibling not on disk` keeps exit 1. - (c) Reworded the dirty-tree guard comment: untracked files don't - block FF on their own, but a genuine overwrite conflict (upstream - adds a path that exists untracked locally) still surfaces via - git's own check as `EX_PULL_FAILED`. Original "no effect on - semantics" wording was misleading. - (d) Exit 0 conflated three outcomes (pulled / up-to-date / - skipped-branch) and the skill had to parse free-form English log - lines to tell them apart. Now each success path emits a single - stable stdout token (`pulled`, `up-to-date`, `skipped-branch`); - failure paths emit empty stdout. Stderr keeps the human text. - (e) `SKILL.md` rewritten around the token contract: the exit-code - table splits exit 0 into three token-keyed sub-rows, procedure - step 4 branches on the token (not stderr), and a new - `up-to-date` example was added. `README.md` exit-code table got - the same split plus an `EX_USAGE=64` row. - Smoke-tested all eight paths end-to-end: synthetic upstream FF emits - `pulled`, re-run on the same clone emits `up-to-date`, `validation` - on `address-issues` emits `skipped-branch`, `base-libraries` (dirty) - exits 4, missing path exits 1, non-repo exits 2, no-args/too-many - exit 64. All failure paths produce empty stdout — agent can never - misread an error message as a result token. -- 2026-05-21 — earlier code-review pass applied six fixes: - (1) `extract-sources`: pre-test `[ -e "$target" ]` plus post-mv - nested-debris cleanup. Previous version was unsafe because - `mv tmp target` into an existing directory silently moves tmp - INSIDE target on macOS/Linux instead of failing. - (2) `discover`: replaced `target=$(...); status=$?` with - `target=$(...) || exit $?` so `set -e` cannot terminate - between assignment and status check. - (3) `clean-cache`: added `prune_empty_parents()` and call it on - both removal and "no entries match" paths (skipped under - `--dry-run`). Empty `//` dirs are now - reclaimed. - (4) `read_declared_version`: anchored regex at line start (with - optional access modifier) to avoid matching `const val version` - strings in KDoc / comments / nested code. - (5) Removed dead `find_dep_file_for_artifact` (callers all use - `find_local_dep_file_for_artifact`). - (6) `find_local_dep_file_for_artifact`: validate artifact name - against `[A-Za-z0-9._-]` and ERE-escape it via new - `escape_ere()` before grep, blocking regex-metachar injection. - All seven smoke tests still pass; race-safety verified by parallel - extractions of `guava-testlib:33.5.0-jre` (both exit 0, no `.tmp.*` - remnants, no nested `target/v.tmp.PID/` debris). diff --git a/.agents/tasks/archive/pom-report-scope-merge.md b/.agents/tasks/archive/pom-report-scope-merge.md deleted file mode 100644 index 81063405e..000000000 --- a/.agents/tasks/archive/pom-report-scope-merge.md +++ /dev/null @@ -1,95 +0,0 @@ ---- -slug: pom-report-scope-merge -branch: group-of-fixes -owner: claude -status: in-review -started: 2026-06-11 ---- - -## Goal - -The aggregated dependency report (`docs/dependencies/pom.xml` in consumer -repos) must never mark a production dependency as `test` -just because a test-only module also uses it. When the retained version of -an artifact comes from several configurations, the higher-ranked Maven scope -wins (`compile` over `provided` over `runtime` over `test`). - -## Context - -Observed in `SpineEventEngine/core-jvm-compiler` PR #94: after adding the -test-only `annotation-tests` module, `io.spine:spine-base` — an `api` -dependency of production modules — flipped to `test` scope in -`docs/dependencies/pom.xml`. Root cause: `deduplicate()` in -`buildSrc/src/main/kotlin/io/spine/gradle/report/pom/DependencyWriter.kt` -collapsed same-GAV entries with `distinctBy { it.gav }`, keeping the -first-encountered occurrence — whose configuration then dictated the scope. - -## Plan - -- [x] Rework `deduplicate()`: group by `group:name`, retain the newest - version, and among the usages of that version pick the occurrence - with the widest scope, ranked by the existing - `ScopedDependency.dependencyPriority()` (compile < runtime < test < - other). No new API surface; the "several versions" log keeps its - old semantics via per-group `distinctBy { it.gav }`. -- [x] Document in `dependencyPriority()` KDoc that the same ordering - drives scope selection for duplicated dependencies. -- [x] Add `DependencyWriterSpec` (JUnit 5 + Kotest, `ProjectBuilder`): - compile-over-test, runtime-over-test, compile-over-runtime, - newest-version-with-widest-scope, scope-taken-from-newest-version- - usages-only, test-only-stays-test, known-scope-over-unknown-config, - undefined-scope-omitted, and the end-to-end `pom.xml` regression. -- [x] Update copyright years; run `:buildSrc:test`; run review agents. -- [x] Replace the lexicographic newest-version pick in `deduplicate()` with - a version-aware comparison: new `internal object VersionComparator` - (numeric segments compared as numbers, release > pre-release, - SemVer-flavored, no new dependency) in the same package, used via - `maxWith(compareBy(VersionComparator) { it.version ?: "" })`. - Scope selection among the newest version's usages stays as is. -- [x] Cover the comparator directly in `VersionComparatorSpec` (7 tests) - and end-to-end in `DependencyWriterSpec` (9.2.0 vs 10.0.0, - SNAPSHOT.99 vs SNAPSHOT.100, release vs snapshot, widest scope - taken from the numerically newest version). -- [x] Follow-up: rank `provided` between `compile` and `runtime` in - `dependencyPriority()` — the conventional Maven scope order - (compile < provided < runtime < test < system < undefined, - as an exhaustive `when` over the scope enum) — so - `compileOnly`/`annotationProcessor` usages are no longer reported - as `test`, and the former `provided`-vs-undefined tie no longer - depends on traversal order. The single ranking is kept for both - scope selection and layout, so `provided` entries move above - `runtime` in the regenerated `docs/dependencies/pom.xml` of - consumer repos (one-time, toward the Maven convention). - -## Log - -- 2026-06-11 — drafted from the user's directive; executing autonomously. -- 2026-06-11 — implemented and verified: full `:buildSrc:test` green, - `DependencyWriterSpec` 9 tests / 0 failures. Stash-check against the - old logic: the order-dependence tests fail as expected, proving the - spec captures the regression. `spine-code-review` and `kotlin-engineer` - reviewers: APPROVE. Known deferred item: version comparison is - lexicographic (pre-existing), e.g. `9.2.0` outranks `10.0.0` — separate - follow-up. -- 2026-06-11 — review-fix pass applied (`review-docs` included): non-null - `maxBy`/`minBy` pipeline, `val` test fixture, spec constants, KDoc - wording aligned with the actual ranking, doc drive-bys. -- 2026-06-11 — `VersionComparator` follow-up completed across the two - parallel sessions: comparator wired into `deduplicate()`, covered by - `VersionComparatorSpec` (7 tests) and end-to-end cases. Final state: - 51 buildSrc tests / 0 failures, `detekt` clean - (`./gradlew :buildSrc:test detekt`). The `provided`-vs-`test` ranking - gap flagged as a follow-up chip; build-verification lesson recorded in - memory `config-build-verification`. Status: in-review; change set - staged for the user to commit. -- 2026-06-11 — `provided` follow-up done: re-ranked into the conventional - Maven order in `dependencyPriority()` (with a `MagicNumber` suppression - per `coding.md`); KDoc aligned in `ScopedDependency.kt` and - `DependencyWriter.kt`; 6 new `DependencyWriterSpec` cases — 57 buildSrc - tests, 0 failures, `detekt` clean. Old-ranking check: the 4 - behavior-pinning tests fail against the previously staged state, as - expected. Layout effect accepted: consumer `pom.xml` reports list - `provided` before `runtime` on next regeneration; pinned end-to-end by - the new layout-order test. `spine-code-review` and `review-docs`: - APPROVE; their non-blocking items applied (exhaustive `when` over the - scope enum, end-to-end layout test, doc wording alignments). diff --git a/.agents/tasks/archive/pom-version-null.md b/.agents/tasks/archive/pom-version-null.md deleted file mode 100644 index 69faae404..000000000 --- a/.agents/tasks/archive/pom-version-null.md +++ /dev/null @@ -1,65 +0,0 @@ ---- -slug: pom-version-null -branch: which-that -owner: claude -status: in-review -started: 2026-06-15 ---- - -## Goal - -The aggregated dependency report (`docs/dependencies/pom.xml` in consumer repos) -must never emit `null`. A BOM-managed coordinate that carries -no explicit version must omit the `` element entirely, producing valid -Maven XML. - -## Context - -Surfaced by a Copilot review on `SpineEventEngine/compiler` PR #69 -(discussion `r3415608846`). Pre-existing on `master`; not introduced by that PR. -Affected artifacts observed in the generated report: `junit-platform-launcher`, -`io.grpc:grpc-protobuf`, `io.grpc:grpc-stub`, `jackson-dataformat-yaml`. - -Root cause: `buildSrc/src/main/kotlin/io/spine/gradle/report/pom/DependencyWriter.kt` -wrote `"version" { xml.text(dependency.version) }` unconditionally. For a -version-less dependency `dependency.version` is `null`, and the -`MarkupBuilder.text` helper (`MarkupExtensions.kt`) does `value.toString()`, -turning `null` into the literal string `"null"`. The data layer already knew a -null version was possible — `deduplicate()` guards it with `it.version ?: ""` — -only the emission site did not. - -Config-owned: the `report/pom/*.kt` files are byte-identical across all consumer -repos and cannot be durably fixed there. Fixed here; floats via the `config` -submodule + `pull`. Relates to the vendored-`buildSrc` audit follow-ups tracked -in config#691 (a 6th, self-contained item — fixed directly rather than deferred). - -## Plan - -- [x] Guard the version element in `DependencyWriter.writeXmlTo`: emit - `` only when `dependency.version != null` - (`dependency.version?.let { … }`), mirroring the existing conditional for - the optional `` element. Chose "omit the element" (option a) over - "resolve the effective BOM-managed version" (option b): the generator - walks declared deps across all configurations, including non-resolvable - ones, so the resolved version is not readily available; an omitted - `` is also the correct Maven representation for a managed version. -- [x] Add `DependencyWriterSpec` regression test - `omit the version of a dependency that declares none`: a version-less - `io.grpc:grpc-stub` (BOM-managed) plus a versioned `spine-base` prove the - literal `null` is gone while versioned entries still emit ``. -- [x] Verify: `./gradlew :buildSrc:test detekt` green; regression proof - (test fails without the fix); detekt clean. - -## Log - -- 2026-06-15 — drafted from the user's directive; plan approved. -- 2026-06-15 — implemented Changes 1–2. No version bump or `docs/dependencies` - regeneration: `config` has no root `version.gradle.kts` and no such - directory; both happen consumer-side on the next `pull` + build. Both - source files already carry the 2026 copyright year. -- 2026-06-15 — verified: `./gradlew :buildSrc:test detekt` BUILD SUCCESSFUL - (JDK 17). New `DependencyWriterSpec` test green (top-level suite 3 → 4 - tests, 0 failures); detekt clean. Regression proof: reverting the guard - makes the new test fail at the `null` assertion - (`DependencyWriterSpec.kt:268`); fix restored. Change set staged for the - user to review and commit. diff --git a/.agents/tasks/archive/prohibit-automatic-commits.md b/.agents/tasks/archive/prohibit-automatic-commits.md deleted file mode 100644 index ff067c505..000000000 --- a/.agents/tasks/archive/prohibit-automatic-commits.md +++ /dev/null @@ -1,92 +0,0 @@ ---- -slug: prohibit-automatic-commits -branch: prohibit-automatic-commits -owner: claude -status: in-review -started: 2026-05-20 ---- - -## Goal - -Make it a durable, team-wide rule that AI agents (Claude Code main thread, -every subagent, every skill) MUST NOT run `git commit` (or other -history-writing git/gh operations) unless authorization is *explicit and -current*. Authorization comes from one of two sources only: - -1. The currently active skill's `SKILL.md` contains an explicit - `## Commit authorization` section. -2. The user's current prompt explicitly instructs the operation - (e.g. "commit this", "push the branch"). - -Agents must otherwise stage changes and stop, letting the user review and -decide. This preserves today's auto-commit behavior for `bump-version` -and `bump-gradle`, which will declare authorization in their SKILL.md. - -## Context - -- Today's pain: Claude Code commits routinely, even when the user wants - to review diffs locally first. -- The project's `.claude/settings.json` already has `Bash(git commit:*)` - in `permissions.ask`. That asks the user per-commit but does not - redirect agent behavior — the agent still proposes commits constantly. - The fix is at the *instruction* layer, not the permission layer. -- Skills that legitimately commit today: `bump-version`, `bump-gradle`. -- Skills that do not commit but prescribe commit messages for the human: - `dependency-update` (already says "Do not commit. Do not push."). -- The user accepted removal of the global `~/.claude/settings.json` hook - added earlier this session. Enforcement lives in `.agents/` instructions - only. - -## Plan - -- [x] **1. Add the canonical rule to `.agents/safety-rules.md`.** - Added section *Commits and history-writing*. Lists default (no - history writes), two authorization sources, the fallback behavior - (stage + show diff + stop), and the operations covered. Names the - `## Commit authorization` marker. - -- [x] **2. Surface the rule in `.agents/quick-reference-card.md`.** - Added one-line pointer to `safety-rules.md` → *Commits and - history-writing*. - -- [x] **3. Add a workflow rule to `CLAUDE.md`.** - Added bullet under *Workflow Rules* referencing - `.agents/safety-rules.md`. - -- [x] **4. Declare authorization in `bump-version/SKILL.md`.** - Added a top-level `## Commit authorization` section above the - Checklist: exactly one commit, stage only `version.gradle.kts`, - subject `` Bump version -> `` ``, no push/tag/amend. - -- [x] **5. Declare authorization in `bump-gradle/SKILL.md`.** - Added a top-level `## Commit authorization` section above the - Checklist: up to two commits (wrapper + dependency reports), exact - subjects, no push/tag/amend. - -- [x] **6. Cross-check the non-authorizing skills.** - `dependency-update/SKILL.md` already explicit ("Do not commit. Do - not push.") — left as is. `pre-pr/SKILL.md` does not commit — left - as is. Other skills scanned (see Log). - -- [x] **7. Verification.** See Log entry — all three grep checks pass. - -## Out of scope - -- Project `.claude/settings.json` `ask` rule for `Bash(git commit:*)`: - leave as defense-in-depth (zero cost when the agent obeys the rule). -- `~/.claude/settings.json` global hook: already reverted earlier this - session per user direction. - -## Log - -- 2026-05-20 — drafted, awaiting plan approval. -- 2026-05-20 — approved by user. Executed steps 1–6. -- 2026-05-20 — verification: - - `grep -RIn '^## Commit authorization' .agents/skills/` returns exactly - `bump-gradle/SKILL.md` and `bump-version/SKILL.md` ✓ - - `safety-rules.md` referenced from `CLAUDE.md`, `quick-reference-card.md`, - `bump-version/SKILL.md`, `bump-gradle/SKILL.md` ✓ - - Literal `git commit` strings live only in the two authorizing skills ✓ - - `dependency-update/SKILL.md` still says "Do not commit. Do not push."; - `pre-pr/SKILL.md` still writes a sentinel and does not commit ✓ -- Status: `in-review` — awaiting user sign-off, then delete on merge to master. diff --git a/.agents/tasks/archive/prompt-caching-org.md b/.agents/tasks/archive/prompt-caching-org.md deleted file mode 100644 index 71f0c4fb9..000000000 --- a/.agents/tasks/archive/prompt-caching-org.md +++ /dev/null @@ -1,165 +0,0 @@ ---- -slug: prompt-caching-org -branch: improve-caching -owner: claude -status: in-review -started: 2026-05-24 -related-memories: [cache-warm-window, anthropic-api-caching] ---- - -## Goal - -Maximise Claude API prompt cache hit rates across the Spine GitHub organisation -(~40 sibling repos) so that repeated session starts and agent invocations read -from cache at 0.1× token cost rather than processing the full prompt fresh. - -## Context - -- Claude Code already applies automatic prompt caching to every API call it - makes. There is no single "enable" switch; the work is about raising the - cache hit rate and keeping it high. -- The `migrate` script overwrites `CLAUDE.md`, `.agents/`, `.claude/`, and - `buildSrc/` in each sibling repo with an exact copy from this repo. This - means all 40 repos hold byte-identical content after a `./config/pull` and - therefore share the same cache entry at any given config version. -- The `openai.yaml` files under each skill are FleetView UI interface metadata - only — they define display name and default prompt, not API call parameters. - `cache_control` cannot go there. -- No GitHub Actions workflow currently calls the Anthropic API directly. -- Current stable prefix: CLAUDE.md (≈ 900 tokens) + quick-reference card - (≈ 200 tokens) ≈ 1,100 tokens. - - This **clears** the 1,024-token minimum for Sonnet 4.6 / Opus. - - This **does not meet** the 4,096-token minimum for Haiku 4.5. -- The team memory system is empty; populating it will grow the stable prefix. -- Cache TTL defaults to 5 minutes. Sessions more than 5 minutes apart miss - the cross-session cache unless the extended 1-hour TTL is used. - -## Plan - -- [ ] **Step 0 — Diagnose why zero caching is happening and enable it** - - The Console Caching dashboard ("TeamDev Management OÜ", All workspaces) shows - no prompt caching in use — no `cache_control` blocks are being sent by any - caller. This is the highest-priority item; the remaining steps only add value - once caching is active. - - Sub-tasks: - - - **0a. Switch to Console OAuth on every developer machine** - - Raw API key auth loses per-developer identity (`email`, `orgId`, `orgName` - all null in `claude auth status`). Console OAuth preserves identity while - still billing to "TeamDev Management OÜ". - - **For each developer:** - 1. Remove `ANTHROPIC_API_KEY` from `~/.claude/settings.json` — it takes - precedence over OAuth in the auth stack and must be absent. - 2. Run `claude` → a browser window opens → log in with Console credentials - (the same account used at console.anthropic.com). - 3. Run `claude auth status` and confirm `email`, `orgId`, `orgName` are - populated. - - **For the org admin (Alexander):** - - Invite the second developer via Console → Settings → Members → Invite. - - Assign the "Developer" or "Claude Code" role. - - They accept the email invite, then follow the three steps above. - - - **0b. Enable 1-hour cache TTL on every developer machine** - - Console OAuth users get the **5-minute** default cache TTL — the 1-hour - TTL is only automatic for claude.ai subscription users. Add the opt-in - to `~/.claude/settings.json` on every developer machine: - - ```json - { - "env": { - "ENABLE_PROMPT_CACHING_1H": "1" - } - } - ``` - - Restart Claude Code after saving. This is the highest-impact change in - the entire plan — without it, cache entries expire every 5 minutes and - cross-session hits are rare. - - - **0c. Verify caching is active** — start a Claude Code session, make a - few turns, wait 2–3 minutes, then check Analytics → Usage in the Console - under "TeamDev Management OÜ". Non-zero `cache_creation_input_tokens` - confirms caching is active. Non-zero `cache_read_input_tokens` on a - subsequent session in the same hour confirms hits are occurring. - - - **0d. Investigate remote skill calls** — FleetView-managed remote skills - (the 7 skills with `openai.yaml`) make their own API calls through the - agent platform. Confirm whether those calls include `cache_control`; if - not, this may require configuration in the FleetView platform outside - this repo. - - Until steps 0a–0b are done on both developer machines, Steps 1–3 improve - future cache hygiene but produce limited cost savings. - -- ~~**Step 1 — Cache-hygiene team memory**~~ — *reverted 2026-05-25: the - batching guidance was too restrictive on `config` changes; removed - `.agents/memory/feedback/cache-hygiene.md` and its references.* - -- [x] **Step 2 — Post-migration cache-warm window (reference memory)** - - Create `.agents/memory/reference/cache-warm-window.md` documenting: - - Realistic concurrency is 1–2 developers working on different repos at the - same time, not the full fleet of 40. - - Default TTL is 5 minutes. If a second session starts within 5 minutes of - the first (on the same config version), it hits the warm entry rather than - writing a new one. - - Extended 1-hour TTL (available in direct API calls via - `cache_control: {ttl: "1h"}`) gives a wider window, at 2× write cost per - token — still profitable after even one hit within the hour. - - Update `.agents/memory/MEMORY.md` index. - -- [x] **Step 3 — API caching pattern reference memory (for future direct calls)** - - No workflow currently calls the Anthropic API directly, but when one is - added, developers need the pattern immediately. - - Create `.agents/memory/reference/anthropic-api-caching.md` documenting: - - Use `cache_control: {type: ephemeral}` on the system message block for - 5-minute TTL (1.25× write / 0.1× read). - - Use `cache_control: {type: ephemeral, ttl: "1h"}` for 1-hour TTL - (2× write / 0.1× read) — right for any workflow job spaced > 5 min apart. - - Place stable content (system instructions, skill definitions, shared - context) **before** any dynamic per-request content so the breakpoint - sits at the end of the stable prefix. - - Monitor: `usage.cache_read_input_tokens` should grow relative to - `usage.cache_creation_input_tokens` as the cache warms. - - Future: once direct API calls exist, consider a cache pre-warm job - triggered on push to `master` — calls the API with `max_tokens: 0` and - `cache_control: {ttl: "1h"}` so the first session after a config change - hits rather than writes. - - Update `.agents/memory/MEMORY.md` index. - -- [x] **Step 4 — API workspace consolidation (already confirmed — verify stays true)** - - A cache entry is visible only to API calls made with a key from the **same - Anthropic workspace** (a named sub-group within your Anthropic Console - organisation). Two requests using keys from different workspaces never share - cache, even if they send identical prompts. - - **Current state (confirmed):** "TeamDev Management OÜ" has a single default - workspace (Environments list is empty). Both developers use Console API keys - from this organisation. Both developers share the same cache pool — no action - needed today. - - **Keep true as the team grows:** do not create separate Environments per - developer or per project unless cache isolation is intentional. Any new API - key issued for a new caller (GitHub Actions, scripts, new developer) should - be issued from the same workspace. - -## Log - -- 2026-05-24 — drafted from codebase audit; awaiting review and approval -- 2026-05-24 — revised per review: added buildSrc to migrate list, removed dependency-audit caching step, corrected concurrency description to 1–2 repos, dropped pre-warm workflow step (pattern preserved in Step 3 memory), clarified per-workspace semantics in Step 4 -- 2026-05-24 — added Step 0 after Console Caching dashboard confirmed zero prompt caching in use; workspace confirmed as single default (no Environments), both devs on same org — Step 4 updated to reflect confirmed state -- 2026-05-24 — Step 0 revised: root cause identified — Console API key users get 5-min TTL by default vs 1-hour for subscription users; ENABLE_PROMPT_CACHING_1H=1 is the fix; warning on first launch is one-time approval only -- 2026-05-24 — Step 0 revised again: switched to Console OAuth (not raw API key) to preserve per-developer identity; ENABLE_PROMPT_CACHING_1H=1 still required for Console OAuth users (5-min TTL default applies to all non-subscription auth) -- 2026-05-24 — Steps 1–4 complete: three memory files created, MEMORY.md index updated, workspace consolidation confirmed; Step 0 remains in progress (Console OAuth setup and verification) -- 2026-05-25 — reverted Step 1: removed `cache-hygiene.md` and references — batching guidance was too restrictive for `config` development cadence diff --git a/.agents/tasks/archive/raise-coverage-kover-migration.md b/.agents/tasks/archive/raise-coverage-kover-migration.md deleted file mode 100644 index 268ba0780..000000000 --- a/.agents/tasks/archive/raise-coverage-kover-migration.md +++ /dev/null @@ -1,449 +0,0 @@ ---- -slug: raise-coverage-kover-migration -branch: coverage-tests-skill -owner: claude -status: in-review -started: 2026-05-30 ---- - -## Goal - -Extend the `raise-coverage` skill with a precondition step that migrates a -consumer repo from the vanilla JaCoCo Gradle plugin to JetBrains Kover (with -`useJacoco(version = Jacoco.version)` so the engine and the JaCoCo-format XML -remain unchanged). The skill becomes **Kover-only** post-migration. Adjacent -JaCoCo-distribution code in `config`'s `buildSrc` is marked deprecated with a -pointer to the Kover path; no behaviour change for repos that still consume -the deprecated script plugins. - -## Context - -The skill in `.agents/skills/raise-coverage/` currently supports two coverage -frontends: Kover (consumer repos) and raw JaCoCo (the `config` repo itself). -Per user decision, the skill collapses to Kover-only and gains a Step 0 that -detects vanilla JaCoCo, proposes a one-shot repo-wide migration, waits for -approval, applies it, smoke-checks, and only then resumes the normal flow. - -`config` itself has no production Kotlin/Java code, so the skill never runs -*on* `config`. However, `config` distributes vanilla-JaCoCo infrastructure -(`buildSrc/src/main/kotlin/jacoco-kotlin-jvm.gradle.kts`, `jacoco-kmm-jvm.gradle.kts`, -and the `JacocoConfig` helper) that consumer repos may still apply — these -get deprecation annotations + a runtime `logger.warn` (script plugins only) -but stay on disk so existing consumers keep building. `Jacoco.kt` (engine -version) and `Kover.kt` (plugin version) are unchanged because Kover uses -`useJacoco(version = Jacoco.version)`. - -### Decisions (locked — do not re-litigate) - -| # | Decision | -|---|----------| -| 1 | Invocation: implicit precondition (Step 0 of the skill) | -| 2 | Scope: repo-wide, proposed once | -| 3 | Trigger: always, unless Kover is already applied everywhere | -| 4 | Both plugins applied: always remove `jacoco`, keep Kover | -| 5 | KMP: JVM-target-only migration via Spine's `kmp-module` script plugin — uses the same `::koverXmlReport` task and `build/reports/kover/report.xml` path as Kotlin-JVM, because `kmp-module` configures only Kover's `total` report (no named variants, so no `koverXmlReport` task is generated) | -| 6 | CI / `.codecov.yml` / scripts: all updated to Kover paths and tasks | -| 7 | Plugin/engine version: reference `io.spine.dependency.test.Kover` / `Jacoco`; do not hardcode | -| 8 | Translation fidelity: best-effort full; flag unmappable constructs | -| 9 | Post-migration: skill flow is Kover-only | -| 10 | No-coverage case: silent install, no approval gate | -| 11 | Verification: smoke check only (`koverXmlReport` exists + parses) | -| 12 | `JacocoConfig` and `jacoco-*.gradle.kts`: mark deprecated, do not delete | - -### Verified facts (from Phase 1 exploration) - -- `buildSrc/src/main/kotlin/jvm-module.gradle.kts:54` applies Kover; `:99` - configures it with `useJacoco(version = Jacoco.version)` and XML-on-check. -- `buildSrc/src/main/kotlin/kmp-module.gradle.kts:74` and `:181` mirror the - above for KMP modules. -- `buildSrc/src/main/kotlin/io/spine/gradle/report/coverage/` contains the - JaCoCo-pipeline classes to be deprecated: `JacocoConfig`, `TaskName`, - `CodebaseFilter`, `FileFilter`, `FileExtensions`, `FileExtension`, - `PathMarker`. -- `scripts/upload-artifacts.sh:38` references `build/jacoco*` directories. -- `.github/workflows/*.yml` in `config` contain no JaCoCo references. - -## Implementation - -Paths are relative to the `config` repo root. - -### Area A — Skill files - -#### A1. `.agents/skills/raise-coverage/SKILL.md` - -- Frontmatter `description: >`: drop "Kover or JaCoCo frontend"; phrase the - report as "Kover's JaCoCo-format XML report"; add: "Before anything else, - ensures the repo is on Kover — if vanilla JaCoCo is detected, proposes a - one-shot repo-wide migration and waits for approval." -- Body "with JaCoCo" → "with **Kover**'s JaCoCo-format XML report". -- **Scope** bullet rewritten Kover-only. Per-module task - `::koverXmlReport`; XML at - `/build/reports/kover/report.xml`. Same task and path on KMP - modules configured by Spine's `kmp-module` script plugin — it sets up only - Kover's `total` report (no named variants, so no - `koverXmlReport` task is generated). Strip every "raw JaCoCo" / - `jacocoTestReport` / `jacocoRootReport` reference as a normal mode. -- **Insert new `## Step 0 — Ensure Kover`** between `## Inputs` and - `## Workflow`. Three branches: - 1. Kover applied everywhere → silently proceed. - 2. Nothing applied anywhere → silently install Kover; record - "Migration: installed Kover" in the final Report; no approval gate. - 3. Vanilla JaCoCo in ≥1 module → emit a proposal and **wait for approval**. -- **Proposal output structure** (Markdown, in this order): - 1. **Detected** — every module applying `jacoco` / `JacocoPlugin` / - `JacocoConfig.applyTo` / a `jacoco-*.gradle.kts`; annotate "vanilla - only" vs. "JaCoCo+Kover both"; note any root `jacocoRootReport`. - 2. **Plan** — file edits with paths (per-module `build.gradle.kts`, root - `build.gradle.kts`, `.codecov.yml`, `.github/workflows/*.yml`, - `scripts/*.sh`). - 3. **Translation notes** — applicable rows from the migrate-to-kover table. - 4. **Manual-review surfaces** — items the user must decide on. - 5. **Smoke check that will follow** — the E1 commands. - 6. Close with: "Confirm to apply, or call out anything to change first." -- **Wait for approval.** No writes until explicit "go" / "yes" / "apply". - On adjustment requests, regenerate the proposal and wait again. -- **Apply** per `references/migrate-to-kover.md`; log `edited ` per - file. Any unresolved manual-review surface → stop ("needs your call on - ``"). -- **Smoke check** per E1. Failure → stop; do not fall through. -- **Resume** at Workflow step 1. -- **Workflow step 1** (`--triage`): "per-module `koverXmlReport`, or the - aggregate `jacocoRootReport` in `config`" → "per-module `koverXmlReport`, - or the root-level Kover aggregation task `koverXmlReport` if the repo - wires one". -- **Workflow step 2**: "Detect the coverage frontend and run …" → "Run - `::koverXmlReport`" — same task on JVM and KMP modules configured - by Spine's `kmp-module` script plugin (no named variants → no - `koverXmlReport` task). Drop "either way" from the XML-parsing - sentence. -- **Workflow step 6**: "(`koverXmlReport` or `jacocoTestReport`)" → - `::koverXmlReport`. -- **Report**: add a **Migration** section (emitted only when Step 0 did work). -- **Safety**: add a bullet — "No migration without explicit approval when - vanilla JaCoCo is detected. Silent install only when *no* frontend is in - place." - -#### A2. `.agents/skills/raise-coverage/references/coverage-signals.md` - -- Top blurb: drop the "two frontends" paragraph; replace with a single - paragraph stating that the engine is JaCoCo and the Spine convention is - Kover with `useJacoco(version = Jacoco.version)`; the XML is - JaCoCo-format either way. -- Delete the entire **"Two coverage frontends"** section (current lines - 11–57). Replace with **"Where the report lives"** — per-module task / XML - path, root-level aggregation paths, `find` recipe if unknown. -- **"Generating a report"**: drop the two JaCoCo `./gradlew` lines; keep - Kover. Same task on KMP modules configured by Spine's `kmp-module` script - plugin — no `koverXmlReport` task is generated unless a named - `variant("…") { … }` block is declared. -- **"Extracting gaps for a class"**: drop "or the jacoco path". -- **"KMP / Kotlin-JVM modules"**: keep first sentence; delete the second - sentence about `jacoco-*-jvm` exec data paths. -- **Verification**: "the **same** report task" → `::koverXmlReport`. -- **Codecov triage tier appendix**: keep verbatim. - -#### A3. `.agents/skills/raise-coverage/references/migrate-to-kover.md` (new) - -Eight sections: - -1. **Purpose** — one paragraph; link to - and the - `migrations/migration-to-0.7.0.html` migration guide. -2. **Detection signals** — grep patterns per module's `build.gradle.kts`: - - Plugin block: `^\s*jacoco\b` inside `plugins {`, `id\("jacoco"\)`, - `apply\(\)`, `apply\(plugin = "jacoco"\)`. - - Script plugin: `apply\(plugin = "jacoco-`. Covers `jacoco-kotlin-jvm`, - `jacoco-kmm-jvm`. - - `JacocoConfig`: `JacocoConfig\.applyTo` or imports of - `io.spine.gradle.report.coverage.JacocoConfig`. - - DSL: `jacoco\s*\{`, `jacocoTestReport\s*\{`, - `jacocoTestCoverageVerification\s*\{`, `tasks\.named\("jacoco`. - - Kover applied: `org.jetbrains.kotlinx.kover`, or `id("jvm-module")` / - `id("kmp-module")` (both auto-apply Kover). - - Root aggregation: `jacocoRootReport`. - - Multi-module walk: parse `settings.gradle.kts` for `include(...)`; - honor `project(":x").projectDir = file(...)` overrides. -3. **Per-module migration**: - - Add Kover via `id(Kover.id)` if `buildSrc` is on the classpath; - otherwise `id("org.jetbrains.kotlinx.kover") version ""`. - If `jvm-module` / `kmp-module` is applied, skip the add (log "already - via jvm-module"). - - Strip `jacoco` from `plugins { }`. - - **Translation table**: - | JaCoCo construct | Kover / action | - |---|---| - | `jacoco { toolVersion = Jacoco.version }` | drop (engine version → root `useJacoco(...)`) | - | `jacoco { toolVersion = }` | **flag** | - | `reports { xml=true; html=true; csv=false }` | `kover { reports { total { xml { onCheck.set(true) }; html { } } } }` | - | `executionData.setFrom(...)` | **flag** (Kover-managed) | - | `sourceDirectories.setFrom(...)` | **flag** (Kover-inferred) | - | `classDirectories.setFrom(...)` (Kotlin-JVM/KMP `walkBottomUp`) | drop; **flag** if non-Kotlin | - | `reports.xml.outputLocation.set(...)` | **flag** (fixed path) | - | `tasks.named("jacocoTestReport") { dependsOn(...) }` | rewrite to `tasks.named("koverXmlReport")` | - | `violationRules { rule { limit { counter; value; minimum } } }` | `kover { reports { verify { rule { … } } } }`; counter map: INSTRUCTION/BRANCH/LINE = same; METHOD → INSTRUCTION + flag; CLASS → flag | - - `jvm-module` / `kmp-module` simplification: Kover already there; - migration becomes "remove JaCoCo bits only". -4. **Root-level aggregation**. Trigger: source had `jacocoRootReport` **or** - >1 module to aggregate. - - Apply Kover at root (skip if root applies `jvm-module`). - - `dependencies { kover(project(":foo")); … }` per consuming module. - - `kover { useJacoco(version = Jacoco.version); reports { total { xml { onCheck.set(true) }; html { } } } }`. - - Mirror per-module `violationRules` to root `verify { rule { … } }` - only if the source repo had a root-level rollup. -5. **CI / `.codecov.yml` / scripts** — substitutions: - - Workflows: `jacocoTestReport` → `koverXmlReport`; `jacocoRootReport` → - root `koverXmlReport`; - `build/reports/jacoco/test/jacocoTestReport.xml` and - `build/reports/jacoco/jacocoRootReport/jacocoRootReport.xml` → - `build/reports/kover/report.xml`. - - `.codecov.yml`: same path tokens; preserve `ignore` and - `coverage.status` verbatim. - - `scripts/*.sh`: `build/jacoco*` glob → `build/reports/kover`; **flag** - scripts reading raw `.exec` paths (e.g., - `scripts/upload-artifacts.sh:38` in `config`). -6. **KMP recipe**. JVM-only target. Same task and XML path as Kotlin-JVM: - `::koverXmlReport` and `/build/reports/kover/report.xml`. - Spine's `kmp-module` script plugin configures only Kover's `total` report, - so no `koverXmlReport` task is generated — CI / `.codecov.yml` - must reference the unsuffixed path. A `koverXmlReportJvm` task would only - appear if a named `variant("jvm") { … }` block were declared, which - `kmp-module` does not do. -7. **Manual-review surfaces** (flag and ask): - - Custom `sourceDirectories` / `classDirectories` on `jacocoTestReport` - (the `jacoco-*-jvm.gradle.kts` pattern). - - Custom `reports.xml.destination` / `outputLocation`. - - Custom `executionData` paths. - - Indirect `jacoco.toolVersion` (property files, `gradle.properties`). - - Multi-pipeline setups where both reports are intentional. - - `JacocoConfig.applyTo(rootProject)` outside `config`. - - Custom convention plugins applying JaCoCo under a non-`jacoco-…` name. - - Non-JVM KMP targets — out of scope (decision 5). -8. **References** — links to the Kover migration guide and DSL docs. - -#### A4. `.agents/skills/raise-coverage/agents/openai.yaml` - -- `short_description`: "Migrate to Kover if needed, then generate unit tests - to close coverage gaps." -- `default_prompt`: rewrite to name Step 0 — detect setup; if vanilla - JaCoCo found, propose a one-shot repo-wide migration and wait for - approval; if nothing applied, install Kover silently. After smoke check, - run the existing flow (localize from Kover XML; propose; approve; - generate Kotest / Truth stubs; re-verify). End with: "Tests-only changes - do not require a version bump." - -### Area B — BuildSrc deprecations in `config` - -#### B1. `buildSrc/src/main/kotlin/jacoco-kotlin-jvm.gradle.kts` and `jacoco-kmm-jvm.gradle.kts` - -Runtime behaviour unchanged. Two edits per file: - -1. Below the copyright header, insert a `// DEPRECATED:` block: "This - script plugin distributes vanilla JaCoCo. New code should apply - `jvm-module` (or `kmp-module`), which configures Kover via - `useJacoco(version = Jacoco.version)`. The `raise-coverage` skill - migrates existing consumers. Kept so older consumer repos continue to - build; will be removed in a future release." -2. Immediately before `plugins { jacoco }`, add - `logger.warn("'jacoco-kotlin-jvm' is deprecated; use 'jvm-module' which applies Kover. See .agents/skills/raise-coverage/references/migrate-to-kover.md.")` - (use `jacoco-kmm-jvm` and `kmp-module` in the KMM file). - -#### B2. `@Deprecated` on JaCoCo-pipeline classes under `buildSrc/src/main/kotlin/io/spine/gradle/report/coverage/` - -All `DeprecationLevel.WARNING`, no `ReplaceWith` (the replacement is a -multi-block DSL). - -- `JacocoConfig.kt` — class `JacocoConfig`: "Use Kover's root-level - aggregation (`dependencies { kover(project(...)) }` plus - `kover { useJacoco(version = Jacoco.version); reports { total { xml { onCheck = true } } } }`) - instead of `JacocoConfig.applyTo(...)`. The `raise-coverage` skill - performs this migration automatically." -- `TaskName.kt` — enum: "Internal task-name catalog for the deprecated - `JacocoConfig` pipeline; Kover uses its built-in task names - (`koverXmlReport`, etc.). Removed when `JacocoConfig` is." -- `CodebaseFilter.kt` — class: "Used only by the deprecated `JacocoConfig`. - Kover infers source sets and respects `kover { filters { excludes { … } } }`." -- `FileFilter.kt` — object: same wording as `CodebaseFilter`. -- `FileExtensions.kt` — `@file:Deprecated("Path/extension helpers used only by the deprecated `JacocoConfig` pipeline. Removed when `JacocoConfig` is.")`. -- `PathMarker.kt` enum and `FileExtension.kt` enum — same wording as - `FileExtensions`. - -For in-package self-references, accept the warnings or apply -`@Suppress("DEPRECATION")` on the call sites. - -#### B3. Untouched - -`buildSrc/src/main/kotlin/io/spine/dependency/test/Jacoco.kt` and `Kover.kt` -remain unchanged. `Jacoco.kt` is the engine-version source used by -`kover { useJacoco(version = Jacoco.version) }`. - -### Area C — Adjacent docs in `config` - -#### C1. `.agents/tasks/raise-coverage.md` - -- Decisions table "Coverage engine" row: "exposed via Kover - (`koverXmlReport`); when a consumer repo still has vanilla JaCoCo, the - skill migrates it first; Codecov deferred." -- "Verified facts": replace the **JaCoCo paths** bullet with a Kover-paths - bullet (`/build/reports/kover/report.xml` — same on KMP via - `kmp-module`, which configures only the `total` report; root aggregation - `build/reports/kover/report.xml`; Kover manages exec data internally). -- Plan: append `- [ ]` "Kover-only pivot: implement - `.agents/tasks/raise-coverage-kover-migration.md`". -- Log: append a 2026-05-30 entry summarising the pivot. -- Keep `status: draft`. - -#### C2. `.claude/commands/raise-coverage.md` - -- Description: "Ensure the repo is on Kover (migrate from JaCoCo if - needed), then localize coverage gaps and generate missing unit tests for - a module or path." -- Order bullet: `::jacocoTestReport` → `::koverXmlReport`. - `--triage` line: "ranked JaCoCo gap report" → "ranked Kover gap report". -- After the Skill bullet, add: "First-time setup: the skill enforces - Kover. If vanilla JaCoCo is found anywhere, the skill proposes a - repo-wide migration and **waits for your approval**. See - `references/migrate-to-kover.md`." -- `allowed-tools`: unchanged. - -#### C3. Other docs - -- `.agents/_TOC.md` — no edit. -- `.agents/tasks/buildsrc-gradle-review-findings.md` — above each item - referencing `jacoco-kmm-jvm.gradle.kts` or `JacocoConfig.kt` (lines - 77–78, 101–103, 121–122, 169–172, 201–203), insert one line: - "**Superseded by Kover-only migration**: these files are deprecated; do - not invest in micro-rewrites. See - `.agents/skills/raise-coverage/references/migrate-to-kover.md`." -- `scripts/upload-artifacts.sh` — add `# DEPRECATED:` comment line above - line 38 (`JACOCO_REPORTS=…`) pointing at the migration reference. No - behaviour change. -- `scripts/buildSrc-migration.kts`, `migrate`, `lychee.toml` — no edits. - -### Area E — Verification - -#### E1. Step 0 smoke check (post-migration) - -1. Run `./gradlew ::koverXmlReport --quiet` on the smallest leaf - JVM migrated module; if the root was touched, also `./gradlew - koverXmlReport --quiet`. -2. Assert `/build/reports/kover/report.xml` exists, is non-empty, - and the first non-XML-declaration line contains `Kt` synthetic) and emits both `FQN` and - `FQN$*` exclusion patterns to cover nested classes. The skill's - migration step now rewrites `JacocoConfig.applyTo` → `KoverConfig.applyTo` - instead of deleting the call. `./gradlew -p buildSrc compileKotlin` - green. diff --git a/.agents/tasks/archive/raise-coverage.md b/.agents/tasks/archive/raise-coverage.md deleted file mode 100644 index b0fc517ef..000000000 --- a/.agents/tasks/archive/raise-coverage.md +++ /dev/null @@ -1,283 +0,0 @@ ---- -slug: raise-coverage -branch: coverage-tests-skill -owner: claude -status: draft -started: 2026-05-29 -updated: 2026-05-30 ---- - -## Goal - -Stand up a reusable, Spine-native agent skill — **`raise-coverage`** — that raises -JVM test coverage by localizing uncovered lines/branches with JaCoCo and -generating policy-compliant unit tests. The skill lives in `config` and -propagates to all ~50 repos via `./config/pull`. Success = the skill and its -wrappers are authored, distribution is wired, and the full loop has been -dry-run on one `base-libraries` module locally (nothing committed). - -## Context - -Scoped in Claude Chat; the produced `SKILL.md` was lost and the two surviving -files (`coverage-signals.md`, `coverage-tests.md`) are **drafts** to be -rewritten, not shipped. Clarification produced eight decisions that narrow and -simplify the original draft. - -### Decisions (locked — do not re-litigate) - -| Decision | Choice | -|---|---| -| Skill name | **`raise-coverage`** (verb-noun, like `write-docs` / `bump-version`) | -| Workflow | localize → propose cases → **wait for approval** → generate → verify; plus read-only `--triage` | -| Coverage engine | **JaCoCo engine**, exposed via **Kover** (`koverXmlReport`); when a consumer repo still has vanilla JaCoCo, the skill migrates it first (see `raise-coverage-kover-migration.md`); Codecov deferred | -| Test language | **Kotlin + Kotest** for every new test, regardless of the language of the code under test; class names use the **`Spec`** suffix (e.g. `AbstractSourceFileSpec`). Truth proto extension is reachable only when Kotest cannot express the assertion | -| Scratch dir | reuse existing `tmp/` → `tmp/base-libraries` (already gitignored via `/tmp`) | -| Done bar | full loop on one `base-libraries` module, **local, nothing committed** | -| Codex parity | include `agents/openai.yaml` | -| Branch/task | keep branch `coverage-tests-skill`; `git mv` task file → `raise-coverage.md` | - -### Verified facts (baked into the deliverables) - -- **Skill system**: source of truth is `.agents/skills//`; `.claude/skills` - is a **symlink** to `../.agents/skills` (author once). `.claude/commands/.md` - is the slash-command wrapper. Action skills also ship `agents/openai.yaml`. -- **Distribution**: `migrate` (sourced by `pull`) copies the whole `.agents` + - `.claude` tree, so a new skill auto-propagates — **except** a Hugo-only-repo - prune block that strips JVM-specific skills. `raise-coverage` is JVM-specific - and must be added to that block. -- **Test stack**: Kotest `6.1.11` (`io.kotest:kotest-assertions-core`), Google - Truth `1.4.4` (`truth` + `truth-proto-extension`), JUnit `6.0.3` - (`org.junit:junit-bom`), JaCoCo `0.8.14` (`Jacoco.kt`, already bumped in the - working tree). -- **House test idiom**: JUnit Jupiter structure (`@Test` / `@Nested` / - `@DisplayName` / `@TempDir`) + **Kotest matchers** (`shouldBe`, `shouldThrow`, - `shouldContainExactlyInAnyOrder`). NOT pure Kotest specs. (Verified in - `buildSrc/src/test/.../FileExtensionsTest.kt`.) -- **Kover paths** (post-migration): per-module - `/build/reports/kover/report.xml` — same on Kotlin-JVM and KMP - modules configured by Spine's `kmp-module` script plugin, which sets up - only the `total` Kover report (no named variants, so no - `koverXmlReport` task is generated). Root aggregation (when wired): - `build/reports/kover/report.xml`. Kover manages exec data internally — no - raw `.exec` paths are exposed to consumers. -- **Runtime successor to `JacocoConfig`**: - `io.spine.gradle.report.coverage.KoverConfig.applyTo(rootProject)`. Applies - the Kover plugin at the root, wires `dependencies { kover(project(...)) }` - for every Kover-enabled subproject, pins - `useJacoco(version = Jacoco.version)`, and pushes the union of generated-class - FQNs as Kover excludes into both per-module and root reports. Preserves the - generated-code-filtering behavior previously provided by `CodebaseFilter` so - the skill does not hallucinate gaps for generated classes. -- **Never test**: generated code (any path containing `generated`), `examples`, - existing `test` sources. `.codecov.yml` scope is `src/main/**` only. -- **No version bump** for tests-only changes (contrast with other action skills, - which end by invoking `/version-bumped`). - -## Deliverables (file-by-file) - -1. **`.agents/skills/raise-coverage/SKILL.md`** — frontmatter `name` + - `description: >`. Sections: Goal/scope (**Kover-only**, using its - JaCoCo-format XML report; human `src/main` only) · Inputs (`$ARGUMENTS` - = `:module` | path | `--triage`) · Step 0 — Ensure Kover (read-only - under `--triage`; silent install when no coverage plugin is in place; - **propose-and-wait** when vanilla JaCoCo is detected, per - `references/migrate-to-kover.md`) · Workflow (1 resolve target → - 2 localize gaps from Kover's `report.xml` → 3 read code-under-test + - existing tests + collaborators → 4 **propose test-case list and WAIT**; - `--triage` stops here with the ranked report → 5 generate → 6 verify) · - Test-generation rules (stubs not mocks; **Kotlin + Kotest** universal — - JUnit Jupiter structure with Kotest assertions, written in Kotlin even - when the code under test is Java; class names use the **`Spec`** suffix; - `truth-proto-extension` is reachable only as an isolated fallback for - Protobuf assertions Kotest cannot express; cover edge cases; scaffold - `when`/sealed branches; skip generated/excluded paths) · Report format · - Safety (`--triage` is read-only; migration requires approval when - vanilla JaCoCo is detected; never weaken a `.codecov.yml` target; never - add a mocking dependency; read-only until step-4 approval; no version - bump for tests-only). - -2. **`.agents/skills/raise-coverage/references/coverage-signals.md`** — JaCoCo - mechanics (rewritten from the draft, corrected to this repo): per-module vs - `jacocoRootReport`; the real report paths above; XML structure and gap rules - (`ci==0` uncovered line, `mb>0` partial branch); `xmllint`/Python extraction - recipes; the generated-code exclusion; `.codecov.yml` scope; KMP - source-set/exec-data variants. Ends with a short **"Future: Codecov triage - tier"** appendix capturing the deferred two-tier design. - -3. **`.agents/skills/raise-coverage/agents/openai.yaml`** — Codex parity - (`interface.display_name` / `short_description` / `default_prompt`). - -4. **`.claude/commands/raise-coverage.md`** — thin slash-command wrapper. - `allowed-tools: Read, Edit, Write, Grep, Glob, Bash(./gradlew:*), - Bash(git status:*), Bash(find:*)` (dropped `curl`/`WebFetch` — Codecov - deferred). Body points at the skill, states the order, honors `testing.md` + - `coding-guidelines.md`, notes no version bump for tests-only. - -5. **`.agents/_TOC.md`** — add `23. [Raise test coverage](skills/raise-coverage/SKILL.md)`. - -6. **`migrate`** — add `raise-coverage` to the Hugo-only prune block: - `rm -rf ../.agents/skills/raise-coverage`, - `rm -rf ../.claude/skills/raise-coverage`, - `rm -f ../.claude/commands/raise-coverage.md` (mirrors existing JVM-skill entries). - -7. **`.agents/tasks/raise-coverage.md`** — this file (`git mv` from - `improve-test-coverage.md`). - -> Dropped from the original plan: the standalone "install README". We author -> directly in `config`, so there is no separate install step — placement is -> documented here. - -## Reusable test harness - -```bash -# from the config repo root -mkdir -p tmp -git clone --recurse-submodules https://github.com/SpineEventEngine/base-libraries tmp/base-libraries -cd tmp/base-libraries && git submodule update --init --recursive - -# lay down the published .agents/.claude baseline -./config/pull - -# overlay the in-development skill on top of the baseline -cp -R /.agents/skills/raise-coverage .agents/skills/ -cp /.claude/commands/raise-coverage.md .claude/commands/ -# (.claude/skills → ../.agents/skills symlink resolves the skill automatically) -``` - -`pull` fetches the **published** config from master, so it won't contain -`raise-coverage` yet — the overlay-copy injects the in-dev version. Then execute -the skill's procedure against one module and verify. - -## Plan - -- [x] Housekeeping: `git mv` task file → `raise-coverage.md`; `TaskCreate` to track. -- [x] Author `SKILL.md`, `references/coverage-signals.md`, `agents/openai.yaml`, - and the `.claude/commands/raise-coverage.md` wrapper. -- [x] Wire-up: add `_TOC.md` entry; add `raise-coverage` to the `migrate` prune block. -- [x] Harness + pilot: cloned `base-libraries` into `tmp/`, ran `./config/pull`, - overlaid the skill. Localized gaps via Kover (`koverXmlReport`), then closed - `EnvironmentType.equals()`/`hashCode()` with a Java+Truth test — the gap went - to zero (4 tests green, nothing committed). Hardened `SKILL.md` + - `coverage-signals.md` for the Kover frontend and for non-actionable - (inline / unreachable) gaps surfaced by the pilot. -- [x] Review: `review-docs` over the new Markdown; sanity-check the `migrate` - edit; confirm nothing staged in `tmp/base-libraries`. -- [x] Kover-only pivot: implemented `.agents/tasks/raise-coverage-kover-migration.md`. - Dropped dual-frontend logic, added Step 0 migration gate to `SKILL.md`, - and deprecated the JaCoCo-pipeline `buildSrc` helpers (`JacocoConfig`, - `CodebaseFilter`, `FileFilter`, `FileExtensions`, `FileExtension`, - `PathMarker`, `TaskName`, plus the `jacoco-*-jvm.gradle.kts` script - plugins). Authored `KoverConfig.kt` as the live runtime successor — - preserves the generated-code exclusion previously provided by - `CodebaseFilter` and wires per-subproject `kover(project(...))` - aggregation, with the union of generated FQNs pushed into both - per-module and root reports. Three review/fix cycles - (`kotlin-review` + `review-docs`, parallel) all returned APPROVE; - `./gradlew -p buildSrc compileKotlin` green. -- [x] Re-run pilot with the updated skill against `tmp/base-libraries` - (`--triage` first, then close one fresh gap). Step 0 correctly detected - the hybrid state (root vanilla JaCoCo + subprojects already on Kover via - `module` script plugin), emitted the structured proposal, and on approval - migrated the root build (drop `jacoco` plugin; swap `JacocoConfig` → - `KoverConfig`; lift the call out of `gradle.projectsEvaluated`). Smoke - check passed: `:base:koverXmlReport` and root `koverXmlReport` both - produce JaCoCo-format XML with ``; generated - `OptionsProto` correctly excluded. Closed gaps in - `io.spine.code.fs.AbstractSourceFile` with a Java + Truth + `@TempDir` - stub (6 cases): coverage delta 20 missed LINE → 2, 2 missed BRANCH → 0 - (LINE 91 %, BRANCH 100 %). The residual 2 missed LINE are non-actionable - (`throw newIllegalStateException(...)` where the helper throws - internally) — pattern added to `references/coverage-signals.md`. -- [ ] On merge: flip `status: done` and delete this task file per the - `.agents/tasks/` lifecycle. - -## Verification (the done bar) - -- Files: `_TOC.md` resolves; `.claude/skills/raise-coverage/SKILL.md` resolves - through the symlink; `openai.yaml` parses. -- Distribution: confirm the `migrate` prune block lists `raise-coverage` so - Hugo-only repos won't receive it. -- End-to-end ✅: in `tmp/base-libraries`, `:environment:koverXmlReport` ran; - `EnvironmentTypeTest` (Java + Truth, 4 tests) compiles and passes; re-parsing - `build/reports/kover/report.xml` shows `EnvironmentType` `missedLINE`/ - `missedBRANCH` → 0 (was 2 / 1). **Nothing committed to base-libraries.** - -## Risks / notes - -- **Build feasibility**: `base-libraries` must build here (JDK + network; first - build slow). Mitigation: build only the pilot module's test+report tasks. If it - can't build, fall back to the analysis dry-run for the pilot and flag it — the - four authored files still ship. -- **Pre-existing working-tree changes**: `Jacoco.kt` (→`0.8.14`) and the old task - file are already modified. Leave `Jacoco.kt` alone (align docs to 0.8.14); only - `git mv`/rewrite the task file. -- **No commits/pushes** anywhere unless explicitly authorized. - -## Log - -- 2026-05-29 — Shortlisted candidate skills; selected `clear-solutions` as the - structural base with Kotest/taxonomy donors. -- 2026-05-29 — Recorded original decisions (mixed Java+Kotlin, Codecov + JaCoCo, - author in `config` for all repos); drafted SKILL/reference/command/install. -- 2026-05-30 — Re-scoped with the user. Renamed skill `coverage-tests` → - **`raise-coverage`**; **deferred Codecov** (JaCoCo-only v1); confirmed - Kotlin→Kotest / Java→Truth; chose `tmp/` scratch dir; set the done bar to a - local full-loop on a `base-libraries` module; added `openai.yaml` + `migrate` - prune-block deliverables. Verified the test stack and JaCoCo report paths from - `buildSrc`. Rewrote this task file from the plan; awaiting review. -- 2026-05-30 — Pivot to Kover-only. Decided to collapse the skill to a single - frontend and add a Step 0 migration gate. When the skill detects vanilla - JaCoCo, it proposes a one-shot repo-wide migration and waits for approval; - when nothing is in place, it installs Kover silently. The vanilla-JaCoCo - helpers under `buildSrc` (`jacoco-kotlin-jvm` / `jacoco-kmm-jvm` script - plugins, `JacocoConfig` aggregator and its support classes) are deprecated, - not deleted, so existing consumers keep building. Full implementation plan - moved to `.agents/tasks/raise-coverage-kover-migration.md`. -- 2026-05-30 — Built the four files + wire-up; ran the `base-libraries` pilot. - Findings that reshaped the skill: (1) consumer repos expose coverage through - **Kover** (`koverXmlReport`, JaCoCo engine, JaCoCo-format XML) — not the - per-module `jacocoTestReport` the draft assumed — so the skill is now - frontend-aware (Kover or raw JaCoCo). (2) `inline`/`reified` functions and - unreachable guards read as uncovered but are **non-actionable** (a passing test - for `parse` left `Parse.kt` `ci=0`), so the skill now filters them out. - Demonstrated true closure on `EnvironmentType.equals()`/`hashCode()` - (Java + Truth). `review-docs` running. -- 2026-05-30 — Tightened the test-generation policy in `SKILL.md` and the - Codex `default_prompt`. New tests are always written in **Kotlin** (JUnit - Jupiter + Kotest assertions), regardless of whether the code under test is - Kotlin or Java, and test class names use the **`Spec`** suffix - (`AbstractSourceFileSpec`, not `AbstractSourceFileTest`). This matches the - `*Spec.kt` convention already in use across `base-libraries` and removes - the dual-language Truth-for-Java branch that the prior pilot followed by - accident. Truth (`truth-proto-extension`) stays reachable only for - Protobuf assertions Kotest cannot express. -- 2026-05-30 — Re-ran the pilot end-to-end on `tmp/base-libraries`. Step 0 - detected vanilla JaCoCo at the root + Kover already applied in subprojects, - proposed the repo-wide migration, and on approval applied it. One lifecycle - gotcha surfaced: `KoverConfig.applyTo(root)` cannot live inside - `gradle.projectsEvaluated { … }` (Kover registers `afterEvaluate` hooks at - apply time). Documented in `references/migrate-to-kover.md` §3 and in the - `KoverConfig` class KDoc. Closed `AbstractSourceFile` with a Java + Truth - stub (6 cases via `@TempDir`); coverage went 20/2 missed LINE/BRANCH → 2/0. - Residual 2 LINE remained `mi=10 ci=0` despite passing tests — root cause is - the Spine `Exceptions.newIllegalStateException` idiom (declared to return - the exception but throws internally), making `throw helper(...)` lines - unreachable for JaCoCo's downstream probe. Added the pattern to - `references/coverage-signals.md` as a third non-actionable category. -- 2026-05-30 — Kover-only pivot landed. Implemented per - `.agents/tasks/raise-coverage-kover-migration.md`: collapsed the skill to a - single Kover frontend with a Step 0 migration gate that proposes a repo-wide - JaCoCo → Kover migration (waits for approval) when vanilla JaCoCo is - detected. Deprecated the `JacocoConfig` aggregator and its supporting helpers - (`CodebaseFilter`, `FileFilter`, `FileExtensions`, `FileExtension`, - `PathMarker`, `TaskName`) plus the `jacoco-*-jvm.gradle.kts` script plugins - — kept on disk so existing consumers keep building. Authored `KoverConfig.kt` - as the live runtime successor (preserves generated-code exclusion via Kover - `filters { excludes { classes(...) } }` derived from source dirs containing - `generated/`; wires `kover(project(...))` aggregation for every Kover-enabled - subproject; pins the JaCoCo engine version). Doc set updated: - `references/migrate-to-kover.md` is the new mechanical recipe; - `SKILL.md` got the Step 0 proposal protocol; `coverage-signals.md` rewritten - Kover-only. Reviewed across three cycles (`kotlin-review` + `review-docs` - in parallel) — all APPROVE, zero outstanding comments; - `./gradlew -p buildSrc compileKotlin` green. Nothing committed. diff --git a/.agents/tasks/archive/setup-cross-tool-agent-instructions.md b/.agents/tasks/archive/setup-cross-tool-agent-instructions.md deleted file mode 100644 index 02672e2c8..000000000 --- a/.agents/tasks/archive/setup-cross-tool-agent-instructions.md +++ /dev/null @@ -1,138 +0,0 @@ ---- -slug: setup-cross-tool-agent-instructions -branch: improve-caching -owner: claude -status: in-review -started: 2026-05-24 ---- - -# Task: Consolidate Agent Instructions into AGENTS.md - -## Goal - -Move universal agent instructions from `CLAUDE.md` into `AGENTS.md` so that -Claude Code, GitHub Copilot, and Codex all read identical rules from a single -source. Reduce `CLAUDE.md` to a thin wrapper that imports `AGENTS.md` plus a -small Claude Code-specific section. - -## Current state - -Both files already exist with real content. - -**`AGENTS.md`** currently has: -- Orientation — `project.md` reference, link to `.agents/_TOC.md` -- Commit and history safety — full rule (authoritative) -- Other safety rules — compile check, no auto-deps, no analytics, no reflection -- Moving files — `git mv` rule - -**`CLAUDE.md`** currently has: -- Project Guidelines — quick-reference-card, `project.md`, `jvm-project.md`, - skills, TOC -- Workflow Rules — `EnterPlanMode`, task planning, `api-discovery` skill, - commit rule (duplicate of AGENTS.md) -- Memory — team memory (`.agents/memory/`) + per-developer (auto-memory) -- Verification & Quality -- Core Principles -- Task Flow — plan writing, `ExitPlanMode`, `TaskCreate` -- Final Rule - -## Content split - -**Universal — move to `AGENTS.md`:** - -| Section | Notes | -|---|---| -| Project Guidelines (project.md, jvm-project.md, skills, TOC) | All agents need this orientation | -| Memory → team-shared store only (`.agents/memory/`) | Codex/Copilot have no auto-memory; the team store is universal | -| Verification & Quality | Universal engineering standards | -| Core Principles | Universal | -| Task Flow items 1, 4, 5, 6 (plan write, verify, update memory, delete task) | Universal; omit items 2–3 (ExitPlanMode/TaskCreate) | - -**Claude Code-specific — keep in `CLAUDE.md` only:** - -| Item | Why Claude-only | -|---|---| -| `EnterPlanMode` / `ExitPlanMode` | Claude Code SDK tools | -| `api-discovery` skill / never unzip JARs | Gradle cache path is machine-local | -| Per-developer auto-memory | Claude Code built-in feature | -| `TaskCreate` for live status | Claude Code SDK tool | -| Final Rule meta-note | Claude Code session advice | - -## Steps - -### 1. Expand `AGENTS.md` - -Add the universal sections to `AGENTS.md` after the existing content. Do not -duplicate the commit rule — it is already there. Resulting sections in order: - -1. Welcome / Orientation *(already exists — update to include quick-reference-card and skills references)* -2. Commit and history safety *(already exists — keep as-is)* -3. Other safety rules *(already exists — keep as-is)* -4. Moving files *(already exists — keep as-is)* -5. **Memory** — team-shared store only; omit the per-developer store -6. **Verification & Quality** -7. **Core Principles** -8. **Task planning** — write plan to `.agents/tasks/.md`; verify before marking done; delete task file on merge - -Keep `AGENTS.md` under 120 lines. Every line must change agent behaviour. - -### 2. Rewrite `CLAUDE.md` as a thin wrapper - -Replace the current content with: - -```markdown -@AGENTS.md - -## Claude Code-specific notes - -- Use Plan mode (`EnterPlanMode`) for architecture, refactoring, multi-file - changes, or lengthy documentation. Show the plan (`ExitPlanMode`) before - implementing. -- Track live progress with `TaskCreate`. -- Before reading library source code from `~/.gradle/caches`, follow the - `api-discovery` skill — never `unzip` JARs directly. -- Per-developer memory lives in the built-in auto-memory dir. Use it for - personal preferences, ephemeral project state, and per-machine resources. - Litmus test: *would a teammate benefit from this next month?* → repo. - Otherwise → auto-memory. -- This is living team memory. Update it regularly and keep it concise - (<120 lines / ~2.5k tokens). -``` - -### 3. Verify `.github/copilot-instructions.md` - -This file already exists. Confirm it contains an explicit reference to `AGENTS.md` -at the repository root, a pointer to `project.md` for repo context, and the -universal "Do not suggest" safety rules. Add the `AGENTS.md` reference if absent. - -### 4. Verify the setup - -Run these checks and report results: - -- `AGENTS.md` exists at repo root and is under 120 lines (`wc -l AGENTS.md`). -- `CLAUDE.md` first non-empty line is `@AGENTS.md`. -- `.github/copilot-instructions.md` exists and references `.agents/project.md`. -- All modified files are tracked by git (no relevant "Untracked files" in - `git status`). - -### 5. Commit - -Stage only the files modified by this task. Use this commit message: - -``` -refactor: consolidate agent instructions into AGENTS.md - -Move universal rules (orientation, memory, quality, principles, task -planning) from CLAUDE.md into AGENTS.md so Codex, Copilot, and Claude -Code all read from a single source. CLAUDE.md becomes a thin @AGENTS.md -wrapper plus Claude Code-specific notes. -``` - -## Acceptance Criteria - -- Editing `AGENTS.md` is the only required change to update agent behaviour - across all three tools. -- No universal instruction content exists only in `CLAUDE.md`. -- `AGENTS.md` is under 120 lines. -- `CLAUDE.md` first non-empty line is `@AGENTS.md`. -- All checks in step 4 pass. diff --git a/.agents/tasks/core-jvm-compiler-pr104-version-publish-investigation.md b/.agents/tasks/core-jvm-compiler-pr104-version-publish-investigation.md deleted file mode 100644 index f587eba49..000000000 --- a/.agents/tasks/core-jvm-compiler-pr104-version-publish-investigation.md +++ /dev/null @@ -1,189 +0,0 @@ -# Investigation: behavior-changing PR merged without a version bump → publish silently lost - -> **Handoff note.** This report is written so it can be attached to a **fresh -> `config`-repo session** with no prior context. The incident originates in -> `SpineEventEngine/core-jvm-compiler` PR #104 and surfaced as a build failure in -> `SpineEventEngine/compiler`, but the *machinery that should have caught it* — -> the **Version Guard** (`checkVersionIncrement`) and the **Publish** workflow — -> is owned and distributed by **`config`**. The goal of the follow-up work is to -> harden that machinery. All file paths below are **`config`-repo-relative**. - ---- - -## 1. TL;DR - -1. core-jvm-compiler **PR #104 "Support ID fields of enum type"** was merged to - `master` **without bumping the version** — it stayed at - `2.0.0-SNAPSHOT.079`. -2. `.079` had **already been published** to GAR (from a prior `master` build that - predates #104). -3. The PR-time **Version Guard** check (`checkVersionIncrement`) **passed**, - because it only verifies *"this version is not yet published"* — **not** - *"the version was incremented relative to the base branch."* -4. The post-merge **Publish** workflow then **failed** at *"Publish artifacts to - Maven"* — you cannot overwrite the already-published fixed version `.079`. -5. **Net effect:** #104's code lives on `master` but was **never published**. The - published `.079` artifact is the *pre-#104* build. Every downstream consumer - pinned to `.079` silently lacks the fix, and **no published version contains - it** until someone bumps to `.080` and publishes. - -This is a **process/tooling gap**, not a one-off mistake: the guard is named -"check version increment" but does not enforce an increment, and the only thing -that *did* catch the collision (the publish step) runs **after** the PR is -already merged, when it is too late to block. - ---- - -## 2. The config-owned mechanisms involved - -| Concern | File (config-relative) | What it does | -|---|---|---| -| Version Guard workflow | `.github-workflows/increment-guard.yml` | Distributed to consumers as `.github/workflows/increment-guard.yml`. Job **"Check version increment"**, `on: pull_request`, runs only when `github.base_ref` ends with `master`/`main`. Runs `./gradlew checkVersionIncrement`. | -| The Gradle task | `buildSrc/src/main/kotlin/io/spine/gradle/publish/CheckVersionIncrement.kt` | Fetches the artifact's published `maven-metadata.xml` and **fails only if the version list already `contains(project.version)`** (`checkInRepo`, ~lines 70–85). It never compares against the base branch. | -| Task enablement | `buildSrc/src/main/kotlin/io/spine/gradle/publish/IncrementGuard.kt` | `shouldCheckVersion(event, baseBranch)` (lines 54–59) enables the task only for `pull_request` events targeting `*master`/`*main`. Wires the task into `check` (line 83). | -| Publish workflow | `.github-workflows/publish.yml` | Distributed as `.github/workflows/publish.yml`. Job **"Publish to Maven repositories"**, `on: push: branches: [master]`. Step **"Publish artifacts to Maven"** performs the actual deploy — and **fails if the version already exists**. | -| Prior design context | `.agents/tasks/version-guard-aux-base-branches.md` | Earlier task that scoped `IncrementGuard` to PR-to-master/main only. Useful background for why the guard is shaped the way it is. | - -**Key semantic to internalize:** `checkVersionIncrement` is really -`checkVersionNotYetPublished`. A PR that does **not** touch the version passes it, -as long as that version is not (yet) in the published metadata at the moment the -check runs. - ---- - -## 3. Evidence & timeline (all timestamps UTC, 2026-06-19 unless noted) - -| Time | Event | Evidence | -|---|---|---| -| 2026-06-18 16:06 | core-jvm-compiler version bumped to `.079` in a **separate** commit `0618423e` ("Bump version -> `2.0.0-SNAPSHOT.079`") — *not* part of #104 | `git log` of `version.gradle.kts` | -| 08:02:43 | **Publish** workflow on `master` head `66521edb` (version `.079`) — **success** → `.079` lands on GAR (the pre-#104 build) | Actions run list; `66521edb:version.gradle.kts` = `.079` | -| 12:15:49 | #104's **"Check version increment"** check — **success** (PR head `75e8fdd3`, version `.079`, no bump) | check-runs on `75e8fdd3` | -| 12:48:46 | **#104 merged** to `master` (merge commit `1ef7e7c`), base `master`, **no version change** | `gh pr view 104` | -| 12:48:49 | **Publish** workflow on the #104 merge `1ef7e7c` — **FAILURE** at step *"Publish artifacts to Maven"* | Actions run `27826655989`, job "Publish to Maven repositories" | -| now | core-jvm-compiler `master` still declares `.079`; latest published `core-jvm-plugins` on GAR is `.079` (pre-#104). The fix is unpublished. | GAR `maven-metadata.xml`; `master:version.gradle.kts` | - -**Confirmed facts** -- PR #104 contains **no** version bump (verified: `75e8fdd3:version.gradle.kts` = `.079`). -- The published `.079` predates #104. Its `RequiredIdReaction` **rejects** enum ID - fields; the post-#104 code (master, and the local `.080` build) **allows** them. -- The merge's publish failed *because* `.079` was already on GAR (08:02) — fixed - versions cannot be overwritten. - ---- - -## 4. Gap analysis — why nothing blocked it - -1. **The PR-time guard does not enforce an increment.** Despite the name, - `checkVersionIncrement` only asks "is `project.version` already published?". - A behavior-changing PR that keeps the same (not-yet-published) version sails - through. There is no comparison of *PR-head version* vs *base-branch version*. - -2. **Time-of-check / time-of-use (TOCTOU) race.** Even the "not-yet-published" - semantics are racy: between a PR's check passing and that PR merging, **another - merge can publish the same version**. That is exactly what happened here — by - the time #104 merged (12:48), `.079` had been published (08:02) by a different - `master` build, so #104's publish failed. GitHub's *"require branches up to date - before merging"* is **not** enforced, so the stale check was never re-evaluated - against the advanced base. - -3. **The only effective guard runs too late.** The actual collision was caught by - the **Publish** step — which runs **on push to `master`, after the PR is already - merged**. A failed publish does not un-merge the PR; it just leaves `master` - with unpublished changes and a red post-merge workflow that is easy to miss. - -4. **Open question (central to the fix):** why did #104's check **pass at 12:15** - when `.079` was already published at **08:02** (≈4 h earlier)? If the check had - correctly seen `.079` as published, it would have **failed #104 at PR time** and - forced a bump. Candidate causes to investigate in `config`: - - GAR `maven-metadata.xml` propagation lag / CDN or HTTP caching seen by - `CheckVersionIncrement.fetch()` (it does a plain `URL` read with no - cache-busting). - - Per-module metadata: the task runs per Gradle subproject - (`project.artifactPath()` uses `artifactPrefix + project.name`); the specific - module(s) checked may have lagged the publish of the fat-jar artifact. - - The PR check ran against a checkout/metadata snapshot that did not yet list - `.079`. - Reproducing this race is the key to a durable fix. - ---- - -## 5. Suggested directions for `config` (not prescriptive — design choices) - -These are options to weigh, not a fixed plan: - -- **A. Make the guard a real increment check.** In `CheckVersionIncrement` (or a - companion task), compare the PR-head version against the **base-branch** - `version.gradle.kts`. Fail when they are equal *and* the PR contains publishable - changes. This directly catches "merged behavior change without a bump," - independent of publish timing/caching. (`IncrementGuard` already has - `GITHUB_BASE_REF`; the base version can be read via `git show - origin/$BASE:version.gradle.kts`.) - -- **B. Close the TOCTOU gap.** Either require PR branches to be **up to date with - base** before merge (so the guard re-runs against the advanced base), or add a - cache-busting/freshness step to the metadata fetch so the "already published" - read is authoritative at check time. - -- **C. Make publish failures loud and actionable.** A failed **Publish** on - `master` currently lands *after* merge. Consider alerting on it explicitly, or a - pre-merge dry-run of the publish-collision check, so the signal arrives before - it's too late to block. - -- **D. Codify the "bump-on-behavior-change / one-bump-per-branch" policy in the - tooling** rather than leaving it to convention, so the guard — not a human — - enforces it. - -Any change here ships to **all** consumer repos via `config` distribution, so it -should be covered by `IncrementGuardTest` -(`buildSrc/src/test/kotlin/io/spine/gradle/publish/IncrementGuardTest.kt`) and -validated against the `config` repo's own CI before floating. - ---- - -## 6. How to reproduce / verify - -1. **Confirm the published `.079` predates #104:** the GAR - `core-jvm-plugins` `maven-metadata.xml` lists `.079` as latest; its - `RequiredIdReaction` lists `enum` among *rejected* ID types, whereas - core-jvm-compiler `master` (post-#104, commit `1ef7e7c`) lists `enum` among - *allowed* types. -2. **Confirm the failed merge publish:** GitHub Actions run - `27826655989` ("Publish", head `1ef7e7c`) → job "Publish to Maven - repositories" → failed step "Publish artifacts to Maven". -3. **Confirm the guard semantics:** read - `buildSrc/src/main/kotlin/io/spine/gradle/publish/CheckVersionIncrement.kt` - (`checkInRepo` only fails on `versions.contains(version)`). - ---- - -## 7. Downstream impact & the *separate* immediate unblock - -The consumer symptom that triggered this investigation is in -`SpineEventEngine/compiler` (PR #74): `:api:launchTestSpineCompiler` fails because -a test proto uses an **enum entity-ID** and the build resolves the **pre-#104 -`.079`** from GAR. That is being unblocked **separately** by: -- publishing core-jvm-compiler **`.080`** (already prepared on its - `update-tool-base` branch, includes #104) to GAR, then -- bumping `CoreJvmCompiler` `.079 → .080` in the `compiler` repo. - -That consumer unblock is **not** the subject of this report. The `config` work is -the **systemic** fix so a behavior-changing PR can never again merge without a -bump and silently fail to publish. - ---- - -## 8. Reference index - -- core-jvm-compiler PR #104 "Support ID fields of enum type" — merged - 2026-06-19T12:48:46Z, merge commit `1ef7e7c`, base `master`, **no version bump**. -- Version bump to `.079`: commit `0618423e` (2026-06-18T16:06:14Z), separate from #104. -- `.079` publish (success): Actions run on `master` head `66521edb`, 08:02:43. -- #104 "Check version increment" (success): 12:15:49 on PR head `75e8fdd3`. -- #104 merge publish (failure): Actions run `27826655989`, 12:48:49. -- config files to edit/inspect: - - `.github-workflows/increment-guard.yml` - - `.github-workflows/publish.yml` - - `buildSrc/src/main/kotlin/io/spine/gradle/publish/CheckVersionIncrement.kt` - - `buildSrc/src/main/kotlin/io/spine/gradle/publish/IncrementGuard.kt` - - `buildSrc/src/test/kotlin/io/spine/gradle/publish/IncrementGuardTest.kt` - - `.agents/tasks/version-guard-aux-base-branches.md` (background) diff --git a/.agents/tasks/fix-temp-dirs-update-gh-pages.md b/.agents/tasks/fix-temp-dirs-update-gh-pages.md deleted file mode 100644 index 5c1fe1c3a..000000000 --- a/.agents/tasks/fix-temp-dirs-update-gh-pages.md +++ /dev/null @@ -1,53 +0,0 @@ ---- -slug: fix-temp-dirs-update-gh-pages -branch: claude/vibrant-heyrovsky-f88e0c -owner: claude -status: in-review -started: 2026-06-30 ---- - -## Goal - -Stop the `updateGitHubPages` task from leaking the `javadoc`, `html`, and -`repoTemp` temporary directories. They must be removed when the JVM shuts down, -even if the build fails before the existing eager cleanup runs -(GitHub issue [#240](https://github.com/SpineEventEngine/config/issues/240)). - -## Context - -`LazyTempPath` created temp dirs directly in `java.io.tmpdir` with no -shutdown-time cleanup, so a failed build (or a killed Gradle daemon) left them -behind forever. `File.deleteOnExit()` can't help — it does not delete non-empty -directories. - -Approach mirrors base PR -[SpineEventEngine/base#671](https://github.com/SpineEventEngine/base/pull/671): -group every temp dir under one recognizable base directory and remove that base -dir recursively via a single JVM shutdown hook. - -## Plan - -- [x] Add `buildSrc/.../io/spine/gradle/fs/SpineTempDir.kt` — lazily-created base - dir `/io.spine.gradle.fs`, deleted recursively by one JVM - shutdown hook. -- [x] Route `LazyTempPath` through `SpineTempDir.path` - (`createTempDirectory(SpineTempDir.path, prefix)`); update KDoc. -- [x] Leave eager cleanup (`UpdateGitHubPages.cleanup()`, `Repository.close()`) - as the primary mechanism. -- [x] Add tests: `fs/LazyTempPathSpec.kt` (4) and `fs/SpineTempDirSpec.kt` (2). -- [x] Verify: `-p buildSrc build` (whole suite green, 6/6 fs tests). - Note: detekt is not applied to `buildSrc`'s own sources, so it is not a gate here. -- [x] Pre-PR reviewers (`kotlin-engineer`, `spine-code-review`, `review-docs`) all APPROVE. - -## Log - -- 2026-06-30 — drafted plan, approved, implemented files. -- 2026-06-30 — `-p buildSrc build` SUCCESSFUL (needs JDK 17 — `JAVA_HOME` defaults - to Corretto 11 via jenv on this machine). -- 2026-06-30 — reviewers APPROVE; applied their feedback: log on shutdown-hook - delete failure, KDoc "folder"→"directory", split `SpineTempDir` test into its - own spec. Rebuilt green. -- 2026-06-30 — addressed Copilot review on PR #722: per-JVM subdirectory under the - `io.spine.gradle.fs` namespace so concurrent daemons don't delete each other's - temp files; null-safe `java.io.tmpdir`; clarified the JVM/daemon cleanup wording - in `LazyTempPath` KDoc. Rebuilt green (6/6 fs tests). diff --git a/.agents/tasks/gradle-caching-plan.md b/.agents/tasks/gradle-caching-plan.md deleted file mode 100644 index c2322f43b..000000000 --- a/.agents/tasks/gradle-caching-plan.md +++ /dev/null @@ -1,201 +0,0 @@ ---- -slug: gradle-caching-plan -branch: gradle-review-skill -owner: claude -status: draft -started: 2026-05-29 ---- - -# Plan: Speed Up Builds via Gradle Caching (org-wide, through `config`) - -> Implementation plan for Claude Code operating in the **`SpineEventEngine/config`** repository. -> Follow the repo's existing conventions in `CLAUDE.md` / `.agents/` (commit style, copyright -> headers, Kotlin guidelines, allowed commands). Make minimal diffs and land each phase as its -> own PR. - -## Purpose - -Make CI and local builds across the Spine organization faster by enabling **every free Gradle -caching layer**. Because `config` is the shared submodule pulled into every Spine repository, -changes here propagate org-wide — no per-repo edits required. - -## Why this work belongs in `config` - -`config` is added to each Spine project as a Git submodule, and `./config/pull` copies shared -files into the consuming project. Two of those files are exactly the levers we need: - -- **Root `gradle.properties`** — *overwritten* into each consuming repo on every `pull`. This is - the single source of truth for Gradle build flags. -- **`.github-workflows/`** — its workflow scripts are *merged into* each repo's - `.github/workflows/` on `pull`. This is where the CI definitions that run in every repo live. - (Per the repo README, these workflows intentionally do **not** run for `config` itself, so they - live under `.github-workflows/` rather than `.github/workflows/`.) - -Editing these here, then bumping the submodule + running `./config/pull` in a consuming repo, is -how the change reaches the whole org. - -## Goal - -Enable, in order of safety/ROI: - -1. **Dependency cache** — downloaded dependencies + wrapper distributions. -2. **Local build cache** — task outputs (`caches/build-cache-1`), persisted across CI runs so cold - CI builds skip unchanged work. -3. **Configuration cache** — skip Gradle's configuration phase on repeat runs (gated; higher risk). - -**Non-goal (out of scope here):** a *remote* build cache (Develocity or a self-hosted cache node). -That is the only layer that shares task outputs *across* repositories and across machines, but it -requires infrastructure (a reachable cache node + credentials, or Develocity) and is not a -config-only change. It is captured as a future phase, not to be implemented now. - -## Mental model (so changes are made for the right reasons) - -- The **dependency cache** speeds up *resolution/download*; it does not reuse build work. -- The **build cache** reuses *task outputs*, keyed by a hash of their inputs. Gradle's up-to-date - checks already cover "same workspace, nothing changed," so the build cache only adds value from a - **cold/fresh state** with unchanged inputs. -- **CI is cold on every run** (fresh checkout), so the build cache is precisely what helps CI — - independent of team size or number of repos. -- `gradle/actions/setup-gradle` persists the Gradle User Home (deps, wrapper, **and** - `caches/build-cache-1`) via the GitHub Actions cache. By default it **writes** the cache only - from the **default branch**; other branches **read** the default branch's cache. So PR builds - reuse what `main`'s CI produced, without polluting the shared cache. - - Caveat: for `pull_request`-triggered runs, the cache scope is the PR merge ref and writes are - disabled by default (only re-runs of the same PR restore them). The read-from-`main` behavior - still applies. - -## Guardrails (do / don't) - -- ✅ **DO** edit the **root `gradle.properties`** in `config` for all Gradle flags. -- ⛔ **DON'T** add Gradle flags to individual consuming repos' `gradle.properties` — `./config/pull` - overwrites that file, so such edits are lost. `config` is the only correct place. -- ✅ **DO** edit workflow templates in **`.github-workflows/`** (and, if you also want `config`'s - own CI to benefit, `config`'s own `.github/workflows/`). -- ⛔ **DON'T** keep `actions/setup-java` with `cache: gradle` alongside `setup-gradle` — the two - caching mechanisms conflict; remove `cache: gradle` when adding `setup-gradle`. -- ⛔ **DON'T** create any remote cache server, add secrets, create accounts, or change repo - permissions. (Out of scope; infra/owner decisions.) -- ✅ Keep diffs minimal: don't reorder or delete existing properties/steps that are unrelated. -- ✅ Land each phase as a **separate commit/PR** and validate before moving on. - -## Tasks - -### Phase 0 — Inventory (no changes) - -1. Read the root `gradle.properties`; record which `org.gradle.*` flags already exist (caching, - parallel, configuration-cache, jvmargs, etc.). -2. List `.github-workflows/`. For each workflow, locate the Java/Gradle setup steps and how Gradle - is invoked (`./gradlew ...`). Note any use of `actions/setup-java` with `cache: gradle`. -3. Check `config`'s own `.github/workflows/` separately (these run for `config` itself). -4. Read `gradle/wrapper/gradle-wrapper.properties` to determine the **Gradle version**. The stable - configuration-cache property names below assume Gradle **8.1+**; if older, adjust property names - and treat Phase 3 with extra caution. -5. Summarize findings before editing. - -### Phase 1 — Switch CI to `gradle/actions/setup-gradle` - -For each relevant workflow: - -- Remove `cache: gradle` from any `actions/setup-java` step. -- Add a `gradle/actions/setup-gradle@v6` step **after** Java setup and **before** any Gradle - invocation. (The action also configures init-scripts that apply to later `run: ./gradlew` steps.) -- Match the repo's existing action-pinning policy; current major versions available are - `actions/checkout@v6`, `actions/setup-java@v5`, `gradle/actions/setup-gradle@v6`. - -Reference shape (adapt to each workflow's actual jobs/matrix — do not blindly overwrite): - -```yaml -steps: - - uses: actions/checkout@v6 - - uses: actions/setup-java@v5 - with: - distribution: temurin - java-version: 17 # keep whatever the repo currently targets; no `cache: gradle` - - uses: gradle/actions/setup-gradle@v6 - - run: ./gradlew build -``` - -Notes: -- The default `enhanced` cache provider is **free for public repositories** (all Spine repos are - public). No `cache-provider` override needed unless a fully-MIT path is preferred - (`cache-provider: basic`). -- Leave the default write-on-default-branch-only behavior in place; it's the desired setup. - -### Phase 2 — Enable build cache + parallel in shared `gradle.properties` - -In the root `gradle.properties`, add (only if absent): - -```properties -org.gradle.caching=true -org.gradle.parallel=true -``` - -- `caching=true` enables the **local** build cache; combined with `setup-gradle` persisting - `caches/build-cache-1`, CI runs now reuse task outputs. -- `parallel=true` is generally safe but must be validated (see acceptance). - -### Phase 3 — Configuration cache (gated; higher risk) - -In the root `gradle.properties`, add: - -```properties -org.gradle.configuration-cache=true -org.gradle.configuration-cache.problems=warn -``` - -- Start in **warn** mode so configuration-cache-incompatible tasks **do not fail** the build. -- Spine relies on many custom Gradle plugins and code-generation tasks (Protobuf / Spine Compiler - / etc.) that may not yet be configuration-cache compatible. Warn mode surfaces problems without - breaking builds. -- Where feasible, fix incompatibilities in **`buildSrc`** (the shared build logic). If problems are - extensive, **leave configuration cache in warn mode or defer Phase 3 entirely** — do **not** - switch to strict/fail mode until the pilot consumer build is clean. -- (On Gradle < 8.1 the stable property differs; do not guess — check the wrapper version from - Phase 0 and use the matching property name, or skip this phase.) - -### Phase 4 — Remote build cache (FUTURE — do not implement now) - -Documented for completeness only. If pursued later: -- Configure `buildCache { remote(HttpBuildCache) { ... } }` (in `settings.gradle.kts` of consuming - projects, or centrally via `buildSrc`), pushing **only from CI**. -- Per Gradle's guidance, **disable the local build cache on CI** when a remote cache is available, - to keep GitHub Actions cache entries small. -- Requires a reachable cache node + credentials (or Develocity) and is an infrastructure decision — - not a config-only change. Stop and flag this to a human rather than implementing it. - -## Verification / acceptance criteria - -Verification rests entirely on a **real CI run in a pilot consumer repo**. The only thing that -proves the caching layers actually work is a `setup-gradle` run on a GitHub-hosted runner, and the -only workflow doing a meaningful build is the consumer repos' `build-on-ubuntu.yml`. There is no -local gate for this task: the workflow switch and the `gradle.properties` flags land in `config` -first, then the **pilot rollout** (see *Rollout* below) produces the evidence — the pilot *is* the -verification, not a precondition to it. - -For each phase, after the pilot repo has bumped the `config` submodule and run `./config/pull`, -inspect its `build-on-ubuntu` run: - -1. **Build is green** with the new `config` applied (workflow switch + `gradle.properties` flags). -2. **Cache is active:** the `setup-gradle` **Job Summary** reports cache entries restored/saved. The - first run on the default branch *writes* the cache; later runs — and PR branches reading the - default-branch cache — *restore* it, with many tasks shown as `FROM-CACHE` / `UP-TO-DATE`. -3. **CI is no slower — ideally faster:** compare overall job wall-clock **before vs after** across a - couple of runs once the cache is warm. -4. **Phase 3 specifically:** the pilot build completes with configuration cache enabled (warn mode - acceptable). Record any remaining configuration-cache problems in the PR description. - -## Rollout - -1. Land Phases 1–2 (and 3 if clean) as separate PRs in `config`. -2. Pilot in **one** consuming repo first (suggest `base`): bump the `config` submodule, run - `./config/pull` (this overwrites `gradle.properties` and merges `.github-workflows/` into - `.github/workflows/`), confirm CI is green and faster. -3. Propagate to the remaining repos once the pilot is validated. - -## References - -- `setup-gradle` docs: https://github.com/gradle/actions/blob/main/docs/setup-gradle.md -- Gradle Build Cache: https://docs.gradle.org/current/userguide/build_cache.html -- Gradle Configuration Cache: https://docs.gradle.org/current/userguide/configuration_cache.html -- `config` README (pull mechanism, `.github-workflows`): - https://github.com/SpineEventEngine/config diff --git a/.agents/tasks/pom-resolved-versions.md b/.agents/tasks/pom-resolved-versions.md deleted file mode 100644 index b4efaa1fb..000000000 --- a/.agents/tasks/pom-resolved-versions.md +++ /dev/null @@ -1,103 +0,0 @@ ---- -slug: pom-resolved-versions -branch: master -owner: claude -status: in-review -started: 2026-06-30 -issue: https://github.com/SpineEventEngine/config/issues/440 ---- - -## Goal - -The aggregated dependency report (`docs/dependencies/pom.xml` in consumer repos, -produced by `generatePom`) must report the **resolved** version of each -dependency — the version Gradle actually puts on the classpath — not the version -**declared** in the build script. - -## Context - -Issue #440. `Project.depsFromAllConfigurations()` in -`buildSrc/src/main/kotlin/io/spine/gradle/report/pom/DependencyWriter.kt` reads -`configuration.dependencies` (declared notations) and only patches in explicit -`force(...)` via `forcedVersionOf()`. It ignores conflict resolution, BOM/platform -constraints, and substitutions. Observed in the `text` module: the same artifact -`io.spine.validation:spine-validation-java-runtime` requested at `…SNAPSHOT.61` -and `…SNAPSHOT.40` logs a spurious "several versions" warning, and `deduplicate()` -(newest-declared wins) can print a version on no classpath when a `force` selects -the older one. - -Issue author's directive: *"`DependencyWriter` is meant to examine already -resolved configurations, and only then deduplicate, if needed."* - -## Plan - -- [ ] Add `Project.resolvedVersions(): Map` keyed by `"group:name"`, - built from `configurations.filter { it.isCanBeResolved }` → - `incoming.resolutionResult.allComponents` → `moduleVersion`. Newest-wins per - module via `io.spine.gradle.VersionComparator`. Per-configuration `try/catch` - so an unresolvable configuration is skipped (logged with the exception, not - swallowed) and the report never breaks the build. -- [ ] Rework `depsFromAllConfigurations(resolvedVersions)`: still iterate declared - external deps (scope), but use - `resolvedVersions["$group:$name"] ?: dependency.version` for the version. -- [ ] Delete `forcedVersionOf()` (subsumed by the resolution result). -- [ ] Test seam: `fun Project.dependencies()` (resolves own configs) + - `internal fun Project.dependencies(resolvedVersions: Map)` - (caller-supplied), both delegating to a private - `collectScopedDependencies(resolvedVersionsOf: (Project) -> Map)`. -- [ ] Update KDoc (class header + `Project.dependencies()`) to state versions are - resolved. -- [ ] `DependencyWriterSpec`: add resolved-path tests — older-resolved-wins, - two-in-one-configuration collapse, declared fallback when absent from the map. - Keep the existing 19 tests green. -- [ ] Verify: `:buildSrc:test`, `:buildSrc:detekt`, stash-check regression proof, - `spine-code-review` + `kotlin-engineer` reviewers. Update copyright year if the - tooling flags it. - -## Log - -- 2026-06-30 — drafted from issue #440; APIs verified against Gradle 9.3.0 - (`incoming.resolutionResult.allComponents`, `ResolvedComponentResult.moduleVersion`, - `Configuration.isCanBeResolved`). Plan approved; implementing. -- 2026-06-30 — implemented in `DependencyWriter.kt` (resolved-version map + - substitution, `forcedVersionOf` removed, HOF test seam) and 3 new - `DependencyWriterSpec` cases. `:buildSrc:test` green — `DependencyWriterSpec` - 23 tests / 0 failures (JDK 17 / Gradle 9.6.1). detekt is not applied to - `buildSrc` in this repo, so its sources are not statically analysed here; code - written detekt-clean regardless. Stash-check: neutralising the substitution makes - the "older resolved version wins" test fail, proving it pins the regression. - Real-resolution path verified once with a throwaway local-file-repo test (stub - POMs, `force` to the older version) — `dependencies()` reported the resolved - version; test then deleted. Unrelated `.idea/{misc,kotlinc}.xml` churn reverted. - Reviewers (`kotlin-engineer`, `spine-code-review`) running. -- 2026-06-30 — both reviewers APPROVE. Applied their findings: (a) reworded the - non-resolving `[resolvedVersionsOf]` KDoc link to backticked prose; (b) extracted - a single `moduleKey(group, name)` helper used by `depsFromAllConfigurations`, - `resolvedVersions`, and `deduplicate` so the three key derivations cannot drift; - (c) rewrote `resolvedVersions()` declaratively (`flatMap`/`mapNotNull`/`groupBy`/ - `maxOfWith`). Promoted the real-resolution check to a permanent - `DependencyWriterSpec` case (`read the version from a resolved configuration`, - local metadata-only POM repo + `force`) — closes the resolution-success coverage - gap. Final: `DependencyWriterSpec` **24 tests / 0 failures**; full `:buildSrc:test` - green. Stash-check repeated: both the injected-map and the real-resolution tests - fail against the neutralised substitution, proving both pin the regression. Change - set: `DependencyWriter.kt` + `DependencyWriterSpec.kt`. Staged for the user to - commit (not committed, per repo safety rules). -- 2026-06-30 — committed on branch `fix-440-resolved-pom-versions`. Ran the `pre-pr` - gate: `:buildSrc:build` PASS (root has no `build`/`dokkaGenerate` task — all code - lives in `buildSrc`; Dokka not applied, so its run is N/A); version gate N/A. - Re-ran the three reviewers on the committed diff — `spine-code-review`, - `kotlin-engineer`, `review-docs` all APPROVE. Applied their minor nits and a user - request: dropped the `#440` references from the test KDoc/companion comment, named - the trailing `ModuleDependency(... factualVersion = version)` argument, and - documented why the test uses the core `Action` repository overload instead of the - `kotlin-dsl` `maven { }` form (absent from the buildSrc test classpath). Rebuilt: - 24 tests / 0 failures. Opened PR #720. -- 2026-06-30 — CI `Run detekt` failed: the root `./gradlew detekt` task (never run - locally; `:buildSrc:detekt` does not exist) analyses `buildSrc` and flagged - `DependencyWriter.kt` for `TooManyFunctions` (11 top-level, threshold 11). Demoted - the single-use `resolvedComponentsOf` helper to a **local function** inside - `resolvedVersions` — keeps the named helper, the imports, and `moduleKey`, and drops - the file to 10 top-level functions. `./gradlew detekt` now green; `:buildSrc:build` - green, 24 tests / 0 failures. Lesson: run the root `detekt` task locally, not just - `:buildSrc:test`. diff --git a/.agents/tasks/port-compiler-coverage.md b/.agents/tasks/port-compiler-coverage.md deleted file mode 100644 index 5ff02a81b..000000000 --- a/.agents/tasks/port-compiler-coverage.md +++ /dev/null @@ -1,72 +0,0 @@ ---- -slug: port-compiler-coverage -branch: port-compiler-coverage -owner: claude -status: in-review -started: 2026-07-06 -related-memories: - - porting-buildsrc-from-consumer-repos - - config-build-verification ---- - -## Goal - -Upstream the Spine Compiler coverage helpers introduced in -[validation#317][pr-317] into `config`'s `buildSrc`, so every consumer -repo receives them via `./config/pull` and can credit forked-compiler -codegen execution to its root Kover report. - -## Context - -The `launch*SpineCompiler` tasks fork a JVM that Kover/JaCoCo do not -instrument, so codegen plugins report ~0% coverage in consumer repos. -[validation#317][pr-317] fixed this in `validation` (root coverage -12% → 86%) and its description names upstreaming the `buildSrc` helpers -to `config` as the follow-up. Only `buildSrc` files port; validation's -root `build.gradle.kts` wiring -(`subprojects { enableSpineCompilerCoverage() }`) stays consumer-owned. - -## Plan - -- [x] Fetch the four changed `buildSrc` files from the PR branch - `credit-codegen-coverage` and diff against `config` HEAD - (confirmed purely additive; no reverse drift). -- [x] `io/spine/dependency/test/Jacoco.kt` — add the `agent` coordinate - constant. -- [x] `io/spine/gradle/testing/SpineCompilerCoverage.kt` — new file: - `enableSpineCompilerCoverage()`, cacheable per-task exec output. -- [x] `io/spine/gradle/testing/TestKitCoverage.kt` — replace the inline - agent coordinate with `Jacoco.agent`. -- [x] `io/spine/gradle/report/coverage/KoverConfig.kt` — feed compiler - exec files into the root report's `additionalBinaryReports`. -- [x] Verify: `JAVA_HOME=$(/usr/libexec/java_home -v 17) ./gradlew - :buildSrc:build detekt`. -- [x] Review diff with `spine-code-review`, `kotlin-engineer`, - `dependency-audit`, and `review-docs`. -- [x] Commit on branch `port-compiler-coverage`, run the pre-PR gate, - open the PR. - -## Log - -- 2026-07-06 — drafted and started; user prompt authorizes the port - (edits only, no commits). -- 2026-07-06 — KDoc generalized while porting: validation-specific - references (`java`/`context` modules, `JavaValidationPlugin`) removed, - since `config` distributes these files to all consumer repos. -- 2026-07-06 — detekt (which covers `buildSrc` only here in `config`) - flagged `TooManyFunctions` in `KoverConfig.kt` after the port; merged - the duplicate `testKitExecFiles`/`compilerExecFiles` helpers into one - `execFiles(project, dirName)`. Build + detekt green afterwards. -- 2026-07-06 — all four reviewers APPROVE. Applied their improvements - on top of the verbatim port: reuse `consumesCoverageBinaryReports()` - from `SiblingCoverage.kt` (promoted to `internal`) instead of a - duplicate predicate; early-return guard makes - `enableSpineCompilerCoverage()` truly idempotent (a second call would - have double-loaded the agent); `dependsOn` comment no longer reads as - ordering-only; KDoc polish (grammar, `testFixtures` spelling, - `[Jacoco.agent]` links in `TestKitCoverage.kt`). -- 2026-07-06 — work complete; committed on branch - `port-compiler-coverage` (two commits), pre-PR gate re-run green (all - four reviewers APPROVE), PR opened for human review. - -[pr-317]: https://github.com/SpineEventEngine/validation/pull/317 diff --git a/.agents/tasks/version-guard-aux-base-branches.md b/.agents/tasks/version-guard-aux-base-branches.md deleted file mode 100644 index e964d01fc..000000000 --- a/.agents/tasks/version-guard-aux-base-branches.md +++ /dev/null @@ -1,50 +0,0 @@ ---- -slug: version-guard-aux-base-branches -branch: claude/modest-thompson-0aqffs -owner: claude -status: in-review -started: 2026-06-10 ---- - -## Goal - -PRs with a base branch other than a default (or release-line) one must not -fail `Version Guard`, `JUnit Test Report (push)`, or `License Reports` -because of a missing version increment. Only a branch heading into a -default/protected branch is responsible for bumping the version; auxiliary -branches stay out of the release cycle. - -## Context - -- `IncrementGuard` enables `checkVersionIncrement` on `push` to any branch - not ending with `master`/`main` — it cannot know the merge target of - a push, so feature branches of auxiliary branches fail. -- `checkVersionIncrement` is wired into `check`, so `Ubuntu CI` (`on: push`) - fails the whole build; tests never run and `JUnit Test Report (push)` - fails with "no test reports found". -- `License Reports` requires the dependency reports (which embed the - version) to be touched in every PR, including PRs to auxiliary branches. -- The only reliable signal of "aims to merge into X" is a pull request - with base `X` → use `pull_request` events and `GITHUB_BASE_REF`. - -## Plan - -- [x] `IncrementGuard.kt`: enable the task only for `pull_request` events - whose `GITHUB_BASE_REF` ends with `master`/`main`; drop the - `push`-event logic; update KDoc; keep the decision a pure function. -- [x] `increment-guard.yml`: trigger on `pull_request` (instead of `push` - to all branches) and skip the job unless the base branch ends with - `master`/`main`. -- [x] `ensure-reports-updated.yml`: same job-level base gate, so PRs into - auxiliary branches do not require report updates. -- [x] Add `IncrementGuardTest` for the decision function. -- [x] Run buildSrc tests and detekt. - -## Log - -- 2026-06-10 — drafted and started. -- 2026-06-10 — implemented; buildSrc tests and detekt pass. -- 2026-06-10 — review (PR #686): replaced the `branches` filters with - job-level `if` conditions — a workflow skipped by branch filtering - leaves a required check `Pending` (blocking the PR), while a skipped - job satisfies it. 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/CONTRIBUTING.md b/CONTRIBUTING.md index 2185ef6d5..896546ae0 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -21,12 +21,12 @@ Code contributions should: Contributor License Agreement ----------------------------- Contributions to the code of Spine Event Engine framework and its libraries must be accompanied by -Contributor License Agreement (CLA). +a Contributor License Agreement (CLA). * If you are an individual writing original source code and you're sure you own the intellectual property, then you'll need to sign an individual CLA. - * If you work for a company which wants you to contribute your work, + * If you work for a company that wants you to contribute your work, then an authorized person from your company will need to sign a corporate CLA. Please [contact us][legal-email] for arranging the paper formalities. diff --git a/README.md b/README.md index e340c03cc..24030f2e5 100644 --- a/README.md +++ b/README.md @@ -110,7 +110,7 @@ against these projects: * [`core-jvm`][core-jvm]. This takes slightly over half an hour, depending on the local configuration. -If you need to change the list of repositories, please update `addRepo()` calls to `ConifigTester`. +If you need to change the list of repositories, please update `addRepo()` calls to `ConfigTester`. The command to start the build process is: ```bash 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/src/main/kotlin/BuildExtensions.kt b/buildSrc/src/main/kotlin/BuildExtensions.kt index eefdb23e1..556f37a88 100644 --- a/buildSrc/src/main/kotlin/BuildExtensions.kt +++ b/buildSrc/src/main/kotlin/BuildExtensions.kt @@ -49,8 +49,8 @@ import org.gradle.plugin.use.PluginDependencySpec /** * Provides shortcuts to reference our dependency objects. * - * Dependency objects cannot be used under `plugins` section because `io` is a value - * declared in auto-generated `org.gradle.kotlin.dsl.PluginAccessors.kt` file. + * Dependency objects cannot be used under the `plugins` section because `io` is a value + * declared in the auto-generated `org.gradle.kotlin.dsl.PluginAccessors.kt` file. * It conflicts with our own declarations. * * In such cases, a shortcut to apply a plugin can be created: @@ -91,7 +91,7 @@ val ScriptHandlerScope.coreJvmCompiler: CoreJvmCompiler * Shortcut to [CoreJvmCompiler] dependency object. * * This plugin is not published to Gradle Portal and cannot be applied directly to a project. - * Firstly, it should be put to buildscript's classpath and then applied by ID only. + * Firstly, it should be put to the buildscript's classpath and then applied by ID only. */ val PluginDependenciesSpec.coreJvmCompiler: CoreJvmCompiler get() = CoreJvmCompiler @@ -116,8 +116,8 @@ val PluginDependenciesSpec.spineCompiler: Compiler /** * Provides shortcuts for applying plugins from our dependency objects. * - * Dependency objects cannot be used under `plugins` section because `io` is a value - * declared in auto-generated `org.gradle.kotlin.dsl.PluginAccessors.kt` file. + * Dependency objects cannot be used under the `plugins` section because `io` is a value + * declared in the auto-generated `org.gradle.kotlin.dsl.PluginAccessors.kt` file. * It conflicts with our own declarations. * * Declaring of top-level shortcuts eliminates the need to apply plugins @@ -177,10 +177,10 @@ fun Project.configureTaskDependencies() { * Creates a dependency between the Gradle task of *this* name * onto the task with `taskName`. * - * If either of tasks does not exist in the enclosing `Project`, + * If either of the tasks does not exist in the enclosing `Project`, * this method does nothing. * - * This extension is kept local to `configureTaskDependencies` extension + * This extension is kept local to the `configureTaskDependencies` extension * to prevent its direct usage from outside. */ fun String.dependOn(taskName: String) { @@ -278,7 +278,7 @@ fun JavaExec.remoteDebug(enabled: Boolean = true) { * * @param enabled If `true` the task will be suspended. * @throws IllegalStateException if the task with the given name is not found, or, - * if the taks is not of [JavaExec] type. + * if the task is not of [JavaExec] type. */ fun Project.setRemoteDebug(taskName: String, enabled: Boolean = true) { val task = tasks.findByName(taskName) @@ -324,7 +324,7 @@ fun Project.testFixturesSpineCompilerRemoteDebug(enabled: Boolean = true) = /** * Parts of names of configurations to be excluded by * `artifactMeta/excludeConfigurations/containing` in the modules - * where `io.spine.atifact-meta` plugin is applied. + * where the `io.spine.atifact-meta` plugin is applied. */ val buildToolConfigurations: Array = arrayOf( "detekt", @@ -337,7 +337,7 @@ val buildToolConfigurations: Array = arrayOf( ) /** - * Make the `sourcesJar` task accept duplicated input, which seems to occur + * Makes the `sourcesJar` task accept duplicated input, which seems to occur * somewhere inside Protobuf Gradle Plugin. */ fun Project.allowDuplicationInSourcesJar() { diff --git a/buildSrc/src/main/kotlin/DependencyResolution.kt b/buildSrc/src/main/kotlin/DependencyResolution.kt index 7d76bbba9..ce3785938 100644 --- a/buildSrc/src/main/kotlin/DependencyResolution.kt +++ b/buildSrc/src/main/kotlin/DependencyResolution.kt @@ -119,7 +119,7 @@ private fun ResolutionStrategy.forceTestDependencies() { } /** - * Forces transitive dependencies of 3rd party components that we don't use directly. + * Forces transitive dependencies of 3rd-party components that we don't use directly. */ private fun ResolutionStrategy.forceTransitiveDependencies() { force( diff --git a/buildSrc/src/main/kotlin/DokkaExts.kt b/buildSrc/src/main/kotlin/DokkaExts.kt index 814250a54..2e3160b04 100644 --- a/buildSrc/src/main/kotlin/DokkaExts.kt +++ b/buildSrc/src/main/kotlin/DokkaExts.kt @@ -198,11 +198,11 @@ fun TaskContainer.dokkaHtmlTask(): Task? = this.findByName("dokkaGeneratePublica fun TaskContainer.dokkaJavadocTask(): Task? = this.findByName("dokkaGeneratePublicationJavadoc") /** - * Locates or creates `htmlDocsJar` task in this [Project]. + * Locates or creates the `htmlDocsJar` task in this [Project]. * * The output of this task is a `jar` archive. The archive contains the Dokka output, generated upon - * Kotlin sources from `main` source set. Requires Dokka to be configured in the target project by - * applying `dokka-setup` plugin. + * Kotlin sources from the `main` source set. Requires Dokka to be configured in the target project by + * applying the `dokka-setup` plugin. */ fun Project.htmlDocsJar(): TaskProvider = tasks.getOrCreate("htmlDocsJar") { group = SpineTaskGroup.name diff --git a/buildSrc/src/main/kotlin/Strings.kt b/buildSrc/src/main/kotlin/Strings.kt index 227bd8a57..0c5b57486 100644 --- a/buildSrc/src/main/kotlin/Strings.kt +++ b/buildSrc/src/main/kotlin/Strings.kt @@ -26,7 +26,7 @@ /** * This file provides extensions to `String` and `CharSequence` that wrap - * analogues from standard Kotlin runtime. + * analogues from the standard Kotlin runtime. * * It helps in switching between versions of Gradle that have different versions of * the Kotlin runtime. Please see the bodies of the extension functions for details on diff --git a/buildSrc/src/main/kotlin/config-tester.gradle.kts b/buildSrc/src/main/kotlin/config-tester.gradle.kts index 2463f738b..79eabac7a 100644 --- a/buildSrc/src/main/kotlin/config-tester.gradle.kts +++ b/buildSrc/src/main/kotlin/config-tester.gradle.kts @@ -37,7 +37,7 @@ val config: Path = Paths.get("./") // A temp folder to use to check out the sources of other repositories with the `ConfigTester`. val tempFolder = File("./tmp") -// Creates a Gradle task which checks out and builds the selected Spine repositories +// 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) .addRepo(SpineRepos.baseTypes) // Builds `base-types` at `master`. diff --git a/buildSrc/src/main/kotlin/detekt-code-analysis.gradle.kts b/buildSrc/src/main/kotlin/detekt-code-analysis.gradle.kts index bbb53af99..15af8442e 100644 --- a/buildSrc/src/main/kotlin/detekt-code-analysis.gradle.kts +++ b/buildSrc/src/main/kotlin/detekt-code-analysis.gradle.kts @@ -29,9 +29,9 @@ import io.gitlab.arturbosch.detekt.Detekt /** * This script-plugin sets up Kotlin code analyzing with Detekt. * - * After applying, Detekt is configured to use `${rootDir}/buildSrc/quality/detekt-config.yml` file. + * After applying, Detekt is configured to use the `${rootDir}/buildSrc/quality/detekt-config.yml` file. * Projects can append their own config files to override some parts of the default one or drop - * it at all in a favor of their own one. + * it at all in favor of their own one. * * An example of appending a custom config file to the default one: * @@ -49,7 +49,7 @@ import io.gitlab.arturbosch.detekt.Detekt * } * ``` * - * Also, it's possible to suppress Detekt findings using [baseline](https://detekt.dev/docs/introduction/baseline/) + * Also, it's possible to suppress Detekt findings using a [baseline](https://detekt.dev/docs/introduction/baseline/) * file instead of suppressions in source code. * * An example of passing a baseline file: diff --git a/buildSrc/src/main/kotlin/io/spine/dependency/Dependency.kt b/buildSrc/src/main/kotlin/io/spine/dependency/Dependency.kt index 0eb1956bd..0b431c56c 100644 --- a/buildSrc/src/main/kotlin/io/spine/dependency/Dependency.kt +++ b/buildSrc/src/main/kotlin/io/spine/dependency/Dependency.kt @@ -79,7 +79,7 @@ abstract class Dependency { * Forces all artifacts of this dependency using the given resolution strategy. * * @param project The project in which the artifacts are forced. Used for logging. - * @param cfg The configuration for which the artifacts are forced. Used for logging. + * @param cfg The configuration for which the artifacts are forced. Used for logging. * @param rs The resolution strategy that forces the artifacts. */ fun forceArtifacts(project: Project, cfg: Configuration, rs: ResolutionStrategy) { 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 e60d6dea5..efe078322 100644 --- a/buildSrc/src/main/kotlin/io/spine/dependency/boms/BomsPlugin.kt +++ b/buildSrc/src/main/kotlin/io/spine/dependency/boms/BomsPlugin.kt @@ -57,7 +57,7 @@ import org.gradle.api.artifacts.ConfigurationContainer * * In addition to forcing BOM-based dependencies, * the plugin [forces][org.gradle.api.artifacts.ResolutionStrategy.force] the versions - * of [Kotlin.StdLib.artifacts] for all configurations because even through Kotlin + * of [Kotlin.StdLib.artifacts] for all configurations because even though Kotlin * artifacts are forced with BOM, the `variants` in the dependencies cannot be * picked by Gradle. * 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 eab2b8fd9..31f1e7b97 100644 --- a/buildSrc/src/main/kotlin/io/spine/dependency/kotlinx/Serialization.kt +++ b/buildSrc/src/main/kotlin/io/spine/dependency/kotlinx/Serialization.kt @@ -61,7 +61,7 @@ object Serialization { object GradlePlugin { /** - * The ID to be used with the `kotlin(shortId)` DSL under the`plugins { }` block. + * The ID to be used with the `kotlin(shortId)` DSL under the `plugins { }` block. */ const val shortId = "plugin.serialization" 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 8401d0a04..0b1958a4e 100644 --- a/buildSrc/src/main/kotlin/io/spine/dependency/lib/Asm.kt +++ b/buildSrc/src/main/kotlin/io/spine/dependency/lib/Asm.kt @@ -34,7 +34,7 @@ object Asm { const val lib = "$group:asm:$version" // We use the following artifacts only to force the versions - // of the dependencies which are transitive for us. + // of the dependencies that are transitive for us. // const val tree = "$group:asm-tree:$version" const val analysis = "$group:asm-analysis:$version" 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 c011186d5..76fcfa67e 100644 --- a/buildSrc/src/main/kotlin/io/spine/dependency/lib/Coroutines.kt +++ b/buildSrc/src/main/kotlin/io/spine/dependency/lib/Coroutines.kt @@ -29,7 +29,7 @@ package io.spine.dependency.lib /** * Kotlin Coroutines. * - * @see GitHub projecet + * @see GitHub project */ @Suppress("unused", "ConstPropertyName") @Deprecated( 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 1e347964c..1cb83e1b9 100644 --- a/buildSrc/src/main/kotlin/io/spine/dependency/lib/Protobuf.kt +++ b/buildSrc/src/main/kotlin/io/spine/dependency/lib/Protobuf.kt @@ -59,7 +59,7 @@ object Protobuf { // https://github.com/google/protobuf-gradle-plugin/releases object GradlePlugin { /** - * The version of this plugin is already specified in `buildSrc/build.gradle.kts` file. + * The version of this plugin is already specified in the `buildSrc/build.gradle.kts` file. * Thus, when applying the plugin to project build files, only the [id] should be used. * * When changing the version, also change the version used in the `build.gradle.kts`. 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 c32da5082..d08b2f517 100644 --- a/buildSrc/src/main/kotlin/io/spine/dependency/lib/Roaster.kt +++ b/buildSrc/src/main/kotlin/io/spine/dependency/lib/Roaster.kt @@ -31,7 +31,7 @@ package io.spine.dependency.lib object Roaster { /** - * This is the last version build with Java 11. + * This is the last version built with Java 11. * * Starting from the version * [2.29.0.Final](https://github.com/forge/roaster/releases/tag/2.29.0.Final), 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 356fb5882..34b15ac4e 100644 --- a/buildSrc/src/main/kotlin/io/spine/dependency/lib/Slf4J.kt +++ b/buildSrc/src/main/kotlin/io/spine/dependency/lib/Slf4J.kt @@ -27,8 +27,8 @@ package io.spine.dependency.lib /** - * Spine used to log with SLF4J. Now we use Flogger. Whenever a choice comes up, we recommend to - * use the latter. + * Spine used to log with SLF4J. Now we use Flogger. Whenever a choice comes up, we recommend + * using the latter. * * The primary purpose of having this dependency object is working in combination with * [Flogger.Runtime.slf4JBackend]. 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 1f54366e3..2e2bc5adf 100644 --- a/buildSrc/src/main/kotlin/io/spine/dependency/local/Compiler.kt +++ b/buildSrc/src/main/kotlin/io/spine/dependency/local/Compiler.kt @@ -55,7 +55,7 @@ import io.spine.dependency.Dependency */ @Suppress( "unused" /* Some subprojects do not use the Compiler directly. */, - "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 Compiler : Dependency() { @@ -64,7 +64,7 @@ object Compiler : Dependency() { const val pluginId = "io.spine.compiler" /** - * Identifies the Compiler as a `classpath` dependency under `buildScript` block. + * Identifies the Compiler as a `classpath` dependency under the `buildScript` block. */ const val module = "io.spine.tools:compiler" 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 d9d23e772..d09a11b81 100644 --- a/buildSrc/src/main/kotlin/io/spine/dependency/local/ProtoTap.kt +++ b/buildSrc/src/main/kotlin/io/spine/dependency/local/ProtoTap.kt @@ -33,7 +33,7 @@ package io.spine.dependency.local */ @Suppress( "unused" /* Some subprojects do not use ProtoTap directly. */, - "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 ProtoTap { 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 e1577e83b..da8ed60f2 100644 --- a/buildSrc/src/main/kotlin/io/spine/dependency/test/AssertK.kt +++ b/buildSrc/src/main/kotlin/io/spine/dependency/test/AssertK.kt @@ -27,7 +27,7 @@ package io.spine.dependency.test /** - * Assertion library for tests in Kotlin + * Assertion library for tests in Kotlin. * * [AssertK](https://github.com/willowtreeapps/assertk) */ 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 741a520d2..25c0066be 100644 --- a/buildSrc/src/main/kotlin/io/spine/dependency/test/Kover.kt +++ b/buildSrc/src/main/kotlin/io/spine/dependency/test/Kover.kt @@ -29,7 +29,7 @@ package io.spine.dependency.test // https://github.com/Kotlin/kotlinx-kover @Suppress("unused", "ConstPropertyName") object Kover { - const val version = "0.9.8" + const val version = "0.9.9" 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/gradle/ConfigTester.kt b/buildSrc/src/main/kotlin/io/spine/gradle/ConfigTester.kt index 14e0ef8c2..c2ab0f28e 100644 --- a/buildSrc/src/main/kotlin/io/spine/gradle/ConfigTester.kt +++ b/buildSrc/src/main/kotlin/io/spine/gradle/ConfigTester.kt @@ -42,7 +42,7 @@ import org.gradle.api.tasks.TaskContainer * 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. * - * Replaces the `config` and `buildSrc` folders in the checked out repository by the local versions + * 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, * they are NOT overwritten, but rather renamed into `buildSrc-original` and `config-original` * accordingly. This allows further tracing if the build fails. @@ -87,7 +87,7 @@ class ConfigTester( } /** - * Adds a test + * Adds a test. */ fun addRepo(repo: URI, branch: Branch): ConfigTester { repos.add(GitRepository(repo, branch)) diff --git a/buildSrc/src/main/kotlin/io/spine/gradle/ProjectExtensions.kt b/buildSrc/src/main/kotlin/io/spine/gradle/ProjectExtensions.kt index afccc24b5..300d423fd 100644 --- a/buildSrc/src/main/kotlin/io/spine/gradle/ProjectExtensions.kt +++ b/buildSrc/src/main/kotlin/io/spine/gradle/ProjectExtensions.kt @@ -52,7 +52,7 @@ val Project.javaPluginExtension: JavaPluginExtension get() = extensions.getByType() /** - * Obtains source set container of the Java project. + * Obtains the source set container of the Java project. */ val Project.sourceSets: SourceSetContainer get() = javaPluginExtension.sourceSets @@ -80,7 +80,7 @@ fun Project.getTask(name: String): T { } /** - * Obtains Maven artifact ID of this [Project]. + * Obtains the Maven artifact ID of this [Project]. * * The property getter checks if [SpinePublishing] extension is configured upon this project. * If yes, it returns [SpinePublishing.artifactId] for the project. diff --git a/buildSrc/src/main/kotlin/io/spine/gradle/RunGradle.kt b/buildSrc/src/main/kotlin/io/spine/gradle/RunGradle.kt index 5d05b4493..4461ba51b 100644 --- a/buildSrc/src/main/kotlin/io/spine/gradle/RunGradle.kt +++ b/buildSrc/src/main/kotlin/io/spine/gradle/RunGradle.kt @@ -39,7 +39,7 @@ import org.gradle.internal.os.OperatingSystem * A Gradle task that runs another Gradle build. * * Launches Gradle wrapper under a given [directory] with the specified [taskNames] names. - * The `clean` task is also run if current build includes a `clean` task. + * The `clean` task is also run if the current build includes a `clean` task. * * The build writes verbose log into `$directory/build/debug-out.txt`. * The error output is written into `$directory/build/error-out.txt`. 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 587c5c209..cb5ae177c 100644 --- a/buildSrc/src/main/kotlin/io/spine/gradle/dart/DartContext.kt +++ b/buildSrc/src/main/kotlin/io/spine/gradle/dart/DartContext.kt @@ -30,13 +30,13 @@ import org.gradle.api.Project import org.gradle.api.tasks.Exec /** - * Provides access to the current [DartEnvironment] and shortcuts for running `pub` tool. + * Provides access to the current [DartEnvironment] and shortcuts for running the `pub` tool. */ open class DartContext(dartEnv: DartEnvironment, internal val project: Project) : DartEnvironment by dartEnv { /** - * Executes `pub` command in this [Exec] task. + * Executes the `pub` command in this [Exec] task. * * The Dart ecosystem uses packages to manage shared software such as libraries and tools. * To get or publish Dart packages, the `pub` package manager is to be used. 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 0e622e2cf..47b8d322b 100644 --- a/buildSrc/src/main/kotlin/io/spine/gradle/dart/DartEnvironment.kt +++ b/buildSrc/src/main/kotlin/io/spine/gradle/dart/DartEnvironment.kt @@ -116,7 +116,7 @@ interface DartEnvironment { * Before the [packageConfig], pub used to create this [packageIndex] file in the root * directory. * - * As for Dart 2.14, `pub` still updates the deprecated file for backwards compatibility. + * As for Dart 2.14, `pub` still updates the deprecated file for backwards compatibility. * * Default value: "$projectDir/.packages". */ @@ -138,8 +138,8 @@ interface DartEnvironment { * Allows overriding [DartEnvironment]'s defaults. * * Please note, not all properties of the environment can be overridden. Properties that describe - * `pub` tool's input/output files can NOT be overridden because `pub` itself doesn't allow to - * specify them for its execution. + * the `pub` tool's input/output files can NOT be overridden because `pub` itself doesn't allow + * specifying them for its execution. * * The next properties could not be overridden: * 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 002531d9b..4f89d3469 100644 --- a/buildSrc/src/main/kotlin/io/spine/gradle/dart/DartExtension.kt +++ b/buildSrc/src/main/kotlin/io/spine/gradle/dart/DartExtension.kt @@ -82,7 +82,7 @@ import org.gradle.kotlin.dsl.findByType * } * ``` * - * Please note, environment should be set up firstly to have the effect on the parts + * Please note, the environment should be set up firstly to have the effect on the parts * of the extension that use it. * * ### Tasks and Plugins @@ -93,7 +93,7 @@ import org.gradle.kotlin.dsl.findByType * Then this extension is called in a project's `build.gradle.kts`. * * `DartTasks` and `DartPlugins` scopes extend [DartContext] that provides access - * to the current [DartEnvironment] and shortcuts for running `pub` tool. + * to the current [DartEnvironment] and shortcuts for running the `pub` tool. * * Below is the simplest example of how to create a primitive `printPubVersion` task. * @@ -169,7 +169,7 @@ open class DartExtension(project: Project) { /** * Overrides default values of [DartEnvironment]. * - * Please note, environment should be set up firstly to have the effect on the parts + * Please note, the environment should be set up firstly to have the effect on the parts * of the extension that use it. */ fun environment(overridings: ConfigurableDartEnvironment.() -> Unit) = 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 1f6e1f0ca..cbe423285 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 @@ -42,12 +42,12 @@ import org.gradle.api.tasks.TaskContainer * 2. [extensions]. * 3. [tasks]. * - * Let's imagine one wants to apply and configure `FooBar` plugin. To do that, several steps + * Let's imagine one wants to apply and configure the `FooBar` plugin. To do that, several steps * should be completed: * * 1. Declare the corresponding extension function upon [DartContext] named after the plugin. * 2. Apply and configure the plugin inside that function. - * 3. Call the resulted extension in your `build.gradle.kts` file. + * 3. Call the resulting extension in your `build.gradle.kts` file. * * Here's an example of `dart/plugin/FooBar.kt`: * 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 55aee20de..568f1f907 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 @@ -32,7 +32,7 @@ import com.google.protobuf.gradle.remove import io.spine.dependency.lib.Protobuf /** - * Applies `protobuf` plugin and configures `GenerateProtoTask` to work with a Dart module. + * Applies the `protobuf` plugin and configures `GenerateProtoTask` to work with a Dart module. * * @see DartPlugins */ 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 3f1ca120c..939963b44 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 @@ -88,9 +88,9 @@ fun DartTasks.build(configuration: DartTasks.() -> Unit = {}) { private val resolveDependenciesName = TaskName.of("resolveDependencies", Exec::class) /** - * Locates `resolveDependencies` task in this [TaskContainer]. + * Locates the `resolveDependencies` task in this [TaskContainer]. * - * The task fetches dependencies declared via `pubspec.yaml` using `pub get` command. + * The task fetches dependencies declared via `pubspec.yaml` using the `pub get` command. */ val TaskContainer.resolveDependencies: TaskProvider get() = named(resolveDependenciesName) @@ -112,12 +112,12 @@ private fun DartTasks.resolveDependencies(): TaskProvider = private val cleanPackageIndexName = TaskName.of("cleanPackageIndex", Delete::class) /** - * Locates `cleanPackageIndex` task in this [TaskContainer]. + * Locates the `cleanPackageIndex` task in this [TaskContainer]. * * The task deletes the resolved module dependencies' index. * - * The standard configuration file that contains index is `package_config.json`. For backwards - * compatability `pub` still updates the deprecated `.packages` file. The task deletes both files. + * The standard configuration file that contains the index is `package_config.json`. For backwards + * compatibility `pub` still updates the deprecated `.packages` file. The task deletes both files. */ val TaskContainer.cleanPackageIndex: TaskProvider get() = named(cleanPackageIndexName) @@ -137,7 +137,7 @@ private fun DartTasks.cleanPackageIndex(): TaskProvider = private val testDartName = TaskName.of("testDart", Exec::class) /** - * Locates `testDart` task in this [TaskContainer]. + * Locates the `testDart` task in this [TaskContainer]. * * The task runs Dart tests declared in the `./test` directory. */ 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 65f94e230..1cea9d455 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 @@ -47,7 +47,7 @@ import org.gradle.api.tasks.TaskContainer * referencing to the new task, so that external tasks could depend on it. This reference * should be documented. * 3. Implement an extension upon [DartTasks] to register the task. - * 4. Call the resulted extension from `build.gradle.kts`. + * 4. Call the resulting extension from `build.gradle.kts`. * * Here's an example of `testDart()` extension: * 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 21aa28b65..7c2755872 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 @@ -37,11 +37,11 @@ import org.gradle.api.tasks.TaskProvider private val integrationTestName = TaskName.of("integrationTest", Exec::class) /** - * Locates `integrationTest` task in this [TaskContainer]. + * Locates the `integrationTest` task in this [TaskContainer]. * * The task runs integration tests of the `spine-dart` library against a sample - * Spine-based application. The tests are run in Chrome browser because they use `WebFirebaseClient` - * that only works in web environment. + * Spine-based application. The tests are run in the Chrome browser because they use `WebFirebaseClient` + * that only works in a web environment. * * A sample Spine-based application is run from the `test-app` module before integration * tests start and is stopped as the tests complete. @@ -50,7 +50,7 @@ val TaskContainer.integrationTest: TaskProvider get() = named(integrationTestName) /** - * Registers [TaskContainer.integrationTest] task. + * Registers the [TaskContainer.integrationTest] task. * * Please note, this task depends on [build] tasks. Therefore, building tasks should be applied in * the first place. 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 c1d72c023..0b3344380 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 @@ -97,7 +97,7 @@ private fun DartTasks.stagePubPublication(): TaskProvider = dependsOn(assemble) - // Beside `.dart` sources itself, `pub` package manager conventions require: + // Besides `.dart` sources itself, `pub` package manager conventions require: // 1. README.md and CHANGELOG.md to build a page at `pub.dev/packages/;`. // 2. `pubspec` file to fill out details about your package on the right side of your // package’s page. @@ -118,9 +118,9 @@ private fun DartTasks.stagePubPublication(): TaskProvider = private val publishToPubName = TaskName.of("publishToPub", Exec::class) /** - * Locates `publishToPub` task in this [TaskContainer]. + * Locates the `publishToPub` task in this [TaskContainer]. * - * The task publishes the prepared publication to Pub using `pub publish` command. + * The task publishes the prepared publication to Pub using the `pub publish` command. */ val TaskContainer.publishToPub: TaskProvider get() = named(publishToPubName) @@ -144,7 +144,7 @@ private fun DartTasks.publishToPub(): TaskProvider = private val activateLocallyName = TaskName.of("activateLocally", Exec::class) /** - * Locates `activateLocally` task in this [TaskContainer]. + * Locates the `activateLocally` task in this [TaskContainer]. * * Makes this package available in the command line as an executable. * 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 8ce4d72a5..4751ac146 100644 --- a/buildSrc/src/main/kotlin/io/spine/gradle/git/Repository.kt +++ b/buildSrc/src/main/kotlin/io/spine/gradle/git/Repository.kt @@ -35,15 +35,15 @@ import org.gradle.api.Project /** * Interacts with a real Git repository. * - * Clones the repository with the provided SSH URL in a temporal folder. Provides - * functionality to configure a user, checkout branches, commit changes and push them + * Clones the repository with the provided SSH URL in a temporary folder. Provides + * functionality to configure a user, check out branches, commit changes and push them * to the remote repository. * * It is assumed that before using this class an appropriate SSH key that has * sufficient rights to perform described above operations was registered * in `ssh-agent`. * - * NOTE: This class creates a temporal folder, so it holds resources. For the proper + * NOTE: This class creates a temporary folder, so it holds resources. For the proper * release of resources please use the provided functionality inside a `use` block or * call the `close` method manually. * @@ -62,12 +62,12 @@ class Repository private constructor( ) : AutoCloseable { /** - * Path to the temporal folder for a clone of the underlying repository. + * Path to the temporary folder for a clone of the underlying repository. */ val location = LazyTempPath("repoTemp") /** - * Clones the repository with [the SSH url][sshUrl] into the [temporal folder][location]. + * Clones the repository with [the SSH url][sshUrl] into the [temporary folder][location]. */ private fun clone() { repoExecute("git", "clone", sshUrl, ".") @@ -132,7 +132,7 @@ class Repository private constructor( /** * Tells whether the remote repository has a branch with the given [name]. * - * Queries the fully-qualified ref `refs/heads/$name` rather than the bare + * Queries the fully qualified ref `refs/heads/$name` rather than the bare * [name]: `git ls-remote` treats a bare name as a tail glob and would also * match a namespaced branch such as `feature/$name`. Relies on `git ls-remote` * returning an empty output with a zero exit code when the branch is absent, @@ -256,7 +256,7 @@ class Repository private constructor( companion object Factory { /** - * Clones the repository with the provided SSH URL in a temporal folder. + * Clones the repository with the provided SSH URL in a temporary folder. * * Configures the username and the email of the Git user. * See [configureUser] documentation for more information. @@ -290,7 +290,7 @@ class Repository private constructor( } /** - * Executes a given operation with retries using exponential backoff strategy. + * Executes a given operation with retries using an exponential backoff strategy. * * If the operation fails, it will be retried up to the specified number of times * with increasing delays between attempts. 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 0382e8364..0214b503b 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 @@ -113,7 +113,7 @@ class UpdateGitHubPages : Plugin { } /** - * Registers `updateGitHubPages` task that performs no actual update, but prints + * Registers the `updateGitHubPages` task that performs no actual update, but prints * the message telling the update is skipped, since the project is in * its `SNAPSHOT` version. */ 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 b2737f20c..568e121f7 100644 --- a/buildSrc/src/main/kotlin/io/spine/gradle/java/Tasks.kt +++ b/buildSrc/src/main/kotlin/io/spine/gradle/java/Tasks.kt @@ -32,7 +32,7 @@ import org.gradle.api.tasks.testing.Test import org.gradle.kotlin.dsl.named /** - * Locates `test` task in this [TaskContainer]. + * Locates the `test` task in this [TaskContainer]. * * Runs the unit tests using JUnit or TestNG. * 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 2fbceed45..8221c7296 100644 --- a/buildSrc/src/main/kotlin/io/spine/gradle/javac/ErrorProne.kt +++ b/buildSrc/src/main/kotlin/io/spine/gradle/javac/ErrorProne.kt @@ -63,7 +63,7 @@ fun JavaCompile.configureErrorProne() { private object ErrorProneConfig { /** - * Command line options for the `Error Prone` compiler. + * Command-line options for the `Error Prone` compiler. */ val ARGUMENTS = CommandLineArgumentProvider { listOf( 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 0732edc8c..b3dce4944 100644 --- a/buildSrc/src/main/kotlin/io/spine/gradle/javadoc/ExcludeInternalDoclet.kt +++ b/buildSrc/src/main/kotlin/io/spine/gradle/javadoc/ExcludeInternalDoclet.kt @@ -52,7 +52,7 @@ class ExcludeInternalDoclet { private const val configurationName = "excludeInternalDoclet" /** - * The fully-qualified class name of the doclet. + * The fully qualified class name of the doclet. */ const val className = "io.spine.tools.javadoc.ExcludeInternalDoclet" 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 21940fe64..df80e8f50 100644 --- a/buildSrc/src/main/kotlin/io/spine/gradle/javadoc/JavadocConfig.kt +++ b/buildSrc/src/main/kotlin/io/spine/gradle/javadoc/JavadocConfig.kt @@ -48,7 +48,7 @@ fun TaskContainer.javadocTask() = this.getByName("javadoc") as Javadoc /** * Javadoc processing settings. * - * This type is named with `Config` suffix to avoid its confusion with the standard `Javadoc` type. + * This type is named with the `Config` suffix to avoid its confusion with the standard `Javadoc` type. */ @Suppress("unused") object JavadocConfig { @@ -90,21 +90,21 @@ object JavadocConfig { * This fixes navigation to classes through the search results. * * The issue appeared after migration to Java 11. When Javadoc is generated for a project - * that does not declare Java 9 modules, search results contain broken links with appended + * that does not declare Java 9 modules, search results contain broken links with an appended * `undefined` prefix to the URL. This `undefined` was meant to be a name of a Java 9 module. * * See: [Issue #334](https://github.com/SpineEventEngine/config/issues/334) */ private fun discardJavaModulesInLinks(javadoc: Javadoc) { - // We ask `Javadoc` task to modify "search.js" and override a method, responsible for + // We ask the `Javadoc` task to modify "search.js" and override a method, responsible for // the formation of URL prefixes. We can't specify the option "--no-module-directories", // because it leads to discarding of all module prefixes in generated links. // That means links to the types from the standard library would not work, // as they are declared within modules since Java 9. val discardModulePrefix = """ - + getURLPrefix = function(ui) { return ""; }; @@ -125,7 +125,7 @@ object JavadocConfig { } /** - * Configures `javadoc` tool to avoid numerous warnings for missing `@param` tags. + * Configures the `javadoc` tool to avoid numerous warnings for missing `@param` tags. * * As suggested by Stephen Colebourne: * [https://blog.joda.org/2014/02/turning-off-doclint-in-jdk-8-javadoc.html] 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 bd1dc0532..8008ea65d 100644 --- a/buildSrc/src/main/kotlin/io/spine/gradle/javascript/JsContext.kt +++ b/buildSrc/src/main/kotlin/io/spine/gradle/javascript/JsContext.kt @@ -32,20 +32,20 @@ import org.gradle.kotlin.dsl.support.serviceOf import org.gradle.process.ExecOperations /** - * Provides access to the current [JsEnvironment] and shortcuts for running `npm` tool. + * Provides access to the current [JsEnvironment] and shortcuts for running the `npm` tool. */ open class JsContext(jsEnv: JsEnvironment, internal val project: Project) : JsEnvironment by jsEnv { /** - * Executes `npm` command in a separate process. + * Executes the `npm` command in a separate process. * * [JsEnvironment.projectDir] is used as a working directory. */ fun npm(vararg args: String) = projectDir.npm(*args) /** - * Executes `npm` command in a separate process. + * Executes the `npm` command in a separate process. * * This [File] is used as a working directory. */ 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 7a649a899..fdbd3e63b 100644 --- a/buildSrc/src/main/kotlin/io/spine/gradle/javascript/JsEnvironment.kt +++ b/buildSrc/src/main/kotlin/io/spine/gradle/javascript/JsEnvironment.kt @@ -107,8 +107,8 @@ interface JsEnvironment { * During installation a token is required only if dependencies from private * repositories are used. * - * Default value is read from the environmental variable - `NPM_TOKEN`. - * "PUBLISHING_FORBIDDEN" stub value would be assigned in case `NPM_TOKEN` variable is not set. + * Default value is read from the environment variable - `NPM_TOKEN`. + * "PUBLISHING_FORBIDDEN" stub value would be assigned in case the `NPM_TOKEN` variable is not set. * * See [Creating and viewing access tokens | npm Docs](https://docs.npmjs.com/creating-and-viewing-access-tokens). */ @@ -143,7 +143,7 @@ interface JsEnvironment { get() = projectDir.resolve(".npmrc") /** - * A cache directory in which `nyc` tool outputs raw coverage report. + * A cache directory in which the `nyc` tool outputs a raw coverage report. * * Default value: "$projectDir/.nyc_output". * @@ -202,12 +202,12 @@ interface JsEnvironment { /** * Allows overriding [JsEnvironment]'s defaults. * - * All of declared properties can be split into two groups: + * All of the declared properties can be split into two groups: * * 1. The ones that *define* something - can be overridden. * 2. The ones that *describe* something - can NOT be overridden. * - * Overriding a "defining" property affects the way `npm` tool works. + * Overriding a "defining" property affects the way the `npm` tool works. * In contrary, overriding a "describing" property does not affect the tool. * Such properties just describe how the used tool works. * 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 a849c7609..9231d902c 100644 --- a/buildSrc/src/main/kotlin/io/spine/gradle/javascript/JsExtension.kt +++ b/buildSrc/src/main/kotlin/io/spine/gradle/javascript/JsExtension.kt @@ -35,7 +35,7 @@ import org.gradle.kotlin.dsl.findByType /** * Configures [JsExtension] that facilitates configuration of Gradle tasks and plugins - * to build JavaScripts projects. + * to build JavaScript projects. * * The whole structure of the extension looks as follows: * @@ -83,7 +83,7 @@ import org.gradle.kotlin.dsl.findByType * } * ``` * - * Please note, environment should be set up firstly to have the effect on the parts + * Please note, the environment should be set up firstly to have the effect on the parts * of the extension that use it. * * ### Tasks and Plugins @@ -94,7 +94,7 @@ import org.gradle.kotlin.dsl.findByType * Then this extension is called in a project's `build.gradle.kts`. * * `JsTasks` and `JsPlugins` scopes extend [JsContext] that provides access - * to the current [JsEnvironment] and shortcuts for running `npm` tool. + * to the current [JsEnvironment] and shortcuts for running the `npm` tool. * * Below is the simplest example of how to create a primitive `printNpmVersion` task. * @@ -173,7 +173,7 @@ open class JsExtension(internal val project: Project) { /** * Overrides default values of [JsEnvironment]. * - * Please note, environment should be set up firstly to have the effect on the parts + * Please note, the environment should be set up firstly to have the effect on the parts * of the extension that use it. */ fun environment(overridings: ConfigurableJsEnvironment.() -> Unit) = 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 8a7782bb4..4219e5adf 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 @@ -30,7 +30,7 @@ import org.gradle.kotlin.dsl.configure import org.gradle.plugins.ide.idea.model.IdeaModel /** - * Applies and configures `idea` plugin to work with a JavaScript module. + * Applies and configures the `idea` plugin to work with a JavaScript module. * * In particular, this method: * 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 e9295b726..0b636ac53 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 @@ -42,12 +42,12 @@ import org.gradle.api.tasks.TaskContainer * 2. [extensions]. * 3. [tasks]. * - * Let's imagine one wants to apply and configure `FooBar` plugin. To do that, several steps + * Let's imagine one wants to apply and configure the `FooBar` plugin. To do that, several steps * should be completed: * * 1. Declare the corresponding extension function upon [JsPlugins] named after the plugin. * 2. Apply and configure the plugin inside that function. - * 3. Call the resulted extension in your `build.gradle.kts` file. + * 3. Call the resulting extension in your `build.gradle.kts` file. * * Here's an example of `javascript/plugin/FooBar.kt`: * 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 271cbd457..b2a46ba8a 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 @@ -32,7 +32,7 @@ import org.gradle.api.tasks.TaskProvider import org.gradle.kotlin.dsl.withGroovyBuilder /** - * Applies `mc-js` plugin and specifies directories for generated code. + * Applies the `mc-js` plugin and specifies directories for generated code. * * @see JsPlugins */ 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 92610e5a6..98b926314 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 @@ -32,11 +32,11 @@ import com.google.protobuf.gradle.remove import io.spine.dependency.lib.Protobuf /** - * Applies and configures `protobuf` plugin to work with a JavaScript module. + * Applies and configures the `protobuf` plugin to work with a JavaScript module. * * In particular, this method: * - * 1. Specifies an executable for `protoc` compiler. + * 1. Specifies an executable for the `protoc` compiler. * 2. Configures `GenerateProtoTask`. * * @see JsPlugins 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 2db59a4f5..475668c05 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 @@ -105,7 +105,7 @@ private val linkSpineWebModuleName = TaskName.of("linkSpineWebModule") /** * Locates `linkSpineWebModule` task in this [TaskContainer]. * - * The task installs unpublished artifact of `spine-web` library as a module dependency. + * The task installs an unpublished artifact of the `spine-web` library as a module dependency. * * Creates a symbolic link from globally-installed `spine-web` library to `node_modules` of * the current project. 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 c12650141..c07e7ba8a 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 @@ -172,7 +172,7 @@ private val publishJsName = TaskName.of("publishJs") * [publicationDirectory][io.spine.gradle.javascript.JsEnvironment.publicationDir] * using `npm publish`. * - * Please note, in order to publish an NMP package, a valid + * Please note, in order to publish an NPM package, a valid * [npmAuthToken][io.spine.gradle.javascript.JsEnvironment.npmAuthToken] should be * set. If no token is set, a default dummy value is quite enough for the local development. * 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 2e7f4cfa4..f6fa12fd4 100644 --- a/buildSrc/src/main/kotlin/io/spine/gradle/publish/CloudArtifactRegistry.kt +++ b/buildSrc/src/main/kotlin/io/spine/gradle/publish/CloudArtifactRegistry.kt @@ -37,7 +37,7 @@ import org.gradle.api.Project * The experimental Google Cloud Artifact Registry repository. * * In order to successfully publish into this repository, a service account key is needed. - * The published must create a service account, grant it the permission to write into + * The publisher must create a service account, grant it the permission to write into * Artifact Registry, and generate a JSON key. * Then, the key must be placed somewhere on the file system and the environment variable * `GOOGLE_APPLICATION_CREDENTIALS` must be set to point at the key file. @@ -47,7 +47,7 @@ import org.gradle.api.Project * automatically. We achieve the same goal by assembling the credentials manually. We do so * in order to fit the Google Cloud Artifact Registry repository into the standard frame of * the Maven [Repository]-s. Applying the plugin would take a substantial effort due to the fact - * that both our publishing scripts and the Google's plugin use `afterEvaluate { }` hooks. + * that both our publishing scripts and Google's plugin use `afterEvaluate { }` hooks. * Ordering said hooks is a non-trivial operation and the result is usually quite fragile. * Thus, we choose to do this small piece of configuration manually. */ 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 c9fbdd651..0d5292513 100644 --- a/buildSrc/src/main/kotlin/io/spine/gradle/publish/PublicationHandler.kt +++ b/buildSrc/src/main/kotlin/io/spine/gradle/publish/PublicationHandler.kt @@ -144,7 +144,7 @@ sealed class PublicationHandler( * 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] + * under which the published artifact is distributed via [LicenseSettings]. * * The source control management attributes are obtained from [DocumentationSettings]. * 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 974542c3f..279a68a01 100644 --- a/buildSrc/src/main/kotlin/io/spine/gradle/publish/PublishingExts.kt +++ b/buildSrc/src/main/kotlin/io/spine/gradle/publish/PublishingExts.kt @@ -124,7 +124,7 @@ internal val TaskContainer.publish: TaskProvider * 1. When this [Project] is not a root, makes `publish` task in a root project * depend on a local `publish`. * 2. Makes local `publish` task verify that credentials are present for each - * of destination repositories. + * of the destination repositories. */ internal fun Project.configurePublishTask(destinations: Set) { attachCredentialsVerification(destinations) @@ -163,7 +163,7 @@ private fun TaskContainer.getOrCreatePublishTask(): TaskProvider = @Suppress( /* Several types of exceptions may be thrown, - and Kotlin does not have a multi-catch support yet. */ + and Kotlin does not have multi-catch support yet. */ "TooGenericExceptionCaught" ) private fun TaskContainer.registerCheckCredentialsTask( 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 bb412ed63..2d778a8d7 100644 --- a/buildSrc/src/main/kotlin/io/spine/gradle/publish/SpinePublishing.kt +++ b/buildSrc/src/main/kotlin/io/spine/gradle/publish/SpinePublishing.kt @@ -120,7 +120,7 @@ import org.gradle.kotlin.dsl.findByType * `spinePublishing` extension within `subprojectA` itself would lead to an exception. * * In Gradle, in order to publish something somewhere, one should create a publication. In each - * of published modules, the extension will create a [publication][StandardJavaPublicationHandler] + * of the published modules, the extension will create a [publication][StandardJavaPublicationHandler] * named "mavenJava". All artifacts published by this extension belong to this publication. * * ## Published artifacts @@ -365,7 +365,7 @@ open class SpinePublishing(private val project: Project) { * * Firstly, an instance of [PublicationHandler] is created for the project depending * on the nature of the publication process configured. - * Then, this the handler is scheduled to apply on [Project.afterEvaluate]. + * Then, the handler is scheduled to apply on [Project.afterEvaluate]. * * General rule of thumb is to avoid using [Project.afterEvaluate] of this closure, * as it configures a project when its configuration is considered completed. @@ -379,7 +379,7 @@ open class SpinePublishing(private val project: Project) { * Let's suppose they are declared in a module's build file. It is a common practice. * But publishing of the module is configured from a root project's build file. * By the time when we need to specify them, we just don't know them. - * As the result, we have to use [Project.afterEvaluate] in order to guarantee that + * As a result, we have to use [Project.afterEvaluate] in order to guarantee that * the module will be configured by the time we configure publishing for it. */ private fun Project.setUpPublishing(jarFlags: JarFlags) { @@ -401,7 +401,7 @@ open class SpinePublishing(private val project: Project) { * If there is a local instance of [io.spine.gradle.publish.SpinePublishing] extension, * the [destinations] are obtained from this instance. * Otherwise, the function attempts to obtain it from a [parent project][Project.getParent]. - * If there is no a parent project, an empty set is returned. + * If there is no parent project, an empty set is returned. * * The normal execution should end up at the root project of a multi-module project * if there are no custom destinations specified by the local extension. 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 17fa0e707..178bf72ef 100644 --- a/buildSrc/src/main/kotlin/io/spine/gradle/publish/StandardJavaPublicationHandler.kt +++ b/buildSrc/src/main/kotlin/io/spine/gradle/publish/StandardJavaPublicationHandler.kt @@ -102,7 +102,7 @@ class StandardJavaPublicationHandler private constructor( * 3. Gradle's metadata file that has the ".module" extension. * * Metadata files contain information about a publication itself, its artifacts, and their - * dependencies. Presence of ".pom" file is mandatory for publication to be consumed by + * dependencies. The presence of ".pom" file is mandatory for publication to be consumed by * `mvn` build tool itself or other build tools that understand Maven notation (Gradle, Ivy). * The presence of ".module" is optional, but useful when a publication is consumed by Gradle. * 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 9a6a4d6b1..23fd62a27 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 @@ -33,7 +33,7 @@ import org.gradle.api.tasks.TaskProvider /** * Locates `generateLicenseReport` in this [TaskContainer]. * - * The task generates a license report for a specific Gradle project. License report includes + * The task generates a license report for a specific Gradle project. The license report includes * information of all dependencies and their licenses. */ val TaskContainer.generateLicenseReport: TaskProvider 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 66cf3b71c..080f80660 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 @@ -39,7 +39,7 @@ enum class DependencyScope { system /** - `import` is also a scope, however, it can't be used outside the `` - section, which is outside of the scope of this script + `import` is also a scope; however, it can't be used outside the `` + section, which is outside of the scope of this script. **/ } 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 5421bfc81..7d03a59de 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 @@ -73,7 +73,7 @@ internal constructor( /** * Obtains a string that contains project dependencies as XML. * - *

Obtained string also contains a closing project tag. + *

The obtained string also contains a closing project tag. */ private fun projectDependencies(): String { val destination = StringWriter() 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 66e3400e2..a72434a05 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 @@ -72,30 +72,20 @@ internal constructor( * * The required information is first retrieved from the project. * And if a property is missing from the `project`, it is taken from the `extra` extension - * of project's root project. + * of the project's root project. */ internal fun Project.metadata(): ProjectMetadata { - val groupId: String by nonEmptyValue(group) - val artifactId: String by nonEmptyValue(name) - val version: String by project.nonEmptyValue(this.version) + val groupId = nonEmptyValue(group, "groupId") + val artifactId = nonEmptyValue(name, "artifactId") + val version = nonEmptyValue(this.version, "version") return ProjectMetadata(project, groupId, artifactId, version) } -private fun Project.nonEmptyValue(prop: Any): NonEmptyValue { - return NonEmptyValue(prop.toString(), this) -} - -private class NonEmptyValue( - private val defaultValue: String, - private val project: Project -) { - - @Suppress("UNCHECKED_CAST") - operator fun getValue(receiver: Any?, property: KProperty<*>): T { - if (defaultValue.isNotEmpty()) { - return defaultValue as T - } - val result = project.rootProject.extra[property.name] - return result as T - } -} +/** + * Obtains the string form of the given [value]. + * + * If that form is empty, falls back to the property named [key] in the `extra` + * properties of the root project, failing if it is absent or not a `String`. + */ +private fun Project.nonEmptyValue(value: Any, key: String): String = + value.toString().ifEmpty { rootProject.extra[key] as String } 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 130f8f3a2..6509a582c 100644 --- a/buildSrc/src/main/kotlin/io/spine/gradle/testing/Multiproject.kt +++ b/buildSrc/src/main/kotlin/io/spine/gradle/testing/Multiproject.kt @@ -33,7 +33,7 @@ import org.gradle.api.Project * Exposes the test classes of this project as a new "testArtifacts" configuration. * * This allows other projects to depend on the test classes from this project within a Gradle - * multi-project build. It is helpful in case the dependant projects re-use abstract test suites + * multi-project build. It is helpful in case the dependent projects re-use abstract test suites * of some "parent" project. * * Please note that this utility requires Gradle `java` plugin to be applied. Hence, it is diff --git a/buildSrc/src/main/kotlin/kmp-module.gradle.kts b/buildSrc/src/main/kotlin/kmp-module.gradle.kts index 4db37f108..0dfb233e5 100644 --- a/buildSrc/src/main/kotlin/kmp-module.gradle.kts +++ b/buildSrc/src/main/kotlin/kmp-module.gradle.kts @@ -107,9 +107,8 @@ fun Project.forceConfigurations() { * * Please note, this extension DOES NOT configure Kotlin for JVM. * It configures KMP, in which Kotlin for JVM is only one of - * possible targets. + * the possible targets. */ -@Suppress("UNUSED_VARIABLE") // Avoid warnings for source set vars. kotlin { // Enables explicit API mode for any Kotlin sources within the module. explicitApi() @@ -183,7 +182,7 @@ tasks { /** * Overrides the default location of Kotlin sources. * - * The default configuration of Detekt assumes presence of Kotlin sources + * The default configuration of Detekt assumes the presence of Kotlin sources * in `src/main/kotlin`, which is not the case for KMP. */ detekt { diff --git a/buildSrc/src/main/kotlin/module-testing.gradle.kts b/buildSrc/src/main/kotlin/module-testing.gradle.kts index 20b68e07f..5b839ebb0 100644 --- a/buildSrc/src/main/kotlin/module-testing.gradle.kts +++ b/buildSrc/src/main/kotlin/module-testing.gradle.kts @@ -79,7 +79,7 @@ private fun DependencyHandlerScope.forceJunitPlatform() { typealias Module = Project /** - * Configure this module to run JUnit-based tests. + * Configures this module to run JUnit-based tests. */ fun Module.setupTests() { tasks { diff --git a/buildSrc/src/main/kotlin/module.gradle.kts b/buildSrc/src/main/kotlin/module.gradle.kts index d8c2a11fb..75392b0af 100644 --- a/buildSrc/src/main/kotlin/module.gradle.kts +++ b/buildSrc/src/main/kotlin/module.gradle.kts @@ -24,7 +24,7 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -// This is a template file for an actual script which should be +// This is a template file for an actual script that should be // defined by a project to which `config` is applied. // // The reason for having this file is that it is referenced as diff --git a/buildSrc/src/main/kotlin/uber-jar-module.gradle.kts b/buildSrc/src/main/kotlin/uber-jar-module.gradle.kts index e59e30ef8..f91b3b987 100644 --- a/buildSrc/src/main/kotlin/uber-jar-module.gradle.kts +++ b/buildSrc/src/main/kotlin/uber-jar-module.gradle.kts @@ -53,7 +53,7 @@ spinePublishing { customPublishing = true } -/** The ID of the far JAR artifact. */ +/** The ID of the fat JAR artifact. */ private val projectArtifact = project.name.replace(":", "") publishing { @@ -70,8 +70,10 @@ publishing { } } -// Declare dependency explicitly to address the Gradle error. -tasks.getByName("publishFatJarPublicationToMavenLocal") { +/** + * Declare dependency explicitly to address the Gradle error. + */ +tasks.named("publishFatJarPublicationToMavenLocal") { dependsOn(tasks.shadowJar) } diff --git a/buildSrc/src/main/kotlin/write-manifest.gradle.kts b/buildSrc/src/main/kotlin/write-manifest.gradle.kts index 2c49daa7c..4656ff420 100644 --- a/buildSrc/src/main/kotlin/write-manifest.gradle.kts +++ b/buildSrc/src/main/kotlin/write-manifest.gradle.kts @@ -81,7 +81,7 @@ val buildTimestampAttr = "Build-Timestamp" /** * The attributes we put into the JAR manifest. * - * This map is shared between the [exposeManifestForTests] task and the action which + * This map is shared between the [exposeManifestForTests] task and the action that * customizes the [Jar] task below. */ val manifestAttributes = mapOf( @@ -99,7 +99,7 @@ val manifestAttributes = mapOf( /** * Creates a manifest file in `resources` so that it is available for the tests. * - * This task does the same what does the block which configures the `tasks.jar` below. + * This task does the same as the block that configures the `tasks.jar` below. * We cannot use the manifest file created by the `Jar` task because it's not visible * when running tests. We cannot depend on the `Jar` from `resources` because it would * form a circular dependency. diff --git a/migrate b/migrate index b395ef5a5..750f5fc62 100644 --- a/migrate +++ b/migrate @@ -411,6 +411,27 @@ if git rev-parse --is-inside-work-tree >/dev/null 2>&1 \ fi if [ "$IS_JVM" = "true" ]; then + # Remove stale root-level dependency reports. The `pom.xml` and + # `dependencies.md` dependency reports are now generated under + # `docs/dependencies` (see `PomGenerator` and `LicenseReporter` in + # `buildSrc`); the legacy copies left at the repository root are stale + # duplicates that the Codex and Copilot CI reviewers flag on every pull + # request. In a Gradle repo a root `pom.xml` is only ever this generated + # report (never a real Maven build file), so deleting it is safe. `git rm` + # stages the deletion when the file is tracked — the usual case, since the + # reports were committed — so the pull's own commit carries the removal; an + # untracked working-tree artifact falls back to `rm -f`. Both guards make a + # re-run a quiet no-op once the files are gone. + for stale_report in pom.xml dependencies.md; do + if git ls-files --error-unmatch "$stale_report" >/dev/null 2>&1; then + echo "Removing stale root dependency report '$stale_report' (now under docs/dependencies)" + git rm --force --quiet "$stale_report" + elif [ -f "$stale_report" ]; then + echo "Removing stale root dependency report '$stale_report' (now under docs/dependencies)" + rm -f "$stale_report" + fi + done + echo "Adding \`buildSrc\` sources to Git..." git add ./buildSrc/src fi diff --git a/scripts/JSpecify-migration.kts b/scripts/JSpecify-migration.kts index 03c6673c4..76357d1e2 100644 --- a/scripts/JSpecify-migration.kts +++ b/scripts/JSpecify-migration.kts @@ -32,7 +32,7 @@ private data class ClassName(val qualifiedName: String) { } /** - * Creates a replacement API migration instruction + * Creates a replacement API migration instruction. */ private fun MutableMap.migrate( oldClass: String, diff --git a/scripts/buildSrc-migration.kts b/scripts/buildSrc-migration.kts index ea6bd65a6..d21600d68 100644 --- a/scripts/buildSrc-migration.kts +++ b/scripts/buildSrc-migration.kts @@ -27,7 +27,7 @@ import java.io.File /** - * Creates a pair of old dependency name and a new one. + * Creates a pair of an old dependency name and a new one. */ private fun MutableMap.mv( oldPackage: String, diff --git a/scripts/publish-documentation/README.md b/scripts/publish-documentation/README.md index b2f4f09b1..d5fcd1bab 100644 --- a/scripts/publish-documentation/README.md +++ b/scripts/publish-documentation/README.md @@ -24,7 +24,7 @@ the target repository. [`dokka-for-java.gradle.kts`][dokka-for-java] script. -- The script modifies the parent directory during its run. At the end, of its run the script reverts +- The script modifies the parent directory during its run. At the end of its run, the script reverts the directory to the initial state. ### Prerequisites