From 1afaaf047d2e8a10a6b1d42f750c630e7dbe675c Mon Sep 17 00:00:00 2001 From: Jianbo Sun Date: Thu, 24 Nov 2022 10:56:01 +0800 Subject: [PATCH] Chore: add definition example doc CI check Signed-off-by: Jianbo Sun --- .github/workflows/definition-lint.yml | 44 +++++++++++++++++++++++++++ hack/docgen/def/gen.go | 25 ++++++++++----- hack/docgen/def/mods/component.go | 27 ++++++++-------- hack/docgen/def/mods/policy.go | 27 ++++++++-------- hack/docgen/def/mods/trait.go | 26 ++++++++-------- hack/docgen/def/mods/types.go | 25 +++++++++++++++ hack/docgen/def/mods/workflow.go | 27 ++++++++-------- references/docgen/markdown.go | 4 +++ 8 files changed, 145 insertions(+), 60 deletions(-) create mode 100644 .github/workflows/definition-lint.yml create mode 100644 hack/docgen/def/mods/types.go diff --git a/.github/workflows/definition-lint.yml b/.github/workflows/definition-lint.yml new file mode 100644 index 000000000..6ba3bd31b --- /dev/null +++ b/.github/workflows/definition-lint.yml @@ -0,0 +1,44 @@ +name: Definition-Lint + +on: + push: + branches: + - master + - release-* + workflow_dispatch: {} + pull_request: + branches: + - master + - release-* + +env: + # Common versions + GO_VERSION: '1.19' + +jobs: + definition-doc: + runs-on: ubuntu-latest + steps: + - name: Setup Go + uses: actions/setup-go@v3 + with: + go-version: ${{ env.GO_VERSION }} + + - name: Checkout + uses: actions/checkout@v3 + with: + submodules: true + + - name: Setup K3d + uses: nolar/setup-k3d-k3s@v1.0.9 + with: + version: v1.20 + github-token: ${{ secrets.GITHUB_TOKEN }} + + - name: Definition Doc generate check + run: | + go build -o docgen hack/docgen/def/gen.go + ./docgen --type=comp --force-example-doc --path=./comp-def-check.md + ./docgen --type=trait --force-example-doc --path=./trait-def-check.md + ./docgen --type=wf --force-example-doc --path=./wf-def-check.md + ./docgen --type=policy --force-example-doc --path=./policy-def-check.md \ No newline at end of file diff --git a/hack/docgen/def/gen.go b/hack/docgen/def/gen.go index 2105aa791..59b128d46 100644 --- a/hack/docgen/def/gen.go +++ b/hack/docgen/def/gen.go @@ -42,6 +42,7 @@ func main() { defdir := flag.String("def-dir", "", "path of definition dir") tp := flag.String("type", "", "choose one of the definition to print") i18nfile := flag.String("i18n", "../kubevela.io/static/reference-i18n.json", "file path of i18n data") + forceExample := flag.Bool("force-example-doc", false, "example must be provided for definitions") flag.Parse() if *i18nfile != "" { @@ -52,21 +53,29 @@ func main() { fmt.Println("you must specify a type with definition ref path specified ") os.Exit(1) } + + opt := mods.Options{ + Path: *path, + Location: *location, + DefDir: *defdir, + ForceExamples: *forceExample, + } + fmt.Printf("creating docs with args path=%s, location=%s, defdir=%s, type=%s.\n", *path, *location, *defdir, *tp) switch types.CapType(*tp) { case types.TypeComponentDefinition, "component", "comp": - mods.ComponentDef(ctx, c, path, location, *defdir) + mods.ComponentDef(ctx, c, opt) case types.TypeTrait: - mods.TraitDef(ctx, c, path, location, *defdir) + mods.TraitDef(ctx, c, opt) case types.TypePolicy: - mods.PolicyDef(ctx, c, path, location, *defdir) + mods.PolicyDef(ctx, c, opt) case types.TypeWorkflowStep, "workflow", "wf": - mods.WorkflowDef(ctx, c, path, location, *defdir) + mods.WorkflowDef(ctx, c, opt) case "": - mods.ComponentDef(ctx, c, path, location, *defdir) - mods.TraitDef(ctx, c, path, location, *defdir) - mods.PolicyDef(ctx, c, path, location, *defdir) - mods.WorkflowDef(ctx, c, path, location, *defdir) + mods.ComponentDef(ctx, c, opt) + mods.TraitDef(ctx, c, opt) + mods.PolicyDef(ctx, c, opt) + mods.WorkflowDef(ctx, c, opt) default: fmt.Printf("type %s not supported\n", *tp) os.Exit(1) diff --git a/hack/docgen/def/mods/component.go b/hack/docgen/def/mods/component.go index fb29879af..82115fc8b 100644 --- a/hack/docgen/def/mods/component.go +++ b/hack/docgen/def/mods/component.go @@ -19,7 +19,6 @@ package mods import ( "context" "fmt" - "io/ioutil" "os" "strings" "time" @@ -60,12 +59,13 @@ title: 内置组件列表 ` + fmt.Sprintf("> 本文档由[脚本](../../contributor/cli-ref-doc)自动生成,请勿手动修改,上次更新于 %s。\n\n", time.Now().Format(time.RFC3339)) // ComponentDef generate component def reference doc -func ComponentDef(ctx context.Context, c common.Args, path, location *string, defdir string) { - if defdir == "" { - defdir = ComponentDefDir +func ComponentDef(ctx context.Context, c common.Args, opt Options) { + if opt.DefDir == "" { + opt.DefDir = ComponentDefDir } ref := &docgen.MarkdownReference{ - AllInOne: true, + AllInOne: true, + ForceExample: opt.ForceExamples, Filter: func(capability types.Capability) bool { if capability.Type != types.TypeComponentDefinition || capability.Category != types.CUECategory { return false @@ -74,9 +74,9 @@ func ComponentDef(ctx context.Context, c common.Args, path, location *string, de return false } // only print capability which contained in cue def - files, err := ioutil.ReadDir(defdir) + files, err := os.ReadDir(opt.DefDir) if err != nil { - fmt.Println("read dir err", defdir, err) + fmt.Println("read dir err", opt.DefDir, err) return false } for _, f := range files { @@ -96,19 +96,20 @@ func ComponentDef(ctx context.Context, c common.Args, path, location *string, de return } ref.DiscoveryMapper = dm - if *path != "" { + if opt.Path != "" { ref.I18N = &docgen.En - if strings.Contains(*location, "zh") || strings.Contains(*location, "chinese") { + if strings.Contains(opt.Location, "zh") || strings.Contains(opt.Location, "chinese") { ref.I18N = &docgen.Zh ref.CustomDocHeader = CustomComponentHeaderZH } - if err := ref.GenerateReferenceDocs(ctx, c, *path); err != nil { + if err := ref.GenerateReferenceDocs(ctx, c, opt.Path); err != nil { fmt.Println(err) os.Exit(1) } - fmt.Printf("component reference docs (%s) successfully generated in %s \n", ref.I18N.Language(), *path) + fmt.Printf("component reference docs (%s) successfully generated in %s \n", ref.I18N.Language(), opt.Path) + return } - if *location == "" || *location == "en" { + if opt.Location == "" || opt.Location == "en" { ref.I18N = &docgen.En if err := ref.GenerateReferenceDocs(ctx, c, ComponentDefRefPath); err != nil { fmt.Println(err) @@ -116,7 +117,7 @@ func ComponentDef(ctx context.Context, c common.Args, path, location *string, de } fmt.Printf("component reference docs (%s) successfully generated in %s \n", ref.I18N.Language(), ComponentDefRefPath) } - if *location == "" || *location == "zh" { + if opt.Location == "" || opt.Location == "zh" { ref.I18N = &docgen.Zh ref.CustomDocHeader = CustomComponentHeaderZH if err := ref.GenerateReferenceDocs(ctx, c, ComponentDefRefPathZh); err != nil { diff --git a/hack/docgen/def/mods/policy.go b/hack/docgen/def/mods/policy.go index 8f0182458..d1e698579 100644 --- a/hack/docgen/def/mods/policy.go +++ b/hack/docgen/def/mods/policy.go @@ -19,7 +19,6 @@ package mods import ( "context" "fmt" - "io/ioutil" "os" "strings" "time" @@ -58,12 +57,13 @@ title: 内置策略列表 ` + fmt.Sprintf("> 本文档由[脚本](../../contributor/cli-ref-doc)自动生成,请勿手动修改,上次更新于 %s。\n\n", time.Now().Format(time.RFC3339)) // PolicyDef generate policy def reference doc -func PolicyDef(ctx context.Context, c common.Args, path, location *string, defdir string) { - if defdir == "" { - defdir = PolicyDefDir +func PolicyDef(ctx context.Context, c common.Args, opt Options) { + if opt.DefDir == "" { + opt.DefDir = PolicyDefDir } ref := &docgen.MarkdownReference{ - AllInOne: true, + AllInOne: true, + ForceExample: opt.ForceExamples, Filter: func(capability types.Capability) bool { if capability.Type != types.TypePolicy || capability.Category != types.CUECategory { return false @@ -72,9 +72,9 @@ func PolicyDef(ctx context.Context, c common.Args, path, location *string, defdi return false } // only print capability which contained in cue def - files, err := ioutil.ReadDir(defdir) + files, err := os.ReadDir(opt.DefDir) if err != nil { - fmt.Println("read dir err", defdir, err) + fmt.Println("read dir err", opt.DefDir, err) return false } for _, f := range files { @@ -87,19 +87,20 @@ func PolicyDef(ctx context.Context, c common.Args, path, location *string, defdi CustomDocHeader: CustomPolicyHeaderEN, } ref.Remote = &docgen.FromCluster{Namespace: types.DefaultKubeVelaNS} - if *path != "" { + if opt.Path != "" { ref.I18N = &docgen.En - if strings.Contains(*location, "zh") || strings.Contains(*location, "chinese") { + if strings.Contains(opt.Location, "zh") || strings.Contains(opt.Location, "chinese") { ref.I18N = &docgen.Zh ref.CustomDocHeader = CustomPolicyHeaderZH } - if err := ref.GenerateReferenceDocs(ctx, c, *path); err != nil { + if err := ref.GenerateReferenceDocs(ctx, c, opt.Path); err != nil { fmt.Println(err) os.Exit(1) } - fmt.Printf("policy reference docs (%s) successfully generated in %s \n", ref.I18N.Language(), *path) + fmt.Printf("policy reference docs (%s) successfully generated in %s \n", ref.I18N.Language(), opt.Path) + return } - if *location == "" || *location == "en" { + if opt.Location == "" || opt.Location == "en" { ref.I18N = &docgen.En if err := ref.GenerateReferenceDocs(ctx, c, PolicyDefRefPath); err != nil { fmt.Println(err) @@ -107,7 +108,7 @@ func PolicyDef(ctx context.Context, c common.Args, path, location *string, defdi } fmt.Printf("policy reference docs (%s) successfully generated in %s \n", ref.I18N.Language(), PolicyDefRefPath) } - if *location == "" || *location == "zh" { + if opt.Location == "" || opt.Location == "zh" { ref.I18N = &docgen.Zh ref.CustomDocHeader = CustomPolicyHeaderZH if err := ref.GenerateReferenceDocs(ctx, c, PolicyDefRefPathZh); err != nil { diff --git a/hack/docgen/def/mods/trait.go b/hack/docgen/def/mods/trait.go index 90ccc4143..92acc8eb8 100644 --- a/hack/docgen/def/mods/trait.go +++ b/hack/docgen/def/mods/trait.go @@ -19,7 +19,6 @@ package mods import ( "context" "fmt" - "io/ioutil" "os" "strings" "time" @@ -58,12 +57,13 @@ title: 内置运维特征列表 ` + fmt.Sprintf("> 本文档由[脚本](../../contributor/cli-ref-doc)自动生成,请勿手动修改,上次更新于 %s。\n\n", time.Now().Format(time.RFC3339)) // TraitDef generate trait def reference doc -func TraitDef(ctx context.Context, c common.Args, path, location *string, defdir string) { - if defdir == "" { - defdir = TraitDefDir +func TraitDef(ctx context.Context, c common.Args, opt Options) { + if opt.DefDir == "" { + opt.DefDir = TraitDefDir } ref := &docgen.MarkdownReference{ - AllInOne: true, + AllInOne: true, + ForceExample: opt.ForceExamples, Filter: func(capability types.Capability) bool { if capability.Type != types.TypeTrait || capability.Category != types.CUECategory { return false @@ -72,9 +72,9 @@ func TraitDef(ctx context.Context, c common.Args, path, location *string, defdir return false } // only print capability which contained in cue def - files, err := ioutil.ReadDir(defdir) + files, err := os.ReadDir(opt.DefDir) if err != nil { - fmt.Println("read dir err", defdir, err) + fmt.Println("read dir err", opt.DefDir, err) return false } for _, f := range files { @@ -90,20 +90,20 @@ func TraitDef(ctx context.Context, c common.Args, path, location *string, defdir Path: TraitDefDir, } - if *path != "" { + if opt.Path != "" { ref.I18N = &docgen.En - if strings.Contains(*location, "zh") || strings.Contains(*location, "chinese") { + if strings.Contains(opt.Location, "zh") || strings.Contains(opt.Location, "chinese") { ref.I18N = &docgen.Zh ref.CustomDocHeader = CustomTraitHeaderZH } - if err := ref.GenerateReferenceDocs(ctx, c, *path); err != nil { + if err := ref.GenerateReferenceDocs(ctx, c, opt.Path); err != nil { fmt.Println(err) os.Exit(1) } - fmt.Printf("trait reference docs (%s) successfully generated in %s \n", ref.I18N.Language(), *path) + fmt.Printf("trait reference docs (%s) successfully generated in %s \n", ref.I18N.Language(), opt.Path) } else { // Generate to default path depends on language - if *location == "" || *location == "en" { + if opt.Location == "" || opt.Location == "en" { ref.I18N = &docgen.En if err := ref.GenerateReferenceDocs(ctx, c, TraitDefRefPath); err != nil { fmt.Println(err) @@ -111,7 +111,7 @@ func TraitDef(ctx context.Context, c common.Args, path, location *string, defdir } fmt.Printf("trait reference docs (%s) successfully generated in %s \n", ref.I18N.Language(), TraitDefRefPath) } - if *location == "" || *location == "zh" { + if opt.Location == "" || opt.Location == "zh" { ref.I18N = &docgen.Zh ref.CustomDocHeader = CustomTraitHeaderZH if err := ref.GenerateReferenceDocs(ctx, c, TraitDefRefPathZh); err != nil { diff --git a/hack/docgen/def/mods/types.go b/hack/docgen/def/mods/types.go new file mode 100644 index 000000000..fccc35255 --- /dev/null +++ b/hack/docgen/def/mods/types.go @@ -0,0 +1,25 @@ +/* + Copyright 2022 The KubeVela Authors. + + Licensed 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 mods + +// Options defines the doc generate options +type Options struct { + Path string + Location string + DefDir string + ForceExamples bool +} diff --git a/hack/docgen/def/mods/workflow.go b/hack/docgen/def/mods/workflow.go index 14a994ec7..8e7293ef7 100644 --- a/hack/docgen/def/mods/workflow.go +++ b/hack/docgen/def/mods/workflow.go @@ -19,7 +19,6 @@ package mods import ( "context" "fmt" - "io/ioutil" "os" "strings" "time" @@ -58,12 +57,13 @@ title: 内置工作流步骤列表 ` + fmt.Sprintf("> 本文档由[脚本](../../contributor/cli-ref-doc)自动生成,请勿手动修改,上次更新于 %s。\n\n", time.Now().Format(time.RFC3339)) // WorkflowDef generate workflow def reference doc -func WorkflowDef(ctx context.Context, c common.Args, path, location *string, defdir string) { - if defdir == "" { - defdir = WorkflowDefDir +func WorkflowDef(ctx context.Context, c common.Args, opt Options) { + if opt.DefDir == "" { + opt.DefDir = WorkflowDefDir } ref := &docgen.MarkdownReference{ - AllInOne: true, + AllInOne: true, + ForceExample: opt.ForceExamples, Filter: func(capability types.Capability) bool { if capability.Type != types.TypeWorkflowStep || capability.Category != types.CUECategory { @@ -74,9 +74,9 @@ func WorkflowDef(ctx context.Context, c common.Args, path, location *string, def return false } // only print capability which contained in cue def - files, err := ioutil.ReadDir(defdir) + files, err := os.ReadDir(opt.DefDir) if err != nil { - fmt.Println("read dir err", defdir, err) + fmt.Println("read dir err", opt.DefDir, err) return false } for _, f := range files { @@ -90,19 +90,20 @@ func WorkflowDef(ctx context.Context, c common.Args, path, location *string, def } ref.Remote = &docgen.FromCluster{Namespace: types.DefaultKubeVelaNS} - if *path != "" { + if opt.Path != "" { ref.I18N = &docgen.En - if strings.Contains(*location, "zh") || strings.Contains(*location, "chinese") { + if strings.Contains(opt.Location, "zh") || strings.Contains(opt.Location, "chinese") { ref.I18N = &docgen.Zh ref.CustomDocHeader = CustomWorkflowHeaderZH } - if err := ref.GenerateReferenceDocs(ctx, c, *path); err != nil { + if err := ref.GenerateReferenceDocs(ctx, c, opt.Path); err != nil { fmt.Println(err) os.Exit(1) } - fmt.Printf("workflow reference docs (%s) successfully generated in %s \n", ref.I18N.Language(), *path) + fmt.Printf("workflow reference docs (%s) successfully generated in %s \n", ref.I18N.Language(), opt.Path) + return } - if *location == "" || *location == "en" { + if opt.Location == "" || opt.Location == "en" { ref.I18N = &docgen.En if err := ref.GenerateReferenceDocs(ctx, c, WorkflowDefRefPath); err != nil { fmt.Println(err) @@ -110,7 +111,7 @@ func WorkflowDef(ctx context.Context, c common.Args, path, location *string, def } fmt.Printf("workflow reference docs (%s) successfully generated in %s \n", ref.I18N.Language(), WorkflowDefRefPath) } - if *location == "" || *location == "zh" { + if opt.Location == "" || opt.Location == "zh" { ref.I18N = &docgen.Zh ref.CustomDocHeader = CustomWorkflowHeaderZH if err := ref.GenerateReferenceDocs(ctx, c, WorkflowDefRefPathZh); err != nil { diff --git a/references/docgen/markdown.go b/references/docgen/markdown.go index a3c0f7f03..c7c0cc983 100644 --- a/references/docgen/markdown.go +++ b/references/docgen/markdown.go @@ -47,6 +47,7 @@ const AllComponentTypes = "*" type MarkdownReference struct { Filter func(types.Capability) bool AllInOne bool + ForceExample bool CustomDocHeader string DiscoveryMapper discoverymapper.DiscoveryMapper ParseReference @@ -255,6 +256,9 @@ func (ref *MarkdownReference) GenerateMarkdownForCap(ctx context.Context, c type if sampleContent != "" { sample = fmt.Sprintf("\n\n%s %s\n\n%s", sharp, exampleTitle, sampleContent) + } else if ref.ForceExample { + fmt.Printf("You must provide example doc for the new added definition %s, place the example doc in the /refereces/docgen/def-doc folders, for more details refer to https://kubevela.io/docs/contributor/cli-ref-doc#how-the-docs-generated", ref.DefinitionName) + os.Exit(1) } if c.Category == types.CUECategory && baseDoc != "" { base = fmt.Sprintf("\n\n%s %s\n\n%s", sharp, baseTitle, baseDoc)