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 RepoBaseData
18 PaginationData
19 Ref string
20 Commits git.Commits
21}
22
23// repoCommits handles commit history view.
24func repoCommits(w http.ResponseWriter, r *http.Request) {
25 ctx := r.Context()
26 logger := log.FromContext(ctx)
27 cfg := config.FromContext(ctx)
28 repo := proto.RepositoryFromContext(ctx)
29 if repo == nil {
30 renderNotFound(w, r)
31 return
32 }
33 vars := mux.Vars(r)
34 ref := vars["ref"]
35
36 gr, err := openRepository(repo)
37 if err != nil {
38 logger.Debug("failed to open repository", "repo", repo.Name(), "err", err)
39 renderInternalServerError(w, r)
40 return
41 }
42
43 refObj, _, err := resolveAndBuildRef(gr, ref)
44 if err != nil {
45 logger.Debug("failed to resolve ref or commit", "repo", repo.Name(), "ref", ref, "err", err)
46 renderNotFound(w, r)
47 return
48 }
49
50 page := 1
51 if pageStr := r.URL.Query().Get("page"); pageStr != "" {
52 if p, err := strconv.Atoi(pageStr); err == nil && p > 0 {
53 page = p
54 }
55 }
56
57 totalCommits, err := gr.CountCommits(refObj)
58 if err != nil {
59 logger.Debug("failed to count commits", "repo", repo.Name(), "ref", ref, "err", err)
60 renderNotFound(w, r)
61 return
62 }
63
64 totalPages := int(math.Ceil(float64(totalCommits) / float64(defaultCommitsPerPage)))
65 if totalPages < 1 {
66 totalPages = 1
67 }
68
69 if page > totalPages {
70 page = totalPages
71 }
72 if page < 1 {
73 page = 1
74 }
75
76 commits, err := gr.CommitsByPage(refObj, page, defaultCommitsPerPage)
77 if err != nil {
78 logger.Debug("failed to get commits", "repo", repo.Name(), "ref", ref, "err", err)
79 renderNotFound(w, r)
80 return
81 }
82
83 defaultBranch := getDefaultBranch(gr)
84
85 repoDisplayName := repo.ProjectName()
86 if repoDisplayName == "" {
87 repoDisplayName = repo.Name()
88 }
89
90 data := CommitsData{
91 RepoBaseData: RepoBaseData{
92 BaseData: BaseData{
93 ServerName: cfg.Name,
94 ActiveTab: "commits",
95 Title: "Commits in " + ref + " | " + repoDisplayName,
96 },
97 Repo: repo,
98 DefaultBranch: defaultBranch,
99 },
100 PaginationData: PaginationData{
101 Page: page,
102 TotalPages: totalPages,
103 HasPrevPage: page > 1,
104 HasNextPage: page < totalPages,
105 },
106 Ref: ref,
107 Commits: commits,
108 }
109
110 renderHTML(w, "commits.html", data)
111}