turnout-cli 0.27.0 → 1.0.0
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.
- package/README.md +27 -100
- package/download.js +1 -0
- package/package.json +2 -2
- package/run.js +24 -1
package/README.md
CHANGED
|
@@ -13,11 +13,11 @@
|
|
|
13
13
|
|
|
14
14
|
Working against several backend stands scatters the day: you `cd` into a folder to start a project, edit `.env` files across repositories to switch a stand, dig through notes for a password, and keep deploy paths in your head.
|
|
15
15
|
|
|
16
|
-
turnout keeps all of it in one place and works from any directory.
|
|
16
|
+
turnout keeps all of it in one place and works from any directory. What it is, on one screen: [lacodda.github.io/turnout/what-is-turnout](https://lacodda.github.io/turnout/what-is-turnout/).
|
|
17
17
|
|
|
18
18
|
## A day in the life
|
|
19
19
|
|
|
20
|
-
Point an app at a stand:
|
|
20
|
+
Point an app at a stand - the app keeps talking to `localhost`, and the [gateway](https://lacodda.github.io/turnout/concepts/gateway/) routes it there, with a cookie jar per app **and** stand so the switch does not log you out:
|
|
21
21
|
|
|
22
22
|
```console
|
|
23
23
|
$ turnout use web staging
|
|
@@ -26,9 +26,7 @@ The running gateway picks this up automatically.
|
|
|
26
26
|
'staging' is up: https://staging.example.com/health answered 200 in 84 ms.
|
|
27
27
|
```
|
|
28
28
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
Start working, from wherever you happen to be:
|
|
29
|
+
Start working, from wherever you happen to be. The console stays quiet once the server is up - until something breaks:
|
|
32
30
|
|
|
33
31
|
```console
|
|
34
32
|
$ cd ~/dev/web/src/components
|
|
@@ -38,136 +36,72 @@ $ turnout dev --open
|
|
|
38
36
|
◇ web ready in 1.4s - http://web.localhost
|
|
39
37
|
```
|
|
40
38
|
|
|
41
|
-
|
|
42
|
-
until something breaks, which is when you want it loud.
|
|
43
|
-
|
|
44
|
-
Move the whole contour at once when the frontend and the API must agree:
|
|
45
|
-
|
|
46
|
-
```console
|
|
47
|
-
$ turnout use contour prod-eu
|
|
48
|
-
Group 'contour' now uses 'prod-eu':
|
|
49
|
-
web -> prod-eu
|
|
50
|
-
api -> prod-eu
|
|
51
|
-
```
|
|
52
|
-
|
|
53
|
-
Forgot a name? Leave it out and pick from a list that shows where things point:
|
|
54
|
-
|
|
55
|
-
```console
|
|
56
|
-
$ turnout use
|
|
57
|
-
? Switch ›
|
|
58
|
-
❯ contour group: web, api
|
|
59
|
-
api -> staging
|
|
60
|
-
web -> staging
|
|
61
|
-
```
|
|
62
|
-
|
|
63
|
-
Ship it:
|
|
39
|
+
Ship it - build, back up, upload as one archive, restart, and ask the stand whether it works:
|
|
64
40
|
|
|
65
41
|
```console
|
|
66
42
|
$ turnout deploy web-prod-eu -b
|
|
67
43
|
[web] pnpm build
|
|
68
44
|
✓ Connected to deploy@prod-eu.example.com:22
|
|
69
45
|
✓ Backup 20260809-011500.tar.gz created in /var/www/web.backups
|
|
70
|
-
================> 2.02 MiB/3.11 MiB · 1.81 MiB/s · eta 1s assets/index-b3f0a1.js
|
|
71
46
|
Uploaded 142 files (3.11 MiB) to prod-eu:/var/www/web
|
|
72
47
|
✓ Restarted: systemctl restart web
|
|
73
48
|
✓ Healthy: GET https://prod-eu.example.com/health - 200 in 38 ms
|
|
74
49
|
Deploy of 'web' to 'prod-eu' finished.
|
|
75
50
|
```
|
|
76
51
|
|
|
77
|
-
Every long flag has a short form, and nothing runs silently: the upload reports throughput and an ETA, and the steps that talk to the server say so while they wait.
|
|
78
|
-
|
|
79
52
|
And see what has been going on:
|
|
80
53
|
|
|
81
54
|
```console
|
|
82
55
|
$ turnout status
|
|
83
|
-
turnout 0.
|
|
56
|
+
turnout 1.0.0 ~/.local/share/lacodda/turnout
|
|
84
57
|
|
|
85
58
|
Apps
|
|
86
59
|
api -> staging http://api.localhost spare :7101 (TURNOUT_GATEWAY_URL)
|
|
87
60
|
web -> prod-eu http://web.localhost spare :7100 (VITE_API_URL)
|
|
88
61
|
|
|
89
62
|
Gateway running · pid 24180 · up 2h 05m
|
|
90
|
-
front door http://localhost
|
|
91
63
|
! 'staging' answers 502 - the stand is down, not the app (3m)
|
|
92
64
|
|
|
93
65
|
Jobs 2 running - `turnout ps` shows the rest
|
|
94
|
-
api dev ready 9m http://api.localhost
|
|
95
|
-
web dev ready 14m http://web.localhost
|
|
96
66
|
|
|
97
67
|
Recent
|
|
98
68
|
3m ago deploy web -> prod-eu (142 files)
|
|
99
|
-
6m ago use web -> prod-eu
|
|
100
|
-
|
|
101
|
-
$ turnout status --short
|
|
102
|
-
prod-eu · gw ok · 2 dev
|
|
103
69
|
```
|
|
104
70
|
|
|
105
71
|
## What you get
|
|
106
72
|
|
|
107
|
-
- **A dev gateway.**
|
|
108
|
-
- **
|
|
109
|
-
- **
|
|
110
|
-
- **
|
|
111
|
-
- **
|
|
112
|
-
- **
|
|
113
|
-
- **
|
|
114
|
-
- **
|
|
115
|
-
- **Commands from any directory.** `dev`, `build`, `test`, `lint` and any custom command run in the right project folder. Commands are taken from your actual `package.json` scripts, so a project whose dev script is `serve` still answers to `turnout dev`.
|
|
116
|
-
- **A quiet console.** A build shows a loader and its elapsed time, not two minutes of scrollback; a dev server goes quiet once it reports itself and speaks again only when something breaks. A failure prints its output on the spot - no re-run to see what went wrong - and every job's output is kept in a log file whatever the terminal showed. `-v` gives you all of it, and so does any pipe, so scripts and CI logs are unchanged.
|
|
117
|
-
- **Jobs in the background.** `turnout dev --detach` gives the terminal back and the server keeps running; so do `build`, `run` and `deploy`. When one is done, a desktop notification says so and opens the page, the stand or the log of the failure. `turnout ps` shows everything turnout runs, `logs -f` follows any of it, and `stop` takes a job down with every process it started.
|
|
118
|
-
- **A hand on the server.** `turnout ssh web-prod` opens a session with host, port, user and key from the catalogs, in the deploy directory, the password already on the clipboard; `turnout exec web-prod -- docker compose ps` runs one command there and hands back its exit code.
|
|
119
|
-
- **Deploy over SSH/SFTP** - build, upload, restart, with remote backup and restore. Artifacts travel as a single archive instead of thousands of round trips. Linux and Windows servers alike: turnout detects which shell answers SSH and phrases every remote command in it.
|
|
120
|
-
- **A deploy that checks itself.** Give a target a health check and a deploy asks the stand after the restart - and rolls it back when it does not answer. `--diff` shows what would change before anything is written; `deploy web-stage web-prod` ships one build to both; a long restart survives a dropped connection.
|
|
121
|
-
- **A history of deploys, and the way back.** Every deploy is recorded with its version, commit and how it ended - files uploaded but the restart failed included, with what the restart said. `turnout history` lists them, `history --diff 12 14` shows the commits between two, and `turnout rollback` sends the build before back to the stand. Server backups are pruned to what each stand keeps.
|
|
122
|
-
- **Portable settings.** `export` writes your apps, servers, credentials, paths, targets and groups to one file and `import` merges it on another machine; secrets come along only when you ask, sealed with a passphrase.
|
|
123
|
-
- **Stays current.** A once-a-day check mentions a new release without ever delaying a command, and `self-update` installs it - leaving package-manager installs to their package manager.
|
|
124
|
-
- **One window onto it all.** `status` shows where every app points, the gateway, running jobs and the latest actions, with clickable addresses; `status --short` puts `prod · gw ok · 2 dev` into a starship or tmux line; `use -` goes back to the stand before. Every command that reports takes `--json`.
|
|
125
|
-
- **A gateway that speaks up.** A stand answering 502 or a session the stand refused shows in `status` and the prompt line, and once on the desktop - not as a mystery in your app. Stands behind single sign-on get their browser session handed over with `turnout cookie set`.
|
|
126
|
-
- **A doctor.** `turnout doctor` answers "why does it not work": a dev server left on the app's port, a dotenv file naming an old port, a stand that is down, a session that lapsed overnight, a tool missing from PATH - each with its fix, and `--fix` repairs what is turnout's to repair. `doctor --server prod` says where a deploy would stop, before it starts.
|
|
127
|
-
- **Groups.** Bind a whole contour to one stand with a single `use`.
|
|
128
|
-
- **Nothing to memorize.** Leave a name out and pick it from a list; in bash, Tab completes app, server, credential, path and group names from your own catalogs. The short alias `tn` is installed alongside.
|
|
129
|
-
- **An action journal.** Every state change appends one JSON line - what happened and to which entities, never secrets or output. `tail`, `grep` and `jq` work on it directly.
|
|
130
|
-
|
|
131
|
-
## Examples
|
|
132
|
-
|
|
133
|
-
Three small apps under `examples/` exist to see turnout at work rather than read about it:
|
|
134
|
-
|
|
135
|
-
- [`vue-demo`](https://github.com/lacodda/turnout/tree/main/examples/vue-demo) and [`react-demo`](https://github.com/lacodda/turnout/tree/main/examples/react-demo) - the gateway end to end: the app's own address through the front door, the gateway URL handed over by `turnout dev`, requests reaching the stand, and the cookie jar keeping what the browser never sees. Each README is the setup, three commands long.
|
|
136
|
-
- [`deploy-demo`](https://github.com/lacodda/turnout/tree/main/examples/deploy-demo) - a page that shows when its bundle was built, so a deploy is verifiable at a glance.
|
|
137
|
-
|
|
138
|
-
## Install
|
|
139
|
-
|
|
140
|
-
**One-line installers.** Windows (PowerShell):
|
|
73
|
+
- **A dev gateway.** One address per app (`http://web.localhost`), ports assigned for you, redirects and WebSockets proxied, a session per app and stand. [Gateway](https://lacodda.github.io/turnout/concepts/gateway/)
|
|
74
|
+
- **Servers, logins and paths, apart** - joined into named targets, so `turnout deploy web-prod` works from any directory. [Entities](https://lacodda.github.io/turnout/concepts/entities/)
|
|
75
|
+
- **A deploy that checks itself.** `--diff` before, a health check after and a rollback when it fails, a history of every deploy; Linux and Windows servers alike. [deploy](https://lacodda.github.io/turnout/reference/deploy/)
|
|
76
|
+
- **Access set up, not just used.** Secrets in the OS keyring, `key setup` that proves a key before switching to it, the SSH agent, and every server's host key checked. [SSH access](https://lacodda.github.io/turnout/guides/ssh-access/)
|
|
77
|
+
- **A quiet console and jobs in the background.** A loader instead of scrollback, the output on the spot when something fails, `--detach` with a desktop notification at the end. [Quiet console](https://lacodda.github.io/turnout/concepts/quiet-console/)
|
|
78
|
+
- **A doctor.** `turnout doctor` says why it does not work, and `doctor --server prod` where a deploy would stop - each with its fix. [doctor](https://lacodda.github.io/turnout/reference/doctor/)
|
|
79
|
+
- **One window onto it all.** `status`, `status --short` for a prompt line, `--json` on every command that reports, an action journal of every change.
|
|
80
|
+
- **Portable settings.** `export` and `import` between machines, secrets sealed with a passphrase; a file from any release since 0.11 still imports.
|
|
141
81
|
|
|
142
|
-
|
|
143
|
-
irm https://raw.githubusercontent.com/lacodda/turnout/main/tools/install.ps1 | iex
|
|
144
|
-
```
|
|
82
|
+
The whole tour is on [the documentation site](https://lacodda.github.io/turnout/).
|
|
145
83
|
|
|
146
|
-
|
|
84
|
+
## Install
|
|
147
85
|
|
|
148
86
|
```bash
|
|
149
|
-
|
|
87
|
+
brew install lacodda/tap/turnout # macOS, Linux
|
|
88
|
+
scoop bucket add lacodda https://github.com/lacodda/scoop-bucket # Windows
|
|
89
|
+
scoop install turnout
|
|
90
|
+
npm i -g turnout-cli # anywhere with Node
|
|
91
|
+
cargo install turnout # from source
|
|
150
92
|
```
|
|
151
93
|
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
**With npm:**
|
|
94
|
+
Or the one-line installers - PowerShell on Windows, `sh` on macOS and Linux:
|
|
155
95
|
|
|
156
|
-
```
|
|
157
|
-
|
|
96
|
+
```powershell
|
|
97
|
+
irm https://raw.githubusercontent.com/lacodda/turnout/main/tools/install.ps1 | iex
|
|
158
98
|
```
|
|
159
99
|
|
|
160
|
-
**With cargo:**
|
|
161
|
-
|
|
162
100
|
```bash
|
|
163
|
-
|
|
101
|
+
curl -fsSL https://raw.githubusercontent.com/lacodda/turnout/main/tools/install.sh | sh
|
|
164
102
|
```
|
|
165
103
|
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
The installers and the npm package also register the short alias `tn` (skipped if the name is already taken; `TURNOUT_NO_ALIAS=1` opts out). `cargo install` gives you `turnout` only. The alias is a link to the binary rather than a copy of it, so an install costs one binary and both names always answer with the same version.
|
|
169
|
-
|
|
170
|
-
Both installers take the newest release by default; set `TURNOUT_VERSION` to a tag to pin one, and `TURNOUT_INSTALL_DIR` to choose where the binary lands.
|
|
104
|
+
Every way but `cargo install` also sets up the short alias `tn`. Archives for Windows x86_64, Linux x86_64 and arm64, and macOS arm64 are on [the releases page](https://github.com/lacodda/turnout/releases/latest); what each installer reads is in [Getting started](https://lacodda.github.io/turnout/getting-started/).
|
|
171
105
|
|
|
172
106
|
## Quick start
|
|
173
107
|
|
|
@@ -180,20 +114,13 @@ turnout gateway start # route traffic through the gateway
|
|
|
180
114
|
turnout deploy-setup # to deploy: walks the credential, path and target
|
|
181
115
|
```
|
|
182
116
|
|
|
183
|
-
Data lives in the platform user data directory (e.g. `%LOCALAPPDATA%\lacodda\turnout` on Windows); set `TURNOUT_DATA_DIR` to override.
|
|
184
|
-
|
|
185
|
-
Full command reference and concepts: **[lacodda.github.io/turnout](https://lacodda.github.io/turnout/)**.
|
|
186
|
-
|
|
187
117
|
## Status
|
|
188
118
|
|
|
189
|
-
|
|
190
|
-
today, deploys are proven against real Linux and Windows servers, and a
|
|
191
|
-
settings export from any version since v0.11 still imports. What landed in each
|
|
192
|
-
version: [the changelog](https://github.com/lacodda/turnout/blob/main/CHANGELOG.md).
|
|
119
|
+
v1.0.0, the first stable release. The settings are a contract: an export written by any release since v0.11 imports into this one, and nothing in 1.x breaks it. Deploys are proven against real Linux and Windows servers on every push; what landed in each version is in [the changelog](https://github.com/lacodda/turnout/blob/main/CHANGELOG.md).
|
|
193
120
|
|
|
194
121
|
## Documentation
|
|
195
122
|
|
|
196
|
-
|
|
123
|
+
Commands, concepts and guides: **[lacodda.github.io/turnout](https://lacodda.github.io/turnout/)**. The site's source is in [`docs/`](https://github.com/lacodda/turnout/tree/main/docs), and architecture decision records are in [`docs/adr/`](https://github.com/lacodda/turnout/tree/main/docs/adr).
|
|
197
124
|
|
|
198
125
|
## License
|
|
199
126
|
|
package/download.js
CHANGED
|
@@ -15,6 +15,7 @@ const TAG = (pkg.turnout && pkg.turnout.binary) || `v${pkg.version}`;
|
|
|
15
15
|
const TARGETS = {
|
|
16
16
|
"win32-x64": ["x86_64-pc-windows-msvc", "zip"],
|
|
17
17
|
"linux-x64": ["x86_64-unknown-linux-gnu", "tar.gz"],
|
|
18
|
+
"linux-arm64": ["aarch64-unknown-linux-gnu", "tar.gz"],
|
|
18
19
|
"darwin-arm64": ["aarch64-apple-darwin", "tar.gz"],
|
|
19
20
|
};
|
|
20
21
|
|
package/package.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "turnout-cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "1.0.0",
|
|
4
4
|
"turnout": {
|
|
5
|
-
"binary": "
|
|
5
|
+
"binary": "v1.0.0"
|
|
6
6
|
},
|
|
7
7
|
"description": "A developer's switchyard: point local apps at any backend stand, keep servers and secrets at hand, build and deploy from any directory",
|
|
8
8
|
"license": "MIT",
|
package/run.js
CHANGED
|
@@ -2,12 +2,35 @@
|
|
|
2
2
|
// Thin launcher: forwards everything to the turnout binary, downloading it on
|
|
3
3
|
// first run when the postinstall script was skipped (npm v12 default).
|
|
4
4
|
const fs = require("fs");
|
|
5
|
+
const os = require("os");
|
|
5
6
|
const { spawnSync } = require("child_process");
|
|
6
7
|
const { install, exePath } = require("./download");
|
|
7
8
|
|
|
9
|
+
// The keystrokes a terminal sends to every process on it, this launcher
|
|
10
|
+
// included. Left to the default, the launcher would die at once and hand the
|
|
11
|
+
// prompt back while turnout - and the dev server `turnout dev` started - is
|
|
12
|
+
// still shutting down on the same keystroke, its exit code lost. Listening
|
|
13
|
+
// keeps the launcher alive until the binary is done; the binary alone decides.
|
|
14
|
+
const KEYSTROKES =
|
|
15
|
+
process.platform === "win32" ? ["SIGINT", "SIGBREAK"] : ["SIGINT", "SIGQUIT"];
|
|
16
|
+
|
|
8
17
|
function exec() {
|
|
18
|
+
const stayPut = () => {};
|
|
19
|
+
for (const signal of KEYSTROKES) process.on(signal, stayPut);
|
|
20
|
+
|
|
9
21
|
const result = spawnSync(exePath, process.argv.slice(2), { stdio: "inherit" });
|
|
10
|
-
|
|
22
|
+
if (result.error) {
|
|
23
|
+
console.error(`turnout-cli: cannot start ${exePath}: ${result.error.message}`);
|
|
24
|
+
process.exit(1);
|
|
25
|
+
}
|
|
26
|
+
if (result.signal) {
|
|
27
|
+
// Ended by a signal: end the same way, so the shell reports it as it
|
|
28
|
+
// would for the binary run directly (130 after Ctrl+C), not as a plain 1.
|
|
29
|
+
for (const signal of KEYSTROKES) process.removeListener(signal, stayPut);
|
|
30
|
+
process.kill(process.pid, result.signal);
|
|
31
|
+
process.exit(128 + (os.constants.signals[result.signal] || 0));
|
|
32
|
+
}
|
|
33
|
+
process.exit(result.status);
|
|
11
34
|
}
|
|
12
35
|
|
|
13
36
|
if (fs.existsSync(exePath)) {
|