Skip to content

Commit 43257b0

Browse files
infer bug_tracking_url and code_view_url from vcs_url
Signed-off-by: Kaushik Kumar <kaushikrjpm10@gmail.com>
1 parent f620729 commit 43257b0

3 files changed

Lines changed: 93 additions & 0 deletions

File tree

src/packagedcode/models.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -768,6 +768,8 @@ def from_data(cls, package_data, package_only=False):
768768
else:
769769
package_data.normalize_extracted_license_statement()
770770

771+
package_data.infer_vcs_urls()
772+
771773
return package_data
772774

773775
@property
@@ -857,6 +859,16 @@ def populate_license_fields(self):
857859

858860
self.normalize_extracted_license_statement()
859861

862+
def infer_vcs_urls(self):
863+
from packagedcode.utils import parse_vcs_urls
864+
if not self.vcs_url:
865+
return
866+
code_view, bug_track = parse_vcs_urls(self.vcs_url)
867+
if not self.code_view_url and code_view:
868+
self.code_view_url = code_view
869+
if not self.bug_tracking_url and bug_track:
870+
self.bug_tracking_url = bug_track
871+
860872
def update_purl_fields(self, package_data, replace=False):
861873

862874
if not self.type == package_data.type:

src/packagedcode/utils.py

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@
77
# See https://aboutcode.org for more information about nexB OSS projects.
88
#
99

10+
from urllib.parse import urlsplit
11+
1012
from packageurl import PackageURL
1113

1214
try:
@@ -114,6 +116,42 @@ def normalize_vcs_url(repo_url, vcs_tool=None):
114116
return repo_url
115117

116118

119+
# map known VCS host -> bug_tracking_url suffix to append
120+
BUG_TRACKING_SUFFIXES = {
121+
'github.com': '/issues',
122+
'gitlab.com': '/-/issues',
123+
'codeberg.org': '/issues',
124+
'bitbucket.org': '/issues',
125+
}
126+
127+
128+
def parse_vcs_urls(vcs_url):
129+
'''
130+
given a vcs_url, return (code_view_url, bug_tracking_url) when the
131+
host platform is recognized, otherwise (None, None)
132+
'''
133+
cleaned = normalize_vcs_url(vcs_url)
134+
if not cleaned:
135+
return None, None
136+
137+
if cleaned.endswith('.git'):
138+
cleaned = cleaned[:-4]
139+
140+
# urlsplit does not handle git@ SSH form, e.g. git@github.com:owner/repo
141+
if cleaned.startswith('git@'):
142+
cleaned = 'https://' + cleaned[4:].replace(':', '/')
143+
144+
parsed = urlsplit(cleaned)
145+
host = parsed.netloc.lower()
146+
path = parsed.path.rstrip('/')
147+
base = f'https://{host}{path}'
148+
149+
suffix = BUG_TRACKING_SUFFIXES.get(host)
150+
if suffix:
151+
return base, base + suffix
152+
return None, None
153+
154+
117155
def build_description(summary, description):
118156
"""
119157
Return a description string from a summary and description

tests/packagedcode/test_utils.py

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
from unittest import TestCase
1111

1212
from packagedcode.utils import normalize_vcs_url
13+
from packagedcode.utils import parse_vcs_urls
1314

1415

1516
class TestPackageUtils(TestCase):
@@ -128,3 +129,45 @@ def test_normalize_vcs_url_does_not_fail_on_empty(self):
128129
assert normalize_vcs_url(None) == None
129130
assert normalize_vcs_url('') == None
130131
assert normalize_vcs_url(' ') == None
132+
133+
# parse_vcs_urls tests
134+
135+
def test_parse_vcs_urls_github_git_ssh(self):
136+
code, bugs = parse_vcs_urls('git@github.com:owner/repo.git')
137+
assert code == 'https://github.com/owner/repo'
138+
assert bugs == 'https://github.com/owner/repo/issues'
139+
140+
def test_parse_vcs_urls_github_https(self):
141+
code, bugs = parse_vcs_urls('https://github.com/owner/repo.git')
142+
assert code == 'https://github.com/owner/repo'
143+
assert bugs == 'https://github.com/owner/repo/issues'
144+
145+
def test_parse_vcs_urls_github_git_plus_https(self):
146+
code, bugs = parse_vcs_urls('git+https://github.com/owner/repo.git')
147+
assert code == 'https://github.com/owner/repo'
148+
assert bugs == 'https://github.com/owner/repo/issues'
149+
150+
def test_parse_vcs_urls_gitlab(self):
151+
code, bugs = parse_vcs_urls('git+https://gitlab.com/owner/repo')
152+
assert code == 'https://gitlab.com/owner/repo'
153+
assert bugs == 'https://gitlab.com/owner/repo/-/issues'
154+
155+
def test_parse_vcs_urls_bitbucket_git_ssh(self):
156+
code, bugs = parse_vcs_urls('git@bitbucket.org:owner/repo')
157+
assert code == 'https://bitbucket.org/owner/repo'
158+
assert bugs == 'https://bitbucket.org/owner/repo/issues'
159+
160+
def test_parse_vcs_urls_codeberg(self):
161+
code, bugs = parse_vcs_urls('https://codeberg.org/owner/repo.git')
162+
assert code == 'https://codeberg.org/owner/repo'
163+
assert bugs == 'https://codeberg.org/owner/repo/issues'
164+
165+
def test_parse_vcs_urls_unknown_host(self):
166+
code, bugs = parse_vcs_urls('https://gitea.example.com/owner/repo.git')
167+
assert code is None
168+
assert bugs is None
169+
170+
def test_parse_vcs_urls_empty(self):
171+
assert parse_vcs_urls(None) == (None, None)
172+
assert parse_vcs_urls('') == (None, None)
173+
assert parse_vcs_urls(' ') == (None, None)

0 commit comments

Comments
 (0)