Skip to content

Commit

Permalink
Add support for tektondir interceptor service
Browse files Browse the repository at this point in the history
This adds support for tektondir interceptor service
to provide piplineruns irrespective of the .tekton
dir
  • Loading branch information
piyush-garg committed Dec 7, 2023
1 parent 5c0708a commit 1c9f97d
Show file tree
Hide file tree
Showing 18 changed files with 237 additions and 12 deletions.
2 changes: 1 addition & 1 deletion pkg/adapter/sinker.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,6 @@ func (s *sinker) processEvent(ctx context.Context, request *http.Request) error
}
}

p := pipelineascode.NewPacs(s.event, s.vcx, s.run, s.kint, s.logger)
p := pipelineascode.NewPacs(s.event, s.vcx, s.run, s.kint, s.logger, s.payload)
return p.Run(ctx)
}
9 changes: 9 additions & 0 deletions pkg/params/settings/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,8 @@ const (

RememberOKToTestKey = "remember-ok-to-test"
rememberOKToTestValue = "true"

TektonDirInterceptorURLKey = "tekton-dir-interceptor-url"
)

var (
Expand Down Expand Up @@ -100,6 +102,8 @@ type Settings struct {
CustomConsoleNamespaceURL string

RememberOKToTest bool

TektonDirInterceptorURL string
}

func ConfigToSettings(logger *zap.SugaredLogger, setting *Settings, config map[string]string) error {
Expand Down Expand Up @@ -243,6 +247,11 @@ func ConfigToSettings(logger *zap.SugaredLogger, setting *Settings, config map[s
setting.RememberOKToTest = rememberOKToTest
}

if setting.TektonDirInterceptorURL != config[TektonDirInterceptorURLKey] {
logger.Infof("CONFIG: setting tekton dir interceptor url to %v", config[TektonDirInterceptorURLKey])
setting.TektonDirInterceptorURL = config[TektonDirInterceptorURLKey]
}

return nil
}

Expand Down
4 changes: 4 additions & 0 deletions pkg/params/settings/default.go
Original file line number Diff line number Diff line change
Expand Up @@ -135,4 +135,8 @@ func SetDefaults(config map[string]string) {
if rememberOKToTest, ok := config[RememberOKToTestKey]; !ok || rememberOKToTest == "" {
config[RememberOKToTestKey] = rememberOKToTestValue
}

if v, ok := config[TektonDirInterceptorURLKey]; !ok || v == "" {
config[TektonDirInterceptorURLKey] = v
}
}
6 changes: 6 additions & 0 deletions pkg/params/settings/validation.go
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,12 @@ func Validate(config map[string]string) error {
}
}

if v, ok := config[TektonDirInterceptorURLKey]; ok && v != "" {
if _, err := url.ParseRequestURI(v); err != nil {
return fmt.Errorf("invalid value for key %v, invalid url: %w", TektonDirInterceptorURLKey, err)
}
}

return nil
}

Expand Down
2 changes: 1 addition & 1 deletion pkg/pipelineascode/cancel_pipelinerun_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -288,7 +288,7 @@ func TestCancelPipelinerun(t *testing.T) {
Kube: stdata.Kube,
},
}
pac := NewPacs(tt.event, nil, cs, nil, logger)
pac := NewPacs(tt.event, nil, cs, nil, logger, nil)
err := pac.cancelPipelineRuns(ctx, tt.repo)
assert.NilError(t, err)

Expand Down
34 changes: 30 additions & 4 deletions pkg/pipelineascode/match.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,13 +32,34 @@ func (p *PacRun) matchRepoPR(ctx context.Context) ([]matcher.Match, *v1alpha1.Re
return nil, repo, p.cancelPipelineRuns(ctx, repo)
}

matchedPRs, err := p.getPipelineRunsFromRepo(ctx, repo)
types, err := p.getPipelineRuns(ctx, repo)
if err != nil {
return nil, repo, err
}

if types == nil {
return nil, repo, err
}

matchedPRs, err := p.getPipelineRunsToTrigger(ctx, repo, types)
if err != nil {
return nil, repo, err
}

return matchedPRs, repo, nil
}

func (p *PacRun) getPipelineRuns(ctx context.Context, repo *v1alpha1.Repository) (*resolve.TektonTypes, error) {
if p.run.Info.Pac.TektonDirInterceptorURL != "" {
request, err := p.getInterceptorRequest()
if err != nil {
return nil, err
}
return p.getPipelineRunsFromService(ctx, request)
}
return p.getPipelineRunsFromRepo(ctx, repo)
}

// verifyRepoAndUser verifies if the Repo CR exists for the Git Repository,
// if the user has permission to run CI and also initialise provider client
func (p *PacRun) verifyRepoAndUser(ctx context.Context) (*v1alpha1.Repository, error) {
Expand Down Expand Up @@ -144,7 +165,7 @@ is that what you want? make sure you use -n when generating the secret, eg: echo
}

// getPipelineRunsFromRepo fetches pipelineruns from git repository and prepare them for creation
func (p *PacRun) getPipelineRunsFromRepo(ctx context.Context, repo *v1alpha1.Repository) ([]matcher.Match, error) {
func (p *PacRun) getPipelineRunsFromRepo(ctx context.Context, repo *v1alpha1.Repository) (*resolve.TektonTypes, error) {
provenance := "source"
if repo.Spec.Settings != nil && repo.Spec.Settings.PipelineRunProvenance != "" {
provenance = repo.Spec.Settings.PipelineRunProvenance
Expand Down Expand Up @@ -184,8 +205,13 @@ func (p *PacRun) getPipelineRunsFromRepo(ctx context.Context, repo *v1alpha1.Rep
p.eventEmitter.EmitMessage(nil, zap.InfoLevel, "RepositoryCannotLocatePipelineRun", msg)
return nil, nil
}
return &types, nil
}

func (p *PacRun) getPipelineRunsToTrigger(ctx context.Context, repo *v1alpha1.Repository, types *resolve.TektonTypes) ([]matcher.Match, error) {
pipelineRuns := types.PipelineRuns

pipelineRuns, err = resolve.MetadataResolve(pipelineRuns)
pipelineRuns, err := resolve.MetadataResolve(pipelineRuns)
if err != nil && pipelineRuns == nil {
p.eventEmitter.EmitMessage(repo, zap.ErrorLevel, "FailedToResolvePipelineRunMetadata", err.Error())
return nil, err
Expand Down Expand Up @@ -227,7 +253,7 @@ func (p *PacRun) getPipelineRunsFromRepo(ctx context.Context, repo *v1alpha1.Rep
}
}
}
pipelineRuns, err = resolve.Resolve(ctx, p.run, p.logger, p.vcx, types, p.event, &resolve.Opts{
pipelineRuns, err = resolve.Resolve(ctx, p.run, p.logger, p.vcx, *types, p.event, &resolve.Opts{
GenerateName: true,
RemoteTasks: true,
})
Expand Down
8 changes: 5 additions & 3 deletions pkg/pipelineascode/match_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ func TestPacRun_checkNeedUpdate(t *testing.T) {
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
p := NewPacs(nil, nil, &params.Run{Clients: clients.Clients{}}, nil, nil)
p := NewPacs(nil, nil, &params.Run{Clients: clients.Clients{}}, nil, nil, nil)
got, needupdate := p.checkNeedUpdate(tt.tmpl)
if tt.upgradeMessageSubstr != "" {
assert.Assert(t, strings.Contains(got, tt.upgradeMessageSubstr))
Expand Down Expand Up @@ -171,8 +171,10 @@ func TestGetPipelineRunsFromRepo(t *testing.T) {
Token: github.String("None"),
Logger: logger,
}
p := NewPacs(runevent, vcx, cs, k8int, logger)
matchedPRs, err := p.getPipelineRunsFromRepo(ctx, tt.repositories)
p := NewPacs(runevent, vcx, cs, k8int, logger, nil)
types, err := p.getPipelineRunsFromRepo(ctx, tt.repositories)
assert.NilError(t, err)
matchedPRs, err := p.getPipelineRunsToTrigger(ctx, nil, types)
assert.NilError(t, err)
matchedPRNames := []string{}
for i := range matchedPRs {
Expand Down
4 changes: 3 additions & 1 deletion pkg/pipelineascode/pipelineascode.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,13 +36,15 @@ type PacRun struct {
logger *zap.SugaredLogger
eventEmitter *events.EventEmitter
manager *ConcurrencyManager
payload []byte
}

func NewPacs(event *info.Event, vcx provider.Interface, run *params.Run, k8int kubeinteraction.Interface, logger *zap.SugaredLogger) PacRun {
func NewPacs(event *info.Event, vcx provider.Interface, run *params.Run, k8int kubeinteraction.Interface, logger *zap.SugaredLogger, payload []byte) PacRun {
return PacRun{
event: event, run: run, vcx: vcx, k8int: k8int, logger: logger,
eventEmitter: events.NewEventEmitter(run.Clients.Kube, logger),
manager: NewConcurrencyManager(),
payload: payload,
}
}

Expand Down
2 changes: 1 addition & 1 deletion pkg/pipelineascode/pipelineascode_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -583,7 +583,7 @@ func TestRun(t *testing.T) {
Token: github.String("None"),
Logger: logger,
}
p := NewPacs(&tt.runevent, vcx, cs, k8int, logger)
p := NewPacs(&tt.runevent, vcx, cs, k8int, logger, nil)
err := p.Run(ctx)

if tt.wantErr != "" {
Expand Down
151 changes: 151 additions & 0 deletions pkg/pipelineascode/tekton_dir_interceptor.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
package pipelineascode

import (
"bytes"
"context"
"encoding/base64"
"encoding/json"
"fmt"
"io"
"net/http"
"time"

"github.com/openshift-pipelines/pipelines-as-code/pkg/params/info"
"github.com/openshift-pipelines/pipelines-as-code/pkg/resolve"
v1 "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1"
"go.uber.org/zap"
)

type Data struct {
// Payload object
Payload []byte `json:"payload,omitempty"`

EventType string `json:"eventType,omitempty"`
BaseBranch string `json:"baseBranch,omitempty"`
HeadBranch string `json:"headBranch,omitempty"`
BaseURL string `json:"baseURL,omitempty"`
HeadURL string `json:"headURL,omitempty"`
SHA string `json:"sha,omitempty"`

// Github
GithubOrganization string `json:"githubOrganization,omitempty"`
GithubRepository string `json:"githubRepository,omitempty"`
GithubInstallationID int64 `json:"githubInstallationID,omitempty"`

// GHE
GHEURL string `json:"gheURL,omitempty"`

// Bitbucket Cloud
BitBucketAccountID string `json:"bitBucketAccountID,omitempty"`

// Bitbucket Server
BitBucketCloneURL string `json:"bitBucketCloneURL,omitempty"`

// Gitlab
GitlabSourceProjectID int `json:"gitlabSourceProjectID,omitempty"`
GitlabTargetProjectID int `json:"gitlabTargetProjectID,omitempty"`
}

type InterceptorRequest struct {
Data string `json:"data"`
Token string `json:"token"`
}

type InterceptorResponse struct {
Tasks []*v1.Task `json:"tasks,omitempty"`
Pipelines []*v1.Pipeline `json:"pipelines,omitempty"`
PipelineRuns []*v1.PipelineRun `json:"pipelineruns"`
}

func (p *PacRun) getPipelineRunsFromService(ctx context.Context, request *InterceptorRequest) (*resolve.TektonTypes, error) {
url := p.run.Info.Pac.TektonDirInterceptorURL

// marshall data to json (like json_encode)
marshalledRequest, err := json.Marshal(request)
if err != nil {
return nil, fmt.Errorf("unable to marshal interceptorRequest struct: %s", err.Error())
}

// Create a HTTP post request
req, err := http.NewRequestWithContext(ctx, "POST", url, bytes.NewBuffer(marshalledRequest))
if err != nil {
return nil, fmt.Errorf("unable to create http request with url %s : %s", url, err.Error())
}
req.Header.Set("Content-Type", "application/json")

// create http client
// do not forget to set timeout; otherwise, no timeout!
client := http.Client{Timeout: 10 * time.Second}
// send the request
resp, err := client.Do(req)
if err != nil {
return nil, fmt.Errorf("unable to make post http request to url %s : %s", url, err.Error())
}
if resp.StatusCode != http.StatusOK {
return nil, fmt.Errorf("received response %v : %s", resp.StatusCode, err.Error())
}

defer resp.Body.Close()
body, _ := io.ReadAll(resp.Body)

var interceptorResponse InterceptorResponse
if err := json.Unmarshal(body, &interceptorResponse); err != nil {
return nil, fmt.Errorf("unable to unmarshal the response %s", err.Error())
}

if len(interceptorResponse.PipelineRuns) == 0 {
msg := fmt.Sprintf("no pipelineruns received for this repository from %s interceptor service", url)
p.eventEmitter.EmitMessage(nil, zap.InfoLevel, "RepositoryCannotLocatePipelineRun", msg)
return nil, nil
}

return &resolve.TektonTypes{
Tasks: interceptorResponse.Tasks,
Pipelines: interceptorResponse.Pipelines,
PipelineRuns: interceptorResponse.PipelineRuns,
}, nil
}

func (p *PacRun) getInterceptorRequest() (*InterceptorRequest, error) {
data := getData(p.event, p.payload)
encodedData, err := encodeToBase64(data)
if err != nil {
return nil, err
}
request := InterceptorRequest{
Data: encodedData,
Token: p.vcx.GetToken(),
}
return &request, nil
}

func encodeToBase64(v interface{}) (string, error) {
var buf bytes.Buffer
encoder := base64.NewEncoder(base64.StdEncoding, &buf)
err := json.NewEncoder(encoder).Encode(v)
if err != nil {
return "", err
}
encoder.Close()
return buf.String(), nil
}

func getData(event *info.Event, payload []byte) Data {
return Data{
Payload: payload,
EventType: event.EventType,
BaseBranch: event.BaseBranch,
HeadBranch: event.HeadBranch,
BaseURL: event.BaseURL,
HeadURL: event.HeadURL,
SHA: event.SHA,
GithubOrganization: event.Organization,
GithubRepository: event.Repository,
GithubInstallationID: event.InstallationID,
GHEURL: event.GHEURL,
BitBucketAccountID: event.AccountID,
BitBucketCloneURL: event.CloneURL,
GitlabSourceProjectID: event.SourceProjectID,
GitlabTargetProjectID: event.TargetProjectID,
}
}
2 changes: 1 addition & 1 deletion pkg/pipelineascode/template_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -369,7 +369,7 @@ func TestProcessTemplates(t *testing.T) {
if tt.event == nil {
tt.event = &info.Event{}
}
p := NewPacs(tt.event, nil, run, &kitesthelper.KinterfaceTest{GetSecretResult: tt.secretData}, nil)
p := NewPacs(tt.event, nil, run, &kitesthelper.KinterfaceTest{GetSecretResult: tt.secretData}, nil, nil)
p.logger = logger
stdata, _ := testclient.SeedTestData(t, ctx, testclient.Data{})
p.eventEmitter = events.NewEventEmitter(stdata.Kube, logger)
Expand Down
4 changes: 4 additions & 0 deletions pkg/provider/bitbucketcloud/bitbucket.go
Original file line number Diff line number Diff line change
Expand Up @@ -284,3 +284,7 @@ func (v *Provider) GetFiles(_ context.Context, _ *info.Event) ([]string, error)
func (v *Provider) CreateToken(_ context.Context, _ []string, _ *info.Event) (string, error) {
return "", nil
}

func (v *Provider) GetToken() string {
return *v.Token
}
4 changes: 4 additions & 0 deletions pkg/provider/bitbucketserver/bitbucketserver.go
Original file line number Diff line number Diff line change
Expand Up @@ -279,3 +279,7 @@ func (v *Provider) GetFiles(_ context.Context, _ *info.Event) ([]string, error)
func (v *Provider) CreateToken(_ context.Context, _ []string, _ *info.Event) (string, error) {
return "", nil
}

func (v *Provider) GetToken() string {
return ""
}
4 changes: 4 additions & 0 deletions pkg/provider/gitea/gitea.go
Original file line number Diff line number Diff line change
Expand Up @@ -320,3 +320,7 @@ func (v *Provider) GetFiles(_ context.Context, _ *info.Event) ([]string, error)
func (v *Provider) CreateToken(_ context.Context, _ []string, _ *info.Event) (string, error) {
return "", nil
}

func (v *Provider) GetToken() string {
return *v.Token
}
4 changes: 4 additions & 0 deletions pkg/provider/github/github.go
Original file line number Diff line number Diff line change
Expand Up @@ -531,6 +531,10 @@ func (v *Provider) CreateToken(ctx context.Context, repository []string, event *
return token, nil
}

func (v *Provider) GetToken() string {
return *v.Token
}

func uniqueRepositoryID(repoIDs []int64, id int64) []int64 {
r := repoIDs
m := make(map[int64]bool)
Expand Down
4 changes: 4 additions & 0 deletions pkg/provider/gitlab/gitlab.go
Original file line number Diff line number Diff line change
Expand Up @@ -342,3 +342,7 @@ func (v *Provider) GetFiles(_ context.Context, runevent *info.Event) ([]string,
func (v *Provider) CreateToken(_ context.Context, _ []string, _ *info.Event) (string, error) {
return "", nil
}

func (v *Provider) GetToken() string {
return *v.Token
}
1 change: 1 addition & 0 deletions pkg/provider/interface.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ type Interface interface {
GetFiles(context.Context, *info.Event) ([]string, error)
GetTaskURI(context.Context, *info.Event, string) (bool, string, error)
CreateToken(context.Context, []string, *info.Event) (string, error)
GetToken() string
CheckPolicyAllowing(context.Context, *info.Event, []string) (bool, string)
}

Expand Down
Loading

0 comments on commit 1c9f97d

Please sign in to comment.