From ff73ca2348775297b289bfa2083cd7b91406a29f Mon Sep 17 00:00:00 2001 From: oppiliappan Date: Wed, 21 May 2025 17:18:34 +0100 Subject: [PATCH] appview: rework RepoLanguages - move endpoint on knot to /{did}/{name}/languages - remove buggy percentage calculation - fix endpoint to work on empty repos - allowing calling endpoint with empty ref --- appview/knotclient/signer.go | 30 +++++++++++--------- appview/pages/pages.go | 24 ++++++++-------- appview/state/repo.go | 27 +++++++++--------- knotserver/handler.go | 7 ++++- knotserver/routes.go | 53 +++++++----------------------------- types/repo.go | 2 +- 6 files changed, 59 insertions(+), 84 deletions(-) diff --git a/appview/knotclient/signer.go b/appview/knotclient/signer.go index 3b976a8..1cded40 100644 --- a/appview/knotclient/signer.go +++ b/appview/knotclient/signer.go @@ -106,19 +106,13 @@ func (s *SignedClient) NewRepo(did, repoName, defaultBranch string) (*http.Respo return s.client.Do(req) } -func (s *SignedClient) RepoLanguages(ownerDid, source, name, branch string) (*types.RepoLanguageResponse, error) { +func (s *SignedClient) RepoLanguages(ownerDid, repoName, ref string) (*types.RepoLanguageResponse, error) { const ( Method = "GET" ) - endpoint := fmt.Sprintf("/repo/languages/%s", url.PathEscape(branch)) + endpoint := fmt.Sprintf("/%s/%s/languages/%s", ownerDid, repoName, url.PathEscape(ref)) - body, _ := json.Marshal(map[string]any{ - "did": ownerDid, - "source": source, - "name": name, - }) - - req, err := s.newRequest(Method, endpoint, body) + req, err := s.newRequest(Method, endpoint, nil) if err != nil { return nil, err } @@ -128,13 +122,23 @@ func (s *SignedClient) RepoLanguages(ownerDid, source, name, branch string) (*ty return nil, err } - var languagePercentages types.RepoLanguageResponse - if err := json.NewDecoder(resp.Body).Decode(&languagePercentages); err != nil { - log.Printf("failed to decode fork status: %s", err) + var result types.RepoLanguageResponse + if resp.StatusCode != http.StatusOK { + log.Println("failed to calculate languages", resp.Status) + return &types.RepoLanguageResponse{}, nil + } + + body, err := io.ReadAll(resp.Body) + if err != nil { + return nil, err + } + + err = json.Unmarshal(body, &result) + if err != nil { return nil, err } - return &languagePercentages, nil + return &result, nil } func (s *SignedClient) RepoForkAheadBehind(ownerDid, source, name, branch, hiddenRef string) (*http.Response, error) { diff --git a/appview/pages/pages.go b/appview/pages/pages.go index 3fd6625..bfd04c2 100644 --- a/appview/pages/pages.go +++ b/appview/pages/pages.go @@ -403,19 +403,19 @@ func (p *Pages) RepoDescriptionFragment(w io.Writer, params RepoDescriptionParam } type RepoIndexParams struct { - LoggedInUser *oauth.User - RepoInfo repoinfo.RepoInfo - Active string - TagMap map[string][]string - CommitsTrunc []*object.Commit - TagsTrunc []*types.TagReference - BranchesTrunc []types.Branch - ForkInfo *types.ForkInfo + LoggedInUser *oauth.User + RepoInfo repoinfo.RepoInfo + Active string + TagMap map[string][]string + CommitsTrunc []*object.Commit + TagsTrunc []*types.TagReference + BranchesTrunc []types.Branch + ForkInfo *types.ForkInfo + HTMLReadme template.HTML + Raw bool + EmailToDidOrHandle map[string]string + Languages *types.RepoLanguageResponse types.RepoIndexResponse - HTMLReadme template.HTML - Raw bool - EmailToDidOrHandle map[string]string - LanguagePercentages map[string]float64 } func (p *Pages) RepoIndexPage(w io.Writer, params RepoIndexParams) error { diff --git a/appview/state/repo.go b/appview/state/repo.go index 976626c..aa63406 100644 --- a/appview/state/repo.go +++ b/appview/state/repo.go @@ -138,30 +138,30 @@ func (s *State) RepoIndex(w http.ResponseWriter, r *http.Request) { var forkInfo *types.ForkInfo if user != nil && (repoInfo.Roles.IsOwner() || repoInfo.Roles.IsCollaborator()) { - forkInfo, err = getForkInfo(repoInfo, s, f, w, user, signedClient) + forkInfo, err = getForkInfo(repoInfo, s, f, user, signedClient) if err != nil { log.Printf("Failed to fetch fork information: %v", err) return } } - repoLanguages, err := signedClient.RepoLanguages(user.Did, string(f.RepoAt), repoInfo.Name, f.Ref) + repoLanguages, err := signedClient.RepoLanguages(f.OwnerDid(), f.RepoName, ref) if err != nil { log.Printf("failed to compute language percentages: %s", err) - return + // non-fatal } s.pages.RepoIndexPage(w, pages.RepoIndexParams{ - LoggedInUser: user, - RepoInfo: repoInfo, - TagMap: tagMap, - RepoIndexResponse: result, - CommitsTrunc: commitsTrunc, - TagsTrunc: tagsTrunc, - ForkInfo: forkInfo, - BranchesTrunc: branchesTrunc, - EmailToDidOrHandle: EmailToDidOrHandle(s, emails), - LanguagePercentages: repoLanguages.Languages, + LoggedInUser: user, + RepoInfo: repoInfo, + TagMap: tagMap, + RepoIndexResponse: result, + CommitsTrunc: commitsTrunc, + TagsTrunc: tagsTrunc, + ForkInfo: forkInfo, + BranchesTrunc: branchesTrunc, + EmailToDidOrHandle: EmailToDidOrHandle(s, emails), + Languages: repoLanguages, }) return } @@ -170,7 +170,6 @@ func getForkInfo( repoInfo repoinfo.RepoInfo, s *State, f *FullyResolvedRepo, - w http.ResponseWriter, user *oauth.User, signedClient *knotclient.SignedClient, ) (*types.ForkInfo, error) { diff --git a/knotserver/handler.go b/knotserver/handler.go index 7b110db..7838afd 100644 --- a/knotserver/handler.go +++ b/knotserver/handler.go @@ -80,6 +80,12 @@ func Setup(ctx context.Context, c *config.Config, db *db.DB, e *rbac.Enforcer, j r.Post("/add", h.AddRepoCollaborator) }) + r.Route("/languages", func(r chi.Router) { + r.With(h.VerifySignature) + r.Get("/", h.RepoLanguages) + r.Get("/{ref}", h.RepoLanguages) + }) + r.Get("/", h.RepoIndex) r.Get("/info/refs", h.InfoRefs) r.Post("/git-upload-pack", h.UploadPack) @@ -126,7 +132,6 @@ func Setup(ctx context.Context, c *config.Config, db *db.DB, e *rbac.Enforcer, j r.Route("/repo", func(r chi.Router) { r.Use(h.VerifySignature) r.Put("/new", h.NewRepo) - r.Get("/languages/{branch}", h.RepoLanguages) r.Delete("/", h.RemoveRepo) r.Route("/fork", func(r chi.Router) { r.Post("/", h.RepoFork) diff --git a/knotserver/routes.go b/knotserver/routes.go index 890b04b..29dca92 100644 --- a/knotserver/routes.go +++ b/knotserver/routes.go @@ -715,50 +715,20 @@ func (h *Handle) RepoForkAheadBehind(w http.ResponseWriter, r *http.Request) { } func (h *Handle) RepoLanguages(w http.ResponseWriter, r *http.Request) { - l := h.l.With("handler", "RepoForkSync") - - data := struct { - Did string `json:"did"` - Source string `json:"source"` - Name string `json:"name,omitempty"` - }{} - - if err := json.NewDecoder(r.Body).Decode(&data); err != nil { - writeError(w, "invalid request body", http.StatusBadRequest) - return - } - - did := data.Did - source := data.Source - - if did == "" || source == "" { - l.Error("invalid request body, empty did or name") - w.WriteHeader(http.StatusBadRequest) - return - } - - var name string - if data.Name != "" { - name = data.Name - } else { - name = filepath.Base(source) - } - - branch := chi.URLParam(r, "branch") - branch, _ = url.PathUnescape(branch) + path, _ := securejoin.SecureJoin(h.c.Repo.ScanPath, didPath(r)) + ref := chi.URLParam(r, "ref") + ref, _ = url.PathUnescape(ref) - relativeRepoPath := filepath.Join(did, name) - repoPath, _ := securejoin.SecureJoin(h.c.Repo.ScanPath, relativeRepoPath) + l := h.l.With("handler", "RepoLanguages") - gr, err := git.Open(repoPath, branch) + gr, err := git.Open(path, ref) if err != nil { - log.Println(err) + l.Error("opening repo", "error", err.Error()) notFound(w) return } languageFileCount := make(map[string]int) - languagePercentage := make(map[string]float64) err = recurseEntireTree(gr, func(absPath string) { lang, safe := enry.GetLanguageByExtension(absPath) @@ -782,18 +752,15 @@ func (h *Handle) RepoLanguages(w http.ResponseWriter, r *http.Request) { } }, "") if err != nil { - log.Println(err) + l.Error("failed to recurse file tree", "error", err.Error()) writeError(w, err.Error(), http.StatusNoContent) return } - for path, fileCount := range languageFileCount { - percentage := float64(fileCount) / float64(len(languageFileCount)) * 100.0 - languagePercentage[path] = percentage - } + resp := types.RepoLanguageResponse{Languages: languageFileCount} - w.Header().Set("Content-Type", "application/json") - json.NewEncoder(w).Encode(types.RepoLanguageResponse{Languages: languagePercentage}) + writeJSON(w, resp) + return } func recurseEntireTree(git *git.GitRepo, callback func(absPath string), filePath string) error { diff --git a/types/repo.go b/types/repo.go index a55d80d..947398a 100644 --- a/types/repo.go +++ b/types/repo.go @@ -112,5 +112,5 @@ type AncestorCheckResponse struct { type RepoLanguageResponse struct { // Language: Percentage - Languages map[string]float64 `json:"languages"` + Languages map[string]int `json:"languages"` } -- 2.51.2