Skip to content

feat: add support for scw docs - #6193

Draft
remyleone wants to merge 1 commit into
mainfrom
docs_browser
Draft

remyleone wants to merge 1 commit into
mainfrom
docs_browser

Conversation

@remyleone

Copy link
Copy Markdown
Member

Community Note

  • Please vote on this pull request by adding a 👍 reaction to the original pull request comment to help the community and maintainers prioritize this request.
  • Please do not leave "+1" or other comments that do not add relevant new information or questions, they generate extra noise for pull request followers and do not help prioritize the request

Relates OR Closes #0000

Copilot AI lite review requested due to automatic review settings September 12, 2026 17:11

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

One or more issues must be addressed before approval.

Get a fresh assessment by requesting another Copilot review.

Pull request overview

Adds interactive CLI documentation browsing/search and guided tutorials with progress persistence.

Changes:

  • Adds documentation hierarchy rendering, fuzzy search, browser UI, and command tips.
  • Adds tutorial catalog, runner, resume support, and progress storage.
  • Registers both namespaces and adds tests, fixtures, and dependencies.
File summaries
File Description
internal/namespaces/tutorial/tutorials.go Updated as part of this pull request.
internal/namespaces/tutorial/tutorial_test.go Updated as part of this pull request.
internal/namespaces/tutorial/tutorial_disabled.go Updated as part of this pull request.
internal/namespaces/tutorial/testdata/test-tutorial-resume-no-progress-no-progress.golden Updated as part of this pull request.
internal/namespaces/tutorial/testdata/test-tutorial-list-simple.golden Updated as part of this pull request.
internal/namespaces/tutorial/runner.go Updated as part of this pull request.
internal/namespaces/tutorial/progress.go Updated as part of this pull request.
internal/namespaces/tutorial/custom.go Updated as part of this pull request.
internal/namespaces/docs/tips.go Updated as part of this pull request.
internal/namespaces/docs/testdata/test-docs-search-search-server.golden Updated as part of this pull request.
internal/namespaces/docs/testdata/test-docs-search-no-results-no-results.golden Updated as part of this pull request.
internal/namespaces/docs/testdata/test-docs-namespace-not-found-not-found.golden Updated as part of this pull request.
internal/namespaces/docs/testdata/test-docs-list-non-interactive.golden Updated as part of this pull request.
internal/namespaces/docs/testdata/test-docs-command-page-instance-server-list.golden Updated as part of this pull request.
internal/namespaces/docs/search.go Updated as part of this pull request.
internal/namespaces/docs/render.go Updated as part of this pull request.
internal/namespaces/docs/fuzzy.go Updated as part of this pull request.
internal/namespaces/docs/docs_test.go Updated as part of this pull request.
internal/namespaces/docs/custom.go Updated as part of this pull request.
internal/namespaces/docs/browser.go Updated as part of this pull request.
internal/namespaces/docs/browser_disabled.go Updated as part of this pull request.
go.sum Updated as part of this pull request.
go.mod Updated as part of this pull request.
commands/commands.go Updated as part of this pull request.
Review details

Suppressed comments (12)

internal/namespaces/docs/custom.go:103

  • A namespace-only command is not necessarily a namespace container: commands such as login, version, and docs have no subcommands but do have a runnable command page. This branch renders scw docs login (and similar leaf commands) as an empty namespace page, omitting usage, arguments, examples, and tips; check commands.HasSubCommands(cmd) before choosing the namespace renderer.
	if cmd.Namespace != "" && cmd.Resource == "" && cmd.Verb == "" {
		return RenderNamespacePage(commands, cmd.Namespace), nil

internal/namespaces/docs/custom.go:84

  • SearchCommands and BuildHierarchy both exclude Hidden commands, but direct-path rendering bypasses that policy. A user who knows a hidden command path can therefore expose it through scw docs; reject hidden commands here as well.
	if cmd == nil {

internal/namespaces/docs/fuzzy.go:27

  • The target is lowercased before being passed to isWordBoundary, so the helper can never see an original lower-to-upper transition. The documented camelCase boundary bonus is therefore unreachable and fuzzy ranking is wrong for camelCase text; retain the original target runes for the boundary check while comparing lowercased runes.
	targetLower := strings.ToLower(target)
	queryLower := strings.ToLower(query)

	queryRunes := []rune(queryLower)
	targetRunes := []rune(targetLower)

internal/namespaces/docs/tips.go:11

  • organization-id is a command argument, not a registered global flag, so --organization-id is not a valid token for this command. Users following this tip will receive an argument parsing error.
		"Use --organization-id to filter by organization.",

internal/namespaces/docs/tips.go:15

  • These Kubernetes examples use the same invalid -- argument syntax. The command-specific forms are version=<version> and cni=cilium or cni=calico, otherwise the copied commands fail parsing.
		"Use --version to specify the Kubernetes version.",
		"Use --cni to specify the container network interface (cilium or calico).",

internal/namespaces/docs/tips.go:25

  • This pitfall again uses --zone=all, but zone is a command-specific argument and must be passed as zone=all. The current copy-paste example is rejected by the CLI argument parser.
		"By default, only servers in the default zone are listed. Use --zone=all to list across all zones.",

internal/namespaces/tutorial/progress.go:44

  • The context is discarded and the SDK's process-global GetScwConfigDir is used for progress storage. This ignores the CLI's contextual environment overrides; in particular, core.Test isolates HOME only through Meta.OverrideEnv, so these commands can read or write the developer's real ~/.config/scw/tutorial-progress.json and make resume behavior depend on external state. Derive the path from the command context and isolate the test fixture.
func progressFilePath(_ context.Context) string {
	configDir, err := scw.GetScwConfigDir()
	if err != nil {
		configDir = filepath.Join(os.Getenv("HOME"), ".config", "scw")
	}

	return filepath.Join(configDir, "tutorial-progress.json")

internal/namespaces/tutorial/runner.go:130

  • Readline returns an interactive.InterruptError on Ctrl-C, but this error is discarded here, so cancelling a non-command step still advances and saves that step as completed. Return the error before updating p.CurrentStep.
			_, _ = interactive.Readline(ctx, &interactive.ReadlineConfig{})

internal/namespaces/tutorial/runner.go:235

  • Selecting yes here does not run scw init; it only returns an error telling the user to run it later. Either invoke the init command or change the earlier prompt to say that manual action is required.
				if runInit {
					return errors.New("please run 'scw init' and then restart the tutorial")

internal/namespaces/tutorial/runner.go:22

  • This non-interactive branch discards startStep and never updates progress because runTutorialNonInteractive always iterates from step zero. Consequently scw tutorial resume repeats completed steps and leaves the tutorial unfinished when no TTY is available. Pass the start index through and either persist progress consistently or explicitly reject non-interactive resume.
func RunTutorial(ctx context.Context, tutorial Tutorial, startStep int) error {
	if !interactive.IsInteractive {
		return runTutorialNonInteractive(ctx, tutorial)

internal/namespaces/tutorial/runner.go:266

  • This prompt is reached before RunTutorial checks interactive.IsInteractive, so a non-interactive scw tutorial <id> or resume with saved progress from another CLI version attempts to open readline. That makes automation fail or block on input; choose and implement a deterministic non-interactive restart/continue policy before calling PromptBool.
		restart, err := interactive.PromptBool(
			ctx,
			fmt.Sprintf(
				"This tutorial was started with CLI version %s but you are now running version %s. Restart from the beginning?",
				p.CLIVersion,
				currentVersion,
			),
			true,
		)

internal/namespaces/tutorial/tutorials.go:62

  • This hint uses --zone=all, but command-specific arguments use name=value tokens and the raw parser does not strip -- prefixes. Users copying the hint will get an invalid argument error; use zone=all instead.
			ErrorHint:      "Make sure you have servers in your default zone. Use --zone=all to list across all zones.",
  • Files reviewed: 23/24 changed files
  • Comments generated: 12
  • Review effort level: Lite

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment on lines +3 to +7
scw block volume create - Create a volume
scw config validate - Validate the config
scw help output - Get help about how the CLI output works
🟩🟩🟩 JSON STDOUT 🟩🟩🟩
"scw block volume create - Create a volume\nscw config validate - Validate the config\nscw help output - Get help about how the CLI output works"
return nil, err
}

return progress, nil
{
Title: "Check Configuration",
Concept: "Let's verify your CLI is properly configured. This command shows your current settings including credentials, default zone, and project.",
Command: "scw config show",
Comment on lines +208 to +211
resCmd := resNode.Command
if resCmd != nil && resCmd.Run != nil && len(resNode.Verbs) == 0 {
m.commandPage = RenderCommandPage(m.ctx, resCmd, m.commands)
m.level = levelCommand
Comment on lines +231 to +232
case levelCommand:
return tea.Quit
Comment on lines +277 to +280
func runTutorialNonInteractive(_ context.Context, tutorial Tutorial) error {
for i, step := range tutorial.Steps {
fmt.Printf("Step %d/%d: %s\n\n", i+1, len(tutorial.Steps), step.Title)
fmt.Println(step.Concept)
Comment on lines +5 to +6
"Use --boot-type=local to boot from a local image for faster startup.",
"Use --root-volume=size:50GB to specify the root disk size.",
Comment on lines +21 to +22
"Forgetting to specify --image or --boot-type will result in a server that cannot boot.",
"The --root-volume flag must include a size suffix (e.g. 50GB).",
),
)
}
sb.WriteString("\nRun 'scw tutorial <title>' to start a tutorial.")
Comment on lines +52 to +54
t.Run("no-progress", core.Test(&core.TestConfig{
Commands: commands.GetCommands(),
Cmd: "scw tutorial resume",
@remyleone
remyleone marked this pull request as draft September 14, 2026 12:41
@remyleone remyleone changed the title feat: add support for docs feat: add support for scw docs Sep 14, 2026

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants