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}