Skip to content

Commit

Permalink
Add a cli tool to the Go version of foundation-sdk
Browse files Browse the repository at this point in the history
  • Loading branch information
K-Phoen committed Oct 11, 2024
1 parent 25dd953 commit dd49dca
Show file tree
Hide file tree
Showing 9 changed files with 267 additions and 1 deletion.
1 change: 0 additions & 1 deletion config/foundation_sdk.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,6 @@ output:

languages:
- go:
go_mod: true
package_root: '%go_package_root%'
builder_templates:
- '%__config_dir%/templates/go'
Expand Down
1 change: 1 addition & 0 deletions package_templates/go/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/vendor
86 changes: 86 additions & 0 deletions package_templates/go/cmd/cli/convert/commands.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
package convert

import (
"encoding/json"
"fmt"
"strings"

"github.com/grafana/grafana-foundation-sdk/go/cmd/cli/tools"
"github.com/grafana/grafana-foundation-sdk/go/cog"
"github.com/grafana/grafana-foundation-sdk/go/dashboard"
"github.com/urfave/cli/v2"
)

type converter func(input []byte, hint string) (string, error)

func Command() *cli.Command {
converters := map[string]converter{
tools.KindDashboard: convertDashboard,
tools.KindPanel: convertPanel,
tools.KindQuery: convertQuery,
}

return &cli.Command{
Name: "convert",
Usage: "Convert Grafana resources to Go",
Description: "Converts a Grafana resource JSON from INPUT (or standard input) to Go.",
ArgsUsage: "[INPUT]",
Flags: []cli.Flag{
&cli.StringFlag{
Name: "kind",
Aliases: []string{"k"},
Required: true,
},
&cli.StringFlag{
Name: "hint",
},
},
Action: func(cCtx *cli.Context) error {
kind := cCtx.String("kind")
converterFunc, found := converters[kind]
if !found {
return fmt.Errorf("unknown kind '%s'. Valid kinds are: %s", kind, strings.Join(tools.KnownKinds(), ", "))
}

input, err := tools.ReadFileOrStdin(cCtx.Args().First())
if err != nil {
return err
}

result, err := converterFunc(input, cCtx.String("hint"))
if err != nil {
return err
}

fmt.Println(result)
return nil
},
}
}

func convertDashboard(input []byte, _ string) (string, error) {
dash := dashboard.Dashboard{}
if err := json.Unmarshal(input, &dash); err != nil {
return "", err
}

return dashboard.DashboardConverter(dash), nil
}

func convertPanel(input []byte, _ string) (string, error) {
panel := dashboard.Panel{}
if err := json.Unmarshal(input, &panel); err != nil {
return "", err
}

return cog.ConvertPanelToCode(panel, panel.Type), nil
}

func convertQuery(input []byte, hint string) (string, error) {
query, err := cog.UnmarshalDataquery(input, hint)
if err != nil {
return "", err
}

return cog.ConvertDataqueryToCode(query), nil
}
28 changes: 28 additions & 0 deletions package_templates/go/cmd/cli/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package main

import (
"fmt"
"os"

"github.com/grafana/grafana-foundation-sdk/go/cmd/cli/convert"
"github.com/grafana/grafana-foundation-sdk/go/cmd/cli/validate"
"github.com/grafana/grafana-foundation-sdk/go/cog/plugins"
"github.com/urfave/cli/v2"
)

func main() {
plugins.RegisterDefaultPlugins()

app := &cli.App{
Name: "grafana-foundation-sdk",
Version: "{{ .Extra.ReleaseBranch }}",
Commands: cli.Commands{
convert.Command(),
validate.Command(),
},
}

if err := app.Run(os.Args); err != nil {
fmt.Fprintf(os.Stderr, "%s\n", err.Error())
}
}
20 changes: 20 additions & 0 deletions package_templates/go/cmd/cli/tools/input.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package tools

import (
"io"
"os"
)

func ReadFileOrStdin(inputFile string) ([]byte, error) {
if inputFile == "" {
return io.ReadAll(os.Stdin)
}

file, err := os.Open(inputFile)
if err != nil {
return nil, err
}
defer func() { _ = file.Close() }()

return io.ReadAll(file)
}
17 changes: 17 additions & 0 deletions package_templates/go/cmd/cli/tools/kinds.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package tools

type Kind = string

const (
KindDashboard = "dashboard"
KindPanel = "panel"
KindQuery = "query"
)

func KnownKinds() []Kind {
return []Kind{
KindDashboard,
KindPanel,
KindQuery,
}
}
96 changes: 96 additions & 0 deletions package_templates/go/cmd/cli/validate/commands.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
package validate

import (
"bytes"
"encoding/json"
"fmt"
"strings"

"github.com/grafana/grafana-foundation-sdk/go/cmd/cli/tools"
"github.com/grafana/grafana-foundation-sdk/go/cog"
"github.com/grafana/grafana-foundation-sdk/go/dashboard"
"github.com/urfave/cli/v2"
)

type unmarshaller func(decoder *json.Decoder, input []byte, hint string) (any, error)

var unmarshallers = map[string]unmarshaller{
tools.KindDashboard: unmarshalDashboard,
tools.KindPanel: unmarshalPanel,
tools.KindQuery: unmarshalQuery,
}

func Command() *cli.Command {
return &cli.Command{
Name: "validate",
Usage: "Validate a Grafana resource",
Description: "Validates a resource JSON from INPUT (or standard input).",
ArgsUsage: "[INPUT]",
Flags: []cli.Flag{
&cli.StringFlag{
Name: "kind",
Aliases: []string{"k"},
Required: true,
},
&cli.StringFlag{
Name: "hint",
},
&cli.BoolFlag{
Name: "strict",
Aliases: []string{"s"},
},
},
Action: func(cCtx *cli.Context) error {
input, err := tools.ReadFileOrStdin(cCtx.Args().First())
if err != nil {
return err
}

decoder := json.NewDecoder(bytes.NewBuffer(input))

if cCtx.Bool("strict") {
decoder.DisallowUnknownFields()
}

_, err = unmarshalKind(decoder, input, cCtx.String("kind"), cCtx.String("hint"))

return err
},
}
}

func unmarshalKind(decoder *json.Decoder, input []byte, kind string, hint string) (any, error) {
unmarshallerFunc, found := unmarshallers[kind]
if !found {
return nil, fmt.Errorf("unknown kind '%s'. Valid kinds are: %s", kind, strings.Join(tools.KnownKinds(), ", "))
}

return unmarshallerFunc(decoder, input, hint)
}

func unmarshalDashboard(decoder *json.Decoder, input []byte, _ string) (any, error) {
dash := dashboard.Dashboard{}
if err := decoder.Decode(&dash); err != nil {
return dash, err
}

return dash, nil
}

func unmarshalPanel(decoder *json.Decoder, input []byte, _ string) (any, error) {
panel := dashboard.Panel{}
if err := decoder.Decode(&panel); err != nil {
return panel, err
}

return panel, nil
}

func unmarshalQuery(decoder *json.Decoder, input []byte, hint string) (any, error) {
query, err := cog.UnmarshalDataquery(input, hint)
if err != nil {
return nil, err
}

return query, nil
}
11 changes: 11 additions & 0 deletions package_templates/go/go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
module github.com/grafana/grafana-foundation-sdk/go

go 1.21

require github.com/urfave/cli/v2 v2.27.4

require (
github.com/cpuguy83/go-md2man/v2 v2.0.4 // indirect
github.com/russross/blackfriday/v2 v2.1.0 // indirect
github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1 // indirect
)
8 changes: 8 additions & 0 deletions package_templates/go/go.sum
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
github.com/cpuguy83/go-md2man/v2 v2.0.4 h1:wfIWP927BUkWJb2NmU/kNDYIBTh/ziUX91+lVfRxZq4=
github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/urfave/cli/v2 v2.27.4 h1:o1owoI+02Eb+K107p27wEX9Bb8eqIoZCfLXloLUSWJ8=
github.com/urfave/cli/v2 v2.27.4/go.mod h1:m4QzxcD2qpra4z7WhzEGn74WZLViBnMpb1ToCAKdGRQ=
github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1 h1:gEOO8jv9F4OT7lGCjxCBTO/36wtF6j2nSip77qHd4x4=
github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1/go.mod h1:Ohn+xnUBiLI6FVj/9LpzZWtj1/D6lUovWYBkxHVV3aM=

0 comments on commit dd49dca

Please sign in to comment.