1package web
2
3import (
4 "math"
5 "net/http"
6 "strconv"
7
8 "github.com/charmbracelet/log/v2"
9 "github.com/charmbracelet/soft-serve/git"
10 "github.com/charmbracelet/soft-serve/pkg/config"
11 "github.com/charmbracelet/soft-serve/pkg/proto"
12 "github.com/gorilla/mux"
13)
14
15// CommitsData contains data for rendering commit history.
16type CommitsData struct {
17 Repo proto.Repository
18 DefaultBranch string
19 Ref string
20 Commits git.Commits
21 ActiveTab string
22 Page int
23 TotalPages int
24 HasPrevPage bool
25 HasNextPage bool
26 ServerName string
27}
28
29// repoCommits handles commit history view.
30func repoCommits(w http.ResponseWriter, r *http.Request) {
31 ctx := r.Context()
32 logger := log.FromContext(ctx)
33 cfg := config.FromContext(ctx)
34 repo := proto.RepositoryFromContext(ctx)
35 if repo == nil {
36 renderNotFound(w, r)
37 return
38 }
39 vars := mux.Vars(r)
40 ref := vars["ref"]
41
42 gr, err := openRepository(repo)
43 if err != nil {
44 logger.Debug("failed to open repository", "repo", repo.Name(), "err", err)
45 renderInternalServerError(w, r)
46 return
47 }
48
49 refObj, err := resolveAndBuildRef(gr, ref)
50 if err != nil {
51 logger.Debug("failed to resolve ref or commit", "repo", repo.Name(), "ref", ref, "err", err)
52 renderNotFound(w, r)
53 return
54 }
55
56 page := 1
57 if pageStr := r.URL.Query().Get("page"); pageStr != "" {
58 if p, err := strconv.Atoi(pageStr); err == nil && p > 0 {
59 page = p
60 }
61 }
62
63 totalCommits, err := gr.CountCommits(refObj)
64 if err != nil {
65 logger.Debug("failed to count commits", "repo", repo.Name(), "ref", ref, "err", err)
66 renderNotFound(w, r)
67 return
68 }
69
70 totalPages := int(math.Ceil(float64(totalCommits) / float64(defaultCommitsPerPage)))
71 if totalPages < 1 {
72 totalPages = 1
73 }
74
75 if page > totalPages {
76 page = totalPages
77 }
78 if page < 1 {
79 page = 1
80 }
81
82 commits, err := gr.CommitsByPage(refObj, page, defaultCommitsPerPage)
83 if err != nil {
84 logger.Debug("failed to get commits", "repo", repo.Name(), "ref", ref, "err", err)
85 renderNotFound(w, r)
86 return
87 }
88
89 defaultBranch := getDefaultBranch(gr)
90
91 data := CommitsData{
92 Repo: repo,
93 DefaultBranch: defaultBranch,
94 Ref: ref,
95 Commits: commits,
96 ActiveTab: "commits",
97 Page: page,
98 TotalPages: totalPages,
99 HasPrevPage: page > 1,
100 HasNextPage: page < totalPages,
101 ServerName: cfg.Name,
102 }
103
104 renderHTML(w, "commits.html", data)
105}