GitRoot
Craft your forge, Build your project, Grow your community freely
1// SPDX-FileCopyrightText: 2025 Romain Maneschi <romain@gitroot.dev>
2//
3// SPDX-License-Identifier: EUPL-1.2
4
5package main
6
7import (
8 "fmt"
9
10 "github.com/tidwall/gjson"
11 "gitroot.dev/libs/golang/glob"
12 gitroot "gitroot.dev/libs/golang/plugin/model"
13)
14
15type conf struct {
16 defaultBranch string
17 style string
18 favicon string
19 header string
20 menu []link
21 footer string
22 generateGitWorktree bool
23 branchesDir string
24 meta map[string]string
25 layout []layout
26}
27
28var defaultRun = []gitroot.PluginRun{{
29 Path: "**/*",
30 Branch: []string{"main"},
31 When: gitroot.PluginRunWhenAll,
32 Func: []gitroot.PluginFunc{},
33 Write: gitroot.PluginWrite{
34 Git: []gitroot.PluginWriteRight{{
35 Path: "index.md",
36 Can: []gitroot.PluginWriteRightCan{gitroot.PluginWriteRightCanAdd},
37 }},
38 Web: []gitroot.PluginWriteRight{{
39 Path: "**/*",
40 Can: gitroot.PluginWriteRightCanAll,
41 }},
42 Exec: []gitroot.PluginExecRight{},
43 CallFunc: []gitroot.PluginCallFuncRight{
44 {PluginName: PLUGIN_MARKDOWN, FuncName: PLUGIN_MARKDOWN_FUNC},
45 {PluginName: PLUGIN_CODE, FuncName: PLUGIN_CODE_FUNC},
46 {PluginName: "apex_mermaid", FuncName: "renderCode"}, //TODO it's transitive how to not do this? It's needed because runtime check that plugin can call that other l.785 runtime.go::CallBuilder()
47 },
48 },
49 Configuration: map[string]any{
50 "defaultBranch": "main",
51 "style": "simple.min.css",
52 "favicon": "icon.png",
53 "header": "<h1>{{repo.name}}</h1>",
54 "menu": []link{
55 {Display: "🏠 Home", Link: "/"},
56 {Display: "📖 Readme", Link: "/README.html"},
57 {Display: "🐞 Issues", Link: "/boards/issues.html"},
58 {Display: "⚖ Licence", Link: "/LICENCE.html"},
59 },
60 "footer": "<p>Clone with <code>git clone {{repo.cloneUrl}}</code></p><small>Hosted with ❤️ by <a href=\"https://gitroot.dev\">GitRoot</a></small>",
61 "generateGitWorktree": true,
62 "branchesDir": "branches",
63 "meta": map[string]string{
64 "description": "a short description",
65 "og:title": "title displayed in social",
66 "og:description": "description displayed in social",
67 "og:type": "article",
68 "fediverse:creator": "@forge@gitroot.dev",
69 },
70 "layout": []layout{},
71 },
72}, {
73 Path: "**/*",
74 Branch: []string{"*", "!main"},
75 When: gitroot.PluginRunWhenAll,
76 Func: []gitroot.PluginFunc{},
77 Write: gitroot.PluginWrite{
78 Git: []gitroot.PluginWriteRight{},
79 Web: []gitroot.PluginWriteRight{{
80 Path: "branches/**/*",
81 Can: gitroot.PluginWriteRightCanAll,
82 }},
83 Exec: []gitroot.PluginExecRight{},
84 CallFunc: []gitroot.PluginCallFuncRight{
85 {PluginName: PLUGIN_MARKDOWN, FuncName: PLUGIN_MARKDOWN_FUNC},
86 {PluginName: PLUGIN_CODE, FuncName: PLUGIN_CODE_FUNC},
87 {PluginName: "apex_mermaid", FuncName: "renderCode"}, //TODO it's transitive how to not do this? It's needed because runtime check that plugin can call that other l.785 runtime.go::CallBuilder()
88 },
89 },
90 Configuration: map[string]any{
91 "defaultBranch": "main",
92 "style": "simple.min.css",
93 "favicon": "icon.png",
94 "header": "<h1>{{repo.name}}</h1>",
95 "menu": []link{
96 {Display: "🏠 Home", Link: "/"},
97 {Display: "📖 Readme", Link: "/README.html"},
98 {Display: "🐞 Issues", Link: "/boards/issues.html"},
99 {Display: "⚖ Licence", Link: "/LICENCE.html"},
100 },
101 "footer": "<p>Clone with <code>git clone {{repo.cloneUrl}}</code></p><small>Hosted with ❤️ by <a href=\"https://gitroot.dev\">GitRoot</a></small>",
102 "generateGitWorktree": false,
103 "branchesDir": "branches",
104 "meta": map[string]string{
105 "description": "a short description",
106 "og:title": "title displayed in social",
107 "og:description": "description displayed in social",
108 "og:type": "article",
109 "fediverse:creator": "@forge@gitroot.dev",
110 },
111 "layout": []layout{},
112 },
113}}
114
115type link struct {
116 Link string `json:"link"`
117 Display string `json:"display"`
118}
119
120type layout struct {
121 Glob *glob.Glob `json:"glob"`
122 Path string `json:"path"`
123}
124
125func (p *Plugin) newConf(serializedConf string) *conf {
126 jsonConf := gjson.Parse(serializedConf)
127 menus := []link{}
128 for _, l := range jsonConf.Get("menu").Array() {
129 menus = append(menus, link{
130 Link: l.Get("link").String(),
131 Display: l.Get("display").String(),
132 })
133 }
134 layouts := []layout{}
135 for _, ljson := range jsonConf.Get("layout").Array() {
136 l := ljson.Get("glob").String()
137 if g, err := glob.NewGlob(l); err == nil {
138 layouts = append(layouts, layout{
139 Glob: g,
140 Path: ljson.Get("path").String(),
141 })
142 } else {
143 p.server.LogError(fmt.Sprintf("bad glob ignore layout %s", l), err)
144 }
145 }
146 metaJson := jsonConf.Get("meta").Map()
147 meta := make(map[string]string, len(metaJson))
148 for key, val := range metaJson {
149 meta[key] = val.String()
150 }
151 defaultBranch := jsonConf.Get("defaultBranch").String()
152 if defaultBranch == "" {
153 defaultBranch = "main"
154 }
155 style := jsonConf.Get("style").String()
156 if style == "" {
157 style = "simple.min.css"
158 }
159 return &conf{
160 defaultBranch: defaultBranch,
161 style: style,
162 favicon: jsonConf.Get("favicon").String(),
163 header: jsonConf.Get("header").String(),
164 menu: menus,
165 footer: jsonConf.Get("footer").String(),
166 generateGitWorktree: jsonConf.Get("generateGitWorktree").Bool(),
167 branchesDir: jsonConf.Get("branchesDir").String(),
168 meta: meta,
169 layout: layouts,
170 }
171}