Skip to content
Merged
Show file tree
Hide file tree
Changes from 23 commits
Commits
Show all changes
56 commits
Select commit Hold shift + click to select a range
9186ca1
feat(database): add support for pipelines
jbrockopp Jan 19, 2022
e9e05bd
chore: update copyright year to 2022
jbrockopp Jan 19, 2022
0a28d42
chore: cleanup comments and imports
jbrockopp Jan 19, 2022
1ab6afe
enhance(pipeline): add fields for secrets
jbrockopp Jan 21, 2022
57e5162
Merge branch 'master' of github.com:go-vela/server
jbrockopp Feb 23, 2022
5366bb3
chore: update go-vela/types dependency
jbrockopp Feb 25, 2022
e07e7bc
enhance(pipeline): add field for commit
jbrockopp Mar 7, 2022
66d626f
Merge branch 'master' into feature/database/pipeline
jbrockopp Mar 7, 2022
b6b840c
Merge branch 'master' of github.com:go-vela/server
jbrockopp Mar 10, 2022
858c818
Merge branch 'master' of github.com:go-vela/server
jbrockopp Mar 16, 2022
6f314e4
Merge branch 'master' into feature/database/pipeline
jbrockopp Mar 16, 2022
7b688cb
Merge branch 'feature/database/pipeline' of github.com:go-vela/server…
jbrockopp Mar 16, 2022
9a14f8c
chore: fix tests
jbrockopp Mar 17, 2022
c2fed8f
feat: add pipeline engine opts
jbrockopp Mar 17, 2022
b4589f8
refactor: structure for creating pipeline engine
jbrockopp Mar 17, 2022
35b52b6
chore: finalize pipeline engine setup
jbrockopp Mar 17, 2022
4a8f272
chore: clean up pipeline database engine
jbrockopp Mar 17, 2022
1195c76
chore: clean up imports
jbrockopp Mar 17, 2022
740e5e0
Merge branch 'feature/database/pipeline' of github.com:go-vela/server…
jbrockopp Mar 18, 2022
0ec78e3
feat(compiler): add support for pipelines
jbrockopp Mar 18, 2022
c763621
feat(api): add support for pipelines
jbrockopp Mar 18, 2022
3958114
Merge branch 'master' into feature/api/pipeline
jbrockopp Mar 18, 2022
4b5bc54
Merge branch 'master' into feature/api/pipeline
jbrockopp Mar 20, 2022
d6fe4f7
Merge branch 'feature/api/pipeline' of github.com:go-vela/server into…
jbrockopp Mar 20, 2022
29888a6
chore: address linter feedback
jbrockopp Mar 20, 2022
ceddb11
Merge branch 'master' of github.com:go-vela/server
jbrockopp Mar 28, 2022
b90e443
Merge branch 'master' into feature/api/pipeline
jbrockopp Mar 31, 2022
cb1ac35
Merge branch 'master' into feature/api/pipeline
jbrockopp Apr 11, 2022
331b2a2
Merge branch 'master' of github.com:go-vela/server
jbrockopp Apr 11, 2022
dc6c732
Merge branch 'feature/api/pipeline' of github.com:go-vela/server into…
jbrockopp Apr 11, 2022
9ee0017
chore: remove unused code
jbrockopp Apr 11, 2022
a6997a8
chore: update go-vela/types dependency
jbrockopp Apr 11, 2022
133439e
Merge branch 'master' into feature/api/pipeline
jbrockopp Apr 12, 2022
45f7fd1
Merge branch 'feature/api/pipeline' of github.com:go-vela/server into…
jbrockopp Apr 12, 2022
9c1825e
enhance: use pipeline commit instead of number
jbrockopp Apr 13, 2022
8a66a15
Merge branch 'master' into feature/api/pipeline
jbrockopp Apr 18, 2022
f858ecd
Merge branch 'feature/api/pipeline' of github.com:go-vela/server into…
jbrockopp Apr 18, 2022
be6c877
chore: remove pipeline number
jbrockopp Apr 18, 2022
c4ec5fb
Merge branches 'master' and 'master' of github.com:go-vela/server
jbrockopp Apr 18, 2022
b3423d4
chore: remove number field from pipelines
jbrockopp Apr 18, 2022
edbc030
Merge branch 'chore/pipeline/number' of github.com:go-vela/server int…
jbrockopp Apr 18, 2022
f8eb267
Merge branch 'master' into feature/api/pipeline
jbrockopp Apr 19, 2022
bfbc27f
Merge branch 'feature/api/pipeline' of github.com:go-vela/server into…
jbrockopp Apr 19, 2022
782c15f
Merge branch 'master' into feature/api/pipeline
jbrockopp Apr 20, 2022
0ef35b5
Merge branch 'feature/api/pipeline' of github.com:go-vela/server into…
jbrockopp Apr 20, 2022
a794666
fix: merge with master
jbrockopp Apr 20, 2022
159df8e
chore: clean go dependencies
jbrockopp Apr 20, 2022
760ed7c
fix(pipeline): update mocks for API changes
jbrockopp Apr 21, 2022
d973677
Merge branch 'master' into feature/api/pipeline
jbrockopp Apr 21, 2022
33d0d03
Merge branch 'master' into feature/api/pipeline
jbrockopp Apr 22, 2022
1183bd4
Merge branch 'feature/api/pipeline' of github.com:go-vela/server into…
jbrockopp Apr 22, 2022
2e147f7
chore: fix go formatting
jbrockopp Apr 22, 2022
256369e
chore: address linter feedback
jbrockopp Apr 22, 2022
c17860d
fix: mock changes for pipelines
jbrockopp Apr 22, 2022
7050468
chore: address review feedback
jbrockopp Apr 26, 2022
da3142e
enhance: add permissions to pipeline endpoints
jbrockopp Apr 26, 2022
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
191 changes: 160 additions & 31 deletions api/build.go
Original file line number Diff line number Diff line change
Expand Up @@ -242,7 +242,7 @@ func CreateBuild(c *gin.Context) {
}

// parse and compile the pipeline configuration file
p, err := compiler.FromContext(c).
p, pipeline, err := compiler.FromContext(c).
WithBuild(input).
WithFiles(files).
WithMetadata(m).
Expand Down Expand Up @@ -274,6 +274,48 @@ func CreateBuild(c *gin.Context) {
return
}

// send API call to capture the last pipeline for the repo
lastPipeline, err := database.FromContext(c).LastPipelineForRepo(r)
if err != nil {
retErr := fmt.Errorf("unable to get last pipeline for %s: %w", r.GetFullName(), err)

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

return
}

pipeline.SetRepoID(r.GetID())
pipeline.SetNumber(1)
pipeline.SetCommit(input.GetCommit())
pipeline.SetRef(input.GetRef())

if lastPipeline != nil {
pipeline.SetNumber(lastPipeline.GetNumber() + 1)
}

// send API call to create the pipeline
err = database.FromContext(c).CreatePipeline(pipeline)
if err != nil {
retErr := fmt.Errorf("%s: failed to create pipeline for %s: %v", baseErr, r.GetFullName(), err)

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

return
}

// send API call to capture the created pipeline
pipeline, err = database.FromContext(c).GetPipelineForRepo(pipeline.GetNumber(), r)
if err != nil {
// nolint: lll // ignore long line length due to error message
retErr := fmt.Errorf("%s: failed to get new pipeline %s/%d: %v", baseErr, r.GetFullName(), pipeline.GetNumber(), err)

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

return
}

input.SetPipelineID(pipeline.GetID())

// create the objects from the pipeline in the database
err = planBuild(database.FromContext(c), p, input, r)
if err != nil {
Expand Down Expand Up @@ -978,47 +1020,134 @@ func RestartBuild(c *gin.Context) {
}
}

// send API call to capture the pipeline configuration file
config, err := scm.FromContext(c).ConfigBackoff(u, r, b.GetCommit())
if err != nil {
retErr := fmt.Errorf("unable to get pipeline configuration for %s: %w", entry, err)
// variables to store pipeline configuration
var (
// variable to store executable pipeline
p *pipeline.Build
// variable to store pipeline configuration
pipeline *library.Pipeline
)

util.HandleError(c, http.StatusNotFound, retErr)
// check if the build was created after pipeline support was added
if b.GetPipelineID() > 0 {
// send API call to capture the pipeline
pipeline, err = database.FromContext(c).GetPipeline(b.GetPipelineID())
if err != nil {
retErr := fmt.Errorf("unable to get pipeline for %s: %w", entry, err)

return
}
util.HandleError(c, http.StatusNotFound, retErr)

// parse and compile the pipeline configuration file
p, err := compiler.FromContext(c).
WithBuild(b).
WithFiles(files).
WithMetadata(m).
WithRepo(r).
WithUser(u).
Compile(config)
if err != nil {
retErr := fmt.Errorf("unable to compile pipeline configuration for %s: %w", entry, err)
return
}

util.HandleError(c, http.StatusInternalServerError, retErr)
// capture the original pipeline type for the repo
originalType := r.GetPipelineType()
// ensure we use the expected pipeline type when compiling
r.SetPipelineType(pipeline.GetType())

// parse and compile the pipeline
p, _, err = compiler.FromContext(c).
WithBuild(b).
WithFiles(files).
WithMetadata(m).
WithRepo(r).
WithUser(u).
Compile(pipeline.GetData())
if err != nil {
retErr := fmt.Errorf("unable to compile pipeline configuration for %s: %w", entry, err)

return
}
util.HandleError(c, http.StatusInternalServerError, retErr)

// skip the build if only the init or clone steps are found
skip := skipEmptyBuild(p)
if skip != "" {
// set build to successful status
b.SetStatus(constants.StatusSkipped)
return
}

// send API call to set the status on the commit
err = scm.FromContext(c).Status(u, b, r.GetOrg(), r.GetName())
// reset the pipeline type for the repo
r.SetPipelineType(originalType)
} else { // keep original behavior for builds ran before pipeline support was added
// send API call to capture the pipeline configuration file
config, err := scm.FromContext(c).ConfigBackoff(u, r, b.GetCommit())
if err != nil {
logger.Errorf("unable to set commit status for %s: %v", entry, err)
retErr := fmt.Errorf("unable to get pipeline configuration for %s: %w", entry, err)

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

return
}

c.JSON(http.StatusOK, skip)
// parse and compile the pipeline configuration file
p, pipeline, err = compiler.FromContext(c).
WithBuild(b).
WithFiles(files).
WithMetadata(m).
WithRepo(r).
WithUser(u).
Compile(config)
if err != nil {
retErr := fmt.Errorf("unable to compile pipeline configuration for %s: %w", entry, err)

return
util.HandleError(c, http.StatusInternalServerError, retErr)

return
}

// skip the build if only the init or clone steps are found
skip := skipEmptyBuild(p)
if skip != "" {
// set build to successful status
b.SetStatus(constants.StatusSkipped)

// send API call to set the status on the commit
err = scm.FromContext(c).Status(u, b, r.GetOrg(), r.GetName())
if err != nil {
logrus.Errorf("unable to set commit status for %s/%d: %v", r.GetFullName(), b.GetNumber(), err)
}

c.JSON(http.StatusOK, skip)

return
}

// send API call to capture the last pipeline for the repo
lastPipeline, err := database.FromContext(c).LastPipelineForRepo(r)
if err != nil {
retErr := fmt.Errorf("unable to get last pipeline for %s: %w", r.GetFullName(), err)

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

return
}

pipeline.SetRepoID(r.GetID())
pipeline.SetNumber(1)
pipeline.SetCommit(b.GetCommit())
pipeline.SetRef(b.GetRef())

if lastPipeline != nil {
pipeline.SetNumber(lastPipeline.GetNumber() + 1)
}

// send API call to create the pipeline
err = database.FromContext(c).CreatePipeline(pipeline)
if err != nil {
retErr := fmt.Errorf("%s: failed to create pipeline for %s: %v", baseErr, r.GetFullName(), err)

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

return
}

// send API call to capture the created pipeline
pipeline, err = database.FromContext(c).GetPipelineForRepo(pipeline.GetNumber(), r)
if err != nil {
// nolint: lll // ignore long line length due to error message
retErr := fmt.Errorf("%s: failed to get new pipeline %s/%d: %v", baseErr, r.GetFullName(), pipeline.GetNumber(), err)

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

return
}

b.SetPipelineID(pipeline.GetID())
}

// create the objects from the pipeline in the database
Expand Down
10 changes: 5 additions & 5 deletions api/pipeline.go
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ func GetPipeline(ctx *gin.Context) {
return
}

pipeline, err := comp.Parse(config, r.GetPipelineType(), map[string]interface{}{})
pipeline, _, err := comp.Parse(config, r.GetPipelineType(), map[string]interface{}{})
if err != nil {
retErr := fmt.Errorf("unable to validate pipeline configuration for %s: %w", repoName(ctx), err)
util.HandleError(ctx, http.StatusBadRequest, retErr)
Expand Down Expand Up @@ -175,7 +175,7 @@ func GetTemplates(ctx *gin.Context) {
return
}

pipeline, err := comp.Parse(config, r.GetPipelineType(), map[string]interface{}{})
pipeline, _, err := comp.Parse(config, r.GetPipelineType(), map[string]interface{}{})
if err != nil {
retErr := fmt.Errorf("unable to validate pipeline configuration for %s: %w", repoName(ctx), err)
util.HandleError(ctx, http.StatusBadRequest, retErr)
Expand Down Expand Up @@ -265,7 +265,7 @@ func ExpandPipeline(ctx *gin.Context) {
return
}

pipeline, err := comp.CompileLite(config, true, false, nil)
pipeline, _, err := comp.CompileLite(config, true, false, nil)
if err != nil {
retErr := fmt.Errorf("unable to validate pipeline configuration for %s: %w", repoName(ctx), err)
util.HandleError(ctx, http.StatusBadRequest, retErr)
Expand Down Expand Up @@ -349,7 +349,7 @@ func ValidatePipeline(ctx *gin.Context) {
template = true
}

pipeline, err := comp.CompileLite(config, template, false, nil)
pipeline, _, err := comp.CompileLite(config, template, false, nil)
if err != nil {
retErr := fmt.Errorf("unable to validate pipeline configuration for %s: %w", repoName(ctx), err)
util.HandleError(ctx, http.StatusBadRequest, retErr)
Expand Down Expand Up @@ -428,7 +428,7 @@ func CompilePipeline(ctx *gin.Context) {
return
}

pipeline, err := comp.CompileLite(config, true, true, nil)
pipeline, _, err := comp.CompileLite(config, true, true, nil)
if err != nil {
retErr := fmt.Errorf("unable to validate pipeline configuration for %s: %w", repoName(ctx), err)
util.HandleError(ctx, http.StatusBadRequest, retErr)
Expand Down
105 changes: 105 additions & 0 deletions api/pipeline/compile.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
// Copyright (c) 2022 Target Brands, Inc. All rights reserved.
//
// Use of this source code is governed by the LICENSE file in this repository.

// nolint: dupl // ignore similar code with expand
package pipeline

import (
"fmt"
"net/http"

"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"
"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/sirupsen/logrus"
)

// swagger:operation POST /api/v1/pipelines/{org}/{repo}/{pipeline}/compile pipelines CompilePipeline
//
// Get, expand and compile a pipeline configuration from the database
//
// ---
// produces:
// - application/x-yaml
// - application/json
// parameters:
// - in: path
// name: repo
// description: Name of the repo
// required: true
// type: string
// - in: path
// name: org
// description: Name of the org
// required: true
// type: string
// - in: query
// name: ref
// description: Ref for retrieving pipeline configuration file
// type: string
// - in: query
// name: output
// description: Output string for specifying output format
// type: string
// security:
// - ApiKeyAuth: []
// responses:
// '200':
// description: Successfully retrieved and compiled the pipeline
// schema:
// "$ref": "#/definitions/PipelineBuild"
// '400':
// description: Unable to validate the pipeline configuration
// schema:
// "$ref": "#/definitions/Error"
// '404':
// description: Unable to retrieve the pipeline configuration
// schema:
// "$ref": "#/definitions/Error"

// CompilePipeline represents the API handler to capture,
// expand and compile a pipeline configuration.
func CompilePipeline(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/%d", r.GetFullName(), p.GetNumber())

// 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.GetNumber(),
"repo": r.GetName(),
"user": u.GetName(),
}).Infof("compiling pipeline %s", entry)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

with the given fields, the contents of %s don't provide any new information. should we drop it?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We certainly could 👍 I'm leaning towards leaving it in there since it doesn't hurt.

This pattern is adopted from existing log entires we already established for other API endpoints.

So if we did want to switch this up, I think we'd have to go back and apply the same changes for consistency.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fair point, I'd vote for removing it maybe in another PR. Seems like a waste of bytes that can add up - then again, this is more compact than logging as separate JSON fields :disappear:

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah I see where you're coming from on that 👍

To me, the message for the log entry is designed for human processing

i.e. user who manually reviews the log entries or using a tool such as grep or awk

In those scenarios, it can add a bit of complexity when trying to search for multiple fields but not impossible:

# searching for specific message
cat log.txt | grep '<org>/<repo>/<commit>'

# searching for specific fields
cat log.txt | grep '"org": <org>' | grep '"repo": <repo>' | grep '"pipeline": <commit>'

While the fields for the log entry are designed for system processing

i.e. most apps/tools consuming logs enable filtering on one or more fields which improves this experience

However, if folks feel strongly enough about it, then I could get behind shortening the message


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

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

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

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

return
}

writeOutput(c, pipeline)
}
Loading