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
  7// compile cmd
  8// tinygo build -o ladybug-0.0.1.wasm -scheduler=none --no-debug -target=wasi ./
  9
 10import (
 11	"bytes"
 12	_ "embed"
 13	"fmt"
 14	"io/fs"
 15
 16	"github.com/sigurn/crc16"
 17	"github.com/tidwall/gjson"
 18	gitroot "gitroot.dev/libs/golang/plugin"
 19)
 20
 21type MyConf struct {
 22	Name      string `json:"name"`
 23	Type      string `json:"type"`
 24	Mandatory bool   `json:"mandatory"`
 25	Default   any    `json:"default"`
 26}
 27
 28var defaultConf = map[string]any{"metadata": []MyConf{
 29	{Name: "id", Type: "crc16", Mandatory: true, Default: "autogenerated"},
 30	{Name: "priority", Type: "int", Mandatory: true, Default: 50},
 31	{Name: "assignee", Type: "user", Mandatory: false, Default: nil},
 32	{Name: "status", Type: "string", Mandatory: false, Default: "triage"},
 33	{Name: "kind", Type: "string", Mandatory: false, Default: "issue"},
 34}}
 35
 36var defaultRun = []gitroot.PluginRun{{
 37	Path:   "issues/**/*.md",
 38	Branch: []string{"*"},
 39	When:   []gitroot.PluginRunWhen{gitroot.PluginRunWhenAdd, gitroot.PluginRunWhenMod},
 40	Write: gitroot.PluginWrite{
 41		Git: []gitroot.PluginWriteRight{{
 42			Path: "issues/**/*.md",
 43			Can:  []gitroot.PluginWriteRightCan{gitroot.PluginWriteRightCanMod},
 44		}},
 45		Web: []gitroot.PluginWriteRight{},
 46	},
 47	Configuration: defaultConf,
 48}}
 49
 50var table = crc16.MakeTable(crc16.CRC16_MAXIM)
 51
 52type Plugin struct {
 53	server gitroot.Server
 54	conf   []MyConf
 55}
 56
 57func (p *Plugin) Init(repoName string, confHasChanged bool, serializedConf string) error {
 58	p.conf = []MyConf{}
 59	for _, meta := range gjson.Parse(serializedConf).Get("metadata").Array() {
 60		myConf := MyConf{
 61			Name:      meta.Get("name").String(),
 62			Type:      meta.Get("type").String(),
 63			Mandatory: meta.Get("mandatory").Bool(),
 64			Default:   meta.Get("default").Value(),
 65		}
 66		p.conf = append(p.conf, myConf)
 67	}
 68	return nil
 69}
 70
 71func (p *Plugin) StartCommit(commit gitroot.Commit) error {
 72	return nil
 73}
 74
 75func (p *Plugin) AddFile(filepath string) error {
 76	content, err := fs.ReadFile(p.server.Worktree(), filepath)
 77	if err != nil {
 78		p.server.LogError("AddFile ReadFile "+filepath, err)
 79		return nil
 80	}
 81	if !bytes.HasPrefix(content, []byte("---")) {
 82		header := ""
 83		for _, props := range p.conf {
 84			if props.Name != "" {
 85				if props.Mandatory {
 86					if props.Default != nil {
 87						def := props.Default
 88						if props.Default == "autogenerated" && props.Type == "crc16" {
 89							def = fmt.Sprintf("%X", crc16.Checksum([]byte(filepath), table))
 90						}
 91						header += fmt.Sprintf("%s: %v\n", props.Name, def)
 92					}
 93				} else {
 94					if props.Default != nil {
 95						header += fmt.Sprintf("%s: %v\n", props.Name, props.Default)
 96					} else {
 97						header += fmt.Sprintf("%s: null\n", props.Name)
 98					}
 99				}
100			}
101		}
102		newContent := fmt.Sprintf("---\n%s---\n\n%s", header, string(content))
103		p.server.ModifyContent(filepath, newContent)
104	} else {
105		metas := bytes.Split(content, []byte("---"))
106		meta := bytes.Trim(metas[1], "\n")
107		header := ""
108		for _, props := range p.conf {
109			if props.Name != "" {
110				if !bytes.Contains(meta, []byte(props.Name)) {
111					if props.Mandatory {
112						if props.Default != "" {
113							def := props.Default
114							if props.Default == "autogenerated" && props.Type == "crc16" {
115								def = fmt.Sprintf("%X", crc16.Checksum([]byte(filepath), table))
116							}
117							header += fmt.Sprintf("%s: %s\n", props.Name, def)
118						}
119					} else {
120						if props.Default != nil && props.Default != "" {
121							header += fmt.Sprintf("%s: %s\n", props.Name, props.Default)
122						} else {
123							header += fmt.Sprintf("%s: null\n", props.Name)
124						}
125					}
126				}
127			}
128		}
129		newContent := fmt.Sprintf("---\n%s\n%s---%s", meta, header, bytes.Join(metas[2:], []byte("\n")))
130		p.server.ModifyContent(filepath, newContent)
131	}
132	return nil
133}
134
135func (p *Plugin) ModFile(fromPath string, toPath string) error {
136	return p.AddFile(toPath)
137}
138
139func (p *Plugin) DelFile(path string) error {
140	return nil
141}
142
143func (p *Plugin) EndCommit(commit gitroot.Commit) error {
144	return nil
145}
146
147func (p *Plugin) Finish() error {
148	p.server.CommitAllIfNeeded("issue metadata added")
149	return nil
150}
151
152func Build(server gitroot.Server) gitroot.Plugin {
153	return &Plugin{
154		server: server,
155	}
156}
157
158//go:wasmexport install
159func main() {
160	gitroot.Register(defaultRun, Build)
161}