@@ -16,6 +16,7 @@ import (
16
16
"github.com/hashicorp/go-multierror"
17
17
"github.com/treeverse/lakefs/pkg/actions/lua/hook"
18
18
"github.com/treeverse/lakefs/pkg/auth"
19
+ "github.com/treeverse/lakefs/pkg/catalog"
19
20
"github.com/treeverse/lakefs/pkg/graveler"
20
21
"github.com/treeverse/lakefs/pkg/kv"
21
22
"github.com/treeverse/lakefs/pkg/logging"
@@ -210,6 +211,7 @@ type Service interface {
210
211
GetTaskResult (ctx context.Context , repositoryID string , runID string , hookRunID string ) (* TaskResult , error )
211
212
ListRunResults (ctx context.Context , repositoryID string , branchID , commitID string , after string ) (RunResultIterator , error )
212
213
ListRunTaskResults (ctx context.Context , repositoryID string , runID string , after string ) (TaskResultIterator , error )
214
+ TriggerAction (ctx context.Context , repository * catalog.Repository , ref string , actionName string ) (* RunResult , error )
213
215
graveler.HooksHandler
214
216
}
215
217
@@ -606,6 +608,96 @@ func (s *StoreService) PostCherryPickHook(ctx context.Context, record graveler.H
606
608
return nil
607
609
}
608
610
611
+ func (s * StoreService ) TriggerAction (ctx context.Context , repository * catalog.Repository , ref string , actionName string ) (* RunResult , error ) {
612
+ if ! s .cfg .Enabled {
613
+ logging .FromContext (ctx ).WithField ("repository" , repository .Name ).Debug ("Hooks are disabled, skipping manual trigger" )
614
+ return nil , fmt .Errorf ("actions are disabled" )
615
+ }
616
+
617
+ // Construct graveler.RepositoryRecord from catalog.Repository
618
+ repoRecord := & graveler.RepositoryRecord {
619
+ RepositoryID : graveler .RepositoryID (repository .Name ),
620
+ Repository : & graveler.Repository {
621
+ StorageID : graveler .StorageID (repository .StorageID ),
622
+ StorageNamespace : graveler .StorageNamespace (repository .StorageNamespace ),
623
+ CreationDate : repository .CreationDate ,
624
+ DefaultBranchID : graveler .BranchID (repository .DefaultBranch ),
625
+ State : graveler .RepositoryState_ACTIVE ,
626
+ InstanceUID : "" , // Not available from catalog API
627
+ ReadOnly : repository .ReadOnly ,
628
+ },
629
+ }
630
+
631
+ runID := s .NewRunID ()
632
+
633
+ // Create hook record for manual trigger with all required fields
634
+ record := graveler.HookRecord {
635
+ RunID : runID ,
636
+ EventType : graveler .EventTypeManualTrigger ,
637
+ Repository : repoRecord ,
638
+ SourceRef : graveler .Ref (ref ),
639
+ BranchID : graveler .BranchID (ref ), // For manual triggers, we use the ref as branch
640
+ CommitID : graveler .CommitID ("" ), // Empty for manual triggers
641
+ TagID : graveler .TagID ("" ), // Empty for manual triggers
642
+ MergeSource : graveler .Ref ("" ), // Empty for manual triggers
643
+ Commit : graveler.Commit {
644
+ Message : "Manual trigger" ,
645
+ MetaRangeID : graveler .MetaRangeID ("" ),
646
+ CreationDate : time .Now (),
647
+ Version : graveler .CommitVersion (1 ),
648
+ Metadata : map [string ]string {},
649
+ Parents : []graveler.CommitID {},
650
+ },
651
+ }
652
+
653
+ // Load actions from the repository
654
+ actions , err := LoadActions (ctx , s .Source , record )
655
+ if err != nil {
656
+ return nil , fmt .Errorf ("failed to load actions: %w" , err )
657
+ }
658
+
659
+ // Filter actions for manual trigger with specific action name
660
+ var matchedActions []* Action
661
+ for _ , action := range actions {
662
+ // Check if action has manual-trigger event and matches the specified action name
663
+ if actionOn , ok := action .On [graveler .EventTypeManualTrigger ]; ok && action .Name == actionName {
664
+ // For manual triggers, we don't need to check branches since they're triggered explicitly
665
+ _ = actionOn // actionOn might be nil, which is fine for manual triggers
666
+ matchedActions = append (matchedActions , action )
667
+ }
668
+ }
669
+
670
+ if len (matchedActions ) == 0 {
671
+ return nil , fmt .Errorf ("no action named '%s' with manual-trigger found" , actionName )
672
+ }
673
+
674
+ // Allocate and run tasks
675
+ tasks , err := s .allocateTasks (runID , matchedActions )
676
+ if err != nil {
677
+ return nil , fmt .Errorf ("failed to allocate tasks: %w" , err )
678
+ }
679
+
680
+ runErr := s .runTasks (ctx , record , tasks )
681
+
682
+ // Save run information
683
+ err = s .saveRunInformation (ctx , record , tasks )
684
+ if err != nil {
685
+ return nil , fmt .Errorf ("failed to save run information: %w" , err )
686
+ }
687
+
688
+ // Return the run result
689
+ if runErr != nil {
690
+ // Return the run result even if there was an error, so caller can see what failed
691
+ runResult , getErr := s .GetRunResult (ctx , string (repoRecord .RepositoryID ), runID )
692
+ if getErr != nil {
693
+ return nil , fmt .Errorf ("action failed and could not retrieve run result: %w" , runErr )
694
+ }
695
+ return runResult , runErr
696
+ }
697
+
698
+ return s .GetRunResult (ctx , string (repoRecord .RepositoryID ), runID )
699
+ }
700
+
609
701
func (s * StoreService ) NewRunID () string {
610
702
return s .idGen .NewRunID ()
611
703
}
0 commit comments