pkg/di/container.go (57 lines of code) (raw):
package di
import (
"fmt"
"os"
"path/filepath"
stepdist "gitlab.com/gitlab-org/step-runner/dist"
"gitlab.com/gitlab-org/step-runner/pkg/api/service"
"gitlab.com/gitlab-org/step-runner/pkg/cache/dist"
"gitlab.com/gitlab-org/step-runner/pkg/cache/git"
"gitlab.com/gitlab-org/step-runner/pkg/runner"
)
/*
Container provides Dependency Injection (DI) for the step-runner.
DI is where an object's dependencies are passed to it, rather than being created internally.
Promotes loose coupling, testability, and maintainability.
Ideally, constructors are called only in two places: DI, and test builders. This makes it easy to change
the constructor function signature.
For example, creating dependencies within an object:
- OCIFetcher depends on `internal.NewClient` and `cache.New`
- Changing `internal.NewClient` or `cache.New` function signatures forces a change in OCIFetcher
func NewOCIFetcher() *OCIFetcher {
return &OCIFetcher{
client: internal.NewClient(cache.New()),
}
}
Creating dependencies using DI:
- OCIFetcher only depends on internal.Client (even better, an interface of Client)
- Changing NewClient or cache.New requires no change in OCIFetcher
- Requires DI Container.OCIFetcher()
func NewOCIFetcher(client *internal.Client) *OCIFetcher {
return &OCIFetcher{ client: client }
}
*/
type Container struct{}
func NewContainer() *Container {
return &Container{}
}
func (c *Container) StepResourceParser() (*runner.StepResourceParser, error) {
gitFetcher, err := c.GitFetcher()
if err != nil {
return nil, fmt.Errorf("creating step resource parser: %w", err)
}
return runner.NewStepResourceParser(gitFetcher, c.DistFetcher()), nil
}
func (c *Container) StepParser() (*runner.Parser, error) {
stepResParser, err := c.StepResourceParser()
if err != nil {
return nil, fmt.Errorf("creating step parser: %w", err)
}
return runner.NewParser(stepResParser), nil
}
func (c *Container) CacheDir() (string, error) {
cacheDir := filepath.Join(os.TempDir(), "step-runner-cache")
if err := os.MkdirAll(cacheDir, 0o750); err != nil {
return "", fmt.Errorf("creating cache dir %q: %w", cacheDir, err)
}
return cacheDir, nil
}
func (c *Container) GitFetcher() (*git.GitFetcher, error) {
cacheDir, err := c.CacheDir()
if err != nil {
return nil, fmt.Errorf("creating git fetcher: %w", err)
}
return git.New(cacheDir, git.CloneOptions{Depth: 1}), nil
}
func (c *Container) DistFetcher() *dist.Fetcher {
return dist.NewFetcher(stepdist.FindDistributedStep)
}
func (c *Container) StepRunnerService() (*service.StepRunnerService, error) {
env, err := runner.NewEnvironmentFromOS()
if err != nil {
return nil, fmt.Errorf("creating step runner service: %w", err)
}
stepParser, err := c.StepParser()
if err != nil {
return nil, fmt.Errorf("creating step runner service: %w", err)
}
return service.New(stepParser, env), nil
}