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)
 | 
			
		||||
					}, reqAdmin())
 | 
			
		||||
				}, reqAnyRepoReader())
 | 
			
		||||
				m.Get("/languages", reqRepoReader(models.UnitTypeCode), repo.GetLanguages)
 | 
			
		||||
			}, 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
 | 
			
		||||
	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": {
 | 
			
		||||
      "get": {
 | 
			
		||||
        "produces": [
 | 
			
		||||
@@ -14917,6 +14953,16 @@
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "LanguageStatistics": {
 | 
			
		||||
      "description": "LanguageStatistics",
 | 
			
		||||
      "schema": {
 | 
			
		||||
        "type": "object",
 | 
			
		||||
        "additionalProperties": {
 | 
			
		||||
          "type": "integer",
 | 
			
		||||
          "format": "int64"
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "MarkdownRender": {
 | 
			
		||||
      "description": "MarkdownRender is a rendered markdown document",
 | 
			
		||||
      "schema": {
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user