specwrk 0.19.3 → 0.20.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: b2eb07bead54ad609b2d8fb821793a60b783485326daeccc092c14343ae96dc0
4
- data.tar.gz: c41e008f026a61f2748cc8f5cd9c7dc2c257103518aa89fded4c84c9bd2ca976
3
+ metadata.gz: bcca0fc704129ebe6ad960f90166eefc96f201770e8f1275819352e3cf393deb
4
+ data.tar.gz: 5d645cd42996ada9777436c77176b5d6f2765ac9bc309a6a95f3168e8cf492ac
5
5
  SHA512:
6
- metadata.gz: 1f9a7206df73023a2262d9775ff3b1983f403b4630ce54a04f7c4500ab77c51d30df6262604332b37e37fdf21cb98fe39952fcd0287f8b9ded7811a39ac97afe
7
- data.tar.gz: ffbf1b2583044b4f3e4bdbc7cadb35278f93eb64274905c5869398f5ece9d2854ddad0c75463ac8172d025d8dcc7a92c8486d5d9ef581ad269c875aca5c22420
6
+ metadata.gz: fd3f60a8fad29da110306d581f4e4488ca40e4ecd34d9d6df0f80738d00523342a2f9bf3300a0f69bd8a68bdd7e462d69dd28472982128554d3e3f64848673b5
7
+ data.tar.gz: b21823a4008acfaa4e0c964cd5885ceec7310827374fa775d53b5ec346fe9417f6b368df6d2908d70cd9dcd67707edc1e0485db13a5d64133c6fd6b82d8a9955
data/CHANGELOG.md CHANGED
@@ -1,7 +1,16 @@
1
1
  # Changelog
2
2
 
3
3
  ## Unreleased
4
- [Compare](https://github.com/danielwestendorf/specwrk/compare/v0.19.3...main)
4
+ [Compare](https://github.com/danielwestendorf/specwrk/compare/v0.20.0...main)
5
+
6
+ ## v0.20.0 — 2026-08-23
7
+ [Compare](https://github.com/danielwestendorf/specwrk/compare/v0.19.4...v0.20.0)
8
+ - Publish the Docker server with `specwrk-store-redis_adapter` 0.2.0 — [@danielwestendorf](https://github.com/danielwestendorf)
9
+
10
+ ## v0.19.4 — 2026-08-23
11
+ [Compare](https://github.com/danielwestendorf/specwrk/compare/v0.19.3...v0.19.4)
12
+ - Return HTTP 423 on lock contention and retry clients with jitter — [#189](https://github.com/danielwestendorf/specwrk/pull/189) by [@danielwestendorf](https://github.com/danielwestendorf)
13
+ - Document the gem and Docker release process — [#190](https://github.com/danielwestendorf/specwrk/pull/190) by [@danielwestendorf](https://github.com/danielwestendorf)
5
14
 
6
15
  ## v0.19.3 — 2026-07-26
7
16
  [Compare](https://github.com/danielwestendorf/specwrk/compare/v0.19.2...v0.19.3)
data/README.md CHANGED
@@ -292,6 +292,8 @@ specwrk is different because it:
292
292
 
293
293
  Bug reports and pull requests are welcome on GitHub at https://github.com/danielwestendorf/specwrk.
294
294
 
295
+ Maintainers can follow [RELEASING.md](RELEASING.md) to publish the gem and Docker image.
296
+
295
297
  ## License
296
298
 
297
299
  The gem is available as open source under the terms of the [LGPLv3 License](http://www.gnu.org/licenses/lgpl-3.0.html).
data/RELEASING.md ADDED
@@ -0,0 +1,126 @@
1
+ # Releasing Specwrk
2
+
3
+ Releases are cut from `main` in two stages:
4
+
5
+ 1. `gem bump` updates the version and creates the release commit.
6
+ 2. Bundler's `rake release` task tags the commit, pushes Git, and publishes the gem.
7
+
8
+ The Docker image is published separately after the gem release.
9
+
10
+ ## One-time setup
11
+
12
+ Install `gem-release`, which provides the `gem bump` command. It is intentionally
13
+ not a development dependency because it is only needed by maintainers cutting a
14
+ release.
15
+
16
+ ```sh
17
+ gem install gem-release
18
+ ```
19
+
20
+ Configure credentials for RubyGems and Docker Hub:
21
+
22
+ ```sh
23
+ gem signin
24
+ docker login docker.io
25
+ ```
26
+
27
+ The Docker release also requires a buildx builder capable of building `linux/arm64`
28
+ and `linux/amd64` images. Check the active builder with:
29
+
30
+ ```sh
31
+ docker buildx inspect --bootstrap
32
+ ```
33
+
34
+ ## Cut the gem release
35
+
36
+ Start from an up-to-date, clean `main` branch. This is important because
37
+ `rake release` pushes the current branch.
38
+
39
+ ```sh
40
+ git switch main
41
+ git pull --ff-only origin main
42
+ git status --short
43
+ ```
44
+
45
+ Bump the version without committing. Use `patch`, `minor`, `major`, or an
46
+ explicit version number:
47
+
48
+ ```sh
49
+ gem bump --version patch --no-commit
50
+ ```
51
+
52
+ This updates `lib/specwrk/version.rb` while leaving the release changes
53
+ uncommitted. Update `CHANGELOG.md` using the new version:
54
+
55
+ 1. Change the Unreleased comparison link to start at the new version.
56
+ 2. Add a dated section for the new version.
57
+ 3. Move the Unreleased entries into that section.
58
+
59
+ Stage the version, changelog, and any release documentation, then create the
60
+ version commit:
61
+
62
+ ```sh
63
+ git add lib/specwrk/version.rb CHANGELOG.md RELEASING.md
64
+ git commit -m "Bump specwrk to VERSION"
65
+ ```
66
+
67
+ Replace `VERSION` with the new version, for example `0.19.4`. Confirm that the
68
+ commit contains the version and changelog updates:
69
+
70
+ ```sh
71
+ git show --stat --oneline HEAD
72
+ git status --short
73
+ ```
74
+
75
+ Run the full checks:
76
+
77
+ ```sh
78
+ bundle exec rake
79
+ ```
80
+
81
+ Publish the release:
82
+
83
+ ```sh
84
+ bundle exec rake release
85
+ ```
86
+
87
+ The release task requires a clean tracked worktree and then:
88
+
89
+ 1. Builds `pkg/specwrk-VERSION.gem`.
90
+ 2. Creates the annotated `vVERSION` tag.
91
+ 3. Pushes `main` and the tag to `origin`.
92
+ 4. Pushes the gem to RubyGems.org.
93
+
94
+ Use `gem bump` only to update the version file; use `bundle exec rake release`,
95
+ not `gem release`, for publishing this project.
96
+
97
+ If the RubyGems push fails after the tag was pushed, fix the authentication or
98
+ network problem and rerun `bundle exec rake release`. The task recognizes the
99
+ existing tag and retries the gem publication.
100
+
101
+ ## Build and publish the Docker image
102
+
103
+ After the gem release succeeds, run:
104
+
105
+ ```sh
106
+ scripts/build-server
107
+ ```
108
+
109
+ The script reads the version from `bundle exec exe/specwrk --version`, builds the
110
+ gem from the current checkout, and runs a multi-platform `docker buildx build`
111
+ with `--push`. It publishes both of these tags:
112
+
113
+ - `docker.io/danielwestendorf/specwrk-server:VERSION`
114
+ - `docker.io/danielwestendorf/specwrk-server:latest`
115
+
116
+ It builds images for both `linux/arm64` and `linux/amd64`. The temporary gem in
117
+ the repository root is removed after a successful build.
118
+
119
+ Verify the published manifest with:
120
+
121
+ ```sh
122
+ docker buildx imagetools inspect docker.io/danielwestendorf/specwrk-server:VERSION
123
+ ```
124
+
125
+ Replace `VERSION` with the released version without the `v` prefix, for example
126
+ `0.19.4`.
data/lib/specwrk/cli.rb CHANGED
@@ -67,7 +67,7 @@ module Specwrk
67
67
 
68
68
  def worker_env_for(idx)
69
69
  {
70
- "TEST_ENV_NUMBER" => idx.to_s,
70
+ "TEST_ENV_NUMBER" => (idx == 1) ? "" : idx.to_s,
71
71
  "SPECWRK_FORKED" => idx.to_s,
72
72
  "SPECWRK_ID" => "#{ENV.fetch("SPECWRK_ID", "specwrk-worker")}-#{idx}"
73
73
  }
@@ -12,6 +12,8 @@ Specwrk.net_http = Net::HTTP
12
12
 
13
13
  module Specwrk
14
14
  class Client
15
+ LockedResponseError = Class.new(StandardError)
16
+
15
17
  def self.connect?
16
18
  http = build_http
17
19
  http.start
@@ -158,10 +160,14 @@ module Specwrk
158
160
  @last_request_at = Time.now
159
161
  @http.request(request).tap do |response|
160
162
  @retry_count = 0
163
+ raise LockedResponseError if response.code == "423"
161
164
 
162
165
  @worker_status = response["x-specwrk-status"].to_i if response["x-specwrk-status"]
163
166
  end
164
167
  end
168
+ rescue LockedResponseError
169
+ sleep rand
170
+ retry
165
171
  rescue Net::ReadTimeout, Net::WriteTimeout => e
166
172
  @retry_count ||= 0
167
173
 
@@ -4,6 +4,8 @@ require "uri"
4
4
 
5
5
  module Specwrk
6
6
  class Store
7
+ LockUnavailableError = Class.new(StandardError)
8
+
7
9
  class << self
8
10
  def with_lock(uri, key)
9
11
  adapter_klass(uri).with_lock(uri, key) { yield }
@@ -24,11 +24,13 @@ module Specwrk
24
24
 
25
25
  lock_file = File.open(lock_file_path, "a")
26
26
 
27
- Thread.pass until lock_file.flock(File::LOCK_EX)
27
+ locked = lock_file.flock(File::LOCK_EX | File::LOCK_NB)
28
+ raise LockUnavailableError unless locked
28
29
 
29
30
  yield
30
31
  ensure
31
- lock_file.flock(File::LOCK_UN)
32
+ lock_file&.flock(File::LOCK_UN) if locked
33
+ lock_file&.close
32
34
  end
33
35
 
34
36
  def schedule_work(&blk)
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Specwrk
4
- VERSION = "0.19.3"
4
+ VERSION = "0.20.0"
5
5
  end
@@ -30,6 +30,8 @@ module Specwrk
30
30
  with_response.tap do |response|
31
31
  response[1]["x-specwrk-status"] = worker_status.to_s
32
32
  end
33
+ rescue Store::LockUnavailableError
34
+ locked
33
35
  end
34
36
 
35
37
  def with_response
@@ -56,6 +58,14 @@ module Specwrk
56
58
  end
57
59
  end
58
60
 
61
+ def locked
62
+ if request.head?
63
+ [423, {}, []]
64
+ else
65
+ [423, {"content-type" => "text/plain"}, ["Locked. Try again later."]]
66
+ end
67
+ end
68
+
59
69
  def payload
60
70
  return unless request.content_type&.start_with?("application/json")
61
71
  return unless request.post? || request.put? || request.delete?
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: specwrk
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.19.3
4
+ version: 0.20.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Daniel Westendorf
@@ -204,6 +204,7 @@ files:
204
204
  - CHANGELOG.md
205
205
  - LICENSE
206
206
  - README.md
207
+ - RELEASING.md
207
208
  - Rakefile
208
209
  - Specwrk.watchfile.rb
209
210
  - config.ru