Skip to content
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

Add support for Markdown #16

Merged
merged 2 commits into from
Nov 22, 2021
Merged
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
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
out.asciidoc
out.md
.idea
27 changes: 22 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,17 +18,34 @@ Pre-built Linux binaries can be downloaded from the Github Releases tab. Alterna
go get -u github.com/elastic/crd-ref-docs
```

The tool can be invoked as follows to generate documentation in Asciidoc format:
The tool can be invoked as follows to generate documentation:

```
crd-ref-docs \
--source-path=$GOPATH/src/github.com/elastic/cloud-on-k8s/pkg/apis \
--config=config.yaml
```

By default, documentation is rendered in Asciidoc format.
In order to generate documentation in Markdown format, you will have to specify the `markdown` renderer:

```
crd-ref-docs \
--source-path=$GOPATH/src/github.com/elastic/cloud-on-k8s/pkg/apis \
--config=config.yaml \
--renderer=asciidoctor \
--templates-dir=templates/asciidoctor \
--output-path=out.asciidoc
--renderer=markdown
```

Default templates are embedded in the binary.
You may provide your own templates by specifying the templates directory:

```
crd-ref-docs \
--source-path=$GOPATH/src/github.com/elastic/cloud-on-k8s/pkg/apis \
--config=config.yaml \
--renderer=asciidoctor \
--templates-dir=templates/asciidoctor
```

### Configuration

Expand All @@ -50,5 +67,5 @@ processor:

render:
# Version of Kubernetes to use when generating links to Kubernetes API documentation.
kubernetesVersion: 1.15
kubernetesVersion: 1.22
```
2 changes: 1 addition & 1 deletion config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,4 @@ processor:
- "TypeMeta$"

render:
kubernetesVersion: 1.15
kubernetesVersion: 1.22
4 changes: 2 additions & 2 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,8 @@ func main() {
cmd.Flags().StringVar(&args.Config, "config", "config.yaml", "Path to config file")
cmd.Flags().StringVar(&args.SourcePath, "source-path", "", "Path to source directory containing CRDs")
cmd.Flags().StringVar(&args.TemplatesDir, "templates-dir", "", "Path to the directory containing template files")
cmd.Flags().StringVar(&args.Renderer, "renderer", "asciidoctor", "Renderer to use")
cmd.Flags().StringVar(&args.OutputPath, "output-path", "out.asciidoc", "Path to output the rendered result")
cmd.Flags().StringVar(&args.Renderer, "renderer", "asciidoctor", "Renderer to use ('asciidoctor' or 'markdown')")
cmd.Flags().StringVar(&args.OutputPath, "output-path", ".", "Path to output the rendered result")
cmd.Flags().IntVar(&args.MaxDepth, "max-depth", 6, "Maximum recursion level for type discovery")

cmd.Execute()
Expand Down
16 changes: 1 addition & 15 deletions renderer/asciidoctor.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ import (
"fmt"
"io/fs"
"os"
"path/filepath"
"strings"
"text/template"

Expand Down Expand Up @@ -66,20 +65,7 @@ func (adr *AsciidoctorRenderer) Render(gvd []types.GroupVersionDetails) error {
return err
}

outputFile := adr.conf.OutputPath
finfo, err := os.Stat(outputFile)
if err != nil && !os.IsNotExist(err) {
return err
}

if finfo != nil && finfo.IsDir() {
outputFile = filepath.Join(outputFile, "out.asciidoc")
}

f, err := os.Create(outputFile)
if err != nil {
return err
}
f, err := createOutFile(adr.conf.OutputPath, "out.asciidoc")
defer f.Close()

return tmpl.ExecuteTemplate(f, mainTemplate, gvd)
Expand Down
142 changes: 142 additions & 0 deletions renderer/markdown.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
// Licensed to Elasticsearch B.V. under one or more contributor
// license agreements. See the NOTICE file distributed with
// this work for additional information regarding copyright
// ownership. Elasticsearch B.V. licenses this file to you under
// the Apache License, Version 2.0 (the "License"); you may
// not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
package renderer

import (
"fmt"
"io/fs"
"os"
"strings"
"text/template"

"github.com/Masterminds/sprig"
"github.com/elastic/crd-ref-docs/config"
"github.com/elastic/crd-ref-docs/templates"
"github.com/elastic/crd-ref-docs/types"
)

type MarkdownRenderer struct {
conf *config.Config
*Functions
}

func NewMarkdownRenderer(conf *config.Config) (*MarkdownRenderer, error) {
baseFuncs, err := NewFunctions(conf)
if err != nil {
return nil, err
}
return &MarkdownRenderer{conf: conf, Functions: baseFuncs}, nil
}

func (m *MarkdownRenderer) Render(gvd []types.GroupVersionDetails) error {
funcMap := combinedFuncMap(funcMap{prefix: "markdown", funcs: m.ToFuncMap()}, funcMap{funcs: sprig.TxtFuncMap()})

var tpls fs.FS
if m.conf.TemplatesDir != "" {
tpls = os.DirFS(m.conf.TemplatesDir)
} else {
sub, err := fs.Sub(templates.Root, "markdown")
if err != nil {
return err
}
tpls = sub
}

tmpl, err := loadTemplate(tpls, funcMap)
if err != nil {
return err
}

f, err := createOutFile(m.conf.OutputPath, "out.md")
defer f.Close()

return tmpl.ExecuteTemplate(f, mainTemplate, gvd)
}

func (m *MarkdownRenderer) ToFuncMap() template.FuncMap {
return template.FuncMap{
"GroupVersionID": m.GroupVersionID,
"RenderExternalLink": m.RenderExternalLink,
"RenderGVLink": m.RenderGVLink,
"RenderLocalLink": m.RenderLocalLink,
"RenderType": m.RenderType,
"RenderTypeLink": m.RenderTypeLink,
"SafeID": m.SafeID,
"ShouldRenderType": m.ShouldRenderType,
"TypeID": m.TypeID,
}
}

func (m *MarkdownRenderer) ShouldRenderType(t *types.Type) bool {
return t != nil && (t.GVK != nil || len(t.References) > 0)
}

func (m *MarkdownRenderer) RenderType(t *types.Type) string {
var sb strings.Builder
switch t.Kind {
case types.MapKind:
sb.WriteString("object (")
sb.WriteString("keys:")
sb.WriteString(m.RenderTypeLink(t.KeyType))
sb.WriteString(", values:")
sb.WriteString(m.RenderTypeLink(t.ValueType))
sb.WriteString(")")
case types.ArrayKind, types.SliceKind:
sb.WriteString(m.RenderTypeLink(t.UnderlyingType))
sb.WriteString(" array")
default:
sb.WriteString(m.RenderTypeLink(t))
}

return sb.String()
}

func (m *MarkdownRenderer) RenderTypeLink(t *types.Type) string {
text := m.SimplifiedTypeName(t)

link, local := m.LinkForType(t)
if link == "" {
return text
}

if local {
return m.RenderLocalLink(text)
} else {
return m.RenderExternalLink(link, text)
}
}

func (m *MarkdownRenderer) RenderLocalLink(text string) string {
anchor := strings.ToLower(
strings.NewReplacer(
" ", "-",
".", "",
"/", "",
"(", "",
")", "",
).Replace(text),
)
return fmt.Sprintf("[%s](#%s)", text, anchor)
thbkrkr marked this conversation as resolved.
Show resolved Hide resolved
}

func (m *MarkdownRenderer) RenderExternalLink(link, text string) string {
return fmt.Sprintf("[%s](%s)", text, link)
}

func (m *MarkdownRenderer) RenderGVLink(gv types.GroupVersionDetails) string {
return m.RenderLocalLink(gv.GroupVersionString())
}
17 changes: 17 additions & 0 deletions renderer/renderer.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ package renderer
import (
"fmt"
"io/fs"
"os"
"path/filepath"
"text/template"

"github.com/elastic/crd-ref-docs/config"
Expand All @@ -35,6 +37,8 @@ func New(conf *config.Config) (Renderer, error) {
switch conf.Renderer {
case "asciidoctor":
return NewAsciidoctorRenderer(conf)
case "markdown":
return NewMarkdownRenderer(conf)
default:
return nil, fmt.Errorf("unknown renderer: %s", conf.Renderer)
}
Expand All @@ -59,3 +63,16 @@ func combinedFuncMap(funcs ...funcMap) template.FuncMap {

return m
}

func createOutFile(outputPath string, defaultFileName string) (*os.File, error) {
finfo, err := os.Stat(outputPath)
if err != nil && !os.IsNotExist(err) {
return nil, err
}

if finfo != nil && finfo.IsDir() {
outputPath = filepath.Join(outputPath, defaultFileName)
}

return os.Create(outputPath)
}
19 changes: 19 additions & 0 deletions templates/markdown/gv_details.tpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
{{- define "gvDetails" -}}
{{- $gv := . -}}

## {{ $gv.GroupVersionString }}

{{ $gv.Doc }}

{{- if $gv.Kinds }}
### Resource Types
{{- range $gv.SortedKinds }}
- {{ $gv.TypeForKind . | markdownRenderTypeLink }}
{{- end }}
{{ end }}

{{ range $gv.SortedTypes }}
{{ template "type" . }}
{{ end }}

{{- end -}}
15 changes: 15 additions & 0 deletions templates/markdown/gv_list.tpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{{- define "gvList" -}}
{{- $groupVersions := . -}}

# API Reference

## Packages
{{- range $groupVersions }}
- {{ markdownRenderGVLink . }}
{{- end }}

{{ range $groupVersions }}
{{ template "gvDetails" . }}
{{ end }}

{{- end -}}
33 changes: 33 additions & 0 deletions templates/markdown/type.tpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
{{- define "type" -}}
{{- $type := . -}}
{{- if markdownShouldRenderType $type -}}

#### {{ $type.Name }}

{{ if $type.IsAlias }}_Underlying type:_ `{{ markdownRenderTypeLink $type.UnderlyingType }}`{{ end }}

{{ $type.Doc }}

{{ if $type.References -}}
_Appears in:_
{{- range $type.SortedReferences }}
- {{ markdownRenderTypeLink . }}
{{- end }}
{{- end }}

{{ if $type.Members -}}
| Field | Description |
| --- | --- |
{{ if $type.GVK -}}
| `apiVersion` _string_ | `{{ $type.GVK.Group }}/{{ $type.GVK.Version }}`
| `kind` _string_ | `{{ $type.GVK.Kind }}`
{{ end -}}

{{ range $type.Members -}}
| `{{ .Name }}` _{{ markdownRenderType .Type }}_ | {{ template "type_members" . }} |
{{ end -}}

{{ end -}}

{{- end -}}
{{- end -}}
8 changes: 8 additions & 0 deletions templates/markdown/type_members.tpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{{- define "type_members" -}}
{{- $field := . -}}
{{- if eq $field.Name "metadata" -}}
Refer to Kubernetes API documentation for fields of `metadata`.
{{- else -}}
{{ $field.Doc }}
{{- end -}}
{{- end -}}
1 change: 1 addition & 0 deletions templates/templates.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,5 @@ package templates
import "embed"

//go:embed asciidoctor
//go:embed markdown
var Root embed.FS
Loading