feat: add support for user-doc-based help routing and manifest generation#6884
feat: add support for user-doc-based help routing and manifest generation#6884robertolopezlopez wants to merge 1 commit into
Conversation
✅ Snyk checks have passed. No issues have been found so far.
💻 Catch issues earlier using the plugins for VS Code, JetBrains IDEs, Visual Studio, and Eclipse. |
393fea9 to
84cb6cd
Compare
This comment has been minimized.
This comment has been minimized.
84cb6cd to
6585a70
Compare
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
0d3b9c3 to
636428d
Compare
This comment has been minimized.
This comment has been minimized.
|
/describe |
|
PR Description updated to latest commit (636428d) |
|
/describe |
|
PR Description updated to latest commit (636428d) |
| var runLegacyHelp = func() error { | ||
| args := utils.RemoveSimilar(os.Args[1:], "--") | ||
| args = append(args, "--help") | ||
| return defaultCmd(args) | ||
| } | ||
|
|
||
| func legacyHelp() error { | ||
| return runLegacyHelp() | ||
| } |
There was a problem hiding this comment.
maybe we can just simplify to have only runLegacyHelp
636428d to
2e2ee2b
Compare
This comment has been minimized.
This comment has been minimized.
2e2ee2b to
121e6e4
Compare
This comment has been minimized.
This comment has been minimized.
| } | ||
|
|
||
| args := helpTargetArgs(os.Args[1:]) | ||
| if len(args) > 0 && args[0] == "help" { |
There was a problem hiding this comment.
the "help" string is being used multiple times, please move to a constant
| func resolveHelpCommand(root *cobra.Command) *cobra.Command { | ||
| if root == nil { | ||
| return nil | ||
| } | ||
| args := helpTargetArgs(os.Args[1:]) | ||
| if len(args) == 0 { | ||
| return nil | ||
| } |
There was a problem hiding this comment.
should here check if os.Args have parameters before accessing? Well actually it kinda does that, so maybe ignore this comment
There was a problem hiding this comment.
Args hold the command-line arguments, starting with the program name.
also to double check what may happen... https://go.dev/play/p/C_KEdMptOeV
| for _, arg := range argv { | ||
| if isHelpFlag(arg) { | ||
| continue | ||
| } | ||
| if strings.HasPrefix(arg, "--help=") { | ||
| out = append(out, strings.TrimPrefix(arg, "--help=")) | ||
| continue | ||
| } | ||
| if strings.HasPrefix(arg, "-") { | ||
| continue | ||
| } | ||
| out = append(out, arg) | ||
| } |
There was a problem hiding this comment.
here you are using if hasPrefix of --help, but line 157 you have isHelpFlag function, maybe that should be used?
func isHelpFlag(arg string) bool {
// -help is a legacy cliv1 flag
return arg == "--help" || arg == "-h" || arg == "-help"
}There was a problem hiding this comment.
isHelpFlag() and line 145 handle different help syntax.
| input | isHelpFlag() output |
helpTargetArgs() output as it is now |
with isHelpFlag() |
|---|---|---|---|
["--help=iac"] |
false |
["iac"] |
[] |
["--help", "container"] |
true (first element + continue) |
["container"] | [] |
I do not think isHelpFlag() is appropriate to use in line 145
| tests := map[string]struct { | ||
| argv []string | ||
| command func(t *testing.T, root *cobra.Command) (*cobra.Command, *bytes.Buffer) | ||
| wantLegacy bool | ||
| cobraOut []string | ||
| }{ | ||
| "top-level --help uses legacy readme": { | ||
| argv: []string{"snyk", "--help"}, | ||
| command: func(_ *testing.T, root *cobra.Command) (*cobra.Command, *bytes.Buffer) { | ||
| return root, nil | ||
| }, | ||
| wantLegacy: true, | ||
| }, |
There was a problem hiding this comment.
Optional: this table of tests is mixing of using legacy and cobra. Maybe is worth changing to two separate table of tests: one with legacy docs and one with cobra
There was a problem hiding this comment.
Mmmh in my opinion checking the two boundaries is correct here, without split. Other tests such as Test_helpTargetArgs or Test_resolveHelpTargetForCobra are already split, but Test_help_routing stays on the top layer: given a help command, which help should be used?
There was a problem hiding this comment.
it was just more about having different scenarios a bit better split
| rInfo := runtimeinfo.New(runtimeinfo.WithName("snyk-cli"), runtimeinfo.WithVersion(cliv2.GetFullVersion())) | ||
|
|
||
| rootCommand := prepareRootCommand() | ||
| globalRootCommand = rootCommand |
There was a problem hiding this comment.
do we really need this globalRootCommand?
There was a problem hiding this comment.
You won here, and I extracted helprouting*.go to a separate package for better separation of concerns. No more globalRootCommand
121e6e4 to
d5de3c9
Compare
| err = defaultCmd(os.Args[1:]) | ||
| case handleErrorShowHelp: | ||
| err = help(nil, []string{}) | ||
| err = help(resolveHelpCommand(rootCommand), []string{}) |
There was a problem hiding this comment.
if have globalRootCommand, then why use 'rootCommand' here? Maybe could drop the global one?
There was a problem hiding this comment.
Yep, this is a design decision.
main.go#prepareRootCommand()returns the mainsnykcommand.- line 538: store the main
snykcommand at package level help_routing#help()makes use of it:- for
root.Find(args)(line 65) - then, deciding legacy help or Cobra help.
- for
in any case, while thinking over all this logic, I decided to refactor it :-D
There was a problem hiding this comment.
I extracted help routing logic to a separate package and globalRootCommand does not exist any more
This comment has been minimized.
This comment has been minimized.
I will check @CatalinSnyk |
This comment has been minimized.
This comment has been minimized.
dd2a28f to
956a5b9
Compare
This comment has been minimized.
This comment has been minimized.
956a5b9 to
306c68c
Compare
|
|
||
| const ( | ||
| helpCommand = "help" | ||
| flagLong = "--help" |
There was a problem hiding this comment.
maybe the name should be helpFlag? or just leave helpCommand and concat in the place, idk better reuse the helpCommand if possible, can even be a helper function commandToFlag
There was a problem hiding this comment.
yeah the naming is not perfect
This comment has been minimized.
This comment has been minimized.
306c68c to
ea08524
Compare
This comment has been minimized.
This comment has been minimized.
@CatalinSnyk after checking carefully, I believe a good approach to fix this issue would be merging #6892 (which adds |
|
/describe |
|
PR Description updated to latest commit (ea08524) |
ea08524 to
e9ad92e
Compare
This comment has been minimized.
This comment has been minimized.
e9ad92e to
c1d9be8
Compare
This comment has been minimized.
This comment has been minimized.
| } | ||
|
|
||
| func runLegacyHelp() error { | ||
| return defaultCmd(append(utils.RemoveSimilar(os.Args[1:], "--"), "--help")) |
There was a problem hiding this comment.
too many function calls in a single line, easy to misread. I'd suggest separating into variables
There was a problem hiding this comment.
ok ok I needed to do one extra modification in any case
|
|
||
| `make -C cliv2 test` and `make build` run this target automatically, but you still need to commit the updated | ||
| `manifest.txt` when it changes. Go tests in `cliv2/pkg/helpdocs` verify that the manifest stays in sync with | ||
| `help/cli-commands/`. |
There was a problem hiding this comment.
so every make build will create this manifest.txt, even in the CI runs? Just wondering if that could create any kind of impact regarding this
There was a problem hiding this comment.
yes it will execute during make build
it won't have any impact and actually it is good. The commands with user help will be added to manifest.txt and the integrity test (helpdocs_test.go#Test_manifestMatchesHelpCLICommands) will not complain. If make buiLd (or directly make -C cliv2 helpdocs-manifest) is not run after adding some user help, the test will fail.
This test is a safeguard so we never forget to add commands with user docs to manifest.txt.
The updated manifest.txt is necessary as it is embedded into helpdocs.go#manifest which feeds docFiles in init() > docFiles > used in HasUserDoc() which is core part of the logic for discerning user docs / Cobra / default
danskmt
left a comment
There was a problem hiding this comment.
LGTM - left some few comments
c1d9be8 to
fe87823
Compare
This comment has been minimized.
This comment has been minimized.
fe87823 to
994a189
Compare
This comment has been minimized.
This comment has been minimized.
| The Go CLI reads user-facing command help from markdown files under `help/cli-commands/`. These files are synced from | ||
| GitBook into this repository (see the `sync-cli-help-to-user-docs` workflow). At build time, the CLI embeds a manifest | ||
| of available help files (`cliv2/pkg/helpdocs/manifest.txt`) and uses it to decide whether to show legacy GitBook help | ||
| or native Cobra help for a given command. |
There was a problem hiding this comment.
Anything in here which audits which commands don't have any help documents?
| ### CLI help command files (`help/cli-commands`) | ||
|
|
||
| The Go CLI reads user-facing command help from markdown files under `help/cli-commands/`. These files are synced from | ||
| GitBook into this repository (see the `sync-cli-help-to-user-docs` workflow). At build time, the CLI embeds a manifest |
There was a problem hiding this comment.
I'd prefer the other way around, that the code defines the public website docs, but I guess that's just preference.
994a189 to
1780cb2
Compare
PR Reviewer Guide 🔍
|
User description
Pull Request Submission Checklist
are release-note ready, emphasizing
what was changed, not how.
What does this PR do?
Shows help generated by Cobra for CLI commands which don't have any GitBook help - existing GitBook help remains as source of truth.
Changes
Help routing now follows this order:
How to find out: generic README contains How to get started. Cobra help contains Usage: and Flags:.
Before
After
Where should the reviewer start?
How should this be manually tested?
Setup
Adjust
BINfor your platform if needed (e.g.snyk-macos-arm64,snyk-linux-amd64).What changed
Help routing now follows this order:
Quick signal: generic README contains
How to get started. Cobra help containsUsage:andFlags:.1. Undocumented Go commands → Cobra help (the fix)
snyk secrets test --helpUsage:+Flags:; not generic READMEsnyk agent-scan --helpsnyk depgraph --helpsnyk secrets test --bad-flag2. Documented commands → user-doc unchanged
snyk test --helpsnyk container --helptest and continuously monitor container images…)snyk iac --helpsnyk redteam setup --helpredteam.md; walk-back)3. Root / unknown help → README unchanged
snyk --helpSnyk CLI scans and monitors…)snyk helpsnyk help hellosnyk --help hello4. Legacy help flag forms (acceptance parity)
Optional grep smoke checks
Regression check
Normal commands should still run (help routing only affects
--help/ flag errors):"$BIN" --versionWhat's the product update that needs to be communicated to CLI users?
PR Type
Enhancement, Documentation, Tests
Description
Implement user-documentation-based help routing.
Prioritize Markdown help files over Cobra's native help.
Generate and embed a manifest of available help documentation.
Update tests and contribute guide for new help system.
Diagram Walkthrough
flowchart LR A["CLI Invoke"] --> B("Help Request"); B --> C{Help Router}; C -- "User Doc Available?" --> D["Show Legacy (Markdown) Help"]; C -- "No User Doc" --> E["Show Cobra Help"]; C -- "Unknown Command" --> D;File Walkthrough
4 files
Update help command tests for new output format.Add tests for new help routing and setup.Add unit tests for help documentation lookup.Add comprehensive tests for help routing scenarios.5 files
Integrate new help routing logic into CLI core.Add logic for checking and identifying user documentation.Implement core help routing logic and decision making.Add Makefile target for help docs manifest generation.Embed manifest of available user help documentation.1 files
Update contribution guide for CLI help commands.