diff --git a/appview/pages/pages.go b/appview/pages/pages.go index 5b9fe993..471f1262 100644 --- a/appview/pages/pages.go +++ b/appview/pages/pages.go @@ -185,3 +185,23 @@ type RepoTreeParams struct { func (p *Pages) RepoTree(w io.Writer, params RepoTreeParams) error { return p.execute("repo/tree", w, params) } + +type RepoBranchesParams struct { + LoggedInUser *auth.User + RepoInfo RepoInfo + types.RepoBranchesResponse +} + +func (p *Pages) RepoBranches(w io.Writer, params RepoBranchesParams) error { + return p.execute("repo/branches", w, params) +} + +type RepoTagsParams struct { + LoggedInUser *auth.User + RepoInfo RepoInfo + types.RepoTagsResponse +} + +func (p *Pages) RepoTags(w io.Writer, params RepoTagsParams) error { + return p.execute("repo/tags", w, params) +} diff --git a/appview/pages/templates/repo/branches.html b/appview/pages/templates/repo/branches.html new file mode 100644 index 00000000..89b880e5 --- /dev/null +++ b/appview/pages/templates/repo/branches.html @@ -0,0 +1,18 @@ +{{ define "title" }} + branches | {{ .RepoInfo.OwnerWithAt }} / + {{ .RepoInfo.Name }} +{{ end }} + +{{ define "content" }} + {{ $name := .RepoInfo.Name }} +

branches

+
+ {{ range .Branches }} +
+ {{ .Name }} + browse + log +
+ {{ end }} +
+{{ end }} diff --git a/appview/pages/templates/repo/empty.html b/appview/pages/templates/repo/empty.html index 27332203..0ba2a347 100644 --- a/appview/pages/templates/repo/empty.html +++ b/appview/pages/templates/repo/empty.html @@ -1,9 +1,7 @@ - - {{ template "layouts/head" . }} +{{ define "title" }}{{ .RepoInfo.OwnerWithAt }} / {{ .RepoInfo.Name }}{{ end }} - -
-

This is an empty Git repository. Push some commits here.

- - - +{{ define "content" }} +
+

This is an empty Git repository. Push some commits here.

+
+{{ end }} diff --git a/appview/pages/templates/repo/refs.html b/appview/pages/templates/repo/refs.html deleted file mode 100644 index cb24aeb0..00000000 --- a/appview/pages/templates/repo/refs.html +++ /dev/null @@ -1,38 +0,0 @@ - -{{ template "layouts/head" . }} - - {{ template "layouts/repo-header" . }} - - {{ template "layouts/nav" . }} -
- {{ $name := .name }} -

branches

-
- {{ range .branches }} -
- {{ .Name.Short }} - browse - log - tar.gz -
- {{ end }} -
- {{ if .tags }} -

tags

-
- {{ range .tags }} -
- {{ .Name }} - browse - log - tar.gz - {{ if .Message }} -
{{ .Message }}
-
- {{ end }} - {{ end }} -
- {{ end }} -
- - \ No newline at end of file diff --git a/appview/pages/templates/repo/tags.html b/appview/pages/templates/repo/tags.html new file mode 100644 index 00000000..3200dc7a --- /dev/null +++ b/appview/pages/templates/repo/tags.html @@ -0,0 +1,22 @@ +{{ define "title" }} + tags | {{ .RepoInfo.OwnerWithAt }} / + {{ .RepoInfo.Name }} +{{ end }} + +{{ define "content" }} + {{ $name := .RepoInfo.Name }} +

tags

+
+ {{ range .Tags }} +
+ {{ .Ref.Name }} + browse + log + tar.gz + {{ if .Message }} +
{{ .Message }}
+ {{ end }} +
+ {{ end }} +
+{{ end }} diff --git a/appview/state/repo.go b/appview/state/repo.go index 9d8458f5..a6a77300 100644 --- a/appview/state/repo.go +++ b/appview/state/repo.go @@ -175,6 +175,82 @@ func (s *State) RepoTree(w http.ResponseWriter, r *http.Request) { return } +func (s *State) RepoTags(w http.ResponseWriter, r *http.Request) { + repoName, knot, id, err := repoKnotAndId(r) + if err != nil { + log.Println("failed to get repo and knot", err) + return + } + + resp, err := http.Get(fmt.Sprintf("http://%s/%s/%s/tags", knot, id.DID.String(), repoName)) + if err != nil { + log.Println("failed to reach knotserver", err) + return + } + + body, err := io.ReadAll(resp.Body) + if err != nil { + log.Fatalf("Error reading response body: %v", err) + return + } + + var result types.RepoTagsResponse + err = json.Unmarshal(body, &result) + if err != nil { + log.Println("failed to parse response:", err) + return + } + + s.pages.RepoTags(w, pages.RepoTagsParams{ + LoggedInUser: s.auth.GetUser(r), + RepoInfo: pages.RepoInfo{ + OwnerDid: id.DID.String(), + OwnerHandle: id.Handle.String(), + Name: repoName, + }, + RepoTagsResponse: result, + }) + return +} + +func (s *State) RepoBranches(w http.ResponseWriter, r *http.Request) { + repoName, knot, id, err := repoKnotAndId(r) + if err != nil { + log.Println("failed to get repo and knot", err) + return + } + + resp, err := http.Get(fmt.Sprintf("http://%s/%s/%s/branches", knot, id.DID.String(), repoName)) + if err != nil { + log.Println("failed to reach knotserver", err) + return + } + + body, err := io.ReadAll(resp.Body) + if err != nil { + log.Fatalf("Error reading response body: %v", err) + return + } + + var result types.RepoBranchesResponse + err = json.Unmarshal(body, &result) + if err != nil { + log.Println("failed to parse response:", err) + return + } + + s.pages.RepoBranches(w, pages.RepoBranchesParams{ + LoggedInUser: s.auth.GetUser(r), + RepoInfo: pages.RepoInfo{ + OwnerDid: id.DID.String(), + OwnerHandle: id.Handle.String(), + Name: repoName, + }, + RepoBranchesResponse: result, + }) + return +} + func repoKnotAndId(r *http.Request) (string, string, identity.Identity, error) { repoName := chi.URLParam(r, "repo") knot, ok := r.Context().Value("knot").(string) diff --git a/appview/state/state.go b/appview/state/state.go index e3b57d94..c92d4dd7 100644 --- a/appview/state/state.go +++ b/appview/state/state.go @@ -614,6 +614,8 @@ func (s *State) UserRouter() http.Handler { r.Get("/*", s.RepoTree) }) r.Get("/commit/{ref}", s.RepoCommit) + r.Get("/branches", s.RepoBranches) + r.Get("/tags", s.RepoTags) // These routes get proxied to the knot r.Get("/info/refs", s.InfoRefs) diff --git a/knotserver/git/git.go b/knotserver/git/git.go index ecd9ddaa..acfa32e8 100644 --- a/knotserver/git/git.go +++ b/knotserver/git/git.go @@ -347,3 +347,11 @@ func (t *TagReference) Message() string { } return "" } + +func (t *TagReference) TagObject() *object.Tag { + return t.tag +} + +func (t *TagReference) Hash() plumbing.Hash { + return t.ref.Hash() +} diff --git a/knotserver/handler.go b/knotserver/handler.go index 5322275b..cce5669f 100644 --- a/knotserver/handler.go +++ b/knotserver/handler.go @@ -84,7 +84,8 @@ func Setup(ctx context.Context, c *config.Config, db *db.DB, e *rbac.Enforcer, l r.Get("/log/{ref}", h.Log) r.Get("/archive/{file}", h.Archive) r.Get("/commit/{ref}", h.Diff) - r.Get("/refs/", h.Refs) + r.Get("/tags", h.Tags) + r.Get("/branches", h.Branches) }) }) diff --git a/knotserver/routes.go b/knotserver/routes.go index a6612ab9..52a3209b 100644 --- a/knotserver/routes.go +++ b/knotserver/routes.go @@ -316,7 +316,7 @@ func (h *Handle) Diff(w http.ResponseWriter, r *http.Request) { return } -func (h *Handle) Refs(w http.ResponseWriter, r *http.Request) { +func (h *Handle) Tags(w http.ResponseWriter, r *http.Request) { path := filepath.Join(h.c.Repo.ScanPath, didPath(r)) l := h.l.With("handler", "Refs") @@ -329,7 +329,37 @@ func (h *Handle) Refs(w http.ResponseWriter, r *http.Request) { tags, err := gr.Tags() if err != nil { // Non-fatal, we *should* have at least one branch to show. - l.Error("getting tags", "error", err.Error()) + l.Warn("getting tags", "error", err.Error()) + } + + rtags := []*types.TagReference{} + for _, tag := range tags { + tr := types.TagReference{ + Ref: types.Reference{ + Name: tag.Name(), + Hash: tag.Hash().String(), + }, + Tag: tag.TagObject(), + } + rtags = append(rtags, &tr) + } + + resp := types.RepoTagsResponse{ + Tags: rtags, + } + + writeJSON(w, resp) + return +} + +func (h *Handle) Branches(w http.ResponseWriter, r *http.Request) { + path := filepath.Join(h.c.Repo.ScanPath, didPath(r)) + l := h.l.With("handler", "Branches") + + gr, err := git.Open(path, "") + if err != nil { + notFound(w) + return } branches, err := gr.Branches() @@ -339,13 +369,19 @@ func (h *Handle) Refs(w http.ResponseWriter, r *http.Request) { return } - data := make(map[string]interface{}) + bs := []types.Branch{} + for _, branch := range branches { + b := types.Branch{} + b.Hash = branch.Hash().String() + b.Name = branch.Name().Short() + bs = append(bs, b) + } - data["branches"] = branches - data["tags"] = tags - data["desc"] = getDescription(path) + resp := types.RepoBranchesResponse{ + Branches: bs, + } - writeJSON(w, data) + writeJSON(w, resp) return } diff --git a/types/repo.go b/types/repo.go index e2fccf63..904138bf 100644 --- a/types/repo.go +++ b/types/repo.go @@ -36,3 +36,26 @@ type RepoTreeResponse struct { DotDot string `json:"dotdot,omitempty"` Files []NiceTree `json:"files,omitempty"` } + +type TagReference struct { + Ref Reference `json:"ref,omitempty"` + Tag *object.Tag `json:"tag,omitempty"` + Message string `json:"message,omitempty"` +} + +type Reference struct { + Name string `json:"name"` + Hash string `json:"hash"` +} + +type Branch struct { + Reference `json:"reference"` +} + +type RepoTagsResponse struct { + Tags []*TagReference `json:"tags,omitempty"` +} + +type RepoBranchesResponse struct { + Branches []Branch `json:"branches,omitempty"` +}