git-pkgs 0.6.1 → 0.6.2
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/CHANGELOG.md +8 -0
- data/README.md +33 -1
- data/lib/git/pkgs/analyzer.rb +1 -1
- data/lib/git/pkgs/commands/diff.rb +59 -2
- data/lib/git/pkgs/commands/diff_driver.rb +1 -1
- data/lib/git/pkgs/commands/list.rb +8 -0
- data/lib/git/pkgs/commands/stale.rb +32 -2
- data/lib/git/pkgs/commands/tree.rb +44 -2
- data/lib/git/pkgs/commands/why.rb +40 -1
- data/lib/git/pkgs/config.rb +2 -1
- data/lib/git/pkgs/version.rb +1 -1
- data/lib/git/pkgs.rb +71 -0
- metadata +3 -3
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: ec8cddb19542e0519e69be68a3f0b65424c940718ba3bd5304ed93f457078ec7
|
|
4
|
+
data.tar.gz: bce2b1006ad63c0f2269d9321948acfa9cde600e8f8e41b3e606768c8f8b6178
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 1488be447b21af773fc7aa6309d8981bb78b45134a755f56bff38f0cac3c92d861f867fb62c70201c1eec9c1f4b40f042a6804f416f64c952bc008678c756831
|
|
7
|
+
data.tar.gz: 998ca9734325cef27dcd3e09a1c7e68acf212a6974f0bd61adb3257322d92881e1c1cb8995be3935b32253f02a94b15f3e531bc40bf4cd1111933b24cc863275
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,13 @@
|
|
|
1
1
|
## [Unreleased]
|
|
2
2
|
|
|
3
|
+
## [0.6.2] - 2026-01-06
|
|
4
|
+
|
|
5
|
+
- `--format=json` support for `diff`, `tree`, `stale`, and `why` commands
|
|
6
|
+
- Ignore go.sum (checksums only), treat go.mod as lockfile
|
|
7
|
+
- Update ecosystems-bibliothecary to ~> 15.1
|
|
8
|
+
- `--manifest` filter for `list` command to filter by manifest path
|
|
9
|
+
- Stateless parsing API for forge integration (`Git::Pkgs.parse_file`, `parse_files`, `diff_file`)
|
|
10
|
+
|
|
3
11
|
## [0.6.1] - 2026-01-05
|
|
4
12
|
|
|
5
13
|
- Fix `stats` command crash on most changed dependencies query
|
data/README.md
CHANGED
|
@@ -95,6 +95,7 @@ Snapshot Coverage
|
|
|
95
95
|
git pkgs list
|
|
96
96
|
git pkgs list --commit=abc123
|
|
97
97
|
git pkgs list --ecosystem=rubygems
|
|
98
|
+
git pkgs list --manifest=Gemfile
|
|
98
99
|
```
|
|
99
100
|
|
|
100
101
|
Example output:
|
|
@@ -416,7 +417,7 @@ git config --add pkgs.ignoredFiles test/fixtures/package.json
|
|
|
416
417
|
|
|
417
418
|
## Performance
|
|
418
419
|
|
|
419
|
-
Benchmarked on an M1 MacBook Pro analyzing [octobox](https://github.com/octobox/octobox) (
|
|
420
|
+
Benchmarked on an M1 MacBook Pro analyzing [octobox](https://github.com/octobox/octobox) (5193 commits, 8 years of history): init takes about 5 seconds at roughly 1000 commits/sec, producing a 4.8 MB database. About half the commits (2439) had dependency changes.
|
|
420
421
|
|
|
421
422
|
Optimizations:
|
|
422
423
|
- Bulk inserts with transaction batching (500 commits per transaction)
|
|
@@ -433,6 +434,37 @@ Actions, BentoML, Bower, Cargo, Carthage, Clojars, CocoaPods, Cog, Conda, CPAN,
|
|
|
433
434
|
|
|
434
435
|
SBOM formats (CycloneDX, SPDX) are not supported as they duplicate information from the actual lockfiles.
|
|
435
436
|
|
|
437
|
+
## Ruby API
|
|
438
|
+
|
|
439
|
+
For embedding in other tools (like forges), git-pkgs provides a stateless parsing API that doesn't require initializing a database:
|
|
440
|
+
|
|
441
|
+
```ruby
|
|
442
|
+
require "git/pkgs"
|
|
443
|
+
|
|
444
|
+
# Parse a single manifest file
|
|
445
|
+
result = Git::Pkgs.parse_file("Gemfile", content)
|
|
446
|
+
# => { platform: "rubygems", kind: "manifest", dependencies: [...] }
|
|
447
|
+
|
|
448
|
+
# Parse multiple files at once
|
|
449
|
+
results = Git::Pkgs.parse_files({
|
|
450
|
+
"Gemfile" => gemfile_content,
|
|
451
|
+
"package.json" => package_json_content
|
|
452
|
+
})
|
|
453
|
+
|
|
454
|
+
# Diff two versions of a manifest
|
|
455
|
+
diff = Git::Pkgs.diff_file("Gemfile", old_content, new_content)
|
|
456
|
+
# => { path: "Gemfile", platform: "rubygems", added: [...], modified: [...], removed: [...] }
|
|
457
|
+
```
|
|
458
|
+
|
|
459
|
+
The diff_file method returns modified dependencies with a `previous_requirement` field showing the old version.
|
|
460
|
+
|
|
461
|
+
For database queries, connect to an existing database and use the Sequel models directly:
|
|
462
|
+
|
|
463
|
+
```ruby
|
|
464
|
+
Git::Pkgs::Database.connect(repo_git_dir)
|
|
465
|
+
Git::Pkgs::Models::DependencyChange.where(name: "rails").all
|
|
466
|
+
```
|
|
467
|
+
|
|
436
468
|
## Contributing
|
|
437
469
|
|
|
438
470
|
Bug reports, feature requests, and pull requests are welcome. If you're unsure about a change, open an issue first to discuss it.
|
data/lib/git/pkgs/analyzer.rb
CHANGED
|
@@ -18,7 +18,7 @@ module Git
|
|
|
18
18
|
pom.xml ivy.xml build.gradle build.gradle.kts gradle-dependencies-q.txt
|
|
19
19
|
maven-resolved-dependencies.txt sbt-update-full.txt maven-dependency-tree.txt maven-dependency-tree.dot
|
|
20
20
|
Cargo.toml Cargo.lock
|
|
21
|
-
go.mod
|
|
21
|
+
go.mod glide.yaml glide.lock Godeps Godeps/Godeps.json
|
|
22
22
|
vendor/manifest vendor/vendor.json Gopkg.toml Gopkg.lock go-resolved-dependencies.json
|
|
23
23
|
composer.json composer.lock
|
|
24
24
|
Podfile Podfile.lock *.podspec *.podspec.json
|
|
@@ -51,11 +51,20 @@ module Git
|
|
|
51
51
|
changes_list = changes.all
|
|
52
52
|
|
|
53
53
|
if changes_list.empty?
|
|
54
|
-
|
|
54
|
+
if @options[:format] == "json"
|
|
55
|
+
require "json"
|
|
56
|
+
puts JSON.pretty_generate({ from: from_commit.short_sha, to: to_commit.short_sha, added: [], modified: [], removed: [] })
|
|
57
|
+
else
|
|
58
|
+
empty_result "No dependency changes between #{from_commit.short_sha} and #{to_commit.short_sha}"
|
|
59
|
+
end
|
|
55
60
|
return
|
|
56
61
|
end
|
|
57
62
|
|
|
58
|
-
|
|
63
|
+
if @options[:format] == "json"
|
|
64
|
+
output_json(from_commit, to_commit, changes_list)
|
|
65
|
+
else
|
|
66
|
+
paginate { output_text(from_commit, to_commit, changes_list) }
|
|
67
|
+
end
|
|
59
68
|
end
|
|
60
69
|
|
|
61
70
|
def output_text(from_commit, to_commit, changes)
|
|
@@ -101,6 +110,50 @@ module Git
|
|
|
101
110
|
puts "Summary: #{added_count} #{removed_count} #{modified_count}"
|
|
102
111
|
end
|
|
103
112
|
|
|
113
|
+
def output_json(from_commit, to_commit, changes)
|
|
114
|
+
require "json"
|
|
115
|
+
|
|
116
|
+
added = changes.select { |c| c.change_type == "added" }
|
|
117
|
+
modified = changes.select { |c| c.change_type == "modified" }
|
|
118
|
+
removed = changes.select { |c| c.change_type == "removed" }
|
|
119
|
+
|
|
120
|
+
format_change = lambda do |change|
|
|
121
|
+
{
|
|
122
|
+
name: change.name,
|
|
123
|
+
ecosystem: change.ecosystem,
|
|
124
|
+
requirement: change.requirement,
|
|
125
|
+
manifest: change.manifest.path,
|
|
126
|
+
commit: change.commit.short_sha,
|
|
127
|
+
date: change.commit.committed_at.iso8601
|
|
128
|
+
}
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
format_modified = lambda do |first, latest|
|
|
132
|
+
{
|
|
133
|
+
name: first.name,
|
|
134
|
+
ecosystem: first.ecosystem,
|
|
135
|
+
previous_requirement: first.previous_requirement,
|
|
136
|
+
requirement: latest.requirement,
|
|
137
|
+
manifest: latest.manifest.path
|
|
138
|
+
}
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
data = {
|
|
142
|
+
from: from_commit.short_sha,
|
|
143
|
+
to: to_commit.short_sha,
|
|
144
|
+
added: added.group_by(&:name).map { |_name, pkg_changes| format_change.call(pkg_changes.last) },
|
|
145
|
+
modified: modified.group_by(&:name).map { |_name, pkg_changes| format_modified.call(pkg_changes.first, pkg_changes.last) },
|
|
146
|
+
removed: removed.group_by(&:name).map { |_name, pkg_changes| format_change.call(pkg_changes.last) },
|
|
147
|
+
summary: {
|
|
148
|
+
added: added.map(&:name).uniq.count,
|
|
149
|
+
modified: modified.map(&:name).uniq.count,
|
|
150
|
+
removed: removed.map(&:name).uniq.count
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
puts JSON.pretty_generate(data)
|
|
155
|
+
end
|
|
156
|
+
|
|
104
157
|
def parse_range_argument
|
|
105
158
|
return [nil, nil] if @args.empty?
|
|
106
159
|
|
|
@@ -142,6 +195,10 @@ module Git
|
|
|
142
195
|
options[:ecosystem] = v
|
|
143
196
|
end
|
|
144
197
|
|
|
198
|
+
opts.on("-f", "--format=FORMAT", "Output format (text, json)") do |v|
|
|
199
|
+
options[:format] = v
|
|
200
|
+
end
|
|
201
|
+
|
|
145
202
|
opts.on("--no-pager", "Do not pipe output into a pager") do
|
|
146
203
|
options[:no_pager] = true
|
|
147
204
|
end
|
|
@@ -25,6 +25,10 @@ module Git
|
|
|
25
25
|
deps = compute_dependencies_at_commit(target_commit, repo)
|
|
26
26
|
|
|
27
27
|
# Apply filters
|
|
28
|
+
if @options[:manifest]
|
|
29
|
+
deps = deps.select { |d| d[:manifest_path] == @options[:manifest] }
|
|
30
|
+
end
|
|
31
|
+
|
|
28
32
|
if @options[:ecosystem]
|
|
29
33
|
deps = deps.select { |d| d[:ecosystem] == @options[:ecosystem] }
|
|
30
34
|
end
|
|
@@ -133,6 +137,10 @@ module Git
|
|
|
133
137
|
options[:ecosystem] = v
|
|
134
138
|
end
|
|
135
139
|
|
|
140
|
+
opts.on("-m", "--manifest=PATH", "Filter by manifest path") do |v|
|
|
141
|
+
options[:manifest] = v
|
|
142
|
+
end
|
|
143
|
+
|
|
136
144
|
opts.on("-t", "--type=TYPE", "Filter by dependency type") do |v|
|
|
137
145
|
options[:type] = v
|
|
138
146
|
end
|
|
@@ -91,11 +91,20 @@ module Git
|
|
|
91
91
|
end
|
|
92
92
|
|
|
93
93
|
if outdated_data.empty?
|
|
94
|
-
|
|
94
|
+
if @options[:format] == "json"
|
|
95
|
+
require "json"
|
|
96
|
+
puts JSON.pretty_generate([])
|
|
97
|
+
else
|
|
98
|
+
empty_result "All dependencies have been updated recently"
|
|
99
|
+
end
|
|
95
100
|
return
|
|
96
101
|
end
|
|
97
102
|
|
|
98
|
-
|
|
103
|
+
if @options[:format] == "json"
|
|
104
|
+
output_json(outdated_data)
|
|
105
|
+
else
|
|
106
|
+
paginate { output_text(outdated_data) }
|
|
107
|
+
end
|
|
99
108
|
end
|
|
100
109
|
|
|
101
110
|
def output_text(outdated_data)
|
|
@@ -112,6 +121,23 @@ module Git
|
|
|
112
121
|
end
|
|
113
122
|
end
|
|
114
123
|
|
|
124
|
+
def output_json(outdated_data)
|
|
125
|
+
require "json"
|
|
126
|
+
|
|
127
|
+
data = outdated_data.map do |dep|
|
|
128
|
+
{
|
|
129
|
+
name: dep[:name],
|
|
130
|
+
ecosystem: dep[:ecosystem],
|
|
131
|
+
requirement: dep[:requirement],
|
|
132
|
+
manifest: dep[:manifest],
|
|
133
|
+
last_updated: dep[:last_updated].iso8601,
|
|
134
|
+
days_ago: dep[:days_ago]
|
|
135
|
+
}
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
puts JSON.pretty_generate(data)
|
|
139
|
+
end
|
|
140
|
+
|
|
115
141
|
def parse_options
|
|
116
142
|
options = {}
|
|
117
143
|
|
|
@@ -130,6 +156,10 @@ module Git
|
|
|
130
156
|
options[:days] = v
|
|
131
157
|
end
|
|
132
158
|
|
|
159
|
+
opts.on("-f", "--format=FORMAT", "Output format (text, json)") do |v|
|
|
160
|
+
options[:format] = v
|
|
161
|
+
end
|
|
162
|
+
|
|
133
163
|
opts.on("--no-pager", "Do not pipe output into a pager") do
|
|
134
164
|
options[:no_pager] = true
|
|
135
165
|
end
|
|
@@ -33,14 +33,23 @@ module Git
|
|
|
33
33
|
snapshots_list = snapshots.all
|
|
34
34
|
|
|
35
35
|
if snapshots_list.empty?
|
|
36
|
-
|
|
36
|
+
if @options[:format] == "json"
|
|
37
|
+
require "json"
|
|
38
|
+
puts JSON.pretty_generate({ manifests: [], total: 0 })
|
|
39
|
+
else
|
|
40
|
+
empty_result "No dependencies found"
|
|
41
|
+
end
|
|
37
42
|
return
|
|
38
43
|
end
|
|
39
44
|
|
|
40
45
|
# Group by manifest and build tree
|
|
41
46
|
grouped = snapshots_list.group_by { |s| s.manifest }
|
|
42
47
|
|
|
43
|
-
|
|
48
|
+
if @options[:format] == "json"
|
|
49
|
+
output_json(grouped, snapshots_list)
|
|
50
|
+
else
|
|
51
|
+
paginate { output_text(grouped, snapshots_list) }
|
|
52
|
+
end
|
|
44
53
|
end
|
|
45
54
|
|
|
46
55
|
def output_text(grouped, snapshots)
|
|
@@ -64,6 +73,35 @@ module Git
|
|
|
64
73
|
puts "Total: #{snapshots.count} dependencies across #{grouped.keys.count} manifest(s)"
|
|
65
74
|
end
|
|
66
75
|
|
|
76
|
+
def output_json(grouped, snapshots)
|
|
77
|
+
require "json"
|
|
78
|
+
|
|
79
|
+
manifests = grouped.map do |manifest, deps|
|
|
80
|
+
by_type = deps.group_by { |d| d.dependency_type || "runtime" }
|
|
81
|
+
|
|
82
|
+
{
|
|
83
|
+
path: manifest.path,
|
|
84
|
+
ecosystem: manifest.ecosystem,
|
|
85
|
+
dependencies: by_type.transform_values do |type_deps|
|
|
86
|
+
type_deps.sort_by(&:name).map do |dep|
|
|
87
|
+
{
|
|
88
|
+
name: dep.name,
|
|
89
|
+
requirement: dep.requirement || "*"
|
|
90
|
+
}
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
}
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
data = {
|
|
97
|
+
manifests: manifests,
|
|
98
|
+
total: snapshots.count,
|
|
99
|
+
manifest_count: grouped.keys.count
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
puts JSON.pretty_generate(data)
|
|
103
|
+
end
|
|
104
|
+
|
|
67
105
|
def print_dependency(dep, indent)
|
|
68
106
|
prefix = " " * indent
|
|
69
107
|
version = dep.requirement || "*"
|
|
@@ -111,6 +149,10 @@ module Git
|
|
|
111
149
|
options[:branch] = v
|
|
112
150
|
end
|
|
113
151
|
|
|
152
|
+
opts.on("-f", "--format=FORMAT", "Output format (text, json)") do |v|
|
|
153
|
+
options[:format] = v
|
|
154
|
+
end
|
|
155
|
+
|
|
114
156
|
opts.on("--no-pager", "Do not pipe output into a pager") do
|
|
115
157
|
options[:no_pager] = true
|
|
116
158
|
end
|
|
@@ -35,12 +35,25 @@ module Git
|
|
|
35
35
|
added_change = added_change.first
|
|
36
36
|
|
|
37
37
|
unless added_change
|
|
38
|
-
|
|
38
|
+
if @options[:format] == "json"
|
|
39
|
+
require "json"
|
|
40
|
+
puts JSON.pretty_generate({ found: false, package: package_name })
|
|
41
|
+
else
|
|
42
|
+
empty_result "Package '#{package_name}' not found in dependency history"
|
|
43
|
+
end
|
|
39
44
|
return
|
|
40
45
|
end
|
|
41
46
|
|
|
42
47
|
commit = added_change.commit
|
|
43
48
|
|
|
49
|
+
if @options[:format] == "json"
|
|
50
|
+
output_json(package_name, added_change, commit)
|
|
51
|
+
else
|
|
52
|
+
output_text(package_name, added_change, commit)
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def output_text(package_name, added_change, commit)
|
|
44
57
|
puts "#{package_name} was added in commit #{commit.short_sha}"
|
|
45
58
|
puts
|
|
46
59
|
puts "Date: #{commit.committed_at.strftime("%Y-%m-%d %H:%M")}"
|
|
@@ -52,6 +65,28 @@ module Git
|
|
|
52
65
|
puts commit.message.to_s.lines.map { |l| " #{l}" }.join
|
|
53
66
|
end
|
|
54
67
|
|
|
68
|
+
def output_json(package_name, added_change, commit)
|
|
69
|
+
require "json"
|
|
70
|
+
|
|
71
|
+
data = {
|
|
72
|
+
found: true,
|
|
73
|
+
package: package_name,
|
|
74
|
+
ecosystem: added_change.ecosystem,
|
|
75
|
+
requirement: added_change.requirement,
|
|
76
|
+
manifest: added_change.manifest.path,
|
|
77
|
+
commit: {
|
|
78
|
+
sha: commit.sha,
|
|
79
|
+
short_sha: commit.short_sha,
|
|
80
|
+
message: commit.message,
|
|
81
|
+
author_name: commit.author_name,
|
|
82
|
+
author_email: commit.author_email,
|
|
83
|
+
date: commit.committed_at.iso8601
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
puts JSON.pretty_generate(data)
|
|
88
|
+
end
|
|
89
|
+
|
|
55
90
|
def parse_options
|
|
56
91
|
options = {}
|
|
57
92
|
|
|
@@ -62,6 +97,10 @@ module Git
|
|
|
62
97
|
options[:ecosystem] = v
|
|
63
98
|
end
|
|
64
99
|
|
|
100
|
+
opts.on("-f", "--format=FORMAT", "Output format (text, json)") do |v|
|
|
101
|
+
options[:format] = v
|
|
102
|
+
end
|
|
103
|
+
|
|
65
104
|
opts.on("-h", "--help", "Show this help") do
|
|
66
105
|
puts opts
|
|
67
106
|
exit
|
data/lib/git/pkgs/config.rb
CHANGED
|
@@ -5,7 +5,7 @@ require "bibliothecary"
|
|
|
5
5
|
module Git
|
|
6
6
|
module Pkgs
|
|
7
7
|
module Config
|
|
8
|
-
# File patterns ignored by default (SBOM formats not supported)
|
|
8
|
+
# File patterns ignored by default (SBOM formats not supported, go.sum is checksums only)
|
|
9
9
|
DEFAULT_IGNORED_FILES = %w[
|
|
10
10
|
cyclonedx.xml
|
|
11
11
|
cyclonedx.json
|
|
@@ -13,6 +13,7 @@ module Git
|
|
|
13
13
|
*.cdx.json
|
|
14
14
|
*.spdx
|
|
15
15
|
*.spdx.json
|
|
16
|
+
go.sum
|
|
16
17
|
].freeze
|
|
17
18
|
|
|
18
19
|
def self.ignored_dirs
|
data/lib/git/pkgs/version.rb
CHANGED
data/lib/git/pkgs.rb
CHANGED
|
@@ -47,6 +47,77 @@ module Git
|
|
|
47
47
|
class << self
|
|
48
48
|
attr_accessor :quiet, :git_dir, :work_tree, :db_path, :batch_size, :snapshot_interval, :threads
|
|
49
49
|
|
|
50
|
+
# Parse dependencies from a single manifest or lockfile.
|
|
51
|
+
# Returns nil if the file is not recognized as a manifest.
|
|
52
|
+
#
|
|
53
|
+
# @param path [String] file path (used for format detection)
|
|
54
|
+
# @param content [String] file contents
|
|
55
|
+
# @return [Hash, nil] parsed manifest with :platform, :path, :kind, :dependencies keys
|
|
56
|
+
def parse_file(path, content)
|
|
57
|
+
Config.configure_bibliothecary
|
|
58
|
+
result = Bibliothecary.analyse_file(path, content).first
|
|
59
|
+
return nil unless result
|
|
60
|
+
return nil if Config.filter_ecosystem?(result[:platform])
|
|
61
|
+
|
|
62
|
+
result
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
# Parse dependencies from multiple files.
|
|
66
|
+
# Returns only files that are recognized as manifests.
|
|
67
|
+
#
|
|
68
|
+
# @param files [Hash<String, String>] hash of path => content
|
|
69
|
+
# @return [Array<Hash>] array of parsed manifests
|
|
70
|
+
def parse_files(files)
|
|
71
|
+
Config.configure_bibliothecary
|
|
72
|
+
files.filter_map do |path, content|
|
|
73
|
+
result = Bibliothecary.analyse_file(path, content).first
|
|
74
|
+
next unless result
|
|
75
|
+
next if Config.filter_ecosystem?(result[:platform])
|
|
76
|
+
|
|
77
|
+
result
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
# Diff dependencies between two versions of a manifest file.
|
|
82
|
+
# Returns added, modified, and removed dependencies.
|
|
83
|
+
#
|
|
84
|
+
# @param path [String] file path (used for format detection)
|
|
85
|
+
# @param old_content [String] previous file contents (empty string for new files)
|
|
86
|
+
# @param new_content [String] current file contents (empty string for deleted files)
|
|
87
|
+
# @return [Hash] with :added, :modified, :removed arrays and :platform, :path keys
|
|
88
|
+
def diff_file(path, old_content, new_content)
|
|
89
|
+
Config.configure_bibliothecary
|
|
90
|
+
|
|
91
|
+
old_result = old_content.empty? ? nil : Bibliothecary.analyse_file(path, old_content).first
|
|
92
|
+
new_result = new_content.empty? ? nil : Bibliothecary.analyse_file(path, new_content).first
|
|
93
|
+
|
|
94
|
+
platform = new_result&.dig(:platform) || old_result&.dig(:platform)
|
|
95
|
+
return nil unless platform
|
|
96
|
+
return nil if Config.filter_ecosystem?(platform)
|
|
97
|
+
|
|
98
|
+
old_deps = (old_result&.dig(:dependencies) || []).map { |d| [d[:name], d] }.to_h
|
|
99
|
+
new_deps = (new_result&.dig(:dependencies) || []).map { |d| [d[:name], d] }.to_h
|
|
100
|
+
|
|
101
|
+
added = (new_deps.keys - old_deps.keys).map { |n| new_deps[n] }
|
|
102
|
+
removed = (old_deps.keys - new_deps.keys).map { |n| old_deps[n] }
|
|
103
|
+
modified = (old_deps.keys & new_deps.keys).filter_map do |name|
|
|
104
|
+
old_dep = old_deps[name]
|
|
105
|
+
new_dep = new_deps[name]
|
|
106
|
+
next if old_dep[:requirement] == new_dep[:requirement] && old_dep[:type] == new_dep[:type]
|
|
107
|
+
|
|
108
|
+
new_dep.to_h.merge(previous_requirement: old_dep[:requirement])
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
{
|
|
112
|
+
path: path,
|
|
113
|
+
platform: platform,
|
|
114
|
+
kind: new_result&.dig(:kind) || old_result&.dig(:kind),
|
|
115
|
+
added: added,
|
|
116
|
+
modified: modified,
|
|
117
|
+
removed: removed
|
|
118
|
+
}
|
|
119
|
+
end
|
|
120
|
+
|
|
50
121
|
def configure_from_env
|
|
51
122
|
@git_dir ||= presence(ENV["GIT_DIR"])
|
|
52
123
|
@work_tree ||= presence(ENV["GIT_WORK_TREE"])
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: git-pkgs
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.6.
|
|
4
|
+
version: 0.6.2
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Andrew Nesbitt
|
|
@@ -57,14 +57,14 @@ dependencies:
|
|
|
57
57
|
requirements:
|
|
58
58
|
- - "~>"
|
|
59
59
|
- !ruby/object:Gem::Version
|
|
60
|
-
version: '15.
|
|
60
|
+
version: '15.1'
|
|
61
61
|
type: :runtime
|
|
62
62
|
prerelease: false
|
|
63
63
|
version_requirements: !ruby/object:Gem::Requirement
|
|
64
64
|
requirements:
|
|
65
65
|
- - "~>"
|
|
66
66
|
- !ruby/object:Gem::Version
|
|
67
|
-
version: '15.
|
|
67
|
+
version: '15.1'
|
|
68
68
|
description: A git subcommand for analyzing package/dependency usage in git repositories
|
|
69
69
|
over time
|
|
70
70
|
email:
|