Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 15 additions & 5 deletions .github/workflows/generate-docs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,11 @@ on:
env:
DOCS_TOKEN: ${{ secrets.DOCS_TOKEN }}
TARGET_REPOSITORY: OctopusDeploy/docs
TARGET_DIRECTORY: src/pages/docs/octopus-rest-api/cli
# The command pages. _generated is the docs repo's convention for a folder a
# generator owns outright, served from the folder above it by an Astro route.
TARGET_DIRECTORY: src/pages/docs/cli/_generated
# The rows the hand-written overview page at /docs/cli imports.
COMMAND_LIST_PATH: src/shared-content/cli/commands.include.md
# Always sync to the same branch in case there's already an open PR, in which case it'll be updated
SYNC_BRANCH: cli-docs-sync
PR_LABEL: cli-docs-sync
Expand Down Expand Up @@ -56,7 +60,13 @@ jobs:

- name: Generate cli docs
working-directory: cli
run: mkdir -p ../docs/$TARGET_DIRECTORY && go run cmd/gen-docs/main.go --website --doc-path ../docs/$TARGET_DIRECTORY --relative-base-path /docs/octopus-rest-api/cli
run: |
mkdir -p ../docs/$TARGET_DIRECTORY
go run cmd/gen-docs/main.go \
--website \
--doc-path ../docs/$TARGET_DIRECTORY \
--command-list-path ../docs/$COMMAND_LIST_PATH \
--relative-base-path /docs/cli

- name: Commit and push
id: commit
Expand All @@ -69,10 +79,10 @@ jobs:
git config user.email 'bob@octopus.com'
git config user.name octobob

git add --all -- "$TARGET_DIRECTORY"
git add --all -- "$TARGET_DIRECTORY" "$COMMAND_LIST_PATH"

# Safety net: only the target folder should have been touched
unexpected_changes="$(git diff --cached --name-only -- . ":(exclude)$TARGET_DIRECTORY")"
# Safety net: only the generated files should have been touched
unexpected_changes="$(git diff --cached --name-only -- . ":(exclude)$TARGET_DIRECTORY" ":(exclude)$COMMAND_LIST_PATH")"
if [ -n "$unexpected_changes" ]; then
echo "Found unexpected staged changes, aborting" >&2
echo "$unexpected_changes" >&2
Expand Down
95 changes: 62 additions & 33 deletions cmd/gen-docs/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ func run(args []string) error {
website := flags.BoolP("website", "", false, "Generate website pages")
dir := flags.StringP("doc-path", "", "", "Path directory where you want generate doc files")
relativeBasePath := flags.StringP("relative-base-path", "", "", "Relative base path for generating index links")
commandListPath := flags.StringP("command-list-path", "", "", "File to write the command list include to. Skipped when unset")
help := flags.BoolP("help", "h", false, "Help about any command")

if err := flags.Parse(args); err != nil {
Expand Down Expand Up @@ -127,17 +128,39 @@ func run(args []string) error {
return err
}

filename := filepath.Join(*dir, "index.md")
f, err := os.Create(filename)
written := make(map[string]bool, pageCollection.Pages.Len())
for _, page := range *pageCollection.Pages {
written[filepath.Base(page.OutputFile)] = true
}

// A generator failure that produced almost nothing would otherwise sync as
// a mass deletion. The real count is in the hundreds.
if len(written) < minimumPageCount {
return fmt.Errorf("only generated %d page(s), expected at least %d, so something went wrong", len(written), minimumPageCount)
}

if err := pruneStalePages(*dir, written); err != nil {
return err
}

if *commandListPath == "" {
return nil
}

if err := os.MkdirAll(filepath.Dir(*commandListPath), 0755); err != nil {
return err
}

// Not `f`: that is the command factory, several lines up.
out, err := os.Create(*commandListPath)
if err != nil {
return err
}
defer f.Close()
t := template.Must(template.New("index-template").Parse(indexTemplate))
defer out.Close()

sort.Sort(pageCollection.Pages)
t.Execute(f, pageCollection)
return nil
t := template.Must(template.New("command-list-template").Parse(commandListTemplate))
return t.Execute(out, pageCollection)
}

header := &doc.GenManHeader{
Expand All @@ -154,6 +177,32 @@ func run(args []string) error {
return nil
}

// Below this, assume the generator broke rather than that the CLI lost most of
// its commands.
const minimumPageCount = 50

// pruneStalePages removes the .mdx files in dir that this run did not write, so
// a renamed or removed command takes its page with it.
func pruneStalePages(dir string, written map[string]bool) error {
entries, err := os.ReadDir(dir)
if err != nil {
return err
}

for _, entry := range entries {
name := entry.Name()
if entry.IsDir() || filepath.Ext(name) != ".mdx" || written[name] {
continue
}
if err := os.Remove(filepath.Join(dir, name)); err != nil {
return err
}
fmt.Fprintf(os.Stderr, "removed stale page %s\n", name)
}

return nil
}

func GenMarkdownCustom(cmd *cobra.Command, w io.Writer, info *TemplateInformation) error {
cmd.InitDefaultHelpCmd()
cmd.InitDefaultHelpFlag()
Expand Down Expand Up @@ -214,7 +263,7 @@ func contentEqualIgnoringModDate(a, b []byte) bool {
}

const documentationTemplate = `---
layout: src/layouts/Default.astro
layout: src/layouts/Cli.astro
pubDate: 2023-01-01
modDate: {{.Date}}
title: {{.Title}}
Expand Down Expand Up @@ -263,32 +312,12 @@ Use "{{.CommandPath}} [command] --help" for more information about a command.{{e

## Learn more

- [Octopus CLI](/docs/octopus-rest-api/cli)
- [Octopus CLI](/docs/cli)
- [Creating API keys](/docs/octopus-rest-api/how-to-create-an-api-key)
`

const indexTemplate = `---
layout: src/layouts/Default.astro
pubDate: 2023-01-01
modDate: 2023-01-01
title: CLI
description: The all-new Octopus CLI
navOrder: 100
hideInThisSection: true
---

The Octopus CLI is a command line tool that builds on top of the [Octopus Deploy REST API](/docs/octopus-rest-api). With the Octopus CLI you can push your application packages for deployment as either Zip or NuGet packages, and manage your environments, deployments, projects, and workers.

The Octopus CLI can be used on Windows, Mac, Linux and Docker. For installation options and direct downloads, visit the [CLI Readme](https://github.com/OctopusDeploy/cli/blob/main/README.md).

:::div{.hint}
The Octopus CLI is built and maintained by the Octopus Deploy team, but it is also open source. You can [view the Octopus CLI project on GitHub](https://github.com/OctopusDeploy/cli), which leans heavily on the [go-octopusdeploy library](https://github.com/OctopusDeploy/go-octopusdeploy).
:::

## Commands {#octopusCommandLine-Commands}

` + "`octopus` supports the following commands:" +
`
{{range .Pages}}
- **[{{.Title}}]({{.RelativePath}})**: {{.Command.Short}}.{{end}}
`
// The rows the overview page lists. The prose around them, and the frontmatter,
// belong to the docs repo: this is imported by src/pages/docs/cli/index.mdx as a
// shared-content include, so a wording change there needs no release here.
const commandListTemplate = `{{range .Pages}}- **[{{.Title}}]({{.RelativePath}})**: {{.Command.Short}}.
{{end}}`
Loading