Skip to content

Commit a40857f

Browse files
committed
docs: config partial generation
1 parent 7d50099 commit a40857f

503 files changed

Lines changed: 7841 additions & 402 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

docs/README.md

Lines changed: 23 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -16,30 +16,38 @@ yarn start
1616
```
1717
This command starts a local development server and open up a browser window. Most changes are reflected live without having to restart the server.
1818

19-
### Generate Config Reference (devspace.yaml)
20-
```bash
21-
cd ../ # main project directory
22-
23-
# JSON Schema:
24-
go run ./hack/docs/config/reference.go >docs/schemas/config-jsonschema.json
19+
### Production Build
20+
```
21+
yarn build
22+
```
23+
This command generates static content into the `build` directory and can be served using any static contents hosting service.
2524

26-
# Open API Spec:
27-
go run ./hack/docs/config/reference.go true >docs/schemas/config-openapi.json
25+
### Create New Major Version
26+
```bash
27+
yarn run docusaurus docs:version 5.x
2828
```
2929

3030
### Generate CLI Reference
3131
```bash
3232
cd ../ # main project directory
33-
go run ./hack/gen-docs.go
33+
go run ./docs/hack/cli/main.go
3434
```
3535

36-
### Create Version
36+
### Generate Partials For Config (devspace.yaml)
3737
```bash
38-
yarn run docusaurus docs:version 5.x
39-
```
38+
cd ../ # main project directory
4039

41-
### Build
40+
go run ./docs/hack/config/partials/main.go
4241
```
43-
yarn build
42+
43+
44+
### Generate Schema For Config (devspace.yaml)
45+
```bash
46+
cd ../ # main project directory
47+
48+
# JSON Schema:
49+
go run ./docs/hack/config/schema/main.go >docs/schemas/config-jsonschema.json
50+
51+
# Open API Spec:
52+
go run ./docs/hack/config/schema/main.go true >docs/schemas/config-openapi.json
4453
```
45-
This command generates static content into the `build` directory and can be served using any static contents hosting service.

docs/hack/config/partials/main.go

Lines changed: 144 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
1+
package main
2+
3+
import (
4+
"fmt"
5+
"io/ioutil"
6+
"os"
7+
"path/filepath"
8+
"strings"
9+
10+
"github.com/invopop/jsonschema"
11+
"github.com/loft-sh/devspace/docs/hack/util"
12+
"github.com/loft-sh/devspace/pkg/devspace/config/versions/latest"
13+
)
14+
15+
const configPartialBasePath = "docs/pages/configuration/_partials/"
16+
17+
func main() {
18+
r := new(jsonschema.Reflector)
19+
r.AllowAdditionalProperties = true
20+
r.PreferYAMLSchema = true
21+
r.RequiredFromJSONSchemaTags = false
22+
r.YAMLEmbeddedStructs = false
23+
r.ExpandedStruct = true
24+
25+
err := r.AddGoComments("github.com/loft-sh/devspace", "./pkg/devspace/config/versions/latest")
26+
if err != nil {
27+
panic(err)
28+
}
29+
30+
schema := r.Reflect(&latest.Config{})
31+
32+
createSections("", schema, schema.Definitions, 1)
33+
}
34+
35+
func createSections(prefix string, schema *jsonschema.Schema, definitions jsonschema.Definitions, depth int) string {
36+
partialImports := &[]string{}
37+
content := ""
38+
39+
for _, fieldName := range schema.Properties.Keys() {
40+
41+
field, ok := schema.Properties.Get(fieldName)
42+
if ok {
43+
if fieldSchema, ok := field.(*jsonschema.Schema); ok {
44+
fieldContent := ""
45+
fieldFile := fmt.Sprintf(configPartialBasePath+"%s/%s%s.mdx", latest.Version, prefix, fieldName)
46+
47+
ref := ""
48+
if fieldSchema.Type == "array" {
49+
ref = fieldSchema.Items.Ref
50+
} else if patternPropertySchema, ok := fieldSchema.PatternProperties[".*"]; ok {
51+
ref = patternPropertySchema.Ref
52+
} else if fieldSchema.Ref != "" {
53+
ref = fieldSchema.Ref
54+
}
55+
56+
if ref != "" {
57+
refSplit := strings.Split(ref, "/")
58+
nestedSchema, ok := definitions[refSplit[len(refSplit)-1]]
59+
60+
if ok {
61+
newPrefix := prefix + fieldName + "/"
62+
createSections(newPrefix, nestedSchema, definitions, depth+1)
63+
}
64+
} else {
65+
required := ""
66+
if contains(schema.Required, fieldName) {
67+
required = util.TemplateConfigFieldRequired
68+
}
69+
70+
fieldTypeRaw := fieldSchema.Type
71+
if fieldTypeRaw == "array" {
72+
fieldTypeRaw = fieldSchema.Items.Type + "[]"
73+
}
74+
fieldType := fmt.Sprintf(util.TemplateConfigFieldType, fieldTypeRaw)
75+
fieldDefault := ""
76+
if fieldSchema.Default != nil {
77+
fieldDefault = fmt.Sprintf(util.TemplateConfigFieldType, fieldSchema.Default)
78+
}
79+
80+
fieldContent = fmt.Sprintf(util.TemplateConfigField, fieldName, required, fieldType, fieldDefault, fieldSchema.Description)
81+
82+
err := os.MkdirAll(filepath.Dir(fieldFile), os.ModePerm)
83+
if err != nil {
84+
panic(err)
85+
}
86+
87+
err = ioutil.WriteFile(fieldFile, []byte(fieldContent), os.ModePerm)
88+
if err != nil {
89+
panic(err)
90+
}
91+
}
92+
93+
*partialImports = append(*partialImports, fieldFile)
94+
fieldPartial := fmt.Sprintf(util.TemplatePartialUse, util.GetPartialImportName(fieldFile))
95+
if ref != "" {
96+
fieldSummary := fmt.Sprintf("<h%d><code>%s</code></h%d>", depth+1, fieldName, depth+1)
97+
fieldPartial = fmt.Sprintf("<details><summary>%s</summary>\n%s\n</details>", fieldSummary, fieldPartial)
98+
}
99+
100+
content = content + "\n\n" + fieldPartial
101+
}
102+
}
103+
}
104+
105+
if prefix == "" {
106+
prefix = "reference"
107+
}
108+
109+
pageFile := fmt.Sprintf(configPartialBasePath+"%s/%s.mdx", latest.Version, strings.TrimSuffix(prefix, "/"))
110+
111+
importContent := ""
112+
for _, partialImport := range *partialImports {
113+
partialImportPath, err := filepath.Rel(filepath.Dir(pageFile), partialImport)
114+
if err != nil {
115+
panic(err)
116+
}
117+
118+
if partialImportPath[0:1] != "." {
119+
partialImportPath = "./" + partialImportPath
120+
}
121+
122+
importContent = importContent + fmt.Sprintf(util.TemplatePartialImport, util.GetPartialImportName(partialImport), partialImportPath)
123+
}
124+
125+
content = fmt.Sprintf("%s%s", importContent, content)
126+
127+
err := ioutil.WriteFile(pageFile, []byte(content), os.ModePerm)
128+
if err != nil {
129+
panic(err)
130+
}
131+
132+
//fmt.Println(content)
133+
134+
return content
135+
}
136+
137+
func contains(s []string, e string) bool {
138+
for _, a := range s {
139+
if a == e {
140+
return true
141+
}
142+
}
143+
return false
144+
}

docs/hack/functions/main.go

Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
package main
2+
3+
import (
4+
"fmt"
5+
"io/ioutil"
6+
"log"
7+
"os"
8+
"path/filepath"
9+
"reflect"
10+
11+
"github.com/loft-sh/devspace/docs/hack/util"
12+
"github.com/loft-sh/devspace/pkg/devspace/pipeline/engine/pipelinehandler/commands"
13+
)
14+
15+
type Function struct {
16+
Handler interface{}
17+
Flags interface{}
18+
}
19+
20+
func main() {
21+
for functionName := range Functions {
22+
function := Functions[functionName]
23+
24+
pageFile := fmt.Sprintf(util.PagePathFunction, functionName)
25+
pageContent := []byte{}
26+
27+
_, err := os.Stat(pageFile)
28+
if err == nil {
29+
pageContent, err = ioutil.ReadFile(pageFile)
30+
if err != nil {
31+
log.Fatal(err)
32+
}
33+
}
34+
35+
functionDescription := util.GetExistingDescription(string(pageContent))
36+
37+
partialImports := &[]string{}
38+
39+
argsContent := fmt.Sprintf("The function `%s` does not expect any arguments.", functionName)
40+
41+
funcHandlerRef := reflect.ValueOf(function.Handler).Type()
42+
maxArguments := funcHandlerRef.NumIn()
43+
if maxArguments > 0 {
44+
lastArgument := funcHandlerRef.In(maxArguments - 1)
45+
if lastArgument.String() == "[]string" {
46+
argsContent = fmt.Sprintf("The function `%s` expects arguments.", functionName)
47+
48+
existingArgsContent := util.GetSection("Arguments", string(pageContent))
49+
if existingArgsContent != "" {
50+
argsContent = existingArgsContent
51+
}
52+
}
53+
}
54+
55+
flagRef := reflect.ValueOf(function.Flags).Type()
56+
flagContent := getFlagReference(functionName, flagRef, partialImports, string(pageContent))
57+
if flagContent == "" {
58+
continue
59+
}
60+
61+
importContent := ""
62+
for _, partialImport := range *partialImports {
63+
partialImportPath, err := filepath.Rel(filepath.Dir(pageFile), partialImport)
64+
if err != nil {
65+
panic(err)
66+
}
67+
68+
if partialImportPath[0:1] != "." {
69+
partialImportPath = "./" + partialImportPath
70+
}
71+
72+
importContent = importContent + fmt.Sprintf(util.TemplatePartialImport, util.GetPartialImportName(partialImport), partialImportPath)
73+
}
74+
75+
content := fmt.Sprintf(util.TemplatePage, functionName, functionName, importContent, functionDescription, argsContent, flagContent)
76+
77+
err = ioutil.WriteFile(pageFile, []byte(content), 0)
78+
if err != nil {
79+
panic(err)
80+
}
81+
}
82+
}
83+
84+
func getFlagReference(functionName string, flagRef reflect.Type, partialImports *[]string, pageContent string) string {
85+
content := ""
86+
87+
for i := 0; i < flagRef.NumField(); i++ {
88+
field := flagRef.Field(i)
89+
if field.Anonymous {
90+
content = content + getFlagReference(functionName, field.Type, partialImports, pageContent)
91+
continue
92+
}
93+
94+
long := field.Tag.Get("long")
95+
if long == "" {
96+
continue
97+
}
98+
99+
existingFlagContent := util.GetPartOfAutogenSection("`--"+long, pageContent)
100+
101+
short := flagRef.Field(i).Tag.Get("short")
102+
description := flagRef.Field(i).Tag.Get("description")
103+
104+
if short != "" {
105+
short = " / -" + short
106+
}
107+
108+
flagPartial := fmt.Sprintf(util.PartialPathFlag, functionName, long)
109+
_, err := os.Stat(flagPartial)
110+
if err == nil {
111+
*partialImports = append(*partialImports, flagPartial)
112+
description = description + "\n\n" + fmt.Sprintf(util.TemplatePartialUseFlag, util.GetPartialImportName(flagPartial), functionName, long)
113+
}
114+
115+
content = content + fmt.Sprintf(util.TemplateFlag, long, short, description) + existingFlagContent
116+
}
117+
118+
return content
119+
}
120+
121+
var Functions = map[string]Function{
122+
"build_images": {
123+
Handler: commands.BuildImages,
124+
Flags: commands.BuildImagesOptions{},
125+
},
126+
"create_deployments": {
127+
Handler: commands.CreateDeployments,
128+
Flags: commands.CreateDeploymentsOptions{},
129+
},
130+
}

docs/hack/util/extract_content.go

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
package util
2+
3+
import (
4+
"regexp"
5+
)
6+
7+
func GetExistingDescription(pageContent string) string {
8+
match := regexp.MustCompile(`(?is)^---.*?---\s*(import.*?\n)*\s*(.*?)\s*\n###? .*$`).ReplaceAllString(pageContent, "$2")
9+
10+
if match != pageContent && match != "" {
11+
return "\n" + match + "\n"
12+
}
13+
return ""
14+
}
15+
16+
func GetSection(headlineText, pageContent string) string {
17+
regex := `(?is)^.*\s*\n###?\s+` + headlineText + `\s*(.*?)(\n+((##)|$).*)?$`
18+
match := regexp.MustCompile(regex).ReplaceAllString(pageContent, "$1")
19+
20+
if match != pageContent && match != "" {
21+
return match
22+
}
23+
return ""
24+
}
25+
26+
func GetPartOfAutogenSection(headlineText, pageContent string) string {
27+
regex := "(?is)^.*" + AutoGenTagBegin + `\s*\n###?\s+` + headlineText + `.*?` + AutoGenTagEnd + `\s*(.*?)\s*` + AutoGenTagBegin + ".*$"
28+
match := regexp.MustCompile(regex).ReplaceAllString(pageContent, "$1")
29+
30+
if match != pageContent && match != "" {
31+
return match + "\n\n"
32+
}
33+
return ""
34+
}

docs/hack/util/partials.go

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
package util
2+
3+
import (
4+
"fmt"
5+
"path/filepath"
6+
"regexp"
7+
"strings"
8+
)
9+
10+
var partialNameRegex = regexp.MustCompile(`(\..*$)|[^a-zA-Z-]`)
11+
12+
func GetPartialImportName(partialImport string) string {
13+
basename := filepath.Base(partialImport)
14+
basename = partialNameRegex.ReplaceAllString(basename, "")
15+
16+
return fmt.Sprintf("Partial%s", strings.Title(basename))
17+
}

0 commit comments

Comments
 (0)