gurney_client 0.3.0 → 0.4.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/CHANGELOG.md +5 -0
- data/Gemfile.lock +10 -8
- data/README.md +30 -21
- data/lib/gurney/api.rb +6 -5
- data/lib/gurney/cli.rb +90 -82
- data/lib/gurney/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 6e7470d3ea652657be230f28b42b3035ee0e2c47122dc297533428831fc20b2b
|
|
4
|
+
data.tar.gz: 7e3bf5796d850cc8e600959a348f521d9d7ee10f5f7e329da391c0b125f57db0
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: c04cfc2febd10dcb6be12b4b8466f5c11d308954c57a7588a0bb41100f64eabc4656867af4d97d1c2d40ee607d5a3206e8fc3c0477021d04efd471c599abd540
|
|
7
|
+
data.tar.gz: cb327dd15bfd5aea5c30a87ff271555c17c9e29c8ec35379fa9bdb4ce3fd21b935e6ba80d1a0057abdd7f75b76d263da1089b209bce7576c857ca570f0f563e8
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
# Gurney changelog
|
|
2
2
|
|
|
3
|
+
## 0.4.0 (2024-11-15)
|
|
4
|
+
* Added: Reporting of the repository path as identifier. Should it ever change,
|
|
5
|
+
it is an indicator for an unchanged gurney.yml in a project fork, and the
|
|
6
|
+
API may respond with an error.
|
|
7
|
+
|
|
3
8
|
## 0.3.0 (2024-11-14)
|
|
4
9
|
* Added: Compatibility with Ruby 3
|
|
5
10
|
* Fixed: Support UTF-8 chars in branch names
|
data/Gemfile.lock
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
PATH
|
|
2
2
|
remote: .
|
|
3
3
|
specs:
|
|
4
|
-
gurney_client (0.
|
|
4
|
+
gurney_client (0.4.0)
|
|
5
5
|
bundler (< 3)
|
|
6
6
|
colorize (~> 0.8)
|
|
7
7
|
git (~> 1.5)
|
|
@@ -10,22 +10,24 @@ PATH
|
|
|
10
10
|
GEM
|
|
11
11
|
remote: https://rubygems.org/
|
|
12
12
|
specs:
|
|
13
|
-
addressable (2.8.
|
|
14
|
-
public_suffix (>= 2.0.2, <
|
|
13
|
+
addressable (2.8.7)
|
|
14
|
+
public_suffix (>= 2.0.2, < 7.0)
|
|
15
15
|
byebug (11.0.1)
|
|
16
16
|
colorize (0.8.1)
|
|
17
17
|
diff-lcs (1.3)
|
|
18
|
-
git (1.
|
|
18
|
+
git (1.19.1)
|
|
19
19
|
addressable (~> 2.8)
|
|
20
20
|
rchardet (~> 1.8)
|
|
21
21
|
httparty (0.17.3)
|
|
22
22
|
mime-types (~> 3.0)
|
|
23
23
|
multi_xml (>= 0.5.2)
|
|
24
|
-
|
|
24
|
+
logger (1.6.1)
|
|
25
|
+
mime-types (3.6.0)
|
|
26
|
+
logger
|
|
25
27
|
mime-types-data (~> 3.2015)
|
|
26
|
-
mime-types-data (3.
|
|
28
|
+
mime-types-data (3.2024.1105)
|
|
27
29
|
multi_xml (0.6.0)
|
|
28
|
-
public_suffix (5.
|
|
30
|
+
public_suffix (5.1.1)
|
|
29
31
|
rake (13.0.1)
|
|
30
32
|
rchardet (1.8.0)
|
|
31
33
|
rspec (3.9.0)
|
|
@@ -52,4 +54,4 @@ DEPENDENCIES
|
|
|
52
54
|
rspec
|
|
53
55
|
|
|
54
56
|
BUNDLED WITH
|
|
55
|
-
2.
|
|
57
|
+
2.3.19
|
data/README.md
CHANGED
|
@@ -1,30 +1,31 @@
|
|
|
1
|
-
|
|
1
|
+
# Gurney
|
|
2
2
|
|
|
3
|
-
Gurney is a small tool to extract dependencies from project files and report
|
|
4
|
-
|
|
3
|
+
Gurney is a small tool to extract dependencies from project files and report
|
|
4
|
+
them to a web API. Modes:
|
|
5
|
+
- normal
|
|
6
|
+
- local pre-push hook
|
|
7
|
+
- remote post-receive hook
|
|
8
|
+
Usually, we configure the latter on our Git server to automatically run on each
|
|
9
|
+
push, with the API url passed as command line option.
|
|
5
10
|
|
|
6
|
-
When run as a
|
|
7
|
-
|
|
8
|
-
|
|
11
|
+
When run as a post-receive hook, Gurney will make a bare copy of the project and
|
|
12
|
+
look for a gurney.yml file. If present, Gurney looks at the configured branches
|
|
13
|
+
and collects their dependencies. These are reported to the web API.
|
|
9
14
|
|
|
10
|
-
|
|
15
|
+
## Usage
|
|
11
16
|
```
|
|
12
17
|
Usage: gurney [options]
|
|
13
|
-
--api-url [API URL]
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
--api-token [API TOKEN]
|
|
17
|
-
Token to be send to the api in the X-AuthToken header
|
|
18
|
+
--api-url [API URL] Url for web API call, can have parameters for <project_id> and <branch>
|
|
19
|
+
Example: --api-url "https://example.com/project/<project_id>/branch/<branch>"
|
|
20
|
+
--api-token [API TOKEN] Token to be sent to the API in the X-AuthToken header
|
|
18
21
|
-c, --config [CONFIG FILE] Config file to use
|
|
19
|
-
-h, --hook Run as a
|
|
20
|
-
--client-hook
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
--help
|
|
24
|
-
Prints this help
|
|
22
|
+
-h, --hook Run as a Git post-receive hook
|
|
23
|
+
--client-hook Run as a Git pre-push hook
|
|
24
|
+
-p, --project-id [PROJECT ID] Specify project id for API
|
|
25
|
+
--help Print this help
|
|
25
26
|
```
|
|
26
27
|
|
|
27
|
-
|
|
28
|
+
## Sample Config
|
|
28
29
|
```yaml
|
|
29
30
|
project_id: 1
|
|
30
31
|
branches:
|
|
@@ -34,5 +35,13 @@ api_url: http://example.com/dep_reporter/project/<project_id>/branch/<branch>
|
|
|
34
35
|
api_token: 1234567890
|
|
35
36
|
```
|
|
36
37
|
|
|
37
|
-
|
|
38
|
-
|
|
38
|
+
## Running as a global Git hook
|
|
39
|
+
See https://docs.gitlab.com/ee/administration/server_hooks.html#create-global-server-hooks-for-all-repositories
|
|
40
|
+
|
|
41
|
+
## Development
|
|
42
|
+
You can run Gurney locally from another directory like this:
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
cd some/real/project
|
|
46
|
+
ruby -I path/to/gurney/lib path/to/gurney/exe/gurney
|
|
47
|
+
```
|
data/lib/gurney/api.rb
CHANGED
|
@@ -9,13 +9,14 @@ module Gurney
|
|
|
9
9
|
@token = token
|
|
10
10
|
end
|
|
11
11
|
|
|
12
|
-
def post_dependencies(dependencies:, branch:, project_id:)
|
|
13
|
-
data = {
|
|
14
|
-
|
|
15
|
-
|
|
12
|
+
def post_dependencies(dependencies:, branch:, project_id:, repo_path: nil)
|
|
13
|
+
data = { dependencies: dependencies }
|
|
14
|
+
data[:repository_path] = repo_path if repo_path
|
|
15
|
+
|
|
16
16
|
url = base_url
|
|
17
17
|
url.gsub! '<project_id>', CGI.escape(project_id)
|
|
18
18
|
url.gsub! '<branch>', CGI.escape(branch)
|
|
19
|
+
|
|
19
20
|
post_json(url, data.to_json)
|
|
20
21
|
end
|
|
21
22
|
|
|
@@ -31,7 +32,7 @@ module Gurney
|
|
|
31
32
|
)
|
|
32
33
|
unless response.success?
|
|
33
34
|
if response.code == 404
|
|
34
|
-
raise ApiError.new("#{response.code}
|
|
35
|
+
raise ApiError.new("#{response.code} API url is probably wrong")
|
|
35
36
|
else
|
|
36
37
|
raise ApiError.new("#{response.code} #{response.body}")
|
|
37
38
|
end
|
data/lib/gurney/cli.rb
CHANGED
|
@@ -6,103 +6,116 @@ require 'git'
|
|
|
6
6
|
require 'fileutils'
|
|
7
7
|
|
|
8
8
|
module Gurney
|
|
9
|
+
|
|
10
|
+
class Error < StandardError; end
|
|
11
|
+
|
|
9
12
|
class CLI
|
|
10
13
|
HOOK_STDIN_REGEX = /(?<old>[0-9a-f]{40}) (?<new>[0-9a-f]{40}) refs\/heads\/(?<ref>\w+)/m
|
|
11
14
|
CLIENT_HOOK_STDIN_REGEX = /refs\/heads\/(?<ref>\w+) (?<new>[0-9a-f]{40}) refs\/heads\/(?<remote_ref>\w+) (?<remote_sha>[0-9a-f]{40})/m
|
|
12
15
|
MAIN_BRANCHES = ['master', 'main'].freeze
|
|
13
16
|
|
|
14
17
|
def self.run(cmd_parameter=[])
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
file = read_file(g, options.hook, branch, options.config_file)
|
|
28
|
-
break file if file
|
|
29
|
-
end
|
|
30
|
-
if !config_file && options.hook
|
|
31
|
-
# dont run as a hook with no config
|
|
32
|
-
exit 0
|
|
33
|
-
end
|
|
34
|
-
config_file ||= '---'
|
|
35
|
-
config = Gurney::Config.from_yaml(config_file)
|
|
36
|
-
|
|
37
|
-
options.branches ||= config&.branches
|
|
38
|
-
options.branches ||= config&.branches
|
|
39
|
-
options.api_token ||= config&.api_token
|
|
40
|
-
options.api_url ||= config&.api_url
|
|
41
|
-
options.project_id ||= config&.project_id
|
|
42
|
-
|
|
43
|
-
if [options.project_id, options.branches, options.api_url, options.api_token].any?(&:nil?)
|
|
44
|
-
raise Gurney::Error.new("Either provide in a config file or set the flags for project id, branches, api url and api token")
|
|
45
|
-
end
|
|
46
|
-
|
|
47
|
-
branches = []
|
|
48
|
-
if options.hook || options.client_hook
|
|
49
|
-
# we get passed changed branches and refs via stdin
|
|
50
|
-
$stdin.each_line do |line|
|
|
51
|
-
regex = options.client_hook ? CLIENT_HOOK_STDIN_REGEX : HOOK_STDIN_REGEX
|
|
52
|
-
line.force_encoding(Encoding::UTF_8)
|
|
53
|
-
matches = line.match(regex)
|
|
54
|
-
if matches && matches[:new] != '0' * 40
|
|
55
|
-
if options.branches.include? matches[:ref]
|
|
56
|
-
branches << matches[:ref]
|
|
57
|
-
end
|
|
58
|
-
end
|
|
59
|
-
end
|
|
18
|
+
new(cmd_parameter).run
|
|
19
|
+
rescue SystemExit
|
|
20
|
+
# Do nothing
|
|
21
|
+
rescue Gurney::ApiError => e
|
|
22
|
+
puts "Gurney API error".red
|
|
23
|
+
puts e.message.red
|
|
24
|
+
rescue Gurney::Error => e
|
|
25
|
+
puts "Gurney error: #{e.message}".red
|
|
26
|
+
rescue Exception
|
|
27
|
+
puts "Gurney: an unexpected error occurred".red
|
|
28
|
+
raise
|
|
29
|
+
end
|
|
60
30
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
31
|
+
def initialize(cmd_parameter=[])
|
|
32
|
+
@options = Gurney::CLI::OptionParser.parse(cmd_parameter)
|
|
33
|
+
@git = if options.hook
|
|
34
|
+
Git.bare(ENV['GIT_DIR'] || Dir.pwd)
|
|
35
|
+
else
|
|
36
|
+
unless Dir.exist? './.git'
|
|
37
|
+
raise Gurney::Error.new('Must be run within a git repository')
|
|
67
38
|
end
|
|
39
|
+
Git.open('.')
|
|
40
|
+
end
|
|
68
41
|
|
|
69
|
-
|
|
70
|
-
|
|
42
|
+
config_file = MAIN_BRANCHES.find do |branch|
|
|
43
|
+
file = read_file(options.hook, branch, options.config_file)
|
|
44
|
+
break file if file
|
|
45
|
+
end
|
|
46
|
+
if options.hook && !config_file
|
|
47
|
+
# Git hooks are activated by the config file. Without, do nothing.
|
|
48
|
+
exit 0
|
|
49
|
+
end
|
|
50
|
+
config_file ||= '---'
|
|
51
|
+
config = Gurney::Config.from_yaml(config_file)
|
|
52
|
+
|
|
53
|
+
options.branches ||= config&.branches
|
|
54
|
+
options.branches ||= config&.branches
|
|
55
|
+
options.api_token ||= config&.api_token
|
|
56
|
+
options.api_url ||= config&.api_url
|
|
57
|
+
options.project_id ||= config&.project_id
|
|
58
|
+
|
|
59
|
+
missing_options = [:project_id, :branches, :api_url, :api_token].select { |option| options.send(option).nil? }
|
|
60
|
+
# Use the line below in development
|
|
61
|
+
# missing_options = [:project_id, :branches, :api_token].select { |option| options.send(option).nil? }
|
|
62
|
+
raise Gurney::Error.new("Incomplete config - missing #{missing_options.map(&:inspect).join(', ')}.") unless missing_options.empty?
|
|
63
|
+
end
|
|
71
64
|
|
|
72
|
-
|
|
73
|
-
|
|
65
|
+
def run
|
|
66
|
+
reporting_branches.each do |branch|
|
|
67
|
+
dependencies = []
|
|
74
68
|
|
|
75
|
-
|
|
76
|
-
|
|
69
|
+
yarn_source = Gurney::Source::Yarn.new(yarn_lock: read_file(options.hook || options.client_hook, branch, 'yarn.lock'))
|
|
70
|
+
dependencies.concat yarn_source.dependencies || []
|
|
77
71
|
|
|
78
|
-
|
|
79
|
-
|
|
72
|
+
bundler_source = Gurney::Source::Bundler.new(gemfile_lock: read_file(options.hook || options.client_hook, branch, 'Gemfile.lock'))
|
|
73
|
+
dependencies.concat bundler_source.dependencies || []
|
|
80
74
|
|
|
81
|
-
|
|
75
|
+
ruby_version_source = Gurney::Source::RubyVersion.new(ruby_version: read_file(options.hook || options.client_hook, branch, '.ruby-version'))
|
|
76
|
+
dependencies.concat ruby_version_source.dependencies || []
|
|
82
77
|
|
|
83
|
-
|
|
84
|
-
api.post_dependencies(dependencies: dependencies, branch: branch, project_id: options.project_id)
|
|
78
|
+
dependencies.compact!
|
|
85
79
|
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
end
|
|
80
|
+
api = Gurney::Api.new(base_url: options.api_url, token: options.api_token)
|
|
81
|
+
api.post_dependencies(dependencies: dependencies, branch: branch, project_id: options.project_id, repo_path: git.repo.path)
|
|
89
82
|
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
puts "Gurney: api error".red
|
|
93
|
-
puts e.message.red
|
|
94
|
-
rescue Gurney::Error => e
|
|
95
|
-
puts "Gurney: error".red
|
|
96
|
-
puts e.message.red
|
|
97
|
-
rescue Exception => e
|
|
98
|
-
puts "Gurney: an unexpected error occurred".red
|
|
99
|
-
raise
|
|
83
|
+
dependency_counts = dependencies.group_by(&:ecosystem).map{|ecosystem, dependencies| "#{ecosystem}: #{dependencies.count}" }.join(', ')
|
|
84
|
+
puts "Gurney: reported dependencies (#{dependency_counts})"
|
|
100
85
|
end
|
|
101
86
|
end
|
|
102
87
|
|
|
103
88
|
private
|
|
104
89
|
|
|
105
|
-
|
|
90
|
+
attr_accessor :git, :options
|
|
91
|
+
|
|
92
|
+
def reporting_branches
|
|
93
|
+
branches = []
|
|
94
|
+
if options.hook || options.client_hook
|
|
95
|
+
# We get changed branches and refs via stdin
|
|
96
|
+
# See https://git-scm.com/docs/githooks#post-receive
|
|
97
|
+
$stdin.each_line do |line|
|
|
98
|
+
regex = options.client_hook ? CLIENT_HOOK_STDIN_REGEX : HOOK_STDIN_REGEX
|
|
99
|
+
line.force_encoding(Encoding::UTF_8)
|
|
100
|
+
matches = line.match(regex)
|
|
101
|
+
if matches && matches[:new] != '0' * 40
|
|
102
|
+
if options.branches.include? matches[:ref]
|
|
103
|
+
branches << matches[:ref]
|
|
104
|
+
end
|
|
105
|
+
end
|
|
106
|
+
end
|
|
107
|
+
else
|
|
108
|
+
current_branch = git.current_branch
|
|
109
|
+
unless options.branches.nil? || options.branches.include?(current_branch)
|
|
110
|
+
raise Gurney::Error.new('The current branch is not specified in the config.')
|
|
111
|
+
end
|
|
112
|
+
branches << current_branch
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
branches
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
def read_file(from_git, branch, filename)
|
|
106
119
|
if from_git
|
|
107
120
|
begin
|
|
108
121
|
git.show("#{branch}:#{filename}")
|
|
@@ -110,14 +123,9 @@ module Gurney
|
|
|
110
123
|
# happens if branch does not exist
|
|
111
124
|
end
|
|
112
125
|
else
|
|
113
|
-
if File.exist?
|
|
114
|
-
return File.read filename
|
|
115
|
-
end
|
|
126
|
+
File.read(filename) if File.exist?(filename)
|
|
116
127
|
end
|
|
117
128
|
end
|
|
118
129
|
|
|
119
130
|
end
|
|
120
|
-
|
|
121
|
-
class Error < Exception
|
|
122
|
-
end
|
|
123
131
|
end
|
data/lib/gurney/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: gurney_client
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.4.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Martin Schaflitzl
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: exe
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2024-11-
|
|
11
|
+
date: 2024-11-15 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: colorize
|