workforest 0.5.2__tar.gz → 0.6.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- workforest-0.6.0/.claude/rules/architecture.md +68 -0
- workforest-0.6.0/.github/workflows/assets.yml +42 -0
- workforest-0.6.0/.github/workflows/binaries.yml +56 -0
- workforest-0.6.0/.github/workflows/ci.yml +162 -0
- workforest-0.6.0/.github/workflows/publish_idea.yml +100 -0
- workforest-0.6.0/.github/workflows/publish_vscode.yml +96 -0
- {workforest-0.5.2 → workforest-0.6.0}/.gitignore +10 -0
- workforest-0.6.0/Makefile +147 -0
- {workforest-0.5.2 → workforest-0.6.0}/PKG-INFO +141 -21
- {workforest-0.5.2 → workforest-0.6.0}/README.md +140 -20
- workforest-0.6.0/assets/generate +228 -0
- {workforest-0.5.2 → workforest-0.6.0}/assets/logo-dark.svg +2 -0
- workforest-0.6.0/assets/logo-icon.svg +5 -0
- {workforest-0.5.2 → workforest-0.6.0}/assets/logo-light.svg +2 -0
- workforest-0.6.0/assets/logo.svg +5 -0
- workforest-0.6.0/assets/src/logo-icon.svg +3 -0
- workforest-0.6.0/editors/idea/.gitignore +4 -0
- workforest-0.6.0/editors/idea/README.md +262 -0
- workforest-0.6.0/editors/idea/build.gradle.kts +96 -0
- workforest-0.6.0/editors/idea/gradle/wrapper/gradle-wrapper.jar +0 -0
- workforest-0.6.0/editors/idea/gradle/wrapper/gradle-wrapper.properties +9 -0
- workforest-0.6.0/editors/idea/gradle.properties +8 -0
- workforest-0.6.0/editors/idea/gradlew +248 -0
- workforest-0.6.0/editors/idea/gradlew.bat +82 -0
- workforest-0.6.0/editors/idea/settings.gradle.kts +7 -0
- workforest-0.6.0/editors/idea/src/main/kotlin/pro/buryakov/workforest/idea/Actions.kt +433 -0
- workforest-0.6.0/editors/idea/src/main/kotlin/pro/buryakov/workforest/idea/ActionsUtil.kt +33 -0
- workforest-0.6.0/editors/idea/src/main/kotlin/pro/buryakov/workforest/idea/Bundled.kt +31 -0
- workforest-0.6.0/editors/idea/src/main/kotlin/pro/buryakov/workforest/idea/CreateWorktreeDialog.kt +53 -0
- workforest-0.6.0/editors/idea/src/main/kotlin/pro/buryakov/workforest/idea/Projects.kt +72 -0
- workforest-0.6.0/editors/idea/src/main/kotlin/pro/buryakov/workforest/idea/Protocol.kt +122 -0
- workforest-0.6.0/editors/idea/src/main/kotlin/pro/buryakov/workforest/idea/Recency.kt +59 -0
- workforest-0.6.0/editors/idea/src/main/kotlin/pro/buryakov/workforest/idea/Running.kt +54 -0
- workforest-0.6.0/editors/idea/src/main/kotlin/pro/buryakov/workforest/idea/WorkforestCli.kt +129 -0
- workforest-0.6.0/editors/idea/src/main/kotlin/pro/buryakov/workforest/idea/WorkforestNotifications.kt +107 -0
- workforest-0.6.0/editors/idea/src/main/kotlin/pro/buryakov/workforest/idea/WorkforestSettings.kt +53 -0
- workforest-0.6.0/editors/idea/src/main/kotlin/pro/buryakov/workforest/idea/WorkforestStatusBar.kt +66 -0
- workforest-0.6.0/editors/idea/src/main/kotlin/pro/buryakov/workforest/idea/WorkforestToolWindow.kt +423 -0
- workforest-0.6.0/editors/idea/src/main/kotlin/pro/buryakov/workforest/idea/WorktreeService.kt +214 -0
- workforest-0.6.0/editors/idea/src/main/kotlin/pro/buryakov/workforest/idea/terminal/RunScriptAction.kt +47 -0
- workforest-0.6.0/editors/idea/src/main/resources/META-INF/plugin.xml +163 -0
- workforest-0.6.0/editors/idea/src/main/resources/META-INF/pluginIcon.svg +5 -0
- workforest-0.6.0/editors/idea/src/main/resources/META-INF/pluginIcon_dark.svg +5 -0
- workforest-0.6.0/editors/idea/src/main/resources/META-INF/workforest-terminal.xml +18 -0
- workforest-0.6.0/editors/idea/src/main/resources/icons/toolWindow.svg +5 -0
- workforest-0.6.0/editors/idea/src/main/resources/icons/toolWindow_dark.svg +5 -0
- workforest-0.6.0/editors/idea/src/test/kotlin/pro/buryakov/workforest/idea/BundledTest.kt +34 -0
- workforest-0.6.0/editors/idea/src/test/kotlin/pro/buryakov/workforest/idea/ProtocolTest.kt +127 -0
- workforest-0.6.0/editors/idea/src/test/kotlin/pro/buryakov/workforest/idea/RecencyTest.kt +25 -0
- workforest-0.6.0/editors/idea/src/test/kotlin/pro/buryakov/workforest/idea/RunningTest.kt +45 -0
- workforest-0.6.0/editors/vscode/.vscodeignore +11 -0
- workforest-0.6.0/editors/vscode/CHANGELOG.md +33 -0
- workforest-0.6.0/editors/vscode/LICENSE +21 -0
- workforest-0.6.0/editors/vscode/README.md +130 -0
- workforest-0.6.0/editors/vscode/media/icon.png +0 -0
- workforest-0.6.0/editors/vscode/media/icon.svg +10 -0
- workforest-0.6.0/editors/vscode/media/workforest.svg +5 -0
- workforest-0.6.0/editors/vscode/package-lock.json +3865 -0
- workforest-0.6.0/editors/vscode/package.json +393 -0
- workforest-0.6.0/editors/vscode/scripts/smoke.sh +32 -0
- workforest-0.6.0/editors/vscode/src/cli.ts +169 -0
- workforest-0.6.0/editors/vscode/src/commands.ts +568 -0
- workforest-0.6.0/editors/vscode/src/extension.ts +97 -0
- workforest-0.6.0/editors/vscode/src/forest.ts +261 -0
- workforest-0.6.0/editors/vscode/src/model.ts +277 -0
- workforest-0.6.0/editors/vscode/src/recency.ts +45 -0
- workforest-0.6.0/editors/vscode/src/smoke/index.ts +84 -0
- workforest-0.6.0/editors/vscode/src/test/forest.test.ts +196 -0
- workforest-0.6.0/editors/vscode/src/tree.ts +216 -0
- workforest-0.6.0/editors/vscode/tsconfig.json +20 -0
- {workforest-0.5.2 → workforest-0.6.0}/man/workforest.1 +14 -9
- {workforest-0.5.2 → workforest-0.6.0}/man/workforest.5 +24 -8
- workforest-0.6.0/packaging/binary/build.sh +37 -0
- {workforest-0.5.2 → workforest-0.6.0}/src/workforest/__init__.py +1 -1
- {workforest-0.5.2 → workforest-0.6.0}/src/workforest/cli.py +2 -2
- {workforest-0.5.2 → workforest-0.6.0}/src/workforest/commands.py +12 -4
- {workforest-0.5.2 → workforest-0.6.0}/src/workforest/completions.py +1 -1
- {workforest-0.5.2 → workforest-0.6.0}/src/workforest/config.py +9 -6
- {workforest-0.5.2 → workforest-0.6.0}/src/workforest/examples/.workforest.yaml +7 -2
- {workforest-0.5.2 → workforest-0.6.0}/src/workforest/hooks.py +56 -37
- {workforest-0.5.2 → workforest-0.6.0}/src/workforest/jobs.py +63 -10
- {workforest-0.5.2 → workforest-0.6.0}/tests/test_commands.py +36 -0
- {workforest-0.5.2 → workforest-0.6.0}/tests/test_config.py +7 -0
- {workforest-0.5.2 → workforest-0.6.0}/tests/test_hooks.py +106 -46
- {workforest-0.5.2 → workforest-0.6.0}/tests/test_jobs.py +70 -9
- {workforest-0.5.2 → workforest-0.6.0}/tests/test_shell.py +2 -1
- workforest-0.5.2/.claude/rules/architecture.md +0 -33
- workforest-0.5.2/.github/workflows/ci.yml +0 -55
- workforest-0.5.2/Makefile +0 -33
- {workforest-0.5.2 → workforest-0.6.0}/.claude/rules/conventions.md +0 -0
- {workforest-0.5.2 → workforest-0.6.0}/.claude/rules/tests.md +0 -0
- {workforest-0.5.2 → workforest-0.6.0}/.github/workflows/publish_aur.yml +0 -0
- {workforest-0.5.2 → workforest-0.6.0}/.github/workflows/publish_homebrew.yml +0 -0
- {workforest-0.5.2 → workforest-0.6.0}/.github/workflows/publish_pypi.yml +0 -0
- {workforest-0.5.2 → workforest-0.6.0}/.github/workflows/release.yml +0 -0
- {workforest-0.5.2 → workforest-0.6.0}/LICENSE +0 -0
- {workforest-0.5.2/assets → workforest-0.6.0/assets/src}/logo.svg +0 -0
- {workforest-0.5.2 → workforest-0.6.0}/completions/_workforest +0 -0
- {workforest-0.5.2 → workforest-0.6.0}/man/wf.1 +0 -0
- {workforest-0.5.2 → workforest-0.6.0}/man/wf.5 +0 -0
- {workforest-0.5.2 → workforest-0.6.0}/packaging/AUR/PKGBUILD.template +0 -0
- {workforest-0.5.2 → workforest-0.6.0}/packaging/homebrew/workforest.rb.template +0 -0
- {workforest-0.5.2 → workforest-0.6.0}/pyproject.toml +0 -0
- {workforest-0.5.2 → workforest-0.6.0}/src/workforest/__main__.py +0 -0
- {workforest-0.5.2 → workforest-0.6.0}/src/workforest/errors.py +0 -0
- {workforest-0.5.2 → workforest-0.6.0}/src/workforest/examples/config.yaml +0 -0
- {workforest-0.5.2 → workforest-0.6.0}/src/workforest/gitutil.py +0 -0
- {workforest-0.5.2 → workforest-0.6.0}/src/workforest/integrations/__init__.py +0 -0
- {workforest-0.5.2 → workforest-0.6.0}/src/workforest/integrations/claude.py +0 -0
- {workforest-0.5.2 → workforest-0.6.0}/src/workforest/launch.py +0 -0
- {workforest-0.5.2 → workforest-0.6.0}/src/workforest/output.py +0 -0
- {workforest-0.5.2 → workforest-0.6.0}/src/workforest/shell/completion.bash +0 -0
- {workforest-0.5.2 → workforest-0.6.0}/src/workforest/shell/completion.zsh +0 -0
- {workforest-0.5.2 → workforest-0.6.0}/src/workforest/shell/workforest.sh +0 -0
- {workforest-0.5.2 → workforest-0.6.0}/src/workforest/shellinit.py +0 -0
- {workforest-0.5.2 → workforest-0.6.0}/src/workforest/templates/project.yaml +0 -0
- {workforest-0.5.2 → workforest-0.6.0}/src/workforest/tui.py +0 -0
- {workforest-0.5.2 → workforest-0.6.0}/tests/__init__.py +0 -0
- {workforest-0.5.2 → workforest-0.6.0}/tests/conftest.py +0 -0
- {workforest-0.5.2 → workforest-0.6.0}/tests/test_claude.py +0 -0
- {workforest-0.5.2 → workforest-0.6.0}/tests/test_cli.py +0 -0
- {workforest-0.5.2 → workforest-0.6.0}/tests/test_gitutil.py +0 -0
- {workforest-0.5.2 → workforest-0.6.0}/tests/test_harness.py +0 -0
- {workforest-0.5.2 → workforest-0.6.0}/tests/test_launch.py +0 -0
- {workforest-0.5.2 → workforest-0.6.0}/tests/test_man.py +0 -0
- {workforest-0.5.2 → workforest-0.6.0}/tests/test_output.py +0 -0
- {workforest-0.5.2 → workforest-0.6.0}/tests/test_tui.py +0 -0
- {workforest-0.5.2 → workforest-0.6.0}/uv.lock +0 -0
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
# Architecture invariants
|
|
2
|
+
|
|
3
|
+
- `gitutil.py` is the only module that spawns git. Consumers get typed
|
|
4
|
+
results; worktree data comes from `--porcelain -z` output, never from
|
|
5
|
+
parsing the human-readable form.
|
|
6
|
+
- `cli.py` is the sole stdout writer. Commands return
|
|
7
|
+
`ShellAction | str | None`; stdout carries the shell-wrapper cd protocol,
|
|
8
|
+
so nothing else may print there (hook/script stdout is diverted to stderr).
|
|
9
|
+
- `tui.py`: everything except the fzf subprocess is pure and unit-tested;
|
|
10
|
+
fzf is the only sanctioned external tool there.
|
|
11
|
+
- `completions.py` must never break the shell: any error yields an empty
|
|
12
|
+
candidate list, and output stays plain `NAME<TAB>ANNOTATION` lines.
|
|
13
|
+
- `integrations/claude.py` is experimental: it reads Claude Code's private
|
|
14
|
+
on-disk state. Session lines are rewritten by JSON parsing, never by
|
|
15
|
+
string substitution.
|
|
16
|
+
- The editor plugins ship the CLI they drive: `packaging/binary/build.sh`
|
|
17
|
+
freezes the wheel into one self-contained executable (PyInstaller) per
|
|
18
|
+
platform, which `make vscode-build`/`make idea-build` (this machine's
|
|
19
|
+
platform) and CI (all four) put in `editors/vscode/bin/workforest` (one per
|
|
20
|
+
platform-specific `.vsix`) and `editors/idea/bin/<os>-<arch>/workforest`
|
|
21
|
+
(all of them in one plugin zip). Both trees build fine without it, and
|
|
22
|
+
both run the bundled copy when there is one — it was built with the
|
|
23
|
+
client, so the two always match; only where the package carries none do
|
|
24
|
+
they fall back to `PATH` and the usual install directories. Neither
|
|
25
|
+
client offers a setting for the path, and neither may add a second way to
|
|
26
|
+
obtain the CLI — no downloading, no installing on the user's behalf.
|
|
27
|
+
- `editors/vscode/` (the VS Code extension) is a thin client: it only ever
|
|
28
|
+
spawns `workforest` — never git — and reads its machine output
|
|
29
|
+
(`list --json`, `config --json`, `--complete` lines). Terminal prompts are
|
|
30
|
+
replaced by VS Code dialogs plus `--force`/`--keep-branch`/`--delete-branch`.
|
|
31
|
+
Parsing lives in `forest.ts`, which never imports `vscode` and is
|
|
32
|
+
unit-tested with `node:test`; `cli.ts` is the only module that spawns.
|
|
33
|
+
Verify with `npm run check` there (compile, tests, `vsce package`).
|
|
34
|
+
- README.md is the project reference; there is no separate design document.
|
|
35
|
+
The man pages under `man/` (`workforest.1`, `workforest.5`) are its
|
|
36
|
+
installed counterpart: any change to commands, options, config keys,
|
|
37
|
+
environment variables, or exit codes updates both README.md and the
|
|
38
|
+
affected page in the same change. `tests/test_man.py` catches drift from
|
|
39
|
+
`cli.py`, not from prose — keep the wording in sync by hand.
|
|
40
|
+
- Script groups (`hooks.py`): a `bulk`/`pipeline` runs under a forked
|
|
41
|
+
supervisor that leads the process group and takes the tty exactly like a
|
|
42
|
+
command, so records, `wf stop`, `exclusive`, `cleanup`, and `-b` need no
|
|
43
|
+
group-specific code. Bulk members must never take the tty (only one
|
|
44
|
+
group can own it); they run in the supervisor's process group so a
|
|
45
|
+
signal to the group reaches them all, write to a pty when stderr is a
|
|
46
|
+
terminal (so their programs keep colors) and to a pipe otherwise, and
|
|
47
|
+
the supervisor relays their lines prefixed. A bulk always waits for
|
|
48
|
+
every member. An outcome of `-SIGINT` or exit 130 is an interruption
|
|
49
|
+
(warning, `wf` dies by SIGINT), never a failure. Forked-child bodies are
|
|
50
|
+
`# pragma: no cover`; the logic lives in tested pure helpers
|
|
51
|
+
(`_Prefixer`, `_pump`, `_bulk_outcome`, `_run_step`).
|
|
52
|
+
- `editors/idea/` (the JetBrains plugin) is a thin client like the VS Code
|
|
53
|
+
one: it only ever spawns `workforest` — never git — and reads its machine
|
|
54
|
+
output (`list --json`, `--complete` lines, the last stderr line as the
|
|
55
|
+
error). Terminal prompts are replaced by IDE dialogs plus
|
|
56
|
+
`--force`/`--keep-branch`/`--delete-branch`. Parsing lives in
|
|
57
|
+
`Protocol.kt`, which is pure and unit-tested; `WorkforestCli.kt` is the
|
|
58
|
+
only file that spawns. `terminal/` is loaded only with the bundled
|
|
59
|
+
Terminal plugin (optional dependency). Verify with `./gradlew build
|
|
60
|
+
buildPlugin` there (JDK 21).
|
|
61
|
+
- Logo assets are generated, never hand-edited: `assets/src/logo.svg`
|
|
62
|
+
(full size) and `assets/src/logo-icon.svg` (adapted for small formats,
|
|
63
|
+
the source of every icon) are the only files touched by hand.
|
|
64
|
+
`assets/generate` writes `assets/logo*.svg` plus the icons vendored into
|
|
65
|
+
`editors/vscode/media/` and `editors/idea/.../resources/`; each carries a
|
|
66
|
+
"do not edit" header. Adding a place that ships the logo means adding a
|
|
67
|
+
target there, not another copy. `.github/workflows/assets.yml` re-runs the
|
|
68
|
+
script on pull requests and commits any difference.
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
name: Assets
|
|
2
|
+
|
|
3
|
+
# Every logo asset is derived from assets/src/ by assets/generate. Re-run it
|
|
4
|
+
# whenever a pull request touches the sources or the script, and commit the
|
|
5
|
+
# result — so a redrawn logo only ever has to be redrawn once. Pushes made
|
|
6
|
+
# with GITHUB_TOKEN do not trigger workflows, so this cannot loop.
|
|
7
|
+
|
|
8
|
+
on:
|
|
9
|
+
pull_request:
|
|
10
|
+
paths:
|
|
11
|
+
- assets/**
|
|
12
|
+
- .github/workflows/assets.yml
|
|
13
|
+
|
|
14
|
+
permissions:
|
|
15
|
+
contents: write
|
|
16
|
+
|
|
17
|
+
jobs:
|
|
18
|
+
generate:
|
|
19
|
+
# Forks cannot be pushed to with this token; leave their PRs alone.
|
|
20
|
+
if: github.event.pull_request.head.repo.full_name == github.repository
|
|
21
|
+
runs-on: ubuntu-latest
|
|
22
|
+
steps:
|
|
23
|
+
- uses: actions/checkout@v4
|
|
24
|
+
with:
|
|
25
|
+
ref: ${{ github.head_ref }}
|
|
26
|
+
|
|
27
|
+
- name: Install rsvg-convert
|
|
28
|
+
run: sudo apt-get update && sudo apt-get install -y librsvg2-bin
|
|
29
|
+
|
|
30
|
+
- name: Regenerate assets
|
|
31
|
+
run: assets/generate
|
|
32
|
+
|
|
33
|
+
- name: Commit any difference
|
|
34
|
+
run: |
|
|
35
|
+
if git diff --quiet; then
|
|
36
|
+
echo "assets are up to date"
|
|
37
|
+
exit 0
|
|
38
|
+
fi
|
|
39
|
+
git config user.name "github-actions[bot]"
|
|
40
|
+
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
|
|
41
|
+
git commit -am "Regenerate assets"
|
|
42
|
+
git push
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
name: Binaries
|
|
2
|
+
|
|
3
|
+
# The self-contained `workforest` executables the editor plugins ship, one
|
|
4
|
+
# per platform (packaging/binary/build.sh). PyInstaller freezes for the
|
|
5
|
+
# machine it runs on, so every target is built on a runner of its own.
|
|
6
|
+
# Artifacts are named workforest-binary-<os>-<arch>, which is both the
|
|
7
|
+
# `vsce package --target` identifier and the bin/<os>-<arch>/ directory the
|
|
8
|
+
# JetBrains plugin looks under.
|
|
9
|
+
#
|
|
10
|
+
# Called by the publish workflows, dispatchable on its own, and run for a
|
|
11
|
+
# pull request that touches the CLI these executables freeze — which is
|
|
12
|
+
# where `make idea-build-full` gets the three platforms a single machine
|
|
13
|
+
# cannot build. A pull request that leaves the CLI alone reuses whatever
|
|
14
|
+
# run built it last: the binaries would be identical anyway.
|
|
15
|
+
#
|
|
16
|
+
# ci.yml builds linux-x64 of its own on every pull request, smoke-tests it,
|
|
17
|
+
# and packages the editor clients around it; this is the full set, only
|
|
18
|
+
# when it can differ.
|
|
19
|
+
|
|
20
|
+
on:
|
|
21
|
+
workflow_call:
|
|
22
|
+
workflow_dispatch:
|
|
23
|
+
pull_request:
|
|
24
|
+
paths:
|
|
25
|
+
- src/**
|
|
26
|
+
- pyproject.toml
|
|
27
|
+
- uv.lock
|
|
28
|
+
- packaging/binary/**
|
|
29
|
+
- .github/workflows/binaries.yml
|
|
30
|
+
|
|
31
|
+
jobs:
|
|
32
|
+
build:
|
|
33
|
+
strategy:
|
|
34
|
+
matrix:
|
|
35
|
+
include:
|
|
36
|
+
- target: linux-x64
|
|
37
|
+
os: ubuntu-latest
|
|
38
|
+
- target: linux-arm64
|
|
39
|
+
os: ubuntu-24.04-arm
|
|
40
|
+
- target: darwin-x64
|
|
41
|
+
os: macos-26-intel # the standard x86_64 macOS runner
|
|
42
|
+
- target: darwin-arm64
|
|
43
|
+
os: macos-latest
|
|
44
|
+
runs-on: ${{ matrix.os }}
|
|
45
|
+
steps:
|
|
46
|
+
- uses: actions/checkout@v4
|
|
47
|
+
|
|
48
|
+
- uses: astral-sh/setup-uv@v5
|
|
49
|
+
|
|
50
|
+
- name: Build the standalone executable
|
|
51
|
+
run: packaging/binary/build.sh
|
|
52
|
+
|
|
53
|
+
- uses: actions/upload-artifact@v4
|
|
54
|
+
with:
|
|
55
|
+
name: workforest-binary-${{ matrix.target }}
|
|
56
|
+
path: dist/binary/workforest
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
pull_request:
|
|
7
|
+
|
|
8
|
+
jobs:
|
|
9
|
+
check:
|
|
10
|
+
runs-on: ubuntu-latest
|
|
11
|
+
container: archlinux:latest
|
|
12
|
+
steps:
|
|
13
|
+
- name: Install system dependencies
|
|
14
|
+
run: pacman -Syu --noconfirm git python uv make zsh groff
|
|
15
|
+
|
|
16
|
+
- uses: actions/checkout@v4
|
|
17
|
+
|
|
18
|
+
- name: Sync dev environment
|
|
19
|
+
run: uv sync
|
|
20
|
+
|
|
21
|
+
- name: Lint, type-check, test
|
|
22
|
+
run: make check
|
|
23
|
+
|
|
24
|
+
package-smoke:
|
|
25
|
+
# Builds the wheel the AUR package would build and installs it into a
|
|
26
|
+
# clean venv — catches missing package data and broken entry points.
|
|
27
|
+
# The full `makepkg -si` + namcap check runs in the release workflow,
|
|
28
|
+
# where a source tarball exists.
|
|
29
|
+
runs-on: ubuntu-latest
|
|
30
|
+
container: archlinux:latest
|
|
31
|
+
steps:
|
|
32
|
+
- name: Install system dependencies
|
|
33
|
+
run: pacman -Syu --noconfirm git python python-build python-installer python-wheel python-hatchling man-db
|
|
34
|
+
|
|
35
|
+
- uses: actions/checkout@v4
|
|
36
|
+
|
|
37
|
+
- name: Build wheel (no isolation, like the PKGBUILD)
|
|
38
|
+
run: python -m build --wheel --no-isolation
|
|
39
|
+
|
|
40
|
+
- name: Install into a clean venv and smoke test
|
|
41
|
+
run: |
|
|
42
|
+
python -m venv /tmp/venv
|
|
43
|
+
/tmp/venv/bin/pip install dist/*.whl
|
|
44
|
+
/tmp/venv/bin/workforest --version
|
|
45
|
+
/tmp/venv/bin/wf --version
|
|
46
|
+
/tmp/venv/bin/workforest shell-init bash | bash -n
|
|
47
|
+
/tmp/venv/bin/workforest shell-init zsh | head -1 | grep -q Workforest
|
|
48
|
+
# man pages ride along in the wheel's share/man data, and shell-init
|
|
49
|
+
# puts that directory on $MANPATH for venv installs
|
|
50
|
+
MANPATH=/tmp/venv/share/man man -w workforest wf 5 workforest wf
|
|
51
|
+
/tmp/venv/bin/workforest shell-init bash | grep -q 'MANPATH=/tmp/venv/share/man'
|
|
52
|
+
# the init starter is package data too
|
|
53
|
+
git init -q /tmp/repo
|
|
54
|
+
(cd /tmp/repo && /tmp/venv/bin/workforest init)
|
|
55
|
+
test -s /tmp/repo/.workforest.yaml
|
|
56
|
+
|
|
57
|
+
binary:
|
|
58
|
+
# The self-contained executable the editor plugins ship
|
|
59
|
+
# (packaging/binary/build.sh). Only linux-x64 here, to keep PRs cheap:
|
|
60
|
+
# the other three platforms are built when publishing.
|
|
61
|
+
runs-on: ubuntu-latest
|
|
62
|
+
steps:
|
|
63
|
+
- uses: actions/checkout@v4
|
|
64
|
+
|
|
65
|
+
- uses: astral-sh/setup-uv@v5
|
|
66
|
+
|
|
67
|
+
- name: Build the standalone executable
|
|
68
|
+
run: packaging/binary/build.sh
|
|
69
|
+
|
|
70
|
+
- name: Smoke test it (no Python, no venv, package data intact)
|
|
71
|
+
run: |
|
|
72
|
+
bin=$PWD/dist/binary/workforest
|
|
73
|
+
"$bin" --version
|
|
74
|
+
"$bin" shell-init bash | bash -n
|
|
75
|
+
git init -q /tmp/repo
|
|
76
|
+
cd /tmp/repo && "$bin" init && test -s .workforest.yaml
|
|
77
|
+
|
|
78
|
+
- uses: actions/upload-artifact@v4
|
|
79
|
+
with:
|
|
80
|
+
name: workforest-binary-linux-x64
|
|
81
|
+
path: dist/binary/workforest
|
|
82
|
+
|
|
83
|
+
vscode-extension:
|
|
84
|
+
# editors/vscode: compile, unit tests (node:test, no VS Code download),
|
|
85
|
+
# and the platform-specific .vsix that carries the CLI in bin/.
|
|
86
|
+
needs: binary
|
|
87
|
+
runs-on: ubuntu-latest
|
|
88
|
+
defaults:
|
|
89
|
+
run:
|
|
90
|
+
working-directory: editors/vscode
|
|
91
|
+
steps:
|
|
92
|
+
- uses: actions/checkout@v4
|
|
93
|
+
|
|
94
|
+
- uses: actions/setup-node@v4
|
|
95
|
+
with:
|
|
96
|
+
node-version: 22
|
|
97
|
+
cache: npm
|
|
98
|
+
cache-dependency-path: editors/vscode/package-lock.json
|
|
99
|
+
|
|
100
|
+
- uses: actions/download-artifact@v4
|
|
101
|
+
with:
|
|
102
|
+
name: workforest-binary-linux-x64
|
|
103
|
+
path: editors/vscode/bin
|
|
104
|
+
|
|
105
|
+
- name: Make the bundled CLI executable
|
|
106
|
+
run: chmod +x bin/workforest
|
|
107
|
+
|
|
108
|
+
- name: Install
|
|
109
|
+
run: npm ci
|
|
110
|
+
|
|
111
|
+
- name: Compile and test
|
|
112
|
+
run: npm test
|
|
113
|
+
|
|
114
|
+
- name: Package for linux-x64
|
|
115
|
+
run: npm run package -- --target linux-x64
|
|
116
|
+
|
|
117
|
+
- name: The .vsix carries the CLI
|
|
118
|
+
run: unzip -l workforest-linux-x64-*.vsix | grep -q 'extension/bin/workforest'
|
|
119
|
+
|
|
120
|
+
- uses: actions/upload-artifact@v4
|
|
121
|
+
with:
|
|
122
|
+
name: workforest-vscode
|
|
123
|
+
path: editors/vscode/*.vsix
|
|
124
|
+
|
|
125
|
+
plugin-idea:
|
|
126
|
+
# The JetBrains plugin under editors/idea: compile, unit tests, and the
|
|
127
|
+
# plugin zip, which carries one CLI per platform under bin/<os>-<arch>/
|
|
128
|
+
# (only linux-x64 here; a published build ships all four).
|
|
129
|
+
# verifyPlugin (downloads IDEs) is run by hand.
|
|
130
|
+
needs: binary
|
|
131
|
+
runs-on: ubuntu-latest
|
|
132
|
+
defaults:
|
|
133
|
+
run:
|
|
134
|
+
working-directory: editors/idea
|
|
135
|
+
steps:
|
|
136
|
+
- uses: actions/checkout@v4
|
|
137
|
+
|
|
138
|
+
- uses: actions/setup-java@v4
|
|
139
|
+
with:
|
|
140
|
+
distribution: temurin
|
|
141
|
+
java-version: 21
|
|
142
|
+
|
|
143
|
+
- uses: gradle/actions/setup-gradle@v4
|
|
144
|
+
|
|
145
|
+
- uses: actions/download-artifact@v4
|
|
146
|
+
with:
|
|
147
|
+
name: workforest-binary-linux-x64
|
|
148
|
+
path: editors/idea/bin/linux-x64
|
|
149
|
+
|
|
150
|
+
- name: Make the bundled CLI executable
|
|
151
|
+
run: chmod +x bin/linux-x64/workforest
|
|
152
|
+
|
|
153
|
+
- name: Compile, test, package
|
|
154
|
+
run: ./gradlew --no-daemon build buildPlugin
|
|
155
|
+
|
|
156
|
+
- name: The plugin zip carries the CLI
|
|
157
|
+
run: unzip -l build/distributions/*.zip | grep -q 'bin/linux-x64/workforest'
|
|
158
|
+
|
|
159
|
+
- uses: actions/upload-artifact@v4
|
|
160
|
+
with:
|
|
161
|
+
name: workforest-idea
|
|
162
|
+
path: editors/idea/build/distributions/*.zip
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
name: Publish JetBrains plugin
|
|
2
|
+
|
|
3
|
+
# Publishes editors/idea to the JetBrains Marketplace when a release is
|
|
4
|
+
# published, or on demand. One zip carrying the `workforest` executable for
|
|
5
|
+
# every platform (packaging/binary/build.sh) under bin/<os>-<arch>/, so
|
|
6
|
+
# installing the plugin is enough — no separate CLI install.
|
|
7
|
+
#
|
|
8
|
+
# The plugin has no version of its own: gradle.properties carries a
|
|
9
|
+
# placeholder and the build is passed the CLI's __version__, so what the
|
|
10
|
+
# Marketplace serves is always the release frozen inside it. A version
|
|
11
|
+
# already on the Marketplace is skipped, which makes a re-run of an old
|
|
12
|
+
# release a no-op. Needs the JB_PUBLISH_TOKEN secret (a
|
|
13
|
+
# Marketplace permanent token, plugins.jetbrains.com/author/me/tokens);
|
|
14
|
+
# without it the publish step is skipped. The environment variable it
|
|
15
|
+
# becomes has to be PUBLISH_TOKEN — that name is the Gradle plugin's, the
|
|
16
|
+
# secret's says which marketplace it opens.
|
|
17
|
+
#
|
|
18
|
+
# Only updates go through here: the Marketplace upload API updates an
|
|
19
|
+
# existing plugin, it cannot create one. pro.buryakov.workforest (id 34090)
|
|
20
|
+
# was uploaded by hand once and reviewed by the Marketplace team.
|
|
21
|
+
#
|
|
22
|
+
# The zip is published unsigned, which makes the IDE warn on install. To
|
|
23
|
+
# sign it, add the CERTIFICATE_CHAIN, PRIVATE_KEY and PRIVATE_KEY_PASSWORD
|
|
24
|
+
# secrets and pass them to the publish step as env — the Gradle plugin
|
|
25
|
+
# reads exactly those names and runs signPlugin before publishPlugin. Set
|
|
26
|
+
# them only once they exist: an empty value is still a value, and signing
|
|
27
|
+
# with one fails.
|
|
28
|
+
|
|
29
|
+
on:
|
|
30
|
+
release:
|
|
31
|
+
types: [published]
|
|
32
|
+
workflow_dispatch:
|
|
33
|
+
|
|
34
|
+
jobs:
|
|
35
|
+
# The CLI the zip ships, one per platform.
|
|
36
|
+
binaries:
|
|
37
|
+
uses: ./.github/workflows/binaries.yml
|
|
38
|
+
|
|
39
|
+
publish:
|
|
40
|
+
needs: binaries
|
|
41
|
+
runs-on: ubuntu-latest
|
|
42
|
+
environment:
|
|
43
|
+
name: jetbrains-marketplace
|
|
44
|
+
url: https://plugins.jetbrains.com/plugin/34090-workforest
|
|
45
|
+
permissions:
|
|
46
|
+
contents: read
|
|
47
|
+
defaults:
|
|
48
|
+
run:
|
|
49
|
+
working-directory: editors/idea
|
|
50
|
+
env:
|
|
51
|
+
PUBLISH_TOKEN: ${{ secrets.JB_PUBLISH_TOKEN }}
|
|
52
|
+
# The Marketplace's own id for pro.buryakov.workforest; the updates
|
|
53
|
+
# API takes that, not the plugin's xml id.
|
|
54
|
+
PLUGIN_ID: "34090"
|
|
55
|
+
steps:
|
|
56
|
+
- uses: actions/checkout@v4
|
|
57
|
+
|
|
58
|
+
- uses: actions/setup-java@v4
|
|
59
|
+
with:
|
|
60
|
+
distribution: temurin
|
|
61
|
+
java-version: 21
|
|
62
|
+
|
|
63
|
+
- uses: gradle/actions/setup-gradle@v4
|
|
64
|
+
|
|
65
|
+
- uses: actions/download-artifact@v4
|
|
66
|
+
with:
|
|
67
|
+
pattern: workforest-binary-*
|
|
68
|
+
path: ${{ github.workspace }}/binaries
|
|
69
|
+
|
|
70
|
+
- name: Lay the executables out the way the plugin resolves them
|
|
71
|
+
run: |
|
|
72
|
+
for target in linux-x64 linux-arm64 darwin-x64 darwin-arm64; do
|
|
73
|
+
mkdir -p "bin/$target"
|
|
74
|
+
cp "$GITHUB_WORKSPACE/binaries/workforest-binary-$target/workforest" "bin/$target/workforest"
|
|
75
|
+
chmod +x "bin/$target/workforest"
|
|
76
|
+
done
|
|
77
|
+
ls -l bin/*
|
|
78
|
+
|
|
79
|
+
- name: Compile, test, package as the version of the CLI it ships
|
|
80
|
+
run: |
|
|
81
|
+
version=$(sed -n 's/^__version__ = "\(.*\)"$/\1/p' "$GITHUB_WORKSPACE/src/workforest/__init__.py")
|
|
82
|
+
[ -n "$version" ] || { echo "cannot read __version__" >&2; exit 1; }
|
|
83
|
+
echo "PLUGIN_VERSION=$version" >> "$GITHUB_ENV"
|
|
84
|
+
./gradlew --no-daemon -PpluginVersion="$version" build buildPlugin
|
|
85
|
+
|
|
86
|
+
- name: The zip carries every platform's CLI
|
|
87
|
+
run: |
|
|
88
|
+
for target in linux-x64 linux-arm64 darwin-x64 darwin-arm64; do
|
|
89
|
+
unzip -l build/distributions/*.zip | grep -q "bin/$target/workforest"
|
|
90
|
+
done
|
|
91
|
+
|
|
92
|
+
- name: Publish
|
|
93
|
+
if: env.PUBLISH_TOKEN != ''
|
|
94
|
+
run: |
|
|
95
|
+
if curl -fsS "https://plugins.jetbrains.com/api/plugins/$PLUGIN_ID/updates" \
|
|
96
|
+
| jq -e --arg v "$PLUGIN_VERSION" 'any(.[]; .version == $v)' > /dev/null; then
|
|
97
|
+
echo "workforest $PLUGIN_VERSION is already on the JetBrains Marketplace — nothing to publish."
|
|
98
|
+
else
|
|
99
|
+
./gradlew --no-daemon -PpluginVersion="$PLUGIN_VERSION" publishPlugin
|
|
100
|
+
fi
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
name: Publish VS Code extension
|
|
2
|
+
|
|
3
|
+
# Publishes editors/vscode to the Visual Studio Marketplace when a release
|
|
4
|
+
# is published, or on demand. One .vsix per platform, each carrying the
|
|
5
|
+
# `workforest` executable for it (packaging/binary/build.sh), so installing
|
|
6
|
+
# the extension is enough — no separate CLI install. Linux and macOS only:
|
|
7
|
+
# that is what workforest supports.
|
|
8
|
+
#
|
|
9
|
+
# The extension has no version of its own: package.json carries a
|
|
10
|
+
# placeholder and the packaging step stamps it with the CLI's __version__,
|
|
11
|
+
# so what the Marketplace serves is always the release frozen inside it. A
|
|
12
|
+
# version already on the Marketplace is skipped, which makes a re-run of an
|
|
13
|
+
# old release a no-op. Needs the VSCE_PAT secret (a
|
|
14
|
+
# Marketplace personal access token for the publisher in package.json);
|
|
15
|
+
# without it the publish step is skipped.
|
|
16
|
+
#
|
|
17
|
+
# That token is an Azure DevOps *global* PAT ("All accessible organizations",
|
|
18
|
+
# scope Marketplace/Manage) — the Marketplace accepts nothing narrower, and
|
|
19
|
+
# global PATs are decommissioned on 2026-12-01. Before then this job has to
|
|
20
|
+
# move to Microsoft Entra (`vsce publish --azure-credential`, a user-assigned
|
|
21
|
+
# managed identity added as a member of the publisher) or to trusted
|
|
22
|
+
# publishing (`vsce publish --oidc`, no secret at all) once that ships — it is
|
|
23
|
+
# in vsce's main branch but not in a release as of 3.9.2.
|
|
24
|
+
|
|
25
|
+
on:
|
|
26
|
+
release:
|
|
27
|
+
types: [published]
|
|
28
|
+
workflow_dispatch:
|
|
29
|
+
|
|
30
|
+
jobs:
|
|
31
|
+
# The CLI each .vsix ships, one per platform.
|
|
32
|
+
binaries:
|
|
33
|
+
uses: ./.github/workflows/binaries.yml
|
|
34
|
+
|
|
35
|
+
publish:
|
|
36
|
+
needs: binaries
|
|
37
|
+
runs-on: ubuntu-latest
|
|
38
|
+
environment:
|
|
39
|
+
name: vscode-marketplace
|
|
40
|
+
url: https://marketplace.visualstudio.com/items?itemName=ArkadyBuryakov.workforest
|
|
41
|
+
permissions:
|
|
42
|
+
contents: read
|
|
43
|
+
defaults:
|
|
44
|
+
run:
|
|
45
|
+
working-directory: editors/vscode
|
|
46
|
+
env:
|
|
47
|
+
VSCE_PAT: ${{ secrets.VSCE_PAT }}
|
|
48
|
+
steps:
|
|
49
|
+
- uses: actions/checkout@v4
|
|
50
|
+
|
|
51
|
+
- uses: actions/setup-node@v4
|
|
52
|
+
with:
|
|
53
|
+
node-version: 22
|
|
54
|
+
cache: npm
|
|
55
|
+
cache-dependency-path: editors/vscode/package-lock.json
|
|
56
|
+
|
|
57
|
+
- uses: actions/download-artifact@v4
|
|
58
|
+
with:
|
|
59
|
+
pattern: workforest-binary-*
|
|
60
|
+
path: ${{ github.workspace }}/binaries
|
|
61
|
+
|
|
62
|
+
- name: Install
|
|
63
|
+
run: npm ci
|
|
64
|
+
|
|
65
|
+
- name: Compile and test
|
|
66
|
+
run: npm test
|
|
67
|
+
|
|
68
|
+
- name: Stamp the extension with the version of the CLI it ships
|
|
69
|
+
run: |
|
|
70
|
+
version=$(sed -n 's/^__version__ = "\(.*\)"$/\1/p' "$GITHUB_WORKSPACE/src/workforest/__init__.py")
|
|
71
|
+
[ -n "$version" ] || { echo "cannot read __version__" >&2; exit 1; }
|
|
72
|
+
npm pkg set version="$version"
|
|
73
|
+
echo "packaging $version"
|
|
74
|
+
|
|
75
|
+
- name: Package one .vsix per platform, each with its own CLI
|
|
76
|
+
run: |
|
|
77
|
+
for target in linux-x64 linux-arm64 darwin-x64 darwin-arm64; do
|
|
78
|
+
rm -rf bin && mkdir bin
|
|
79
|
+
cp "$GITHUB_WORKSPACE/binaries/workforest-binary-$target/workforest" bin/workforest
|
|
80
|
+
chmod +x bin/workforest
|
|
81
|
+
npx vsce package --no-dependencies --target "$target"
|
|
82
|
+
done
|
|
83
|
+
ls -l ./*.vsix
|
|
84
|
+
|
|
85
|
+
- name: Publish
|
|
86
|
+
if: env.VSCE_PAT != ''
|
|
87
|
+
run: |
|
|
88
|
+
version=$(node -p "require('./package.json').version")
|
|
89
|
+
publisher=$(node -p "require('./package.json').publisher")
|
|
90
|
+
name=$(node -p "require('./package.json').name")
|
|
91
|
+
if npx vsce show "$publisher.$name" --json 2>/dev/null \
|
|
92
|
+
| node -e "let d='';process.stdin.on('data',c=>d+=c).on('end',()=>process.exit(JSON.parse(d).versions.some(v=>v.version==='$version')?0:1))"; then
|
|
93
|
+
echo "$publisher.$name@$version is already on the Marketplace — nothing to publish."
|
|
94
|
+
else
|
|
95
|
+
npx vsce publish --no-dependencies --packagePath workforest-*.vsix
|
|
96
|
+
fi
|
|
@@ -24,5 +24,15 @@ packaging/AUR/PKGBUILD
|
|
|
24
24
|
packaging/AUR/.SRCINFO
|
|
25
25
|
packaging/homebrew/workforest.rb
|
|
26
26
|
|
|
27
|
+
# VS Code extension (editors/vscode)
|
|
28
|
+
node_modules/
|
|
29
|
+
editors/vscode/out/
|
|
30
|
+
*.vsix
|
|
31
|
+
|
|
32
|
+
# Bundled CLI binaries: built by packaging/binary/build.sh at package time
|
|
33
|
+
editors/vscode/bin/
|
|
34
|
+
editors/idea/bin/
|
|
35
|
+
|
|
27
36
|
# Tooling config
|
|
28
37
|
/.workforest.yaml
|
|
38
|
+
/Makefile.local
|