Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

enhance(compiler): add ruledata option to CompileLite #1076

Merged
merged 10 commits into from
Apr 5, 2024
58 changes: 55 additions & 3 deletions api/pipeline/compile.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,17 @@ package pipeline
import (
"fmt"
"net/http"
"strings"

"github.com/gin-gonic/gin"
"github.com/go-vela/server/compiler"
"github.com/go-vela/server/router/middleware/org"
"github.com/go-vela/server/router/middleware/pipeline"
pMiddleware "github.com/go-vela/server/router/middleware/pipeline"
"github.com/go-vela/server/router/middleware/repo"
"github.com/go-vela/server/router/middleware/user"
"github.com/go-vela/server/util"
"github.com/go-vela/types"
"github.com/go-vela/types/pipeline"
"github.com/sirupsen/logrus"
)

Expand Down Expand Up @@ -72,7 +74,7 @@ func CompilePipeline(c *gin.Context) {
// capture middleware values
m := c.MustGet("metadata").(*types.Metadata)
o := org.Retrieve(c)
p := pipeline.Retrieve(c)
p := pMiddleware.Retrieve(c)
r := repo.Retrieve(c)
u := user.Retrieve(c)

Expand All @@ -94,8 +96,10 @@ func CompilePipeline(c *gin.Context) {
// create the compiler object
compiler := compiler.FromContext(c).Duplicate().WithCommit(p.GetCommit()).WithMetadata(m).WithRepo(r).WithUser(u)

ruleData := prepareRuleData(c)

// compile the pipeline
pipeline, _, err := compiler.CompileLite(p.GetData(), true)
pipeline, _, err := compiler.CompileLite(p.GetData(), ruleData, true)
if err != nil {
retErr := fmt.Errorf("unable to compile pipeline %s: %w", entry, err)

Expand All @@ -106,3 +110,51 @@ func CompilePipeline(c *gin.Context) {

writeOutput(c, pipeline)
}

// prepareRuleData is a helper function to prepare the rule data from the query parameters.
func prepareRuleData(c *gin.Context) *pipeline.RuleData {
// capture the branch name parameter
branch := c.Query("branch")
// capture the comment parameter
comment := c.Query("comment")
// capture the event type parameter
event := c.Query("event")
// capture the repo parameter
ruleDataRepo := c.Query("repo")
// capture the status type parameter
status := c.Query("status")
// capture the tag parameter
tag := c.Query("tag")
// capture the target parameter
target := c.Query("target")

var pathSet []string
// capture the path parameter
path := c.Query("path")
if len(path) > 0 {
pathSet = strings.Split(path, ",")
}

// if any ruledata query params were provided, create ruledata struct
if len(branch) > 0 ||
len(comment) > 0 ||
len(event) > 0 ||
len(path) > 0 ||
len(ruleDataRepo) > 0 ||
len(status) > 0 ||
len(tag) > 0 ||
len(target) > 0 {
return &pipeline.RuleData{
Branch: branch,
Comment: comment,
Event: event,
Path: pathSet,
Repo: ruleDataRepo,
Status: status,
Tag: tag,
Target: target,
}
}

return nil
}
4 changes: 3 additions & 1 deletion api/pipeline/expand.go
Original file line number Diff line number Diff line change
Expand Up @@ -95,8 +95,10 @@ func ExpandPipeline(c *gin.Context) {
// create the compiler object
compiler := compiler.FromContext(c).Duplicate().WithCommit(p.GetCommit()).WithMetadata(m).WithRepo(r).WithUser(u)

ruleData := prepareRuleData(c)

// expand the templates in the pipeline
pipeline, _, err := compiler.CompileLite(p.GetData(), false)
pipeline, _, err := compiler.CompileLite(p.GetData(), ruleData, false)
if err != nil {
retErr := fmt.Errorf("unable to expand pipeline %s: %w", entry, err)

Expand Down
4 changes: 3 additions & 1 deletion api/pipeline/validate.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@

// ValidatePipeline represents the API handler to capture,
// expand and validate a pipeline configuration.
func ValidatePipeline(c *gin.Context) {

Check failure on line 70 in api/pipeline/validate.go

View workflow job for this annotation

GitHub Actions / golangci

[golangci] api/pipeline/validate.go#L70

70-109 lines are duplicate of `api/pipeline/compile.go:73-112` (dupl)
Raw output
api/pipeline/validate.go:70: 70-109 lines are duplicate of `api/pipeline/compile.go:73-112` (dupl)
func ValidatePipeline(c *gin.Context) {
	// capture middleware values
	m := c.MustGet("metadata").(*types.Metadata)
	o := org.Retrieve(c)
	p := pipeline.Retrieve(c)
	r := repo.Retrieve(c)
	u := user.Retrieve(c)

	entry := fmt.Sprintf("%s/%s", r.GetFullName(), p.GetCommit())

	// update engine logger with API metadata
	//
	// https://pkg.go.dev/github.com/sirupsen/logrus?tab=doc#Entry.WithFields
	logrus.WithFields(logrus.Fields{
		"org":      o,
		"pipeline": p.GetCommit(),
		"repo":     r.GetName(),
		"user":     u.GetName(),
	}).Infof("validating pipeline %s", entry)

	// ensure we use the expected pipeline type when compiling
	r.SetPipelineType(p.GetType())

	// create the compiler object
	compiler := compiler.FromContext(c).Duplicate().WithCommit(p.GetCommit()).WithMetadata(m).WithRepo(r).WithUser(u)

	ruleData := prepareRuleData(c)

	// validate the pipeline
	pipeline, _, err := compiler.CompileLite(p.GetData(), ruleData, false)
	if err != nil {
		retErr := fmt.Errorf("unable to validate pipeline %s: %w", entry, err)

		util.HandleError(c, http.StatusBadRequest, retErr)

		return
	}

	writeOutput(c, pipeline)
}
// capture middleware values
m := c.MustGet("metadata").(*types.Metadata)
o := org.Retrieve(c)
Expand All @@ -93,8 +93,10 @@
// create the compiler object
compiler := compiler.FromContext(c).Duplicate().WithCommit(p.GetCommit()).WithMetadata(m).WithRepo(r).WithUser(u)

ruleData := prepareRuleData(c)

// validate the pipeline
pipeline, _, err := compiler.CompileLite(p.GetData(), false)
pipeline, _, err := compiler.CompileLite(p.GetData(), ruleData, false)
if err != nil {
retErr := fmt.Errorf("unable to validate pipeline %s: %w", entry, err)

Expand Down
2 changes: 1 addition & 1 deletion compiler/engine.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ type Engine interface {
// CompileLite defines a function that produces an light executable
// representation of a pipeline from an object. This calls
// Parse internally to convert the object to a yaml configuration.
CompileLite(interface{}, bool) (*yaml.Build, *library.Pipeline, error)
CompileLite(interface{}, *pipeline.RuleData, bool) (*yaml.Build, *library.Pipeline, error)

// Duplicate defines a function that
// creates a clone of the Engine.
Expand Down
73 changes: 54 additions & 19 deletions compiler/native/compile.go
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@
}

// CompileLite produces a partial of an executable pipeline from a yaml configuration.
func (c *client) CompileLite(v interface{}, substitute bool) (*yaml.Build, *library.Pipeline, error) {
func (c *client) CompileLite(v interface{}, ruleData *pipeline.RuleData, substitute bool) (*yaml.Build, *library.Pipeline, error) {
p, data, err := c.Parse(v, c.repo.GetPipelineType(), new(yaml.Template))
if err != nil {
return nil, nil, err
Expand Down Expand Up @@ -125,36 +125,71 @@
// create map of templates for easy lookup
templates := mapFromTemplates(p.Templates)

if len(templates) > 0 {
switch {
case len(p.Stages) > 0:
// inject the templates into the steps
p, err = c.ExpandStages(p, templates, nil)
switch {
case len(p.Stages) > 0:
// inject the templates into the steps
p, err = c.ExpandStages(p, templates, ruleData)
if err != nil {
return nil, _pipeline, err
}

if substitute {
// inject the substituted environment variables into the steps
p.Stages, err = c.SubstituteStages(p.Stages)
if err != nil {
return nil, _pipeline, err
}
}

if ruleData != nil {
purgedStages := new(yaml.StageSlice)

if substitute {
// inject the substituted environment variables into the steps
p.Stages, err = c.SubstituteStages(p.Stages)
if err != nil {
return nil, _pipeline, err
for _, stg := range p.Stages {
purgedSteps := new(yaml.StepSlice)

for _, s := range stg.Steps {
cRuleset := s.Ruleset.ToPipeline()
if match, err := cRuleset.Match(ruleData); err == nil && match {
*purgedSteps = append(*purgedSteps, s)
}
}

stg.Steps = *purgedSteps

if len(stg.Steps) > 0 {
*purgedStages = append(*purgedStages, stg)
}
}
case len(p.Steps) > 0:
// inject the templates into the steps
p, err = c.ExpandSteps(p, templates, nil, c.TemplateDepth)

p.Stages = *purgedStages
}

case len(p.Steps) > 0:
// inject the templates into the steps
p, err = c.ExpandSteps(p, templates, ruleData, c.TemplateDepth)
if err != nil {
return nil, _pipeline, err
}

if substitute {
// inject the substituted environment variables into the steps
p.Steps, err = c.SubstituteSteps(p.Steps)
if err != nil {
return nil, _pipeline, err
}
}

if substitute {
// inject the substituted environment variables into the steps
p.Steps, err = c.SubstituteSteps(p.Steps)
if err != nil {
return nil, _pipeline, err
if ruleData != nil {
purgedSteps := new(yaml.StepSlice)

for _, s := range p.Steps {
cRuleset := s.Ruleset.ToPipeline()
if match, err := cRuleset.Match(ruleData); err == nil && match {
*purgedSteps = append(*purgedSteps, s)
}
}

p.Steps = *purgedSteps
}
}

Expand Down Expand Up @@ -264,7 +299,7 @@

// compileSteps executes the workflow for converting a YAML pipeline into an executable struct.
//
//nolint:dupl,lll // linter thinks the steps and stages workflows are identical

Check failure on line 302 in compiler/native/compile.go

View workflow job for this annotation

GitHub Actions / golangci

[golangci] compiler/native/compile.go#L302

directive `//nolint:dupl,lll // linter thinks the steps and stages workflows are identical` is unused for linter "dupl" (nolintlint)
Raw output
compiler/native/compile.go:302:1: directive `//nolint:dupl,lll // linter thinks the steps and stages workflows are identical` is unused for linter "dupl" (nolintlint)
//nolint:dupl,lll // linter thinks the steps and stages workflows are identical
^
func (c *client) compileSteps(p *yaml.Build, _pipeline *library.Pipeline, tmpls map[string]*yaml.Template, r *pipeline.RuleData) (*pipeline.Build, *library.Pipeline, error) {
var err error

Expand Down Expand Up @@ -361,7 +396,7 @@

// compileStages executes the workflow for converting a YAML pipeline into an executable struct.
//
//nolint:dupl,lll // linter thinks the steps and stages workflows are identical

Check failure on line 399 in compiler/native/compile.go

View workflow job for this annotation

GitHub Actions / golangci

[golangci] compiler/native/compile.go#L399

directive `//nolint:dupl,lll // linter thinks the steps and stages workflows are identical` is unused for linter "dupl" (nolintlint)
Raw output
compiler/native/compile.go:399:1: directive `//nolint:dupl,lll // linter thinks the steps and stages workflows are identical` is unused for linter "dupl" (nolintlint)
//nolint:dupl,lll // linter thinks the steps and stages workflows are identical
^
func (c *client) compileStages(p *yaml.Build, _pipeline *library.Pipeline, tmpls map[string]*yaml.Template, r *pipeline.RuleData) (*pipeline.Build, *library.Pipeline, error) {
var err error

Expand Down
Loading
Loading