java-dependency-analyzer 1.0.0__tar.gz → 1.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (33) hide show
  1. java_dependency_analyzer-1.1.0/LICENSE +21 -0
  2. java_dependency_analyzer-1.0.0/README.md → java_dependency_analyzer-1.1.0/PKG-INFO +260 -175
  3. java_dependency_analyzer-1.0.0/PKG-INFO → java_dependency_analyzer-1.1.0/README.md +45 -19
  4. java_dependency_analyzer-1.1.0/java_dependency_analyzer/__init__.py +18 -0
  5. {java_dependency_analyzer-1.0.0 → java_dependency_analyzer-1.1.0}/java_dependency_analyzer/cache/vulnerability_cache.py +6 -2
  6. {java_dependency_analyzer-1.0.0 → java_dependency_analyzer-1.1.0}/java_dependency_analyzer/cli.py +21 -5
  7. {java_dependency_analyzer-1.0.0 → java_dependency_analyzer-1.1.0}/java_dependency_analyzer/parsers/base.py +4 -4
  8. {java_dependency_analyzer-1.0.0 → java_dependency_analyzer-1.1.0}/java_dependency_analyzer/parsers/gradle_dep_tree_parser.py +1 -3
  9. {java_dependency_analyzer-1.0.0 → java_dependency_analyzer-1.1.0}/java_dependency_analyzer/parsers/gradle_parser.py +14 -4
  10. {java_dependency_analyzer-1.0.0 → java_dependency_analyzer-1.1.0}/java_dependency_analyzer/parsers/maven_dep_tree_parser.py +1 -3
  11. {java_dependency_analyzer-1.0.0 → java_dependency_analyzer-1.1.0}/java_dependency_analyzer/parsers/maven_parser.py +13 -4
  12. {java_dependency_analyzer-1.0.0 → java_dependency_analyzer-1.1.0}/java_dependency_analyzer/resolvers/__init__.py +11 -11
  13. {java_dependency_analyzer-1.0.0 → java_dependency_analyzer-1.1.0}/java_dependency_analyzer/resolvers/transitive.py +14 -9
  14. {java_dependency_analyzer-1.0.0 → java_dependency_analyzer-1.1.0}/java_dependency_analyzer/scanners/base.py +1 -3
  15. {java_dependency_analyzer-1.0.0 → java_dependency_analyzer-1.1.0}/java_dependency_analyzer/scanners/ghsa_scanner.py +2 -1
  16. java_dependency_analyzer-1.1.0/logging.ini +28 -0
  17. {java_dependency_analyzer-1.0.0 → java_dependency_analyzer-1.1.0}/pyproject.toml +39 -37
  18. java_dependency_analyzer-1.0.0/java_dependency_analyzer/__init__.py +0 -11
  19. {java_dependency_analyzer-1.0.0 → java_dependency_analyzer-1.1.0}/java_dependency_analyzer/cache/__init__.py +0 -0
  20. {java_dependency_analyzer-1.0.0 → java_dependency_analyzer-1.1.0}/java_dependency_analyzer/cache/db.py +0 -0
  21. {java_dependency_analyzer-1.0.0 → java_dependency_analyzer-1.1.0}/java_dependency_analyzer/models/__init__.py +0 -0
  22. {java_dependency_analyzer-1.0.0 → java_dependency_analyzer-1.1.0}/java_dependency_analyzer/models/dependency.py +0 -0
  23. {java_dependency_analyzer-1.0.0 → java_dependency_analyzer-1.1.0}/java_dependency_analyzer/models/report.py +0 -0
  24. {java_dependency_analyzer-1.0.0 → java_dependency_analyzer-1.1.0}/java_dependency_analyzer/parsers/__init__.py +0 -0
  25. {java_dependency_analyzer-1.0.0 → java_dependency_analyzer-1.1.0}/java_dependency_analyzer/reporters/__init__.py +0 -0
  26. {java_dependency_analyzer-1.0.0 → java_dependency_analyzer-1.1.0}/java_dependency_analyzer/reporters/base.py +0 -0
  27. {java_dependency_analyzer-1.0.0 → java_dependency_analyzer-1.1.0}/java_dependency_analyzer/reporters/html_reporter.py +0 -0
  28. {java_dependency_analyzer-1.0.0 → java_dependency_analyzer-1.1.0}/java_dependency_analyzer/reporters/json_reporter.py +0 -0
  29. {java_dependency_analyzer-1.0.0 → java_dependency_analyzer-1.1.0}/java_dependency_analyzer/reporters/templates/report.html +0 -0
  30. {java_dependency_analyzer-1.0.0 → java_dependency_analyzer-1.1.0}/java_dependency_analyzer/scanners/__init__.py +0 -0
  31. {java_dependency_analyzer-1.0.0 → java_dependency_analyzer-1.1.0}/java_dependency_analyzer/scanners/osv_scanner.py +0 -0
  32. {java_dependency_analyzer-1.0.0 → java_dependency_analyzer-1.1.0}/java_dependency_analyzer/util/__init__.py +0 -0
  33. {java_dependency_analyzer-1.0.0 → java_dependency_analyzer-1.1.0}/java_dependency_analyzer/util/logger.py +0 -0
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Ron Webb
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -1,175 +1,260 @@
1
- # Java Dependency Analyzer 1.0.0
2
-
3
- > A Python CLI tool that inspects Java dependency hierarchies in Maven and Gradle projects and reports known vulnerabilities.
4
-
5
- ## Prerequisites
6
-
7
- - Python `^3.14`
8
- - [Poetry](https://python-poetry.org/) `2.2`
9
-
10
- ## Installation
11
-
12
- Clone the repository and install all dependencies:
13
-
14
- ```bash
15
- git clone <repository-url>
16
- cd java-dependency-analyzer
17
- poetry install
18
- ```
19
-
20
- ## Usage
21
-
22
- ```
23
- jda <COMMAND> [OPTIONS] [FILE]
24
- ```
25
-
26
- `COMMAND` is one of `gradle` or `maven`.
27
-
28
- ### gradle
29
-
30
- ```
31
- jda gradle [OPTIONS] [FILE]
32
- ```
33
-
34
- `FILE` is the path to a `build.gradle` or `build.gradle.kts` file.
35
- Omit `FILE` when supplying `--dependencies`.
36
-
37
- ### maven
38
-
39
- ```
40
- jda maven [OPTIONS] [FILE]
41
- ```
42
-
43
- `FILE` is the path to a `pom.xml` file.
44
- Omit `FILE` when supplying `--dependencies`.
45
-
46
- ### Options (both subcommands)
47
-
48
- | Option | Short | Default | Description |
49
- |---|---|---|---|
50
- | `--dependencies` | `-d` | | Path to a pre-resolved dependency tree text file (see below). When supplied, parsing and transitive resolution are skipped. |
51
- | `--output-format` | `-f` | `all` | Report format: `json`, `html`, or `all` (both). |
52
- | `--output-dir` | `-o` | `.` | Directory to write the report file(s) into. |
53
- | `--no-transitive` | | `false` | Skip transitive dependency resolution; analyse direct dependencies only. |
54
- | `--verbose` | `-v` | `false` | Print progress messages to the console. |
55
- | `--rebuild-cache` | | `false` | Delete the vulnerability cache before scanning. |
56
- | `--cache-ttl` | | `7` | Cache TTL in days. Set to `0` to disable caching. |
57
-
58
- ### Pre-resolved dependency trees (`--dependencies`)
59
-
60
- When a Gradle or Maven project already has a dependency tree available (e.g. from CI), you can pass it directly to skip the parser and transitive resolver:
61
-
62
- - **Gradle**: generate with `gradle dependencies --configuration runtimeClasspath > gradle.txt`
63
- - **Maven**: generate with `mvn dependency:tree -Dscope=runtime > maven.txt`
64
-
65
- The report will reflect the exact tree from the file, including all transitive dependencies.
66
-
67
- ### Examples
68
-
69
- Analyse a Maven POM and produce both JSON and HTML reports in the current directory:
70
-
71
- ```bash
72
- jda maven pom.xml
73
- ```
74
-
75
- Analyse a Gradle build file and write only an HTML report to `./reports/`:
76
-
77
- ```bash
78
- jda gradle build.gradle -f html -o reports/
79
- ```
80
-
81
- Analyse direct dependencies only, with verbose output:
82
-
83
- ```bash
84
- jda gradle build.gradle.kts --no-transitive -v
85
- ```
86
-
87
- Scan using a pre-resolved Gradle dependency tree (skips transitive resolution):
88
-
89
- ```bash
90
- jda gradle --dependencies runtime.txt -f json -o reports/
91
- ```
92
-
93
- Scan using a pre-resolved Maven dependency tree (skips transitive resolution):
94
-
95
- ```bash
96
- jda maven --dependencies maven.txt -f json -o reports/
97
- ```
98
-
99
- ## Architecture
100
-
101
- ```mermaid
102
- graph TD
103
- CLI["jda CLI (cli.py)"] --> Parser["DependencyParser (ABC)"]
104
- Parser --> MavenParser
105
- Parser --> GradleParser
106
- Parser --> MavenDepTreeParser
107
- Parser --> GradleDepTreeParser
108
- CLI --> Resolver["TransitiveResolver<br/>(Maven Central)"]
109
- CLI --> Scanner["VulnerabilityScanner (ABC)"]
110
- Scanner --> OsvScanner["OsvScanner<br/>(OSV.dev API)"]
111
- Scanner --> GhsaScanner["GhsaScanner<br/>(GitHub Advisory DB)"]
112
- OsvScanner --> Cache["VulnerabilityCache<br/>(SQLite)"]
113
- GhsaScanner --> Cache
114
- CLI --> Reporter["Reporter (ABC)"]
115
- Reporter --> JsonReporter
116
- Reporter --> HtmlReporter
117
- MavenParser --> Dependency["Dependency / Vulnerability<br/>Dataclasses"]
118
- GradleParser --> Dependency
119
- MavenDepTreeParser --> Dependency
120
- GradleDepTreeParser --> Dependency
121
- Resolver --> Dependency
122
- OsvScanner --> Dependency
123
- GhsaScanner --> Dependency
124
- JsonReporter --> ScanResult["ScanResult"]
125
- HtmlReporter --> ScanResult
126
- Dependency --> ScanResult
127
- ```
128
-
129
- ### Components
130
-
131
- | Component | Location | Responsibility |
132
- |---|---|---|
133
- | CLI | `java_dependency_analyzer/cli.py` | Entry point (`gradle` / `maven` subcommands); orchestrates parsing, resolving, scanning, and reporting. |
134
- | `MavenParser` | `parsers/maven_parser.py` | Parses `pom.xml`, resolves `${property}` placeholders, filters by runtime scope. |
135
- | `GradleParser` | `parsers/gradle_parser.py` | Parses Groovy DSL (`build.gradle`) and Kotlin DSL (`build.gradle.kts`) files. |
136
- | `MavenDepTreeParser` | `parsers/maven_dep_tree_parser.py` | Parses `mvn dependency:tree` text output into a full dependency tree. |
137
- | `GradleDepTreeParser` | `parsers/gradle_dep_tree_parser.py` | Parses `gradle dependencies` text output into a full dependency tree. |
138
- | `TransitiveResolver` | `resolvers/transitive.py` | Fetches transitive dependencies by downloading POM files from Maven Central. |
139
- | `OsvScanner` | `scanners/osv_scanner.py` | Queries the [OSV.dev](https://osv.dev/) batch API for known CVEs. |
140
- | `GhsaScanner` | `scanners/ghsa_scanner.py` | Queries the [GitHub Advisory Database](https://github.com/advisories) REST API for security advisories. |
141
- | `VulnerabilityCache` | `cache/vulnerability_cache.py` | SQLite-backed cache for raw vulnerability API payloads with configurable TTL. |
142
- | `DatabaseManager` | `cache/db.py` | Manages SQLite connection lifecycle and schema initialisation. |
143
- | `JsonReporter` | `reporters/json_reporter.py` | Writes a `ScanResult` to a JSON file. |
144
- | `HtmlReporter` | `reporters/html_reporter.py` | Renders a `ScanResult` to a styled HTML report via a Jinja2 template. |
145
-
146
- ## Development Setup
147
-
148
- Install all dependencies (including dev tools):
149
-
150
- ```bash
151
- poetry install
152
- ```
153
-
154
- ### Running Tests
155
-
156
- Run the full test suite with coverage and generate an HTML report:
157
-
158
- ```bash
159
- poetry run pytest --cov=java_dependency_analyzer tests --cov-report html
160
- ```
161
-
162
- ### Code Quality
163
-
164
- Format and lint the source code (linter must score 10/10):
165
-
166
- ```bash
167
- poetry run black java_dependency_analyzer
168
- poetry run pylint java_dependency_analyzer
169
- ```
170
-
171
- ## [Changelog](CHANGELOG.md)
172
-
173
- ## Author
174
-
175
- Ron Webb &lt;ron@ronella.xyz&gt;
1
+ Metadata-Version: 2.4
2
+ Name: java-dependency-analyzer
3
+ Version: 1.1.0
4
+ Summary: Java Dependency Analyzer is a tool that inspects dependencies.
5
+ License: MIT License
6
+
7
+ Copyright (c) 2026 Ron Webb
8
+
9
+ Permission is hereby granted, free of charge, to any person obtaining a copy
10
+ of this software and associated documentation files (the "Software"), to deal
11
+ in the Software without restriction, including without limitation the rights
12
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13
+ copies of the Software, and to permit persons to whom the Software is
14
+ furnished to do so, subject to the following conditions:
15
+
16
+ The above copyright notice and this permission notice shall be included in all
17
+ copies or substantial portions of the Software.
18
+
19
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
25
+ SOFTWARE.
26
+ License-File: LICENSE
27
+ Author: Ron Webb
28
+ Author-email: ron@ronella.xyz
29
+ Requires-Python: >=3.14
30
+ Classifier: License :: Other/Proprietary License
31
+ Classifier: Programming Language :: Python :: 3
32
+ Classifier: Programming Language :: Python :: 3.14
33
+ Requires-Dist: beautifulsoup4 (>=4.14.3,<5.0.0)
34
+ Requires-Dist: click (>=8.3.1,<9.0.0)
35
+ Requires-Dist: httpx (>=0.28.1,<0.29.0)
36
+ Requires-Dist: jinja2 (>=3.1.6,<4.0.0)
37
+ Requires-Dist: lxml (>=6.0.2,<7.0.0)
38
+ Requires-Dist: python-dotenv (>=1.2.2,<2.0.0)
39
+ Description-Content-Type: text/markdown
40
+
41
+ # Java Dependency Analyzer 1.1.0
42
+
43
+ > A Python CLI tool that inspects Java dependency hierarchies in Maven and Gradle projects and reports known vulnerabilities.
44
+
45
+ ## Prerequisites
46
+
47
+ - Python `^3.14`
48
+ - [Poetry](https://python-poetry.org/) `2.2`
49
+
50
+ ## Installation
51
+
52
+ Clone the repository and install all dependencies:
53
+
54
+ ```bash
55
+ git clone <repository-url>
56
+ cd java-dependency-analyzer
57
+ poetry install
58
+ ```
59
+
60
+ ## Usage
61
+
62
+ ```
63
+ jda <COMMAND> [OPTIONS] [FILE]
64
+ ```
65
+
66
+ `COMMAND` is one of `gradle` or `maven`.
67
+
68
+ ### gradle
69
+
70
+ ```
71
+ jda gradle [OPTIONS] [FILE]
72
+ ```
73
+
74
+ `FILE` is the path to a `build.gradle` or `build.gradle.kts` file.
75
+ Omit `FILE` when supplying `--dependencies`.
76
+
77
+ ### maven
78
+
79
+ ```
80
+ jda maven [OPTIONS] [FILE]
81
+ ```
82
+
83
+ `FILE` is the path to a `pom.xml` file.
84
+ Omit `FILE` when supplying `--dependencies`.
85
+
86
+ ### Options (both subcommands)
87
+
88
+ | Option | Short | Default | Description |
89
+ |---|---|---|---|
90
+ | `--dependencies` | `-d` | | Path to a pre-resolved dependency tree text file (see below). When supplied, parsing and transitive resolution are skipped. |
91
+ | `--output-format` | `-f` | `all` | Report format: `json`, `html`, or `all` (both). |
92
+ | `--output-dir` | `-o` | `.` | Directory to write the report file(s) into. |
93
+ | `--no-transitive` | | `false` | Skip transitive dependency resolution; analyse direct dependencies only. |
94
+ | `--verbose` | `-v` | `false` | Print progress messages to the console. |
95
+ | `--rebuild-cache` | | `false` | Delete the vulnerability cache before scanning. |
96
+ | `--cache-ttl` | | `7` | Cache TTL in days. Set to `0` to disable caching. |
97
+
98
+ ### Exit Codes
99
+
100
+ | Code | Meaning |
101
+ |---|---|
102
+ | `0` | Scan completed successfully; no vulnerabilities found. |
103
+ | `10` | Scan completed successfully; at least one vulnerability was detected. |
104
+
105
+ ### Pre-resolved dependency trees (`--dependencies`)
106
+
107
+ When a Gradle or Maven project already has a dependency tree available (e.g. from CI), you can pass it directly to skip the parser and transitive resolver:
108
+
109
+ - **Gradle**: generate with `gradle dependencies --configuration runtimeClasspath > gradle.txt`
110
+ - **Maven**: generate with `mvn dependency:tree -Dscope=runtime > maven.txt`
111
+
112
+ The report will reflect the exact tree from the file, including all transitive dependencies.
113
+
114
+ ### Examples
115
+
116
+ Analyse a Maven POM and produce both JSON and HTML reports in the current directory:
117
+
118
+ ```bash
119
+ jda maven pom.xml
120
+ ```
121
+
122
+ Analyse a Gradle build file and write only an HTML report to `./reports/`:
123
+
124
+ ```bash
125
+ jda gradle build.gradle -f html -o reports/
126
+ ```
127
+
128
+ Analyse direct dependencies only, with verbose output:
129
+
130
+ ```bash
131
+ jda gradle build.gradle.kts --no-transitive -v
132
+ ```
133
+
134
+ Scan using a pre-resolved Gradle dependency tree (skips transitive resolution):
135
+
136
+ ```bash
137
+ jda gradle --dependencies runtime.txt -f json -o reports/
138
+ ```
139
+
140
+ Scan using a pre-resolved Maven dependency tree (skips transitive resolution):
141
+
142
+ ```bash
143
+ jda maven --dependencies maven.txt -f json -o reports/
144
+ ```
145
+
146
+ ## Logging
147
+
148
+ The tool writes logs to `java_dependency_analyzer.log` in the current working directory, in addition to printing them to the console (`stderr`).
149
+
150
+ Logging requires a `logging.ini` file to be present in the working directory or any of its parent directories. The logger walks up the directory tree until it finds one.
151
+
152
+ **When installed via pip**, no `logging.ini` is bundled. Without it the tool falls back to console-only logging (no log file is created). To enable file logging, copy `logging.ini` from the [repository](https://github.com/rcw3bb/java-dependency-analyzer/blob/master/logging.ini) to your working directory:
153
+
154
+ ```bash
155
+ curl -O https://raw.githubusercontent.com/rcw3bb/java-dependency-analyzer/master/logging.ini
156
+ ```
157
+
158
+ Then run `jda` from that same directory.
159
+
160
+ ## Architecture
161
+
162
+ ```mermaid
163
+ graph TD
164
+ CLI["jda CLI (cli.py)"] --> Parser["DependencyParser (ABC)"]
165
+ Parser --> MavenParser
166
+ Parser --> GradleParser
167
+ Parser --> MavenDepTreeParser
168
+ Parser --> GradleDepTreeParser
169
+ CLI --> Resolver["TransitiveResolver<br/>(Maven Central)"]
170
+ CLI --> Scanner["VulnerabilityScanner (ABC)"]
171
+ Scanner --> OsvScanner["OsvScanner<br/>(OSV.dev API)"]
172
+ Scanner --> GhsaScanner["GhsaScanner<br/>(GitHub Advisory DB)"]
173
+ OsvScanner --> Cache["VulnerabilityCache<br/>(SQLite)"]
174
+ GhsaScanner --> Cache
175
+ CLI --> Reporter["Reporter (ABC)"]
176
+ Reporter --> JsonReporter
177
+ Reporter --> HtmlReporter
178
+ MavenParser --> Dependency["Dependency / Vulnerability<br/>Dataclasses"]
179
+ GradleParser --> Dependency
180
+ MavenDepTreeParser --> Dependency
181
+ GradleDepTreeParser --> Dependency
182
+ Resolver --> Dependency
183
+ OsvScanner --> Dependency
184
+ GhsaScanner --> Dependency
185
+ JsonReporter --> ScanResult["ScanResult"]
186
+ HtmlReporter --> ScanResult
187
+ Dependency --> ScanResult
188
+ ```
189
+
190
+ ### Components
191
+
192
+ | Component | Location | Responsibility |
193
+ |---|---|---|
194
+ | CLI | `java_dependency_analyzer/cli.py` | Entry point (`gradle` / `maven` subcommands); orchestrates parsing, resolving, scanning, and reporting. |
195
+ | `MavenParser` | `parsers/maven_parser.py` | Parses `pom.xml`, resolves `${property}` placeholders, filters by runtime scope. |
196
+ | `GradleParser` | `parsers/gradle_parser.py` | Parses Groovy DSL (`build.gradle`) and Kotlin DSL (`build.gradle.kts`) files. |
197
+ | `MavenDepTreeParser` | `parsers/maven_dep_tree_parser.py` | Parses `mvn dependency:tree` text output into a full dependency tree. |
198
+ | `GradleDepTreeParser` | `parsers/gradle_dep_tree_parser.py` | Parses `gradle dependencies` text output into a full dependency tree. |
199
+ | `TransitiveResolver` | `resolvers/transitive.py` | Fetches transitive dependencies by downloading POM files from Maven Central. |
200
+ | `OsvScanner` | `scanners/osv_scanner.py` | Queries the [OSV.dev](https://osv.dev/) batch API for known CVEs. |
201
+ | `GhsaScanner` | `scanners/ghsa_scanner.py` | Queries the [GitHub Advisory Database](https://github.com/advisories) REST API for security advisories. |
202
+ | `VulnerabilityCache` | `cache/vulnerability_cache.py` | SQLite-backed cache for raw vulnerability API payloads with configurable TTL. |
203
+ | `DatabaseManager` | `cache/db.py` | Manages SQLite connection lifecycle and schema initialisation. |
204
+ | `JsonReporter` | `reporters/json_reporter.py` | Writes a `ScanResult` to a JSON file. |
205
+ | `HtmlReporter` | `reporters/html_reporter.py` | Renders a `ScanResult` to a styled HTML report via a Jinja2 template. |
206
+
207
+ ## Development Setup
208
+
209
+ Install all dependencies (including dev tools):
210
+
211
+ ```bash
212
+ poetry install
213
+ ```
214
+
215
+ ### Running Tests
216
+
217
+ Run the full test suite with coverage and generate an HTML report:
218
+
219
+ ```bash
220
+ poetry run pytest --cov=java_dependency_analyzer tests --cov-report html
221
+ ```
222
+
223
+ ### Code Quality
224
+
225
+ Format and lint the source code (linter must score 10/10):
226
+
227
+ ```bash
228
+ poetry run black java_dependency_analyzer
229
+ poetry run pylint java_dependency_analyzer
230
+ ```
231
+
232
+ ## Publishing to PyPI
233
+
234
+ ### Prerequisites
235
+
236
+ - A [PyPI](https://pypi.org/) account with an API token.
237
+
238
+ ### Configure the token
239
+
240
+ ```bash
241
+ poetry config pypi-token.pypi <your-token>
242
+ ```
243
+
244
+ ### Build and publish
245
+
246
+ ```bash
247
+ poetry publish --build
248
+ ```
249
+
250
+ This builds the source distribution and wheel, then uploads them to PyPI in one step.
251
+
252
+ > **Note:** PyPI releases are immutable. Once a version is published, it cannot be overwritten.
253
+ > To fix a mistake, yank the release via the PyPI web UI and publish a new version.
254
+
255
+ ## [Changelog](CHANGELOG.md)
256
+
257
+ ## Author
258
+
259
+ Ron Webb &lt;ron@ronella.xyz&gt;
260
+
@@ -1,21 +1,4 @@
1
- Metadata-Version: 2.4
2
- Name: java-dependency-analyzer
3
- Version: 1.0.0
4
- Summary: Java Dependency Analyzer is a tool that inspects dependencies.
5
- Author: Ron Webb
6
- Author-email: ron@ronella.xyz
7
- Requires-Python: >=3.14
8
- Classifier: Programming Language :: Python :: 3
9
- Classifier: Programming Language :: Python :: 3.14
10
- Requires-Dist: beautifulsoup4 (>=4.14.3,<5.0.0)
11
- Requires-Dist: click (>=8.3.1,<9.0.0)
12
- Requires-Dist: httpx (>=0.28.1,<0.29.0)
13
- Requires-Dist: jinja2 (>=3.1.6,<4.0.0)
14
- Requires-Dist: lxml (>=6.0.2,<7.0.0)
15
- Requires-Dist: python-dotenv (>=1.2.2,<2.0.0)
16
- Description-Content-Type: text/markdown
17
-
18
- # Java Dependency Analyzer 1.0.0
1
+ # Java Dependency Analyzer 1.1.0
19
2
 
20
3
  > A Python CLI tool that inspects Java dependency hierarchies in Maven and Gradle projects and reports known vulnerabilities.
21
4
 
@@ -72,6 +55,13 @@ Omit `FILE` when supplying `--dependencies`.
72
55
  | `--rebuild-cache` | | `false` | Delete the vulnerability cache before scanning. |
73
56
  | `--cache-ttl` | | `7` | Cache TTL in days. Set to `0` to disable caching. |
74
57
 
58
+ ### Exit Codes
59
+
60
+ | Code | Meaning |
61
+ |---|---|
62
+ | `0` | Scan completed successfully; no vulnerabilities found. |
63
+ | `10` | Scan completed successfully; at least one vulnerability was detected. |
64
+
75
65
  ### Pre-resolved dependency trees (`--dependencies`)
76
66
 
77
67
  When a Gradle or Maven project already has a dependency tree available (e.g. from CI), you can pass it directly to skip the parser and transitive resolver:
@@ -113,6 +103,20 @@ Scan using a pre-resolved Maven dependency tree (skips transitive resolution):
113
103
  jda maven --dependencies maven.txt -f json -o reports/
114
104
  ```
115
105
 
106
+ ## Logging
107
+
108
+ The tool writes logs to `java_dependency_analyzer.log` in the current working directory, in addition to printing them to the console (`stderr`).
109
+
110
+ Logging requires a `logging.ini` file to be present in the working directory or any of its parent directories. The logger walks up the directory tree until it finds one.
111
+
112
+ **When installed via pip**, no `logging.ini` is bundled. Without it the tool falls back to console-only logging (no log file is created). To enable file logging, copy `logging.ini` from the [repository](https://github.com/rcw3bb/java-dependency-analyzer/blob/master/logging.ini) to your working directory:
113
+
114
+ ```bash
115
+ curl -O https://raw.githubusercontent.com/rcw3bb/java-dependency-analyzer/master/logging.ini
116
+ ```
117
+
118
+ Then run `jda` from that same directory.
119
+
116
120
  ## Architecture
117
121
 
118
122
  ```mermaid
@@ -185,9 +189,31 @@ poetry run black java_dependency_analyzer
185
189
  poetry run pylint java_dependency_analyzer
186
190
  ```
187
191
 
192
+ ## Publishing to PyPI
193
+
194
+ ### Prerequisites
195
+
196
+ - A [PyPI](https://pypi.org/) account with an API token.
197
+
198
+ ### Configure the token
199
+
200
+ ```bash
201
+ poetry config pypi-token.pypi <your-token>
202
+ ```
203
+
204
+ ### Build and publish
205
+
206
+ ```bash
207
+ poetry publish --build
208
+ ```
209
+
210
+ This builds the source distribution and wheel, then uploads them to PyPI in one step.
211
+
212
+ > **Note:** PyPI releases are immutable. Once a version is published, it cannot be overwritten.
213
+ > To fix a mistake, yank the release via the PyPI web UI and publish a new version.
214
+
188
215
  ## [Changelog](CHANGELOG.md)
189
216
 
190
217
  ## Author
191
218
 
192
219
  Ron Webb &lt;ron@ronella.xyz&gt;
193
-
@@ -0,0 +1,18 @@
1
+ """
2
+ java_dependency_analyzer package.
3
+
4
+ Java Dependency Analyzer is a tool that inspects dependencies.
5
+
6
+ :author: Ron Webb
7
+ :since: 1.0.0
8
+ """
9
+
10
+ from importlib.metadata import version, PackageNotFoundError
11
+
12
+ __author__ = "Ron Webb"
13
+ __since__ = "1.0.0"
14
+
15
+ try:
16
+ __version__ = version("java-dependency-analyzer")
17
+ except PackageNotFoundError:
18
+ __version__ = "unknown"
@@ -81,14 +81,18 @@ class VulnerabilityCache:
81
81
  :author: Ron Webb
82
82
  :since: 1.0.0
83
83
  """
84
- cursor = self._conn.execute(_SELECT_SQL, (source, group_id, artifact_id, version))
84
+ cursor = self._conn.execute(
85
+ _SELECT_SQL, (source, group_id, artifact_id, version)
86
+ )
85
87
  row = cursor.fetchone()
86
88
  if row is None:
87
89
  return None
88
90
  payload, cached_at = row
89
91
  if self._is_expired(cached_at):
90
92
  with self._conn:
91
- self._conn.execute(_DELETE_SQL, (source, group_id, artifact_id, version))
93
+ self._conn.execute(
94
+ _DELETE_SQL, (source, group_id, artifact_id, version)
95
+ )
92
96
  _logger.debug(
93
97
  "Cache entry expired and deleted for %s/%s:%s@%s",
94
98
  source,
@@ -7,10 +7,12 @@ Command-line interface entry point for the Java Dependency Analyzer.
7
7
  :since: 1.0.0
8
8
  """
9
9
 
10
+ import sys
10
11
  from pathlib import Path
11
12
 
12
13
  import click
13
14
 
15
+ from . import __version__
14
16
  from .cache.db import delete_database
15
17
  from .cache.vulnerability_cache import VulnerabilityCache
16
18
  from .models.dependency import Dependency
@@ -31,6 +33,9 @@ __since__ = "1.0.0"
31
33
 
32
34
  _logger = setup_logger(__name__)
33
35
 
36
+ EXIT_VULNERABILITIES_FOUND = 10
37
+ """Exit status returned when vulnerabilities are detected."""
38
+
34
39
  # ---------------------------------------------------------------------------
35
40
  # Shared CLI options applied to both subcommands
36
41
  # ---------------------------------------------------------------------------
@@ -96,6 +101,7 @@ def _common_options(func):
96
101
  @click.group()
97
102
  def main() -> None:
98
103
  """Java Dependency Analyzer -- inspect Java dependency trees for known vulnerabilities."""
104
+ _logger.info("Java Dependency Analyzer v%s", __version__)
99
105
 
100
106
 
101
107
  # ---------------------------------------------------------------------------
@@ -162,7 +168,7 @@ def gradle( # pylint: disable=too-many-arguments,too-many-positional-arguments
162
168
  click.echo(f"Loading dependency tree from {dependencies}...")
163
169
  parsed_deps = GradleDepTreeParser().parse(dependencies)
164
170
  source = file if file is not None else dependencies
165
- _run_analysis(
171
+ found = _run_analysis(
166
172
  parsed_deps,
167
173
  source_file=source,
168
174
  output_format=output_format,
@@ -175,7 +181,7 @@ def gradle( # pylint: disable=too-many-arguments,too-many-positional-arguments
175
181
  if verbose:
176
182
  click.echo(f"Parsing {Path(file).name}...") # type: ignore[arg-type]
177
183
  parsed_deps = GradleParser().parse(file) # type: ignore[arg-type]
178
- _run_analysis(
184
+ found = _run_analysis(
179
185
  parsed_deps,
180
186
  source_file=file, # type: ignore[arg-type]
181
187
  output_format=output_format,
@@ -188,6 +194,9 @@ def gradle( # pylint: disable=too-many-arguments,too-many-positional-arguments
188
194
  if cache is not None:
189
195
  cache.close()
190
196
 
197
+ if found:
198
+ sys.exit(EXIT_VULNERABILITIES_FOUND)
199
+
191
200
 
192
201
  # ---------------------------------------------------------------------------
193
202
  # maven subcommand
@@ -251,7 +260,7 @@ def maven( # pylint: disable=too-many-arguments,too-many-positional-arguments
251
260
  click.echo(f"Loading dependency tree from {dependencies}...")
252
261
  parsed_deps = MavenDepTreeParser().parse(dependencies)
253
262
  source = file if file is not None else dependencies
254
- _run_analysis(
263
+ found = _run_analysis(
255
264
  parsed_deps,
256
265
  source_file=source,
257
266
  output_format=output_format,
@@ -264,7 +273,7 @@ def maven( # pylint: disable=too-many-arguments,too-many-positional-arguments
264
273
  if verbose:
265
274
  click.echo(f"Parsing {Path(file).name}...") # type: ignore[arg-type]
266
275
  parsed_deps = MavenParser().parse(file) # type: ignore[arg-type]
267
- _run_analysis(
276
+ found = _run_analysis(
268
277
  parsed_deps,
269
278
  source_file=file, # type: ignore[arg-type]
270
279
  output_format=output_format,
@@ -277,6 +286,9 @@ def maven( # pylint: disable=too-many-arguments,too-many-positional-arguments
277
286
  if cache is not None:
278
287
  cache.close()
279
288
 
289
+ if found:
290
+ sys.exit(EXIT_VULNERABILITIES_FOUND)
291
+
280
292
 
281
293
  # ---------------------------------------------------------------------------
282
294
  # Private helpers
@@ -308,11 +320,13 @@ def _run_analysis( # pylint: disable=too-many-arguments,too-many-positional-arg
308
320
  no_transitive: bool,
309
321
  verbose: bool,
310
322
  cache: VulnerabilityCache | None,
311
- ) -> None:
323
+ ) -> bool:
312
324
  """
313
325
  Resolve transitive dependencies (unless skipped), scan for vulnerabilities,
314
326
  and write the requested reports.
315
327
 
328
+ Returns True when at least one vulnerability was detected, False otherwise.
329
+
316
330
  :author: Ron Webb
317
331
  :since: 1.0.0
318
332
  """
@@ -345,6 +359,8 @@ def _run_analysis( # pylint: disable=too-many-arguments,too-many-positional-arg
345
359
  f"{result.total_vulnerabilities} vulnerabilities found."
346
360
  )
347
361
 
362
+ return result.total_vulnerabilities > 0
363
+
348
364
 
349
365
  def _scan_all(
350
366
  dependencies: list[Dependency],
@@ -21,7 +21,9 @@ __since__ = "1.0.0"
21
21
  _logger = setup_logger(__name__)
22
22
 
23
23
  # Runtime scopes that contribute to the executable classpath
24
- RUNTIME_SCOPES = frozenset({"compile", "runtime", "implementation", "api", "runtimeOnly"})
24
+ RUNTIME_SCOPES = frozenset(
25
+ {"compile", "runtime", "implementation", "api", "runtimeOnly"}
26
+ )
25
27
 
26
28
 
27
29
  def attach_node(
@@ -138,9 +140,7 @@ class DepTreeParser(DependencyParser):
138
140
  return build_tree_from_lines(lines, self._line_to_entry)
139
141
 
140
142
  @abstractmethod
141
- def _line_to_entry(
142
- self, line: str
143
- ) -> tuple[int, bool, Dependency] | None:
143
+ def _line_to_entry(self, line: str) -> tuple[int, bool, Dependency] | None:
144
144
  """
145
145
  Convert a single dependency-tree text line into a
146
146
  ``(depth, is_leaf, dep)`` tuple, or return *None* to skip the line.
@@ -56,9 +56,7 @@ class GradleDepTreeParser(DepTreeParser):
56
56
  # Private helpers
57
57
  # ------------------------------------------------------------------
58
58
 
59
- def _line_to_entry(
60
- self, line: str
61
- ) -> tuple[int, bool, Dependency] | None:
59
+ def _line_to_entry(self, line: str) -> tuple[int, bool, Dependency] | None:
62
60
  """
63
61
  Convert a single Gradle dep-tree line to a ``(depth, is_leaf, dep)``
64
62
  entry, or return *None* to skip the line.
@@ -139,12 +139,13 @@ class GradleParser(DependencyParser):
139
139
  :author: Ron Webb
140
140
  :since: 1.0.0
141
141
  """
142
+
142
143
  def _replacer(match: re.Match) -> str:
143
144
  return props.get(match.group(1), match.group(0))
144
145
 
145
146
  return re.sub(r"\$\{(\w+)\}", _replacer, content)
146
147
 
147
- def _strip_comments(self, content: str, is_kotlin_dsl: bool) -> str: # pylint: disable=unused-argument
148
+ def _strip_comments(self, content: str, _is_kotlin_dsl: bool) -> str:
148
149
  """
149
150
  Remove single-line (//) and block (/* */) comments from the file content.
150
151
 
@@ -165,7 +166,12 @@ class GradleParser(DependencyParser):
165
166
  :since: 1.0.0
166
167
  """
167
168
  deps: list[Dependency] = []
168
- for pattern in (_GROOVY_SHORTHAND, _KOTLIN_SHORTHAND, _GROOVY_BLOCK, _KOTLIN_BLOCK):
169
+ for pattern in (
170
+ _GROOVY_SHORTHAND,
171
+ _KOTLIN_SHORTHAND,
172
+ _GROOVY_BLOCK,
173
+ _KOTLIN_BLOCK,
174
+ ):
169
175
  for match in pattern.finditer(content):
170
176
  dep = self._match_to_dependency(match)
171
177
  if dep is not None:
@@ -194,10 +200,14 @@ class GradleParser(DependencyParser):
194
200
 
195
201
  # Skip variable references that couldn't be resolved
196
202
  if "$" in version:
197
- _logger.debug("Skipping %s:%s — unresolved version: %s", group, artifact, version)
203
+ _logger.debug(
204
+ "Skipping %s:%s — unresolved version: %s", group, artifact, version
205
+ )
198
206
  return None
199
207
 
200
- _logger.debug("Found dependency: %s:%s:%s (scope=%s)", group, artifact, version, scope)
208
+ _logger.debug(
209
+ "Found dependency: %s:%s:%s (scope=%s)", group, artifact, version, scope
210
+ )
201
211
  return Dependency(
202
212
  group_id=group,
203
213
  artifact_id=artifact,
@@ -52,9 +52,7 @@ class MavenDepTreeParser(DepTreeParser):
52
52
  # Private helpers
53
53
  # ------------------------------------------------------------------
54
54
 
55
- def _line_to_entry(
56
- self, line: str
57
- ) -> tuple[int, bool, Dependency] | None:
55
+ def _line_to_entry(self, line: str) -> tuple[int, bool, Dependency] | None:
58
56
  """
59
57
  Convert a single Maven dep-tree line to a ``(depth, is_leaf, dep)``
60
58
  entry, or return *None* to skip the line.
@@ -43,7 +43,9 @@ class MavenParser(DependencyParser):
43
43
  """
44
44
  _logger.info("Parsing Maven POM: %s", file_path)
45
45
  try:
46
- tree = etree.parse(file_path) # nosec B320 # pylint: disable=c-extension-no-member
46
+ tree = etree.parse(
47
+ file_path
48
+ ) # nosec B320 # pylint: disable=c-extension-no-member
47
49
  except etree.XMLSyntaxError as exc: # pylint: disable=c-extension-no-member
48
50
  _logger.error("Failed to parse POM XML: %s", exc)
49
51
  return []
@@ -88,7 +90,9 @@ class MavenParser(DependencyParser):
88
90
  props_el = root.find(self._tag("properties", namespace))
89
91
  if props_el is not None:
90
92
  for child in props_el:
91
- local = etree.QName(child.tag).localname # pylint: disable=c-extension-no-member
93
+ local = etree.QName(
94
+ child.tag
95
+ ).localname # pylint: disable=c-extension-no-member
92
96
  if child.text:
93
97
  props[local] = child.text.strip()
94
98
 
@@ -153,9 +157,12 @@ class MavenParser(DependencyParser):
153
157
  :author: Ron Webb
154
158
  :since: 1.0.0
155
159
  """
160
+
156
161
  def text(tag: str) -> str:
157
162
  child_el = dep_el.find(self._tag(tag, namespace))
158
- raw = child_el.text.strip() if child_el is not None and child_el.text else ""
163
+ raw = (
164
+ child_el.text.strip() if child_el is not None and child_el.text else ""
165
+ )
159
166
  return self._resolve_value(raw, properties)
160
167
 
161
168
  group_id = text("groupId")
@@ -167,7 +174,9 @@ class MavenParser(DependencyParser):
167
174
  return None
168
175
 
169
176
  if scope not in RUNTIME_SCOPES:
170
- _logger.debug("Skipping dependency %s:%s (scope=%s)", group_id, artifact_id, scope)
177
+ _logger.debug(
178
+ "Skipping dependency %s:%s (scope=%s)", group_id, artifact_id, scope
179
+ )
171
180
  return None
172
181
 
173
182
  if not version:
@@ -1,11 +1,11 @@
1
- """
2
- resolvers package.
3
-
4
- Provides transitive dependency resolution from Maven Central.
5
-
6
- :author: Ron Webb
7
- :since: 1.0.0
8
- """
9
-
10
- __author__ = "Ron Webb"
11
- __since__ = "1.0.0"
1
+ """
2
+ resolvers package.
3
+
4
+ Provides transitive dependency resolution from Maven Central.
5
+
6
+ :author: Ron Webb
7
+ :since: 1.0.0
8
+ """
9
+
10
+ __author__ = "Ron Webb"
11
+ __since__ = "1.0.0"
@@ -71,7 +71,9 @@ class TransitiveResolver:
71
71
  _visited = set()
72
72
 
73
73
  if depth >= _MAX_DEPTH:
74
- _logger.debug("Max depth %d reached at %s", _MAX_DEPTH, dependency.coordinates)
74
+ _logger.debug(
75
+ "Max depth %d reached at %s", _MAX_DEPTH, dependency.coordinates
76
+ )
75
77
  return dependency
76
78
 
77
79
  key = dependency.coordinates
@@ -132,8 +134,7 @@ class TransitiveResolver:
132
134
  :since: 1.0.0
133
135
  """
134
136
  return (
135
- f"{_MAVEN_CENTRAL}/{dep.maven_path}"
136
- f"/{dep.artifact_id}-{dep.version}.pom"
137
+ f"{_MAVEN_CENTRAL}/{dep.maven_path}" f"/{dep.artifact_id}-{dep.version}.pom"
137
138
  )
138
139
 
139
140
  def _fetch_pom(self, url: str) -> bytes | None:
@@ -162,7 +163,9 @@ class TransitiveResolver:
162
163
  :since: 1.0.0
163
164
  """
164
165
  try:
165
- root = etree.fromstring(pom_content) # nosec B320 # pylint: disable=c-extension-no-member
166
+ root = etree.fromstring(
167
+ pom_content
168
+ ) # nosec B320 # pylint: disable=c-extension-no-member
166
169
  except etree.XMLSyntaxError as exc: # pylint: disable=c-extension-no-member
167
170
  _logger.warning("Could not parse POM for %s: %s", parent.coordinates, exc)
168
171
  return []
@@ -171,7 +174,9 @@ class TransitiveResolver:
171
174
  ns_prefix = "m:" if root.tag.startswith("{") else ""
172
175
 
173
176
  def find(node: etree._Element, tag: str) -> etree._Element | None:
174
- return node.find(f"{ns_prefix}{tag}", ns_map) if ns_prefix else node.find(tag)
177
+ return (
178
+ node.find(f"{ns_prefix}{tag}", ns_map) if ns_prefix else node.find(tag)
179
+ )
175
180
 
176
181
  def text(node: etree._Element, tag: str) -> str:
177
182
  child = find(node, tag)
@@ -213,15 +218,15 @@ class TransitiveResolver:
213
218
  """
214
219
  props: dict[str, str] = {}
215
220
  props_el = (
216
- root.find("m:properties", ns_map)
217
- if ns_prefix
218
- else root.find("properties")
221
+ root.find("m:properties", ns_map) if ns_prefix else root.find("properties")
219
222
  )
220
223
  if props_el is not None:
221
224
  for child in props_el:
222
225
  if not isinstance(child.tag, str): # skip comments and PIs
223
226
  continue
224
- local = etree.QName(child.tag).localname # pylint: disable=c-extension-no-member
227
+ local = etree.QName(
228
+ child.tag
229
+ ).localname # pylint: disable=c-extension-no-member
225
230
  if child.text:
226
231
  props[local] = child.text.strip()
227
232
  return props
@@ -83,9 +83,7 @@ class VulnerabilityScanner(ABC):
83
83
  payload,
84
84
  )
85
85
 
86
- def _apply_cache_source(
87
- self, data: str, source: str
88
- ) -> list[Vulnerability]:
86
+ def _apply_cache_source(self, data: str, source: str) -> list[Vulnerability]:
89
87
  """
90
88
  Deserialise *data* (a cached JSON string), parse into ``Vulnerability``
91
89
  objects, and mark each with ``source = "<source>-cache"``.
@@ -97,7 +97,8 @@ class GhsaScanner(VulnerabilityScanner):
97
97
  response = self._client.get(_GHSA_API_URL, params=params)
98
98
  if response.status_code == 429:
99
99
  _logger.warning(
100
- "GitHub Advisory API rate limit exceeded for %s", dependency.coordinates
100
+ "GitHub Advisory API rate limit exceeded for %s",
101
+ dependency.coordinates,
101
102
  )
102
103
  return []
103
104
  response.raise_for_status()
@@ -0,0 +1,28 @@
1
+ [loggers]
2
+ keys=root
3
+
4
+ [handlers]
5
+ keys=consoleHandler,fileHandler
6
+
7
+ [formatters]
8
+ keys=logFormatter,consoleFormatter
9
+
10
+ [logger_root]
11
+ level=INFO
12
+ handlers=consoleHandler,fileHandler
13
+
14
+ [handler_consoleHandler]
15
+ class=StreamHandler
16
+ formatter=consoleFormatter
17
+ args=(sys.stderr,)
18
+
19
+ [handler_fileHandler]
20
+ class=FileHandler
21
+ formatter=logFormatter
22
+ args=('java_dependency_analyzer.log', 'a')
23
+
24
+ [formatter_logFormatter]
25
+ format=%(asctime)s [%(levelname)s] %(name)s - %(message)s
26
+
27
+ [formatter_consoleFormatter]
28
+ format=%(asctime)s - %(name)s - %(levelname)s - %(message)s
@@ -1,37 +1,39 @@
1
- [project]
2
- name = "java-dependency-analyzer"
3
- version = "1.0.0"
4
- description = "Java Dependency Analyzer is a tool that inspects dependencies."
5
- authors = [
6
- {name = "Ron Webb",email = "ron@ronella.xyz"}
7
- ]
8
- readme = "README.md"
9
- requires-python = ">=3.14"
10
- dependencies = [
11
- "click (>=8.3.1,<9.0.0)",
12
- "httpx (>=0.28.1,<0.29.0)",
13
- "beautifulsoup4 (>=4.14.3,<5.0.0)",
14
- "lxml (>=6.0.2,<7.0.0)",
15
- "jinja2 (>=3.1.6,<4.0.0)",
16
- "python-dotenv (>=1.2.2,<2.0.0)"
17
- ]
18
-
19
- [project.scripts]
20
- jda = "java_dependency_analyzer.cli:main"
21
-
22
-
23
- [tool.poetry]
24
- packages = [{include = "java_dependency_analyzer"}]
25
-
26
- [build-system]
27
- requires = ["poetry-core>=2.0.0,<3.0.0"]
28
- build-backend = "poetry.core.masonry.api"
29
-
30
- [dependency-groups]
31
- dev = [
32
- "black (>=26.3.1,<27.0.0)",
33
- "pylint (>=4.0.5,<5.0.0)",
34
- "pytest (>=9.0.2,<10.0.0)",
35
- "pytest-cov (>=7.1.0,<8.0.0)",
36
- "pytest-httpx (>=0.36.0,<0.37.0)"
37
- ]
1
+ [project]
2
+ name = "java-dependency-analyzer"
3
+ version = "1.1.0"
4
+ description = "Java Dependency Analyzer is a tool that inspects dependencies."
5
+ authors = [
6
+ {name = "Ron Webb",email = "ron@ronella.xyz"}
7
+ ]
8
+ readme = "README.md"
9
+ license = {file = "LICENSE"}
10
+ requires-python = ">=3.14"
11
+ dependencies = [
12
+ "click (>=8.3.1,<9.0.0)",
13
+ "httpx (>=0.28.1,<0.29.0)",
14
+ "beautifulsoup4 (>=4.14.3,<5.0.0)",
15
+ "lxml (>=6.0.2,<7.0.0)",
16
+ "jinja2 (>=3.1.6,<4.0.0)",
17
+ "python-dotenv (>=1.2.2,<2.0.0)"
18
+ ]
19
+
20
+ [project.scripts]
21
+ jda = "java_dependency_analyzer.cli:main"
22
+
23
+
24
+ [tool.poetry]
25
+ packages = [{include = "java_dependency_analyzer"}]
26
+ include = ["logging.ini"]
27
+
28
+ [build-system]
29
+ requires = ["poetry-core>=2.0.0,<3.0.0"]
30
+ build-backend = "poetry.core.masonry.api"
31
+
32
+ [dependency-groups]
33
+ dev = [
34
+ "black (>=26.3.1,<27.0.0)",
35
+ "pylint (>=4.0.5,<5.0.0)",
36
+ "pytest (>=9.0.2,<10.0.0)",
37
+ "pytest-cov (>=7.1.0,<8.0.0)",
38
+ "pytest-httpx (>=0.36.0,<0.37.0)"
39
+ ]
@@ -1,11 +0,0 @@
1
- """
2
- java_dependency_analyzer package.
3
-
4
- Java Dependency Analyzer is a tool that inspects dependencies.
5
-
6
- :author: Ron Webb
7
- :since: 1.0.0
8
- """
9
-
10
- __author__ = "Ron Webb"
11
- __since__ = "1.0.0"