Skip to content

Commit 9fa7366

Browse files
committed
htmlreport: support remote GitHub/GitLab links for source files
Motivation: Cppcheck-htmlreport previously generated local annotated HTML for all source files. For private or large repositories, generating local HTML is unnecessary and cumbersome. It consumes additional disk space, increases report generation time, and duplicates functionality already provided by GitHub/GitLab browseable HTML pages. This patch allows the cppcheck report itself to be public, while the actual source code remains protected on GitHub/GitLab using their standard access controls. Changes: - Detect --source-dir URLs pointing to GitHub/GitLab. - Use remote URLs in index.html instead of generating local HTML for those files. - Line numbers link directly to GitHub/GitLab with proper anchors (#L123). - Remote links open in a new tab (target="_blank"), preserving local HTML behavior for normal files. Signed-off-by: Robin Getz <[email protected]>
1 parent d1e4660 commit 9fa7366

File tree

1 file changed

+30
-5
lines changed

1 file changed

+30
-5
lines changed

htmlreport/cppcheck-htmlreport

Lines changed: 30 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -494,9 +494,20 @@ def tr_str(td_th, line, id, cwe, severity, classification, guideline, message, t
494494
if classification:
495495
items.extend([classification, guideline])
496496
if htmlfile:
497-
ret += '<%s><a href="%s#line-%d">%d</a></%s>' % (td_th, htmlfile, line, line, td_th)
497+
if htmlfile.startswith("http://") or htmlfile.startswith("https://"):
498+
# GitHub/GitLab style line anchor
499+
href = f"{htmlfile.rstrip('#L1')}#L{line}"
500+
# Emit **line number with link**
501+
ret += f'<{td_th}><a href="{href}" target="_blank" rel="noopener noreferrer">{line}</a></{td_th}>'
502+
else:
503+
# local HTML annotated
504+
href = f"{htmlfile}#line-{line}"
505+
# Emit **line number with link**
506+
ret += f'<{td_th}><a href="{href}">{line}</a></{td_th}>'
507+
508+
# Emit id, cwe, severity, classification, ...
498509
for item in items:
499-
ret += '<%s>%s</%s>' % (td_th, item, td_th)
510+
ret += f'<{td_th}>{item}</{td_th}>'
500511
else:
501512
items.insert(0,line)
502513
for item in items:
@@ -705,6 +716,10 @@ def main() -> None:
705716
if options.source_dir:
706717
source_dir = options.source_dir
707718

719+
is_remote = False
720+
if source_dir.startswith("http://") or source_dir.startswith("https://"):
721+
is_remote = True
722+
708723
add_author_information = []
709724
if options.add_author_information:
710725
fields = [x.strip() for x in options.add_author_information.split(',')]
@@ -753,9 +768,14 @@ def main() -> None:
753768
for error in contentHandler.errors:
754769
filename = error['file']
755770
if filename not in files:
756-
files[filename] = {
757-
'errors': [], 'htmlfile': str(file_no) + '.html'}
758-
file_no = file_no + 1
771+
if is_remote:
772+
# Construct remote URL for GitHub/GitLab
773+
# tr_str() will use the actual line number, so we can just start with line 1
774+
remote_url = source_dir.rstrip('/') + '/' + filename + '#L1'
775+
files[filename] = {'errors': [], 'htmlfile': remote_url}
776+
else:
777+
files[filename] = {'errors': [], 'htmlfile': str(file_no) + '.html'}
778+
file_no += 1
759779
files[filename]['errors'].append(error)
760780

761781
# Make sure that the report directory is created if it doesn't exist.
@@ -795,6 +815,11 @@ def main() -> None:
795815
if filename == '':
796816
continue
797817

818+
if is_remote:
819+
# Remote source: do NOT generate local annotated HTML files.
820+
# The index will still point directly to GitHub/GitLab URLs.
821+
continue
822+
798823
source_filename = os.path.join(source_dir, filename)
799824
try:
800825
with io.open(source_filename, 'r', encoding=options.source_encoding) as input_file:

0 commit comments

Comments
 (0)