stackharbinger 0.3.0 → 1.0.0
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.
- checksums.yaml +4 -4
- data/README.md +143 -35
- data/docs/index.html +70 -23
- data/lib/harbinger/analyzers/database_detector.rb +13 -3
- data/lib/harbinger/analyzers/docker_compose_detector.rb +121 -0
- data/lib/harbinger/analyzers/go_detector.rb +86 -0
- data/lib/harbinger/analyzers/mongo_detector.rb +104 -0
- data/lib/harbinger/analyzers/mysql_detector.rb +8 -1
- data/lib/harbinger/analyzers/node_detector.rb +109 -0
- data/lib/harbinger/analyzers/postgres_detector.rb +6 -0
- data/lib/harbinger/analyzers/python_detector.rb +110 -0
- data/lib/harbinger/analyzers/rails_analyzer.rb +5 -1
- data/lib/harbinger/analyzers/redis_detector.rb +98 -0
- data/lib/harbinger/analyzers/ruby_detector.rb +9 -1
- data/lib/harbinger/analyzers/rust_detector.rb +116 -0
- data/lib/harbinger/cli.rb +453 -149
- data/lib/harbinger/eol_fetcher.rb +19 -10
- data/lib/harbinger/exporters/base_exporter.rb +100 -0
- data/lib/harbinger/exporters/csv_exporter.rb +36 -0
- data/lib/harbinger/exporters/json_exporter.rb +21 -0
- data/lib/harbinger/version.rb +1 -1
- metadata +11 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 1d46315e9aab151406a3993d75a034eaf28f16d1ce92f44b6344438ba8b9c482
|
|
4
|
+
data.tar.gz: b4d3c35c6578600ed85d1a387b1cfe13ce5873c256dce6d20267c0366e329052
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: a6d586f4ccc611050bff15516e5ce10601b21b530c51a899742dd8fb8a167cb2d297d0d182fb3a4536b78d85db09b084c25c646fbf3249fd1120125a614aa50b
|
|
7
|
+
data.tar.gz: a1a0aa1900b07a3be28862e6ad4e3196e05735dc338c22ed592f6ad6d3af6d925764b0c2d957a96fa3d48b9f995e500edcfbb932897237a1a4c44e8bd1d16228
|
data/README.md
CHANGED
|
@@ -2,17 +2,19 @@
|
|
|
2
2
|
|
|
3
3
|
**Track End-of-Life dates for your tech stack and stay ahead of deprecations.**
|
|
4
4
|
|
|
5
|
-
Harbinger is a CLI tool that scans your Ruby, Rails, PostgreSQL, and
|
|
5
|
+
Harbinger is a CLI tool that scans your Ruby, Rails, Python, Node.js, Rust, Go, PostgreSQL, MySQL, Redis, and MongoDB versions, and warns you about upcoming EOL (End-of-Life) dates. Never get caught off-guard by unsupported dependencies again.
|
|
6
6
|
|
|
7
7
|
## Features
|
|
8
8
|
|
|
9
|
-
- 🔍 **Auto-detects versions** from `.ruby-version`, `Gemfile`, `Gemfile.lock`,
|
|
10
|
-
- 🐘 **Database detection** for PostgreSQL
|
|
9
|
+
- 🔍 **Auto-detects versions** from `.ruby-version`, `Gemfile`, `Gemfile.lock`, `.nvmrc`, `.python-version`, `pyproject.toml`, `package.json`, `rust-toolchain`, `Cargo.toml`, `go.mod`, `config/database.yml`, and `docker-compose.yml`
|
|
10
|
+
- 🐘 **Database detection** for PostgreSQL, MySQL, Redis, and MongoDB
|
|
11
|
+
- 🌐 **Multi-language support** - Ruby, Python, Node.js, Rust, Go
|
|
12
|
+
- 📊 **Ecosystem-grouped dashboard** - Projects organized by language ecosystem with relevant components only
|
|
11
13
|
- 📅 **Fetches EOL data** from [endoflife.date](https://endoflife.date)
|
|
12
14
|
- 🎨 **Color-coded warnings** (red: already EOL, yellow: <6 months, green: safe)
|
|
13
15
|
- ⚡ **Smart caching** (24-hour cache, works offline after first fetch)
|
|
14
|
-
- 📊 **Track multiple projects** with `--save` and view dashboard with `harbinger show`
|
|
15
16
|
- 🔄 **Bulk operations** with `--recursive` scan and `rescan` command
|
|
17
|
+
- 📤 **Export to JSON/CSV** for reporting and automation
|
|
16
18
|
- 🚀 **Zero configuration** - just run `harbinger scan`
|
|
17
19
|
|
|
18
20
|
## Installation
|
|
@@ -86,23 +88,72 @@ PostgreSQL 16.11:
|
|
|
86
88
|
```bash
|
|
87
89
|
# Show dashboard of all tracked projects
|
|
88
90
|
harbinger show
|
|
91
|
+
|
|
92
|
+
# Filter to specific project(s) by name or path
|
|
93
|
+
harbinger show budget
|
|
94
|
+
harbinger show job
|
|
95
|
+
|
|
96
|
+
# Show project paths with verbose mode
|
|
97
|
+
harbinger show -v
|
|
98
|
+
harbinger show job --verbose
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
### Export data
|
|
102
|
+
|
|
103
|
+
```bash
|
|
104
|
+
# Export to JSON (stdout)
|
|
105
|
+
harbinger show --format json
|
|
106
|
+
|
|
107
|
+
# Export to CSV (stdout)
|
|
108
|
+
harbinger show --format csv
|
|
109
|
+
|
|
110
|
+
# Save to file
|
|
111
|
+
harbinger show --format json -o report.json
|
|
112
|
+
harbinger show --format csv --output eol-report.csv
|
|
113
|
+
|
|
114
|
+
# Export filtered projects
|
|
115
|
+
harbinger show myproject --format json
|
|
89
116
|
```
|
|
90
117
|
|
|
91
118
|
**Example output:**
|
|
92
119
|
|
|
93
120
|
```
|
|
94
|
-
Tracked Projects (
|
|
121
|
+
Tracked Projects (12)
|
|
122
|
+
|
|
123
|
+
Ruby Ecosystem (7)
|
|
124
|
+
================================================================================
|
|
125
|
+
┌─────────────────┬───────┬──────────┬────────────┬───────┬─────────────────┐
|
|
126
|
+
│ Project │ Ruby │ Rails │ PostgreSQL │ Redis │ Status │
|
|
127
|
+
├─────────────────┼───────┼──────────┼────────────┼───────┼─────────────────┤
|
|
128
|
+
│ shop-api │ 3.2.0 │ 6.1.7 │ 15.0 │ - │ ✗ Rails EOL │
|
|
129
|
+
│ blog-engine │ 3.3.0 │ 7.0.8 │ 16.0 │ 7.0 │ ✗ Rails EOL │
|
|
130
|
+
│ analytics-app │ 3.3.0 │ 8.0.1 │ 16.0 │ - │ ✓ Current │
|
|
131
|
+
│ admin-portal │ 3.3.0 │ 8.0.4 │ 16.11 │ 7.2 │ ✓ Current │
|
|
132
|
+
│ billing-service │ 3.4.1 │ 8.1.0 │ 17.0 │ - │ ✓ Current │
|
|
133
|
+
└─────────────────┴───────┴──────────┴────────────┴───────┴─────────────────┘
|
|
134
|
+
|
|
135
|
+
Python Ecosystem (3)
|
|
136
|
+
================================================================================
|
|
137
|
+
┌──────────────┬────────┬────────────┬─────────┐
|
|
138
|
+
│ Project │ Python │ PostgreSQL │ Status │
|
|
139
|
+
├──────────────┼────────┼────────────┼─────────┤
|
|
140
|
+
│ ml-pipeline │ 3.11 │ 16.0 │ ✓ Current │
|
|
141
|
+
│ data-scraper │ 3.12 │ - │ ✓ Current │
|
|
142
|
+
│ ai-worker │ 3.13 │ 15.0 │ ✓ Current │
|
|
143
|
+
└──────────────┴────────┴────────────┴─────────┘
|
|
144
|
+
|
|
145
|
+
Node.js Ecosystem (2)
|
|
95
146
|
================================================================================
|
|
96
|
-
|
|
97
|
-
│ Project
|
|
98
|
-
|
|
99
|
-
│
|
|
100
|
-
│
|
|
101
|
-
|
|
102
|
-
│ job_tracker │ 3.3.0 │ 8.0.4 │ 16.11 │ - │ ✓ Current │
|
|
103
|
-
└───────────────────┴───────┴──────────┴────────────┴───────┴─────────────┘
|
|
147
|
+
┌───────────────┬─────────┬────────────┬──────────────────────┐
|
|
148
|
+
│ Project │ Node.js │ PostgreSQL │ Status │
|
|
149
|
+
├───────────────┼─────────┼────────────┼──────────────────────┤
|
|
150
|
+
│ frontend-app │ 18.0 │ - │ ⚠ Node.js ending soon │
|
|
151
|
+
│ realtime-api │ 22.0 │ 16.0 │ ✓ Current │
|
|
152
|
+
└───────────────┴─────────┴────────────┴──────────────────────┘
|
|
104
153
|
```
|
|
105
154
|
|
|
155
|
+
Projects are grouped by their primary programming language ecosystem. Each ecosystem only displays relevant components (e.g., Python projects don't show Ruby/Rails columns).
|
|
156
|
+
|
|
106
157
|
### Re-scan all tracked projects
|
|
107
158
|
|
|
108
159
|
```bash
|
|
@@ -113,6 +164,13 @@ harbinger rescan
|
|
|
113
164
|
harbinger rescan --verbose
|
|
114
165
|
```
|
|
115
166
|
|
|
167
|
+
### Remove a project
|
|
168
|
+
|
|
169
|
+
```bash
|
|
170
|
+
# Remove a project from tracking
|
|
171
|
+
harbinger remove my-project
|
|
172
|
+
```
|
|
173
|
+
|
|
116
174
|
### Update EOL data
|
|
117
175
|
|
|
118
176
|
```bash
|
|
@@ -131,8 +189,14 @@ harbinger version
|
|
|
131
189
|
1. **Detection**: Harbinger looks for version info in your project:
|
|
132
190
|
- Ruby: `.ruby-version`, `Gemfile` (`ruby "x.x.x"`), `Gemfile.lock` (RUBY VERSION)
|
|
133
191
|
- Rails: `Gemfile.lock` (rails gem)
|
|
192
|
+
- Python: `.python-version`, `pyproject.toml`, `docker-compose.yml`, or `python --version`
|
|
193
|
+
- Node.js: `.nvmrc`, `.node-version`, `package.json` engines, `docker-compose.yml`, or `node --version`
|
|
194
|
+
- Rust: `rust-toolchain`, `rust-toolchain.toml`, `Cargo.toml` (rust-version), `docker-compose.yml`, or `rustc --version`
|
|
195
|
+
- Go: `go.mod`, `go.work`, `.go-version`, `docker-compose.yml`, or `go version`
|
|
134
196
|
- PostgreSQL: `config/database.yml` (adapter check) + `psql --version` or `pg` gem
|
|
135
197
|
- MySQL: `config/database.yml` (mysql2/trilogy adapter) + `mysql --version` or gem version
|
|
198
|
+
- Redis: `docker-compose.yml` + `redis-server --version` or `redis` gem
|
|
199
|
+
- MongoDB: `docker-compose.yml` + `mongod --version` or `mongoid`/`mongo` gem
|
|
136
200
|
|
|
137
201
|
2. **EOL Data**: Fetches official EOL dates from [endoflife.date](https://endoflife.date) API
|
|
138
202
|
|
|
@@ -173,6 +237,53 @@ Parses `Gemfile.lock` for the rails gem version.
|
|
|
173
237
|
|
|
174
238
|
**Supported adapters**: `mysql2` (traditional) and `trilogy` (Rails 7.1+)
|
|
175
239
|
|
|
240
|
+
### Redis Detection
|
|
241
|
+
|
|
242
|
+
1. Checks `docker-compose.yml` for redis image with version tag
|
|
243
|
+
2. Tries `redis-server --version` for local installations
|
|
244
|
+
3. Falls back to `redis` gem version from `Gemfile.lock`
|
|
245
|
+
|
|
246
|
+
### MongoDB Detection
|
|
247
|
+
|
|
248
|
+
1. Checks `docker-compose.yml` for mongo image with version tag
|
|
249
|
+
2. Tries `mongod --version` for local installations
|
|
250
|
+
3. Falls back to `mongoid` or `mongo` gem version from `Gemfile.lock`
|
|
251
|
+
|
|
252
|
+
### Python Detection
|
|
253
|
+
|
|
254
|
+
1. `.python-version` file (highest priority)
|
|
255
|
+
2. `pyproject.toml` (`requires-python` field)
|
|
256
|
+
3. Docker Compose `python:*` images
|
|
257
|
+
4. `python --version` for system installation
|
|
258
|
+
|
|
259
|
+
### Node.js Detection
|
|
260
|
+
|
|
261
|
+
1. `.nvmrc` or `.node-version` files (highest priority - explicit version specification)
|
|
262
|
+
2. `package.json` `engines.node` field (e.g., ">=18.0.0")
|
|
263
|
+
3. Docker Compose `node:*` images
|
|
264
|
+
4. `node --version` for system installation
|
|
265
|
+
|
|
266
|
+
**Version Normalization**: Handles constraint operators (`>=`, `^`, `~`), LTS names (`lts/hydrogen`), and version ranges
|
|
267
|
+
|
|
268
|
+
### Rust Detection
|
|
269
|
+
|
|
270
|
+
1. `rust-toolchain` or `rust-toolchain.toml` files (highest priority - explicit toolchain specification)
|
|
271
|
+
2. `Cargo.toml` `rust-version` field (MSRV - Minimum Supported Rust Version)
|
|
272
|
+
3. Docker Compose `rust:*` images
|
|
273
|
+
4. `rustc --version` for system installation (only when Rust project files exist)
|
|
274
|
+
|
|
275
|
+
**Note:** Symbolic channels like "stable", "beta", "nightly" are skipped as they don't provide specific versions.
|
|
276
|
+
|
|
277
|
+
### Go Detection
|
|
278
|
+
|
|
279
|
+
1. `go.mod` file (highest priority - standard Go module version specification)
|
|
280
|
+
2. `go.work` file (Go workspace format)
|
|
281
|
+
3. `.go-version` file
|
|
282
|
+
4. Docker Compose `golang:*` images
|
|
283
|
+
5. `go version` for system installation (only when Go project files exist)
|
|
284
|
+
|
|
285
|
+
**Note:** Shell fallback only executes when Go project files are detected, preventing unnecessary command execution.
|
|
286
|
+
|
|
176
287
|
## Requirements
|
|
177
288
|
|
|
178
289
|
- Ruby >= 3.1.0
|
|
@@ -197,30 +308,27 @@ bundle exec exe/harbinger scan .
|
|
|
197
308
|
|
|
198
309
|
## Roadmap
|
|
199
310
|
|
|
200
|
-
###
|
|
201
|
-
- ✅
|
|
202
|
-
- ✅ MySQL version detection
|
|
203
|
-
- ✅
|
|
204
|
-
- ✅
|
|
205
|
-
- ✅
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
-
|
|
211
|
-
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
- 🐍 Python support (pyproject.toml, requirements.txt)
|
|
215
|
-
- 📦 Node.js support (package.json, .nvmrc)
|
|
216
|
-
- 🦀 Rust support (Cargo.toml)
|
|
217
|
-
- 🐘 Go support (go.mod)
|
|
311
|
+
### V1.0 - Current (Ready for Release!)
|
|
312
|
+
- ✅ Ruby, Rails, Python, Node.js, Rust, Go version detection
|
|
313
|
+
- ✅ PostgreSQL, MySQL, Redis, MongoDB version detection
|
|
314
|
+
- ✅ Ecosystem-grouped dashboard with smart component display
|
|
315
|
+
- ✅ Export reports to JSON/CSV
|
|
316
|
+
- ✅ Bulk scanning with `--recursive` and `rescan` commands
|
|
317
|
+
- ✅ 24-hour smart caching for offline support
|
|
318
|
+
- ✅ Color-coded EOL warnings
|
|
319
|
+
|
|
320
|
+
### V1.1 - Next
|
|
321
|
+
- 🔷 TypeScript version detection
|
|
322
|
+
- 🎯 Framework detection (Django, Flask, Express, Gin)
|
|
323
|
+
- 📦 Package manager detection (npm, yarn, pip, bundler, go modules versions)
|
|
324
|
+
- 🔍 Dependency vulnerability scanning integration
|
|
218
325
|
|
|
219
326
|
### V2.0 - Vision
|
|
220
|
-
- 🤖 AI-powered upgrade summaries
|
|
221
|
-
- 📧 Email/Slack notifications
|
|
222
|
-
- ☁️ Cloud platform detection (AWS, Heroku,
|
|
223
|
-
- 👥 Team collaboration features
|
|
327
|
+
- 🤖 AI-powered upgrade summaries and breaking change analysis
|
|
328
|
+
- 📧 Email/Slack notifications for approaching EOL dates
|
|
329
|
+
- ☁️ Cloud platform detection (AWS, Heroku, Render)
|
|
330
|
+
- 👥 Team collaboration features (shared dashboards)
|
|
331
|
+
- 📈 Historical tracking and trends
|
|
224
332
|
|
|
225
333
|
## Contributing
|
|
226
334
|
|
data/docs/index.html
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
<meta charset="UTF-8">
|
|
5
5
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
6
|
<title>Harbinger - Track EOL Dates for Your Tech Stack</title>
|
|
7
|
-
<meta name="description" content="Never get caught off-guard by unsupported dependencies. Harbinger tracks End-of-Life dates for Ruby, Rails, and
|
|
7
|
+
<meta name="description" content="Never get caught off-guard by unsupported dependencies. Harbinger tracks End-of-Life dates for Ruby, Rails, PostgreSQL, MySQL, Redis, MongoDB, Python, Node.js, and Rust.">
|
|
8
8
|
<script src="https://cdn.tailwindcss.com"></script>
|
|
9
9
|
<style>
|
|
10
10
|
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;600;700;900&display=swap');
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
<div class="max-w-6xl mx-auto px-4 py-20">
|
|
18
18
|
<h1 class="text-5xl md:text-7xl font-black mb-6">Harbinger</h1>
|
|
19
19
|
<p class="text-2xl md:text-3xl mb-8 text-blue-100">Track End-of-Life dates for your tech stack</p>
|
|
20
|
-
<p class="text-xl mb-12 text-blue-100 max-w-2xl">Never get caught off-guard by unsupported dependencies. Harbinger scans your Ruby and
|
|
20
|
+
<p class="text-xl mb-12 text-blue-100 max-w-2xl">Never get caught off-guard by unsupported dependencies. Harbinger scans your Ruby, Rails, Python, Node.js, Rust, Go, PostgreSQL, MySQL, Redis, and MongoDB versions and warns you before support ends.</p>
|
|
21
21
|
|
|
22
22
|
<div class="flex flex-col sm:flex-row gap-4">
|
|
23
23
|
<div class="bg-gray-900 rounded-lg p-4 font-mono text-sm">
|
|
@@ -38,7 +38,7 @@
|
|
|
38
38
|
<div class="bg-white p-6 rounded-lg shadow-sm">
|
|
39
39
|
<div class="text-4xl mb-4">🔍</div>
|
|
40
40
|
<h3 class="text-xl font-semibold mb-2">Auto-Detection</h3>
|
|
41
|
-
<p class="text-gray-600">
|
|
41
|
+
<p class="text-gray-600">Detects Ruby, Rails, Python, Node.js, Rust, Go, PostgreSQL, MySQL, Redis, and MongoDB versions from project files and Docker configs</p>
|
|
42
42
|
</div>
|
|
43
43
|
<div class="bg-white p-6 rounded-lg shadow-sm">
|
|
44
44
|
<div class="text-4xl mb-4">📅</div>
|
|
@@ -62,8 +62,8 @@
|
|
|
62
62
|
</div>
|
|
63
63
|
<div class="bg-white p-6 rounded-lg shadow-sm">
|
|
64
64
|
<div class="text-4xl mb-4">📊</div>
|
|
65
|
-
<h3 class="text-xl font-semibold mb-2">
|
|
66
|
-
<p class="text-gray-600">
|
|
65
|
+
<h3 class="text-xl font-semibold mb-2">Ecosystem Grouping</h3>
|
|
66
|
+
<p class="text-gray-600">Projects organized by language ecosystem (Ruby, Python, Node.js, Rust) with only relevant components displayed</p>
|
|
67
67
|
</div>
|
|
68
68
|
<div class="bg-white p-6 rounded-lg shadow-sm">
|
|
69
69
|
<div class="text-4xl mb-4">🔄</div>
|
|
@@ -73,7 +73,7 @@
|
|
|
73
73
|
<div class="bg-white p-6 rounded-lg shadow-sm">
|
|
74
74
|
<div class="text-4xl mb-4">🧪</div>
|
|
75
75
|
<h3 class="text-xl font-semibold mb-2">Well Tested</h3>
|
|
76
|
-
<p class="text-gray-600">
|
|
76
|
+
<p class="text-gray-600">146 RSpec tests with 100% pass rate, built with TDD</p>
|
|
77
77
|
</div>
|
|
78
78
|
</div>
|
|
79
79
|
</div>
|
|
@@ -109,12 +109,58 @@
|
|
|
109
109
|
</div>
|
|
110
110
|
|
|
111
111
|
<div class="prose max-w-none">
|
|
112
|
-
<h3 class="text-2xl font-semibold mb-4">
|
|
112
|
+
<h3 class="text-2xl font-semibold mb-4">Dashboard with Ecosystem Grouping</h3>
|
|
113
|
+
<p class="text-gray-600 mb-4">Projects are organized by their primary programming language ecosystem, showing only relevant components:</p>
|
|
114
|
+
|
|
115
|
+
<div class="bg-gray-900 rounded-lg p-6 font-mono text-xs overflow-x-auto mb-8">
|
|
116
|
+
<div class="text-gray-400 mb-1">$ harbinger show</div>
|
|
117
|
+
<div class="text-white mb-2">Tracked Projects (12)</div>
|
|
118
|
+
|
|
119
|
+
<div class="text-cyan-400 mt-3 mb-1">Ruby Ecosystem (7)</div>
|
|
120
|
+
<div class="text-gray-400">================================================================================</div>
|
|
121
|
+
<div class="text-white">
|
|
122
|
+
<div>┌─────────────────┬───────┬──────────┬────────────┬───────┬─────────────────┐</div>
|
|
123
|
+
<div>│ Project │ Ruby │ Rails │ PostgreSQL │ Redis │ Status │</div>
|
|
124
|
+
<div>├─────────────────┼───────┼──────────┼────────────┼───────┼─────────────────┤</div>
|
|
125
|
+
<div>│ shop-api │ 3.2.0 │ 6.1.7 │ 15.0 │ - │ <span class="text-red-400">✗ Rails EOL</span> │</div>
|
|
126
|
+
<div>│ blog-engine │ 3.3.0 │ 7.0.8 │ 16.0 │ 7.0 │ <span class="text-red-400">✗ Rails EOL</span> │</div>
|
|
127
|
+
<div>│ admin-portal │ 3.3.0 │ 8.0.4 │ 16.11 │ 7.2 │ <span class="text-green-400">✓ Current</span> │</div>
|
|
128
|
+
<div>└─────────────────┴───────┴──────────┴────────────┴───────┴─────────────────┘</div>
|
|
129
|
+
</div>
|
|
130
|
+
|
|
131
|
+
<div class="text-cyan-400 mt-3 mb-1">Python Ecosystem (3)</div>
|
|
132
|
+
<div class="text-gray-400">================================================================================</div>
|
|
133
|
+
<div class="text-white">
|
|
134
|
+
<div>┌──────────────┬────────┬────────────┬─────────┐</div>
|
|
135
|
+
<div>│ Project │ Python │ PostgreSQL │ Status │</div>
|
|
136
|
+
<div>├──────────────┼────────┼────────────┼─────────┤</div>
|
|
137
|
+
<div>│ ml-pipeline │ 3.11 │ 16.0 │ <span class="text-green-400">✓ Current</span> │</div>
|
|
138
|
+
<div>│ data-scraper │ 3.12 │ - │ <span class="text-green-400">✓ Current</span> │</div>
|
|
139
|
+
<div>└──────────────┴────────┴────────────┴─────────┘</div>
|
|
140
|
+
</div>
|
|
141
|
+
|
|
142
|
+
<div class="text-cyan-400 mt-3 mb-1">Node.js Ecosystem (2)</div>
|
|
143
|
+
<div class="text-gray-400">================================================================================</div>
|
|
144
|
+
<div class="text-white">
|
|
145
|
+
<div>┌──────────────┬─────────┬────────────┬─────────┐</div>
|
|
146
|
+
<div>│ Project │ Node.js │ PostgreSQL │ Status │</div>
|
|
147
|
+
<div>├──────────────┼─────────┼────────────┼─────────┤</div>
|
|
148
|
+
<div>│ frontend-app │ 18.0 │ - │ <span class="text-yellow-400">⚠ Node.js ending soon</span> │</div>
|
|
149
|
+
<div>│ realtime-api │ 22.0 │ 16.0 │ <span class="text-green-400">✓ Current</span> │</div>
|
|
150
|
+
<div>└──────────────┴─────────┴────────────┴─────────┘</div>
|
|
151
|
+
</div>
|
|
152
|
+
</div>
|
|
153
|
+
|
|
154
|
+
<h3 class="text-2xl font-semibold mb-4 mt-8">Commands</h3>
|
|
113
155
|
<ul class="space-y-3 text-gray-700">
|
|
114
156
|
<li><code class="bg-gray-100 px-2 py-1 rounded">harbinger scan --path [PATH]</code> - Scan a project and show EOL status</li>
|
|
115
157
|
<li><code class="bg-gray-100 px-2 py-1 rounded">harbinger scan --save</code> - Save project for tracking</li>
|
|
116
158
|
<li><code class="bg-gray-100 px-2 py-1 rounded">harbinger scan --recursive</code> - Scan all projects in a directory</li>
|
|
117
|
-
<li><code class="bg-gray-100 px-2 py-1 rounded">harbinger show</code> - View dashboard
|
|
159
|
+
<li><code class="bg-gray-100 px-2 py-1 rounded">harbinger show [PROJECT] [-v]</code> - View dashboard (filter by name/path, -v shows paths)</li>
|
|
160
|
+
<li><code class="bg-gray-100 px-2 py-1 rounded">harbinger show --format json|csv</code> - Export data to JSON or CSV</li>
|
|
161
|
+
<li><code class="bg-gray-100 px-2 py-1 rounded">harbinger show --format json -o report.json</code> - Save export to file</li>
|
|
162
|
+
<li><code class="bg-gray-100 px-2 py-1 rounded">harbinger rescan</code> - Re-scan all tracked projects and update versions</li>
|
|
163
|
+
<li><code class="bg-gray-100 px-2 py-1 rounded">harbinger remove PROJECT</code> - Remove a project from tracking</li>
|
|
118
164
|
<li><code class="bg-gray-100 px-2 py-1 rounded">harbinger update</code> - Force refresh EOL data from API</li>
|
|
119
165
|
<li><code class="bg-gray-100 px-2 py-1 rounded">harbinger version</code> - Show harbinger version</li>
|
|
120
166
|
</ul>
|
|
@@ -127,30 +173,31 @@
|
|
|
127
173
|
<h2 class="text-3xl font-bold mb-8 text-center">Roadmap</h2>
|
|
128
174
|
<div class="grid md:grid-cols-3 gap-8">
|
|
129
175
|
<div>
|
|
130
|
-
<h3 class="text-xl font-semibold mb-4 text-green-600">✅
|
|
176
|
+
<h3 class="text-xl font-semibold mb-4 text-green-600">✅ V1.0 (Current)</h3>
|
|
131
177
|
<ul class="space-y-2 text-gray-600">
|
|
132
|
-
<li>•
|
|
133
|
-
<li>•
|
|
134
|
-
<li>•
|
|
135
|
-
<li>•
|
|
178
|
+
<li>• Ruby, Rails, Python, Node.js, Rust, Go</li>
|
|
179
|
+
<li>• PostgreSQL, MySQL, Redis, MongoDB</li>
|
|
180
|
+
<li>• Ecosystem-grouped dashboard</li>
|
|
181
|
+
<li>• Export to JSON/CSV</li>
|
|
182
|
+
<li>• Bulk scanning & rescan</li>
|
|
136
183
|
</ul>
|
|
137
184
|
</div>
|
|
138
185
|
<div>
|
|
139
|
-
<h3 class="text-xl font-semibold mb-4 text-blue-600">📋
|
|
186
|
+
<h3 class="text-xl font-semibold mb-4 text-blue-600">📋 V1.1 (Next)</h3>
|
|
140
187
|
<ul class="space-y-2 text-gray-600">
|
|
141
|
-
<li>•
|
|
142
|
-
<li>•
|
|
143
|
-
<li>•
|
|
144
|
-
<li>•
|
|
188
|
+
<li>• TypeScript detection</li>
|
|
189
|
+
<li>• Framework detection (Django, Flask, Express, Gin)</li>
|
|
190
|
+
<li>• Package manager versions</li>
|
|
191
|
+
<li>• Vulnerability scanning integration</li>
|
|
145
192
|
</ul>
|
|
146
193
|
</div>
|
|
147
194
|
<div>
|
|
148
|
-
<h3 class="text-xl font-semibold mb-4 text-purple-600">🚀
|
|
195
|
+
<h3 class="text-xl font-semibold mb-4 text-purple-600">🚀 V2.0 (Vision)</h3>
|
|
149
196
|
<ul class="space-y-2 text-gray-600">
|
|
150
|
-
<li>•
|
|
151
|
-
<li>•
|
|
152
|
-
<li>•
|
|
153
|
-
<li>•
|
|
197
|
+
<li>• AI-powered upgrade summaries</li>
|
|
198
|
+
<li>• Email/Slack notifications</li>
|
|
199
|
+
<li>• Cloud platform detection</li>
|
|
200
|
+
<li>• Team collaboration</li>
|
|
154
201
|
</ul>
|
|
155
202
|
</div>
|
|
156
203
|
</div>
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
require "English"
|
|
3
4
|
require "yaml"
|
|
4
5
|
|
|
5
6
|
module Harbinger
|
|
@@ -17,7 +18,11 @@ module Harbinger
|
|
|
17
18
|
def detect
|
|
18
19
|
return nil unless database_detected?
|
|
19
20
|
|
|
20
|
-
# Try
|
|
21
|
+
# Try docker-compose.yml first (most accurate for Docker-based projects)
|
|
22
|
+
version = detect_from_docker_compose
|
|
23
|
+
return version if version
|
|
24
|
+
|
|
25
|
+
# Try shell command (actual database version for non-Docker setups)
|
|
21
26
|
version = detect_from_shell
|
|
22
27
|
return version if version
|
|
23
28
|
|
|
@@ -68,6 +73,11 @@ module Harbinger
|
|
|
68
73
|
raise NotImplementedError, "Subclasses must implement detect_from_shell"
|
|
69
74
|
end
|
|
70
75
|
|
|
76
|
+
# Optional method - subclasses can override to detect from docker-compose.yml
|
|
77
|
+
def detect_from_docker_compose
|
|
78
|
+
nil
|
|
79
|
+
end
|
|
80
|
+
|
|
71
81
|
# Abstract method - must be implemented by subclasses
|
|
72
82
|
# Detects version from Gemfile.lock gem version
|
|
73
83
|
def detect_from_gemfile_lock
|
|
@@ -81,7 +91,7 @@ module Harbinger
|
|
|
81
91
|
|
|
82
92
|
content = File.read(database_yml_path)
|
|
83
93
|
YAML.safe_load(content, aliases: true)
|
|
84
|
-
rescue
|
|
94
|
+
rescue StandardError
|
|
85
95
|
nil
|
|
86
96
|
end
|
|
87
97
|
|
|
@@ -112,7 +122,7 @@ module Harbinger
|
|
|
112
122
|
# Execute shell command safely
|
|
113
123
|
def execute_command(command)
|
|
114
124
|
output = `#{command} 2>&1`.strip
|
|
115
|
-
return nil unless
|
|
125
|
+
return nil unless $CHILD_STATUS.success?
|
|
116
126
|
|
|
117
127
|
output
|
|
118
128
|
rescue StandardError
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "yaml"
|
|
4
|
+
|
|
5
|
+
module Harbinger
|
|
6
|
+
module Analyzers
|
|
7
|
+
# Detects versions from docker-compose.yml and Dockerfile
|
|
8
|
+
class DockerComposeDetector
|
|
9
|
+
attr_reader :project_path
|
|
10
|
+
|
|
11
|
+
def initialize(project_path)
|
|
12
|
+
@project_path = project_path
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
# Extract version from a Docker image in docker-compose.yml
|
|
16
|
+
# e.g., "postgres:16-alpine" => "16", "mysql:8.0" => "8.0"
|
|
17
|
+
def image_version(image_pattern)
|
|
18
|
+
compose = parse_docker_compose
|
|
19
|
+
return nil unless compose
|
|
20
|
+
|
|
21
|
+
services = compose["services"]
|
|
22
|
+
return nil unless services
|
|
23
|
+
|
|
24
|
+
services.each_value do |service|
|
|
25
|
+
image = service["image"]
|
|
26
|
+
next unless image
|
|
27
|
+
|
|
28
|
+
if image.match?(/^#{image_pattern}[:\d]/)
|
|
29
|
+
version = extract_version_from_image(image)
|
|
30
|
+
return version if version
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
nil
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
# Extract Ruby version from Dockerfile
|
|
38
|
+
# e.g., "FROM ruby:3.4.7-slim" => "3.4.7"
|
|
39
|
+
def ruby_version_from_dockerfile
|
|
40
|
+
dockerfile = read_dockerfile
|
|
41
|
+
return nil unless dockerfile
|
|
42
|
+
|
|
43
|
+
# Match patterns like:
|
|
44
|
+
# FROM ruby:3.4.7
|
|
45
|
+
# FROM ruby:3.4.7-slim
|
|
46
|
+
# FROM ruby:3.4.7-alpine
|
|
47
|
+
match = dockerfile.match(/^FROM\s+ruby:(\d+\.\d+(?:\.\d+)?)/i)
|
|
48
|
+
match[1] if match
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
# Extract Rails version from Dockerfile (rare, but possible)
|
|
52
|
+
def rails_version_from_dockerfile
|
|
53
|
+
dockerfile = read_dockerfile
|
|
54
|
+
return nil unless dockerfile
|
|
55
|
+
|
|
56
|
+
# Match patterns like:
|
|
57
|
+
# FROM rails:7.0
|
|
58
|
+
# ARG RAILS_VERSION=7.0.8
|
|
59
|
+
match = dockerfile.match(/^FROM\s+rails:(\d+\.\d+(?:\.\d+)?)/i)
|
|
60
|
+
return match[1] if match
|
|
61
|
+
|
|
62
|
+
match = dockerfile.match(/RAILS_VERSION[=:](\d+\.\d+(?:\.\d+)?)/i)
|
|
63
|
+
match[1] if match
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
# Check if docker-compose.yml exists
|
|
67
|
+
def docker_compose_exists?
|
|
68
|
+
docker_compose_path != nil
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
# Check if Dockerfile exists
|
|
72
|
+
def dockerfile_exists?
|
|
73
|
+
File.exist?(File.join(project_path, "Dockerfile"))
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
private
|
|
77
|
+
|
|
78
|
+
def docker_compose_path
|
|
79
|
+
paths = [
|
|
80
|
+
File.join(project_path, "docker-compose.yml"),
|
|
81
|
+
File.join(project_path, "docker-compose.yaml"),
|
|
82
|
+
File.join(project_path, "compose.yml"),
|
|
83
|
+
File.join(project_path, "compose.yaml")
|
|
84
|
+
]
|
|
85
|
+
paths.find { |p| File.exist?(p) }
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
def parse_docker_compose
|
|
89
|
+
path = docker_compose_path
|
|
90
|
+
return nil unless path
|
|
91
|
+
|
|
92
|
+
YAML.safe_load(File.read(path), aliases: true)
|
|
93
|
+
rescue StandardError
|
|
94
|
+
nil
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
def read_dockerfile
|
|
98
|
+
path = File.join(project_path, "Dockerfile")
|
|
99
|
+
return nil unless File.exist?(path)
|
|
100
|
+
|
|
101
|
+
File.read(path)
|
|
102
|
+
rescue StandardError
|
|
103
|
+
nil
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
# Extract version number from Docker image tag
|
|
107
|
+
# "postgres:16-alpine" => "16"
|
|
108
|
+
# "postgres:16.2" => "16.2"
|
|
109
|
+
# "mysql:8.0.33" => "8.0.33"
|
|
110
|
+
# "redis:7-alpine" => "7"
|
|
111
|
+
def extract_version_from_image(image)
|
|
112
|
+
return nil unless image.include?(":")
|
|
113
|
+
|
|
114
|
+
tag = image.split(":").last
|
|
115
|
+
# Extract leading version number (digits and dots)
|
|
116
|
+
match = tag.match(/^(\d+(?:\.\d+)*)/)
|
|
117
|
+
match[1] if match
|
|
118
|
+
end
|
|
119
|
+
end
|
|
120
|
+
end
|
|
121
|
+
end
|