Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 42 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,48 @@ followed by flat Keep-a-Changelog categories. API consumers should scan

_(Release-manager scratchpad. Populated at release-cut time.)_

## [8.1.0.01] - 2026-08-21

**Highlights.** The build number now matches the release name. This work has
been called VCell 8.1 in the release notes since it began, while its builds
continued the `8.0.x` sequence; from this build the two agree. This is the
first release candidate for VCell 8.1. VCell also checks properly now whether
your client matches the server it is talking to, including when the server is
updated part-way through a session — a mismatch it has been unable to detect
since 2022.

### Added
- When the server is updated during a session, VCell now says so. The client
reconnects on its own after a deployment, and that reconnect now reports the
change and asks the user to save, exit and restart to install the matching
version. Previously the automatic reconnect was silent, so a user could work
on against a server their client no longer matched. (#2012)

### Fixed
- VCell could not detect a client/server version mismatch that lay in the
PATCH number. `VCellSoftwareVersion` read PATCH from the MINOR position, so
the check that compares client against server was comparing MINOR twice and
ignoring PATCH entirely. Since a VCell patch release can carry a breaking
API change, this is the case that most needed catching. The line dates from
2018 but was dead until a 2022 fix to the same statement made it live.
(#2011)

### Changed
- Version numbering realigned with the release narrative: builds are numbered
`8.1.x` from here, rather than continuing `8.0.x`. Published numbers up to
8.0.28.01 are unchanged. (#2010)
- The client/server version warning now appears whenever MAJOR, MINOR **or**
PATCH differ — which is what it was always meant to do, and could not.
Expect to see it more often than before: it was effectively dormant across
the whole 8.0 line, and a patch difference alone is now enough to raise it.
The warning is advisory and does not prevent use. Only the BUILD number is
ignored. (#2012)

### Notes for API consumers
No API changes. Clients that parse the version string should note that
`MAJOR.MINOR` moves from `8.0` to `8.1`; the four-part
`MAJOR.MINOR.PATCH.BUILD` shape is unchanged.

## [8.0.28.01] - 2026-08-20

**Highlights.** Dragging in the SpringSaLaD trajectory viewer turned the scene the wrong way —
Expand Down
8 changes: 5 additions & 3 deletions docs/RELEASING.md
Original file line number Diff line number Diff line change
Expand Up @@ -122,12 +122,14 @@ This has already happened once. **VCell 8.0** is the 8.0.0 builds only
— 8.0.0.01 through 8.0.0.03, the SpringSaLaD GA that ran in production
from 2026-05-21 to 2026-08-14. Everything released after 8.0.0.03 is
**VCell 8.1**, even though those builds are numbered 8.0.2.01 through
8.0.28.01 and beyond.
8.0.28.01. The numbering was realigned at **8.1.0.01**, so the two agree
again from that build onward; the divergence covers 8.0.2.01–8.0.28.01
only.

So, at release-cut time, add the user-facing items to the narrative
file for the release **currently being accumulated** — today
`8.1.md` — not to the file whose name matches the build's
`MAJOR.MINOR`. `CHANGELOG.md` is unaffected: it is organised strictly
`8.1.md` — which is not necessarily the file whose name matches the
build's `MAJOR.MINOR`. `CHANGELOG.md` is unaffected: it is organised strictly
by build version and always records the real number.

When a long-running `MAJOR.MINOR` line accumulates multiple distinct
Expand Down
30 changes: 20 additions & 10 deletions release-notes/major/8.1.md
Original file line number Diff line number Diff line change
@@ -1,15 +1,19 @@
# VCell 8.1

**Status:** pre-release. Rolled to the production site on 2026-08-14
and updated since; not yet announced as a public release event.

> **A note on version numbers.** VCell 8.1 is delivered by builds whose
> version numbers continue the `8.0.x` sequence — 8.0.2.01 through
> 8.0.28.01 so far. Those numbers are what they are and are not being
> restated. For release notes and user-facing announcements, **VCell 8.0
> means the 8.0.0 builds** (8.0.0.01–8.0.0.03, the SpringSaLaD GA that
> ran in production from 2026-05-21 to 2026-08-14), and **everything
> released after 8.0.0.03 is VCell 8.1**.
**Status:** release candidate — **8.1.0.01**. An earlier form of this
release has been on the production site since 2026-08-14 under `8.0.x`
build numbers; from 8.1.0.01 the build number carries the release name.

> **A note on version numbers.** VCell 8.1 was developed under build
> numbers that continued the `8.0.x` sequence — 8.0.2.01 through
> 8.0.28.01. Those numbers are published and are not being restated.
> **From 8.1.0.01 the two agree**, and the explanation below applies
> only to the builds before it.
>
> For release notes and user-facing announcements, **VCell 8.0 means
> the 8.0.0 builds** (8.0.0.01–8.0.0.03, the SpringSaLaD GA that ran in
> production from 2026-05-21 to 2026-08-14), and **everything released
> after 8.0.0.03 is VCell 8.1**.

## Headline

Expand Down Expand Up @@ -72,6 +76,12 @@ where spatial visualization is heading, not because it is ready.

## Improvements

- VCell now checks properly whether your client matches the server, and says
so when it does not — including when the server is updated part-way through
a session, which it previously reconnected to in silence. A VCell patch
release can change the API, so a client and server differing in any part of
the version may not work together; the check had been unable to see a
difference in the patch number since 2022 (8.1.0.01).
- Desktop window behaviour: child windows and dialogs now stay in front
of the window that opened them — and minimize and travel with it — on
modern macOS and Windows, where they could previously slip behind the
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -275,7 +275,18 @@ public MessageEvent[] getMessageEvents() throws RemoteProxyException, IOExceptio
}
}

private void checkClientServerSoftwareVersion(InteractiveClientServerContext requester, ClientServerInfo clientServerInfo) {
/**
* Why the version check is running. The comparison is the same either way -- any
* difference in MAJOR, MINOR or PATCH -- but the two situations need different advice.
*/
private enum VersionCheck {
/** At login, or a reconnect the user asked for: the client was already out of date. */
ON_CONNECT,
/** After an automatic reconnect: the server was redeployed underneath a running client. */
AFTER_SERVER_CHANGED
}

private void checkClientServerSoftwareVersion(InteractiveClientServerContext requester, ClientServerInfo clientServerInfo, VersionCheck when) {
String clientSoftwareVersion = System.getProperty(PropertyLoader.vcellSoftwareVersion);
if (clientSoftwareVersion != null && clientSoftwareVersion.toLowerCase().contains("devel") ) {
return;
Expand All @@ -293,13 +304,27 @@ private void checkClientServerSoftwareVersion(InteractiveClientServerContext req
+ "We have adopted a Release Early, Release Often software development approach\n\n"
+ "\nPlease exit VCell and download the latest client from VCell Software page (http://vcell.org).");
}
//
// MAJOR, MINOR and PATCH all matter. A VCell PATCH release can carry a breaking
// API change, so a client and server differing in any of the three are not known
// to be compatible. Only BUILD is ignored. This is what the check has always
// meant to do; it could not, because getPatchVersion() returned MINOR (#2011).
//
if (clientVersion.getMajorVersion()!=serverVersion.getMajorVersion() ||
clientVersion.getMinorVersion()!=serverVersion.getMinorVersion() ||
clientVersion.getPatchVersion()!=serverVersion.getPatchVersion()) {
requester.showWarningDialog("software version mismatch between client and server:\n"
+ "client VCell version : " + clientSoftwareVersion + "\n"
+ "server VCell version : " + serverSoftwareVersion + "\n"
+ "\nPlease exit VCell and download the latest client from VCell Software page (http://vcell.org).");
if (when == VersionCheck.AFTER_SERVER_CHANGED) {
requester.showWarningDialog("The VCell server was updated while you were working:\n"
+ "client VCell version : " + clientSoftwareVersion + "\n"
+ "server VCell version : " + serverSoftwareVersion + "\n"
+ "\nThis client no longer matches the server."
+ "\nPlease save your work, then exit and restart VCell to install the matching version.");
} else {
requester.showWarningDialog("software version mismatch between client and server:\n"
+ "client VCell version : " + clientSoftwareVersion + "\n"
+ "server VCell version : " + serverSoftwareVersion + "\n"
+ "\nPlease exit VCell and download the latest client from VCell Software page (http://vcell.org).");
}
}
}
}
Expand All @@ -318,7 +343,7 @@ public void connectNewServer(InteractiveClientServerContext requester, ClientSer
public void connect(InteractiveClientServerContext requester) {
asynchMessageManager.stopPolling();
reconnectStat = ReconnectStatus.NOT;
checkClientServerSoftwareVersion(requester,clientServerInfo);
checkClientServerSoftwareVersion(requester,clientServerInfo,VersionCheck.ON_CONNECT);

// get new server connection
VCellConnection newVCellConnection = connectToServer(requester,true);
Expand Down Expand Up @@ -727,6 +752,12 @@ void reconnect() {
changeConnection(requester,connection);
rc.stop();
asynchMessageManager.startPolling();
//
// Only once the reconnect has succeeded -- a failed attempt says nothing about
// the server's version, and this check makes an HTTP call of its own that the
// retry loop should not repeat.
//
checkClientServerSoftwareVersion(requester,clientServerInfo,VersionCheck.AFTER_SERVER_CHANGED);
return;
}
setConnectionStatus(new ClientConnectionStatus(getClientServerInfo().getUsername(), getClientServerInfo().getApihost(), getClientServerInfo().getApiport(), ConnectionStatus.DISCONNECTED));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ private VCellSoftwareVersion(String softwareVersionString){
minorVersion = safeParse(minor);
}
if (parts.length > 2) {
String patch = parts[1];
String patch = parts[2];
patchVersion = safeParse(patch);
}
} catch (Exception exc) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package org.vcell.util.document;

import org.junit.jupiter.api.Tag;
import org.junit.jupiter.api.Test;

import static org.junit.jupiter.api.Assertions.assertEquals;

/**
* The four-part version is carried as "<EDITION>_Version_<MAJOR.MINOR.PATCH>_build_<BUILD>".
* PATCH was read from the MINOR position for four years (issue #2011) without anything
* noticing, because its only consumer compared it against a value that was equally wrong.
*/
@Tag("Fast")
public class VCellSoftwareVersionTest {

@Test
public void parsesAllFourParts() {
VCellSoftwareVersion v = VCellSoftwareVersion.fromString("Alpha_Version_8.0.28_build_01");
assertEquals(VCellSoftwareVersion.VCellSite.alpha, v.getSite());
assertEquals(8, v.getMajorVersion());
assertEquals(0, v.getMinorVersion());
assertEquals(28, v.getPatchVersion());
assertEquals("01", v.getBuildNumber());
}

@Test
public void patchIsNotAliasedToMinor() {
// 8.1.0 and 8.0.1 differ only by which of the two middle numbers is set, so a
// parser that reads PATCH from the MINOR position cannot tell them apart.
VCellSoftwareVersion a = VCellSoftwareVersion.fromString("Rel_Version_8.1.0_build_01");
assertEquals(1, a.getMinorVersion());
assertEquals(0, a.getPatchVersion());

VCellSoftwareVersion b = VCellSoftwareVersion.fromString("Rel_Version_8.0.1_build_01");
assertEquals(0, b.getMinorVersion());
assertEquals(1, b.getPatchVersion());
}

@Test
public void unparseableVersionIsUnknownRatherThanThrowing() {
VCellSoftwareVersion v = VCellSoftwareVersion.fromString("nonsense");
assertEquals(VCellSoftwareVersion.VCellSite.unknown, v.getSite());
}
}
Loading