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

feat: add types, fix errors, add conditional status report #1071

Closed
wants to merge 6 commits into from
Closed
Show file tree
Hide file tree
Changes from 7 commits
Commits
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
13 changes: 13 additions & 0 deletions .github/renovate.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,18 @@
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
"extends": [
"local>go-vela/renovate-config"
],
"regexManagers": [
{
"description": "Update docker images in go files",
"fileMatch": [
"^.*\\.go$"
],
"matchStrings": [
"\\/\\/ renovate: image=(?<depName>.*?)\\s+?.*[:|=]\\s+\"(?<currentValue>.*)\"\\,?"
],
"versioningTemplate": "docker",
"datasourceTemplate": "docker"
}
]
}
14 changes: 12 additions & 2 deletions api/build/approve.go
Original file line number Diff line number Diff line change
Expand Up @@ -86,17 +86,26 @@ func ApproveBuild(c *gin.Context) {
"user": u.GetName(),
})

// verify build is in correct status
if !strings.EqualFold(b.GetStatus(), constants.StatusPendingApproval) {
retErr := fmt.Errorf("unable to approve build %s/%d: build not in pending approval state", r.GetFullName(), b.GetNumber())
util.HandleError(c, http.StatusBadRequest, retErr)

return
}

// verify user is not the sender of the build
if strings.EqualFold(u.GetName(), b.GetSender()) {
retErr := fmt.Errorf("unable to approve build %s/%d: approver cannot be the sender of the build", r.GetFullName(), b.GetNumber())
util.HandleError(c, http.StatusBadRequest, retErr)

return
}

logger.Debugf("user %s approved build %s/%d for execution", u.GetName(), r.GetFullName(), b.GetNumber())

// send API call to capture the repo owner
u, err := database.FromContext(c).GetUser(ctx, r.GetUserID())
owner, err := database.FromContext(c).GetUser(ctx, r.GetUserID())
if err != nil {
retErr := fmt.Errorf("unable to get owner for %s: %w", r.GetFullName(), err)

Expand All @@ -105,6 +114,7 @@ func ApproveBuild(c *gin.Context) {
return
}

// set fields
b.SetStatus(constants.StatusPending)
b.SetApprovedAt(time.Now().Unix())
b.SetApprovedBy(u.GetName())
Expand All @@ -122,7 +132,7 @@ func ApproveBuild(c *gin.Context) {
database.FromContext(c),
b,
r,
u,
owner,
b.GetHost(),
)

Expand Down
2 changes: 1 addition & 1 deletion api/build/create.go
Original file line number Diff line number Diff line change
Expand Up @@ -320,7 +320,7 @@ func CreateBuild(c *gin.Context) {
input.SetPipelineID(pipeline.GetID())

// create the objects from the pipeline in the database
err = PlanBuild(ctx, database.FromContext(c), p, input, r)
err = PlanBuild(ctx, database.FromContext(c), scm.FromContext(c), p, input, r)
if err != nil {
util.HandleError(c, http.StatusInternalServerError, err)

Expand Down
2 changes: 1 addition & 1 deletion api/build/restart.go
Original file line number Diff line number Diff line change
Expand Up @@ -319,7 +319,7 @@ func RestartBuild(c *gin.Context) {
b.SetPipelineID(pipeline.GetID())

// create the objects from the pipeline in the database
err = PlanBuild(ctx, database.FromContext(c), p, b, r)
err = PlanBuild(ctx, database.FromContext(c), scm.FromContext(c), p, b, r)
if err != nil {
util.HandleError(c, http.StatusInternalServerError, err)

Expand Down
17 changes: 9 additions & 8 deletions api/step/plan.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ func PlanSteps(ctx context.Context, database database.Interface, scm scm.Service

// iterate through all pipeline steps
for _, step := range p.Steps {
s, err := planStep(ctx, database, b, step, "")
s, err := planStep(ctx, database, scm, b, r, step, "")
if err != nil {
return steps, err
}
Expand All @@ -61,14 +61,15 @@ func planStep(ctx context.Context, database database.Interface, scm scm.Service,
s.SetStatus(constants.StatusPending)
s.SetCreated(time.Now().UTC().Unix())

id, err := scm.CreateChecks(ctx, r, b.GetCommit(), s.GetName())
if err != nil {
// TODO: make this error more meaningful
return nil, err
}
if c.ReportStatus {
id, err := scm.CreateChecks(ctx, r, b.GetCommit(), s.GetName(), b.GetEvent())
if err != nil {
// TODO: make this error more meaningful
return nil, err
}

// TODO: have to store the check ID somewhere
s.SetCheckID(id)
s.SetCheckID(id)
}

// send API call to create the step
s, err := database.CreateStep(ctx, s)
Expand Down
14 changes: 9 additions & 5 deletions api/step/update.go
Original file line number Diff line number Diff line change
Expand Up @@ -157,13 +157,17 @@ func UpdateStep(c *gin.Context) {
return
}

err = scm.FromContext(c).UpdateChecks(ctx, r, s, b.GetCommit())
if err != nil {
retErr := fmt.Errorf("unable to set step check %s: %w", entry, err)
if s.GetCheckID() != 0 {
s.SetReport(input.GetReport())

util.HandleError(c, http.StatusInternalServerError, retErr)
err = scm.FromContext(c).UpdateChecks(ctx, r, s, b.GetCommit(), b.GetEvent())
if err != nil {
retErr := fmt.Errorf("unable to set step check %s: %w", entry, err)

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

return
}
}

c.JSON(http.StatusOK, s)
Expand Down
2 changes: 1 addition & 1 deletion api/webhook/post.go
Original file line number Diff line number Diff line change
Expand Up @@ -589,7 +589,7 @@ func PostWebhook(c *gin.Context) {
// using the same Number and thus create a constraint
// conflict; consider deleting the partially created
// build object in the database
err = build.PlanBuild(ctx, database.FromContext(c), p, b, repo)
err = build.PlanBuild(ctx, database.FromContext(c), scm.FromContext(c), p, b, repo)
if err != nil {
retErr := fmt.Errorf("%s: %w", baseErr, err)

Expand Down
3 changes: 2 additions & 1 deletion cmd/vela-server/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,8 @@ func main() {
EnvVars: []string{"VELA_CLONE_IMAGE"},
Name: "clone-image",
Usage: "the clone image to use for the injected clone step",
Value: "target/vela-git:v0.8.0@sha256:02de004ae9dbf184c70039cb9ce431c31d6e7580eb9e6ec64a97ebf108aa65cb",
// renovate: image=target/vela-git
Value: "target/vela-git:v0.8.0@sha256:02de004ae9dbf184c70039cb9ce431c31d6e7580eb9e6ec64a97ebf108aa65cb",
},
&cli.StringSliceFlag{
EnvVars: []string{"VELA_REPO_ALLOWLIST"},
Expand Down
2 changes: 1 addition & 1 deletion cmd/vela-server/schedule.go
Original file line number Diff line number Diff line change
Expand Up @@ -356,7 +356,7 @@ func processSchedule(ctx context.Context, s *library.Schedule, compiler compiler
// using the same Number and thus create a constraint
// conflict; consider deleting the partially created
// build object in the database
err = build.PlanBuild(ctx, database, p, b, r)
err = build.PlanBuild(ctx, database, scm, p, b, r)
if err != nil {
// check if the retry limit has been exceeded
if i < retryLimit-1 {
Expand Down
2 changes: 2 additions & 0 deletions database/repo/table.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ repos (
pipeline_type TEXT,
previous_name VARCHAR(100),
approve_build VARCHAR(20),
install_id INTEGER,
UNIQUE(full_name)
);
`
Expand Down Expand Up @@ -75,6 +76,7 @@ repos (
pipeline_type TEXT,
previous_name TEXT,
approve_build TEXT,
install_id INTEGER,
UNIQUE(full_name)
);
`
Expand Down
3 changes: 3 additions & 0 deletions database/step/table.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ package step

import (
"context"

"github.com/go-vela/types/constants"
)

Expand All @@ -29,6 +30,7 @@ steps (
host VARCHAR(250),
runtime VARCHAR(250),
distribution VARCHAR(250),
check_id INTEGER,
UNIQUE(build_id, number)
);
`
Expand All @@ -54,6 +56,7 @@ steps (
host TEXT,
runtime TEXT,
distribution TEXT,
check_id INTEGER,
UNIQUE(build_id, number)
);
`
Expand Down
2 changes: 2 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

go 1.21

replace github.com/go-vela/types => ../types

Check failure on line 5 in go.mod

View workflow job for this annotation

GitHub Actions / golangci

[golangci] go.mod#L5

local replacement are not allowed: github.com/go-vela/types (gomoddirectives)
Raw output
go.mod:5:1: local replacement are not allowed: github.com/go-vela/types (gomoddirectives)
replace github.com/go-vela/types => ../types
^

Choose a reason for hiding this comment

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

🚫 [golangci] reported by reviewdog 🐶
local replacement are not allowed: github.com/go-vela/types (gomoddirectives)


require (
github.com/Bose/minisentinel v0.0.0-20200130220412-917c5a9223bb
github.com/DATA-DOG/go-sqlmock v1.5.2
Expand Down
2 changes: 0 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -88,8 +88,6 @@ github.com/go-playground/validator/v10 v10.14.0 h1:vgvQWe3XCz3gIeFDm/HnTIbj6UGmg
github.com/go-playground/validator/v10 v10.14.0/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU=
github.com/go-test/deep v1.0.2 h1:onZX1rnHT3Wv6cqNgYyFOOlgVKJrksuCMCRvJStbMYw=
github.com/go-test/deep v1.0.2/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA=
github.com/go-vela/types v0.23.1 h1:st4BeDcYVyaaFqblU1YroztNvmYLBgmfZpWq0En0Sg0=
github.com/go-vela/types v0.23.1/go.mod h1:AAqgxIw1aRBgPkE/5juGuiwh/JZuOtL8fcPaEkjFWwQ=
github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU=
github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
Expand Down
41 changes: 34 additions & 7 deletions scm/github/github.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@ package github

import (
"context"
"crypto/x509"
"encoding/base64"
"encoding/pem"
"fmt"
"net/http"
"net/url"
Expand Down Expand Up @@ -120,11 +123,24 @@ func New(opts ...ClientOpt) (*client, error) {

if c.config.GithubAppID != 0 && len(c.config.GithubAppPrivateKey) > 0 {
c.Logger.Infof("sourcing private key from path: %s", c.config.GithubAppPrivateKey)
transport, err := ghinstallation.NewAppsTransportKeyFromFile(http.DefaultTransport, c.config.GithubAppID, c.config.GithubAppPrivateKey)

decodedPEM, err := base64.StdEncoding.DecodeString(c.config.GithubAppPrivateKey)
if err != nil {
return nil, err
return nil, fmt.Errorf("error decoding base64: %w", err)
}

block, _ := pem.Decode(decodedPEM)
if block == nil {
return nil, fmt.Errorf("failed to parse PEM block containing the key")
}

privateKey, err := x509.ParsePKCS1PrivateKey(block.Bytes)
if err != nil {
return nil, fmt.Errorf("failed to parse RSA private key: %w", err)
}

transport := ghinstallation.NewAppsTransportFromPrivateKey(http.DefaultTransport, c.config.GithubAppID, privateKey)

transport.BaseURL = c.config.API
c.AppsTransport = transport
}
Expand Down Expand Up @@ -186,17 +202,28 @@ func (c *client) newClientToken(token string) *github.Client {
}

// helper function to return the GitHub App token.
func (c *client) newGithubAppToken(r *library.Repo) *github.Client {
func (c *client) newGithubAppToken(r *library.Repo) (*github.Client, error) {
Copy link
Member

Choose a reason for hiding this comment

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

recommendation: looks like it returns a client using a token, not the token itself. maybe remove Token suffix and update comment?

// create a github client based off the existing GitHub App configuration
client, err := github.NewClient(&http.Client{Transport: c.AppsTransport}).WithEnterpriseURLs(c.config.API, c.config.API)
if err != nil {
panic(err)
return nil, err
}

// if repo has an install ID, use it to create an installation token
if r.GetInstallID() != 0 {
// create installation token for the repo
t, _, err := client.Apps.CreateInstallationToken(context.Background(), r.GetInstallID(), &github.InstallationTokenOptions{})
if err != nil {
panic(err)
}

return c.newClientToken(t.GetToken()), nil
}

// list all installations (a.k.a. orgs) where the GitHub App is installed
installations, _, err := client.Apps.ListInstallations(context.Background(), &github.ListOptions{})
if err != nil {
panic(err)
return nil, err
}

var id int64
Expand All @@ -210,7 +237,7 @@ func (c *client) newGithubAppToken(r *library.Repo) *github.Client {

// failsafe in case the repo does not belong to an org where the GitHub App is installed
if id == 0 {
panic(err)
return nil, err
}

// create installation token for the repo
Expand All @@ -219,5 +246,5 @@ func (c *client) newGithubAppToken(r *library.Repo) *github.Client {
panic(err)
}

return c.newClientToken(t.GetToken())
return c.newClientToken(t.GetToken()), nil
}
48 changes: 41 additions & 7 deletions scm/github/repo.go
Original file line number Diff line number Diff line change
Expand Up @@ -587,12 +587,15 @@ func (c *client) GetBranch(ctx context.Context, u *library.User, r *library.Repo
}

// CreateChecks defines a function that does stuff...
func (c *client) CreateChecks(ctx context.Context, r *library.Repo, commit, step string) (int64, error) {
func (c *client) CreateChecks(ctx context.Context, r *library.Repo, commit, step, event string) (int64, error) {
// create client from GitHub App
client := c.newGithubAppToken(r)
client, err := c.newGithubAppToken(r)
if err != nil {
return 0, err
}

opts := github.CreateCheckRunOptions{
Name: fmt.Sprintf("vela-%s-%s", commit, step),
Name: fmt.Sprintf("vela-%s-%s", event, step),
HeadSHA: commit,
}

Expand All @@ -605,9 +608,12 @@ func (c *client) CreateChecks(ctx context.Context, r *library.Repo, commit, step
}

// UpdateChecks defines a function that does stuff...
func (c *client) UpdateChecks(ctx context.Context, r *library.Repo, s *library.Step, commit string) error {
func (c *client) UpdateChecks(ctx context.Context, r *library.Repo, s *library.Step, commit, event string) error {
// create client from GitHub App
client := c.newGithubAppToken(r)
client, err := c.newGithubAppToken(r)
if err != nil {
return err
}

var (
conclusion string
Expand Down Expand Up @@ -644,13 +650,41 @@ func (c *client) UpdateChecks(ctx context.Context, r *library.Repo, s *library.S
status = "completed"
}

var annotations []*github.CheckRunAnnotation

for _, reportAnnotation := range s.GetReport().GetAnnotations() {
annotation := &github.CheckRunAnnotation{
Path: github.String(reportAnnotation.GetPath()),
StartLine: github.Int(reportAnnotation.GetStartLine()),
EndLine: github.Int(reportAnnotation.GetEndLine()),
StartColumn: github.Int(reportAnnotation.GetStartColumn()),
EndColumn: github.Int(reportAnnotation.GetEndColumn()),
AnnotationLevel: github.String(reportAnnotation.GetAnnotationLevel()),
Message: github.String(reportAnnotation.GetMessage()),
Title: github.String(reportAnnotation.GetTitle()),
RawDetails: github.String(reportAnnotation.GetRawDetails()),
}

annotations = append(annotations, annotation)
}

output := &github.CheckRunOutput{
Title: github.String(s.GetReport().GetTitle()),
Summary: github.String(s.GetReport().GetSummary()),
Text: github.String(s.GetReport().GetText()),
AnnotationsCount: github.Int(s.GetReport().GetAnnotationsCount()),
AnnotationsURL: github.String(s.GetReport().GetAnnotationsURL()),
Annotations: annotations,
}

opts := github.UpdateCheckRunOptions{
Name: fmt.Sprintf("vela-%s-%s", commit, s.GetName()),
Name: fmt.Sprintf("vela-%s-%s", event, s.GetName()),
Conclusion: github.String(conclusion),
Status: github.String(status),
Output: output,
}

_, _, err := client.Checks.UpdateCheckRun(ctx, r.GetOrg(), r.GetName(), s.GetCheckID(), opts)
_, _, err = client.Checks.UpdateCheckRun(ctx, r.GetOrg(), r.GetName(), s.GetCheckID(), opts)
if err != nil {
return err
}
Expand Down
4 changes: 2 additions & 2 deletions scm/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -133,8 +133,8 @@ type Service interface {
GetHTMLURL(context.Context, *library.User, string, string, string, string) (string, error)

// TODO: add comments
CreateChecks(context.Context, *library.Repo, string, string) (int64, error)
UpdateChecks(context.Context, *library.Repo, *library.Step, string) error
CreateChecks(context.Context, *library.Repo, string, string, string) (int64, error)
UpdateChecks(context.Context, *library.Repo, *library.Step, string, string) error

// Webhook SCM Interface Functions

Expand Down
Loading