From a11a30dd516cdb72708010c75a9a929d784b3ab2 Mon Sep 17 00:00:00 2001 From: Tim Fennell Date: Sat, 25 Apr 2026 07:26:29 -0600 Subject: [PATCH 1/3] Make snapshot version names reflect the next planned release. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Previously the build appended "-SNAPSHOT" to git-describe output, so all snapshots between releases were named after the *previous* release (e.g. "4.3.0-3-gabcdef0-SNAPSHOT"), the opposite of Maven convention where SNAPSHOTs are previews of the next release. The fix: declare a `nextVersionBump` ("x" / "x.x" / "x.x.x") at the top of build.gradle, and compute the next semver from the most recent release tag plus that bump. Snapshots are then named "--SNAPSHOT" (e.g. "5.0.0-23c681a8dc-SNAPSHOT"); including the hash makes each snapshot a distinct, pinnable artifact. Release builds (-Drelease=true) require HEAD to be on a semver tag and the working tree to be clean; the tag is the version (nextVersionBump is ignored on release — the tag is authoritative). nextVersionBump is set to "x" since the next release will be a major one. --- CONTRIBUTING.md | 60 ++++++++++++++++++++++++++++++++------- build.gradle | 74 ++++++++++++++++++++++++++++++++++++++++++++----- 2 files changed, 117 insertions(+), 17 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index ea46e2d43d..40ec5a95ef 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -148,12 +148,44 @@ export GPG_TTY=$(tty) ### Version Numbering -The version is derived automatically from git tags using the -[palantir git-version](https://github.com/palantir/gradle-git-version) plugin: +The build computes the version from git state plus a single declaration in +`build.gradle`: -- On a release tag (e.g. `4.3.0`): version is `4.3.0` -- On a commit after a tag: version includes the commit distance and hash -- Without `-Drelease=true`: `-SNAPSHOT` is appended +```groovy +final nextVersionBump = "x" // "x" major, "x.x" minor, "x.x.x" patch +``` + +`nextVersionBump` declares the *shape* of the next planned release relative to +the most recent semver tag (e.g. `4.3.0`): + +| Bump | Most recent tag | Computed next version | +| ------- | --------------- | --------------------- | +| `x` | `4.3.0` | `5.0.0` | +| `x.x` | `4.3.0` | `4.4.0` | +| `x.x.x` | `4.3.0` | `4.3.1` | + +What the build actually publishes: + +- **Release** (`-Drelease=true`): HEAD must be on a semver-tagged commit; the + tag itself is the version (e.g. `5.0.0`). `nextVersionBump` is ignored on + release — the tag is authoritative. +- **Snapshot** (default): `--SNAPSHOT` + (e.g. `5.0.0-23c681a-SNAPSHOT`). + +The short hash in snapshot versions makes each snapshot a distinct, pinnable +artifact rather than the usual moving-target Maven SNAPSHOT — consumers can +lock to a specific commit. Trade-off: there is no plain `5.0.0-SNAPSHOT` to +depend on for "always latest." + +To see the version the build will produce: + +```bash +./gradlew -q printVersion +``` + +After cutting a release, update `nextVersionBump` if the *next* planned release +is a different shape (e.g. switch from `x` to `x.x` once you start shipping +minor releases on a stable major line). ### Publishing a Snapshot @@ -163,9 +195,6 @@ Snapshots are published from any state of the repository without signing: ./gradlew publishAllPublicationsToCentralPortalSnapshots ``` -The version will be whatever `git describe` produces with `-SNAPSHOT` appended -(e.g. `4.3.0-1-gabcdef0-SNAPSHOT`). - **Note:** Snapshot publishing to Central Portal requires that SNAPSHOT support is enabled on the `com.github.samtools` namespace in the Central Portal settings. @@ -175,9 +204,20 @@ Releases are published from a git tag. The full process: #### Step 1: Tag the Release +Make sure `nextVersionBump` in `build.gradle` matches the kind of release you +intend to ship (major / minor / patch). Then check the version and tag the +release commit: + +```bash +./gradlew -q printVersion # prints e.g. "5.0.0-23c681a-SNAPSHOT" +``` + +Strip the `--SNAPSHOT` suffix to get the tag string. For the example +above, that's `5.0.0`: + ```bash -git tag X.Y.Z -git push origin X.Y.Z +git tag 5.0.0 +git push origin 5.0.0 ``` #### Step 2: Verify Locally (Dry Run) diff --git a/build.gradle b/build.gradle index e359d9df5e..f83371d7bf 100644 --- a/build.gradle +++ b/build.gradle @@ -60,15 +60,75 @@ java { withSourcesJar() } -// Version is derived from git tags via the palantir git-version plugin. -// On a tagged commit (e.g. tag "4.3.0") the version is "4.3.0". -// On a later commit it includes the distance and hash, e.g. "4.3.0-3-gabcdef0". -// Without -Drelease=true, "-SNAPSHOT" is appended (e.g. "4.3.0-3-gabcdef0-SNAPSHOT"). +// Versioning +// ---------- +// The version of the *next* planned release is computed from the most recent +// release tag plus a "bump shape" declared below: +// "x" -> bump the major component (e.g. 4.3.0 -> 5.0.0) +// "x.x" -> bump the minor component (e.g. 4.3.0 -> 4.4.0) +// "x.x.x" -> bump the patch component (e.g. 4.3.0 -> 4.3.1) +// +// Release builds (-Drelease=true) require HEAD to be tagged exactly with the +// computed next version, and the published version is just that string (e.g. "5.0.0"). +// +// Snapshot builds (the default) publish "--SNAPSHOT" +// (e.g. "5.0.0-abc1234-SNAPSHOT"). Including the short hash means each snapshot +// is a distinct, pinnable artifact rather than the typical Maven "moving target" +// SNAPSHOT, so consumers can lock to a specific commit. +// +// To change the planned bump (e.g. after a release lands), update nextVersionBump +// below and commit. +final nextVersionBump = "x" + final isRelease = Boolean.getBoolean("release") -final gitVersion = gitVersion().replaceAll("\\.dirty", "") -version = isRelease ? gitVersion : gitVersion + "-SNAPSHOT" +final details = versionDetails() +final lastTag = details.lastTag +if (lastTag == null) { + throw new GradleException("No release tags found; cannot determine version.") +} +final semverPattern = /^(\d+)\.(\d+)\.(\d+)$/ +final tagMatcher = lastTag =~ semverPattern +if (!tagMatcher.matches()) { + throw new GradleException( + "Most recent tag '${lastTag}' is not in MAJOR.MINOR.PATCH form.") +} + +if (isRelease) { + // Release: HEAD must be exactly on a semver-tagged commit AND the working tree + // must be clean; the tag IS the version. (nextVersionBump is informational/for + // snapshots only — the tag is authoritative.) + if (details.commitDistance != 0) { + throw new GradleException( + "Release requested but HEAD is not on a tagged commit " + + "(lastTag=${lastTag}, commitDistance=${details.commitDistance}).") + } + if (!details.isCleanTag) { + throw new GradleException( + "Release requested but the working tree has uncommitted changes; " + + "commit, stash, or reset before publishing.") + } + version = lastTag +} else { + // Snapshot: compute the next planned version from the most recent tag + bump shape. + final lastMajor = tagMatcher.group(1).toInteger() + final lastMinor = tagMatcher.group(2).toInteger() + final lastPatch = tagMatcher.group(3).toInteger() + final String nextVersion + switch (nextVersionBump) { + case "x": nextVersion = "${lastMajor + 1}.0.0"; break + case "x.x": nextVersion = "${lastMajor}.${lastMinor + 1}.0"; break + case "x.x.x": nextVersion = "${lastMajor}.${lastMinor}.${lastPatch + 1}"; break + default: + throw new GradleException( + "Unrecognized nextVersionBump '${nextVersionBump}'; expected 'x', 'x.x', or 'x.x.x'.") + } + version = "${nextVersion}-${details.gitHash.substring(0, 7)}-SNAPSHOT" +} -logger.info("build for version:" + version) +logger.info("build for version: ${version}") +// Note: the palantir git-version plugin already provides a 'printVersion' task +// that prints the resolved project.version — useful for CI scripts and for +// figuring out what tag to apply for a release. group = 'com.github.samtools' defaultTasks 'jar' From 67f2f3c51100f43999fcc7b30a05b90ca12b3b99 Mon Sep 17 00:00:00 2001 From: Tim Fennell Date: Sat, 25 Apr 2026 07:28:47 -0600 Subject: [PATCH 2/3] Remove dead Ant build and Travis CI config. CI is on GitHub Actions (.github/workflows/tests.yml); Travis hasn't been used in years and Travis-CI.org no longer offers free OSS minutes anyway. The Ant build.xml has been superseded by the Gradle build for as long as anyone can remember. Nothing in the repo references either file. Also drops the matching /htsjdk.version.properties .gitignore entry, which was an artifact of the Ant build. --- .gitignore | 1 - .travis.yml | 56 ----------------------------------------------- build.xml | 62 ----------------------------------------------------- 3 files changed, 119 deletions(-) delete mode 100644 .travis.yml delete mode 100755 build.xml diff --git a/.gitignore b/.gitignore index 03a8d6d509..606b65033a 100644 --- a/.gitignore +++ b/.gitignore @@ -1,7 +1,6 @@ htsjdk.iws .command_tmp atlassian-ide-plugin.xml -/htsjdk.version.properties /test-output/ .DS_Store diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index f00fe8b27e..0000000000 --- a/.travis.yml +++ /dev/null @@ -1,56 +0,0 @@ -language: java -dist: trusty -sudo: true -services: - - docker -before_cache: - - rm -f $HOME/.gradle/caches/modules-2/modules-2.lock -cache: - directories: - - $HOME/.gradle/caches/ - - $HOME/.gradle/wrapper/ - - $HOME/.m2 -env: - global: - - HTSJDK_SAMTOOLS_BIN=/usr/bin/samtools -jdk: - - oraclejdk8 - - openjdk8 - - openjdk11 -matrix: - fast_finish: true - allow_failures: - - env: TEST_TYPE=EXTERNAL_APIS - - env: TEST_TYPE=FTP - include: - - jdk: oraclejdk8 - env: TEST_TYPE=EXTERNAL_APIS - - jdk: oraclejdk8 - env: TEST_TYPE=FTP - - jdk: openjdk8 - env: SPOT_BUGS=true - -before_install: - - scripts/install-samtools.sh - - scripts/htsget-scripts/start-htsget-test-server.sh - -script: - - if [[ $SPOT_BUGS == "true" ]]; then - ./gradlew spotBugsMain spotBugsTest; - elif [[ $TEST_TYPE == "FTP" ]]; then - ./gradlew testFTP jacocoTestReport; - elif [[ $TEST_TYPE == "EXTERNAL_APIS" ]]; then - ./gradlew testExternalApis jacocoTestReport; - else - ./gradlew test jacocoTestReport; - fi - -after_success: - - bash <(curl -s https://raw.githubusercontent.com/broadinstitute/codecov-bash-uploader/main/codecov-verified.bash) - - echo "TRAVIS_BRANCH='$TRAVIS_BRANCH'"; - echo "JAVA_HOME='$JAVA_HOME'"; - if [ "$TRAVIS_BRANCH" == "master" ]; then - if [[ $JAVA_HOME = *java-8-openjdk* ]]; then - ./gradlew publish; - fi; - fi; diff --git a/build.xml b/build.xml deleted file mode 100755 index 59bebded33..0000000000 --- a/build.xml +++ /dev/null @@ -1,62 +0,0 @@ - - - - - - - - - - ANT IS DEPRECATED FOR BUILDING HTSJDK - - Please switch to using gradlew - - Examples: - compile htsjdk or it's tests - ./gradlew compileJava - ./gradlew compileTest - - build a jar - ./gradlew jar - - build a jar, along with source and document jars - ./gradlew build - - build a jar that packages all of htsjdk's dependencies in a single jar - ./gradlew shadowJar - - run tests, or a single test, or run a test and wait for the debugger - ./gradlew test - ./gradlew test --tests "*AlleleUnitTest" - ./gradlew test --tests "*AlleleUnitTest" --debug-jvm - - clean the project directory - ./gradlew clean - - see an exhaustive list of all available targets - ./gradlew tasks - - - From 1a076999fd8c6f098b00e94de3eccc0503a66d3f Mon Sep 17 00:00:00 2001 From: Tim Fennell Date: Sat, 25 Apr 2026 07:39:38 -0600 Subject: [PATCH 3/3] ci: use full-history checkout so git-version can find tags. GitHub's actions/checkout defaults to a shallow clone (fetch-depth: 1) with no tags fetched, so palantir/git-version's `versionDetails().lastTag` returned an abbreviated commit hash instead of "4.3.0", which the new semver parser correctly rejected. Set fetch-depth: 0 on all three checkout steps. --- .github/workflows/tests.yml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 64fe051ba9..e336d3c9fa 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -21,6 +21,8 @@ jobs: name: Java ${{ matrix.Java }} build and test steps: - uses: actions/checkout@v3 + with: + fetch-depth: 0 # full history + tags so palantir/git-version sees the latest release tag - name: Set up java ${{ matrix.Java }} uses: actions/setup-java@v3 with: @@ -49,6 +51,8 @@ jobs: name: Tests that require external APIs steps: - uses: actions/checkout@v3 + with: + fetch-depth: 0 # full history + tags so palantir/git-version sees the latest release tag - name: Set up java 17 uses: actions/setup-java@v3 with: @@ -72,6 +76,8 @@ jobs: name: SpotBugs steps: - uses: actions/checkout@v3 + with: + fetch-depth: 0 # full history + tags so palantir/git-version sees the latest release tag - name: Set up java 17 uses: actions/setup-java@v3 with: