devrites 5.10.1 → 5.10.2
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/CHANGELOG.md +7 -0
- package/README.md +1 -1
- package/docs/cli.md +4 -1
- package/docs/command-map.md +2 -1
- package/docs/engine/commands.md +7 -5
- package/docs/orchestration.md +5 -2
- package/docs/usage.md +3 -1
- package/engine/commands.go +3 -0
- package/engine/help.go +190 -0
- package/engine/help_test.go +98 -0
- package/engine/internal/parallel/cli.go +90 -32
- package/engine/internal/parallel/cli_test.go +32 -0
- package/engine/main.go +15 -8
- package/engine/root_routing_test.go +4 -0
- package/pack/.claude/skills/devrites-lib/reference/standards/afk-hitl.md +15 -8
- package/pack/.claude/skills/rite-autocomplete/SKILL.md +10 -5
- package/pack/.claude/skills/rite-autocomplete/reference/loop.md +12 -7
- package/pack/.claude/skills/rite-build/SKILL.md +3 -1
- package/pack/.claude/skills/rite-build/reference/afk-discipline.md +4 -3
- package/pack/.claude/skills/rite-build/reference/parallel-batch.md +3 -1
- package/pack/.claude/skills/rite-define/reference/plan-template.md +1 -1
- package/pack/generated/claude/skills/devrites-lib/reference/standards/afk-hitl.md +15 -8
- package/pack/generated/claude/skills/rite-autocomplete/SKILL.md +10 -5
- package/pack/generated/claude/skills/rite-autocomplete/reference/loop.md +12 -7
- package/pack/generated/claude/skills/rite-build/SKILL.md +3 -1
- package/pack/generated/claude/skills/rite-build/reference/afk-discipline.md +4 -3
- package/pack/generated/claude/skills/rite-build/reference/parallel-batch.md +3 -1
- package/pack/generated/claude/skills/rite-define/reference/plan-template.md +1 -1
- package/pack/generated/codex/skills/devrites-lib/reference/standards/afk-hitl.md +15 -8
- package/pack/generated/codex/skills/rite-autocomplete/SKILL.md +10 -5
- package/pack/generated/codex/skills/rite-autocomplete/reference/loop.md +12 -7
- package/pack/generated/codex/skills/rite-build/SKILL.md +3 -1
- package/pack/generated/codex/skills/rite-build/reference/afk-discipline.md +4 -3
- package/pack/generated/codex/skills/rite-build/reference/parallel-batch.md +3 -1
- package/pack/generated/codex/skills/rite-define/reference/plan-template.md +1 -1
- package/pack/generated/omp/skills/devrites-lib/reference/standards/afk-hitl.md +15 -8
- package/pack/generated/omp/skills/rite-autocomplete/SKILL.md +10 -5
- package/pack/generated/omp/skills/rite-autocomplete/reference/loop.md +12 -7
- package/pack/generated/omp/skills/rite-build/SKILL.md +3 -1
- package/pack/generated/omp/skills/rite-build/reference/afk-discipline.md +4 -3
- package/pack/generated/omp/skills/rite-build/reference/parallel-batch.md +3 -1
- package/pack/generated/omp/skills/rite-define/reference/plan-template.md +1 -1
- package/pack/generated/pi/skills/devrites-lib/reference/standards/afk-hitl.md +15 -8
- package/pack/generated/pi/skills/rite-autocomplete/SKILL.md +10 -5
- package/pack/generated/pi/skills/rite-autocomplete/reference/loop.md +12 -7
- package/pack/generated/pi/skills/rite-build/SKILL.md +3 -1
- package/pack/generated/pi/skills/rite-build/reference/afk-discipline.md +4 -3
- package/pack/generated/pi/skills/rite-build/reference/parallel-batch.md +3 -1
- package/pack/generated/pi/skills/rite-define/reference/plan-template.md +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,13 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to DevRites are documented here. The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/) and DevRites adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). Releases are generated automatically by [semantic-release](https://semantic-release.gitbook.io/) from Conventional Commits on `main`.
|
|
4
4
|
|
|
5
|
+
## [5.10.2](https://github.com/ViktorsBaikers/DevRites/compare/v5.10.1...v5.10.2) (2026-09-15)
|
|
6
|
+
|
|
7
|
+
### Fixed
|
|
8
|
+
|
|
9
|
+
* **ci:** stop gosec false positive on secret-scan help ([ac8ef15](https://github.com/ViktorsBaikers/DevRites/commit/ac8ef1530f5121cf192fb9e60acef781b0e3fbb8))
|
|
10
|
+
* **rite:** honor --parallel over leftover AFK cap ([#78](https://github.com/ViktorsBaikers/DevRites/issues/78)) ([db6c299](https://github.com/ViktorsBaikers/DevRites/commit/db6c299e24be5e1b8c5739e45542f2ef8b572e3b))
|
|
11
|
+
|
|
5
12
|
## [5.10.1](https://github.com/ViktorsBaikers/DevRites/compare/v5.10.0...v5.10.1) (2026-09-15)
|
|
6
13
|
|
|
7
14
|
### Fixed
|
package/README.md
CHANGED
|
@@ -33,7 +33,7 @@ project-conventional push, tag, or PR action, and archive the workspace.
|
|
|
33
33
|
Unattended runs may create local WIP checkpoint commits along the way, but they
|
|
34
34
|
remain local unless Ship's disclosed plan includes an approved remote action.
|
|
35
35
|
|
|
36
|
-
**Status:** [`v5.10.
|
|
36
|
+
**Status:** [`v5.10.2`](https://github.com/ViktorsBaikers/DevRites/releases/tag/v5.10.2): see [`CHANGELOG.md`](CHANGELOG.md) for release notes.
|
|
37
37
|
|
|
38
38
|
This is the latest published release; `main` may contain unreleased work.
|
|
39
39
|
|
package/docs/cli.md
CHANGED
|
@@ -8,7 +8,10 @@ cross-host primitives; it never dispatches an agent or grades reviewer prose.
|
|
|
8
8
|
## Command surface
|
|
9
9
|
|
|
10
10
|
`devrites-engine help` lists the exhaustive operational surface. Standard
|
|
11
|
-
`help`, `-h`, `--help`, `version`, and `--version` forms also remain supported
|
|
11
|
+
`help`, `-h`, `--help`, `version`, and `--version` forms also remain supported.
|
|
12
|
+
Each operational command and subcommand accepts `-h` / `--help` and prints that
|
|
13
|
+
command's usage to stdout (exit 0) without requiring a workspace. Missing
|
|
14
|
+
required arguments still print usage to stderr and exit 2.
|
|
12
15
|
|
|
13
16
|
```text
|
|
14
17
|
devrites-engine install [flags]
|
package/docs/command-map.md
CHANGED
|
@@ -49,7 +49,8 @@ The Go surface is intentionally closed and deterministic:
|
|
|
49
49
|
|
|
50
50
|
`devrites-engine help` exhaustively lists the operational engine commands.
|
|
51
51
|
Standard `help`, `-h`, `--help`, `version`, and `--version` forms remain
|
|
52
|
-
available;
|
|
52
|
+
available; each operational command and subcommand also accepts `-h` / `--help`.
|
|
53
|
+
There are no legacy operational aliases. `check candidate <slug>`
|
|
53
54
|
prints exactly
|
|
54
55
|
`candidate-sha256: <64 lowercase hex>` and `candidate-files: <row count>` on a
|
|
55
56
|
pass; usage/root errors exit `2` and candidate blocks exit `3`. There are no
|
package/docs/engine/commands.md
CHANGED
|
@@ -27,11 +27,13 @@ workflow strategy.
|
|
|
27
27
|
| `open-visual <path-or-name> [--slug <slug>] [--no-open]` | Resolve a local visual HTML file, optionally open it in the OS browser, warn if the sibling outline is missing or inventory ids are absent from HTML, and print agent path tips. No network. |
|
|
28
28
|
| `version` | Print the engine version. |
|
|
29
29
|
|
|
30
|
-
`help`, `-h`, and `--help` print this operational inventory.
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
30
|
+
`help`, `-h`, and `--help` print this operational inventory. Each operational
|
|
31
|
+
command and subcommand also accepts `-h` / `--help` and prints that command's
|
|
32
|
+
usage to stdout without requiring a workspace. `version` and `--version` print
|
|
33
|
+
the binary version. Other unlisted command forms are rejected as unknown; the
|
|
34
|
+
engine has no compatibility aliases or tombstones. The `add`/`upgrade`/`remove`
|
|
35
|
+
conveniences belong only to the `npx devrites` adapter, not to the engine
|
|
36
|
+
command namespace.
|
|
35
37
|
|
|
36
38
|
## Check boundary
|
|
37
39
|
|
package/docs/orchestration.md
CHANGED
|
@@ -128,8 +128,11 @@ preserved. No ad hoc copy/cherry-pick/merge occurs from the read-only root.
|
|
|
128
128
|
|
|
129
129
|
Isolation does not authorize same-worktree throughput. Parallel writers are allowed
|
|
130
130
|
**only** under the `/rite-build` batch path when path-disjoint eligibility, abort-batch,
|
|
131
|
-
and a control `parallel-lease.md` apply. `--parallel N`
|
|
132
|
-
|
|
131
|
+
and a control `parallel-lease.md` apply. `--parallel N` on `/rite-autocomplete`
|
|
132
|
+
or `/rite-build` is the batch cap for that run and wins over leftover sentinel
|
|
133
|
+
`max_parallel`; `/rite-autocomplete --parallel N` also writes or replaces only
|
|
134
|
+
that field. Absent the flag, the sentinel (default cap 10 under
|
|
135
|
+
`/rite-autocomplete`) is a **cap**: each round runs
|
|
133
136
|
the largest eligible set, recomputes after every completed round, and repeats until no
|
|
134
137
|
pending slice remains; a one-slice round is serial for that round only (see
|
|
135
138
|
[`parallel-batch.md`](../pack/.claude/skills/rite-build/reference/parallel-batch.md)).
|
package/docs/usage.md
CHANGED
|
@@ -413,7 +413,9 @@ remaining from the pending-slice count and ignores leftover remaining and
|
|
|
413
413
|
- **`.devrites/AFK` is per-developer, not per-repo**: gitignore it (or commit
|
|
414
414
|
it deliberately if the team agrees on AFK defaults). The sentinel is
|
|
415
415
|
read-only config: it toggles your local session mode and sets the initial
|
|
416
|
-
`max_slices` budget
|
|
416
|
+
`max_slices` budget. `/rite-autocomplete --parallel N` is the one exception:
|
|
417
|
+
it writes or replaces only `max_parallel: N` so a leftover `1` cannot keep
|
|
418
|
+
later ticks serial. The mutable remaining-slice count lives
|
|
417
419
|
in `state.md` (`AFK slices remaining`), never in the sentinel. The root
|
|
418
420
|
charges it once with each green pending → built transition and stops before
|
|
419
421
|
another dispatch at zero; malformed values fail closed.
|
package/engine/commands.go
CHANGED
|
@@ -25,6 +25,9 @@ const (
|
|
|
25
25
|
// workspace or Git state, which must never fall back after an unsafe root
|
|
26
26
|
// selection.
|
|
27
27
|
func rootModeFor(command string, args []string) rootMode {
|
|
28
|
+
if hasHelpFlag(args) || (len(args) > 0 && isHelpToken(args[0])) {
|
|
29
|
+
return rootUnused
|
|
30
|
+
}
|
|
28
31
|
subcommand := firstRootOperand(args)
|
|
29
32
|
switch command {
|
|
30
33
|
case "secret-scan", "open-visual":
|
package/engine/help.go
ADDED
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
package main
|
|
2
|
+
|
|
3
|
+
import (
|
|
4
|
+
"fmt"
|
|
5
|
+
"io"
|
|
6
|
+
"strings"
|
|
7
|
+
|
|
8
|
+
"github.com/devrites/devrites/internal/parallel"
|
|
9
|
+
)
|
|
10
|
+
|
|
11
|
+
const (
|
|
12
|
+
checkUsage = `usage: devrites-engine check <candidate|readiness|seal|path-disjoint|task-graph|skill-trust|indexes> ...
|
|
13
|
+
|
|
14
|
+
check candidate <slug>
|
|
15
|
+
check readiness <slug>
|
|
16
|
+
check readiness --emit-binding <slug>
|
|
17
|
+
check seal <slug>
|
|
18
|
+
check path-disjoint [--root <dir>] [<json-file>|-]
|
|
19
|
+
check task-graph <slug>
|
|
20
|
+
check skill-trust <path>
|
|
21
|
+
check indexes [--root <dir>]
|
|
22
|
+
`
|
|
23
|
+
|
|
24
|
+
stateUsage = `usage: devrites-engine state <resolve|merge-manifest|close> ...
|
|
25
|
+
|
|
26
|
+
state resolve <qid> "<answer>"
|
|
27
|
+
state resolve --drop <qid> ["<reason>"]
|
|
28
|
+
state resolve --batch <file>
|
|
29
|
+
state merge-manifest <slug> [<predecessor>...]
|
|
30
|
+
state close <slug>
|
|
31
|
+
`
|
|
32
|
+
|
|
33
|
+
observeUsage = `usage: devrites-engine observe summary <slug> | observe slice <slug> <SLICE-ID>
|
|
34
|
+
|
|
35
|
+
observe summary [slug]
|
|
36
|
+
observe slice <slug> <SLICE-ID>
|
|
37
|
+
`
|
|
38
|
+
|
|
39
|
+
orientUsage = "usage: devrites-engine orient [slug]"
|
|
40
|
+
migrateUsage = "usage: devrites-engine migrate <slug> [--dry-run] [--answer id=choice]"
|
|
41
|
+
// scanCmdUsage is help text for `secret-scan`. The identifier must not
|
|
42
|
+
// contain "secret": gosec G101 treats secret* string consts as credentials.
|
|
43
|
+
scanCmdUsage = "usage: devrites-engine secret-scan [--staged] [--stdin] [slug]"
|
|
44
|
+
openVisualUsage = "usage: devrites-engine open-visual <path-or-name> [--slug <slug>] [--no-open]"
|
|
45
|
+
versionUsage = "usage: devrites-engine version"
|
|
46
|
+
candidateUsage = "usage: devrites-engine check candidate <slug>"
|
|
47
|
+
readinessUsage = "usage: devrites-engine check readiness <slug>\n devrites-engine check readiness --emit-binding <slug>"
|
|
48
|
+
sealUsage = "usage: devrites-engine check seal <slug>"
|
|
49
|
+
taskGraphUsage = "usage: devrites-engine check task-graph <slug>"
|
|
50
|
+
skillTrustUsage = "usage: devrites-engine check skill-trust <path>"
|
|
51
|
+
indexesUsage = "usage: devrites-engine check indexes [--root <dir>]"
|
|
52
|
+
resolveUsage = `usage: devrites-engine state resolve <qid> "<answer>" | state resolve --drop <qid> ["<reason>"] | state resolve --batch <file>`
|
|
53
|
+
mergeManifestUsage = "usage: devrites-engine state merge-manifest <slug> [<predecessor>...]"
|
|
54
|
+
closeUsage = "usage: devrites-engine state close <slug>"
|
|
55
|
+
observeSliceUsage = "usage: devrites-engine observe slice <slug> <SLICE-ID>"
|
|
56
|
+
observeSummaryUsage = "usage: devrites-engine observe summary [slug]"
|
|
57
|
+
)
|
|
58
|
+
|
|
59
|
+
func isHelpFlag(arg string) bool {
|
|
60
|
+
switch arg {
|
|
61
|
+
case "-h", "-help", "--help":
|
|
62
|
+
return true
|
|
63
|
+
default:
|
|
64
|
+
return false
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
func isHelpToken(arg string) bool {
|
|
69
|
+
return isHelpFlag(arg) || arg == "help"
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
func hasHelpFlag(args []string) bool {
|
|
73
|
+
for _, arg := range args {
|
|
74
|
+
if isHelpFlag(arg) {
|
|
75
|
+
return true
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
return false
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
func shouldPrintHelp(args []string) bool {
|
|
82
|
+
if len(args) == 0 {
|
|
83
|
+
return false
|
|
84
|
+
}
|
|
85
|
+
if isHelpToken(args[0]) {
|
|
86
|
+
return true
|
|
87
|
+
}
|
|
88
|
+
if hasHelpFlag(args) {
|
|
89
|
+
return true
|
|
90
|
+
}
|
|
91
|
+
switch args[0] {
|
|
92
|
+
case "check", "state", "observe", "parallel":
|
|
93
|
+
return len(args) >= 2 && args[1] == "help"
|
|
94
|
+
default:
|
|
95
|
+
return false
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
func firstNonHelp(args []string) string {
|
|
100
|
+
for _, arg := range args {
|
|
101
|
+
if isHelpToken(arg) || strings.HasPrefix(arg, "-") {
|
|
102
|
+
continue
|
|
103
|
+
}
|
|
104
|
+
return arg
|
|
105
|
+
}
|
|
106
|
+
return ""
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
func writeHelp(stdout io.Writer, text string) int {
|
|
110
|
+
fmt.Fprintln(stdout, strings.TrimRight(text, "\n"))
|
|
111
|
+
return exitOK
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
// commandHelp returns the usage text for a help request on a known command.
|
|
115
|
+
// ok is false when args are not a help request, or the command is unknown so
|
|
116
|
+
// the existing unknown-command path should run.
|
|
117
|
+
func commandHelp(args []string) (string, bool) {
|
|
118
|
+
if !shouldPrintHelp(args) {
|
|
119
|
+
return "", false
|
|
120
|
+
}
|
|
121
|
+
switch args[0] {
|
|
122
|
+
case "-h", "-help", "--help", "help":
|
|
123
|
+
return usage, true
|
|
124
|
+
case "check":
|
|
125
|
+
return helpCheck(args[1:]), true
|
|
126
|
+
case "state":
|
|
127
|
+
return helpState(args[1:]), true
|
|
128
|
+
case "observe":
|
|
129
|
+
return helpObserve(args[1:]), true
|
|
130
|
+
case "orient":
|
|
131
|
+
return orientUsage, true
|
|
132
|
+
case "parallel":
|
|
133
|
+
return parallel.CommandUsage(firstNonHelp(args[1:])), true
|
|
134
|
+
case "migrate":
|
|
135
|
+
return migrateUsage, true
|
|
136
|
+
case "secret-scan":
|
|
137
|
+
return scanCmdUsage, true
|
|
138
|
+
case "open-visual":
|
|
139
|
+
return openVisualUsage, true
|
|
140
|
+
case "version", "--version":
|
|
141
|
+
return versionUsage, true
|
|
142
|
+
default:
|
|
143
|
+
return "", false
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
func helpCheck(rest []string) string {
|
|
148
|
+
switch firstNonHelp(rest) {
|
|
149
|
+
case "candidate":
|
|
150
|
+
return candidateUsage
|
|
151
|
+
case "readiness":
|
|
152
|
+
return readinessUsage
|
|
153
|
+
case "seal":
|
|
154
|
+
return sealUsage
|
|
155
|
+
case "path-disjoint":
|
|
156
|
+
return parallel.CommandUsage("path-disjoint")
|
|
157
|
+
case "task-graph":
|
|
158
|
+
return taskGraphUsage
|
|
159
|
+
case "skill-trust":
|
|
160
|
+
return skillTrustUsage
|
|
161
|
+
case "indexes":
|
|
162
|
+
return indexesUsage
|
|
163
|
+
default:
|
|
164
|
+
return checkUsage
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
func helpState(rest []string) string {
|
|
169
|
+
switch firstNonHelp(rest) {
|
|
170
|
+
case "resolve":
|
|
171
|
+
return resolveUsage
|
|
172
|
+
case "merge-manifest":
|
|
173
|
+
return mergeManifestUsage
|
|
174
|
+
case "close":
|
|
175
|
+
return closeUsage
|
|
176
|
+
default:
|
|
177
|
+
return stateUsage
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
func helpObserve(rest []string) string {
|
|
182
|
+
switch firstNonHelp(rest) {
|
|
183
|
+
case "summary":
|
|
184
|
+
return observeSummaryUsage
|
|
185
|
+
case "slice":
|
|
186
|
+
return observeSliceUsage
|
|
187
|
+
default:
|
|
188
|
+
return observeUsage
|
|
189
|
+
}
|
|
190
|
+
}
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
package main
|
|
2
|
+
|
|
3
|
+
import (
|
|
4
|
+
"bytes"
|
|
5
|
+
"strings"
|
|
6
|
+
"testing"
|
|
7
|
+
)
|
|
8
|
+
|
|
9
|
+
func TestCommandHelp(t *testing.T) {
|
|
10
|
+
t.Setenv("DEVRITES_ROOT", "")
|
|
11
|
+
tests := []struct {
|
|
12
|
+
args []string
|
|
13
|
+
want string
|
|
14
|
+
}{
|
|
15
|
+
{args: []string{"--help"}, want: "Usage:"},
|
|
16
|
+
{args: []string{"-h"}, want: "Usage:"},
|
|
17
|
+
{args: []string{"help"}, want: "Usage:"},
|
|
18
|
+
{args: []string{"check", "--help"}, want: "check candidate <slug>"},
|
|
19
|
+
{args: []string{"check", "help"}, want: "check <candidate|readiness|seal|path-disjoint|task-graph|skill-trust|indexes>"},
|
|
20
|
+
{args: []string{"check", "candidate", "--help"}, want: "check candidate <slug>"},
|
|
21
|
+
{args: []string{"check", "readiness", "-h"}, want: "check readiness --emit-binding <slug>"},
|
|
22
|
+
{args: []string{"check", "seal", "--help"}, want: "check seal <slug>"},
|
|
23
|
+
{args: []string{"check", "path-disjoint", "--help"}, want: "check path-disjoint"},
|
|
24
|
+
{args: []string{"check", "task-graph", "--help"}, want: "check task-graph <slug>"},
|
|
25
|
+
{args: []string{"check", "skill-trust", "--help"}, want: "check skill-trust <path>"},
|
|
26
|
+
{args: []string{"check", "indexes", "--help"}, want: "check indexes [--root <dir>]"},
|
|
27
|
+
{args: []string{"state", "--help"}, want: "state <resolve|merge-manifest|close>"},
|
|
28
|
+
{args: []string{"state", "-h"}, want: "state resolve"},
|
|
29
|
+
{args: []string{"state", "help"}, want: "state close <slug>"},
|
|
30
|
+
{args: []string{"state", "resolve", "--help"}, want: `state resolve <qid> "<answer>"`},
|
|
31
|
+
{args: []string{"state", "merge-manifest", "--help"}, want: "state merge-manifest <slug>"},
|
|
32
|
+
{args: []string{"state", "close", "--help"}, want: "state close <slug>"},
|
|
33
|
+
{args: []string{"parallel", "--help"}, want: "usage: parallel <subcommand>"},
|
|
34
|
+
{args: []string{"parallel", "create", "--help"}, want: "usage: parallel create --root --slug --batch --base --json"},
|
|
35
|
+
{args: []string{"parallel", "create", "-h"}, want: "parallel create"},
|
|
36
|
+
{args: []string{"parallel", "select", "--help"}, want: "parallel select --cap"},
|
|
37
|
+
{args: []string{"observe", "--help"}, want: "observe summary"},
|
|
38
|
+
{args: []string{"observe", "summary", "--help"}, want: "observe summary"},
|
|
39
|
+
{args: []string{"observe", "slice", "--help"}, want: "observe slice <slug> <SLICE-ID>"},
|
|
40
|
+
{args: []string{"orient", "--help"}, want: "orient [slug]"},
|
|
41
|
+
{args: []string{"migrate", "--help"}, want: "migrate <slug>"},
|
|
42
|
+
{args: []string{"secret-scan", "--help"}, want: "secret-scan [--staged] [--stdin]"},
|
|
43
|
+
{args: []string{"open-visual", "--help"}, want: "open-visual <path-or-name>"},
|
|
44
|
+
{args: []string{"version", "--help"}, want: "devrites-engine version"},
|
|
45
|
+
{args: []string{"install", "--help"}, want: "usage: devrites-engine install"},
|
|
46
|
+
{args: []string{"update", "--help"}, want: "usage: devrites-engine update"},
|
|
47
|
+
{args: []string{"uninstall", "--help"}, want: "usage: devrites-engine uninstall"},
|
|
48
|
+
}
|
|
49
|
+
for _, test := range tests {
|
|
50
|
+
t.Run(strings.Join(test.args, " "), func(t *testing.T) {
|
|
51
|
+
var stdout, stderr bytes.Buffer
|
|
52
|
+
code := run(test.args, strings.NewReader(""), &stdout, &stderr)
|
|
53
|
+
if code != exitOK {
|
|
54
|
+
t.Fatalf("run(%q) = %d, want %d; stdout=%q stderr=%q", test.args, code, exitOK, stdout.String(), stderr.String())
|
|
55
|
+
}
|
|
56
|
+
if stderr.Len() != 0 {
|
|
57
|
+
t.Fatalf("run(%q) wrote stderr %q", test.args, stderr.String())
|
|
58
|
+
}
|
|
59
|
+
if !strings.Contains(stdout.String(), test.want) {
|
|
60
|
+
t.Fatalf("run(%q) stdout=%q, want %q", test.args, stdout.String(), test.want)
|
|
61
|
+
}
|
|
62
|
+
if strings.Contains(stdout.String(), "unknown") {
|
|
63
|
+
t.Fatalf("run(%q) treated help as unknown: %q", test.args, stdout.String())
|
|
64
|
+
}
|
|
65
|
+
})
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
func TestCommandHelpDoesNotRequireWorkspace(t *testing.T) {
|
|
70
|
+
t.Setenv("DEVRITES_ROOT", "")
|
|
71
|
+
for _, args := range [][]string{
|
|
72
|
+
{"state", "--help"},
|
|
73
|
+
{"check", "candidate", "--help"},
|
|
74
|
+
{"orient", "--help"},
|
|
75
|
+
{"migrate", "--help"},
|
|
76
|
+
{"parallel", "create", "--help"},
|
|
77
|
+
} {
|
|
78
|
+
var stdout, stderr bytes.Buffer
|
|
79
|
+
code := run(args, strings.NewReader(""), &stdout, &stderr)
|
|
80
|
+
if code != exitOK || stderr.Len() != 0 || !strings.Contains(stdout.String(), "usage:") {
|
|
81
|
+
t.Fatalf("run(%q) code=%d stdout=%q stderr=%q", args, code, stdout.String(), stderr.String())
|
|
82
|
+
}
|
|
83
|
+
if strings.Contains(stdout.String()+stderr.String(), "root selection") {
|
|
84
|
+
t.Fatalf("run(%q) required a workspace for help", args)
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
func TestUnknownCommandHelpStillUnknown(t *testing.T) {
|
|
90
|
+
var stdout, stderr bytes.Buffer
|
|
91
|
+
args := []string{"frobnicate", "--help"}
|
|
92
|
+
if code := run(args, strings.NewReader(""), &stdout, &stderr); code != exitUsage {
|
|
93
|
+
t.Fatalf("run(%q) = %d, want %d", args, code, exitUsage)
|
|
94
|
+
}
|
|
95
|
+
if !strings.Contains(stderr.String(), `unknown command "frobnicate"`) {
|
|
96
|
+
t.Fatalf("stderr = %q, want unknown-command diagnostic", stderr.String())
|
|
97
|
+
}
|
|
98
|
+
}
|