Coverage for lobster/tools/core/online_report_nogit/online_report_nogit.py: 51%
47 statements
« prev ^ index » next coverage.py v7.10.7, created at 2026-09-22 04:43 +0000
« prev ^ index » next coverage.py v7.10.7, created at 2026-09-22 04:43 +0000
1# LOBSTER - Lightweight Open BMW Software Traceability Evidence Report
2# Copyright (C) 2025 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
3#
4# This program is free software: you can redistribute it and/or modify
5# it under the terms of the GNU Affero General Public License as
6# published by the Free Software Foundation, either version 3 of the
7# License, or (at your option) any later version.
8#
9# This program is distributed in the hope that it will be useful, but
10# WITHOUT ANY WARRANTY; without even the implied warranty of
11# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12# Affero General Public License for more details.
13#
14# You should have received a copy of the GNU Affero General Public
15# License along with this program. If not, see
16# <https://www.gnu.org/licenses/>.
18import argparse
19import os
20import sys
22from dataclasses import dataclass
23from typing import Iterable, Optional, Sequence
24from urllib.parse import quote
26from lobster.common.items import Item
27from lobster.common.location import File_Reference, Github_Reference
28from lobster.common.report import Report
29from lobster.common.meta_data_tool_base import MetaDataToolBase
32@dataclass
33class RepoInfo:
34 """
35 Data class to hold repository information.
37 Attributes:
38 remote_url (str): The root URL of the GitHub repository.
39 root (str): The local path to the root of the repository.
40 commit (str): The commit hash to use when building a URL to a file.
41 """
42 remote_url: str
43 root: str
44 commit: str
47def _file_ref_to_github_ref(
48 file_ref: File_Reference,
49 repo_info: RepoInfo,
50 paths_must_exist: bool,
51) -> Github_Reference:
52 """
53 Convert a File_Reference to a Github_Reference.
55 Args:
56 file_ref (File_Reference): The file reference to convert (can be a directory).
57 repo_data (RepoData): The repository meta information to use for the conversion.
58 paths_must_exist (bool): If True, then a sanity check is performed. If the path
59 is is not a directory and not a file, then a FileNotFoundError is raised.
61 Returns:
62 Github_Reference: The converted GitHub reference.
63 """
64 if (not paths_must_exist) \
65 or os.path.isfile(file_ref.filename) or os.path.isdir(file_ref.filename):
66 return Github_Reference(
67 gh_root=repo_info.remote_url,
68 filename=quote(
69 os.path.relpath(
70 os.path.realpath(file_ref.filename),
71 os.path.realpath(repo_info.root),
72 ).replace(os.sep, "/")
73 ),
74 line=file_ref.line,
75 commit=repo_info.commit,
76 )
77 raise FileNotFoundError(f"File '{file_ref.filename}' does not exist.")
80def _update_items(items: Iterable[Item], repo_info: RepoInfo, paths_must_exist: bool):
81 for item in items:
82 if isinstance(item.location, File_Reference):
83 item.location = _file_ref_to_github_ref(
84 item.location,
85 repo_info,
86 paths_must_exist,
87 )
90def apply_github_urls(
91 in_file: str,
92 out_file: str,
93 repository_info: RepoInfo,
94 paths_must_exist: bool = True):
95 """
96 Reads a report file, converts all file references to GitHub references,
97 and saves the report.
99 Args:
100 file (str): Path to the input LOBSTER report file.
101 out_file (str): Output file for the updated LOBSTER report.
102 repo_data (RepoData): object containing remote URL, root path, and commit hash.
103 paths_must_exist (bool): If True, then a sanity check is performed. If the path
104 is is not a directory and not a file, then a FileNotFoundError is raised.
105 """
106 report = Report()
107 report.load_report(in_file)
108 _update_items(report.items.values(), repository_info, paths_must_exist)
109 report.write_report(out_file)
112class OnlineReportNogitTool(MetaDataToolBase):
113 def __init__(self):
114 super().__init__(
115 name="lobster-online-report-nogit",
116 description="Update file locations in LOBSTER report to GitHub references.",
117 official=True,
118 )
119 ap = self._argument_parser
120 ap.add_argument(dest="report",
121 metavar="LOBSTER_REPORT",
122 help="Path to the input LOBSTER report file.")
123 ap.add_argument("--repo-root", required=True,
124 help="Local path to the root of the repository.")
125 ap.add_argument("--remote-url", required=True,
126 help="GitHub repository root URL.")
127 ap.add_argument("--commit", required=True,
128 help="Git commit hash to use for the references.")
129 ap.add_argument("--out", required=True, metavar="OUTPUT_FILE",
130 help="Output file for the updated LOBSTER report."
131 "It can be the same as the input file in order to "
132 "overwrite the input file.",)
134 def _run_impl(self, options: argparse.Namespace) -> int:
135 try:
136 apply_github_urls(
137 in_file=options.report,
138 repository_info=RepoInfo(
139 remote_url=options.remote_url,
140 root=options.repo_root,
141 commit=options.commit,
142 ),
143 out_file=options.out,
144 )
145 print(f"LOBSTER report {options.out} created, using remote URL references.")
146 except FileNotFoundError as e:
147 print(
148 f"Error: {e}\n"
149 f"Note: Relative paths are resolved with respect to the "
150 f"current working directory '{os.getcwd()}'.",
151 file=sys.stderr,
152 )
153 return 1
154 return 0
157def main(args: Optional[Sequence[str]] = None) -> int:
158 return OnlineReportNogitTool().run(args)