mirror of https://github.com/databricks/cli.git
Work in progress to automate doc generation
This commit is contained in:
parent
a014d50a6a
commit
53289dabdd
|
@ -0,0 +1,58 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"slices"
|
||||
"strings"
|
||||
|
||||
"github.com/databricks/databricks-sdk-go/service/serving"
|
||||
)
|
||||
|
||||
func PromptMessage() ([]serving.ChatMessage, error) {
|
||||
home, err := os.UserHomeDir()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
dir := filepath.Join(home, "emu/docs/source/dev-tools/cli")
|
||||
files, err := filepath.Glob(filepath.Join(dir, "*.md"))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
messages := []string{`
|
||||
You're helping write documentation for the Databricks CLI.
|
||||
Forget everything you know about the Databricks CLI and start from scratch.
|
||||
You'll be provided with all the information you need to write the documentation.
|
||||
Example invocations must be wrapped in Markdown code blocks.
|
||||
|
||||
What follows is existing official documentation for the Databricks CLI.
|
||||
`}
|
||||
|
||||
ignore := []string{
|
||||
"completion-commands.md",
|
||||
"migrate.md",
|
||||
"bundle-commands.md",
|
||||
}
|
||||
for _, file := range files {
|
||||
if slices.Contains(ignore, filepath.Base(file)) {
|
||||
continue
|
||||
}
|
||||
|
||||
contents, err := os.ReadFile(file)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
messages = append(messages, fmt.Sprintf("File %s:\n\n------------%s\n------------", file, string(contents)))
|
||||
}
|
||||
|
||||
return []serving.ChatMessage{
|
||||
{
|
||||
Role: serving.ChatMessageRoleSystem,
|
||||
Content: strings.Join(messages, "\n\n"),
|
||||
},
|
||||
}, nil
|
||||
}
|
|
@ -0,0 +1,60 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/databricks/cli/cmd"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
type Group struct {
|
||||
Name string
|
||||
Package string
|
||||
Command *cobra.Command
|
||||
Subcommands []*cobra.Command
|
||||
}
|
||||
|
||||
func Find(name string) *Group {
|
||||
root := cmd.New(context.Background())
|
||||
for _, c := range root.Commands() {
|
||||
if c.Use != name {
|
||||
continue
|
||||
}
|
||||
return &Group{
|
||||
Name: name,
|
||||
Package: c.Annotations["package"],
|
||||
Command: c,
|
||||
Subcommands: c.Commands(),
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (g *Group) Prompt() string {
|
||||
msg := fmt.Sprintf(`
|
||||
We're authoring documentation and examples for the "%s" command group.
|
||||
|
||||
All output must be valid Markdown.
|
||||
|
||||
Do not include expected command output; you don't know.
|
||||
|
||||
Every command has its own Markdown header.
|
||||
|
||||
The documentation should be written in Markdown, with code blocks for each command invocation.
|
||||
By concatenating the code blocks, you should be able to run the script and see the output.
|
||||
|
||||
Below is the help output of each one of the commands.
|
||||
`, Invocation(g.Command))
|
||||
|
||||
sep := "SEPARATOR BETWEEN INSTRUCTION AND HELP OUTPUT"
|
||||
all := append([]*cobra.Command{g.Command}, g.Subcommands...)
|
||||
for _, c := range all {
|
||||
inv := Invocation(c)
|
||||
msg += "\n\n" + sep + "\n\n$ " + inv + " --help\n\n" + CaptureHelp(c)
|
||||
}
|
||||
|
||||
msg += "\n\n" + sep + "\n\n"
|
||||
return msg
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
package main_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
main "github.com/databricks/cli/experimental/docs"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestGroupFind(t *testing.T) {
|
||||
g := main.Find("catalogs")
|
||||
require.NotNil(t, g)
|
||||
assert.Equal(t, "catalogs", g.Name)
|
||||
assert.Equal(t, "catalogs", g.Command.Use)
|
||||
assert.Len(t, g.Subcommands, 5)
|
||||
g.Command.CalledAs()
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"slices"
|
||||
"strings"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
func CaptureHelp(cmd *cobra.Command) string {
|
||||
var buf bytes.Buffer
|
||||
cmd.SetOut(&buf)
|
||||
if err := cmd.Help(); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return buf.String()
|
||||
}
|
||||
|
||||
func Invocation(cmd *cobra.Command) string {
|
||||
var args []string
|
||||
|
||||
for cmd != nil {
|
||||
args = append(args, cmd.Use)
|
||||
cmd = cmd.Parent()
|
||||
}
|
||||
|
||||
slices.Reverse(args)
|
||||
return strings.Join(args, " ")
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
package main_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/databricks/cli/cmd"
|
||||
main "github.com/databricks/cli/experimental/docs"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestCaptureHelp(t *testing.T) {
|
||||
c := cmd.New(context.Background())
|
||||
h := main.CaptureHelp(c)
|
||||
require.NotNil(t, h)
|
||||
}
|
||||
|
||||
func TestInvocation(t *testing.T) {
|
||||
g := main.Find("catalogs")
|
||||
require.NotNil(t, g)
|
||||
assert.Equal(t, "databricks catalogs", main.Invocation(g.Command))
|
||||
}
|
|
@ -0,0 +1,89 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/databricks/databricks-sdk-go"
|
||||
"github.com/databricks/databricks-sdk-go/service/serving"
|
||||
)
|
||||
|
||||
func main() {
|
||||
ctx := context.Background()
|
||||
w, err := databricks.NewWorkspaceClient()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
messages, err := PromptMessage()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
// Please author Markdown documentation that first
|
||||
// creates the necessary resources, demonstrates usage of the commands, and then
|
||||
// finally cleans up the resources. Make sure to demonstrate usage of necessary flags. Remember to not delete
|
||||
// the resource before demonstrating the other commands. If the final step is to delete the resource, then
|
||||
// you can delete the resource at the end of the script.
|
||||
|
||||
g := Find("jobs")
|
||||
contents := g.Prompt()
|
||||
|
||||
// contents += `
|
||||
|
||||
// The output should have the following structure:
|
||||
|
||||
// # <command group>
|
||||
|
||||
// <prose description of the command group>
|
||||
|
||||
// ## Quick start
|
||||
|
||||
// BEGIN
|
||||
|
||||
// <
|
||||
// Markdown documentation that first creates the necessary resources, demonstrates usage of the commands, and then
|
||||
// finally cleans up the resources. Make sure to demonstrate usage of necessary flags. Remember to not delete
|
||||
// the resource before demonstrating the other commands. If the final step is to delete the resource, then
|
||||
// you can delete the resource at the end of the script.
|
||||
// Each command is a separate code block with prose separating them.
|
||||
// Do not include command output; you don't know.
|
||||
// Never use placeholders in the commands, but use for example "my_catalog" for a "CATALOG_NAME" placeholder.
|
||||
// All code blocks concatenated should be runnable as a bash script.
|
||||
// If commands depend on pre-existing resources, do not include the commands to create or destroy them,
|
||||
// but call out this requirement in a comment.
|
||||
// >
|
||||
|
||||
// END
|
||||
// `
|
||||
|
||||
// `
|
||||
// ## Commands
|
||||
|
||||
// <Markdown headers for each command, with the command name as the header text>
|
||||
// `
|
||||
|
||||
contents += `
|
||||
Output an executable Bash script that demonstrates how to use these commands.
|
||||
Insert comments where you expect the user to have pre-existing resources.
|
||||
`
|
||||
|
||||
messages = append(messages, serving.ChatMessage{
|
||||
Role: serving.ChatMessageRoleUser,
|
||||
Content: contents,
|
||||
})
|
||||
|
||||
res, err := w.ServingEndpoints.Query(ctx, serving.QueryEndpointInput{
|
||||
Name: "databricks-dbrx-instruct",
|
||||
Messages: messages,
|
||||
})
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
// enc := json.NewEncoder(os.Stdout)
|
||||
// enc.SetIndent("", " ")
|
||||
// enc.Encode(res)
|
||||
|
||||
fmt.Printf("Output: %s\n", res.Choices[0].Message.Content)
|
||||
}
|
|
@ -0,0 +1,39 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/databricks/cli/cmd"
|
||||
"golang.org/x/exp/maps"
|
||||
)
|
||||
|
||||
type Package struct {
|
||||
Name string
|
||||
Groups []*Group
|
||||
}
|
||||
|
||||
func Packages() []Package {
|
||||
root := cmd.New(context.Background())
|
||||
packages := make(map[string]Package)
|
||||
for _, c := range root.Commands() {
|
||||
pkg := c.Annotations["package"]
|
||||
if pkg == "" {
|
||||
continue
|
||||
}
|
||||
|
||||
g := Find(c.Use)
|
||||
p, ok := packages[pkg]
|
||||
if !ok {
|
||||
p = Package{
|
||||
Name: pkg,
|
||||
Groups: []*Group{g},
|
||||
}
|
||||
} else {
|
||||
p.Groups = append(p.Groups, g)
|
||||
}
|
||||
|
||||
packages[pkg] = p
|
||||
}
|
||||
|
||||
return maps.Values(packages)
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
package main_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
main "github.com/databricks/cli/experimental/docs"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestPackagesAll(t *testing.T) {
|
||||
pkgs := main.Packages()
|
||||
require.NotEmpty(t, pkgs)
|
||||
}
|
Loading…
Reference in New Issue