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
15 changes: 15 additions & 0 deletions .claude/rules/architecture.md
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,21 @@
only file that spawns. `terminal/` is loaded only with the bundled
Terminal plugin (optional dependency). Verify with `./gradlew build
buildPlugin` there (JDK 21).
- The changelog is written once: `CHANGELOG.md` at the root is the only
one edited by hand. Its versions are the CLI's — the clients ship it, so
one entry covers all three, back to 0.1.0, which predates them. It is
an end-user document, shipped verbatim in the .vsix: release notes
only, nothing about versioning policy or how the copies are made.
The clients' copies —
`editors/vscode/CHANGELOG.md` (the source verbatim) and the
`<change-notes>` block of the JetBrains `plugin.xml` (HTML, the most
recent releases only) — are placeholders in the repository exactly like
the version, stamped by `packaging/changelog/generate` at package time
and never committed: releasing is one commit to `CHANGELOG.md`. The
`make` targets put the placeholder back around a build; the publish
workflows only stamp. `release.yml` takes a release's GitHub notes from
the matching section. Adding a place that publishes a changelog means
adding a target there, not another file to keep in step.
- Logo assets are generated, never hand-edited: `assets/src/logo.svg`
(full size) and `assets/src/logo-icon.svg` (adapted for small formats,
the source of every icon) are the only files touched by hand.
Expand Down
1 change: 1 addition & 0 deletions .github/workflows/publish_idea.yml
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ jobs:
version=$(sed -n 's/^__version__ = "\(.*\)"$/\1/p' "$GITHUB_WORKSPACE/src/workforest/__init__.py")
[ -n "$version" ] || { echo "cannot read __version__" >&2; exit 1; }
echo "PLUGIN_VERSION=$version" >> "$GITHUB_ENV"
"$GITHUB_WORKSPACE/packaging/changelog/generate"
./gradlew --no-daemon -PpluginVersion="$version" build buildPlugin

- name: The zip carries every platform's CLI
Expand Down
1 change: 1 addition & 0 deletions .github/workflows/publish_openvsx.yml
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ jobs:
version=$(sed -n 's/^__version__ = "\(.*\)"$/\1/p' "$GITHUB_WORKSPACE/src/workforest/__init__.py")
[ -n "$version" ] || { echo "cannot read __version__" >&2; exit 1; }
npm pkg set version="$version" name=workforest displayName=Workforest
"$GITHUB_WORKSPACE/packaging/changelog/generate"
echo "packaging $version as $(npm pkg get name | tr -d '\"')"
for target in linux-x64 linux-arm64 darwin-x64 darwin-arm64; do
rm -rf bin && mkdir bin
Expand Down
1 change: 1 addition & 0 deletions .github/workflows/publish_vscode.yml
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ jobs:
version=$(sed -n 's/^__version__ = "\(.*\)"$/\1/p' "$GITHUB_WORKSPACE/src/workforest/__init__.py")
[ -n "$version" ] || { echo "cannot read __version__" >&2; exit 1; }
npm pkg set version="$version"
"$GITHUB_WORKSPACE/packaging/changelog/generate"
echo "packaging $version as $(npm pkg get name | tr -d '\"')"
for target in linux-x64 linux-arm64 darwin-x64 darwin-arm64; do
rm -rf bin && mkdir bin
Expand Down
12 changes: 10 additions & 2 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,17 @@ jobs:
# token do not trigger the release-published publisher workflows.
GH_TOKEN: ${{ secrets.RELEASE_TOKEN }}
run: |
tag="v${{ steps.version.outputs.version }}"
version="${{ steps.version.outputs.version }}"
tag="v$version"
if git ls-remote --exit-code --tags origin "refs/tags/$tag" > /dev/null; then
echo "Tag $tag already exists — nothing to release."
else
gh release create "$tag" --target "$GITHUB_SHA" --generate-notes
# The release's own section of CHANGELOG.md is its notes; a
# version that has none falls back to the commit list.
notes=$(mktemp)
if packaging/changelog/generate --release-notes "$version" > "$notes"; then
gh release create "$tag" --target "$GITHUB_SHA" --notes-file "$notes"
else
gh release create "$tag" --target "$GITHUB_SHA" --generate-notes
fi
fi
115 changes: 115 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
# Changelog

## 0.6.1

- The VS Code extension is published to
[Open VSX](https://open-vsx.org/extension/ArkadyBuryakov/workforest) as
well as the Visual Studio Marketplace, so VSCodium, Cursor, Windsurf and
the other forks install it from the registry they use.
- On the Visual Studio Marketplace the extension is `workforest-vscode`,
shown as **Workforest for VS Code** — the plain name is held there by
another publisher. On Open VSX it stays `workforest`.

## 0.6.0

The first release with editor clients: a VS Code extension and a JetBrains
plugin, each on its marketplace.

Both ship the `workforest` CLI. The package for each platform
(`linux-x64`, `linux-arm64`, `darwin-x64`, `darwin-arm64`) carries a
self-contained executable, and that is the one the client runs — it was
built with the package, so the two always match. Only where the package
has none does a client fall back to `PATH` and the usual install
directories; neither offers a setting for the path.

- VS Code: the Workforest sidebar — a header toolbar (create, open, run
script, checkout, delete, refresh, and more under `…`) over two
collapsible sections, Scripts (run and stop with one click) and
Worktrees (the main checkout, then the managed worktrees by recency,
with dirty markers and the worktree this window is in) — the same
commands in the Command Palette, the merged configuration, config
scaffolding, and a status bar item.
- JetBrains: the Workforest tool window over the same two sections, with
tooltips, inline buttons and context menus; create, open, checkout and
delete worktrees; run and stop scripts in a terminal tab; the current
worktree on the status bar.
- Scripts are marked where they run: the row's icon turns light blue in
this window's worktree and orange in the others, with the instance
counts next to the name. The marks are part of the row, so the run and
stop buttons no longer shift as a script starts or stops.
- Checkout and Delete from the header or the Command Palette act on the
worktree this window is in, after confirming it, instead of asking
which; from the main checkout they still ask.
- Any number of instances of a script may run at once, in one worktree or
across several: each keeps a record and a log of its own
(`WORKTREE.PID.log`) and runs its own `cleanup`, and `wf stop NAME`
stops every instance in the worktree. `exclusive` is what holds a script
to one.
- A group member can set `hidden: true`: it is then left out of shell
completion and the clients' script lists, while `wf run` and `wf stop`
still take its name.

## 0.5.2

- `wf list --json` describes the whole forest for programs.
- The project logo.
- Fixes: `wf init`, and foreground openers run from `workforest` rather
than the `wf` shell function.

## 0.5.1

- Script groups: a `bulk` runs its members at once and relays their output
line by line; a `pipeline` runs them in turn and stops at the first
failure. Both are scripts like any other — `background`, `exclusive`,
`cleanup` and `wf stop` apply to the group.
- Packaging fixes for the AUR package and the Homebrew formula.

## 0.5.0

- Scripts grew up: `background` (or `wf run -b`) detaches a script under a
supervisor of its own with its output in a log, `exclusive` holds one to
a single instance per project, `cleanup` runs when it ends, and
`stop_timeout` bounds SIGTERM before SIGKILL.
- Man pages: `workforest(1)` and `workforest(5)`, installed with the
package.
- Opener shortcuts are gone; openers are named in full.

## 0.4.0

- Openers reworked: one config shape for every kind of opener, with the
window command alongside.

## 0.3.0

- Openers and `window_command` are shell-native — they are the command
line you would type, not a template language.
- Better opener completion: an opener whose name overlaps a command is
left out rather than shadowing it.
- Remote branch resolution across several remotes.
- The Claude Code integration is marked experimental.

## 0.2.3

- Virtual environments are scrubbed from a new worktree instead of being
copied into it.
- Packaging moved to templates rendered at release time, so a release no
longer commits back to the repository.

## 0.2.2

- macOS support, via a Homebrew tap.

## 0.2.0

- Opener variables and placeholders reworked.

## 0.1.1

- The AUR package.

## 0.1.0

First release: worktrees created, opened, and deleted in a predictable
place, with the project's own symlinks and setup scripts run for each; the
`wf` shell function and its alias; `wf run` for the project's `scripts`;
shell completion; PyPI packaging.
21 changes: 17 additions & 4 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,12 @@ PLATFORM := $(shell uname -s | tr '[:upper:]' '[:lower:]')-$(shell uname -m | se
VERSION := $(shell sed -n 's/^__version__ = "\(.*\)"$$/\1/p' src/workforest/__init__.py)
PLACEHOLDER_VERSION := 0.0.0

# The changelog the clients publish is a placeholder in the repository too:
# a release is one commit to CHANGELOG.md. Stamp it in for the build and put
# the placeholder back afterwards, whether the build succeeded or not.
STAMP := packaging/changelog/generate > /dev/null
UNSTAMP := packaging/changelog/generate --placeholder > /dev/null

sync:
uv sync

Expand Down Expand Up @@ -75,8 +81,11 @@ vscode-build: binary
rm -rf editors/vscode/bin && mkdir -p editors/vscode/bin
cp dist/binary/workforest editors/vscode/bin/workforest
cd editors/vscode && rm -f *.vsix && npm install --no-audit --no-fund
@cd editors/vscode && npm pkg set version=$(VERSION) && npm run package; \
status=$$?; npm pkg set version=$(PLACEHOLDER_VERSION); exit $$status
@$(STAMP); \
(cd editors/vscode && npm pkg set version=$(VERSION) && npm run package); \
status=$$?; \
(cd editors/vscode && npm pkg set version=$(PLACEHOLDER_VERSION)); \
$(UNSTAMP); exit $$status

vscode-install:
@vsix=$$(ls -t editors/vscode/*.vsix 2>/dev/null | head -1); \
Expand All @@ -95,7 +104,9 @@ vscode: vscode-build vscode-install
idea-build: binary
rm -rf editors/idea/bin && mkdir -p editors/idea/bin/$(PLATFORM)
cp dist/binary/workforest editors/idea/bin/$(PLATFORM)/workforest
cd editors/idea && JAVA_HOME="$(IDEA_JAVA_HOME)" ./gradlew --quiet -PpluginVersion=$(VERSION) buildPlugin
@$(STAMP); \
(cd editors/idea && JAVA_HOME="$(IDEA_JAVA_HOME)" ./gradlew --quiet -PpluginVersion=$(VERSION) buildPlugin); \
status=$$?; $(UNSTAMP); exit $$status

# All four platforms in one zip: what CI publishes, and what the manual
# first upload to the JetBrains Marketplace needs. PyInstaller only builds
Expand Down Expand Up @@ -127,7 +138,9 @@ idea-build-full:
cp "$$src" editors/idea/bin/$$target/workforest; \
chmod +x editors/idea/bin/$$target/workforest; \
done
cd editors/idea && JAVA_HOME="$(IDEA_JAVA_HOME)" ./gradlew --quiet -PpluginVersion=$(VERSION) buildPlugin
@$(STAMP); \
(cd editors/idea && JAVA_HOME="$(IDEA_JAVA_HOME)" ./gradlew --quiet -PpluginVersion=$(VERSION) buildPlugin); \
status=$$?; $(UNSTAMP); exit $$status
@ls -l editors/idea/build/distributions/workforest-idea-*.zip

# What "Install Plugin from Disk" does: unpack the zip into the plugins dir.
Expand Down
8 changes: 2 additions & 6 deletions editors/idea/src/main/resources/META-INF/plugin.xml
Original file line number Diff line number Diff line change
Expand Up @@ -38,12 +38,8 @@
]]></description>

<change-notes><![CDATA[
<ul>
<li>0.2.0: the workforest CLI ships with the plugin and is the copy it runs — no separate install
needed, and the executable-path setting is gone; running badges on the scripts, one per place with
the instance counts; Delete and Checkout act on this window's worktree.</li>
<li>0.1.0: create, open, checkout, and delete worktrees; run scripts in the terminal; the Workforest tool window.</li>
</ul>
<!-- Generated by packaging/changelog/generate from the CHANGELOG.md at the repository root. Do not edit. -->
<p>Placeholder: the change notes are stamped in at package time, the way the version is. Until then they live <a href="https://github.com/ArkadyBuryakov/workforest/blob/main/CHANGELOG.md">at the repository root</a>.</p>
]]></change-notes>

<depends>com.intellij.modules.platform</depends>
Expand Down
38 changes: 7 additions & 31 deletions editors/vscode/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,33 +1,9 @@
# Changelog

Versions are the `workforest` CLI's: the extension ships that CLI and is
released with it, so its number is stamped in at package time.

## 0.2.0
<!--
Generated by packaging/changelog/generate from the CHANGELOG.md at the
repository root. Do not edit.
-->

The `workforest` CLI ships with the extension: the Marketplace package for
each platform (`linux-x64`, `linux-arm64`, `darwin-x64`, `darwin-arm64`)
carries a self-contained executable, and that is the one the extension
runs — it was built with this .vsix, so the two always match. Only where
the package has none (other platforms, the universal build) does it fall
back to `PATH` and the usual install directories. The
`workforest.executable` setting is gone with it.

- Scripts are marked where they run: the row's icon turns light blue in
this window's worktree and orange in the others, with the instance
counts next to the name. The marks are part of the row, so the run and
stop buttons no longer shift as a script starts or stops.
- Checkout and Delete from the header or the Command Palette act on the
worktree this window is in, after confirming it, instead of asking
which; from the main checkout they still ask.

## 0.1.0
# Changelog

Initial release: the Workforest sidebar — a header toolbar (create, open,
run script, checkout, delete, refresh, and more under `…`) over two
collapsible sections, Scripts (run/stop with one click) and Worktrees
(main checkout, then managed worktrees by recency; dirty markers; the
worktree this window is in) —
create/open/delete/checkout worktrees, run and stop `scripts` in the
integrated terminal, show the merged configuration, scaffold project and
`.vscode/` local configs, status bar item.
Placeholder: the changelog is stamped in at package time, the way the
version is. Until then it lives [at the repository root](https://github.com/ArkadyBuryakov/workforest/blob/main/CHANGELOG.md).
Loading
Loading