GitRoot

craft your forge, build your project, grow your community freely
  1// SPDX-FileCopyrightText: 2025 Romain Maneschi <romain@gitroot.dev>
  2//
  3// SPDX-License-Identifier: EUPL-1.2
  4
  5package plugin
  6
  7import (
  8	"context"
  9	"time"
 10
 11	"github.com/go-git/go-git/v5/plumbing"
 12	"github.com/go-git/go-git/v5/plumbing/object"
 13	"github.com/go-git/go-git/v5/plumbing/protocol/packp"
 14	"gitroot.dev/server/repository"
 15	"gitroot.dev/server/user"
 16)
 17
 18type commitForDiffAction int
 19
 20const (
 21	commitForDiffActionAdd commitForDiffAction = iota
 22	commitForDiffActionMod
 23	commitForDiffActionDel
 24)
 25
 26type CommandForDiff struct {
 27	branch       plumbing.ReferenceName
 28	branchAction commitForDiffAction
 29	commits      []commitForDiffCommit
 30	pusher       user.SimpleUser
 31}
 32
 33type commitForDiffCommit struct {
 34	parent      *object.Commit
 35	hash        plumbing.Hash
 36	message     string
 37	sshCommiter string
 38	files       []commitForDiffFile
 39	date        time.Time
 40}
 41
 42type commitForDiffFile struct {
 43	path    string
 44	oldPath string //only if action == commitForDiffActionMod
 45	action  commitForDiffAction
 46}
 47
 48func CommandForDiffFromPackpCmd(ctx context.Context, repo *repository.GitRootRepository, commands []*packp.Command, pusher user.SimpleUser) ([]CommandForDiff, error) {
 49	res := make([]CommandForDiff, len(commands))
 50	for i, cmd := range commands {
 51		branchAction := commitForDiffActionMod
 52		if cmd.New == plumbing.ZeroHash {
 53			branchAction = commitForDiffActionDel
 54		} else if cmd.Old == plumbing.ZeroHash {
 55			branchAction = commitForDiffActionAdd
 56		}
 57		commits := make([]commitForDiffCommit, 0)
 58		if cmd.Old.String() != cmd.New.String() { //nothing todo
 59			if err := repo.WalkCommit(cmd.Old, cmd.New, func(com *object.Commit) error {
 60				parent, err := com.Parent(0) // TODO what parent?
 61				if err != nil {
 62					return err
 63				}
 64				patch, err := parent.PatchContext(ctx, com)
 65				if err != nil {
 66					return err
 67				}
 68				files := make([]commitForDiffFile, 0)
 69				for _, d := range patch.FilePatches() {
 70					from, to := d.Files()
 71					fileAction := commitForDiffActionMod
 72					path := ""
 73					oldPath := ""
 74					if from == nil && to != nil {
 75						fileAction = commitForDiffActionAdd
 76						path = to.Path()
 77					} else if from != nil && to == nil {
 78						fileAction = commitForDiffActionDel
 79						path = from.Path()
 80					} else {
 81						fileAction = commitForDiffActionMod
 82						path = to.Path()
 83						oldPath = from.Path()
 84					}
 85					files = append(files, commitForDiffFile{path: path, oldPath: oldPath, action: fileAction})
 86				}
 87				commits = append(commits, commitToCommitForDiff(com, parent, files))
 88				return nil
 89			}); err != nil {
 90				return nil, err
 91			}
 92		}
 93		res[i] = CommandForDiff{
 94			branch:       cmd.Name,
 95			branchAction: branchAction,
 96			commits:      commits,
 97			pusher:       pusher,
 98		}
 99	}
100	return res, nil
101}
102
103func CommandForDiffFromCommitCmd(ctx context.Context, repo *repository.GitRootRepository, plugin Plugin, com repository.LastCommit, cmd CommandForDiff) (CommandForDiff, error) {
104	files := []commitForDiffFile{}
105	for _, f := range com.Filepath {
106		files = append(files, commitForDiffFile{
107			path:   f,
108			action: commitForDiffActionMod, //TODO can be add
109		})
110	}
111	comP, err := com.Commit.Parents().Next()
112	if err != nil {
113		return CommandForDiff{}, err
114	}
115	commits := []commitForDiffCommit{{
116		parent:      comP,
117		hash:        com.Commit.Hash,
118		message:     com.Commit.Message,
119		sshCommiter: plugin.commiter.SimpleUser.Ssh,
120		files:       files,
121		date:        com.Commit.Committer.When,
122	}}
123	return CommandForDiff{
124		branch:       cmd.branch,
125		branchAction: commitForDiffActionMod,
126		commits:      commits,
127		pusher:       plugin.commiter.SimpleUser,
128	}, nil
129}
130
131func commitToCommitForDiff(com *object.Commit, parent *object.Commit, files []commitForDiffFile) commitForDiffCommit {
132	return commitForDiffCommit{
133		parent:      parent,
134		hash:        com.Hash,
135		message:     com.Message,
136		sshCommiter: com.PGPSignature,
137		files:       files,
138		date:        com.Committer.When,
139	}
140}
141
142func (c CommandForDiff) IsFileTouched(branch plumbing.ReferenceName, filepath string) bool {
143	if branch != c.branch {
144		return false
145	}
146	for _, com := range c.commits {
147		for _, f := range com.files {
148			if f.path == filepath || f.oldPath == filepath {
149				return true
150			}
151		}
152	}
153	return false
154}
155
156func IsFileTouched(cmds []CommandForDiff, branch plumbing.ReferenceName, filepath string) bool {
157	for _, c := range cmds {
158		if branch != c.branch {
159			continue
160		}
161		for _, com := range c.commits {
162			for _, f := range com.files {
163				if f.path == filepath || f.oldPath == filepath {
164					return true
165				}
166			}
167		}
168	}
169	return false
170}