Skip to content

Fix release workflow: ignore .kotlin and set reckon.stage=final#46

Merged
ogolberg merged 2 commits intomainfrom
ignore-kotlin-session-files
May 5, 2026
Merged

Fix release workflow: ignore .kotlin and set reckon.stage=final#46
ogolberg merged 2 commits intomainfrom
ignore-kotlin-session-files

Conversation

@ogolberg
Copy link
Copy Markdown
Member

@ogolberg ogolberg commented May 5, 2026

Root cause

The 0.0.17 release failed with Task 'publishToSonatype' not found in root project 'testkit-plugins' and its subprojects. The failed run resolved Reckoned version: 0.0.18-SNAPSHOT rather than 0.0.17, which made isRelease() false, the if (isRelease()) { nexusPublishing { sonatype { ... } } } block skip, and the publishToSonatype task never get registered.

The chain from release-tag-push to SNAPSHOT version:

  1. buildSrc/build.gradle.kts adds ../shared-build-logic/src/main/kotlin as a Kotlin source dir. No equivalent in expediter.
  2. This forces the Kotlin compiler to run against that external source tree during the settings phase. It writes buildSrc/.kotlin/sessions/kotlin-compiler-<id>.salive as a daemon liveness file.
  3. .kotlin was not ignored. JGit's status() reports the tree as dirty with untracked=[buildSrc/.kotlin/sessions/kotlin-compiler-...salive].
  4. Reckon's GitInventorySupplier.isClean() returns false (confirmed via --debug: Git repository is not clean: ... untracked=[buildSrc/.kotlin/sessions/kotlin-compiler-...salive]).
  5. In Reckoner.reckonTargetVersion (reckon-core-2.0.0), the "rebuild" branch requires all three of isClean() && currentVersion.isPresent() && stage == null. With clean=false, that branch is skipped, falling through to the snapshot path — output 0.0.18-SNAPSHOT.
  6. isRelease() checks for -SNAPSHOT suffix → false → no sonatype {} configured → no publishToSonatype task registered → TaskSelectionException.

Fix (defense in depth)

  1. Add .kotlin to .gitignore — removes the untracked session file from Reckon's view so the clean check passes naturally. Also quiets git status during local development.
  2. Pass -Preckon.stage=final in the release workflow — short-circuits the clean check entirely. The final-stage branch (Reckoner.reckonTargetVersion, reckon-core-2.0.0) returns the target normal before ever reaching the rebuild branch. Defensive against any future tool dropping a new untracked cache dir into the tree during the settings phase.

Reproduction

Locally, fresh clone at the 0.0.17 tag (matching actions/checkout's git init, full fetch, checkout --force refs/tags/0.0.17):

$ ./gradlew properties 2>&1 | grep -E '^version:|Reckoned'
Reckoned version: 0.0.18-SNAPSHOT
version: 0.0.18-SNAPSHOT

$ ./gradlew properties --debug 2>&1 | grep 'not clean'
Git repository is not clean: added=[], changed=[], removed=[], untracked=[buildSrc/.kotlin/sessions/kotlin-compiler-*.salive], modified=[], missing=[]

With .kotlin ignored (committed + tag moved to that commit):

$ ./gradlew properties 2>&1 | grep -E '^version:|Reckoned'
Reckoned version: 0.0.17
version: 0.0.17

Why expediter isn't affected

Expediter's buildSrc/build.gradle.kts doesn't add external Kotlin source dirs, so the Kotlin compiler never creates buildSrc/.kotlin/ during settings evaluation. Same Reckon config, same gitignore, but no untracked file to trip Reckon's clean check. Expediter's -Preckon.stage=final drop in e0fcecd with the claim it's redundant actually does hold for expediter — just not here.

Test plan

  • After merge, delete and re-push 0.0.17 (or cut 0.0.18) and confirm the release workflow publishes to Sonatype

🤖 Generated with Claude Code

ogolberg added 2 commits May 5, 2026 14:13
buildSrc/build.gradle.kts adds ../shared-build-logic as a Kotlin source
dir, so the Kotlin compiler creates buildSrc/.kotlin/sessions/*.salive
during the settings phase. Without .kotlin in .gitignore, JGit reports
the tree as dirty during Reckon's clean check, so the tag-is-current
rebuild branch (Reckoner.java:122) is skipped and a SNAPSHOT falls out
instead. That broke the 0.0.17 release with "Task 'publishToSonatype'
not found".

Generated with Claude Code
Short-circuits Reckon's clean check: the final-stage branch in
Reckoner.reckonTargetVersion returns the target normal directly, before
ever reaching the rebuild branch that requires isClean(). Defensive
against future tools dropping untracked cache dirs into the tree
during the settings phase.

Generated with Claude Code
@ogolberg ogolberg changed the title Ignore .kotlin session files to fix release builds Fix release workflow: ignore .kotlin and set reckon.stage=final May 5, 2026
@ogolberg ogolberg merged commit 52e9e84 into main May 5, 2026
1 check passed
@ogolberg ogolberg deleted the ignore-kotlin-session-files branch May 5, 2026 19:05
ogolberg added a commit that referenced this pull request May 6, 2026
## Summary
- Tagging `0.1.0` published as `0.1.1` to Maven Central because the
release workflow passed `-Preckon.stage=final`.
- With `stage` set, reckon skips the rebuild branch in
`Reckoner.reckonTargetVersion` that would return the tag's exact version
when `isClean() && currentVersion.isPresent() && stage == null`, and
instead computes a target normal via `defaultInferredScope=patch` —
bumping `0.1.0` to `0.1.1`.
- The `.kotlin` → `.gitignore` change from #46 is the real fix for the
untracked-file clean-check problem; the `-Preckon.stage=final` "defense
in depth" is counterproductive.

## Verification
At tag `0.1.0` with a clean tree:

```
$ ./gradlew properties 2>&1 | grep -E '^version:|Reckoned'
Reckoned version: 0.1.0
version: 0.1.0
```

With `-Preckon.stage=final` (the bug):

```
$ ./gradlew properties -Preckon.stage=final 2>&1 | grep -E '^version:|Reckoned'
Reckoned version: 0.1.1
version: 0.1.1
```

## Test plan
- [ ] After merge, re-push `0.1.0` (or cut a new tag) and confirm the
release workflow publishes the tagged version, not tag+1.

🤖 Generated with [Claude Code](https://claude.com/claude-code)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant