push.go

  1package webhook
  2
  3import (
  4	"context"
  5	"errors"
  6	"fmt"
  7
  8	gitm "github.com/aymanbagabas/git-module"
  9	"github.com/charmbracelet/soft-serve/git"
 10	"github.com/charmbracelet/soft-serve/pkg/config"
 11	"github.com/charmbracelet/soft-serve/pkg/db"
 12	"github.com/charmbracelet/soft-serve/pkg/proto"
 13	"github.com/charmbracelet/soft-serve/pkg/store"
 14)
 15
 16// PushEvent is a push event.
 17type PushEvent struct {
 18	Common
 19
 20	// Ref is the branch or tag name.
 21	Ref string `json:"ref" url:"ref"`
 22	// Before is the previous commit SHA.
 23	Before string `json:"before" url:"before"`
 24	// After is the current commit SHA.
 25	After string `json:"after" url:"after"`
 26	// Commits is the list of commits.
 27	Commits []Commit `json:"commits" url:"commits"`
 28}
 29
 30// NewPushEvent sends a push event.
 31func NewPushEvent(ctx context.Context, user proto.User, repo proto.Repository, ref, before, after string) (PushEvent, error) {
 32	event := EventPush
 33
 34	payload := PushEvent{
 35		Ref:    ref,
 36		Before: before,
 37		After:  after,
 38		Common: Common{
 39			EventType: event,
 40			Repository: Repository{
 41				ID:          repo.ID(),
 42				Name:        repo.Name(),
 43				Description: repo.Description(),
 44				ProjectName: repo.ProjectName(),
 45				Private:     repo.IsPrivate(),
 46				CreatedAt:   repo.CreatedAt(),
 47				UpdatedAt:   repo.UpdatedAt(),
 48			},
 49			Sender: User{
 50				ID:       user.ID(),
 51				Username: user.Username(),
 52			},
 53		},
 54	}
 55
 56	cfg := config.FromContext(ctx)
 57	payload.Repository.HTTPURL = repoURL(cfg.HTTP.PublicURL, repo.Name())
 58	payload.Repository.SSHURL = repoURL(cfg.SSH.PublicURL, repo.Name())
 59	payload.Repository.GitURL = repoURL(cfg.Git.PublicURL, repo.Name())
 60
 61	// Find repo owner.
 62	dbx := db.FromContext(ctx)
 63	datastore := store.FromContext(ctx)
 64	owner, err := datastore.GetUserByID(ctx, dbx, repo.UserID())
 65	if err != nil {
 66		return PushEvent{}, db.WrapError(err)
 67	}
 68
 69	handle, err := datastore.GetHandleByUserID(ctx, dbx, owner.ID)
 70	if err != nil {
 71		return PushEvent{}, db.WrapError(err)
 72	}
 73
 74	payload.Repository.Owner.ID = owner.ID
 75	payload.Repository.Owner.Username = handle.Handle
 76
 77	// Find commits.
 78	r, err := repo.Open()
 79	if err != nil {
 80		return PushEvent{}, err
 81	}
 82
 83	payload.Repository.DefaultBranch, err = proto.RepositoryDefaultBranch(repo)
 84	// XXX: we check for ErrReferenceNotExist here because we don't want to
 85	// return an error if the repo is an empty repo.
 86	// This means that the repo doesn't have a default branch yet and this is
 87	// the first push to it.
 88	if err != nil && !errors.Is(err, git.ErrReferenceNotExist) {
 89		return PushEvent{}, err
 90	}
 91
 92	rev := after
 93	if !git.IsZeroHash(before) {
 94		rev = fmt.Sprintf("%s..%s", before, after)
 95	}
 96
 97	commits, err := r.Log(rev, gitm.LogOptions{
 98		// XXX: limit to 20 commits for now
 99		// TODO: implement a commits api
100		MaxCount: 20,
101	})
102	if err != nil {
103		return PushEvent{}, err
104	}
105
106	payload.Commits = make([]Commit, len(commits))
107	for i, c := range commits {
108		payload.Commits[i] = Commit{
109			ID:      c.ID.String(),
110			Message: c.Message,
111			Title:   c.Summary(),
112			Author: Author{
113				Name:  c.Author.Name,
114				Email: c.Author.Email,
115				Date:  c.Author.When,
116			},
117			Committer: Author{
118				Name:  c.Committer.Name,
119				Email: c.Committer.Email,
120				Date:  c.Committer.When,
121			},
122			Timestamp: c.Committer.When,
123		}
124	}
125
126	return payload, nil
127}