tinyci 0.1.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 +7 -0
- data/.gitignore +7 -0
- data/.rspec +3 -0
- data/.ruby-version +1 -0
- data/.yardopts +1 -0
- data/Gemfile +13 -0
- data/Gemfile.lock +97 -0
- data/Guardfile +7 -0
- data/LICENSE +21 -0
- data/README.md +211 -0
- data/Rakefile +1 -0
- data/bin/tinyci +10 -0
- data/lib/pidfile.rb +150 -0
- data/lib/tinyci/builders/rkt_builder.rb +31 -0
- data/lib/tinyci/builders/script_builder.rb +18 -0
- data/lib/tinyci/builders/test_builder.rb +11 -0
- data/lib/tinyci/cli.rb +104 -0
- data/lib/tinyci/config.rb +55 -0
- data/lib/tinyci/executor.rb +21 -0
- data/lib/tinyci/git_utils.rb +68 -0
- data/lib/tinyci/installer.rb +55 -0
- data/lib/tinyci/logging.rb +16 -0
- data/lib/tinyci/logo.txt +6 -0
- data/lib/tinyci/multi_logger.rb +49 -0
- data/lib/tinyci/runner.rb +154 -0
- data/lib/tinyci/scheduler.rb +105 -0
- data/lib/tinyci/subprocesses.rb +111 -0
- data/lib/tinyci/symbolize.rb +22 -0
- data/lib/tinyci/testers/rkt_tester.rb +40 -0
- data/lib/tinyci/testers/script_tester.rb +18 -0
- data/lib/tinyci/testers/test_tester.rb +11 -0
- data/lib/tinyci/version.rb +3 -0
- data/tinyci.gemspec +44 -0
- metadata +179 -0
@@ -0,0 +1,111 @@
|
|
1
|
+
require 'open3'
|
2
|
+
require 'tinyci/logging'
|
3
|
+
|
4
|
+
module TinyCI
|
5
|
+
# Methods for executing subprocesses in various ways and collecting the results.
|
6
|
+
module Subprocesses
|
7
|
+
|
8
|
+
# Synchronously execute a command as a subprocess and return the output.
|
9
|
+
#
|
10
|
+
# @param [Array<String>] command The command line
|
11
|
+
# @param [String] label A label for debug and logging purposes
|
12
|
+
#
|
13
|
+
# @return [String] The output of the command
|
14
|
+
# @raise [SubprocessError] if the subprocess returns status > 0
|
15
|
+
def execute(*command, label: nil)
|
16
|
+
output, status = Open3.capture2(*command.flatten)
|
17
|
+
|
18
|
+
log_debug caller[0]
|
19
|
+
log_debug "CMD: #{command.join(' ')}"
|
20
|
+
log_debug "OUT: #{output}"
|
21
|
+
|
22
|
+
unless status.success?
|
23
|
+
log_error output
|
24
|
+
raise SubprocessError.new(label, command.join(' '), status.to_i)
|
25
|
+
end
|
26
|
+
|
27
|
+
output.chomp
|
28
|
+
end
|
29
|
+
|
30
|
+
# Synchronously execute a chain multiple commands piped into each other as a
|
31
|
+
# subprocess and return the output.
|
32
|
+
#
|
33
|
+
# @param [Array<Array<String>>] commands The command lines
|
34
|
+
# @param [String] label A label for debug and logging purposes
|
35
|
+
#
|
36
|
+
# @return [String] The output of the command
|
37
|
+
# @raise [SubprocessError] if the subprocess returns status > 0
|
38
|
+
def execute_pipe(*commands, label: nil)
|
39
|
+
stdout, waiters = Open3.pipeline_r(*commands)
|
40
|
+
output = stdout.read
|
41
|
+
|
42
|
+
waiters.each_with_index do |waiter, i|
|
43
|
+
status = waiter.value
|
44
|
+
unless status.success?
|
45
|
+
log_error output
|
46
|
+
raise SubprocessError.new(label, commands[i].join(' '), status.to_i)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
output.chomp
|
51
|
+
end
|
52
|
+
|
53
|
+
# Synchronously execute a command as a subprocess and and stream the output
|
54
|
+
# asynchronously to `STDOUT`
|
55
|
+
#
|
56
|
+
# @param [Array<String>] command The command line
|
57
|
+
# @param [String] label A label for debug and logging purposes
|
58
|
+
# @param [String] pwd Optionally specify a different working directory in which to execute the command
|
59
|
+
#
|
60
|
+
# @return [TrueClass] `true` if the command executed successfully
|
61
|
+
# @raise [SubprocessError] if the subprocess returns status > 0
|
62
|
+
def execute_stream(*command, label: nil, pwd: nil)
|
63
|
+
opts = {}
|
64
|
+
opts[:chdir] = pwd unless pwd.nil?
|
65
|
+
|
66
|
+
Open3.popen2e(command.join(' '), opts) do |stdin, stdout_and_stderr, wait_thr|
|
67
|
+
stdin.close
|
68
|
+
|
69
|
+
Thread.new do
|
70
|
+
stdout_and_stderr.each_line do |l|
|
71
|
+
log_info l.chomp
|
72
|
+
$stdout.flush
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
unless wait_thr.value.success?
|
77
|
+
raise SubprocessError.new(label, command.join(' '), wait_thr.value)
|
78
|
+
end
|
79
|
+
stdout_and_stderr.close
|
80
|
+
end
|
81
|
+
|
82
|
+
true
|
83
|
+
end
|
84
|
+
|
85
|
+
# An error raised when any of the {Subprocesses} methods fail
|
86
|
+
#
|
87
|
+
# @attr_reader [Integer] status The return code of the process
|
88
|
+
# @attr_reader [String] command The command used to spawn the process
|
89
|
+
class SubprocessError < RuntimeError
|
90
|
+
attr_reader :status
|
91
|
+
attr_reader :command
|
92
|
+
|
93
|
+
def initialize(label, command, status, message = "`#{label || command}` failed with code #{status.to_i}")
|
94
|
+
@status = status
|
95
|
+
@command = command
|
96
|
+
super(message)
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
private
|
101
|
+
|
102
|
+
def self.included(base)
|
103
|
+
base.include TinyCI::Logging
|
104
|
+
end
|
105
|
+
|
106
|
+
def self.extended(base)
|
107
|
+
base.extend TinyCI::Logging
|
108
|
+
end
|
109
|
+
|
110
|
+
end
|
111
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module TinyCI
|
2
|
+
module Symbolize
|
3
|
+
# recursively make all keys of `hash` into symbols
|
4
|
+
# @param [Hash] hash The hash
|
5
|
+
def symbolize(hash)
|
6
|
+
{}.tap do |h|
|
7
|
+
hash.each { |key, value| h[key.to_sym] = map_value(value) }
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
def map_value(thing)
|
12
|
+
case thing
|
13
|
+
when Hash
|
14
|
+
symbolize thing
|
15
|
+
when Array
|
16
|
+
thing.map { |v| map_value(v) }
|
17
|
+
else
|
18
|
+
thing
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
require 'tinyci/executor'
|
2
|
+
|
3
|
+
module TinyCI
|
4
|
+
module Testers
|
5
|
+
class RktTester < TinyCI::Executor
|
6
|
+
def test
|
7
|
+
cmd = [
|
8
|
+
'sudo',
|
9
|
+
'rkt',
|
10
|
+
'run',
|
11
|
+
'--net=host',
|
12
|
+
'--insecure-options=image',
|
13
|
+
'--volume',
|
14
|
+
"src,kind=host,source=#{@config[:target]}/src,readOnly=false",
|
15
|
+
'--mount',
|
16
|
+
"volume=src,target=#{@config[:src_path]}",
|
17
|
+
@config[:image],
|
18
|
+
'--working-dir',
|
19
|
+
@config[:src_path],
|
20
|
+
set_env,
|
21
|
+
'--exec',
|
22
|
+
@config[:command]
|
23
|
+
].flatten
|
24
|
+
|
25
|
+
log_info "RKT test command: #{cmd.join(' ')}"
|
26
|
+
|
27
|
+
execute_stream(*cmd, label: 'test')
|
28
|
+
|
29
|
+
end
|
30
|
+
|
31
|
+
private
|
32
|
+
|
33
|
+
def set_env
|
34
|
+
return [] if @config[:env].nil?
|
35
|
+
|
36
|
+
@config[:env].map {|k,v| "--set-env=#{k.upcase}=#{v}"}
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
require 'tinyci/executor'
|
2
|
+
|
3
|
+
module TinyCI
|
4
|
+
module Testers
|
5
|
+
class ScriptTester < TinyCI::Executor
|
6
|
+
def test
|
7
|
+
execute_stream(script_location, label: 'test', pwd: @config[:target])
|
8
|
+
end
|
9
|
+
|
10
|
+
private
|
11
|
+
|
12
|
+
def script_location
|
13
|
+
File.join @config[:target], @config[:command]
|
14
|
+
end
|
15
|
+
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
data/tinyci.gemspec
ADDED
@@ -0,0 +1,44 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'tinyci/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "tinyci"
|
8
|
+
spec.version = TinyCI::VERSION
|
9
|
+
spec.authors = ["Jonathan Davies"]
|
10
|
+
spec.email = ["jonnie@cleverna.me"]
|
11
|
+
|
12
|
+
desc = "A minimal Continuous Integration system, written in ruby, powered by git"
|
13
|
+
spec.summary = desc
|
14
|
+
spec.description = desc
|
15
|
+
spec.homepage = "https://github.com/JonnieCache/tinyci"
|
16
|
+
spec.license = "MIT"
|
17
|
+
|
18
|
+
# Prevent pushing this gem to RubyGems.org. To allow pushes either set the 'allowed_push_host'
|
19
|
+
# to allow pushing to a single host or delete this section to allow pushing to any host.
|
20
|
+
if spec.respond_to?(:metadata)
|
21
|
+
spec.metadata['allowed_push_host'] = "https://rubygems.org"
|
22
|
+
else
|
23
|
+
raise "RubyGems 2.0 or newer is required to protect against " \
|
24
|
+
"public gem pushes."
|
25
|
+
end
|
26
|
+
|
27
|
+
spec.files = `git ls-files -z`.split("\x0").reject do |f|
|
28
|
+
f.match(%r{^(test|spec|features)/})
|
29
|
+
end
|
30
|
+
spec.executables = ["tinyci"]
|
31
|
+
spec.require_paths = ["lib"]
|
32
|
+
|
33
|
+
LOGO = File.read(File.expand_path('lib/tinyci/logo.txt', __dir__))
|
34
|
+
|
35
|
+
spec.post_install_message = (LOGO % TinyCI::VERSION) + "\n"
|
36
|
+
|
37
|
+
spec.add_development_dependency "bundler", "~> 1.14"
|
38
|
+
spec.add_development_dependency 'awesome_print'
|
39
|
+
spec.add_development_dependency 'rspec'
|
40
|
+
spec.add_development_dependency 'barrier'
|
41
|
+
spec.add_development_dependency 'rake'
|
42
|
+
spec.add_development_dependency 'yard'
|
43
|
+
spec.add_development_dependency 'redcarpet'
|
44
|
+
end
|
metadata
ADDED
@@ -0,0 +1,179 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: tinyci
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Jonathan Davies
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2018-05-01 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bundler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.14'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.14'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: awesome_print
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rspec
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: barrier
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: rake
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ">="
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ">="
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: yard
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - ">="
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '0'
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - ">="
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '0'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: redcarpet
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - ">="
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '0'
|
104
|
+
type: :development
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - ">="
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '0'
|
111
|
+
description: A minimal Continuous Integration system, written in ruby, powered by
|
112
|
+
git
|
113
|
+
email:
|
114
|
+
- jonnie@cleverna.me
|
115
|
+
executables:
|
116
|
+
- tinyci
|
117
|
+
extensions: []
|
118
|
+
extra_rdoc_files: []
|
119
|
+
files:
|
120
|
+
- ".gitignore"
|
121
|
+
- ".rspec"
|
122
|
+
- ".ruby-version"
|
123
|
+
- ".yardopts"
|
124
|
+
- Gemfile
|
125
|
+
- Gemfile.lock
|
126
|
+
- Guardfile
|
127
|
+
- LICENSE
|
128
|
+
- README.md
|
129
|
+
- Rakefile
|
130
|
+
- bin/tinyci
|
131
|
+
- lib/pidfile.rb
|
132
|
+
- lib/tinyci/builders/rkt_builder.rb
|
133
|
+
- lib/tinyci/builders/script_builder.rb
|
134
|
+
- lib/tinyci/builders/test_builder.rb
|
135
|
+
- lib/tinyci/cli.rb
|
136
|
+
- lib/tinyci/config.rb
|
137
|
+
- lib/tinyci/executor.rb
|
138
|
+
- lib/tinyci/git_utils.rb
|
139
|
+
- lib/tinyci/installer.rb
|
140
|
+
- lib/tinyci/logging.rb
|
141
|
+
- lib/tinyci/logo.txt
|
142
|
+
- lib/tinyci/multi_logger.rb
|
143
|
+
- lib/tinyci/runner.rb
|
144
|
+
- lib/tinyci/scheduler.rb
|
145
|
+
- lib/tinyci/subprocesses.rb
|
146
|
+
- lib/tinyci/symbolize.rb
|
147
|
+
- lib/tinyci/testers/rkt_tester.rb
|
148
|
+
- lib/tinyci/testers/script_tester.rb
|
149
|
+
- lib/tinyci/testers/test_tester.rb
|
150
|
+
- lib/tinyci/version.rb
|
151
|
+
- tinyci.gemspec
|
152
|
+
homepage: https://github.com/JonnieCache/tinyci
|
153
|
+
licenses:
|
154
|
+
- MIT
|
155
|
+
metadata:
|
156
|
+
allowed_push_host: https://rubygems.org
|
157
|
+
post_install_message: " _____ _ _____ _____\n/__ (_)_ __ _ _ /
|
158
|
+
___/ /_ _/\n | || | '_ \\| | | |/ / / /\n | || | | | | |_| / /___/\\/ /_
|
159
|
+
\ \n |_||_|_| |_|\\__, \\____/\\____/ 0.1.0\n |___/\n\n"
|
160
|
+
rdoc_options: []
|
161
|
+
require_paths:
|
162
|
+
- lib
|
163
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
164
|
+
requirements:
|
165
|
+
- - ">="
|
166
|
+
- !ruby/object:Gem::Version
|
167
|
+
version: '0'
|
168
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
169
|
+
requirements:
|
170
|
+
- - ">="
|
171
|
+
- !ruby/object:Gem::Version
|
172
|
+
version: '0'
|
173
|
+
requirements: []
|
174
|
+
rubyforge_project:
|
175
|
+
rubygems_version: 2.6.13
|
176
|
+
signing_key:
|
177
|
+
specification_version: 4
|
178
|
+
summary: A minimal Continuous Integration system, written in ruby, powered by git
|
179
|
+
test_files: []
|