From 30c26bfc85f117507d4ac52be80ae51c56ddda92 Mon Sep 17 00:00:00 2001 From: Barak Amar Date: Wed, 10 Feb 2021 15:22:07 +0200 Subject: [PATCH] Hooks separate actions from entry catalog (#1443) --- actions/action.go | 137 +++++++++++ actions/action_test.go | 229 ++++++++++++++++++ actions/event.go | 32 +++ actions/hook.go | 38 +++ .../testdata/action_duplicate_id.yaml | 0 .../testdata/action_full.yaml | 0 .../testdata/action_invalid_id.yaml | 0 .../testdata/action_invalid_type.yaml | 0 actions/testdata/action_invalid_yaml.yaml | 1 + .../testdata/action_required.yaml | 1 + actions/webhook.go | 115 +++++++++ catalog/action.go | 49 ---- catalog/action_test.go | 41 ---- catalog/entry_catalog.go | 30 ++- catalog/errors.go | 1 - catalog/rocks_cataloger_test.go | 3 +- 16 files changed, 582 insertions(+), 95 deletions(-) create mode 100644 actions/action.go create mode 100644 actions/action_test.go create mode 100644 actions/event.go create mode 100644 actions/hook.go rename {catalog => actions}/testdata/action_duplicate_id.yaml (100%) rename {catalog => actions}/testdata/action_full.yaml (100%) rename {catalog => actions}/testdata/action_invalid_id.yaml (100%) rename {catalog => actions}/testdata/action_invalid_type.yaml (100%) create mode 100644 actions/testdata/action_invalid_yaml.yaml rename {catalog => actions}/testdata/action_required.yaml (90%) create mode 100644 actions/webhook.go delete mode 100644 catalog/action.go delete mode 100644 catalog/action_test.go diff --git a/actions/action.go b/actions/action.go new file mode 100644 index 00000000000..91d9729a72d --- /dev/null +++ b/actions/action.go @@ -0,0 +1,137 @@ +package actions + +import ( + "errors" + "fmt" + "path" + "regexp" + + "gopkg.in/yaml.v3" +) + +type Action struct { + Name string `yaml:"name"` + Description string `yaml:"description"` + On OnEvents `yaml:"on"` + Hooks []ActionHook `yaml:"hooks"` +} + +type OnEvents struct { + PreMerge *ActionOn `yaml:"pre-merge"` + PreCommit *ActionOn `yaml:"pre-commit"` +} + +type ActionOn struct { + Branches []string `yaml:"branches"` +} + +type ActionHook struct { + ID string `yaml:"id"` + Type string `yaml:"type"` + Description string `yaml:"description"` + Properties map[string]string `yaml:"properties"` +} + +type MatchSpec struct { + EventType EventType + Branch string +} + +var ( + reHookID = regexp.MustCompile(`^[_a-zA-Z][\-_a-zA-Z0-9]{1,255}$`) + + ErrInvalidAction = errors.New("invalid action") + ErrInvalidEventType = errors.New("invalid event type") +) + +func (a *Action) Validate() error { + if a.Name == "" { + return fmt.Errorf("%w 'name' is required", ErrInvalidAction) + } + if a.On.PreMerge == nil && a.On.PreCommit == nil { + return fmt.Errorf("%w 'on' is required", ErrInvalidAction) + } + ids := make(map[string]struct{}) + for i, hook := range a.Hooks { + if !reHookID.MatchString(hook.ID) { + return fmt.Errorf("hook[%d] missing ID: %w", i, ErrInvalidAction) + } + if _, found := ids[hook.ID]; found { + return fmt.Errorf("hook[%d] duplicate ID '%s': %w", i, hook.ID, ErrInvalidAction) + } + ids[hook.ID] = struct{}{} + if _, found := hooks[HookType(hook.Type)]; !found { + return fmt.Errorf("hook[%d] type '%s' unknown: %w", i, hook.ID, ErrInvalidAction) + } + } + return nil +} + +func (a *Action) Match(spec MatchSpec) (bool, error) { + // at least one matched event definition + var actionOn *ActionOn + switch spec.EventType { + case EventTypePreCommit: + actionOn = a.On.PreCommit + case EventTypePreMerge: + actionOn = a.On.PreMerge + default: + return false, ErrInvalidEventType + } + // if no action specified - no match + if actionOn == nil { + return false, nil + } + // if no branches spec found - all match + if len(actionOn.Branches) == 0 { + return true, nil + } + // find at least one match + for _, b := range actionOn.Branches { + matched, err := path.Match(b, spec.Branch) + if err != nil { + return false, err + } + if matched { + return true, nil + } + } + return false, nil +} + +// ParseAction helper function to read, parse and validate Action from a reader +func ParseAction(data []byte) (*Action, error) { + var act Action + err := yaml.Unmarshal(data, &act) + if err != nil { + return nil, err + } + err = act.Validate() + if err != nil { + return nil, err + } + return &act, nil +} + +type Source interface { + List() []string + Load(name string) ([]byte, error) +} + +func LoadActions(source Source) ([]*Action, error) { + return nil, nil +} + +func MatchActions(actions []*Action, spec MatchSpec) ([]*Action, error) { + var matched []*Action + for _, act := range actions { + m, err := act.Match(spec) + if err != nil { + return nil, err + } + if m { + matched = append(matched, act) + } + } + return matched, nil +} diff --git a/actions/action_test.go b/actions/action_test.go new file mode 100644 index 00000000000..2ac79b57ba5 --- /dev/null +++ b/actions/action_test.go @@ -0,0 +1,229 @@ +package actions_test + +import ( + "io/ioutil" + "path" + "testing" + + "github.com/go-test/deep" + "github.com/treeverse/lakefs/actions" +) + +func TestAction_ReadAction(t *testing.T) { + tests := []struct { + name string + filename string + wantErr bool + }{ + {name: "full", filename: "action_full.yaml", wantErr: false}, + {name: "required", filename: "action_required.yaml", wantErr: false}, + {name: "duplicate id", filename: "action_duplicate_id.yaml", wantErr: true}, + {name: "invalid id", filename: "action_invalid_id.yaml", wantErr: true}, + {name: "invalid hook type", filename: "action_invalid_type.yaml", wantErr: true}, + {name: "invalid yaml", filename: "action_invalid_yaml.yaml", wantErr: true}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + data, err := ioutil.ReadFile(path.Join("testdata", tt.filename)) + if err != nil { + t.Fatalf("Failed to load testdata %s, err=%s", tt.filename, err) + } + act, err := actions.ParseAction(data) + if (err != nil) != tt.wantErr { + t.Errorf("ParseAction() error = %v, wantErr %t", err, tt.wantErr) + } + if err == nil && act == nil { + t.Error("ParseAction() no error, missing Action") + } + }) + } +} + +func TestAction_Match(t *testing.T) { + tests := []struct { + name string + on actions.OnEvents + spec actions.MatchSpec + want bool + wantErr bool + }{ + { + name: "none - on pre-merge without branch", + on: actions.OnEvents{}, + spec: actions.MatchSpec{EventType: actions.EventTypePreMerge}, + want: false, + wantErr: false, + }, + { + name: "none - on invalid event type", + on: actions.OnEvents{}, + spec: actions.MatchSpec{EventType: "nothing"}, + want: false, + wantErr: true, + }, + { + name: "pre-merge - on pre-merge without branch", + on: actions.OnEvents{PreMerge: &actions.ActionOn{}}, + spec: actions.MatchSpec{EventType: actions.EventTypePreMerge}, + want: true, + wantErr: false, + }, + { + name: "pre-merge - on pre-commit without branch", + on: actions.OnEvents{PreMerge: &actions.ActionOn{}}, + spec: actions.MatchSpec{EventType: actions.EventTypePreCommit}, + want: false, + wantErr: false, + }, + { + name: "pre-commit - on pre-merge without branch", + on: actions.OnEvents{PreCommit: &actions.ActionOn{}}, + spec: actions.MatchSpec{EventType: actions.EventTypePreMerge}, + want: false, + wantErr: false, + }, + { + name: "pre-commit - on pre-commit without branch", + on: actions.OnEvents{PreCommit: &actions.ActionOn{}}, + spec: actions.MatchSpec{EventType: actions.EventTypePreCommit}, + want: true, + wantErr: false, + }, + { + name: "both - on pre-commit without branch", + on: actions.OnEvents{PreCommit: &actions.ActionOn{}, PreMerge: &actions.ActionOn{}}, + spec: actions.MatchSpec{EventType: actions.EventTypePreCommit}, + want: true, + wantErr: false, + }, + { + name: "both - on pre-merge without branch", + on: actions.OnEvents{PreCommit: &actions.ActionOn{}, PreMerge: &actions.ActionOn{}}, + spec: actions.MatchSpec{EventType: actions.EventTypePreMerge}, + want: true, + wantErr: false, + }, + { + name: "pre-commit master - on pre-commit master", + on: actions.OnEvents{PreCommit: &actions.ActionOn{Branches: []string{"master"}}}, + spec: actions.MatchSpec{EventType: actions.EventTypePreCommit, Branch: "master"}, + want: true, + wantErr: false, + }, + { + name: "pre-commit master - on pre-commit masterer", + on: actions.OnEvents{PreCommit: &actions.ActionOn{Branches: []string{"master"}}}, + spec: actions.MatchSpec{EventType: actions.EventTypePreCommit, Branch: "masterer"}, + want: false, + wantErr: false, + }, + { + name: "pre-commit ends with feature - on pre-commit new-feature", + on: actions.OnEvents{PreCommit: &actions.ActionOn{Branches: []string{"*-feature"}}}, + spec: actions.MatchSpec{EventType: actions.EventTypePreCommit, Branch: "new-feature"}, + want: true, + wantErr: false, + }, + { + name: "pre-commit branch a1 or b1 - on pre-commit b1", + on: actions.OnEvents{PreCommit: &actions.ActionOn{Branches: []string{"a1", "b1"}}}, + spec: actions.MatchSpec{EventType: actions.EventTypePreCommit, Branch: "b1"}, + want: true, + wantErr: false, + }, + { + name: "pre-commit branch invalid - on pre-commit master", + on: actions.OnEvents{PreCommit: &actions.ActionOn{Branches: []string{"\\"}}}, + spec: actions.MatchSpec{EventType: actions.EventTypePreCommit, Branch: "master"}, + want: false, + wantErr: true, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + a := &actions.Action{ + Name: tt.name, + On: tt.on, + } + got, err := a.Match(tt.spec) + if (err != nil) != tt.wantErr { + t.Errorf("Match() error = %v, wantErr %v", err, tt.wantErr) + return + } + if got != tt.want { + t.Errorf("Match() got = %v, want %v", got, tt.want) + } + }) + } +} + +func TestMatchActions(t *testing.T) { + tests := []struct { + name string + actions []*actions.Action + spec actions.MatchSpec + want []*actions.Action + wantErr bool + }{ + { + name: "empty", + actions: nil, + spec: actions.MatchSpec{}, + want: nil, + wantErr: false, + }, + { + name: "all", + actions: []*actions.Action{ + {Name: "act1", On: actions.OnEvents{PreCommit: &actions.ActionOn{}}}, + {Name: "act2", On: actions.OnEvents{PreCommit: &actions.ActionOn{}}}, + }, + spec: actions.MatchSpec{ + EventType: actions.EventTypePreCommit, + }, + want: []*actions.Action{ + {Name: "act1", On: actions.OnEvents{PreCommit: &actions.ActionOn{}}}, + {Name: "act2", On: actions.OnEvents{PreCommit: &actions.ActionOn{}}}, + }, + wantErr: false, + }, + { + name: "none", + actions: []*actions.Action{ + {Name: "act1", On: actions.OnEvents{PreCommit: &actions.ActionOn{}}}, + {Name: "act2", On: actions.OnEvents{PreCommit: &actions.ActionOn{}}}, + }, + spec: actions.MatchSpec{ + EventType: actions.EventTypePreMerge, + }, + want: nil, + wantErr: false, + }, + { + name: "one", + actions: []*actions.Action{ + {Name: "act1", On: actions.OnEvents{PreCommit: &actions.ActionOn{}}}, + {Name: "act2", On: actions.OnEvents{PreMerge: &actions.ActionOn{}}}, + }, + spec: actions.MatchSpec{ + EventType: actions.EventTypePreMerge, + }, + want: []*actions.Action{ + {Name: "act2", On: actions.OnEvents{PreMerge: &actions.ActionOn{}}}, + }, + wantErr: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, err := actions.MatchActions(tt.actions, tt.spec) + if (err != nil) != tt.wantErr { + t.Errorf("MatchActions() error = %v, wantErr %v", err, tt.wantErr) + return + } + if diff := deep.Equal(got, tt.want); diff != nil { + t.Error("MatchActions() found diff", diff) + } + }) + } +} diff --git a/actions/event.go b/actions/event.go new file mode 100644 index 00000000000..7ea835e293d --- /dev/null +++ b/actions/event.go @@ -0,0 +1,32 @@ +package actions + +import ( + "strings" + "time" + + "github.com/google/uuid" +) + +type EventType string + +const ( + EventTypePreCommit EventType = "pre-commit" + EventTypePreMerge EventType = "pre-merge" +) + +type Event struct { + EventType EventType + EventTime time.Time + RepositoryID string + BranchID string + SourceRef string + CommitMessage string + Committer string + Metadata map[string]string +} + +func NewRunID(t time.Time) string { + uid := strings.ReplaceAll(uuid.New().String(), "-", "") + runID := t.UTC().Format(time.RFC3339) + "_" + uid + return runID +} diff --git a/actions/hook.go b/actions/hook.go new file mode 100644 index 00000000000..d5816092cb2 --- /dev/null +++ b/actions/hook.go @@ -0,0 +1,38 @@ +package actions + +import ( + "context" + "errors" + "fmt" + "io" +) + +type HookType string + +const ( + HookTypeWebhook HookType = "webhook" +) + +type OutputWriter interface { + OutputWrite(ctx context.Context, name string, reader io.Reader) error +} + +type Hook interface { + Run(ctx context.Context, runID string, event Event, writer OutputWriter) error +} + +type NewHookFunc func(*Action, ActionHook) (Hook, error) + +var hooks = map[HookType]NewHookFunc{ + HookTypeWebhook: NewWebhook, +} + +var ErrUnknownHookType = errors.New("unknown hook type") + +func NewHook(h HookType, a *Action, ah ActionHook) (Hook, error) { + f := hooks[h] + if f == nil { + return nil, fmt.Errorf("%w (%s)", ErrUnknownHookType, h) + } + return f(a, ah) +} diff --git a/catalog/testdata/action_duplicate_id.yaml b/actions/testdata/action_duplicate_id.yaml similarity index 100% rename from catalog/testdata/action_duplicate_id.yaml rename to actions/testdata/action_duplicate_id.yaml diff --git a/catalog/testdata/action_full.yaml b/actions/testdata/action_full.yaml similarity index 100% rename from catalog/testdata/action_full.yaml rename to actions/testdata/action_full.yaml diff --git a/catalog/testdata/action_invalid_id.yaml b/actions/testdata/action_invalid_id.yaml similarity index 100% rename from catalog/testdata/action_invalid_id.yaml rename to actions/testdata/action_invalid_id.yaml diff --git a/catalog/testdata/action_invalid_type.yaml b/actions/testdata/action_invalid_type.yaml similarity index 100% rename from catalog/testdata/action_invalid_type.yaml rename to actions/testdata/action_invalid_type.yaml diff --git a/actions/testdata/action_invalid_yaml.yaml b/actions/testdata/action_invalid_yaml.yaml new file mode 100644 index 00000000000..f5ddaa12981 --- /dev/null +++ b/actions/testdata/action_invalid_yaml.yaml @@ -0,0 +1 @@ +not a yaml file \ No newline at end of file diff --git a/catalog/testdata/action_required.yaml b/actions/testdata/action_required.yaml similarity index 90% rename from catalog/testdata/action_required.yaml rename to actions/testdata/action_required.yaml index b24f629941a..35cf422b194 100644 --- a/catalog/testdata/action_required.yaml +++ b/actions/testdata/action_required.yaml @@ -1,3 +1,4 @@ +name: action name on: pre-merge: branches: diff --git a/actions/webhook.go b/actions/webhook.go new file mode 100644 index 00000000000..4bfc09b96d6 --- /dev/null +++ b/actions/webhook.go @@ -0,0 +1,115 @@ +package actions + +import ( + "bytes" + "context" + "encoding/json" + "errors" + "fmt" + "net/http" + "time" +) + +type Webhook struct { + ID string + ActionName string + URL string + Timeout time.Duration +} + +type WebhookEventInfo struct { + RunID string `json:"run_id"` + EventType string `json:"event_type"` + EventTime string `json:"event_time"` + ActionName string `json:"action_name"` + HookID string `json:"hook_id"` + RepositoryID string `json:"repository_id"` + BranchID string `json:"branch_id"` + SourceRef string `json:"source_ref"` + CommitMessage string `json:"commit_message"` + Committer string `json:"committer"` + Metadata map[string]string `json:"metadata"` +} + +const webhookClientTimeout = 5 * time.Minute + +var ( + ErrWebhookRequestFailed = errors.New("webhook request failed") + ErrWebhookMissingURL = errors.New("webhook missing url") +) + +func NewWebhook(action *Action, h ActionHook) (Hook, error) { + webhookURL := h.Properties["url"] + if len(webhookURL) == 0 { + return nil, ErrWebhookMissingURL + } + + requestTimeout := webhookClientTimeout + timeoutDuration := h.Properties["timeout"] + if len(timeoutDuration) > 0 { + d, err := time.ParseDuration(timeoutDuration) + if err != nil { + return nil, fmt.Errorf("webhook request duration: %w", err) + } + requestTimeout = d + } + return &Webhook{ + ID: h.ID, + ActionName: action.Name, + Timeout: requestTimeout, + URL: webhookURL, + }, nil +} + +func (w *Webhook) Run(ctx context.Context, runID string, ed Event, writer OutputWriter) error { + // post event information as json to webhook endpoint + eventData, err := w.marshalEvent(runID, ed) + if err != nil { + return err + } + req, err := http.NewRequest(http.MethodPost, w.URL, bytes.NewReader(eventData)) + if err != nil { + return err + } + client := &http.Client{ + Timeout: w.Timeout, + } + resp, err := client.Do(req) + if err != nil { + return err + } + defer func() { + _ = resp.Body.Close() + }() + + // log response body if needed + if resp.Body != nil && resp.ContentLength > 0 { + if err := writer.OutputWrite(ctx, w.ID, resp.Body); err != nil { + return err + } + } + + // check status code + if resp.StatusCode < http.StatusOK || resp.StatusCode >= http.StatusMultipleChoices { + return fmt.Errorf("%w (status code: %d)", ErrWebhookRequestFailed, resp.StatusCode) + } + return nil +} + +func (w *Webhook) marshalEvent(runID string, ed Event) ([]byte, error) { + now := time.Now() + info := WebhookEventInfo{ + RunID: runID, + EventType: string(ed.EventType), + EventTime: now.UTC().Format(time.RFC3339), + ActionName: w.ActionName, + HookID: w.ID, + RepositoryID: ed.RepositoryID, + BranchID: ed.BranchID, + SourceRef: ed.SourceRef, + CommitMessage: ed.CommitMessage, + Committer: ed.Committer, + Metadata: ed.Metadata, + } + return json.Marshal(info) +} diff --git a/catalog/action.go b/catalog/action.go deleted file mode 100644 index 81879edddfe..00000000000 --- a/catalog/action.go +++ /dev/null @@ -1,49 +0,0 @@ -package catalog - -import ( - "fmt" - "regexp" -) - -type Action struct { - Name string `yaml:"name"` - Description string `yaml:"description"` - On struct { - PreMerge *ActionOn `yaml:"pre-merge"` - PreCommit *ActionOn `yaml:"pre-commit"` - } `yaml:"on"` - Hooks []ActionHook `yaml:"hooks"` -} - -type ActionOn struct { - Branches []string `yaml:"branches"` -} - -type ActionHook struct { - ID string `yaml:"id"` - Type string `yaml:"type"` - Description string `yaml:"description"` - Properties map[string]string `yaml:"properties"` -} - -var reHookID = regexp.MustCompile(`^[_a-zA-Z][\-_a-zA-Z0-9]{1,255}$`) - -func (a *Action) Validate() error { - if a.On.PreMerge == nil && a.On.PreCommit == nil { - return fmt.Errorf("%w 'on' is required", ErrInvalidAction) - } - ids := make(map[string]struct{}) - for i, hook := range a.Hooks { - if !reHookID.MatchString(hook.ID) { - return fmt.Errorf("hook[%d] missing ID: %w", i, ErrInvalidAction) - } - if _, found := ids[hook.ID]; found { - return fmt.Errorf("hook[%d] duplicate ID '%s': %w", i, hook.ID, ErrInvalidAction) - } - ids[hook.ID] = struct{}{} - if hook.Type != "webhook" { - return fmt.Errorf("hook[%d] '%s' unknown type: %w", i, hook.ID, ErrInvalidAction) - } - } - return nil -} diff --git a/catalog/action_test.go b/catalog/action_test.go deleted file mode 100644 index 2dd0084e375..00000000000 --- a/catalog/action_test.go +++ /dev/null @@ -1,41 +0,0 @@ -package catalog - -import ( - "errors" - "io/ioutil" - "path" - "testing" - - "gopkg.in/yaml.v3" -) - -func TestAction_Validate(t *testing.T) { - tests := []struct { - name string - filename string - wantErr error - }{ - {name: "full", filename: "action_full.yaml", wantErr: nil}, - {name: "required", filename: "action_required.yaml", wantErr: nil}, - {name: "duplicate id", filename: "action_duplicate_id.yaml", wantErr: ErrInvalidAction}, - {name: "invalid id", filename: "action_invalid_id.yaml", wantErr: ErrInvalidAction}, - {name: "invalid hook type", filename: "action_invalid_type.yaml", wantErr: ErrInvalidAction}, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - actionData, err := ioutil.ReadFile(path.Join("testdata", tt.filename)) - if err != nil { - t.Fatalf("Failed to load testdata %s, err=%s", tt.filename, err) - } - var act Action - err = yaml.Unmarshal(actionData, &act) - if err != nil { - t.Fatalf("Unmarshal action err=%s", err) - } - err = act.Validate() - if !errors.Is(err, tt.wantErr) { - t.Errorf("Validate() error = %v, wantErr %v", err, tt.wantErr) - } - }) - } -} diff --git a/catalog/entry_catalog.go b/catalog/entry_catalog.go index d69601e6a70..a6196b33ea9 100644 --- a/catalog/entry_catalog.go +++ b/catalog/entry_catalog.go @@ -5,8 +5,12 @@ import ( "crypto" _ "crypto/sha256" "fmt" + "time" + + "github.com/treeverse/lakefs/actions" "github.com/cockroachdb/pebble" + "github.com/treeverse/lakefs/block" "github.com/treeverse/lakefs/config" "github.com/treeverse/lakefs/db" "github.com/treeverse/lakefs/graveler" @@ -78,7 +82,8 @@ type Store interface { } type EntryCatalog struct { - Store Store + BlockAdapter block.Adapter + Store Store } const ( @@ -129,7 +134,10 @@ func NewEntryCatalog(cfg *config.Config, db db.Database) (*EntryCatalog, error) refManager := ref.NewPGRefManager(db, ident.NewHexAddressProvider()) branchLocker := ref.NewBranchLocker(db) store := graveler.NewGraveler(branchLocker, committedManager, stagingManager, refManager) - entryCatalog := &EntryCatalog{Store: store} + entryCatalog := &EntryCatalog{ + BlockAdapter: tierFSParams.Adapter, + Store: store, + } store.SetPreCommitHook(entryCatalog.preCommitHook) store.SetPreMergeHook(entryCatalog.preMergeHook) return entryCatalog, nil @@ -505,9 +513,27 @@ func (e *EntryCatalog) DumpTags(ctx context.Context, repositoryID graveler.Repos } func (e *EntryCatalog) preCommitHook(ctx context.Context, repositoryID graveler.RepositoryID, branchID graveler.BranchID, commit graveler.Commit) error { + _ = actions.Event{ + EventType: actions.EventTypePreCommit, + EventTime: time.Now(), + RepositoryID: repositoryID.String(), + BranchID: branchID.String(), + CommitMessage: commit.Message, + Committer: commit.Committer, + Metadata: commit.Metadata, + } return nil } func (e *EntryCatalog) preMergeHook(ctx context.Context, repositoryID graveler.RepositoryID, destination graveler.BranchID, source graveler.Ref, commit graveler.Commit) error { + _ = actions.Event{ + EventType: actions.EventTypePreMerge, + EventTime: time.Now(), + RepositoryID: repositoryID.String(), + BranchID: source.String(), + CommitMessage: commit.Message, + Committer: commit.Committer, + Metadata: commit.Metadata, + } return nil } diff --git a/catalog/errors.go b/catalog/errors.go index 2f98ae45401..6ea0697bfdf 100644 --- a/catalog/errors.go +++ b/catalog/errors.go @@ -17,5 +17,4 @@ var ( ErrNoDifferenceWasFound = errors.New("no difference was found") ErrConflictFound = errors.New("conflict found") ErrUnsupportedRelation = errors.New("unsupported relation") - ErrInvalidAction = errors.New("invalid action") ) diff --git a/catalog/rocks_cataloger_test.go b/catalog/rocks_cataloger_test.go index 99b2861309f..ed60c334474 100644 --- a/catalog/rocks_cataloger_test.go +++ b/catalog/rocks_cataloger_test.go @@ -5,11 +5,10 @@ import ( "testing" "time" - "google.golang.org/protobuf/types/known/timestamppb" - "github.com/go-test/deep" "github.com/treeverse/lakefs/graveler" "github.com/treeverse/lakefs/testutil" + "google.golang.org/protobuf/types/known/timestamppb" ) func TestCataloger_ListRepositories(t *testing.T) {