242 lines
5.5 KiB
Go
242 lines
5.5 KiB
Go
// SPDX-License-Identifier: EUPL-1.2
|
|
|
|
package setup
|
|
|
|
import (
|
|
core "dappco.re/go/core"
|
|
"gopkg.in/yaml.v3"
|
|
)
|
|
|
|
// ConfigData supplies values when setup renders workspace templates.
|
|
//
|
|
// data := setup.ConfigData{Name: "agent", Type: "go", Repository: "core/agent"}
|
|
type ConfigData struct {
|
|
Name string
|
|
Description string
|
|
Type string
|
|
Module string
|
|
Repository string
|
|
GoVersion string
|
|
Targets []Target
|
|
Commands []Command
|
|
Env map[string]string
|
|
}
|
|
|
|
// Target describes one build target.
|
|
//
|
|
// target := setup.Target{OS: "linux", Arch: "amd64"}
|
|
type Target struct {
|
|
OS string
|
|
Arch string
|
|
}
|
|
|
|
// Command defines one named command in generated config.
|
|
//
|
|
// command := setup.Command{Name: "unit", Run: "go test ./..."}
|
|
type Command struct {
|
|
Name string
|
|
Run string
|
|
}
|
|
|
|
type configSection struct {
|
|
Key string
|
|
Values []configValue
|
|
}
|
|
|
|
type configValue struct {
|
|
Key string
|
|
Value any
|
|
}
|
|
|
|
// GenerateBuildConfig renders `build.yaml` content for a detected repo type.
|
|
//
|
|
// r := setup.GenerateBuildConfig("/srv/repos/agent", setup.TypeGo)
|
|
// if r.OK { content := r.Value.(string) }
|
|
func GenerateBuildConfig(path string, projectType ProjectType) core.Result {
|
|
name := core.PathBase(path)
|
|
sections := []configSection{
|
|
{
|
|
Key: "project",
|
|
Values: []configValue{
|
|
{Key: "name", Value: name},
|
|
{Key: "type", Value: string(projectType)},
|
|
},
|
|
},
|
|
}
|
|
|
|
switch projectType {
|
|
case TypeGo, TypeWails:
|
|
sections = append(sections, configSection{
|
|
Key: "build",
|
|
Values: []configValue{
|
|
{Key: "main", Value: core.Concat("./cmd/", name)},
|
|
{Key: "binary", Value: name},
|
|
{Key: "cgo", Value: false},
|
|
},
|
|
})
|
|
case TypePHP:
|
|
sections = append(sections, configSection{
|
|
Key: "build",
|
|
Values: []configValue{
|
|
{Key: "dockerfile", Value: "Dockerfile"},
|
|
{Key: "image", Value: name},
|
|
},
|
|
})
|
|
case TypeNode:
|
|
sections = append(sections, configSection{
|
|
Key: "build",
|
|
Values: []configValue{
|
|
{Key: "script", Value: "npm run build"},
|
|
{Key: "output", Value: "dist"},
|
|
},
|
|
})
|
|
}
|
|
|
|
return renderConfig(core.Concat(name, " build configuration"), sections)
|
|
}
|
|
|
|
// GenerateTestConfig renders `test.yaml` content for a detected repo type.
|
|
//
|
|
// r := setup.GenerateTestConfig(setup.TypeGo)
|
|
// if r.OK { content := r.Value.(string) }
|
|
func GenerateTestConfig(projectType ProjectType) core.Result {
|
|
var sections []configSection
|
|
|
|
switch projectType {
|
|
case TypeGo, TypeWails:
|
|
sections = []configSection{
|
|
{
|
|
Key: "commands",
|
|
Values: []configValue{
|
|
{Key: "unit", Value: "go test ./..."},
|
|
{Key: "coverage", Value: "go test -coverprofile=coverage.out ./..."},
|
|
{Key: "race", Value: "go test -race ./..."},
|
|
},
|
|
},
|
|
}
|
|
case TypePHP:
|
|
sections = []configSection{
|
|
{
|
|
Key: "commands",
|
|
Values: []configValue{
|
|
{Key: "unit", Value: "vendor/bin/pest --parallel"},
|
|
{Key: "lint", Value: "vendor/bin/pint --test"},
|
|
},
|
|
},
|
|
}
|
|
case TypeNode:
|
|
sections = []configSection{
|
|
{
|
|
Key: "commands",
|
|
Values: []configValue{
|
|
{Key: "unit", Value: "npm test"},
|
|
{Key: "lint", Value: "npm run lint"},
|
|
},
|
|
},
|
|
}
|
|
}
|
|
|
|
return renderConfig("Test configuration", sections)
|
|
}
|
|
|
|
func renderConfig(headerComment string, sections []configSection) core.Result {
|
|
builder := core.NewBuilder()
|
|
|
|
if headerComment != "" {
|
|
builder.WriteString("# ")
|
|
builder.WriteString(headerComment)
|
|
builder.WriteString("\n\n")
|
|
}
|
|
|
|
for sectionIndex, section := range sections {
|
|
builder.WriteString(section.Key)
|
|
builder.WriteString(":\n")
|
|
|
|
for _, value := range section.Values {
|
|
scalar := marshalConfigValue(value.Value)
|
|
if !scalar.OK {
|
|
err, _ := scalar.Value.(error)
|
|
return core.Result{
|
|
Value: core.E("setup.renderConfig", core.Concat("marshal ", section.Key, ".", value.Key), err),
|
|
OK: false,
|
|
}
|
|
}
|
|
|
|
builder.WriteString(" ")
|
|
builder.WriteString(value.Key)
|
|
builder.WriteString(": ")
|
|
builder.WriteString(scalar.Value.(string))
|
|
builder.WriteString("\n")
|
|
}
|
|
|
|
if sectionIndex < len(sections)-1 {
|
|
builder.WriteString("\n")
|
|
}
|
|
}
|
|
|
|
return core.Result{Value: builder.String(), OK: true}
|
|
}
|
|
|
|
func marshalConfigValue(value any) (result core.Result) {
|
|
defer func() {
|
|
if recovered := recover(); recovered != nil {
|
|
result = core.Result{
|
|
Value: core.E("setup.marshalConfigValue", core.Sprint(recovered), nil),
|
|
OK: false,
|
|
}
|
|
}
|
|
}()
|
|
|
|
data, err := yaml.Marshal(value)
|
|
if err != nil {
|
|
return core.Result{
|
|
Value: core.E("setup.marshalConfigValue", "yaml marshal value", err),
|
|
OK: false,
|
|
}
|
|
}
|
|
return core.Result{Value: core.Trim(string(data)), OK: true}
|
|
}
|
|
|
|
func parseGitRemote(remote string) string {
|
|
remote = core.Trim(remote)
|
|
if remote == "" {
|
|
return ""
|
|
}
|
|
|
|
// HTTPS/HTTP URL — extract path after host
|
|
if core.Contains(remote, "://") {
|
|
schemeParts := core.SplitN(remote, "://", 2)
|
|
if len(schemeParts) == 2 {
|
|
rest := schemeParts[1]
|
|
if pathSegments := core.Split(rest, "/"); len(pathSegments) > 1 {
|
|
// Skip host, take path
|
|
pathStart := len(pathSegments[0]) + 1
|
|
if pathStart < len(rest) {
|
|
return trimRemotePath(rest[pathStart:])
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
pathParts := core.SplitN(remote, ":", 2)
|
|
if len(pathParts) == 2 && core.Contains(pathParts[0], "@") {
|
|
return trimRemotePath(pathParts[1])
|
|
}
|
|
|
|
if core.Contains(remote, "/") {
|
|
return trimRemotePath(remote)
|
|
}
|
|
|
|
return ""
|
|
}
|
|
|
|
func trimRemotePath(remote string) string {
|
|
trimmed := core.Trim(remote)
|
|
for core.HasPrefix(trimmed, "/") {
|
|
trimmed = core.TrimPrefix(trimmed, "/")
|
|
}
|
|
for core.HasSuffix(trimmed, "/") {
|
|
trimmed = core.TrimSuffix(trimmed, "/")
|
|
}
|
|
return core.TrimSuffix(trimmed, ".git")
|
|
}
|