gemkeeper 0.5.0 → 0.6.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 +18 -1
- data/README.md +34 -0
- data/exe/gemkeeper +3 -0
- data/lib/gemkeeper/cli/commands/manifest/generate.rb +6 -3
- data/lib/gemkeeper/cli/commands/server/stop.rb +2 -3
- data/lib/gemkeeper/cli/commands/setup.rb +12 -7
- data/lib/gemkeeper/cli/lockfile_resolution.rb +34 -0
- data/lib/gemkeeper/cli.rb +1 -0
- data/lib/gemkeeper/configuration.rb +8 -1
- data/lib/gemkeeper/version.rb +1 -1
- metadata +2 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 001a1d05846be989be3ef4c6f4c614f0fc36d8da80f0adaa2cf26998c8664e07
|
|
4
|
+
data.tar.gz: 3816ebfed535178ac1a26c21d9605feb00860182b6558641436ac060cd3a51dd
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: e19335cfccc7d720acc122fed595b9d9115f0fe3bff5d1e29369413df03a4d799a91ce585a211f3b916af6f12aa38fef3b21f59318827a7008106cb0b523876b
|
|
7
|
+
data.tar.gz: 89832f20c7349469c53b7918fd58c85a43d8988374c321016d520b0e3b93ae567c16ca5d63e0e0bbf3b0a94dd2d5b023cadc359ec38a63e4ed6b89d39420a87e
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,21 @@
|
|
|
1
1
|
## [Unreleased]
|
|
2
2
|
|
|
3
|
+
## [0.6.0] - 2026-05-28
|
|
4
|
+
|
|
5
|
+
### Added
|
|
6
|
+
|
|
7
|
+
- `gemkeeper setup` now accepts a directory path and finds `Gemfile.lock` inside it.
|
|
8
|
+
- `gemkeeper setup` now accepts a `Gemfile` path and uses the sibling `Gemfile.lock`.
|
|
9
|
+
- `gemkeeper setup` now works with no arguments by finding the nearest `Gemfile.lock` (walks up from the current directory).
|
|
10
|
+
- `gemkeeper manifest generate` now accepts a directory, `Gemfile` path, or no arguments (same resolution as `setup`).
|
|
11
|
+
|
|
12
|
+
### Fixed
|
|
13
|
+
|
|
14
|
+
- `gemkeeper setup` no longer configures a Bundler mirror for a private gem registry when all gems from that source were skipped during manifest resolution.
|
|
15
|
+
- `gemkeeper setup` and `gemkeeper manifest generate` now report a clear error when the resolved source path does not exist.
|
|
16
|
+
- All commands that accept `--config` now report a clear error when the specified config file does not exist, instead of silently using defaults.
|
|
17
|
+
- `gemkeeper server stop` now exits 0 when the server is already stopped; stopping an already-stopped server is not an error.
|
|
18
|
+
|
|
3
19
|
## [0.5.0] - 2026-05-27
|
|
4
20
|
|
|
5
21
|
### Added
|
|
@@ -67,7 +83,8 @@
|
|
|
67
83
|
|
|
68
84
|
- Initial release
|
|
69
85
|
|
|
70
|
-
[Unreleased]: https://github.com/danhorst/gemkeeper/compare/v0.
|
|
86
|
+
[Unreleased]: https://github.com/danhorst/gemkeeper/compare/v0.6.0...HEAD
|
|
87
|
+
[0.6.0]: https://github.com/danhorst/gemkeeper/compare/0.5.0...0.6.0
|
|
71
88
|
[0.5.0]: https://github.com/danhorst/gemkeeper/compare/0.4.0...0.5.0
|
|
72
89
|
[0.4.0]: https://github.com/danhorst/gemkeeper/compare/0.3.0...0.4.0
|
|
73
90
|
[0.3.0]: https://github.com/danhorst/gemkeeper/compare/0.2.1...0.3.0
|
data/README.md
CHANGED
|
@@ -169,12 +169,21 @@ gemkeeper server status
|
|
|
169
169
|
# Generate gemkeeper.yml from a Gemfile.lock and org manifest
|
|
170
170
|
gemkeeper setup path/to/Gemfile.lock
|
|
171
171
|
|
|
172
|
+
# Use an existing gemkeeper.yml as input (updates manifest, optionally installs as global config)
|
|
173
|
+
gemkeeper setup path/to/gemkeeper.yml
|
|
174
|
+
|
|
172
175
|
# Use a custom manifest path
|
|
173
176
|
gemkeeper setup path/to/Gemfile.lock --manifest ~/.config/myorg/manifest.yml
|
|
174
177
|
|
|
178
|
+
# Write gemkeeper.yml to a specific path
|
|
179
|
+
gemkeeper setup path/to/Gemfile.lock --config path/to/output.yml
|
|
180
|
+
|
|
175
181
|
# Overwrite existing gemkeeper.yml entirely
|
|
176
182
|
gemkeeper setup path/to/Gemfile.lock --force
|
|
177
183
|
|
|
184
|
+
# Skip auto-configuring Bundler mirrors
|
|
185
|
+
gemkeeper setup path/to/Gemfile.lock --skip-bundler-config
|
|
186
|
+
|
|
178
187
|
# Write to the global Homebrew service config instead of the current directory
|
|
179
188
|
gemkeeper setup path/to/Gemfile.lock --global
|
|
180
189
|
```
|
|
@@ -183,6 +192,31 @@ gemkeeper setup path/to/Gemfile.lock --global
|
|
|
183
192
|
It sets `repos_path` and `gems_path` as absolute paths under the corresponding `var` directory so the daemon finds them regardless of which directory you run commands from.
|
|
184
193
|
`--global` and `--config` are mutually exclusive.
|
|
185
194
|
|
|
195
|
+
### Manifest Management
|
|
196
|
+
|
|
197
|
+
The manifest (`~/.config/gemkeeper/manifest.yml`) is the global name→repo lookup table shared across projects.
|
|
198
|
+
`manifest generate` builds or updates it; `setup` reads it.
|
|
199
|
+
|
|
200
|
+
```bash
|
|
201
|
+
# Build or update the manifest from a Gemfile.lock
|
|
202
|
+
gemkeeper manifest generate path/to/Gemfile.lock
|
|
203
|
+
|
|
204
|
+
# Use a custom manifest path
|
|
205
|
+
gemkeeper manifest generate path/to/Gemfile.lock --manifest ~/.config/myorg/manifest.yml
|
|
206
|
+
|
|
207
|
+
# Overwrite the manifest entirely (discard existing entries)
|
|
208
|
+
gemkeeper manifest generate path/to/Gemfile.lock --force
|
|
209
|
+
|
|
210
|
+
# Validate the default manifest
|
|
211
|
+
gemkeeper manifest validate
|
|
212
|
+
|
|
213
|
+
# Validate a specific manifest file
|
|
214
|
+
gemkeeper manifest validate path/to/manifest.yml
|
|
215
|
+
|
|
216
|
+
# Validate and probe each repo via git ls-remote
|
|
217
|
+
gemkeeper manifest validate --resolve
|
|
218
|
+
```
|
|
219
|
+
|
|
186
220
|
### Gem Synchronization
|
|
187
221
|
|
|
188
222
|
```bash
|
data/exe/gemkeeper
CHANGED
|
@@ -5,16 +5,19 @@ module Gemkeeper
|
|
|
5
5
|
module Commands
|
|
6
6
|
module Manifest
|
|
7
7
|
class Generate < Dry::CLI::Command
|
|
8
|
+
include CLI::LockfileResolution
|
|
9
|
+
|
|
8
10
|
desc "Build or update the gem manifest from a Gemfile.lock"
|
|
9
11
|
|
|
10
|
-
argument :lockfile_path, type: :string, required:
|
|
11
|
-
desc: "
|
|
12
|
+
argument :lockfile_path, type: :string, required: false,
|
|
13
|
+
desc: "Gemfile.lock, Gemfile, or directory (default: nearest Gemfile.lock)"
|
|
12
14
|
option :manifest, type: :string,
|
|
13
15
|
desc: "Path to write manifest (default: ~/.config/gemkeeper/manifest.yml)"
|
|
14
16
|
option :force, type: :boolean, default: false,
|
|
15
17
|
desc: "Overwrite existing manifest entirely"
|
|
16
18
|
|
|
17
|
-
def call(lockfile_path
|
|
19
|
+
def call(lockfile_path: nil, **options)
|
|
20
|
+
lockfile_path = resolve_source_path(lockfile_path)
|
|
18
21
|
path = manifest_path(options)
|
|
19
22
|
manifest = ManifestReader.load(path)
|
|
20
23
|
manifest.clear! if options[:force]
|
|
@@ -15,9 +15,8 @@ module Gemkeeper
|
|
|
15
15
|
manager.stop
|
|
16
16
|
|
|
17
17
|
puts "Geminabox server stopped"
|
|
18
|
-
rescue ServerNotRunningError
|
|
19
|
-
|
|
20
|
-
exit 1
|
|
18
|
+
rescue ServerNotRunningError
|
|
19
|
+
puts "Geminabox server is not running"
|
|
21
20
|
rescue ServerError => error
|
|
22
21
|
warn "Error stopping server: #{error.message}"
|
|
23
22
|
exit 1
|
|
@@ -4,10 +4,13 @@ module Gemkeeper
|
|
|
4
4
|
module CLI
|
|
5
5
|
module Commands
|
|
6
6
|
class Setup < Dry::CLI::Command
|
|
7
|
+
include CLI::LockfileResolution
|
|
8
|
+
|
|
7
9
|
desc "Generate gemkeeper.yml from a Gemfile.lock or existing gemkeeper.yml"
|
|
8
10
|
|
|
9
|
-
argument :source_path, type: :string, required:
|
|
10
|
-
desc: "
|
|
11
|
+
argument :source_path, type: :string, required: false,
|
|
12
|
+
desc: "Gemfile.lock, Gemfile, directory, or gemkeeper.yml " \
|
|
13
|
+
"(default: nearest Gemfile.lock)"
|
|
11
14
|
option :manifest, type: :string,
|
|
12
15
|
desc: "Path to gem manifest (default: ~/.config/gemkeeper/manifest.yml)"
|
|
13
16
|
option :config, type: :string, desc: "Path to write gemkeeper.yml (default: ./gemkeeper.yml)"
|
|
@@ -18,14 +21,15 @@ module Gemkeeper
|
|
|
18
21
|
option :skip_bundler_config, type: :boolean, default: false,
|
|
19
22
|
desc: "Skip configuring Bundler mirrors for private gem sources"
|
|
20
23
|
|
|
21
|
-
def call(source_path
|
|
24
|
+
def call(source_path: nil, **options)
|
|
22
25
|
validate_options!(options)
|
|
23
26
|
output_path = resolve_output_path(options)
|
|
27
|
+
resolved = resolve_source_path(source_path)
|
|
24
28
|
|
|
25
|
-
if lockfile?(
|
|
26
|
-
setup_from_lockfile(
|
|
29
|
+
if lockfile?(resolved)
|
|
30
|
+
setup_from_lockfile(resolved, output_path, options)
|
|
27
31
|
else
|
|
28
|
-
setup_from_config(
|
|
32
|
+
setup_from_config(resolved, output_path, options)
|
|
29
33
|
end
|
|
30
34
|
rescue UnresolvableGemError, ManifestConflictError => error
|
|
31
35
|
warn "Error: #{error.message}"
|
|
@@ -53,7 +57,8 @@ module Gemkeeper
|
|
|
53
57
|
return if options[:skip_bundler_config]
|
|
54
58
|
|
|
55
59
|
port = config.fetch("port", Configuration::DEFAULT_PORT)
|
|
56
|
-
|
|
60
|
+
resolved = result.candidates.select { |c| result.manifest.repo_for(c[:name]) }
|
|
61
|
+
BundlerMirrorConfigurator.new(resolved, port:, global: options[:global]).configure
|
|
57
62
|
end
|
|
58
63
|
|
|
59
64
|
def setup_from_config(source_path, output_path, options)
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Gemkeeper
|
|
4
|
+
module CLI
|
|
5
|
+
# Shared path coercion for commands that accept a Gemfile.lock argument.
|
|
6
|
+
# Accepts nil (find nearest), a directory, a Gemfile path, or an explicit path.
|
|
7
|
+
module LockfileResolution
|
|
8
|
+
private
|
|
9
|
+
|
|
10
|
+
def resolve_source_path(path)
|
|
11
|
+
resolved = coerce_source_path(path)
|
|
12
|
+
File.exist?(resolved) ? resolved : missing_source!(resolved)
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def coerce_source_path(path)
|
|
16
|
+
return LockfileParser.find || no_lockfile! if path.nil?
|
|
17
|
+
return File.join(path, "Gemfile.lock") if File.directory?(path)
|
|
18
|
+
return File.join(File.dirname(path), "Gemfile.lock") if File.basename(path) == "Gemfile"
|
|
19
|
+
|
|
20
|
+
path
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def no_lockfile!
|
|
24
|
+
warn "Error: no Gemfile.lock found in #{Dir.pwd} or any parent directory"
|
|
25
|
+
exit 1
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def missing_source!(path)
|
|
29
|
+
warn "Error: file not found — #{path}"
|
|
30
|
+
exit 1
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
data/lib/gemkeeper/cli.rb
CHANGED
|
@@ -56,6 +56,7 @@ module Gemkeeper
|
|
|
56
56
|
end
|
|
57
57
|
|
|
58
58
|
def initialize(config_path = nil)
|
|
59
|
+
@explicit_config = !config_path.nil?
|
|
59
60
|
@config_path = config_path || find_config_file
|
|
60
61
|
@config = load_config
|
|
61
62
|
apply_config
|
|
@@ -91,7 +92,13 @@ module Gemkeeper
|
|
|
91
92
|
end
|
|
92
93
|
|
|
93
94
|
def load_config
|
|
94
|
-
return {} unless @config_path
|
|
95
|
+
return {} unless @config_path
|
|
96
|
+
|
|
97
|
+
unless File.exist?(@config_path)
|
|
98
|
+
raise ConfigFileNotFoundError, "config file not found — #{@config_path}" if @explicit_config
|
|
99
|
+
|
|
100
|
+
return {}
|
|
101
|
+
end
|
|
95
102
|
|
|
96
103
|
begin
|
|
97
104
|
YAML.safe_load_file(@config_path, permitted_classes: [], symbolize_names: true) || {}
|
data/lib/gemkeeper/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: gemkeeper
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.6.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Dan Brubaker Horst
|
|
@@ -106,6 +106,7 @@ files:
|
|
|
106
106
|
- lib/gemkeeper/cli/commands/setup.rb
|
|
107
107
|
- lib/gemkeeper/cli/commands/sync.rb
|
|
108
108
|
- lib/gemkeeper/cli/commands/version.rb
|
|
109
|
+
- lib/gemkeeper/cli/lockfile_resolution.rb
|
|
109
110
|
- lib/gemkeeper/config_generator.rb
|
|
110
111
|
- lib/gemkeeper/configuration.rb
|
|
111
112
|
- lib/gemkeeper/errors.rb
|