local-development-gateway 0.2.2 → 0.2.3

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 31c635514c35283b8ebab124d6a9f9ac8e17e8de5faaeb8573b0c73153b3efd4
4
- data.tar.gz: 946d3a12335cff8a00f10a5ac330de37b5f5ec509a33779e44cefc265b8c0554
3
+ metadata.gz: c8606a508df46ba2018a8cd768c86e6a41ce38a5ef7caedff7c5832017d34e38
4
+ data.tar.gz: ebd5a8310bcb5b235d0c00c717813873b73e6061d6333f89ba188818636b3162
5
5
  SHA512:
6
- metadata.gz: 04b07e9aeb612b723744759bebb4f8e19319ac885a9dff3163446eaebcaf9a424cb203c36c89649a2378d1db675c5a167aade5bc0f33e6c82ccb70c11d7bcec6
7
- data.tar.gz: 28528704687762d7a053b62f7c1fc1e7f5af76700e4c332efadaef32cb5c594e420af8bbd53803a1e3d0cecdafa3d892ceeee5edbac100aa388ea72e98a80de1
6
+ metadata.gz: cb84da27199e8af6e78189f9025240ae090ae84372e3ccbd3f1d25240e18a4710a3eb16f32793b2e1411bc0bb9d9f0535f9a4ff5955815cc1b0eda322680fdd8
7
+ data.tar.gz: e0e3a2a24e3f039d516a150496b37527ff98d6549aafaeeb0aca5b36116f68ed24bb5f3948c35ab3555efeca1c40267d334f233d50a46aa7dbf55c50333b62e5
data/README.md CHANGED
@@ -106,6 +106,21 @@ command that must not start a missing gateway, pass
106
106
  `ensure_running: false`; the block still runs and unused-gateway cleanup is
107
107
  attempted.
108
108
 
109
+ ### Installed versus active versions
110
+
111
+ `bundle exec local-development-gateway status` reports the invoking gem's installed version separately from each running shared service's active version, provenance, and mounted asset path. Healthy CLI `up`/`ensure` reuse also prints these diagnostics without recreating containers. Ruby callers can inspect `LocalDevelopmentGateway.status`; `ensure_running` still returns `:reused` for healthy services, and `ready?` remains a health check, not an artifact-version check.
112
+
113
+ For the database router, the active version comes from a record written by the Ruby process after loading the library at startup. For the HTTP gateway, it is the gateway configuration artifact version recorded in a container-creation label, not the Traefik image version. Missing records or labels are `unknown`. A legacy mount path containing a gem version is useful diagnostic evidence but does not prove which Ruby code or configuration the running process loaded. Neither version record is a content hash or proof that bind-mounted files have remained unchanged.
114
+
115
+ Installing a newer gem does not update already-running services. A known difference is reported as `mismatch`; legacy `unknown` provenance cannot establish that an upgrade is active. Coordinate restart timing with all consumers before explicitly updating only the database router:
116
+
117
+ ```sh
118
+ bundle exec local-development-gateway up --no-deps --force-recreate database-router
119
+ bundle exec local-development-gateway status
120
+ ```
121
+
122
+ Recreating the shared database router interrupts existing database client sessions across every consuming project/worktree. This command leaves the HTTP gateway and consumer database containers/volumes alone. If the HTTP gateway itself needs an update, separately coordinate and explicitly select `gateway` instead. Do not use `down` for a router-only update. After updating, confirm the selected service's active version is current and exercise an encrypted connection to the intended database; readiness alone is insufficient release verification.
123
+
109
124
  ## Worktree database services
110
125
 
111
126
  The gateway includes protocol drivers for encrypted SQL Server and PostgreSQL
@@ -419,6 +434,11 @@ It mounts the Docker socket so it can discover labelled containers. A read-only
419
434
  | A project uses normal ports unexpectedly | Confirm the gateway container is running and has `local-gateway=true`. |
420
435
  | Authentication rejects the callback | Confirm the generated hostname matches the allowed wildcard callback pattern. |
421
436
 
437
+ ## Release 0.2.3
438
+
439
+ - Status and healthy CLI reuse distinguish the installed gem version from each active shared service, reporting mismatches and unknown legacy provenance without restarting services.
440
+ - Scoped router update instructions explain shared database session interruption and keep restart timing under caller control. Health readiness and Ruby lifecycle return values remain unchanged.
441
+
422
442
  ## Release 0.2.2
423
443
 
424
444
  - Canonical SQL Server/PostgreSQL Compose integration supports concurrent
data/docker-compose.yml CHANGED
@@ -13,6 +13,7 @@ services:
13
13
  start_period: 1s
14
14
  labels:
15
15
  local-gateway: "true"
16
+ local-gateway.version: "${LOCAL_DEVELOPMENT_GATEWAY_VERSION:-unknown}"
16
17
  ports:
17
18
  - "127.0.0.1:80:80"
18
19
  restart: unless-stopped
@@ -29,7 +30,7 @@ services:
29
30
  - -I/app/lib
30
31
  - -rlocal_development_gateway
31
32
  - -e
32
- - LocalDevelopmentGateway::DatabaseRouter.run
33
+ - File.write("/tmp/local-development-gateway-version", LocalDevelopmentGateway::VERSION); LocalDevelopmentGateway::DatabaseRouter.run
33
34
  healthcheck:
34
35
  test:
35
36
  - CMD
@@ -43,6 +44,7 @@ services:
43
44
  start_period: 1s
44
45
  labels:
45
46
  local-gateway: "true"
47
+ local-gateway.version: "${LOCAL_DEVELOPMENT_GATEWAY_VERSION:-unknown}"
46
48
  ports:
47
49
  - "127.0.0.1:1433:1433"
48
50
  - "127.0.0.1:5432:5432"
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module LocalDevelopmentGateway
4
- VERSION = "0.2.2"
4
+ VERSION = "0.2.3"
5
5
  end
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "open3"
4
+ require "json"
4
5
  require "local_development_gateway/version"
5
6
 
6
7
  module LocalDevelopmentGateway
@@ -29,16 +30,16 @@ module LocalDevelopmentGateway
29
30
  end
30
31
 
31
32
  class Docker
32
- def call(*args, capture: true)
33
+ def call(*args, capture: true, env: {})
33
34
  command = ["docker", *args]
34
35
  if capture
35
- stdout, stderr, status = Open3.capture3(*command)
36
+ stdout, stderr, status = Open3.capture3(env, *command)
36
37
  unless status.success?
37
38
  raise DockerError.new(command, stderr.empty? ? stdout : stderr)
38
39
  end
39
40
 
40
41
  stdout
41
- elsif system(*command)
42
+ elsif system(env, *command)
42
43
  true
43
44
  else
44
45
  raise DockerError.new(command, "")
@@ -85,7 +86,17 @@ module LocalDevelopmentGateway
85
86
  end
86
87
 
87
88
  def status
88
- compose("ps", "--all")
89
+ output = compose("ps", "--all")
90
+ output << "\nInstalled gateway version: #{VERSION}\n"
91
+ SERVICE_NAMES.each do |service|
92
+ ids = gateway_container_ids(service: service, status: "running")
93
+ if ids.empty?
94
+ output << "#{service}: not running; active=unknown\n"
95
+ else
96
+ ids.each { |id| output << service_version_status(service, id) }
97
+ end
98
+ end
99
+ output
89
100
  end
90
101
 
91
102
  def logs(*args, follow: false)
@@ -122,12 +133,56 @@ module LocalDevelopmentGateway
122
133
  "--file",
123
134
  COMPOSE_FILE,
124
135
  *args,
125
- capture: capture
136
+ capture: capture,
137
+ env: {
138
+ "LOCAL_DEVELOPMENT_GATEWAY_VERSION" => VERSION
139
+ }
126
140
  )
127
141
  end
128
142
 
129
143
  private
130
144
 
145
+ def service_version_status(service, id)
146
+ container = JSON.parse(@runner.call("inspect", id)).fetch(0)
147
+ if service == "database-router"
148
+ version = router_version(id)
149
+ provenance = "process-start record"
150
+ asset_target = "/app/lib"
151
+ else
152
+ version = container.dig("Config", "Labels", "local-gateway.version")
153
+ provenance = "container-creation label"
154
+ asset_target = "/etc/traefik/traefik.yml"
155
+ end
156
+ version = "unknown" if version.nil? || version.empty?
157
+ comparison = version_comparison(version)
158
+ mount =
159
+ container
160
+ .fetch("Mounts", [])
161
+ .find { |entry| entry["Destination"] == asset_target }
162
+ source = "unknown"
163
+ source = mount.fetch("Source") if mount
164
+ "#{service} (#{id[0, 12]}): active=#{version}; #{comparison}; " \
165
+ "provenance=#{provenance}; mounted assets=#{source}\n"
166
+ end
167
+
168
+ def router_version(id)
169
+ @runner.call(
170
+ "exec",
171
+ id,
172
+ "cat",
173
+ "/tmp/local-development-gateway-version"
174
+ ).strip
175
+ rescue DockerError
176
+ nil
177
+ end
178
+
179
+ def version_comparison(version)
180
+ return "unknown" if version == "unknown"
181
+ return "current" if version == VERSION
182
+
183
+ "mismatch (installed=#{VERSION}); explicit service recreation required"
184
+ end
185
+
131
186
  def wait_until_ready
132
187
  deadline = @clock.call + @timeout
133
188
  until ready?
@@ -233,7 +288,7 @@ module LocalDevelopmentGateway
233
288
 
234
289
  Commands:
235
290
  up, ensure Start or reuse the shared gateway
236
- status Show the gateway Compose status
291
+ status Show Compose status and installed/active gateway versions
237
292
  ready Check gateway readiness
238
293
  logs Follow gateway logs
239
294
  down, stop Stop the gateway only when unused
@@ -260,7 +315,8 @@ module LocalDevelopmentGateway
260
315
 
261
316
  case command
262
317
  when "up", "ensure"
263
- @client.ensure_running(*@argv)
318
+ result = @client.ensure_running(*@argv)
319
+ @output.write(@client.status) if result == :reused
264
320
  when "status"
265
321
  @output.write(@client.status)
266
322
  when "ready"
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: local-development-gateway
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.2
4
+ version: 0.2.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Marlen Brunner
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2026-10-14 00:00:00.000000000 Z
11
+ date: 2026-10-22 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: Ruby API and CLI for starting, monitoring, and conditionally stopping
14
14
  the shared Docker gateway.