donce 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/Gemfile.lock ADDED
@@ -0,0 +1,227 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ donce (0.0.0)
5
+ backtrace (> 0)
6
+ os (> 0)
7
+ qbash (> 0)
8
+
9
+ GEM
10
+ remote: https://rubygems.org/
11
+ specs:
12
+ actionpack (8.0.1)
13
+ actionview (= 8.0.1)
14
+ activesupport (= 8.0.1)
15
+ nokogiri (>= 1.8.5)
16
+ rack (>= 2.2.4)
17
+ rack-session (>= 1.0.1)
18
+ rack-test (>= 0.6.3)
19
+ rails-dom-testing (~> 2.2)
20
+ rails-html-sanitizer (~> 1.6)
21
+ useragent (~> 0.16)
22
+ actionview (8.0.1)
23
+ activesupport (= 8.0.1)
24
+ builder (~> 3.1)
25
+ erubi (~> 1.11)
26
+ rails-dom-testing (~> 2.2)
27
+ rails-html-sanitizer (~> 1.6)
28
+ activesupport (8.0.1)
29
+ base64
30
+ benchmark (>= 0.3)
31
+ bigdecimal
32
+ concurrent-ruby (~> 1.0, >= 1.3.1)
33
+ connection_pool (>= 2.2.5)
34
+ drb
35
+ i18n (>= 1.6, < 2)
36
+ logger (>= 1.4.2)
37
+ minitest (>= 5.1)
38
+ securerandom (>= 0.3)
39
+ tzinfo (~> 2.0, >= 2.0.5)
40
+ uri (>= 0.13.1)
41
+ ansi (1.5.0)
42
+ ast (2.4.2)
43
+ backtrace (0.4.0)
44
+ base64 (0.2.0)
45
+ benchmark (0.4.0)
46
+ bigdecimal (3.1.9)
47
+ builder (3.3.0)
48
+ concurrent-ruby (1.3.5)
49
+ connection_pool (2.5.0)
50
+ crass (1.0.6)
51
+ date (3.4.1)
52
+ diff-lcs (1.5.1)
53
+ docile (1.4.1)
54
+ drb (2.2.1)
55
+ elapsed (0.0.1)
56
+ loog (> 0)
57
+ tago (> 0)
58
+ erubi (1.13.1)
59
+ i18n (1.14.7)
60
+ concurrent-ruby (~> 1.0)
61
+ io-console (0.8.0)
62
+ irb (1.15.1)
63
+ pp (>= 0.6.0)
64
+ rdoc (>= 4.0.0)
65
+ reline (>= 0.4.2)
66
+ json (2.9.1)
67
+ language_server-protocol (3.17.0.4)
68
+ logger (1.6.5)
69
+ loofah (2.24.0)
70
+ crass (~> 1.0.2)
71
+ nokogiri (>= 1.12.0)
72
+ loog (0.6.0)
73
+ minitest (5.25.4)
74
+ minitest-reporters (1.7.1)
75
+ ansi
76
+ builder
77
+ minitest (>= 5.0)
78
+ ruby-progressbar
79
+ minitest-retry (0.2.5)
80
+ minitest (>= 5.0)
81
+ nokogiri (1.18.2-arm64-darwin)
82
+ racc (~> 1.4)
83
+ nokogiri (1.18.2-x64-mingw-ucrt)
84
+ racc (~> 1.4)
85
+ nokogiri (1.18.2-x86_64-darwin)
86
+ racc (~> 1.4)
87
+ nokogiri (1.18.2-x86_64-linux-gnu)
88
+ racc (~> 1.4)
89
+ os (1.1.4)
90
+ parallel (1.26.3)
91
+ parser (3.3.7.1)
92
+ ast (~> 2.4.1)
93
+ racc
94
+ pp (0.6.2)
95
+ prettyprint
96
+ prettyprint (0.2.0)
97
+ psych (5.2.3)
98
+ date
99
+ stringio
100
+ qbash (0.3.2)
101
+ backtrace (> 0)
102
+ elapsed (> 0)
103
+ loog (> 0)
104
+ tago (> 0)
105
+ racc (1.8.1)
106
+ rack (3.1.9)
107
+ rack-session (2.1.0)
108
+ base64 (>= 0.1.0)
109
+ rack (>= 3.0.0)
110
+ rack-test (2.2.0)
111
+ rack (>= 1.3)
112
+ rackup (2.2.1)
113
+ rack (>= 3)
114
+ rails-dom-testing (2.2.0)
115
+ activesupport (>= 5.0.0)
116
+ minitest
117
+ nokogiri (>= 1.6)
118
+ rails-html-sanitizer (1.6.2)
119
+ loofah (~> 2.21)
120
+ nokogiri (>= 1.15.7, != 1.16.7, != 1.16.6, != 1.16.5, != 1.16.4, != 1.16.3, != 1.16.2, != 1.16.1, != 1.16.0.rc1, != 1.16.0)
121
+ railties (8.0.1)
122
+ actionpack (= 8.0.1)
123
+ activesupport (= 8.0.1)
124
+ irb (~> 1.13)
125
+ rackup (>= 1.0.0)
126
+ rake (>= 12.2)
127
+ thor (~> 1.0, >= 1.2.2)
128
+ zeitwerk (~> 2.6)
129
+ rainbow (3.1.1)
130
+ rake (13.2.1)
131
+ rdoc (6.11.0)
132
+ psych (>= 4.0.0)
133
+ regexp_parser (2.10.0)
134
+ reline (0.6.0)
135
+ io-console (~> 0.5)
136
+ rexml (3.4.0)
137
+ rspec-core (3.13.2)
138
+ rspec-support (~> 3.13.0)
139
+ rspec-expectations (3.13.3)
140
+ diff-lcs (>= 1.2.0, < 2.0)
141
+ rspec-support (~> 3.13.0)
142
+ rspec-mocks (3.13.2)
143
+ diff-lcs (>= 1.2.0, < 2.0)
144
+ rspec-support (~> 3.13.0)
145
+ rspec-rails (7.1.0)
146
+ actionpack (>= 7.0)
147
+ activesupport (>= 7.0)
148
+ railties (>= 7.0)
149
+ rspec-core (~> 3.13)
150
+ rspec-expectations (~> 3.13)
151
+ rspec-mocks (~> 3.13)
152
+ rspec-support (~> 3.13)
153
+ rspec-support (3.13.2)
154
+ rubocop (1.71.2)
155
+ json (~> 2.3)
156
+ language_server-protocol (>= 3.17.0)
157
+ parallel (~> 1.10)
158
+ parser (>= 3.3.0.2)
159
+ rainbow (>= 2.2.2, < 4.0)
160
+ regexp_parser (>= 2.9.3, < 3.0)
161
+ rubocop-ast (>= 1.38.0, < 2.0)
162
+ ruby-progressbar (~> 1.7)
163
+ unicode-display_width (>= 2.4.0, < 4.0)
164
+ rubocop-ast (1.38.0)
165
+ parser (>= 3.3.1.0)
166
+ rubocop-minitest (0.36.0)
167
+ rubocop (>= 1.61, < 2.0)
168
+ rubocop-ast (>= 1.31.1, < 2.0)
169
+ rubocop-performance (1.23.1)
170
+ rubocop (>= 1.48.1, < 2.0)
171
+ rubocop-ast (>= 1.31.1, < 2.0)
172
+ rubocop-rake (0.6.0)
173
+ rubocop (~> 1.0)
174
+ rubocop-rspec (3.4.0)
175
+ rubocop (~> 1.61)
176
+ ruby-progressbar (1.13.0)
177
+ securerandom (0.4.1)
178
+ simplecov (0.22.0)
179
+ docile (~> 1.1)
180
+ simplecov-html (~> 0.11)
181
+ simplecov_json_formatter (~> 0.1)
182
+ simplecov-cobertura (2.1.0)
183
+ rexml
184
+ simplecov (~> 0.19)
185
+ simplecov-html (0.13.1)
186
+ simplecov_json_formatter (0.1.4)
187
+ stringio (3.1.2)
188
+ tago (0.0.2)
189
+ thor (1.3.2)
190
+ tzinfo (2.0.6)
191
+ concurrent-ruby (~> 1.0)
192
+ unicode-display_width (3.1.4)
193
+ unicode-emoji (~> 4.0, >= 4.0.4)
194
+ unicode-emoji (4.0.4)
195
+ uri (1.0.2)
196
+ useragent (0.16.11)
197
+ yard (0.9.37)
198
+ zeitwerk (2.7.1)
199
+
200
+ PLATFORMS
201
+ arm64-darwin-22
202
+ arm64-darwin-23
203
+ arm64-darwin-24
204
+ x64-mingw-ucrt
205
+ x86_64-darwin-20
206
+ x86_64-darwin-21
207
+ x86_64-linux
208
+
209
+ DEPENDENCIES
210
+ donce!
211
+ loog (> 0)
212
+ minitest (= 5.25.4)
213
+ minitest-reporters (= 1.7.1)
214
+ minitest-retry (= 0.2.5)
215
+ rake (= 13.2.1)
216
+ rspec-rails (= 7.1.0)
217
+ rubocop (= 1.71.2)
218
+ rubocop-minitest (= 0.36.0)
219
+ rubocop-performance (= 1.23.1)
220
+ rubocop-rake (> 0)
221
+ rubocop-rspec (= 3.4.0)
222
+ simplecov (= 0.22.0)
223
+ simplecov-cobertura (= 2.1.0)
224
+ yard (= 0.9.37)
225
+
226
+ BUNDLED WITH
227
+ 2.5.16
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ (The MIT License)
2
+
3
+ Copyright (c) 2025 Yegor Bugayenko
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the 'Software'), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,51 @@
1
+ # Builds Docker image, runs it, and kills
2
+
3
+ [![DevOps By Rultor.com](http://www.rultor.com/b/yegor256/donce)](http://www.rultor.com/p/yegor256/donce)
4
+ [![We recommend RubyMine](https://www.elegantobjects.org/rubymine.svg)](https://www.jetbrains.com/ruby/)
5
+
6
+ [![rake](https://github.com/yegor256/donce/actions/workflows/rake.yml/badge.svg)](https://github.com/yegor256/donce/actions/workflows/rake.yml)
7
+ [![PDD status](http://www.0pdd.com/svg?name=yegor256/donce)](http://www.0pdd.com/p?name=yegor256/donce)
8
+ [![Gem Version](https://badge.fury.io/rb/donce.svg)](http://badge.fury.io/rb/donce)
9
+ [![Test Coverage](https://img.shields.io/codecov/c/github/yegor256/donce.svg)](https://codecov.io/github/yegor256/donce?branch=master)
10
+ [![Yard Docs](http://img.shields.io/badge/yard-docs-blue.svg)](http://rubydoc.info/github/yegor256/donce/master/frames)
11
+ [![Hits-of-Code](https://hitsofcode.com/github/yegor256/donce)](https://hitsofcode.com/view/github/yegor256/donce)
12
+ [![License](https://img.shields.io/badge/license-MIT-green.svg)](https://github.com/yegor256/donce/blob/master/LICENSE.txt)
13
+
14
+ This small Ruby library helps building temporary [Docker]
15
+ images, run Docker containers, and clean up afterwards --- may be
16
+ convenient for automated tests (for example, with [Minitest]):
17
+
18
+ ```ruby
19
+ class MyTest < Minitest::Test
20
+ def test_prints_hello_world
21
+ stdout = donce(
22
+ dockerfile: '
23
+ FROM ubuntu
24
+ CMD echo "Hello, world!"
25
+ '
26
+ )
27
+ assert_equal("Hello, world!\n", stdout)
28
+ end
29
+ end
30
+ ```
31
+
32
+ That's it.
33
+
34
+ ## How to contribute
35
+
36
+ Read
37
+ [these guidelines](https://www.yegor256.com/2014/04/15/github-guidelines.html).
38
+ Make sure you build is green before you contribute
39
+ your pull request. You will need to have
40
+ [Ruby](https://www.ruby-lang.org/en/) 3.2+ and
41
+ [Bundler](https://bundler.io/) installed. Then:
42
+
43
+ ```bash
44
+ bundle update
45
+ bundle exec rake
46
+ ```
47
+
48
+ If it's clean and you don't see any error messages, submit your pull request.
49
+
50
+ [Docker]: https://www.docker.com/
51
+ [Minitest]: https://github.com/minitest/minitest
data/Rakefile ADDED
@@ -0,0 +1,63 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Copyright (c) 2025 Yegor Bugayenko
4
+ #
5
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ # of this software and associated documentation files (the 'Software'), to deal
7
+ # in the Software without restriction, including without limitation the rights
8
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ # copies of the Software, and to permit persons to whom the Software is
10
+ # furnished to do so, subject to the following conditions:
11
+ #
12
+ # The above copyright notice and this permission notice shall be included in all
13
+ # copies or substantial portions of the Software.
14
+ #
15
+ # THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ # SOFTWARE.
22
+
23
+ require 'rubygems'
24
+ require 'rake'
25
+ require 'rake/clean'
26
+
27
+ def name
28
+ @name ||= File.basename(Dir['*.gemspec'].first, '.*')
29
+ end
30
+
31
+ def version
32
+ Gem::Specification.load(Dir['*.gemspec'].first).version
33
+ end
34
+
35
+ task default: %i[clean test rubocop yard]
36
+
37
+ require 'rake/testtask'
38
+ desc 'Run all unit tests'
39
+ Rake::TestTask.new(:test) do |test|
40
+ Rake::Cleaner.cleanup_files(['coverage'])
41
+ test.libs << 'lib' << 'test'
42
+ test.pattern = 'test/**/test_*.rb'
43
+ test.warning = true
44
+ test.verbose = false
45
+ end
46
+
47
+ require 'yard'
48
+ desc 'Build Yard documentation'
49
+ YARD::Rake::YardocTask.new do |t|
50
+ t.files = ['lib/**/*.rb']
51
+ end
52
+
53
+ require 'rubocop/rake_task'
54
+ desc 'Run RuboCop on all directories'
55
+ RuboCop::RakeTask.new(:rubocop) do |task|
56
+ task.fail_on_error = true
57
+ task.requires << 'rubocop-rspec'
58
+ end
59
+
60
+ desc 'Run benchmark script'
61
+ task :benchmark do
62
+ ruby 'benchmarks/simple.rb'
63
+ end
data/donce.gemspec ADDED
@@ -0,0 +1,49 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Copyright (c) 2025 Yegor Bugayenko
4
+ #
5
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ # of this software and associated documentation files (the 'Software'), to deal
7
+ # in the Software without restriction, including without limitation the rights
8
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ # copies of the Software, and to permit persons to whom the Software is
10
+ # furnished to do so, subject to the following conditions:
11
+ #
12
+ # The above copyright notice and this permission notice shall be included in all
13
+ # copies or substantial portions of the Software.
14
+ #
15
+ # THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ # SOFTWARE.
22
+
23
+ require 'English'
24
+
25
+ Gem::Specification.new do |s|
26
+ s.required_rubygems_version = Gem::Requirement.new('>= 0') if s.respond_to? :required_rubygems_version=
27
+ s.required_ruby_version = '>=3.0'
28
+ s.name = 'donce'
29
+ s.version = '0.0.1'
30
+ s.license = 'MIT'
31
+ s.summary = 'Builds and starts temporary Docker containers'
32
+ s.description =
33
+ 'A one-function library that helps you build a temporary Docker ' \
34
+ 'image, run a temporary Docker container from it, and then clean ' \
35
+ 'up, deleting them both. This may be helpful for automated testing, ' \
36
+ 'when you test how your code might behave in an isolated environment. ' \
37
+ 'This may also be helpful when you need a custom Docker image with a ' \
38
+ 'tool inside, but Testcontainers don\' have such an image.'
39
+ s.authors = ['Yegor Bugayenko']
40
+ s.email = 'yegor256@gmail.com'
41
+ s.homepage = 'http://github.com/yegor256/donce.rb'
42
+ s.files = `git ls-files`.split($RS)
43
+ s.rdoc_options = ['--charset=UTF-8']
44
+ s.extra_rdoc_files = ['README.md', 'LICENSE.txt']
45
+ s.add_dependency 'backtrace', '>0'
46
+ s.add_dependency 'os', '>0'
47
+ s.add_dependency 'qbash', '>0'
48
+ s.metadata['rubygems_mfa_required'] = 'true'
49
+ end
data/lib/donce.rb ADDED
@@ -0,0 +1,147 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Copyright (c) 2025 Yegor Bugayenko
4
+ #
5
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ # of this software and associated documentation files (the 'Software'), to deal
7
+ # in the Software without restriction, including without limitation the rights
8
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ # copies of the Software, and to permit persons to whom the Software is
10
+ # furnished to do so, subject to the following conditions:
11
+ #
12
+ # The above copyright notice and this permission notice shall be included in all
13
+ # copies or substantial portions of the Software.
14
+ #
15
+ # THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFINGEMENT. IN NO EVENT SHALL THE
18
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ # SOFTWARE.
22
+
23
+ require 'logger'
24
+ require 'os'
25
+ require 'qbash'
26
+ require 'securerandom'
27
+ require 'shellwords'
28
+
29
+ # Execute Docker container and clean up afterwards.
30
+ #
31
+ # This function helps building temporary Docker
32
+ # images, run Docker containers, and clean up afterwards — may be
33
+ # convenient for automated tests (for example, with Minitest):
34
+ #
35
+ # class MyTest < Minitest::Test
36
+ # def test_prints_hello_world
37
+ # stdout = donce(
38
+ # dockerfile: '
39
+ # FROM ubuntu
40
+ # CMD echo "Hello, world!"
41
+ # '
42
+ # )
43
+ # assert_equal("Hello, world!\n", stdout)
44
+ # end
45
+ # end
46
+ #
47
+ # It's possible to pass a block to it too, which will lead to
48
+ # background execution of the container (in daemon mode):
49
+ #
50
+ # def test_runs_daemon
51
+ # donce(dockerfile: "FROM ubuntu\nCMD sleep 9999") do |id, host|
52
+ # refute_empty(id) # the ID of the container
53
+ # refute_empty(host) # the hostname of it
54
+ # end
55
+ # end
56
+ #
57
+ # If you need to run +docker+ via +sudo+, simply set +DONCE_SUDO+ environment
58
+ # variable to any value.
59
+ #
60
+ # Author:: Yegor Bugayenko (yegor256@gmail.com)
61
+ # Copyright:: Copyright (c) 2025 Yegor Bugayenko
62
+ # License:: MIT
63
+ module Kernel
64
+ # Build Docker image (or use existing one), run Docker container, and then clean up.
65
+ #
66
+ # @param [String] dockerfile The content of the +Dockerfile+
67
+ # @param [String] home The directory with Dockerfile and all other necessary files
68
+ # @param [String] image The name of Docker image, e.g. "ubuntu:24.04"
69
+ # @param [Logger] log The logging destination, can be +$stdout+
70
+ # @param [String|Array<String>] args List of extra arguments for the +docker+ command
71
+ # @param [Hash<String,String>] env Environment variables going into the container
72
+ # @param [Boolean] root Let user inside the container be "root"?
73
+ # @param [String|Array<String>] command The command for the script inside the container
74
+ # @param [Integer] timeout Maximum seconds to spend on each +docker+ call
75
+ def donce(dockerfile: nil, image: nil, home: nil, log: $stdout, args: '', env: {}, root: false, command: '',
76
+ timeout: 10)
77
+ raise 'Either use "dockerfile" or "home"' if dockerfile && home
78
+ raise 'Either use "dockerfile" or "image"' if dockerfile && image
79
+ raise 'Either use "image" or "home"' if home && image
80
+ raise 'Either "dockerfile", or "home", or "image" must be provided' if !dockerfile && !home && !image
81
+ docker = ENV['DONCE_SUDO'] ? 'sudo docker' : 'docker'
82
+ img =
83
+ if image
84
+ image
85
+ else
86
+ i = "donce-#{SecureRandom.hex(8)}"
87
+ if dockerfile
88
+ Dir.mktmpdir do |home|
89
+ File.write(File.join(home, 'Dockerfile'), dockerfile)
90
+ qbash("#{docker} build #{Shellwords.escape(home)} -t #{i}", log:)
91
+ end
92
+ end
93
+ i
94
+ end
95
+ container = "donce-#{SecureRandom.hex(8)}"
96
+ host = OS.linux? ? '172.17.0.1' : 'host.docker.internal'
97
+ begin
98
+ stdout = nil
99
+ code = 0
100
+ begin
101
+ cmd = [
102
+ docker, 'run',
103
+ block_given? ? '-d' : '',
104
+ '--name', Shellwords.escape(container),
105
+ OS.linux? ? '' : "--add-host #{host}:host-gateway",
106
+ args,
107
+ env.map { |k, v| "-e #{Shellwords.escape("#{k}=#{v}")}" }.join(' '),
108
+ root ? '' : "--user=#{Shellwords.escape("#{Process.uid}:#{Process.gid}")}",
109
+ Shellwords.escape(img),
110
+ command
111
+ ].join(' ')
112
+ stdout, code =
113
+ Timeout.timeout(timeout) do
114
+ qbash(
115
+ cmd,
116
+ log:,
117
+ accept: nil,
118
+ both: true,
119
+ env:
120
+ )
121
+ end
122
+ unless code.zero?
123
+ log.error(stdout)
124
+ raise \
125
+ "Failed to run #{cmd} " \
126
+ "(exit code is ##{code}, stdout has #{stdout.split("\n").count} lines)"
127
+ end
128
+ if block_given?
129
+ r = yield container, host
130
+ return r
131
+ end
132
+ ensure
133
+ qbash(
134
+ "#{docker} logs #{Shellwords.escape(container)}",
135
+ level: code.zero? ? Logger::DEBUG : Logger::ERROR,
136
+ log:
137
+ )
138
+ qbash("#{docker} rm -f #{Shellwords.escape(container)}", log:)
139
+ end
140
+ stdout
141
+ ensure
142
+ Timeout.timeout(10) do
143
+ qbash("#{docker} rmi #{img}", log:) unless image
144
+ end
145
+ end
146
+ end
147
+ end
data/renovate.json ADDED
@@ -0,0 +1,6 @@
1
+ {
2
+ "$schema": "https://docs.renovatebot.com/renovate-schema.json",
3
+ "extends": [
4
+ "config:base"
5
+ ]
6
+ }
@@ -0,0 +1,39 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Copyright (c) 2025 Yegor Bugayenko
4
+ #
5
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ # of this software and associated documentation files (the 'Software'), to deal
7
+ # in the Software without restriction, including without limitation the rights
8
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ # copies of the Software, and to permit persons to whom the Software is
10
+ # furnished to do so, subject to the following conditions:
11
+ #
12
+ # The above copyright notice and this permission notice shall be included in all
13
+ # copies or substantial portions of the Software.
14
+ #
15
+ # THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFINGEMENT. IN NO EVENT SHALL THE
18
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ # SOFTWARE.
22
+
23
+ $stdout.sync = true
24
+
25
+ require 'simplecov'
26
+ SimpleCov.external_at_exit = true
27
+ SimpleCov.start
28
+
29
+ require 'simplecov-cobertura'
30
+ SimpleCov.formatter = SimpleCov::Formatter::CoberturaFormatter
31
+
32
+ require 'minitest/autorun'
33
+
34
+ require 'minitest/reporters'
35
+ Minitest::Reporters.use! [Minitest::Reporters::SpecReporter.new]
36
+
37
+ # To make tests retry on failure:
38
+ require 'minitest/retry'
39
+ Minitest::Retry.use!(methods_to_skip: [])
@@ -0,0 +1,46 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Copyright (c) 2025 Yegor Bugayenko
4
+ #
5
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ # of this software and associated documentation files (the 'Software'), to deal
7
+ # in the Software without restriction, including without limitation the rights
8
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ # copies of the Software, and to permit persons to whom the Software is
10
+ # furnished to do so, subject to the following conditions:
11
+ #
12
+ # The above copyright notice and this permission notice shall be included in all
13
+ # copies or substantial portions of the Software.
14
+ #
15
+ # THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFINGEMENT. IN NO EVENT SHALL THE
18
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ # SOFTWARE.
22
+
23
+ require 'minitest/autorun'
24
+ require 'loog'
25
+ require_relative '../lib/donce'
26
+
27
+ # Test.
28
+ # Author:: Yegor Bugayenko (yegor256@gmail.com)
29
+ # Copyright:: Copyright (c) 2025 Yegor Bugayenko
30
+ # License:: MIT
31
+ class TestDonce < Minitest::Test
32
+ def test_runs_simple_echo
33
+ stdout = donce(dockerfile: "FROM ubuntu\nCMD echo hello", log: Loog::NULL)
34
+ assert_equal("hello\n", stdout)
35
+ end
36
+
37
+ def test_runs_daemon
38
+ seen = false
39
+ donce(dockerfile: "FROM ubuntu\nCMD while true; do sleep 1; echo sleeping; done", log: Loog::NULL) do |id, host|
40
+ seen = true
41
+ refute_empty(id)
42
+ refute_empty(host)
43
+ end
44
+ assert(seen)
45
+ end
46
+ end