| name | dependency-update |
| description | Walks every dependency declaration under `buildSrc/src/main/kotlin/io/spine/dependency/`, discovers the latest accepted version of each artifact from the URL hinted in its file (or from Maven metadata if no URL is present), and update the `version` constant in place. Also refresh the build script's own dependencies declared in `buildSrc/build.gradle.kts` (Gradle plugins and `buildSrc` libraries), respecting their pin rationale and "keep in sync with `io.spine.dependency.*`" comments. External dependency scopes accept only released versions; the `local` scope also accepts snapshots and pre-releases published from sibling Spine repos. Use when asked to refresh dependency versions, bump libraries, run a dependency audit, or "see what's stale".
|
Update dependencies
Goal
Bring every dependency object under
buildSrc/src/main/kotlin/io/spine/dependency/ to its latest accepted version.
For every scope except local/, that means the latest released version:
snapshots, release candidates, milestones, alpha/beta, EAP, and -dev builds
are excluded.
local/ is the deliberate exception. It holds Spine SDK dependencies published
from sibling Spine repositories, and it may move to newer snapshots or
pre-releases such as 2.0.0-SNAPSHOT.388 or 2.1.0-RC1.
Beyond that catalogue, also refresh the build script's own dependencies —
the Gradle plugins and buildSrc libraries declared in
buildSrc/build.gradle.kts (as version constants, plugins {} literals, or
inline coordinates). These follow the same released-only rule, but the
file constrains them with its own comments: some versions are deliberately
pinned below the newest release, and some must be kept in sync with a
io.spine.dependency.* object rather than chasing latest independently. The
mechanics are in
references/buildsrc-build-script.md.
The authoritative version source for each artifact is the web page already
referenced in its file. When the file has no URL, use the Maven metadata
fallback described below. For non-local/ artifacts, a discovered Maven
Central URL is added back to the file as a line comment so the next run has
a hint.
Inputs
- No arguments → scan all of
buildSrc/src/main/kotlin/io/spine/dependency/
and buildSrc/build.gradle.kts.
- One or more paths or sub-package names (
lib, local, test, build,
kotlinx, boms) → restrict the scan to those dependency-object scopes; the
build script is excluded unless buildsrc is also named.
buildsrc (matched case-insensitively, so buildSrc is equivalent) or the
path buildSrc/build.gradle.kts → restrict the scan to the build script's own
dependencies.
--dry-run → discover and report, but do not edit.
Pre-flight
- Run
git status --short. If the worktree is dirty in files this skill will
touch, stop and ask the user. Otherwise preserve unrelated changes.
- Confirm the directories for the passes actually in scope exist. The
dependency-object pass needs
buildSrc/src/main/kotlin/io/spine/dependency/;
require it only when that pass runs (i.e. not for a buildsrc-only scope).
The build-script pass needs buildSrc/build.gradle.kts; if it is absent, skip
that pass and note it in the report rather than failing.
- Note the current branch — every change this skill makes is a candidate for
a single
chore(deps): refresh external versions commit at the end; the
skill itself does NOT commit. The user decides.
Per-file workflow
For each *.kt file in scope, apply the deterministic mechanics in
references/version-discovery.md:
- Parse the file — extract
objectName, the version literal (handle
multiple or renamed version constants), group, the module artifact names,
and the versionUrl hint. Skip abstract base classes and helpers.
- Find the latest accepted version — discovery depends on the URL shape
(GitHub release page, Maven Central, Spine SDK Maven metadata, project
homepage, or the no-URL Maven fallback). For
local/ files, check Spine SDK
Maven metadata first and keep snapshots / pre-releases as candidates.
- Filter pre-releases outside
local/ — reject -SNAPSHOT, -RC, -M,
-alpha / -beta / -EAP / -pre / -dev, and Spring-style .RC / .M
/ .Alpha / .Beta suffixes. local/ keeps them as candidates.
- Compare versions by semver; only update when
latest > current.
Then apply the edit and handle local/ artifacts:
5. Apply the edit
- Replace the
version literal with the new value. Use a precise replacement
anchored on the full line (const val version = "<old>" →
const val version = "<new>"). Do not blindly replace the version string,
because the same string can appear in module URLs constructed via
interpolation ("$group:…:$version") — those will pick up the new value
automatically.
- If the file uses a renamed version constant (
runtimeVersion,
compilerVersion, etc.) that feeds override val version = compilerVersion,
update the source constant, not the alias.
- For
DependencyWithBom objects, verify the bom line still resolves
correctly. The conventional shape is
override val bom = "$group:<artifact>-bom:$version", in which case no
separate edit is needed. If the BOM version is hard-coded, update it too.
- Preserve indentation, comment style, and surrounding blank lines exactly.
6. Watch for local/ artifacts
local/ holds Spine SDK dependencies (Base, CoreJvm, ModelCompiler, …) that
are published from sibling Spine repos. This scope accepts snapshots and
pre-releases because these artifacts often advance through internal snapshot
builds before a stable SDK release.
Still flag every local/ update in the report, and note whether the target
is a release, snapshot, or pre-release. The user can then decide whether to
bump the SDK in lockstep with the rest of the project. Spine SDK artifacts
often need to move together; one-off bumps can cause runtime ABI mismatches.
Build-script dependencies (buildSrc/build.gradle.kts)
After the per-file pass above, refresh the version declarations for the Gradle
plugins and buildSrc libraries in buildSrc/build.gradle.kts. Run this pass
last so that versions which mirror an io.spine.dependency.* object can read
the value that pass may have just updated. The full mechanics are in
references/buildsrc-build-script.md;
the policy is:
- Find each version declaration — a top-level
val <name>Version = "…", a
plugins {} id(…).version("…") literal, or an inline coordinate literal in
dependencies {}. A version used in both plugins {} and a val is declared
twice; both copies move together.
- Classify it by its comment:
- Pinned (the comment gives a reason to stay below the newest release,
e.g. "latest before
2.2.0, which introduces breaking changes", "last
version compatible with Gradle 7.x") → never auto-bump. Discover the
latest for the report, but make no edit; list it under Build script —
pinned with the rationale quoted.
- Synced (the comment carries an explicit sync directive — "keep in
sync with", "same version as" — naming an
io.spine.dependency.* object) →
the source of truth is that object's version, not an independent latest
lookup. Read the object's current on-disk value and align only upward
(never downgrade) — this works even in a buildsrc-only run, so it can fix
an out-of-sync declaration. Report under Build script — synced drift only
when the object's value is lower or incomparable. A bare @see to a
dependency object is not a sync directive — the object may govern a
different artifact — so treat it as independent. A version that is both
synced and pinned is treated as pinned (the pin wins).
- Independent (a URL hint or coordinate, and no pin or explicit sync
directive) → discover the latest released version (always filter
pre-releases; the build script is external scope) and auto-edit, exactly
like an external dependency object.
- Apply the edit in place, preserving the
val / plugins / inline shape,
the pin rationale, and the sync comment. Editing a val propagates through
every $…Version interpolation and force(…) entry automatically — do not
rewrite those.
The major-bump guard in Safety applies to independent build-script
versions just as it does to dependency objects.
Report
When the run completes, emit a Markdown report with these sections:
- Updated — table of
file | objectName | old → new | source URL.
- Already current — file/object pairs whose version was already the
newest accepted version.
- Skipped (manual review) — anything left untouched because it could not be
resolved: no URL hint and an empty metadata fallback, or a build-script
synced version whose io.spine.dependency.* object could not be located.
- Filtered pre-releases — newer versions found but rejected because they
were RC/SNAPSHOT/alpha/etc. Applies only outside
local/.
local/ bumps to confirm — every local/ change called out separately,
including snapshot and pre-release targets.
- Build script — updated —
buildSrc/build.gradle.kts versions changed,
each tagged independent or synced with its source (URL or the
io.spine.dependency.* object it mirrors).
- Build script — pinned — versions left untouched because of an explicit pin,
with the current value, the newest available value, and the quoted rationale.
- Build script — synced drift —
synced versions left unedited because the
referenced object's value was lower than (or could not be compared to) the
current build-script value — i.e. the build script is already ahead of, or
incomparable to, its object. Lists both values so the user can reconcile.
End with the suggested next steps:
- Review the diff (
git diff buildSrc/), covering both the dependency
catalogue and buildSrc/build.gradle.kts.
- Run the
version-bumped skill. Every feature branch must advance
version.gradle.kts strictly above the base before any
./gradlew build (which may transitively publishToMavenLocal). The
skill is a no-op when a bump already happened earlier on the branch
and otherwise uses the bump-version skill to perform the increment.
- Run
./gradlew build (or ./gradlew clean build if .proto files
participate).
- Commit. Match the shape of the actual change:
- Single
local/ bump (most common): Bump Spine Base -> `2.0.0-SNAPSHOT.190`
- Coordinated external set:
Bump Protobuf and gRPC (one commit;
mention both).
- Bulk external refresh (rare):
Refresh external dependencies.
Safety
- Do not commit. Do not push. Editing files is the limit of this skill's
authority.
- Never edit
version.gradle.kts — that's the bump-version skill's
responsibility.
- In
buildSrc/build.gradle.kts, never bump a pinned version past its stated
ceiling, and never silently drop or edit a pin rationale or a "keep in sync"
comment. When a synced version's referenced io.spine.dependency.* object
cannot be resolved, leave the value and flag it — do not guess.
- Never downgrade a synced build-script version: align it to its object only
when the object's value is strictly higher; otherwise report the drift, never
edit. Aligning upward is safe even in a
buildsrc-only run. A bare @see to a
dependency object is a cross-reference, not a sync directive — it may name a
different artifact, so look such versions up independently.
- Never auto-resolve a Maven Central query that returns multiple matching
artifacts with different groups (e.g. a library that exists under both
io.netty and io.netty.incubator). Ask the user.
- If a discovered "latest" version is more than one major ahead of the
current value (e.g.
1.x → 3.x), flag it as a major bump in the report
and apply the edit only if the user confirms, or only when running
non-interactively with --include-majors. Major bumps frequently break
ABI.
Failure modes to expect
- GitHub rate limit on the unauthenticated REST API. The
/releases/latest
HTML page does not require auth and is the preferred fallback.
- Per-component tags in a monorepo. Match by artifact name, don't take the
topmost tag blindly.
- Repositories that publish to JCenter only — JCenter is sunset; if Maven
Central is empty, the dependency may need migration. Flag it.
- Vendor-specific version schemes (e.g. dates:
2025.10.01) — the
semver comparator above will still order these correctly; just don't
mis-classify them as pre-releases.