1package web
  2
  3import (
  4	"net/http"
  5	"strings"
  6
  7	"github.com/charmbracelet/log/v2"
  8	"github.com/charmbracelet/soft-serve/git"
  9	"github.com/charmbracelet/soft-serve/pkg/config"
 10	"github.com/charmbracelet/soft-serve/pkg/proto"
 11	"github.com/gorilla/mux"
 12)
 13
 14// CommitData contains data for rendering individual commit view.
 15type CommitData struct {
 16	RepoBaseData
 17	Commit    *git.Commit
 18	Diff      *git.Diff
 19	ParentIDs []string
 20}
 21
 22func repoCommit(w http.ResponseWriter, r *http.Request) {
 23	ctx := r.Context()
 24	logger := log.FromContext(ctx)
 25	cfg := config.FromContext(ctx)
 26	repo := proto.RepositoryFromContext(ctx)
 27	vars := mux.Vars(r)
 28	hash := vars["hash"]
 29
 30	gr, err := openRepository(repo)
 31	if err != nil {
 32		logger.Debug("failed to open repository", "repo", repo.Name(), "err", err)
 33		renderInternalServerError(w, r)
 34		return
 35	}
 36
 37	commit, err := gr.CatFileCommit(hash)
 38	if err != nil {
 39		logger.Debug("failed to get commit", "repo", repo.Name(), "hash", hash, "err", err)
 40		renderNotFound(w, r)
 41		return
 42	}
 43
 44	diff, err := gr.Diff(commit)
 45	if err != nil {
 46		logger.Debug("failed to get diff", "repo", repo.Name(), "hash", hash, "err", err)
 47		renderInternalServerError(w, r)
 48		return
 49	}
 50
 51	defaultBranch := getDefaultBranch(gr)
 52
 53	parentIDs := make([]string, commit.ParentsCount())
 54	for i := 0; i < commit.ParentsCount(); i++ {
 55		parentID, err := commit.ParentID(i)
 56		if err == nil && parentID != nil {
 57			parentIDs[i] = parentID.String()
 58		}
 59	}
 60
 61	commitSubject := commit.Message
 62	commitBody := ""
 63	if lines := strings.Split(commit.Message, "\n"); len(lines) > 0 {
 64		commitSubject = lines[0]
 65		if len(lines) > 1 {
 66			commitBody = strings.TrimSpace(strings.Join(lines[1:], "\n"))
 67			if len(commitBody) > 200 {
 68				commitBody = commitBody[:200] + "..."
 69			}
 70		}
 71	}
 72
 73	repoDisplayName := repo.ProjectName()
 74	if repoDisplayName == "" {
 75		repoDisplayName = repo.Name()
 76	}
 77
 78	shortHash := hash
 79	if len(hash) > 7 {
 80		shortHash = hash[:7]
 81	}
 82
 83	data := CommitData{
 84		RepoBaseData: RepoBaseData{
 85			BaseData: BaseData{
 86				ServerName:  cfg.Name,
 87				ActiveTab:   "commits",
 88				Title:       commitSubject + " | " + repoDisplayName + "@" + shortHash,
 89				Description: commitBody,
 90			},
 91			Repo:          repo,
 92			DefaultBranch: defaultBranch,
 93			HasGitBug:     hasGitBug(ctx, repo),
 94		},
 95		Commit:    commit,
 96		Diff:      diff,
 97		ParentIDs: parentIDs,
 98	}
 99
100	renderHTML(w, "commit.html", data)
101}
102
103func repoCommitPatch(w http.ResponseWriter, r *http.Request) {
104	ctx := r.Context()
105	logger := log.FromContext(ctx)
106	repo := proto.RepositoryFromContext(ctx)
107	vars := mux.Vars(r)
108	hash := vars["hash"]
109
110	gr, err := openRepository(repo)
111	if err != nil {
112		logger.Debug("failed to open repository", "repo", repo.Name(), "err", err)
113		renderInternalServerError(w, r)
114		return
115	}
116
117	_, err = gr.CatFileCommit(hash)
118	if err != nil {
119		logger.Debug("failed to get commit", "repo", repo.Name(), "hash", hash, "err", err)
120		renderNotFound(w, r)
121		return
122	}
123
124	w.Header().Set("Content-Type", "text/plain; charset=utf-8")
125	if err := gr.RawDiff(hash, git.RawDiffPatch, w); err != nil {
126		logger.Debug("failed to generate patch", "repo", repo.Name(), "hash", hash, "err", err)
127	}
128}
129
130func repoCommitDiff(w http.ResponseWriter, r *http.Request) {
131	ctx := r.Context()
132	logger := log.FromContext(ctx)
133	repo := proto.RepositoryFromContext(ctx)
134	vars := mux.Vars(r)
135	hash := vars["hash"]
136
137	gr, err := openRepository(repo)
138	if err != nil {
139		logger.Debug("failed to open repository", "repo", repo.Name(), "err", err)
140		renderInternalServerError(w, r)
141		return
142	}
143
144	_, err = gr.CatFileCommit(hash)
145	if err != nil {
146		logger.Debug("failed to get commit", "repo", repo.Name(), "hash", hash, "err", err)
147		renderNotFound(w, r)
148		return
149	}
150
151	w.Header().Set("Content-Type", "text/plain; charset=utf-8")
152	if err := gr.RawDiff(hash, git.RawDiffNormal, w); err != nil {
153		logger.Debug("failed to generate diff", "repo", repo.Name(), "hash", hash, "err", err)
154	}
155}