// Copyright 2026 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT package issues import ( "context" "code.gitea.io/gitea/models/db" ) // FileCommitComments holds commit comments for a single file, // split by side (left = old, right = new) with int keys matching DiffLine indices. type FileCommitComments struct { Left map[int][]*Comment Right map[int][]*Comment } // CommitCommentsForDiff maps file paths to their commit comments. type CommitCommentsForDiff map[string]*FileCommitComments // FindCommitCommentsByCommitSHA returns all comments for a given commit in a repo. func FindCommitCommentsByCommitSHA(ctx context.Context, repoID int64, commitSHA string) ([]*Comment, error) { comments := make([]*Comment, 0) if err := db.GetEngine(ctx). Where("repo_id = ? AND commit_sha = ? AND type = ?", repoID, commitSHA, CommentTypeCommitComment). OrderBy("created_unix ASC"). Find(&comments); err != nil { return nil, err } if err := CommentList(comments).LoadPosters(ctx); err != nil { return nil, err } return comments, nil } // FindCommitCommentsForDiff returns comments grouped by path and side for rendering in a diff view. func FindCommitCommentsForDiff(ctx context.Context, repoID int64, commitSHA string) (CommitCommentsForDiff, error) { comments, err := FindCommitCommentsByCommitSHA(ctx, repoID, commitSHA) if err != nil { return nil, err } result := make(CommitCommentsForDiff) for _, c := range comments { fcc, ok := result[c.TreePath] if !ok { fcc = &FileCommitComments{ Left: make(map[int][]*Comment), Right: make(map[int][]*Comment), } result[c.TreePath] = fcc } if c.Line < 0 { idx := int(-c.Line) fcc.Left[idx] = append(fcc.Left[idx], c) } else { idx := int(c.Line) fcc.Right[idx] = append(fcc.Right[idx], c) } } return result, nil } // CreateCommitComment creates a Comment with type CommitComment. func CreateCommitComment(ctx context.Context, comment *Comment) error { comment.Type = CommentTypeCommitComment _, err := db.GetEngine(ctx).Insert(comment) return err } // DeleteCommitComment deletes a commit comment by ID, verifying it belongs to the given repo. func DeleteCommitComment(ctx context.Context, repoID, commentID int64) error { _, err := db.GetEngine(ctx). Where("id = ? AND repo_id = ? AND type = ?", commentID, repoID, CommentTypeCommitComment). Delete(&Comment{}) return err } // GetCommitCommentByID returns a commit comment by ID, verifying it belongs to the given repo. func GetCommitCommentByID(ctx context.Context, repoID, commentID int64) (*Comment, error) { c := &Comment{} has, err := db.GetEngine(ctx). Where("id = ? AND repo_id = ? AND type = ?", commentID, repoID, CommentTypeCommitComment). Get(c) if err != nil { return nil, err } if !has { return nil, db.ErrNotExist{Resource: "CommitComment", ID: commentID} } return c, nil }