Skip to content

Commit 52d264d

Browse files
committed
Document release process
Signed-off-by: BoykoAlex <alex.boyko@broadcom.com>
1 parent e0226b6 commit 52d264d

1 file changed

Lines changed: 222 additions & 0 deletions

File tree

‎RELEASE.md‎

Lines changed: 222 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,222 @@
1+
# Spring Tools Release Process
2+
3+
Spring Tools ships three independent release tracks that all build on the
4+
Java language servers but are released, tested, and published on their own
5+
schedules:
6+
7+
- **Eclipse track** — Eclipse LS Extensions → Eclipse Distribution → Test → Publish
8+
- **VSCode track** — VSCode Extensions RC → Test → Publish
9+
- **Claude Code plugin track** — Test locally → Release (build + publish)
10+
11+
The Eclipse and VSCode tracks each have their own release-candidate loop: if
12+
testing turns up a problem in one track, only that track's release step is
13+
re-spun. The other track keeps whatever candidate it already has and does
14+
not need to be rebuilt. The Claude Code plugin track has no candidate/staging
15+
step at all — see below.
16+
17+
Every step below except "Test" is a GitHub Actions workflow, triggered via
18+
`workflow_dispatch` from the Actions tab (or `gh workflow run`).
19+
20+
## Prerequisite: Update Changelogs
21+
22+
Before kicking off *any* of the three tracks below, the changelog entries
23+
for this release must be written and pushed:
24+
25+
- the wiki's `Changelog.md` (in the `spring-tools.wiki` repo)
26+
- the `CHANGELOG.md` of whichever VSCode extension(s) are being released
27+
(typically just [`vscode-extensions/vscode-spring-boot/CHANGELOG.md`](vscode-extensions/vscode-spring-boot/CHANGELOG.md))
28+
29+
A draft is generated by the [`changelog-draft.yml`](.github/workflows/changelog-draft.yml)
30+
workflow (input: `release`, e.g. `4.20.1.RELEASE`). Despite its "Push to
31+
wiki" step name, it doesn't actually commit or push anything — it checks
32+
out the wiki, runs `github-changelog-generator` against the given release
33+
marker, prepends the result to a local copy of `Changelog.md`, and just
34+
prints it to the job log. That printed content has to be copied by hand,
35+
reformatted to match the existing entries' style (grouped bullet points
36+
tagged by component, e.g. `_(Spring Boot)_`), and manually committed/pushed
37+
to both the wiki and the relevant extension `CHANGELOG.md` file(s). This
38+
manual reformatting step is a good candidate for AI-assisted automation.
39+
40+
## Eclipse Track
41+
42+
| # | Step | Workflow | Key inputs |
43+
|---|------|----------|------------|
44+
| 1 | Release Eclipse LS Extensions | [`release-eclipse-ls-extensions.yml`](.github/workflows/release-eclipse-ls-extensions.yml) | `sts-language-servers-version` — the date-based suffix of the p2 repo S3 path, e.g. `2026-09-03` |
45+
| 2 | Release Eclipse Distribution | [`release-eclipse-distro-build.yml`](.github/workflows/release-eclipse-distro-build.yml) | `sts-language-servers-version` — **same date as step 1**; `qualifier` — `RELEASE` (default) |
46+
| 3 | Test | — manual | Install/verify the staged Eclipse distro build |
47+
| 4 | Publish Eclipse Distribution | [`publish-eclipse-release.yml`](.github/workflows/publish-eclipse-release.yml) | `ls_version` (same date as step 1), `release_version` (e.g. `4.20.1`), `qualifier`, `eclipse_latest` (e.g. `e4.40`) |
48+
49+
Step 2 depends on the language-server date produced in step 1. Unlike the
50+
VSCode track, there is no RC-numbered build for Eclipse: step 2 builds and
51+
stages a single `RELEASE` p2 repo. If testing finds a distro-only problem,
52+
re-running step 2 with the same inputs simply overwrites that staged build
53+
in place — there's nothing to increment. Step 1 only needs to be re-run if
54+
the language servers themselves are the problem. Step 4 doesn't build
55+
anything new; it just aggregates/publishes whatever is currently staged
56+
from step 2.
57+
58+
```mermaid
59+
stateDiagram-v2
60+
[*] --> ReleaseLSExtensions
61+
ReleaseLSExtensions --> ReleaseDistro : ls-version (date)
62+
ReleaseDistro --> TestEclipse
63+
TestEclipse --> ReleaseDistro : issues found\n(re-spin: overwrites staged build)
64+
TestEclipse --> PublishDistro : tests pass
65+
PublishDistro --> [*]
66+
```
67+
68+
## VSCode Track
69+
70+
| # | Step | Workflow | Key inputs |
71+
|---|------|----------|------------|
72+
| 1 | Release VSCode Extensions RC | [`release-vscode-extension.yml`](.github/workflows/release-vscode-extension.yml) | `extension-name` (`vscode-spring-boot`), `postfix` (e.g. `RC1`), `tag` |
73+
| 2 | Test | — manual | Install/verify the built `.vsix` RC build |
74+
| 3 | Publish VSCode Extension | [`publish-vscode-extension.yml`](.github/workflows/publish-vscode-extension.yml) | `extension-name`, `version`, `postfix` — **the exact RC you're promoting to release** (e.g. `RC1`); it downloads that specific `<extension-name>-<version>-<postfix>.vsix` and publishes it as-is to both the VSCode Marketplace and Open VSX |
75+
76+
This is per-extension, not a bulk step: run it once for whichever extension
77+
you're publishing. `vscode-spring-boot` is the extension that goes through
78+
this release process regularly; the other VSCode extensions
79+
(`vscode-concourse`, `vscode-manifest-yaml`, `vscode-bosh`, `boot-dev-pack`)
80+
use the same two workflows but are released far less frequently. Note that
81+
publishing doesn't relabel the artifact as `RELEASE` — the same RC-suffixed
82+
`.vsix` you tested is what goes out to the marketplaces, so the `postfix`
83+
you pass here must match whichever RC actually passed testing.
84+
85+
If testing finds an issue, re-spin step 1 with an incremented `postfix`
86+
(`RC1` → `RC2`, …), then test again.
87+
88+
```mermaid
89+
stateDiagram-v2
90+
[*] --> ReleaseVSCodeRC
91+
ReleaseVSCodeRC --> TestVSCode
92+
TestVSCode --> ReleaseVSCodeRC : issues found\n(re-spin: RC1 -> RC2 -> ...)
93+
TestVSCode --> PublishVSCode : tests pass
94+
PublishVSCode --> [*]
95+
```
96+
97+
## Claude Code Plugin Track
98+
99+
The `spring-tools` Claude Code plugin (`claude-plugins/spring-tools`) bundles
100+
the standalone Spring Boot language server (Jandex-based, no JDT LS) as an
101+
MCP server for Claude Code. Its release process is different from the other
102+
two tracks: there is no RC/staging step — the release workflow builds *and*
103+
publishes atomically in one shot, so verification has to happen locally
104+
*before* that workflow is dispatched.
105+
106+
| # | Step | Workflow | Key inputs |
107+
|---|------|----------|------------|
108+
| 1 | Test locally | — manual | Run [`claude-plugins/update-local-jars.sh`](claude-plugins/update-local-jars.sh) to build the standalone LS jar from the current `headless-services` snapshot and drop it into `spring-tools/language-server/`, then exercise the plugin through the local `spring-tools-local` marketplace ([`claude-plugins/.claude-plugin/marketplace.json`](claude-plugins/.claude-plugin/marketplace.json)) |
109+
| 2 | Release (build + publish) | [`release-standalone-ls.yml`](.github/workflows/release-standalone-ls.yml) | `dist: release` — builds the standalone LS jar, uploads it to the CDN, tags the repo `v<version>`, and updates the release marketplace's `marketplace.json` to point at that tag |
110+
111+
(Nightly/on-demand snapshot builds of the plugin are handled separately by
112+
[`snapshot-standalone-ls.yml`](.github/workflows/snapshot-standalone-ls.yml)
113+
and are not part of this manual release process.)
114+
115+
```mermaid
116+
stateDiagram-v2
117+
[*] --> TestLocally
118+
TestLocally --> TestLocally : issues found\n(fix and re-test locally)
119+
TestLocally --> ReleaseAndPublish : tests pass
120+
ReleaseAndPublish --> [*]
121+
```
122+
123+
## Combined view
124+
125+
The three tracks run independently and converge only in the sense that all
126+
are cut, tested, and published for the same overall Spring Tools release —
127+
not that any one of them blocks the others.
128+
129+
```mermaid
130+
stateDiagram-v2
131+
state "Eclipse Track" as Eclipse {
132+
[*] --> ReleaseLSExtensions
133+
ReleaseLSExtensions --> ReleaseDistro
134+
ReleaseDistro --> TestEclipse
135+
TestEclipse --> ReleaseDistro : issues found\n(overwrites staged build)
136+
TestEclipse --> PublishDistro : pass
137+
PublishDistro --> [*]
138+
}
139+
state "VSCode Track" as VSCode {
140+
[*] --> ReleaseVSCodeRC
141+
ReleaseVSCodeRC --> TestVSCode
142+
TestVSCode --> ReleaseVSCodeRC : issues found\n(RC1 -> RC2 -> ...)
143+
TestVSCode --> PublishVSCode : pass
144+
PublishVSCode --> [*]
145+
}
146+
state "Claude Code Plugin Track" as ClaudePlugin {
147+
[*] --> TestLocally
148+
TestLocally --> TestLocally : issues found
149+
TestLocally --> ReleaseAndPublish : pass
150+
ReleaseAndPublish --> [*]
151+
}
152+
```
153+
154+
## Announcements
155+
156+
Once all three tracks above have been published, the release is announced
157+
in four places. This is the last step and covers the whole release, not any
158+
one track:
159+
160+
| Channel | How |
161+
|---|---|
162+
| Eclipse Marketplace | manual — update the listing at marketplace.eclipse.org to point at the new Eclipse distribution |
163+
| spring.io release page | manual — PR against [`spring-io/spring-website-content`](https://github.com/spring-io/spring-website-content) |
164+
| Social media | manual |
165+
| GChat `Spring-Releases` space | [`announce-release.yml`](.github/workflows/announce-release.yml) — input `version` (e.g. `4.20.1.RELEASE`); also posts a notice to the internal Spring Tools team GChat space |
166+
167+
## Prepare the Repo for the Next Version
168+
169+
The very last step, after announcing, is bumping `main` to the next
170+
`-SNAPSHOT` version so every track above is already sitting on an
171+
un-released version by the time the next release cycle starts. This is a
172+
manual, multi-file edit (no script or workflow does it) committed as one
173+
commit — see e.g. `afd629304` ("Bump 2.3.0 5.3.0") or `df8038dc0` ("Bump to
174+
5.4.0") for the pattern to replicate. Each version below is bumped to the
175+
next **minor**:
176+
177+
- **Language servers (`headless-services`)** — the `commons-parent` version
178+
(e.g. `2.4.0-SNAPSHOT` → `2.5.0-SNAPSHOT`) is hardcoded in every
179+
`headless-services/**/pom.xml`'s own `<version>` and `<parent><version>`
180+
and has to be edited in each one by hand.
181+
- **Eclipse plugins** — the parallel `5.x` scheme (e.g.
182+
`5.4.0-SNAPSHOT` → `5.5.0-SNAPSHOT`), hardcoded across
183+
`eclipse-language-servers`, `eclipse-extensions`, and
184+
`eclipse-distribution`: every `pom.xml` `<version>`, every `MANIFEST.MF`
185+
`Bundle-Version`, every `feature.xml` `version`, and the `.product` file.
186+
- **VSCode extensions** — bump `version` in `package.json` (and the
187+
corresponding `CHANGELOG.md` heading) **only for the extension(s) that
188+
were actually released this cycle** — normally just
189+
[`vscode-extensions/vscode-spring-boot/package.json`](vscode-extensions/vscode-spring-boot/package.json).
190+
Extensions that weren't released (`vscode-concourse`,
191+
`vscode-manifest-yaml`, `vscode-bosh`, `boot-dev-pack`) are left alone.
192+
- **Claude Code plugin** — bump `version` in
193+
[`claude-plugins/spring-tools/.claude-plugin/plugin.json`](claude-plugins/spring-tools/.claude-plugin/plugin.json)
194+
to match the new `headless-services` version. This is exactly what makes
195+
the [Claude Code Plugin Track](#claude-code-plugin-track) work: it leaves
196+
`main` on a version that has never been tagged, ready for the next
197+
`release-standalone-ls.yml` run.
198+
199+
**Conditionally — only if a new Eclipse release train shipped this
200+
cycle** — adopt the new target platform:
201+
202+
- Add a new `<profile>` (e.g. `e442`) to
203+
[`eclipse-language-servers/pom.xml`](eclipse-language-servers/pom.xml)
204+
and [`eclipse-distribution/pom.xml`](eclipse-distribution/pom.xml),
205+
mirroring the existing `e440`/`e441` blocks (`dist.target`,
206+
`dist.target.major`, `dist.platform.name`, `dist.platform.name.long`).
207+
- Update the workflows that hardcode which `eclipse_profile`(s) to build:
208+
[`release-eclipse-ls-extensions.yml`](.github/workflows/release-eclipse-ls-extensions.yml)
209+
(currently pinned to `e440` only),
210+
[`release-eclipse-distro-build.yml`](.github/workflows/release-eclipse-distro-build.yml)
211+
(currently builds both `e441` and `e440`, with an older `e435` job already
212+
commented out — that's the pattern for retiring a train), and
213+
`snapshot-all.yml`. `gh-hosted-eclipse-distro-build.yml` and
214+
`eclipse-ls-extensions-build.yml` themselves don't need changes — they're
215+
reusable workflows that just take `eclipse_profile` as an input.
216+
- Also worth checking: `CLAUDE.md`'s "Eclipse profile options" line is
217+
currently stale (`e439`/`e440`) relative to what the poms and release
218+
workflows actually build (`e440`/`e441`) — keep it in sync when adopting
219+
a new train.
220+
221+
Given how tedious and error-prone the manual multi-file version bumps above
222+
are, this whole step is another good candidate for automation.

0 commit comments

Comments
 (0)