hiero-ledger / hiero-ledger/hiero-sdk-java
version.txt on main must always contain a -SNAPSHOT version between releases
- Dominant language
- Java
- Stars
- 264
- Forks
- 192
- Avg merge
- 2d
- Merged PRs (30d)
- 39
Description
Today the release process sets `version.txt` to the version that is about to be released (e.g. `2.76.0`, commit `ab3fcb9`, "chore: release 2.76.0" #2880) and then leaves it there. As a result, `main` permanently carries a version number that has **already been published to Maven Central**. Every commit merged after a release — up to and including the day before the next release — builds artifacts that claim to be `com.hedera.hashgraph:sdk:2.76.0`, even though they are not that release.
This was the motivation for #2648, which changed `version.txt` to `2.68.0-SNAPSHOT`. The intent of that PR was apparently not clear, so this issue describes the underlying problem and the concrete fix.
## Why this is a problem
1. **Local development builds silently overwrite the real release.** `./gradlew publishToMavenLocal` on `main` writes `sdk-2.76.0.jar` into `~/.m2/repository`. From that point on, *every* project on that machine that depends on `com.hedera.hashgraph:sdk:2.76.0` — including projects that have nothing to do with SDK development — resolves an unreviewed local build instead of the official release. This is invisible and produces bug reports that cannot be reproduced.
2. **Release versions are immutable by contract; SNAPSHOT versions are not.** Maven and Gradle treat a non-SNAPSHOT version as immutable and cache it forever: once `2.76.0` is in the local cache, a rebuild of `main` is not picked up. A `-SNAPSHOT` version is explicitly defined as mutable and is re-resolved (`changing = true`, configurable update interval). Without SNAPSHOT versions, iterating on the SDK from a consuming application means manually deleting cache entries.
3. **There is no way to consume "the current state of `main`".** Downstream consumers (`examples`, `tck`, `example-android`, integration tests in other Hiero repos, users who want to verify a fix before a release) currently have no coordinate that unambiguously refers to unreleased code. `2.76.0` is not that coordinate — it is the release.
4. **Publishing pre-release/nightly artifacts is impossible.** Publishing snapshots to a snapshot repository (Central Portal snapshots, GitHub Packages) requires a `-SNAPSHOT` version by definition. As long as `main` carries a release version, we cannot offer nightly builds at all, and any attempt would be an attempt to overwrite a released coordinate.
5. **Version numbers become ambiguous in issue reports.** "I'm on 2.76.0" can mean the release or any commit on `main` after it. With `2.77.0-SNAPSHOT` the two states are distinguishable on sight.
This is not a stylistic preference: it is the standard Maven/Gradle release convention, and the repository already follows it elsewhere — `examples/version.txt` contains `0.1.0-SNAPSHOT`.
## Proposed solution
Adopt the standard rule, explicitly:
> **The version in `version.txt` on `main` is always a `-SNAPSHOT` version. A non-SNAPSHOT version exists only on the release commit that is tagged and published.**
Concrete release flow:
1. Release PR sets `version.txt` from `X.Y.Z-SNAPSHOT` to `X.Y.Z` (as today) and is merged.
2. Tag `vX.Y.Z` is created **on that release commit** and pushed; `release-artifacts.yml` validates tag vs. project version and publishes to Maven Central (unchanged behaviour).
3. Immediately afterwards, a follow-up commit on `main` sets `version.txt` to the next development version, e.g. `X.(Y+1).0-SNAPSHOT`.
Steps 1–3 can be a single automated sequence in the release workflow, or two PRs — that is an implementation detail. The invariant is that `main` never stays on a published version.
Note: this does **not** change what gets published. `release-artifacts.yml` only publishes on `v*.*.*` tag pushes, so a `-SNAPSHOT` on `main` can never be released to Maven Central by accident. The `validate-release` check keeps working, because the tag points at the release commit whose `version.txt` contains the exact release version.
## Acceptance criteria
- [ ] `version.txt` on `main` contains `2.77.0-SNAPSHOT` (i.e. the next development version, not the last released one).
- [ ] The release process (documented and/or automated) contains an explicit post-release step that restores the `-SNAPSHOT` version on `main`.
- [ ] The rule is documented for contributors (`CONTRIBUTING.md` / release runbook / `MAINTAINERS.md`): release versions live on tags only, `main` is always SNAPSHOT.
- [ ] `./gradlew publishToMavenLocal` on `main` produces `-SNAPSHOT` artifacts that cannot shadow a published release.
## Optional follow-ups (not required for this issue)
- CI guard on `main`: fail the build if `version.txt` does not end in `-SNAPSHOT` (outside of the release commit), so the post-release step can never be forgotten again.
- Publish snapshots from `main` to a snapshot repository so consumers can test unreleased fixes without building locally.
## References
- PR #2648 — "fix: Version number need to be changed after releases" (the original attempt to fix this)
- `.github/workflows/release-artifacts.yml` — tag-triggered publishing and the tag/version consistency check
- `examples/version.txt` — already uses `0.1.0-SNAPSHOT`, i.e. the convention this issue asks for
Contributor guide
Research direction
Start with version.txt and .github/workflows/release-artifacts.yml, then read the contributor or release documentation named in the acceptance criteria. Trace how the release tag and project version are validated, and verify the post-release development version is restored on main. Done means main uses the next -SNAPSHOT version, the process is documented or automated, and local publishing cannot shadow a released coordinate.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- github-actions, java
- Domain
- build-system, documentation, release
- Issue type
- Feature
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Active
- Clarity
- Clearly specified
- Newbie friendliness
- 68/100