github.com/covergates/covergates@v0.2.2-0.20201009050117-42ef8a19fb95/modules/hook/hook.go (about)

     1  package hook
     2  
     3  import (
     4  	"context"
     5  	"errors"
     6  
     7  	"github.com/covergates/covergates/core"
     8  )
     9  
    10  var errHookEventNotSupport = errors.New("hook event not support")
    11  
    12  // Service of webhook resolve and management
    13  type Service struct {
    14  	SCM           core.SCMService
    15  	RepoStore     core.RepoStore
    16  	ReportStore   core.ReportStore
    17  	ReportService core.ReportService
    18  }
    19  
    20  // Create a webhook to repository. If existed webhook found, it will be removed first
    21  func (s *Service) Create(ctx context.Context, repo *core.Repo) error {
    22  	user, err := s.RepoStore.Creator(repo)
    23  	if err != nil {
    24  		return err
    25  	}
    26  	client, err := s.SCM.Client(repo.SCM)
    27  	if err != nil {
    28  		return err
    29  	}
    30  	if hook, err := s.RepoStore.FindHook(repo); hook != nil && err == nil {
    31  		client.Repositories().RemoveHook(ctx, user, repo.FullName(), hook)
    32  	}
    33  	hook, err := client.Repositories().CreateHook(ctx, user, repo.FullName())
    34  	if err != nil {
    35  		return err
    36  	}
    37  	return s.RepoStore.UpdateHook(repo, hook)
    38  }
    39  
    40  // Delete a repository webhook
    41  func (s *Service) Delete(ctx context.Context, repo *core.Repo) error {
    42  	user, err := s.RepoStore.Creator(repo)
    43  	if err != nil {
    44  		return err
    45  	}
    46  	client, err := s.SCM.Client(repo.SCM)
    47  	if err != nil {
    48  		return err
    49  	}
    50  	hook, err := s.RepoStore.FindHook(repo)
    51  	if err != nil {
    52  		return err
    53  	}
    54  	return client.Repositories().RemoveHook(ctx, user, repo.FullName(), hook)
    55  }
    56  
    57  // Resolve webhook event from the SCM
    58  func (s *Service) Resolve(ctx context.Context, repo *core.Repo, hook core.HookEvent) error {
    59  	if hook == nil {
    60  		return errHookEventNotSupport
    61  	}
    62  	switch event := hook.(type) {
    63  	case *core.PullRequestHook:
    64  		return s.resolvePullRequest(ctx, repo, event)
    65  	}
    66  	return nil
    67  }
    68  
    69  func (s *Service) resolvePullRequest(ctx context.Context, repo *core.Repo, hook *core.PullRequestHook) error {
    70  	setting, err := s.RepoStore.Setting(repo)
    71  	if err != nil {
    72  		return err
    73  	}
    74  	if !setting.MergePullRequest {
    75  		return nil
    76  	}
    77  
    78  	client, err := s.SCM.Client(repo.SCM)
    79  	if err != nil {
    80  		return err
    81  	}
    82  	user, err := s.RepoStore.Creator(repo)
    83  	if err != nil {
    84  		return err
    85  	}
    86  	changes, err := client.PullRequests().ListChanges(ctx, user, repo.FullName(), hook.Number)
    87  	if err != nil {
    88  		// TODO: Gitea does not support ListChanges, need to find alternative solution
    89  		changes = []*core.FileChange{}
    90  	}
    91  
    92  	report, err := s.ReportStore.Find(&core.Report{
    93  		ReportID: repo.ReportID,
    94  		Commit:   hook.Commit,
    95  	})
    96  	if err != nil {
    97  		report, err = s.ReportStore.Find(&core.Report{
    98  			ReportID:  repo.ReportID,
    99  			Reference: hook.Source,
   100  		})
   101  		if err != nil {
   102  			return err
   103  		}
   104  	}
   105  	if previous, err := s.ReportStore.Find(&core.Report{
   106  		ReportID:  repo.ReportID,
   107  		Reference: hook.Target,
   108  	}); err == nil {
   109  		if report, err = s.ReportService.MergeReport(previous, report, changes); err != nil {
   110  			return err
   111  		}
   112  	}
   113  	report.Reference = hook.Target
   114  	report.Commit = hook.Commit
   115  	// TODO: need to use transation to prevent error occur in the middle
   116  	if err := s.ReportStore.Upload(report); err != nil {
   117  		return err
   118  	}
   119  	return nil
   120  }