Skip to content

Commit 2874ab5

Browse files
authored
Add language statistics API endpoint (#11737)
* Add language statistics API * Add tests
1 parent 94f60e1 commit 2874ab5

File tree

5 files changed

+184
-0
lines changed

5 files changed

+184
-0
lines changed
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
// Copyright 2020 The Gitea Authors. All rights reserved.
2+
// Use of this source code is governed by a MIT-style
3+
// license that can be found in the LICENSE file.
4+
5+
package integrations
6+
7+
import (
8+
"net/http"
9+
"net/url"
10+
"testing"
11+
12+
"github.com/stretchr/testify/assert"
13+
)
14+
15+
func TestRepoLanguages(t *testing.T) {
16+
onGiteaRun(t, func(t *testing.T, u *url.URL) {
17+
session := loginUser(t, "user2")
18+
19+
// Request editor page
20+
req := NewRequest(t, "GET", "/user2/repo1/_new/master/")
21+
resp := session.MakeRequest(t, req, http.StatusOK)
22+
23+
doc := NewHTMLParser(t, resp.Body)
24+
lastCommit := doc.GetInputValueByName("last_commit")
25+
assert.NotEmpty(t, lastCommit)
26+
27+
// Save new file to master branch
28+
req = NewRequestWithValues(t, "POST", "/user2/repo1/_new/master/", map[string]string{
29+
"_csrf": doc.GetCSRF(),
30+
"last_commit": lastCommit,
31+
"tree_path": "test.go",
32+
"content": "package main",
33+
"commit_choice": "direct",
34+
})
35+
session.MakeRequest(t, req, http.StatusFound)
36+
37+
// Save new file to master branch
38+
req = NewRequest(t, "GET", "/api/v1/repos/user2/repo1/languages")
39+
resp = session.MakeRequest(t, req, http.StatusOK)
40+
41+
var languages map[string]int64
42+
DecodeJSON(t, resp, &languages)
43+
44+
assert.InDeltaMapValues(t, map[string]int64{"Go": 12}, languages, 0)
45+
})
46+
}

routers/api/v1/api.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -855,6 +855,7 @@ func RegisterRoutes(m *macaron.Macaron) {
855855
Delete(reqToken(), repo.DeleteTopic)
856856
}, reqAdmin())
857857
}, reqAnyRepoReader())
858+
m.Get("/languages", reqRepoReader(models.UnitTypeCode), repo.GetLanguages)
858859
}, repoAssignment())
859860
})
860861

routers/api/v1/repo/language.go

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
// Copyright 2020 The Gitea Authors. All rights reserved.
2+
// Use of this source code is governed by a MIT-style
3+
// license that can be found in the LICENSE file.
4+
5+
package repo
6+
7+
import (
8+
"bytes"
9+
"net/http"
10+
"strconv"
11+
12+
"code.gitea.io/gitea/models"
13+
"code.gitea.io/gitea/modules/context"
14+
"code.gitea.io/gitea/modules/log"
15+
)
16+
17+
type languageResponse []*models.LanguageStat
18+
19+
func (l languageResponse) MarshalJSON() ([]byte, error) {
20+
var buf bytes.Buffer
21+
if _, err := buf.WriteString("{"); err != nil {
22+
return nil, err
23+
}
24+
for i, lang := range l {
25+
if i > 0 {
26+
if _, err := buf.WriteString(","); err != nil {
27+
return nil, err
28+
}
29+
}
30+
if _, err := buf.WriteString(strconv.Quote(lang.Language)); err != nil {
31+
return nil, err
32+
}
33+
if _, err := buf.WriteString(":"); err != nil {
34+
return nil, err
35+
}
36+
if _, err := buf.WriteString(strconv.FormatInt(lang.Size, 10)); err != nil {
37+
return nil, err
38+
}
39+
}
40+
if _, err := buf.WriteString("}"); err != nil {
41+
return nil, err
42+
}
43+
44+
return buf.Bytes(), nil
45+
}
46+
47+
// GetLanguages returns languages and number of bytes of code written
48+
func GetLanguages(ctx *context.APIContext) {
49+
// swagger:operation GET /repos/{owner}/{repo}/languages repository repoGetLanguages
50+
// ---
51+
// summary: Get languages and number of bytes of code written
52+
// produces:
53+
// - application/json
54+
// parameters:
55+
// - name: owner
56+
// in: path
57+
// description: owner of the repo
58+
// type: string
59+
// required: true
60+
// - name: repo
61+
// in: path
62+
// description: name of the repo
63+
// type: string
64+
// required: true
65+
// responses:
66+
// "404":
67+
// "$ref": "#/responses/notFound"
68+
// "200":
69+
// "$ref": "#/responses/LanguageStatistics"
70+
71+
langs, err := ctx.Repo.Repository.GetLanguageStats()
72+
if err != nil {
73+
log.Error("GetLanguageStats failed: %v", err)
74+
ctx.InternalServerError(err)
75+
return
76+
}
77+
78+
resp := make(languageResponse, len(langs))
79+
for i, v := range langs {
80+
resp[i] = v
81+
}
82+
83+
ctx.JSON(http.StatusOK, resp)
84+
}

routers/api/v1/swagger/repo.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -302,3 +302,10 @@ type swaggerTopicNames struct {
302302
// in: body
303303
Body api.TopicName `json:"body"`
304304
}
305+
306+
// LanguageStatistics
307+
// swagger:response LanguageStatistics
308+
type swaggerLanguageStatistics struct {
309+
// in: body
310+
Body map[string]int64 `json:"body"`
311+
}

templates/swagger/v1_json.tmpl

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6049,6 +6049,42 @@
60496049
}
60506050
}
60516051
},
6052+
"/repos/{owner}/{repo}/languages": {
6053+
"get": {
6054+
"produces": [
6055+
"application/json"
6056+
],
6057+
"tags": [
6058+
"repository"
6059+
],
6060+
"summary": "Get languages and number of bytes of code written",
6061+
"operationId": "repoGetLanguages",
6062+
"parameters": [
6063+
{
6064+
"type": "string",
6065+
"description": "owner of the repo",
6066+
"name": "owner",
6067+
"in": "path",
6068+
"required": true
6069+
},
6070+
{
6071+
"type": "string",
6072+
"description": "name of the repo",
6073+
"name": "repo",
6074+
"in": "path",
6075+
"required": true
6076+
}
6077+
],
6078+
"responses": {
6079+
"200": {
6080+
"$ref": "#/responses/LanguageStatistics"
6081+
},
6082+
"404": {
6083+
"$ref": "#/responses/notFound"
6084+
}
6085+
}
6086+
}
6087+
},
60526088
"/repos/{owner}/{repo}/milestones": {
60536089
"get": {
60546090
"produces": [
@@ -14917,6 +14953,16 @@
1491714953
}
1491814954
}
1491914955
},
14956+
"LanguageStatistics": {
14957+
"description": "LanguageStatistics",
14958+
"schema": {
14959+
"type": "object",
14960+
"additionalProperties": {
14961+
"type": "integer",
14962+
"format": "int64"
14963+
}
14964+
}
14965+
},
1492014966
"MarkdownRender": {
1492114967
"description": "MarkdownRender is a rendered markdown document",
1492214968
"schema": {

0 commit comments

Comments
 (0)