Skip to content

Commit

Permalink
Generate markdown documentation for error definitions with error-defi…
Browse files Browse the repository at this point in the history
…nitions command
  • Loading branch information
Arnold Iakab committed Mar 24, 2023
1 parent 8eac512 commit 199388d
Show file tree
Hide file tree
Showing 4 changed files with 107 additions and 84 deletions.
63 changes: 41 additions & 22 deletions cmd/pb/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
package main

import (
"errors"
"github.com/spf13/cobra"

"github.com/pace/bricks/internal/service"
Expand Down Expand Up @@ -107,6 +108,31 @@ func addRootCommands(rootCmd *cobra.Command) {
addServiceGenerateCommands(rootCmdGenerate)
}

type errorDefinitionsOutputFlag string

const (
goOutputFlag errorDefinitionsOutputFlag = "go"
mdOutputFlag errorDefinitionsOutputFlag = "md"
)

func (e *errorDefinitionsOutputFlag) String() string {
return string(*e)
}

func (e *errorDefinitionsOutputFlag) Set(v string) error {
switch v {
case "go", "md":
*e = errorDefinitionsOutputFlag(v)
return nil
default:
return errors.New(`must be "go" or "md"`)
}
}

func (e *errorDefinitionsOutputFlag) Type() string {
return "errorDefinitionsOutputFlag"
}

// pace service generate ...
func addServiceGenerateCommands(rootCmdGenerate *cobra.Command) {
var pkgName, path, source string
Expand Down Expand Up @@ -166,36 +192,29 @@ func addServiceGenerateCommands(rootCmdGenerate *cobra.Command) {
rootCmdGenerate.AddCommand(cmdMakefile)

var errorsDefinitionsPkgName, errorsDefinitionsPath, errorsDefinitionsSource string

errorDefinitionsOutput := goOutputFlag
cmdErrorDefinitions := &cobra.Command{
Use: "error-definitions",
Short: "generate BricksErrors based on an array of JSON error objects",
Run: func(cmd *cobra.Command, args []string) {
generate.ErrorDefinitionFile(generate.ErrorDefinitionFileOptions{
PkgName: errorsDefinitionsPkgName,
Path: errorsDefinitionsPath,
Source: errorsDefinitionsSource,
})
switch errorDefinitionsOutput {
case goOutputFlag:
generate.ErrorDefinitionFile(generate.ErrorDefinitionFileOptions{
PkgName: errorsDefinitionsPkgName,
Path: errorsDefinitionsPath,
Source: errorsDefinitionsSource,
})
case mdOutputFlag:
generate.ErrorDefinitionsMarkdown(generate.ErrorDefinitionFileOptions{
Path: errorsDefinitionsPath,
Source: errorsDefinitionsSource,
})
}
},
}
cmdErrorDefinitions.Flags().StringVar(&errorsDefinitionsPkgName, "pkg", "", "name for the generated go package")
cmdErrorDefinitions.Flags().StringVar(&errorsDefinitionsPath, "path", "", "path for generated file")
cmdErrorDefinitions.Flags().StringVar(&errorsDefinitionsSource, "source", "", "JSONAPI conform error definitions source to use for generation")
cmdErrorDefinitions.Flags().VarP(&errorDefinitionsOutput, "output", "o", "go code or markdown documentation")
rootCmdGenerate.AddCommand(cmdErrorDefinitions)
addErrorDefinitionsCommands(cmdErrorDefinitions)
}

func addErrorDefinitionsCommands(rootCmdErrorDefinitions *cobra.Command) {
var inputPath, outputPath string

cmdMarkdown := &cobra.Command{
Use: "markdown",
Short: "generate error definitions markdown from yaml file",
Run: func(cmd *cobra.Command, args []string) {
generate.ErrorDefinitionsMarkdown(inputPath, outputPath)
},
}
cmdMarkdown.Flags().StringVarP(&inputPath, "input", "i", "", "path for the yaml file")
cmdMarkdown.Flags().StringVarP(&outputPath, "output", "o", "", "path for the generated markdown file")
rootCmdErrorDefinitions.AddCommand(cmdMarkdown)
}
33 changes: 12 additions & 21 deletions internal/service/generate/error.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import (
"os"

"github.com/pace/bricks/internal/service/generate/errordefinition/generator"
markdown "github.com/pace/bricks/internal/service/generate/errormarkdown/generator"
)

// ErrorDefinitionFileOptions options that change the rendering of the error definition file
Expand All @@ -26,37 +25,29 @@ func ErrorDefinitionFile(options ErrorDefinitionFileOptions) {
log.Fatal(err)
}

// create file
file, err := os.Create(options.Path)
if err != nil {
log.Fatal(err)
}
defer file.Close() // nolint: errcheck

// write file
_, err = file.WriteString(result)
if err != nil {
log.Fatal(err)
}
writeResult(result, options.Path)
}

func ErrorDefinitionsMarkdown(inputPath, outputPath string) {
input, err := os.Open(inputPath)
func ErrorDefinitionsMarkdown(options ErrorDefinitionFileOptions) {
g := generator.Generator{}
result, err := g.BuildMarkdown(options.Source)
if err != nil {
log.Fatal(err)
}
defer input.Close() // nolint: errcheck

g := markdown.Generator{}
res, err := g.Generate(input)
writeResult(result, options.Path)
}

output, err := os.Create(outputPath)
func writeResult(result, path string) {
// create file
file, err := os.Create(path)
if err != nil {
log.Fatal(err)
}
defer output.Close() // nolint: errcheck
defer file.Close() // nolint: errcheck

_, err = output.WriteString(res)
// write file
_, err = file.WriteString(result)
if err != nil {
log.Fatal(err)
}
Expand Down
49 changes: 28 additions & 21 deletions internal/service/generate/errordefinition/generator/generate.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,30 @@ type Generator struct {
serviceName string
}

func loadDefinitionData(source string) ([]byte, error) {
var data []byte
if strings.HasPrefix(source, "http://") || strings.HasPrefix(source, "https://") {
loc, err := url.Parse(source)
if err != nil {
return nil, err
}

data, err = loadDefinitionDataFromURI(loc)
if err != nil {
return nil, err
}
} else {
// read definition file from disk
var err error
data, err = os.ReadFile(source) // nolint: gosec
if err != nil {
return nil, err
}
}

return data, nil
}

func loadDefinitionDataFromURI(url *url.URL) ([]byte, error) {
resp, err := http.Get(url.String())
if err != nil {
Expand All @@ -42,31 +66,14 @@ func loadDefinitionDataFromURI(url *url.URL) ([]byte, error) {
// BuildSource generates the go code in the specified path with specified package name
// based on the passed schema source (url or file path)
func (g *Generator) BuildSource(source, packagePath, packageName string) (string, error) {

var data []byte
if strings.HasPrefix(source, "http://") || strings.HasPrefix(source, "https://") {
loc, err := url.Parse(source)
if err != nil {
return "", err
}

data, err = loadDefinitionDataFromURI(loc)
if err != nil {
return "", err
}
} else {
// read definition file from disk
var err error
data, err = os.ReadFile(source) // nolint: gosec
if err != nil {
return "", err
}

data, err := loadDefinitionData(source)
if err != nil {
return "", err
}

// parse definition
var errors runtime.Errors
err := json.Unmarshal(data, &errors)
err = json.Unmarshal(data, &errors)
if err != nil {
return "", err
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
package generator

import (
"encoding/json"
"fmt"
"gopkg.in/yaml.v3"
"io"
"strings"
)

Expand All @@ -21,34 +20,41 @@ type GroupedErrorDetails struct {
Title string
}

type Generator struct{}
func (g *Generator) BuildMarkdown(source string) (string, error) {
data, err := loadDefinitionData(source)
if err != nil {
return "", err
}

// parse definitions
eds, err := g.parseDefinitions(data)
if err != nil {
return "", err
}

func (g *Generator) Generate(in io.Reader) (string, error) {
eds := g.parseInput(in)
return g.generateMarkdown(eds)
}

func (g *Generator) parseInput(r io.Reader) ErrorDefinitions {
dec := yaml.NewDecoder(r)
func (g *Generator) parseDefinitions(data []byte) (ErrorDefinitions, error) {
var parsedData []ErrorDefinition
err := json.Unmarshal(data, &parsedData)
if err != nil {
return nil, err
}

eds := make(ErrorDefinitions)
for {
var ed ErrorDefinition
if dec.Decode(&ed) != nil {
break
}

if _, ok := eds[ed.Service]; ok {
eds[ed.Service][ed.Status] = append(eds[ed.Service][ed.Status], GroupedErrorDetails{
Code: ed.Code,
Title: ed.Title,
})
} else {
for _, ed := range parsedData {
if _, ok := eds[ed.Service]; !ok {
eds[ed.Service] = make(map[string][]GroupedErrorDetails)
}

eds[ed.Service][ed.Status] = append(eds[ed.Service][ed.Status], GroupedErrorDetails{
Code: ed.Code,
Title: ed.Title,
})
}

return eds
return eds, nil
}

func (g *Generator) generateMarkdown(eds ErrorDefinitions) (string, error) {
Expand Down

0 comments on commit 199388d

Please sign in to comment.