Skip to content

Commit

Permalink
feat: add stripansi function, store outputs in this.output
Browse files Browse the repository at this point in the history
  • Loading branch information
srevinsaju committed Nov 1, 2023
1 parent 79351bf commit f4aef85
Show file tree
Hide file tree
Showing 10 changed files with 91 additions and 19 deletions.
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ require (
code.gitea.io/gitea v1.19.3
github.com/AlecAivazis/survey/v2 v2.3.6
github.com/Netflix/go-expect v0.0.0-20220104043353-73e0943537d2
github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d
github.com/alessio/shellescape v1.4.1
github.com/bcicen/jstream v1.0.1
github.com/bmatcuk/doublestar v1.1.5
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,8 @@ github.com/Netflix/go-expect v0.0.0-20220104043353-73e0943537d2/go.mod h1:HBCaDe
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
github.com/ProtonMail/go-crypto v0.0.0-20230717121422-5aa5874ade95 h1:KLq8BE0KwCL+mmXnjLWEAOYO+2l2AE4YMmqG1ZpZHBs=
github.com/ProtonMail/go-crypto v0.0.0-20230717121422-5aa5874ade95/go.mod h1:EjAoLdwvbIOoOQr3ihjnSoLZRtE8azugULFRteWMNc0=
github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d h1:licZJFw2RwpHMqeKTCYkitsPqHNxTmd4SNR5r94FGM8=
github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d/go.mod h1:asat636LX7Bqt5lYEZ27JNDcqxfjdBQuJ/MM4CN/Lzo=
github.com/acomagu/bufpipe v1.0.4 h1:e3H4WUzM3npvo5uv95QuJM3cQspFNtFBzvJ2oNjKIDQ=
github.com/acomagu/bufpipe v1.0.4/go.mod h1:mxdxdup/WdsKVreO5GpW4+M/1CE2sMG4jeGJ2sYmHc4=
github.com/agext/levenshtein v1.2.3 h1:YB2fHEn0UJagG8T1rrWknE3ZQzWM06O8AMAatNn7lmo=
Expand Down
29 changes: 29 additions & 0 deletions internal/ci/conductor.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package ci

import (
"bytes"
"context"
"github.com/google/uuid"
"github.com/hashicorp/hcl/v2"
Expand Down Expand Up @@ -108,6 +109,34 @@ type Conductor struct {
parent *Conductor

variables Variables

outputsMu sync.Mutex
outputs map[string]*bytes.Buffer
}

func (c *Conductor) Outputs() map[string]*bytes.Buffer {
c.outputsMu.Lock()
defer c.outputsMu.Unlock()
return c.outputs

Check warning on line 120 in internal/ci/conductor.go

View check run for this annotation

Codecov / codecov/patch

internal/ci/conductor.go#L117-L120

Added lines #L117 - L120 were not covered by tests
}

func (c *Conductor) OutputMemoryStream(name string) *bytes.Buffer {
c.outputsMu.Lock()
defer c.outputsMu.Unlock()
if c.outputs == nil {
c.outputs = make(map[string]*bytes.Buffer)
}
return c.outputs[name]

Check warning on line 129 in internal/ci/conductor.go

View check run for this annotation

Codecov / codecov/patch

internal/ci/conductor.go#L123-L129

Added lines #L123 - L129 were not covered by tests
}

func (c *Conductor) NewOutputMemoryStream(name string) *bytes.Buffer {
c.outputsMu.Lock()
defer c.outputsMu.Unlock()
if c.outputs == nil {
c.outputs = make(map[string]*bytes.Buffer)
}
c.outputs[name] = bytes.NewBuffer(nil)
return c.outputs[name]
}

type Parser struct {
Expand Down
2 changes: 2 additions & 0 deletions internal/ci/conductor_hcl.go
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,8 @@ func CreateEvalContext(cfg ConductorConfig, process Process) *hcl.EvalContext {
"yamlencode": yaml.YAMLEncodeFunc,
"zipmap": stdlib.ZipmapFunc,

"stripansi": ui.StripAnsiFunc,

"ansifmt": ui.AnsiFunc,
"env": function.New(&function.Spec{
Params: []function.Parameter{
Expand Down
2 changes: 1 addition & 1 deletion internal/ci/stage_hooks.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ func (s *Stage) AfterRun(conductor *Conductor, opts ...runnable.Option) hcl.Diag

for _, hook := range s.PostHook {
diags = diags.Extend(
(&Stage{fmt.Sprintf("%s.pre", s.Id), nil, hook.Stage, nil}).Run(conductor, opts...),
(&Stage{fmt.Sprintf("%s.post", s.Id), nil, hook.Stage, nil}).Run(conductor, opts...),
)
}
return diags
Expand Down
10 changes: 9 additions & 1 deletion internal/ci/stage_prop.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
package ci

import "github.com/hashicorp/hcl/v2"
import (
"github.com/hashicorp/hcl/v2"
"github.com/srevinsaju/togomak/v1/internal/blocks"
"github.com/srevinsaju/togomak/v1/internal/x"
)

func (s *Stage) Override() bool {
return false
Expand All @@ -27,3 +31,7 @@ func (s Stages) CheckIfDistinct(ss Stages) hcl.Diagnostics {
}
return diags
}

func (s *Stage) String() string {
return x.RenderBlock(blocks.StageBlock, s.Id)
}
41 changes: 24 additions & 17 deletions internal/ci/stage_run.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package ci

import (
"bytes"
"context"
"errors"
"fmt"
Expand Down Expand Up @@ -411,14 +412,16 @@ func (s *Stage) Run(conductor *Conductor, options ...runnable.Option) (diags hcl

}

func (s *Stage) run(conductor *Conductor, evalCtx *hcl.EvalContext, options ...runnable.Option) (diags hcl.Diagnostics) {
func (s *Stage) run(conductor *Conductor, evalCtx *hcl.EvalContext, options ...runnable.Option) hcl.Diagnostics {
var err error
logger := conductor.Logger().WithField("stage", s.Id)
tmpDir := conductor.TempDir()
status := runnable.StatusRunning
cfg := runnable.NewConfig(options...)
stream := conductor.NewOutputMemoryStream(s.String())
diags := &dg.Diagnostics{}

defer func() {
defer func(stream *bytes.Buffer) {
logger.Debug("running post hooks")
success := !diags.HasErrors()
if !success {
Expand All @@ -429,15 +432,16 @@ func (s *Stage) run(conductor *Conductor, evalCtx *hcl.EvalContext, options ...r
hookOpts := []runnable.Option{
runnable.WithStatus(status),
runnable.WithHook(),
runnable.WithStatusOutput(stream.String()),
runnable.WithParent(runnable.ParentConfig{Name: s.Name, Id: s.Id}),
}
hookOpts = append(hookOpts, options...)
diags = diags.Extend(s.AfterRun(conductor, hookOpts...))
diags.Extend(s.AfterRun(conductor, hookOpts...))
logger.Debug("finished running post hooks")
}()
}(stream)

d := s.executePreHooks(conductor, status, options...)
diags = diags.Extend(d)
diags.Extend(d)

paramsGo := map[string]cty.Value{}

Expand Down Expand Up @@ -468,6 +472,7 @@ func (s *Stage) run(conductor *Conductor, evalCtx *hcl.EvalContext, options ...r
"id": cty.StringVal(id),
"hook": cty.BoolVal(cfg.Hook),
"status": cty.StringVal(string(cfg.Status.Status)),
"output": cty.StringVal(cfg.Status.Output),
}),
}
if cfg.Each != nil {
Expand All @@ -479,7 +484,7 @@ func (s *Stage) run(conductor *Conductor, evalCtx *hcl.EvalContext, options ...r
conductor.Eval().Mutex().RLock()
parameters, d := s.Use.Parameters.Value(evalCtx)
conductor.Eval().Mutex().RUnlock()
diags = diags.Extend(d)
diags.Extend(d)
if !parameters.IsNull() {
for k, v := range parameters.AsValueMap() {
paramsGo[k] = v
Expand All @@ -489,17 +494,17 @@ func (s *Stage) run(conductor *Conductor, evalCtx *hcl.EvalContext, options ...r
evalCtx.Variables[blocks.ParamBlock] = cty.ObjectVal(paramsGo)

environment, d := s.parseEnvironmentVariables(conductor, evalCtx)
diags = diags.Extend(d)
diags.Extend(d)
if diags.HasErrors() {
return diags
return diags.Diagnostics()

Check warning on line 499 in internal/ci/stage_run.go

View check run for this annotation

Codecov / codecov/patch

internal/ci/stage_run.go#L499

Added line #L499 was not covered by tests
}

envStrings := s.processEnvironmentVariables(conductor, environment, cfg, tmpDir, paramsGo)

cmd, d := s.parseExecCommand(conductor, evalCtx, cfg, envStrings)
diags = diags.Extend(d)
cmd, d := s.parseExecCommand(conductor, evalCtx, cfg, envStrings, stream)
diags.Extend(d)
if diags.HasErrors() {
return diags
return diags.Diagnostics()

Check warning on line 507 in internal/ci/stage_run.go

View check run for this annotation

Codecov / codecov/patch

internal/ci/stage_run.go#L507

Added line #L507 was not covered by tests
}
logger.Trace("command parsed")
logger.Tracef("script: %.30s... ", cmd.String())
Expand All @@ -519,23 +524,24 @@ func (s *Stage) run(conductor *Conductor, evalCtx *hcl.EvalContext, options ...r
}
} else {
d := s.executeDocker(conductor, evalCtx, cmd, cfg)
diags = diags.Extend(d)
diags.Extend(d)
}

if err != nil {
diags = diags.Append(&hcl.Diagnostic{
diags.Append(&hcl.Diagnostic{

Check warning on line 531 in internal/ci/stage_run.go

View check run for this annotation

Codecov / codecov/patch

internal/ci/stage_run.go#L531

Added line #L531 was not covered by tests
Severity: hcl.DiagError,
Summary: fmt.Sprintf("failed to run command (%s)", s.Identifier()),
Detail: err.Error(),
})
}

return diags
return diags.Diagnostics()
}

func (s *Stage) executeDocker(conductor *Conductor, evalCtx *hcl.EvalContext, cmd *exec.Cmd, cfg *runnable.Config) hcl.Diagnostics {
var diags hcl.Diagnostics
logger := conductor.Logger().WithField("stage", s.Id)

ctx := conductor.Context()

image, d := s.hclImage(conductor, evalCtx)
Expand Down Expand Up @@ -763,7 +769,7 @@ func (s *Stage) parseEnvironmentVariables(conductor *Conductor, evalCtx *hcl.Eva
return environment, diags
}

func (s *Stage) parseExecCommand(conductor *Conductor, evalCtx *hcl.EvalContext, cfg *runnable.Config, envStrings []string) (*exec.Cmd, hcl.Diagnostics) {
func (s *Stage) parseExecCommand(conductor *Conductor, evalCtx *hcl.EvalContext, cfg *runnable.Config, envStrings []string, outputBuffer io.Writer) (*exec.Cmd, hcl.Diagnostics) {
var diags hcl.Diagnostics
logger := conductor.Logger().WithField("stage", s.Id)

Expand Down Expand Up @@ -827,8 +833,8 @@ func (s *Stage) parseExecCommand(conductor *Conductor, evalCtx *hcl.EvalContext,
}

cmd := exec.CommandContext(conductor.Context(), cmdHcl.command, cmdHcl.args...)
cmd.Stdout = logger.Writer()
cmd.Stderr = logger.WriterLevel(logrus.WarnLevel)
cmd.Stdout = io.MultiWriter(logger.Writer(), outputBuffer)
cmd.Stderr = io.MultiWriter(logger.Writer(), outputBuffer)
cmd.Env = append(os.Environ(), envStrings...)
cmd.Dir = dir
return cmd, diags
Expand Down Expand Up @@ -1011,6 +1017,7 @@ func (s *Stage) CanRun(conductor *Conductor, options ...runnable.Option) (ok boo
"id": cty.StringVal(id),
"hook": cty.BoolVal(cfg.Hook),
"status": cty.StringVal(string(cfg.Status.Status)),
"output": cty.StringVal(cfg.Status.Output),
}),
"param": cty.ObjectVal(paramsGo),
}
Expand Down
6 changes: 6 additions & 0 deletions internal/runnable/options.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,12 @@ func WithStatus(status StatusType) Option {
}
}

func WithStatusOutput(artifact string) Option {
return func(c *Config) {
c.Status.Output = artifact
}
}

func WithPaths(paths *path.Path) Option {
return func(c *Config) {
c.Paths = paths
Expand Down
2 changes: 2 additions & 0 deletions internal/runnable/status.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,4 +23,6 @@ type Status struct {

// Status is the status of the runnable
Status StatusType

Output string
}
15 changes: 15 additions & 0 deletions internal/ui/colors.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package ui

import (
"fmt"
"github.com/acarl005/stripansi"
"github.com/fatih/color"
"github.com/zclconf/go-cty/cty"
"github.com/zclconf/go-cty/cty/function"
Expand Down Expand Up @@ -61,6 +62,20 @@ var AnsiFunc = function.New(&function.Spec{
},
})

var StripAnsiFunc = function.New(&function.Spec{
Params: []function.Parameter{
{
Name: "message",
Type: cty.String,
},
},
Type: function.StaticReturnType(cty.String),
Impl: func(args []cty.Value, retType cty.Type) (cty.Value, error) {
message := args[0].AsString()
return cty.StringVal(stripansi.Strip(message)), nil
},

Check warning on line 76 in internal/ui/colors.go

View check run for this annotation

Codecov / codecov/patch

internal/ui/colors.go#L73-L76

Added lines #L73 - L76 were not covered by tests
})

func Color(color string, message string) string {
switch color {
case "green":
Expand Down

0 comments on commit f4aef85

Please sign in to comment.