Skip to content

Commit

Permalink
Auto generate CLI docs for documentation repo (#685)
Browse files Browse the repository at this point in the history
## What was changed
Auto generate all of the *.mdx files present in the current
documentation repo. index.mdx is not auto-generated

IMPORTANT: The generated files are not yet being consumed anywhere. A
future PR will auto-publish a PR into the docs repo whenever there is a
docs related change.

Added a field in the YML to indicate doc-specific information, like SEO
related keywords and descriptions.

Removed `cmd-options.cdx` and print each command option description
inline in each file instead.
temporalio/documentation#3122 removes all
references to this file from the documentation side.

## Why?
This is in a larger effort to have the CLI be the source of truth for
docs, and have the documentation auto-ingest any CLI changes, keeping
all information in sync.

This is the first step to this goal, there are a number of follow up
tasks that I wanted to split up from this PR:
1. Diff the current information on the docs with the CLI, and unify into
a single master-description for each command.
2. Auto-publish PR to docs repo whenever there is a CLI doc change
1. Auto update sidebars.js and vercel.js whenever a new temporal command
is added.
3. Clean up the SEO keywords/tags - being handled by the documentation
team
4. Support markdown in the CLI help output in terminal #687

## Checklist
7. Any docs updates needed?
<!--- update README if applicable
      or point out where to update docs.temporal.io -->
For now, docs will not be updated. There will be a future PR that
auto-creates a PR into the documentation repo with any updates.

---------

Co-authored-by: David Reiss <[email protected]>
  • Loading branch information
yuandrew and dnr authored Oct 8, 2024
1 parent 4daeb0e commit bd76c2f
Show file tree
Hide file tree
Showing 5 changed files with 343 additions and 0 deletions.
8 changes: 8 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,15 @@ First, update [commands.yml](temporalcli/commandsgen/commands.yml) following the
This will expect every non-parent command to have a `run` method, so for new commands developers will have to implement
`run` on the new command in a separate file before it will compile.

Once a command is updated, the CI will automatically generate new docs
and create a PR in the Documentation repo with the corresponding updates. To generate these docs locally, run:

go run ./temporalcli/internal/cmd/gen-docs

This will auto-generate a new set of docs to `temporalcli/docs/`. If a new root command is added, a new file will be automatically generated, like `temporal activity` and `activity.mdx`.

## Inject additional build-time information

To add build-time information to the version string printed by the binary, use

go build -ldflags "-X github.com/temporalio/cli/temporalcli.buildInfo=<MyString>"
Expand Down
152 changes: 152 additions & 0 deletions temporalcli/commandsgen/commands.yml
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,20 @@ commands:
```
option-sets:
- client
docs:
description-header: >-
Learn how to use Temporal Activity commands for completing or failing
Activity Executions in your Workflow. Optimize your Temporal Workflow
management effectively.
keywords:
- activity
- activity complete
- activity execution
- activity fail
- cli reference
- cli-feature
- command-line-interface-cli
- temporal cli

- name: temporal activity complete
summary: Complete an Activity
Expand Down Expand Up @@ -308,6 +322,20 @@ commands:
and Query creation.
option-sets:
- client
docs:
description-header: >-
Use Temporal CLI to manage multiple Workflow Executions with Batch
Jobs that can Cancel, Signal, or Terminate Workflows. Filter and monitor
Batch Jobs effectively.
keywords:
- batch
- batch describe
- batch list
- batch terminate
- cli reference
- cli-feature
- command-line-interface-cli
- temporal cli

- name: temporal batch describe
summary: Show batch job progress
Expand Down Expand Up @@ -382,6 +410,22 @@ commands:
Temporal CLI checks for an `--env` option first, then checks for the
`TEMPORAL_ENV` environment variable. If neither is set, the CLI uses the
"default" environment.
docs:
description-header: >-
Temporal CLI 'env' commands allow the configuration, setting, deleting,
and listing of environmental properties, making it easy to manage Temporal
Server instances.
keywords:
- cli reference
- command-line-interface-cli
- configuration
- env
- env delete
- env get
- env list
- env set
- environment
- temporal cli

- name: temporal env delete
summary: Delete an environment or environment property
Expand Down Expand Up @@ -495,6 +539,33 @@ commands:
```
option-sets:
- client
docs:
description-header: >-
Operator commands in Temporal allow actions on Namespaces, Search Attributes,
and Clusters using specific subcommands. Execute with
"temporal operator [command] [subcommand] [options]".
keywords:
- cli reference
- cluster
- cluster health
- cluster list
- cluster remove
- cluster upsert
- command-line-interface-cli
- describe
- namespace
- namespace create
- namespace delete
- namespace describe
- namespace list
- operator
- search attribute
- search attribute create
- search attribute list
- search attribute remove
- system
- temporal cli
- update

- name: temporal operator cluster
summary: Manage a Temporal Cluster
Expand Down Expand Up @@ -1100,6 +1171,26 @@ commands:
```
option-sets:
- client
docs:
description-header: >-
Temporal's Schedule commands allow users to create, update, and manage
Workflow Executions seamlessly for automation, supporting commands for
creation, backfill, deletion, and more.
keywords:
- backfill
- cli reference
- command-line-interface-cli
- schedule
- schedule backfill
- schedule create
- schedule delete
- schedule describe
- schedule list
- schedule toggle
- schedule trigger
- schedule update
- temporal cli
- updates

- name: temporal schedule backfill
summary: Backfill past actions
Expand Down Expand Up @@ -1339,6 +1430,17 @@ commands:
temporal server start-dev \
--ui-port 3000
```
docs:
description-header: >-
Manage your Temporal Server easily with CLI commands. Start a local
server using `temporal server start-dev` and access the Web UI at
http://localhost:8233. Customize with multiple options.
keywords:
- cli reference
- command-line-interface-cli
- server
- server start-dev
- temporal cli

- name: temporal server start-dev
summary: Start Temporal development server
Expand Down Expand Up @@ -1467,6 +1569,19 @@ commands:
```
option-sets:
- client
docs:
description-header: >-
Temporal Task Queue commands facilitate operations like describing
poller info, displaying partitions, fetching compatible Build IDs,
and determining Build ID reachability for effective Workflow and
Activity management.
keywords:
- cli reference
- command-line-interface-cli
- list partitions
- task queue
- task queue describe
- temporal cli

- name: temporal task-queue describe
summary: Show active Workers
Expand Down Expand Up @@ -2181,6 +2296,43 @@ commands:
```
option-sets:
- client
docs:
description-header: >-
Temporal Workflow commands enable operations on Workflow Executions,
such as cancel, count, delete, describe, execute, list, query, reset,
reset-batch, show, signal, stack, start, terminate, trace, and update,
enhancing efficiency and control.
keywords:
- call stack
- cancellation
- child workflows
- cli reference
- command-line-interface-cli
- event history
- query
- resets-feature
- signals
- signals-feature
- stack trace
- temporal cli
- termination
- workflow
- workflow cancel
- workflow count
- workflow delete
- workflow describe
- workflow execute
- workflow execution
- workflow list
- workflow query
- workflow reset
- workflow reset-batch
- workflow show
- workflow signal
- workflow stack
- workflow start
- workflow terminate
- workflow trace

- name: temporal workflow cancel
summary: Send cancellation to Workflow Execution
Expand Down
117 changes: 117 additions & 0 deletions temporalcli/commandsgen/docs.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
package commandsgen

import (
"bytes"
"fmt"
"sort"
"strings"
)

type DocsFile struct {
FileName string
}

func GenerateDocsFiles(commands Commands) (map[string][]byte, error) {
optionSetMap := make(map[string]OptionSets)
for i, optionSet := range commands.OptionSets {
optionSetMap[optionSet.Name] = commands.OptionSets[i]
}

w := &docWriter{fileMap: make(map[string]*bytes.Buffer), optionSetMap: optionSetMap}

// sort by parent command (activity, batch, etc)
for _, cmd := range commands.CommandList {
if err := cmd.writeDoc(w); err != nil {
return nil, fmt.Errorf("failed writing docs for command %s: %w", cmd.FullName, err)
}
}

// Format and return
var finalMap = make(map[string][]byte)
for key, buf := range w.fileMap {
finalMap[key] = buf.Bytes()
}
return finalMap, nil
}

type docWriter struct {
fileMap map[string]*bytes.Buffer
optionSetMap map[string]OptionSets
optionsStack [][]Option
}

func (c *Command) writeDoc(w *docWriter) error {
commandLength := len(strings.Split(c.FullName, " "))
w.processOptions(c)

// If this is a root command, write a new file
if commandLength == 2 {
w.writeCommand(c)
} else if commandLength > 2 {
w.writeSubcommand(c)
}
return nil
}

func (w *docWriter) writeCommand(c *Command) {
fileName := strings.Split(c.FullName, " ")[1]
w.fileMap[fileName] = &bytes.Buffer{}
w.fileMap[fileName].WriteString("---\n")
w.fileMap[fileName].WriteString("id: " + fileName + "\n")
w.fileMap[fileName].WriteString("title: " + c.FullName + "\n")
w.fileMap[fileName].WriteString("sidebar_label: " + c.FullName + "\n")
w.fileMap[fileName].WriteString("description: " + c.Docs.DescriptionHeader + "\n")
w.fileMap[fileName].WriteString("toc_max_heading_level: 4\n")
w.fileMap[fileName].WriteString("keywords:\n")
for _, keyword := range c.Docs.Keywords {
w.fileMap[fileName].WriteString(" - " + keyword + "\n")
}
// tags are the same as Keywords, but with `-` instead of ` `
w.fileMap[fileName].WriteString("tags:\n")
for _, keyword := range c.Docs.Keywords {
w.fileMap[fileName].WriteString(" - " + strings.ReplaceAll(keyword, " ", "-") + "\n")
}
w.fileMap[fileName].WriteString("---\n\n")
}

func (w *docWriter) writeSubcommand(c *Command) {
fileName := strings.Split(c.FullName, " ")[1]
subCommand := strings.Join(strings.Split(c.FullName, " ")[2:], "")
w.fileMap[fileName].WriteString("## " + subCommand + "\n\n")
w.fileMap[fileName].WriteString(c.Description + "\n\n")
w.fileMap[fileName].WriteString("Use the following options to change the behavior of this command.\n\n")

// gather options from command and all options aviailable from parent commands
var allOptions = make([]Option, 0)
for _, options := range w.optionsStack {
allOptions = append(allOptions, options...)
}

// alphabetize options
sort.Slice(allOptions, func(i, j int) bool {
return allOptions[i].Name < allOptions[j].Name
})

for _, option := range allOptions {
w.fileMap[fileName].WriteString(fmt.Sprintf("## %s\n\n", option.Name))
w.fileMap[fileName].WriteString(option.Description + "\n\n")

}
}

func (w *docWriter) processOptions(c *Command) {
// Pop options from stack if we are moving up a level
if len(w.optionsStack) >= len(strings.Split(c.FullName, " ")) {
w.optionsStack = w.optionsStack[:len(w.optionsStack)-1]
}
var options []Option
options = append(options, c.Options...)

// Maintain stack of options available from parent commands
for _, set := range c.OptionSets {
optionSetOptions := w.optionSetMap[set].Options
options = append(options, optionSetOptions...)
}

w.optionsStack = append(w.optionsStack, options)
}
16 changes: 16 additions & 0 deletions temporalcli/commandsgen/parse.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,13 @@ type (
IgnoreMissingEnv bool `yaml:"ignores-missing-env"`
Options []Option `yaml:"options"`
OptionSets []string `yaml:"option-sets"`
Docs Docs `yaml:"docs"`
}

// Docs represents docs-only information that is not used in CLI generation.
Docs struct {
Keywords []string `yaml:"keywords"`
DescriptionHeader string `yaml:"description-header"`
}

// OptionSets represents the structure of option sets.
Expand Down Expand Up @@ -125,6 +132,15 @@ func (c *Command) processSection() error {
return fmt.Errorf("missing description for command: %s", c.FullName)
}

if len(c.NamePath) == 2 {
if c.Docs.Keywords == nil {
return fmt.Errorf("missing keywords for root command: %s", c.FullName)
}
if c.Docs.DescriptionHeader == "" {
return fmt.Errorf("missing description for root command: %s", c.FullName)
}
}

// Strip trailing newline for description
c.Description = strings.TrimRight(c.Description, "\n")

Expand Down
Loading

0 comments on commit bd76c2f

Please sign in to comment.