mirror of
				https://github.com/go-gitea/gitea
				synced 2025-11-04 05:18:25 +00:00 
			
		
		
		
	Add language statistics API endpoint (#11737)
* Add language statistics API * Add tests
This commit is contained in:
		
							
								
								
									
										46
									
								
								integrations/api_repo_languages_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										46
									
								
								integrations/api_repo_languages_test.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,46 @@
 | 
				
			|||||||
 | 
					// Copyright 2020 The Gitea Authors. All rights reserved.
 | 
				
			||||||
 | 
					// Use of this source code is governed by a MIT-style
 | 
				
			||||||
 | 
					// license that can be found in the LICENSE file.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					package integrations
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"net/http"
 | 
				
			||||||
 | 
						"net/url"
 | 
				
			||||||
 | 
						"testing"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						"github.com/stretchr/testify/assert"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func TestRepoLanguages(t *testing.T) {
 | 
				
			||||||
 | 
						onGiteaRun(t, func(t *testing.T, u *url.URL) {
 | 
				
			||||||
 | 
							session := loginUser(t, "user2")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// Request editor page
 | 
				
			||||||
 | 
							req := NewRequest(t, "GET", "/user2/repo1/_new/master/")
 | 
				
			||||||
 | 
							resp := session.MakeRequest(t, req, http.StatusOK)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							doc := NewHTMLParser(t, resp.Body)
 | 
				
			||||||
 | 
							lastCommit := doc.GetInputValueByName("last_commit")
 | 
				
			||||||
 | 
							assert.NotEmpty(t, lastCommit)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// Save new file to master branch
 | 
				
			||||||
 | 
							req = NewRequestWithValues(t, "POST", "/user2/repo1/_new/master/", map[string]string{
 | 
				
			||||||
 | 
								"_csrf":         doc.GetCSRF(),
 | 
				
			||||||
 | 
								"last_commit":   lastCommit,
 | 
				
			||||||
 | 
								"tree_path":     "test.go",
 | 
				
			||||||
 | 
								"content":       "package main",
 | 
				
			||||||
 | 
								"commit_choice": "direct",
 | 
				
			||||||
 | 
							})
 | 
				
			||||||
 | 
							session.MakeRequest(t, req, http.StatusFound)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// Save new file to master branch
 | 
				
			||||||
 | 
							req = NewRequest(t, "GET", "/api/v1/repos/user2/repo1/languages")
 | 
				
			||||||
 | 
							resp = session.MakeRequest(t, req, http.StatusOK)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							var languages map[string]int64
 | 
				
			||||||
 | 
							DecodeJSON(t, resp, &languages)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							assert.InDeltaMapValues(t, map[string]int64{"Go": 12}, languages, 0)
 | 
				
			||||||
 | 
						})
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -855,6 +855,7 @@ func RegisterRoutes(m *macaron.Macaron) {
 | 
				
			|||||||
							Delete(reqToken(), repo.DeleteTopic)
 | 
												Delete(reqToken(), repo.DeleteTopic)
 | 
				
			||||||
					}, reqAdmin())
 | 
										}, reqAdmin())
 | 
				
			||||||
				}, reqAnyRepoReader())
 | 
									}, reqAnyRepoReader())
 | 
				
			||||||
 | 
									m.Get("/languages", reqRepoReader(models.UnitTypeCode), repo.GetLanguages)
 | 
				
			||||||
			}, repoAssignment())
 | 
								}, repoAssignment())
 | 
				
			||||||
		})
 | 
							})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										84
									
								
								routers/api/v1/repo/language.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										84
									
								
								routers/api/v1/repo/language.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,84 @@
 | 
				
			|||||||
 | 
					// Copyright 2020 The Gitea Authors. All rights reserved.
 | 
				
			||||||
 | 
					// Use of this source code is governed by a MIT-style
 | 
				
			||||||
 | 
					// license that can be found in the LICENSE file.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					package repo
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"bytes"
 | 
				
			||||||
 | 
						"net/http"
 | 
				
			||||||
 | 
						"strconv"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						"code.gitea.io/gitea/models"
 | 
				
			||||||
 | 
						"code.gitea.io/gitea/modules/context"
 | 
				
			||||||
 | 
						"code.gitea.io/gitea/modules/log"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type languageResponse []*models.LanguageStat
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (l languageResponse) MarshalJSON() ([]byte, error) {
 | 
				
			||||||
 | 
						var buf bytes.Buffer
 | 
				
			||||||
 | 
						if _, err := buf.WriteString("{"); err != nil {
 | 
				
			||||||
 | 
							return nil, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						for i, lang := range l {
 | 
				
			||||||
 | 
							if i > 0 {
 | 
				
			||||||
 | 
								if _, err := buf.WriteString(","); err != nil {
 | 
				
			||||||
 | 
									return nil, err
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if _, err := buf.WriteString(strconv.Quote(lang.Language)); err != nil {
 | 
				
			||||||
 | 
								return nil, err
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if _, err := buf.WriteString(":"); err != nil {
 | 
				
			||||||
 | 
								return nil, err
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if _, err := buf.WriteString(strconv.FormatInt(lang.Size, 10)); err != nil {
 | 
				
			||||||
 | 
								return nil, err
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if _, err := buf.WriteString("}"); err != nil {
 | 
				
			||||||
 | 
							return nil, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return buf.Bytes(), nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// GetLanguages returns languages and number of bytes of code written
 | 
				
			||||||
 | 
					func GetLanguages(ctx *context.APIContext) {
 | 
				
			||||||
 | 
						// swagger:operation GET /repos/{owner}/{repo}/languages repository repoGetLanguages
 | 
				
			||||||
 | 
						// ---
 | 
				
			||||||
 | 
						// summary: Get languages and number of bytes of code written
 | 
				
			||||||
 | 
						// produces:
 | 
				
			||||||
 | 
						//   - application/json
 | 
				
			||||||
 | 
						// parameters:
 | 
				
			||||||
 | 
						// - name: owner
 | 
				
			||||||
 | 
						//   in: path
 | 
				
			||||||
 | 
						//   description: owner of the repo
 | 
				
			||||||
 | 
						//   type: string
 | 
				
			||||||
 | 
						//   required: true
 | 
				
			||||||
 | 
						// - name: repo
 | 
				
			||||||
 | 
						//   in: path
 | 
				
			||||||
 | 
						//   description: name of the repo
 | 
				
			||||||
 | 
						//   type: string
 | 
				
			||||||
 | 
						//   required: true
 | 
				
			||||||
 | 
						// responses:
 | 
				
			||||||
 | 
						//   "404":
 | 
				
			||||||
 | 
						//     "$ref": "#/responses/notFound"
 | 
				
			||||||
 | 
						//   "200":
 | 
				
			||||||
 | 
						//     "$ref": "#/responses/LanguageStatistics"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						langs, err := ctx.Repo.Repository.GetLanguageStats()
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							log.Error("GetLanguageStats failed: %v", err)
 | 
				
			||||||
 | 
							ctx.InternalServerError(err)
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						resp := make(languageResponse, len(langs))
 | 
				
			||||||
 | 
						for i, v := range langs {
 | 
				
			||||||
 | 
							resp[i] = v
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ctx.JSON(http.StatusOK, resp)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -302,3 +302,10 @@ type swaggerTopicNames struct {
 | 
				
			|||||||
	// in: body
 | 
						// in: body
 | 
				
			||||||
	Body api.TopicName `json:"body"`
 | 
						Body api.TopicName `json:"body"`
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// LanguageStatistics
 | 
				
			||||||
 | 
					// swagger:response LanguageStatistics
 | 
				
			||||||
 | 
					type swaggerLanguageStatistics struct {
 | 
				
			||||||
 | 
						// in: body
 | 
				
			||||||
 | 
						Body map[string]int64 `json:"body"`
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -6049,6 +6049,42 @@
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 | 
					    "/repos/{owner}/{repo}/languages": {
 | 
				
			||||||
 | 
					      "get": {
 | 
				
			||||||
 | 
					        "produces": [
 | 
				
			||||||
 | 
					          "application/json"
 | 
				
			||||||
 | 
					        ],
 | 
				
			||||||
 | 
					        "tags": [
 | 
				
			||||||
 | 
					          "repository"
 | 
				
			||||||
 | 
					        ],
 | 
				
			||||||
 | 
					        "summary": "Get languages and number of bytes of code written",
 | 
				
			||||||
 | 
					        "operationId": "repoGetLanguages",
 | 
				
			||||||
 | 
					        "parameters": [
 | 
				
			||||||
 | 
					          {
 | 
				
			||||||
 | 
					            "type": "string",
 | 
				
			||||||
 | 
					            "description": "owner of the repo",
 | 
				
			||||||
 | 
					            "name": "owner",
 | 
				
			||||||
 | 
					            "in": "path",
 | 
				
			||||||
 | 
					            "required": true
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					          {
 | 
				
			||||||
 | 
					            "type": "string",
 | 
				
			||||||
 | 
					            "description": "name of the repo",
 | 
				
			||||||
 | 
					            "name": "repo",
 | 
				
			||||||
 | 
					            "in": "path",
 | 
				
			||||||
 | 
					            "required": true
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					        ],
 | 
				
			||||||
 | 
					        "responses": {
 | 
				
			||||||
 | 
					          "200": {
 | 
				
			||||||
 | 
					            "$ref": "#/responses/LanguageStatistics"
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					          "404": {
 | 
				
			||||||
 | 
					            "$ref": "#/responses/notFound"
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
    "/repos/{owner}/{repo}/milestones": {
 | 
					    "/repos/{owner}/{repo}/milestones": {
 | 
				
			||||||
      "get": {
 | 
					      "get": {
 | 
				
			||||||
        "produces": [
 | 
					        "produces": [
 | 
				
			||||||
@@ -14917,6 +14953,16 @@
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 | 
					    "LanguageStatistics": {
 | 
				
			||||||
 | 
					      "description": "LanguageStatistics",
 | 
				
			||||||
 | 
					      "schema": {
 | 
				
			||||||
 | 
					        "type": "object",
 | 
				
			||||||
 | 
					        "additionalProperties": {
 | 
				
			||||||
 | 
					          "type": "integer",
 | 
				
			||||||
 | 
					          "format": "int64"
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
    "MarkdownRender": {
 | 
					    "MarkdownRender": {
 | 
				
			||||||
      "description": "MarkdownRender is a rendered markdown document",
 | 
					      "description": "MarkdownRender is a rendered markdown document",
 | 
				
			||||||
      "schema": {
 | 
					      "schema": {
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user