Skip to content
Snippets Groups Projects
Commit e8e11dd8 authored by Cameron Swords's avatar Cameron Swords :ghost:
Browse files

Move domain objects to runner namespace

parent 6aac7c0b
No related branches found
No related tags found
1 merge request!85Move domain objects to runner namespace
......@@ -4,16 +4,14 @@ import (
ctx "context"
"fmt"
"os"
"strings"
"slices"
"strings"
"github.com/spf13/cobra"
"google.golang.org/protobuf/encoding/protojson"
"gopkg.in/yaml.v3"
"gitlab.com/gitlab-org/step-runner/pkg/cache"
"gitlab.com/gitlab-org/step-runner/pkg/context"
"gitlab.com/gitlab-org/step-runner/pkg/runner"
"gitlab.com/gitlab-org/step-runner/pkg/step"
"gitlab.com/gitlab-org/step-runner/schema/v1"
......@@ -41,7 +39,7 @@ func run(cmd *cobra.Command, args []string) error {
if err != nil {
return fmt.Errorf("creating cache: %w", err)
}
globalCtx, err := context.NewGlobal()
globalCtx, err := runner.NewGlobalContext()
if err != nil {
return fmt.Errorf("creating global context: %w", err)
}
......
package expression
package expression_test
import (
"bytes"
"errors"
"testing"
"gitlab.com/gitlab-org/step-runner/pkg/context"
"gitlab.com/gitlab-org/step-runner/pkg/internal/expression"
"gitlab.com/gitlab-org/step-runner/pkg/runner"
"gitlab.com/gitlab-org/step-runner/proto"
"github.com/stretchr/testify/require"
......@@ -29,7 +30,7 @@ func TestEvaluate(t *testing.T) {
}}
for _, c := range cases {
t.Run(c.value, func(t *testing.T) {
got, err := Evaluate(textContextSteps(), c.value)
got, err := expression.Evaluate(textContextSteps(), c.value)
if c.wantErr != nil {
require.Equal(t, c.wantErr, err)
} else {
......@@ -63,7 +64,7 @@ func TestEvaluateSensitivity(t *testing.T) {
build()
stepContext := b.stepContext().withStepResult(stepResult).build()
value, err := Evaluate(stepContext, "steps.secret_factory.outputs.secret")
value, err := expression.Evaluate(stepContext, "steps.secret_factory.outputs.secret")
require.NoError(t, err)
require.Equal(t, structpb.NewStringValue("secret.value"), value.Value)
require.Equal(t, test.sensitive, value.Sensitive)
......@@ -94,14 +95,14 @@ func (bldr *stepContextBuilder) withStepResult(stepResult *proto.StepResult) *st
return bldr
}
func (bldr *stepContextBuilder) build() *context.Steps {
return &context.Steps{
Global: b.globalContext().build(),
StepDir: ".",
OutputFile: "output",
Env: map[string]string{},
Inputs: map[string]*structpb.Value{},
Steps: bldr.stepResults,
func (bldr *stepContextBuilder) build() *runner.StepsContext {
return &runner.StepsContext{
GlobalContext: b.globalContext().build(),
StepDir: ".",
OutputFile: "output",
Env: map[string]string{},
Inputs: map[string]*structpb.Value{},
Steps: bldr.stepResults,
}
}
......@@ -112,8 +113,8 @@ func (*builders) globalContext() *globalContextBuilder {
return &globalContextBuilder{}
}
func (*globalContextBuilder) build() *context.Global {
return &context.Global{
func (*globalContextBuilder) build() *runner.GlobalContext {
return &runner.GlobalContext{
WorkDir: ".",
Job: map[string]string{},
ExportFile: "export",
......
package expression
package expression_test
import (
"errors"
"testing"
"gitlab.com/gitlab-org/step-runner/pkg/internal/expression"
"gitlab.com/gitlab-org/step-runner/proto"
"github.com/stretchr/testify/require"
......@@ -81,7 +82,7 @@ func TestExpandString(t *testing.T) {
}}
for _, c := range cases {
t.Run(c.value, func(t *testing.T) {
got, err := ExpandString(textContextSteps(), c.value)
got, err := expression.ExpandString(textContextSteps(), c.value)
if c.wantErr != nil {
require.Equal(t, c.wantErr, err)
} else {
......@@ -147,7 +148,7 @@ func TestExpand(t *testing.T) {
want: structpb.NewStringValue("Hello, my name is Kevin Flynn. You killed my process. Prepare to SIGTERM."),
}}
for _, c := range cases {
got, err := Expand(textContextSteps(), c.value)
got, err := expression.Expand(textContextSteps(), c.value)
if c.wantErr != nil {
require.Equal(t, c.wantErr, err)
} else {
......@@ -195,7 +196,7 @@ func TestExpandSensitivity(t *testing.T) {
t.Run(name, func(t *testing.T) {
stepContext := b.stepContext().withStepResult(test.stepResult).build()
value, err := Expand(stepContext, test.template)
value, err := expression.Expand(stepContext, test.template)
require.NoError(t, err)
require.Equal(t, test.wantValue, value.Value)
require.Equal(t, test.wantSensitive, value.Sensitive)
......
......@@ -10,17 +10,17 @@ import (
"sync"
"time"
rctx "gitlab.com/gitlab-org/step-runner/pkg/context"
"gitlab.com/gitlab-org/step-runner/pkg/internal/streamer/file"
"gitlab.com/gitlab-org/step-runner/pkg/runner"
"gitlab.com/gitlab-org/step-runner/proto"
)
type Job struct {
TmpDir string
WorkDir string
GlobCtx *rctx.Global // To capture stdout/err from all subprocesses
Ctx context.Context // The context used to manage the Job's entire lifetime.
ID string // The ID of the job to run/being run. Must be unique. Typically this will be the CI job ID.
GlobCtx *runner.GlobalContext // To capture stdout/err from all subprocesses
Ctx context.Context // The context used to manage the Job's entire lifetime.
ID string // The ID of the job to run/being run. Must be unique. Typically this will be the CI job ID.
cancel func() // Used to cancel the Ctx.
err error // Captures any error returned when executing steps.
......@@ -60,7 +60,7 @@ func New(request *proto.RunRequest) (*Job, error) {
// TODO: add job timeout to RunRequest and hook it up here
ctx, cancel := context.WithCancel(context.Background())
globCtx, err := rctx.NewGlobal()
globCtx, err := runner.NewGlobalContext()
if err != nil {
cancel()
return nil, fmt.Errorf("creating global context: %w", err)
......
......@@ -5,9 +5,7 @@ import (
"fmt"
"os/exec"
"gitlab.com/gitlab-org/step-runner/pkg/context"
"gitlab.com/gitlab-org/step-runner/pkg/internal/expression"
"gitlab.com/gitlab-org/step-runner/pkg/internal/output"
"gitlab.com/gitlab-org/step-runner/proto"
)
......@@ -21,7 +19,7 @@ func NewExecutableStep() *ExecutableStep {
func (s *ExecutableStep) Run(
ctx ctx.Context,
stepsCtx *context.Steps,
stepsCtx *StepsContext,
specDefinition *proto.SpecDefinition,
result *proto.StepResult,
) error {
......@@ -36,7 +34,7 @@ func (s *ExecutableStep) Run(
outputMethod := specDefinition.Spec.Spec.OutputMethod
// Create output and export files and add to context
files, err := output.New(stepsCtx, outputMethod, outputs)
files, err := NewFiles(stepsCtx, outputMethod, outputs)
if err != nil {
return err
}
......@@ -82,8 +80,8 @@ func (s *ExecutableStep) Run(
cmd.Env = stepsCtx.GetEnvList()
result.Env = stepsCtx.GetEnvs()
// TODO: Use multi-writer
cmd.Stdout = stepsCtx.Global.Stdout
cmd.Stderr = stepsCtx.Global.Stderr
cmd.Stdout = stepsCtx.GlobalContext.Stdout
cmd.Stderr = stepsCtx.GlobalContext.Stderr
// Capture results of execution
err = cmd.Run()
......@@ -101,7 +99,7 @@ func (s *ExecutableStep) Run(
return fmt.Errorf("outputting: %w", err)
}
err = stepsCtx.Global.ExportTo(result)
err = stepsCtx.GlobalContext.ExportTo(result)
if err != nil {
return fmt.Errorf("exporting: %w", err)
......
package output
package runner
import (
"encoding/json"
......@@ -10,7 +10,6 @@ import (
"google.golang.org/protobuf/types/known/structpb"
"gitlab.com/gitlab-org/step-runner/pkg/context"
"gitlab.com/gitlab-org/step-runner/proto"
)
......@@ -19,7 +18,7 @@ const (
)
type Files struct {
stepCtx *context.Steps
stepCtx *StepsContext
outputMethod proto.OutputMethod
specOutputs map[string]*proto.Spec_Content_Output
......@@ -27,8 +26,8 @@ type Files struct {
outputFile string
}
func New(
stepCtx *context.Steps,
func NewFiles(
stepCtx *StepsContext,
outputMethod proto.OutputMethod,
specOutputs map[string]*proto.Spec_Content_Output,
) (*Files, error) {
......
package output
package runner
import (
"maps"
......@@ -10,7 +10,6 @@ import (
protobuf "google.golang.org/protobuf/proto"
"google.golang.org/protobuf/types/known/structpb"
"gitlab.com/gitlab-org/step-runner/pkg/context"
"gitlab.com/gitlab-org/step-runner/proto"
)
......@@ -262,10 +261,10 @@ food=apple
for _, tc := range cases {
t.Run(tc.name, func(t *testing.T) {
ctx, err := context.NewGlobal()
globalCtx, err := NewGlobalContext()
require.NoError(t, err)
defer ctx.Cleanup()
files, err := New(context.NewSteps(ctx), tc.outputMethod, tc.outputs)
defer globalCtx.Cleanup()
files, err := NewFiles(NewStepsContext(globalCtx), tc.outputMethod, tc.outputs)
require.NoError(t, err)
outputFile, err := os.OpenFile(filepath.Join(files.dir, outputFilename), os.O_APPEND|os.O_WRONLY, 0660)
......@@ -344,7 +343,7 @@ foo=baz
for _, tc := range cases {
t.Run(tc.name, func(t *testing.T) {
ctx, err := context.NewGlobal()
ctx, err := NewGlobalContext()
require.NoError(t, err)
if tc.globalEnv != nil {
ctx.Env = tc.globalEnv
......
package context
package runner
import (
"fmt"
"io"
"maps"
"os"
"path/filepath"
"strings"
"github.com/joho/godotenv"
"google.golang.org/protobuf/types/known/structpb"
"gitlab.com/gitlab-org/step-runner/proto"
)
......@@ -18,7 +16,7 @@ const (
exportFilename = "export"
)
type Global struct {
type GlobalContext struct {
WorkDir string `json:"work_dir"`
Job map[string]string `json:"job"`
ExportFile string `json:"export_file"`
......@@ -29,7 +27,7 @@ type Global struct {
dir string
}
func NewGlobal() (*Global, error) {
func NewGlobalContext() (*GlobalContext, error) {
dir, err := os.MkdirTemp("", "step-runner-export-*")
if err != nil {
return nil, fmt.Errorf("making export directory: %w", err)
......@@ -40,7 +38,7 @@ func NewGlobal() (*Global, error) {
return nil, fmt.Errorf("creating export file: %w", err)
}
return &Global{
return &GlobalContext{
Job: map[string]string{},
ExportFile: exportFile,
Env: map[string]string{},
......@@ -50,7 +48,7 @@ func NewGlobal() (*Global, error) {
}, nil
}
func (g *Global) InheritEnv(envs ...string) {
func (g *GlobalContext) InheritEnv(envs ...string) {
if g.Env == nil {
g.Env = make(map[string]string, len(envs))
}
......@@ -62,7 +60,7 @@ func (g *Global) InheritEnv(envs ...string) {
}
}
func (g *Global) ExportTo(result *proto.StepResult) error {
func (g *GlobalContext) ExportTo(result *proto.StepResult) error {
exports, err := godotenv.Read(g.ExportFile)
if err != nil {
return fmt.Errorf("reading exports: %w", err)
......@@ -82,44 +80,6 @@ func (g *Global) ExportTo(result *proto.StepResult) error {
return err
}
func (g *Global) Cleanup() {
func (g *GlobalContext) Cleanup() {
os.RemoveAll(g.dir)
}
type Steps struct {
*Global
StepDir string `json:"step_dir"`
OutputFile string `json:"output_file"`
Env map[string]string `json:"env"`
Inputs map[string]*structpb.Value `json:"inputs"`
Steps map[string]*proto.StepResult `json:"steps"`
}
func NewSteps(global *Global) *Steps {
return &Steps{
Global: global,
Env: maps.Clone(global.Env),
Inputs: map[string]*structpb.Value{},
Steps: map[string]*proto.StepResult{},
}
}
func (s *Steps) GetEnvs() map[string]string {
r := make(map[string]string)
for k, v := range s.Global.Env {
r[k] = v
}
for k, v := range s.Env {
r[k] = v
}
return r
}
func (s *Steps) GetEnvList() []string {
r := []string{}
for k, v := range s.GetEnvs() {
r = append(r, k+"="+v)
}
return r
}
......@@ -54,11 +54,11 @@ func New(defs cache.Cache) (*Execution, error) {
// will be expanded before sub-steps are executed.
func (e *Execution) Run(
ctx ctx.Context,
globalCtx *context.Global,
globalCtx *GlobalContext,
params *Params,
specDefinition *proto.SpecDefinition,
) (*proto.StepResult, error) {
stepsCtx := context.NewSteps(globalCtx)
stepsCtx := NewStepsContext(globalCtx)
// We tell steps where to find their cached definition so they
// can find their files. And so that sub-steps with relative
......@@ -103,7 +103,7 @@ func (e *Execution) Run(
// spec. Missing inputs are given defaults. Missing inputs without a
// default produce an error. Extra inputs not declared also produce an
// error.
func addInputs(stepsCtx *context.Steps, spec *proto.Spec, inputs map[string]*context.Variable) error {
func addInputs(stepsCtx *StepsContext, spec *proto.Spec, inputs map[string]*context.Variable) error {
// Match inputs with definition
for key, value := range spec.Spec.Inputs {
callValue := inputs[key]
......@@ -130,7 +130,7 @@ func addInputs(stepsCtx *context.Steps, spec *proto.Spec, inputs map[string]*con
// addDefinitionEnv expands the step definition environment variables
// with the step context. After expansion, definition environment
// variables are added to the step context.
func addDefinitionEnv(stepsCtx *context.Steps, definition *proto.Definition) error {
func addDefinitionEnv(stepsCtx *StepsContext, definition *proto.Definition) error {
defEnv := map[string]string{}
for k, v := range definition.Env {
res, resErr := expression.ExpandString(stepsCtx, v)
......
......@@ -10,17 +10,16 @@ import (
"gitlab.com/gitlab-org/step-runner/pkg/cache"
"gitlab.com/gitlab-org/step-runner/pkg/context"
"gitlab.com/gitlab-org/step-runner/pkg/internal/expression"
"gitlab.com/gitlab-org/step-runner/pkg/internal/output"
"gitlab.com/gitlab-org/step-runner/proto"
)
// SequenceOfSteps is a step that executes many steps.
type SequenceOfSteps struct {
resourceLoader cache.Cache
runStep func(ctx ctx.Context, globalCtx *context.Global, params *Params, specDefinition *proto.SpecDefinition) (*proto.StepResult, error)
runStep func(ctx ctx.Context, globalCtx *GlobalContext, params *Params, specDefinition *proto.SpecDefinition) (*proto.StepResult, error)
}
func NewSequenceOfSteps(resourceLoader cache.Cache, runStep func(ctx ctx.Context, globalCtx *context.Global, params *Params, specDefinition *proto.SpecDefinition) (*proto.StepResult, error)) *SequenceOfSteps {
func NewSequenceOfSteps(resourceLoader cache.Cache, runStep func(ctx ctx.Context, globalCtx *GlobalContext, params *Params, specDefinition *proto.SpecDefinition) (*proto.StepResult, error)) *SequenceOfSteps {
return &SequenceOfSteps{
resourceLoader: resourceLoader,
runStep: runStep,
......@@ -29,7 +28,7 @@ func NewSequenceOfSteps(resourceLoader cache.Cache, runStep func(ctx ctx.Context
func (s *SequenceOfSteps) Run(
ctx ctx.Context,
stepsCtx *context.Steps,
stepsCtx *StepsContext,
specDefinition *proto.SpecDefinition,
result *proto.StepResult,
) error {
......@@ -41,7 +40,7 @@ func (s *SequenceOfSteps) Run(
result.Env = stepsCtx.GetEnvs()
// Create output and export files and add to context
files, err := output.New(stepsCtx, specDefinition.Spec.Spec.OutputMethod, specDefinition.Spec.Spec.Outputs)
files, err := NewFiles(stepsCtx, specDefinition.Spec.Spec.OutputMethod, specDefinition.Spec.Spec.Outputs)
if err != nil {
return err
}
......@@ -82,7 +81,7 @@ func (s *SequenceOfSteps) Run(
if resErr == nil {
result.Outputs[k] = res.Value
} else {
fmt.Fprintf(stepsCtx.Global.Stderr, "Cannot assign %q due to error: %s", k, resErr.Error())
fmt.Fprintf(stepsCtx.GlobalContext.Stderr, "Cannot assign %q due to error: %s", k, resErr.Error())
}
}
......@@ -94,7 +93,7 @@ func (s *SequenceOfSteps) Run(
// into params in preparation for a recursive call to Run.
func (s *SequenceOfSteps) runSubStep(
ctx ctx.Context,
stepsCtx *context.Steps,
stepsCtx *StepsContext,
specDefinition *proto.SpecDefinition,
stepReference *proto.Step,
) (*proto.StepResult, error) {
......@@ -133,7 +132,7 @@ func (s *SequenceOfSteps) runSubStep(
}
// Run the step definition with the global context and expanded parameters
result, err := s.runStep(ctx, stepsCtx.Global, params, subStepSpecDefinition)
result, err := s.runStep(ctx, stepsCtx.GlobalContext, params, subStepSpecDefinition)
if err != nil {
return result, err
}
......
......@@ -3,10 +3,9 @@ package runner
import (
ctx "context"
"gitlab.com/gitlab-org/step-runner/pkg/context"
"gitlab.com/gitlab-org/step-runner/proto"
)
type Step interface {
Run(ctx ctx.Context, stepsCtx *context.Steps, specDefinition *proto.SpecDefinition, result *proto.StepResult) error
Run(ctx ctx.Context, stepsCtx *StepsContext, specDefinition *proto.SpecDefinition, result *proto.StepResult) error
}
package runner
import (
"maps"
"google.golang.org/protobuf/types/known/structpb"
"gitlab.com/gitlab-org/step-runner/proto"
)
type StepsContext struct {
*GlobalContext
StepDir string `json:"step_dir"`
OutputFile string `json:"output_file"`
Env map[string]string `json:"env"`
Inputs map[string]*structpb.Value `json:"inputs"`
Steps map[string]*proto.StepResult `json:"steps"`
}
func NewStepsContext(globalCtx *GlobalContext) *StepsContext {
return &StepsContext{
GlobalContext: globalCtx,
Env: maps.Clone(globalCtx.Env),
Inputs: map[string]*structpb.Value{},
Steps: map[string]*proto.StepResult{},
}
}
func (s *StepsContext) GetEnvs() map[string]string {
r := make(map[string]string)
for k, v := range s.GlobalContext.Env {
r[k] = v
}
for k, v := range s.Env {
r[k] = v
}
return r
}
func (s *StepsContext) GetEnvList() []string {
r := []string{}
for k, v := range s.GetEnvs() {
r = append(r, k+"="+v)
}
return r
}
......@@ -8,7 +8,6 @@ import (
"testing"
"gitlab.com/gitlab-org/step-runner/pkg/cache"
"gitlab.com/gitlab-org/step-runner/pkg/context"
"gitlab.com/gitlab-org/step-runner/pkg/step"
"github.com/stretchr/testify/require"
......@@ -47,7 +46,7 @@ func runTest(testCase runnerTest) func(*testing.T) {
var log bytes.Buffer
globalCtx, err := context.NewGlobal()
globalCtx, err := NewGlobalContext()
require.NoError(t, err)
defer globalCtx.Cleanup()
maps.Copy(globalCtx.Env, testCase.globalEnv)
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment