Skip to content

Commit 0647ada

Browse files
committed
Add GitLab Statistics
Added star and fork statistics on detailed project view for projects with an valid GitLab URL. Ref: #4301
1 parent babeb7a commit 0647ada

File tree

6 files changed

+111
-40
lines changed

6 files changed

+111
-40
lines changed

tests/unit/packaging/test_models.py

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -328,6 +328,36 @@ def test_github_repo_info_url(self, db_session, home_page, expected):
328328
release = DBReleaseFactory.create(home_page=home_page)
329329
assert release.github_repo_info_url == expected
330330

331+
@pytest.mark.parametrize(
332+
("home_page", "expected"),
333+
[
334+
(None, None),
335+
(
336+
"https://gitlab.com/user/project",
337+
"https://gitlab.com/api/v4/projects/user%2Fproject",
338+
),
339+
(
340+
"https://gitlab.com/user/project/",
341+
"https://gitlab.com/api/v4/projects/user%2Fproject",
342+
),
343+
(
344+
"https://gitlab.com/user/project/tree/master",
345+
"https://gitlab.com/api/v4/projects/user%2Fproject",
346+
),
347+
(
348+
"https://www.gitlab.com/user/project",
349+
"https://gitlab.com/api/v4/projects/user%2Fproject",
350+
),
351+
("https://gitlab.com/user/", None),
352+
("https://google.com/user/project/tree/master", None),
353+
("https://google.com", None),
354+
("incorrect url", None),
355+
],
356+
)
357+
def test_gitlab_repo_info_url(self, db_session, home_page, expected):
358+
release = DBReleaseFactory.create(home_page=home_page)
359+
assert release.gitlab_repo_info_url == expected
360+
331361

332362
class TestFile:
333363
def test_requires_python(self, db_session):

tests/unit/test_csp.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -201,6 +201,7 @@ def test_includeme():
201201
"connect-src": [
202202
"'self'",
203203
"https://github.com/api/repos/",
204+
"https://gitlab.com/api/v4/projects/",
204205
"*.fastly-insights.com",
205206
"sentry.io",
206207
"https://2p66nmmycsj3.statuspage.io",

warehouse/csp.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@ def includeme(config):
8181
"connect-src": [
8282
SELF,
8383
"https://github.com/api/repos/",
84+
"https://gitlab.com/api/v4/projects/",
8485
"*.fastly-insights.com",
8586
"sentry.io",
8687
]

warehouse/packaging/models.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -413,6 +413,18 @@ def github_repo_info_url(self):
413413
user_name, repo_name = segments[:2]
414414
return f"https://github.com/api/repos/{user_name}/{repo_name}"
415415

416+
@property
417+
def gitlab_repo_info_url(self):
418+
# import pdb; pdb.set_trace()
419+
for parsed in [urlparse(url) for url in self.urls.values()]:
420+
segments = parsed.path.strip("/").rstrip("/").split("/")
421+
422+
if (
423+
parsed.netloc == "gitlab.com" or parsed.netloc == "www.gitlab.com"
424+
) and len(segments) >= 2:
425+
user_name, repo_name = segments[:2]
426+
return f"https://gitlab.com/api/v4/projects/{user_name}%2F{repo_name}"
427+
416428
@property
417429
def has_meta(self):
418430
return any(

warehouse/static/js/warehouse/utils/repository-info.js

Lines changed: 47 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -12,46 +12,53 @@
1212
*/
1313

1414
export default () => {
15-
const repoInfoContainer = document.querySelector(".github-repo-info");
16-
if (repoInfoContainer !== null){
17-
const url = repoInfoContainer.dataset.url;
18-
fetch(url, {
19-
method: "GET",
20-
mode: "cors",
21-
}).then((response) => {
22-
if (response.ok){
23-
return response.json();
24-
} else {
25-
return null;
26-
}
27-
}).then((json) => {
28-
if (json === null){
29-
return;
30-
}
31-
repoInfoContainer.classList.remove("hidden");
32-
const items = document.querySelectorAll(".github-repo-info__item");
33-
items.forEach(function(elem) {
34-
const jsonKey = elem.dataset.key;
35-
let jsonValue = json[jsonKey];
36-
if(jsonValue !== undefined){
37-
const supplement = elem.dataset.supplement;
38-
if (supplement !== undefined) {
39-
jsonValue += supplement;
40-
}
41-
if (jsonKey.includes("_count")) {
42-
// Number formatting for count keys.
43-
jsonValue = jsonValue.toLocaleString();
44-
}
45-
const attr = elem.dataset.attr;
46-
if (attr !== undefined) {
47-
elem[attr] = jsonValue;
48-
} else {
49-
elem.innerText = jsonValue;
50-
}
15+
const services = [
16+
{wrapper: ".github-repo-info", items: ".github-repo-info__item"},
17+
{wrapper: ".gitlab-repo-info", items: ".gitlab-repo-info__item"}
18+
]
19+
20+
services.forEach((service) => {
21+
let repoInfoContainer = document.querySelector(service.wrapper);
22+
if (repoInfoContainer !== null){
23+
const url = repoInfoContainer.dataset.url;
24+
fetch(url, {
25+
method: "GET",
26+
mode: "cors",
27+
}).then((response) => {
28+
if (response.ok){
29+
return response.json();
30+
} else {
31+
return null;
32+
}
33+
}).then((json) => {
34+
if (json === null){
35+
return;
5136
}
52-
}, this);
53-
}).catch(function() {
37+
repoInfoContainer.classList.remove("hidden");
38+
const items = document.querySelectorAll(service.items);
39+
items.forEach(function(elem) {
40+
const jsonKey = elem.dataset.key;
41+
let jsonValue = json[jsonKey];
42+
if(jsonValue !== undefined){
43+
const supplement = elem.dataset.supplement;
44+
if (supplement !== undefined) {
45+
jsonValue += supplement;
46+
}
47+
if (jsonKey.includes("_count")) {
48+
// Number formatting for count keys.
49+
jsonValue = jsonValue.toLocaleString();
50+
}
51+
const attr = elem.dataset.attr;
52+
if (attr !== undefined) {
53+
elem[attr] = jsonValue;
54+
} else {
55+
elem.innerText = jsonValue;
56+
}
57+
}
58+
}, this);
59+
}).catch(function() {
5460

55-
});
56-
}
61+
});
62+
}
63+
});
5764
};

warehouse/templates/includes/packaging/project-data.html

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,26 @@ <h3 class="sidebar-section__title">Statistics</h3>
5454
</a>
5555
</div>
5656
{% endif %}
57+
58+
{% if release.gitlab_repo_info_url %}
59+
<div class="gitlab-repo-info hidden" data-url="{{release.gitlab_repo_info_url}}">
60+
<em>GitLab statistics:</em>
61+
<a class="vertical-tabs__tab vertical-tabs__tab--with-icon vertical-tabs__tab--condensed gitlab-repo-info__item"
62+
data-key="html_url" data-attr="href" data-supplement="/stargazers" rel="noopener"
63+
target="_blank">
64+
<i class="fa fa-star" aria-hidden="true"></i>
65+
<strong>Stars: </strong>
66+
<span class="gitlab-repo-info__item" data-key="star_count"></span>
67+
</a>
68+
<a class="vertical-tabs__tab vertical-tabs__tab--with-icon vertical-tabs__tab--condensed gitlab-repo-info__item"
69+
data-key="html_url" data-attr="href" data-supplement="/network" rel="noopener"
70+
target="_blank">
71+
<i class="fa fa-code-branch" aria-hidden="true"></i>
72+
<strong>Forks: </strong>
73+
<span class="gitlab-repo-info__item" data-key="forks_count"></span>
74+
</a>
75+
</div>
76+
{% endif %}
5777
<p>View statistics for this project via <a
5878
href="https://libraries.io/pypi/{{ release.project.name }}">Libraries.io</a>, or by using
5979
<a href="https://packaging.python.org/guides/analyzing-pypi-package-downloads/">Google

0 commit comments

Comments
 (0)