From 5ca17eeae25965f084dccb326120a4b171b7a095 Mon Sep 17 00:00:00 2001 From: Robin Getz Date: Thu, 27 Nov 2025 16:29:34 -0500 Subject: [PATCH] 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. - Add doc in md pages Signed-off-by: Robin Getz --- htmlreport/cppcheck-htmlreport | 39 ++++++++++++++++++++++++++++------ man/manual-premium.md | 31 +++++++++++++++++++++++++-- man/manual.md | 31 +++++++++++++++++++++++++-- 3 files changed, 91 insertions(+), 10 deletions(-) diff --git a/htmlreport/cppcheck-htmlreport b/htmlreport/cppcheck-htmlreport index b33699ca2ed..5fd2f5017a7 100755 --- a/htmlreport/cppcheck-htmlreport +++ b/htmlreport/cppcheck-htmlreport @@ -494,9 +494,20 @@ def tr_str(td_th, line, id, cwe, severity, classification, guideline, message, t if classification: items.extend([classification, guideline]) if htmlfile: - ret += '<%s>%d' % (td_th, htmlfile, line, line, td_th) + if htmlfile.startswith("http://") or htmlfile.startswith("https://"): + # GitHub/GitLab style line anchor + href = f"{htmlfile.rstrip('#L1')}#L{line}" + # Emit **line number with link** + ret += f'<{td_th}>{line}' + else: + # local HTML annotated + href = f"{htmlfile}#line-{line}" + # Emit **line number with link** + ret += f'<{td_th}>{line}' + + # Emit id, cwe, severity, classification, ... for item in items: - ret += '<%s>%s' % (td_th, item, td_th) + ret += f'<{td_th}>{item}' else: items.insert(0,line) for item in items: @@ -675,7 +686,9 @@ def main() -> None: 'written.') parser.add_argument('--source-dir', dest='source_dir', help='Base directory where source code files can be ' - 'found.') + 'found, or a URL to a remote GitHub/GitLab ' + 'repository including a branch, e.g. ' + '--source-dir=https://github.com///blob//') parser.add_argument('--add-author-information', dest='add_author_information', help='Blame information to include. ' 'Adds specified author information. ' @@ -705,6 +718,10 @@ def main() -> None: if options.source_dir: source_dir = options.source_dir + is_remote = False + if source_dir.startswith("http://") or source_dir.startswith("https://"): + is_remote = True + add_author_information = [] if options.add_author_information: fields = [x.strip() for x in options.add_author_information.split(',')] @@ -753,9 +770,14 @@ def main() -> None: for error in contentHandler.errors: filename = error['file'] if filename not in files: - files[filename] = { - 'errors': [], 'htmlfile': str(file_no) + '.html'} - file_no = file_no + 1 + if is_remote: + # Construct remote URL for GitHub/GitLab + # tr_str() will use the actual line number, so we can just start with line 1 + remote_url = source_dir.rstrip('/') + '/' + filename + '#L1' + files[filename] = {'errors': [], 'htmlfile': remote_url} + else: + files[filename] = {'errors': [], 'htmlfile': str(file_no) + '.html'} + file_no += 1 files[filename]['errors'].append(error) # Make sure that the report directory is created if it doesn't exist. @@ -795,6 +817,11 @@ def main() -> None: if filename == '': continue + if is_remote: + # Remote source: do NOT generate local annotated HTML files. + # The index will still point directly to GitHub/GitLab URLs. + continue + source_filename = os.path.join(source_dir, filename) try: with io.open(source_filename, 'r', encoding=options.source_encoding) as input_file: diff --git a/man/manual-premium.md b/man/manual-premium.md index 6ae337a9fb0..9f2e5992537 100644 --- a/man/manual-premium.md +++ b/man/manual-premium.md @@ -1158,14 +1158,41 @@ The output screen says: Default is reading from stdin. --report-dir=REPORT_DIR The directory where the html report content is written. - --source-dir=SOURCE_DIR - Base directory where source code files can be found. + --source-dir=SOURCE_DIR|URL + Base directory where source code files can be found, or + a URL to a remote GitHub/GitLab repository including a + branch, e.g.: + --source-dir=https://github.com///blob// Example usage: cppcheck gui/test.cpp --xml 2> err.xml cppcheck-htmlreport --file=err.xml --report-dir=test1 --source-dir=. +or + cppcheck gui/test.cpp --xml 2> err.xml + cppcheck-htmlreport --file=err.xml --report-dir=test1 \ + --source-dir=https://github.com///blob// + +## Choosing Between Local Annotated HTML and Remote Repository Links + +cppcheck-htmlreport supports two modes for linking to source files: + - Local annotated HTML files (default when `--source-dir` is a filesystem path) + - Remote GitHub/GitLab links (when `--source-dir` is a URL) + +Pointing `--source-dir` to a filesystem path generates local annotated HTML files. +This is useful when you need a fully self-contained report that works offline, +includes inline annotations, and is ideal for small or medium projects where +generation is fast. +Using a remote GitHub/GitLab URL avoids generating per-file HTML and keeps the +summary report lightweight and fast to produce. This mode is ideal when the +source is already hosted online and local duplication is unnecessary. +Remote mode is especially helpful when the HTML report may be public or widely +distributed but the source code should remain private, since access control is +handled by the hosting service. +In general, local mode fits air-gapped environments, while remote mode works +best for CI workflows and large or private repositories. + # Check Level ## Reduced diff --git a/man/manual.md b/man/manual.md index cc1182ab9ab..68a59109666 100644 --- a/man/manual.md +++ b/man/manual.md @@ -1182,14 +1182,41 @@ The output screen says: Default is reading from stdin. --report-dir=REPORT_DIR The directory where the html report content is written. - --source-dir=SOURCE_DIR - Base directory where source code files can be found. + --source-dir=SOURCE_DIR|URL + Base directory where source code files can be found, or + a URL to a remote GitHub/GitLab repository including a + branch, e.g.: + --source-dir=https://github.com///blob// Example usage: cppcheck gui/test.cpp --xml 2> err.xml cppcheck-htmlreport --file=err.xml --report-dir=test1 --source-dir=. +or + cppcheck gui/test.cpp --xml 2> err.xml + cppcheck-htmlreport --file=err.xml --report-dir=test1 \ + --source-dir=https://github.com///blob// + +## Choosing Between Local Annotated HTML and Remote Repository Links + +cppcheck-htmlreport supports two modes for linking to source files: + - Local annotated HTML files (default when `--source-dir` is a filesystem path) + - Remote GitHub/GitLab links (when `--source-dir` is a URL) + +Pointing `--source-dir` to a filesystem path generates local annotated HTML files. +This is useful when you need a fully self-contained report that works offline, +includes inline annotations, and is ideal for small or medium projects where +generation is fast. +Using a remote GitHub/GitLab URL avoids generating per-file HTML and keeps the +summary report lightweight and fast to produce. This mode is ideal when the +source is already hosted online and local duplication is unnecessary. +Remote mode is especially helpful when the HTML report may be public or widely +distributed but the source code should remain private, since access control is +handled by the hosting service. +In general, local mode fits air-gapped environments, while remote mode works +best for CI workflows and large or private repositories. + # Check Level ## Reduced