-
Notifications
You must be signed in to change notification settings - Fork 63
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: Config reference documentation autogeneration #2033
Open
ilyakuz-db
wants to merge
45
commits into
main
Choose a base branch
from
feat/config-reference-doc-autogen
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from 33 commits
Commits
Show all changes
45 commits
Select commit
Hold shift + click to select a range
8c58d48
tmp: Documentation autogeneration script
ilyakuz-db e27cc9a
fix: Custom table markup changes
ilyakuz-db fe4c6b8
fix: Styling issues
ilyakuz-db cfa2be3
fix: Remove openAPI docs
ilyakuz-db 10e0d27
fix: Remove extra headings
ilyakuz-db 64fa2bf
fix: Small readme
ilyakuz-db 40c4b3a
Merge branch 'main' of github.com:databricks/cli into feat/config-ref…
ilyakuz-db 820dd5f
feat: Add examples to the docs
ilyakuz-db 460a455
chore: Extract annotation package
ilyakuz-db 541c3e3
feat: More explicit type for arrays
ilyakuz-db 2aadfcb
feat: Support for resources
ilyakuz-db c6703c1
fix: Updated styles
ilyakuz-db fe6ba76
fix: Styling
ilyakuz-db c355fbf
fix: Description of root types with additional properties
ilyakuz-db f9278c2
docs: Add override for volume spec
ilyakuz-db 6c5268a
fix: Missing array types
ilyakuz-db bad77bd
fix: Sync annotations
ilyakuz-db 954ef76
Merge branch 'main' of github.com:databricks/cli into feat/config-ref…
ilyakuz-db d5d433e
fix: More descriptions
ilyakuz-db 1fbec37
fix: Link
ilyakuz-db 151a6f8
fix: Multiple links
ilyakuz-db 4b01f6b
fix: Add links
ilyakuz-db ee5db18
fix: Move logic to separate fiels
ilyakuz-db 0bd7b52
fix: Invalid refrences
ilyakuz-db 880a4cf
fix: Few extra links
ilyakuz-db c546604
fix: Schema bump
ilyakuz-db 90cafad
fix: Allow nodes with only description
ilyakuz-db fd88e4c
fix: Use markdown from original pages
ilyakuz-db 5fb4fa0
fix: Add field-name for some properties
ilyakuz-db ad81e1f
fix: Few links updates
ilyakuz-db c88498e
fix: Schema update
ilyakuz-db 3e0d232
fix: Allow empty fields
ilyakuz-db 2591172
fix: Circular types
ilyakuz-db f684afe
Merge branch 'main' of github.com:databricks/cli into feat/config-ref…
ilyakuz-db 1e41e61
fix: Apps fixes after merge
ilyakuz-db 14b2c86
fix: Add `vendor` step to `make docs`
ilyakuz-db c74ab75
fix: Stage output changes
ilyakuz-db 1b73105
fix: Split annotations/main.go in 2 files
ilyakuz-db e5497f7
fix: Move templates to separate files
ilyakuz-db 33bd3b8
fix: Typo
ilyakuz-db b91bb4d
fix: Remove extra dependency
ilyakuz-db 14721de
fix: More documentation for internal types
ilyakuz-db 26466d2
fix: Remove type inconsistency in maps
ilyakuz-db d27282c
fix: Rename fields to make it more clear
ilyakuz-db 13181fc
fix: More ducmentation + tests
ilyakuz-db File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
pietern marked this conversation as resolved.
Show resolved
Hide resolved
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
package annotation | ||
|
||
import ( | ||
"bytes" | ||
"os" | ||
|
||
"github.com/databricks/cli/libs/dyn" | ||
"github.com/databricks/cli/libs/dyn/convert" | ||
"github.com/databricks/cli/libs/dyn/merge" | ||
"github.com/databricks/cli/libs/dyn/yamlloader" | ||
) | ||
|
||
type Descriptor struct { | ||
Description string `json:"description,omitempty"` | ||
MarkdownDescription string `json:"markdown_description,omitempty"` | ||
Title string `json:"title,omitempty"` | ||
Default any `json:"default,omitempty"` | ||
Enum []any `json:"enum,omitempty"` | ||
MarkdownExamples string `json:"markdown_examples,omitempty"` | ||
} | ||
|
||
/** | ||
* Parsed file with annotations, expected format: | ||
* github.com/databricks/cli/bundle/config.Bundle: | ||
* cluster_id: | ||
* description: "Description" | ||
*/ | ||
pietern marked this conversation as resolved.
Show resolved
Hide resolved
|
||
type File map[string]map[string]Descriptor | ||
|
||
func LoadAndMerge(sources []string) (File, error) { | ||
prev := dyn.NilValue | ||
for _, path := range sources { | ||
b, err := os.ReadFile(path) | ||
if err != nil { | ||
return nil, err | ||
} | ||
generated, err := yamlloader.LoadYAML(path, bytes.NewBuffer(b)) | ||
if err != nil { | ||
return nil, err | ||
} | ||
prev, err = merge.Merge(prev, generated) | ||
if err != nil { | ||
return nil, err | ||
} | ||
} | ||
|
||
var data File | ||
|
||
err := convert.ToTyped(&data, prev) | ||
if err != nil { | ||
return nil, err | ||
} | ||
return data, nil | ||
} | ||
|
||
const Placeholder = "PLACEHOLDER" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
output/**/* |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
## docs-autogen | ||
|
||
1. Install [Golang](https://go.dev/doc/install) | ||
2. Run `go mod download` from the repo root | ||
3. Run `make docs` from the repo | ||
pietern marked this conversation as resolved.
Show resolved
Hide resolved
|
||
4. See generated documents in `./bundle/internal/docs/output` directory | ||
5. To change descriptions update content in `./bundle/internal/schema/annotations.yml` or `./bundle/internal/schema/annotations_openapi_overrides.yml` and re-run `make docs` | ||
|
||
For simpler usage run it together with copy command to move resulting files to local `docs` repo. Note that it will overwrite any local changes in affected files. Example: | ||
|
||
``` | ||
make docs && cp bundle/internal/docs/output/*.md ../docs/source/dev-tools/bundles | ||
``` | ||
|
||
To change file names or file headers update them in `main.go` file in this directory | ||
|
||
### Annotation file structure | ||
|
||
```yaml | ||
"<root-type-name>": | ||
"<property-name>": | ||
description: Description of the property, only plain text is supported | ||
markdown_description: Description with markdown support, if defined it will override the value in docs and in JSON-schema | ||
markdown_examples: Custom block for any example, in free form, Markdown is supported | ||
title: JSON-schema title, not used in docs | ||
default: Default value of the property, not used in docs | ||
enum: Possible values of enum-type, not used in docs | ||
``` | ||
|
||
Descriptions with `PLACEHOLDER` value are not displayed in docs and JSON-schema | ||
|
||
All relative links like `[_](/dev-tools/bundles/settings.md#cluster_id)` are kept as is in docs but converted to absolute links in JSON schema | ||
|
||
### Example annotation | ||
|
||
```yaml | ||
github.com/databricks/cli/bundle/config.Bundle: | ||
"cluster_id": | ||
"description": |- | ||
The ID of a cluster to use to run the bundle. | ||
"markdown_description": |- | ||
The ID of a cluster to use to run the bundle. See [_](/dev-tools/bundles/settings.md#cluster_id). | ||
"compute_id": | ||
"description": |- | ||
PLACEHOLDER | ||
"databricks_cli_version": | ||
"description": |- | ||
The Databricks CLI version to use for the bundle. | ||
"markdown_description": |- | ||
The Databricks CLI version to use for the bundle. See [_](/dev-tools/bundles/settings.md#databricks_cli_version). | ||
"deployment": | ||
"description": |- | ||
The definition of the bundle deployment | ||
"markdown_description": |- | ||
The definition of the bundle deployment. For supported attributes, see [_](#deployment) and [_](/dev-tools/bundles/deployment-modes.md). | ||
"git": | ||
"description": |- | ||
The Git version control details that are associated with your bundle. | ||
"markdown_description": |- | ||
The Git version control details that are associated with your bundle. For supported attributes, see [_](#git) and [_](/dev-tools/bundles/settings.md#git). | ||
"name": | ||
"description": |- | ||
The name of the bundle. | ||
"uuid": | ||
"description": |- | ||
PLACEHOLDER | ||
``` | ||
|
||
### TODO | ||
|
||
Add file watcher to track changes in the annotation files and re-run `make docs` script automtically |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,119 @@ | ||
package main | ||
|
||
import ( | ||
"fmt" | ||
"log" | ||
"os" | ||
"path" | ||
"reflect" | ||
"strings" | ||
|
||
"github.com/databricks/cli/bundle/config" | ||
"github.com/databricks/cli/bundle/internal/annotation" | ||
"github.com/databricks/cli/libs/jsonschema" | ||
) | ||
|
||
func main() { | ||
if len(os.Args) != 3 { | ||
fmt.Println("Usage: go run main.go <annotation-file> <output-file>") | ||
os.Exit(1) | ||
} | ||
|
||
annotationDir := os.Args[1] | ||
docsDir := os.Args[2] | ||
outputDir := path.Join(docsDir, "output") | ||
|
||
if _, err := os.Stat(outputDir); os.IsNotExist(err) { | ||
if err := os.MkdirAll(outputDir, 0o755); err != nil { | ||
log.Fatal(err) | ||
} | ||
} | ||
|
||
err := generateDocs( | ||
[]string{path.Join(annotationDir, "annotations.yml")}, | ||
path.Join(outputDir, rootFileName), | ||
reflect.TypeOf(config.Root{}), | ||
rootHeader, | ||
) | ||
if err != nil { | ||
log.Fatal(err) | ||
} | ||
err = generateDocs( | ||
[]string{path.Join(annotationDir, "annotations_openapi.yml"), path.Join(annotationDir, "annotations_openapi_overrides.yml"), path.Join(annotationDir, "annotations.yml")}, | ||
path.Join(outputDir, resourcesFileName), | ||
reflect.TypeOf(config.Resources{}), | ||
resourcesHeader, | ||
) | ||
if err != nil { | ||
log.Fatal(err) | ||
} | ||
} | ||
|
||
func generateDocs(inputPaths []string, outputPath string, rootType reflect.Type, header string) error { | ||
annotations, err := annotation.LoadAndMerge(inputPaths) | ||
if err != nil { | ||
log.Fatal(err) | ||
} | ||
|
||
schemas := map[string]jsonschema.Schema{} | ||
customFields := map[string]bool{} | ||
|
||
s, err := jsonschema.FromType(rootType, []func(reflect.Type, jsonschema.Schema) jsonschema.Schema{ | ||
func(typ reflect.Type, s jsonschema.Schema) jsonschema.Schema { | ||
_, isCustomField := annotations[jsonschema.TypePath(typ)] | ||
if isCustomField { | ||
customFields[jsonschema.TypePath(typ)] = true | ||
} | ||
|
||
refPath := getPath(typ) | ||
shouldHandle := strings.HasPrefix(refPath, "github.com") | ||
if !shouldHandle { | ||
schemas[jsonschema.TypePath(typ)] = s | ||
return s | ||
} | ||
|
||
a := annotations[refPath] | ||
if a == nil { | ||
a = map[string]annotation.Descriptor{} | ||
} | ||
|
||
rootTypeAnnotation, ok := a["_"] | ||
if ok { | ||
assignAnnotation(&s, rootTypeAnnotation) | ||
} | ||
|
||
for k, v := range s.Properties { | ||
assignAnnotation(v, a[k]) | ||
} | ||
|
||
schemas[jsonschema.TypePath(typ)] = s | ||
return s | ||
}, | ||
}) | ||
if err != nil { | ||
log.Fatal(err) | ||
} | ||
|
||
nodes := getNodes(s, schemas, customFields) | ||
err = buildMarkdown(nodes, outputPath, header) | ||
if err != nil { | ||
log.Fatal(err) | ||
} | ||
return nil | ||
} | ||
|
||
func getPath(typ reflect.Type) string { | ||
return typ.PkgPath() + "." + typ.Name() | ||
} | ||
|
||
func assignAnnotation(s *jsonschema.Schema, a annotation.Descriptor) { | ||
if a.Description != "" && a.Description != annotation.Placeholder { | ||
s.Description = a.Description | ||
} | ||
if a.MarkdownDescription != "" { | ||
s.MarkdownDescription = a.MarkdownDescription | ||
} | ||
if a.MarkdownExamples != "" { | ||
s.Examples = []any{a.MarkdownExamples} | ||
} | ||
} |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why is this part if /bundle/internal/ ?
internal is meant for code that is not meant to be used outside of the package, but this is clearly intended to be used outside the package, that's why it's in Makefile.
How about placing this at top level? /docsgen/ ?
I see you're following existing structure, so it's a more of a question for @pietern
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes I reused same approach as with json schema generation which is used in
.codegen.json
along with other internal scripts