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 exec
 6
 7import (
 8	"context"
 9	"fmt"
10	"os"
11	"path/filepath"
12	"time"
13
14	pluginLib "gitroot.dev/libs/golang/plugin/model"
15	"gitroot.dev/server/configuration"
16	"gitroot.dev/server/logger"
17	"gitroot.dev/server/repository"
18	"gitroot.dev/server/user"
19)
20
21const APP_DIR = "app"
22
23type executor interface {
24	name() string
25	exec(dir string, exec pluginLib.Exec) (*pluginLib.ExecStatus, error)
26}
27
28type manager struct {
29	logger   *logger.Logger
30	ctx      context.Context
31	conf     needConf
32	executor executor
33}
34
35type needConf interface {
36	GetExecConf() configuration.ExecConf
37}
38
39type needUser interface {
40	RootCommiter() *user.Commiter
41}
42
43func NewManager(ctx context.Context, conf needConf, userManager needUser) *manager {
44	log := logger.NewLoggerCtx(logger.EXEC, ctx)
45	var exe executor = NewNone(log)
46	c := conf.GetExecConf()
47	if c.BareMetal.Enabled {
48		exe = NewBareMetal(log)
49	} else if c.Bwrap.Enabled {
50		exe = NewBwrap(log, conf.GetExecConf().Bwrap)
51	} else if c.Container.Enabled {
52		exe = NewContainer(log, conf.GetExecConf().Container)
53	} else if c.Ssh.Enabled {
54		exe = NewSsh(log, conf.GetExecConf().Ssh, userManager)
55	} else {
56		log.Warn("executor not found will use none")
57	}
58	m := &manager{
59		logger:   log,
60		ctx:      ctx,
61		conf:     conf,
62		executor: exe,
63	}
64	return m
65}
66
67func (m *manager) prepareExec(project *repository.GitRootRepository, branch string, callback func(dir string) (*pluginLib.ExecStatus, error)) (*pluginLib.ExecStatus, error) {
68	dir := os.TempDir()
69	tempDir := filepath.Join(dir, "pipelines-gitroot", fmt.Sprintf("%s-%s-%d", project.Name(), branch, time.Now().Nanosecond()))
70
71	err := os.MkdirAll(tempDir, os.ModePerm)
72	if err != nil {
73		return nil, err
74	}
75
76	err = project.Worktree(filepath.Join(tempDir, APP_DIR))
77	if err != nil {
78		return nil, err
79	}
80	return callback(tempDir)
81}
82
83func (m *manager) Exec(project *repository.GitRootRepository, branch string, exec pluginLib.Exec) (*pluginLib.ExecStatus, error) {
84	m.logger.Info("will exec", logger.NewLoggerPair("executor", m.executor.name()), logger.NewLoggerPair("project", project.Name()), logger.NewLoggerPair("branch", branch))
85	return m.prepareExec(project, branch, func(dir string) (*pluginLib.ExecStatus, error) {
86		return m.executor.exec(dir, exec)
87	})
88}