tinyci 0.4 → 0.5.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +2 -2
- data/.rspec +2 -0
- data/.rubocop.yml +17 -2
- data/.ruby-version +1 -1
- data/.tinyci.yml +3 -1
- data/.yardopts +1 -0
- data/CHANGELOG.md +5 -0
- data/Dockerfile +3 -2
- data/Gemfile +2 -1
- data/Gemfile.lock +67 -39
- data/Guardfile +5 -3
- data/Rakefile +3 -1
- data/bin/tinyci +3 -2
- data/lib/pidfile.rb +28 -39
- data/lib/tinyci/builders/script_builder.rb +2 -0
- data/lib/tinyci/builders/test_builder.rb +3 -1
- data/lib/tinyci/cli.rb +159 -78
- data/lib/tinyci/cli_ssh_delegator.rb +111 -0
- data/lib/tinyci/compactor.rb +26 -26
- data/lib/tinyci/config.rb +22 -23
- data/lib/tinyci/config_transformer.rb +14 -16
- data/lib/tinyci/executor.rb +14 -12
- data/lib/tinyci/git_utils.rb +87 -18
- data/lib/tinyci/hookers/script_hooker.rb +26 -27
- data/lib/tinyci/installer.rb +28 -21
- data/lib/tinyci/log_viewer.rb +87 -0
- data/lib/tinyci/logging.rb +5 -5
- data/lib/tinyci/multi_logger.rb +30 -21
- data/lib/tinyci/path_utils.rb +44 -0
- data/lib/tinyci/runner.rb +95 -78
- data/lib/tinyci/scheduler.rb +44 -42
- data/lib/tinyci/subprocesses.rb +41 -32
- data/lib/tinyci/symbolize.rb +3 -1
- data/lib/tinyci/testers/script_tester.rb +2 -0
- data/lib/tinyci/testers/test_tester.rb +2 -0
- data/lib/tinyci/version.rb +3 -1
- data/lib/yard_plugin.rb +9 -1
- data/tinyci.gemspec +30 -22
- metadata +106 -19
data/lib/tinyci/runner.rb
CHANGED
@@ -1,5 +1,8 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'tinyci/subprocesses'
|
2
4
|
require 'tinyci/git_utils'
|
5
|
+
require 'tinyci/path_utils'
|
3
6
|
require 'tinyci/logging'
|
4
7
|
require 'tinyci/config'
|
5
8
|
|
@@ -14,178 +17,191 @@ require 'fileutils'
|
|
14
17
|
|
15
18
|
module TinyCI
|
16
19
|
# Responsible for managing the running of TinyCI against a single git object.
|
17
|
-
#
|
18
|
-
# @attr builder [TinyCI::Executor] Returns the Builder object. Used solely for testing
|
19
|
-
# @attr tester [TinyCI::Executor] Returns the Tester object. Used solely for testing
|
20
|
+
#
|
21
|
+
# @attr builder [TinyCI::Executor] Returns the Builder object. Used solely for testing.
|
22
|
+
# @attr tester [TinyCI::Executor] Returns the Tester object. Used solely for testing.
|
20
23
|
class Runner
|
21
24
|
include Subprocesses
|
22
25
|
include GitUtils
|
26
|
+
include PathUtils
|
23
27
|
include Logging
|
24
|
-
|
28
|
+
|
29
|
+
CONFIG_FILENAME = '.tinyci.yml'
|
30
|
+
|
25
31
|
attr_accessor :builder, :tester, :hooker
|
26
|
-
|
32
|
+
|
27
33
|
# Constructor, allows injection of generic configuration params.
|
28
|
-
#
|
34
|
+
#
|
29
35
|
# @param working_dir [String] The working directory to execute against.
|
30
36
|
# @param commit [String] SHA1 of git object to run against
|
31
37
|
# @param logger [Logger] Logger object
|
32
|
-
# @param time [Time] Override time of object creation. Used solely for testing
|
33
|
-
# @param config [Hash] Override TinyCI config object, normally loaded from `.tinyci` file.
|
38
|
+
# @param time [Time] Override time of object creation. Used solely for testing.
|
39
|
+
# @param config [Hash] Override TinyCI config object, normally loaded from `.tinyci` file.
|
40
|
+
# Used solely for testing.
|
34
41
|
def initialize(working_dir: '.', commit:, time: nil, logger: nil, config: nil)
|
35
42
|
@working_dir = working_dir
|
36
|
-
@logger = logger
|
37
43
|
@config = config
|
38
44
|
@commit = commit
|
39
|
-
@time = time
|
45
|
+
@time = time
|
46
|
+
@logger = logger.is_a?(MultiLogger) ? MultiLogger.new(quiet: logger.quiet) : nil
|
47
|
+
ensure_path target_path
|
48
|
+
setup_log
|
40
49
|
end
|
41
|
-
|
50
|
+
|
42
51
|
# Runs the TinyCI system against the single git object referenced in `@commit`.
|
43
|
-
#
|
52
|
+
#
|
44
53
|
# @return [Boolean] `true` if the commit was built and tested successfully, `false` otherwise
|
54
|
+
# rubocop:disable Metrics/AbcSize, Metrics/PerceivedComplexity, Metrics/MethodLength, Metrics/CyclomaticComplexity
|
45
55
|
def run!
|
46
56
|
begin
|
47
|
-
ensure_path target_path
|
48
|
-
setup_log
|
49
|
-
|
50
57
|
log_info "Commit: #{@commit}"
|
51
|
-
|
52
|
-
|
58
|
+
|
59
|
+
unless config_exists?
|
60
|
+
log_error "No config found for #{@commit}"
|
61
|
+
|
62
|
+
return false
|
63
|
+
end
|
64
|
+
|
65
|
+
log_info 'Cleaning...'
|
53
66
|
clean
|
54
|
-
|
55
|
-
log_info
|
67
|
+
|
68
|
+
log_info 'Exporting...'
|
56
69
|
ensure_path export_path
|
57
70
|
export
|
58
|
-
|
71
|
+
|
59
72
|
begin
|
60
|
-
|
73
|
+
config
|
61
74
|
rescue ConfigMissingError => e
|
62
75
|
log_error e.message
|
63
76
|
log_error 'Removing export...'
|
64
77
|
clean
|
65
|
-
|
78
|
+
|
66
79
|
return false
|
67
80
|
end
|
68
81
|
@builder ||= instantiate_builder
|
69
82
|
@tester ||= instantiate_tester
|
70
83
|
@hooker ||= instantiate_hooker
|
71
|
-
|
72
|
-
log_info
|
84
|
+
|
85
|
+
log_info 'Building...'
|
73
86
|
run_hook! :before_build
|
74
87
|
begin
|
75
88
|
@builder.build
|
76
|
-
rescue => e
|
89
|
+
rescue StandardError => e
|
77
90
|
run_hook! :after_build_failure
|
78
|
-
|
91
|
+
|
79
92
|
raise e if ENV['TINYCI_ENV'] == 'test'
|
80
|
-
|
93
|
+
|
81
94
|
log_error e
|
82
95
|
log_debug e.backtrace
|
83
|
-
|
96
|
+
|
84
97
|
return false
|
85
98
|
else
|
86
99
|
run_hook! :after_build_success
|
87
100
|
ensure
|
88
101
|
run_hook! :after_build
|
89
102
|
end
|
90
|
-
|
91
|
-
|
92
|
-
log_info "Testing..."
|
103
|
+
|
104
|
+
log_info 'Testing...'
|
93
105
|
run_hook! :before_test
|
94
106
|
begin
|
95
107
|
@tester.test
|
96
|
-
rescue => e
|
108
|
+
rescue StandardError => e
|
97
109
|
run_hook! :after_test_failure
|
98
|
-
|
110
|
+
|
99
111
|
raise e if ENV['TINYCI_ENV'] == 'test'
|
100
|
-
|
112
|
+
|
101
113
|
log_error e
|
102
114
|
log_debug e.backtrace
|
103
|
-
|
115
|
+
|
104
116
|
return false
|
105
117
|
else
|
106
118
|
run_hook! :after_test_success
|
107
119
|
ensure
|
108
120
|
run_hook! :after_test
|
109
121
|
end
|
110
|
-
|
122
|
+
|
111
123
|
log_info "Finished #{@commit}"
|
112
|
-
rescue => e
|
124
|
+
rescue StandardError => e
|
113
125
|
raise e if ENV['TINYCI_ENV'] == 'test'
|
114
|
-
|
126
|
+
|
115
127
|
log_error e
|
116
128
|
log_debug e.backtrace
|
117
129
|
return false
|
118
130
|
ensure
|
119
131
|
run_hook! :after_all
|
120
132
|
end
|
121
|
-
|
133
|
+
|
122
134
|
true
|
123
135
|
end
|
124
|
-
|
125
|
-
|
126
|
-
def target_path
|
127
|
-
File.absolute_path("#{@working_dir}/builds/#{@time.to_i}_#{@commit}/")
|
128
|
-
end
|
129
|
-
|
130
|
-
# Build the export path
|
131
|
-
def export_path
|
132
|
-
File.join(target_path, 'export')
|
133
|
-
end
|
134
|
-
|
136
|
+
# rubocop:enable Metrics/AbcSize, Metrics/PerceivedComplexity, Metrics/MethodLength, Metrics/CyclomaticComplexity
|
137
|
+
|
135
138
|
private
|
136
|
-
|
139
|
+
|
137
140
|
def run_hook!(name)
|
138
141
|
return unless @hooker
|
139
|
-
|
142
|
+
|
140
143
|
@hooker.send("#{name}!")
|
141
144
|
end
|
142
|
-
|
145
|
+
|
143
146
|
# Creates log file if it doesnt exist
|
144
147
|
def setup_log
|
145
148
|
return unless @logger.is_a? MultiLogger
|
146
|
-
|
147
|
-
@logger.
|
148
|
-
|
149
|
-
|
150
|
-
def logfile_path
|
151
|
-
File.join(target_path, 'tinyci.log')
|
149
|
+
|
150
|
+
@logger.add_output_path logfile_path
|
151
|
+
@logger.add_output_path repo_logfile_path
|
152
152
|
end
|
153
|
-
|
153
|
+
|
154
154
|
# Instantiate the Builder object according to the class named in the config
|
155
155
|
def instantiate_builder
|
156
156
|
klass = TinyCI::Builders.const_get(@config[:builder][:class])
|
157
|
-
|
157
|
+
konfig = @config[:builder][:config].merge(
|
158
|
+
target: target_path,
|
159
|
+
export: export_path,
|
160
|
+
commit: @commit,
|
161
|
+
logger: @logger
|
162
|
+
)
|
163
|
+
klass.new(konfig)
|
158
164
|
end
|
159
|
-
|
165
|
+
|
160
166
|
# Instantiate the Tester object according to the class named in the config
|
161
167
|
def instantiate_tester
|
162
168
|
klass = TinyCI::Testers.const_get(@config[:tester][:class])
|
163
|
-
|
169
|
+
konfig = @config[:tester][:config].merge(
|
170
|
+
target: target_path,
|
171
|
+
export: export_path,
|
172
|
+
commit: @commit,
|
173
|
+
logger: @logger
|
174
|
+
)
|
175
|
+
klass.new(konfig)
|
164
176
|
end
|
165
|
-
|
177
|
+
|
166
178
|
# Instantiate the Hooker object according to the class named in the config
|
167
179
|
def instantiate_hooker
|
168
180
|
return nil unless @config[:hooker].is_a? Hash
|
169
|
-
|
181
|
+
|
170
182
|
klass = TinyCI::Hookers.const_get(@config[:hooker][:class])
|
171
|
-
|
183
|
+
konfig = @config[:hooker][:config].merge(
|
184
|
+
target: target_path,
|
185
|
+
export: export_path,
|
186
|
+
commit: @commit,
|
187
|
+
logger: @logger
|
188
|
+
)
|
189
|
+
klass.new(konfig)
|
172
190
|
end
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
@config ||= Config.new(working_dir: export_path)
|
191
|
+
|
192
|
+
def config_path
|
193
|
+
File.expand_path(CONFIG_FILENAME, export_path)
|
177
194
|
end
|
178
195
|
|
179
|
-
|
180
|
-
|
181
|
-
Time.at execute(git_cmd('show', '-s', '--format=%ct', @commit)).to_i
|
196
|
+
def config_exists?
|
197
|
+
file_exists_in_git? CONFIG_FILENAME
|
182
198
|
end
|
183
199
|
|
184
|
-
#
|
185
|
-
def
|
186
|
-
|
200
|
+
# The {Config} object from the `.tinyci.yml` file in the exported directory
|
201
|
+
def config
|
202
|
+
@config ||= Config.new(config_path)
|
187
203
|
end
|
188
|
-
|
204
|
+
|
189
205
|
# Delete the export path
|
190
206
|
def clean
|
191
207
|
FileUtils.rm_rf export_path
|
@@ -196,7 +212,8 @@ module TinyCI
|
|
196
212
|
# a `git export` subcommand.
|
197
213
|
# see https://stackoverflow.com/a/163769
|
198
214
|
def export
|
199
|
-
execute_pipe git_cmd('archive', '--format=tar',
|
215
|
+
execute_pipe git_cmd('archive', '--format=tar',
|
216
|
+
@commit), ['tar', '-C', export_path, '-xf', '-']
|
200
217
|
end
|
201
218
|
end
|
202
219
|
end
|
data/lib/tinyci/scheduler.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'tinyci/runner'
|
2
4
|
require 'tinyci/subprocesses'
|
3
5
|
require 'tinyci/git_utils'
|
@@ -7,82 +9,82 @@ module TinyCI
|
|
7
9
|
# Manages the execution of test jobs. Responsible for deciding which
|
8
10
|
# commits need to be built and tested. Also manages the pidfile. This
|
9
11
|
# is the main entrypoint for TinyCI.
|
10
|
-
#
|
12
|
+
#
|
11
13
|
# @attr_reader [String] working_dir The working directory to execute against
|
12
14
|
class Scheduler
|
13
15
|
include Subprocesses
|
14
16
|
include Logging
|
15
17
|
include GitUtils
|
16
|
-
|
18
|
+
|
17
19
|
attr_reader :working_dir
|
18
|
-
|
20
|
+
|
19
21
|
# Constructor, allows injection of configuration and custom {Runner} class.
|
20
22
|
# Config params are passed to {Runner} instances.
|
21
|
-
#
|
23
|
+
#
|
22
24
|
# @param working_dir [String] The working directory to execute against
|
23
25
|
# @param logger [Logger] Logger object
|
24
26
|
# @param commit [String] specific git object to run against
|
25
27
|
# @param runner_class [TinyCI::Runner] Injection of {Runner} dependency
|
26
28
|
def initialize(
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
29
|
+
working_dir: nil,
|
30
|
+
logger: nil,
|
31
|
+
commit: nil,
|
32
|
+
runner_class: Runner
|
33
|
+
)
|
34
|
+
|
33
35
|
@working_dir = working_dir || repo_root
|
34
36
|
@logger = logger
|
35
37
|
@runner_class = runner_class
|
36
38
|
@commit = commit
|
37
39
|
end
|
38
|
-
|
40
|
+
|
39
41
|
# Runs the TinyCI system against the relevant commits. Also sets up the pidfile.
|
40
|
-
#
|
42
|
+
#
|
41
43
|
# @return [Boolean] `true` if all commits built and tested successfully, `false` otherwise
|
42
44
|
def run!
|
43
45
|
pid = PidFile.new(pidfile: 'tinyci.pid', piddir: @working_dir)
|
44
|
-
|
46
|
+
|
45
47
|
result = if @commit
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
48
|
+
run_commit get_commit @commit
|
49
|
+
else
|
50
|
+
run_all_commits
|
51
|
+
end
|
52
|
+
|
51
53
|
pid.release
|
52
|
-
|
54
|
+
|
53
55
|
result
|
54
56
|
end
|
55
|
-
|
57
|
+
|
56
58
|
private
|
57
|
-
|
59
|
+
|
58
60
|
# Git objects to be executed against, all those without a tinyci tag
|
59
|
-
#
|
61
|
+
#
|
60
62
|
# @return [Array<String>] the sha1 hashes in reverse order of creation time
|
61
|
-
def
|
63
|
+
def retrieve_commits
|
62
64
|
log = execute(git_cmd('log', '--notes=tinyci*', '--format=%H %ct %N§§§', '--reverse'))
|
63
|
-
lines = log.split(
|
64
|
-
|
65
|
-
lines.map {|l| format_commit_data(l)}.select {|c| c[:result].nil?}
|
65
|
+
lines = log.split('§§§')
|
66
|
+
|
67
|
+
lines.map { |l| format_commit_data(l) }.select { |c| c[:result].nil? }
|
66
68
|
end
|
67
|
-
|
69
|
+
|
68
70
|
def get_commit(sha)
|
69
|
-
data = execute(git_cmd('show', '--quiet', '--notes=tinyci*',
|
70
|
-
|
71
|
+
data = execute(git_cmd('show', '--quiet', '--notes=tinyci*', '--format=%H %ct', sha))
|
72
|
+
|
71
73
|
format_commit_data(data)
|
72
74
|
end
|
73
|
-
|
75
|
+
|
74
76
|
# Instantiates {Runner} for a given git object, runs it, and stores the result
|
75
77
|
def run_commit(commit)
|
76
78
|
result = @runner_class.new(
|
77
|
-
working_dir: @working_dir,
|
79
|
+
working_dir: @working_dir,
|
78
80
|
commit: commit[:sha],
|
79
81
|
time: commit[:time],
|
80
82
|
logger: @logger
|
81
83
|
).run!
|
82
|
-
|
84
|
+
|
83
85
|
set_result(commit, result)
|
84
86
|
end
|
85
|
-
|
87
|
+
|
86
88
|
def format_commit_data(data)
|
87
89
|
parts = data.split(' ')
|
88
90
|
{
|
@@ -91,22 +93,22 @@ module TinyCI
|
|
91
93
|
result: parts[2]
|
92
94
|
}
|
93
95
|
end
|
94
|
-
|
96
|
+
|
95
97
|
# Repeatedly gets the list of eligable commits and runs TinyCI against them until there are no more remaining
|
96
98
|
def run_all_commits
|
97
|
-
commits =
|
98
|
-
|
99
|
-
until commits.empty?
|
100
|
-
commits.each {|c| run_commit(c)}
|
101
|
-
|
102
|
-
commits =
|
99
|
+
commits = retrieve_commits
|
100
|
+
|
101
|
+
until commits.empty?
|
102
|
+
commits.each { |c| run_commit(c) }
|
103
|
+
|
104
|
+
commits = retrieve_commits
|
103
105
|
end
|
104
106
|
end
|
105
|
-
|
107
|
+
|
106
108
|
# Stores the result in a git note
|
107
109
|
def set_result(commit, result)
|
108
110
|
result_message = result ? 'success' : 'failure'
|
109
|
-
|
111
|
+
|
110
112
|
execute git_cmd('notes', '--ref', 'tinyci-result', 'add', '-m', result_message, commit[:sha])
|
111
113
|
end
|
112
114
|
end
|
data/lib/tinyci/subprocesses.rb
CHANGED
@@ -1,44 +1,48 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'open3'
|
4
|
+
require 'English'
|
2
5
|
require 'tinyci/logging'
|
3
6
|
|
4
7
|
module TinyCI
|
5
8
|
# Methods for executing subprocesses in various ways and collecting the results.
|
6
9
|
module Subprocesses
|
7
|
-
|
8
10
|
# Synchronously execute a command as a subprocess and return the output.
|
9
|
-
#
|
11
|
+
#
|
10
12
|
# @param [Array<String>] command The command line
|
11
13
|
# @param [String] label A label for debug and logging purposes
|
12
|
-
#
|
14
|
+
#
|
13
15
|
# @return [String] The output of the command
|
14
16
|
# @raise [SubprocessError] if the subprocess returns status > 0
|
15
17
|
def execute(*command, label: nil)
|
16
|
-
|
17
|
-
|
18
|
+
stdout, stderr, status = Open3.capture3(*command.flatten)
|
19
|
+
|
18
20
|
log_debug caller[0]
|
19
21
|
log_debug "CMD: #{command.join(' ')}"
|
20
|
-
log_debug "OUT: #{
|
21
|
-
|
22
|
+
log_debug "OUT: #{stdout}"
|
23
|
+
log_debug "ERR: #{stderr}"
|
24
|
+
|
22
25
|
unless status.success?
|
23
|
-
log_error
|
26
|
+
log_error stdout
|
27
|
+
log_error stderr
|
24
28
|
raise SubprocessError.new(label, command.join(' '), status)
|
25
29
|
end
|
26
|
-
|
27
|
-
|
30
|
+
|
31
|
+
stdout.chomp
|
28
32
|
end
|
29
|
-
|
33
|
+
|
30
34
|
# Synchronously execute a chain multiple commands piped into each other as a
|
31
35
|
# subprocess and return the output.
|
32
|
-
#
|
36
|
+
#
|
33
37
|
# @param [Array<Array<String>>] commands The command lines
|
34
38
|
# @param [String] label A label for debug and logging purposes
|
35
|
-
#
|
39
|
+
#
|
36
40
|
# @return [String] The output of the command
|
37
41
|
# @raise [SubprocessError] if the subprocess returns status > 0
|
38
42
|
def execute_pipe(*commands, label: nil)
|
39
43
|
stdout, waiters = Open3.pipeline_r(*commands)
|
40
44
|
output = stdout.read
|
41
|
-
|
45
|
+
|
42
46
|
waiters.each_with_index do |waiter, i|
|
43
47
|
status = waiter.value
|
44
48
|
unless status.success?
|
@@ -46,67 +50,72 @@ module TinyCI
|
|
46
50
|
raise SubprocessError.new(label, commands[i].join(' '), status)
|
47
51
|
end
|
48
52
|
end
|
49
|
-
|
53
|
+
|
50
54
|
output.chomp
|
51
55
|
end
|
52
|
-
|
56
|
+
|
53
57
|
# Synchronously execute a command as a subprocess and and stream the output
|
54
58
|
# to `STDOUT`
|
55
|
-
#
|
59
|
+
#
|
56
60
|
# @param [Array<String>] command The command line
|
57
61
|
# @param [String] label A label for debug and logging purposes
|
58
62
|
# @param [String] pwd Optionally specify a different working directory in which to execute the command
|
59
|
-
#
|
63
|
+
#
|
60
64
|
# @return [TrueClass] `true` if the command executed successfully
|
61
65
|
# @raise [SubprocessError] if the subprocess returns status > 0
|
62
66
|
def execute_stream(*command, label: nil, pwd: nil)
|
63
67
|
opts = {}
|
64
68
|
opts[:chdir] = pwd unless pwd.nil?
|
65
|
-
|
69
|
+
|
66
70
|
log_debug "CMD: #{command.join(' ')}"
|
67
|
-
|
71
|
+
|
68
72
|
Open3.popen2e(command.join(' '), opts) do |stdin, stdout_and_stderr, wait_thr|
|
69
73
|
stdin.close
|
70
|
-
|
74
|
+
|
71
75
|
until stdout_and_stderr.closed? || stdout_and_stderr.eof?
|
72
76
|
line = stdout_and_stderr.gets
|
73
77
|
log_info line.chomp
|
74
78
|
$stdout.flush
|
75
79
|
end
|
76
|
-
|
77
|
-
unless wait_thr.value.success?
|
80
|
+
|
81
|
+
unless wait_thr.value.success?
|
78
82
|
raise SubprocessError.new(label, command.join(' '), wait_thr.value)
|
79
83
|
end
|
84
|
+
|
85
|
+
ensure
|
80
86
|
stdout_and_stderr.close
|
81
87
|
end
|
82
|
-
|
88
|
+
|
83
89
|
true
|
84
90
|
end
|
85
|
-
|
91
|
+
|
92
|
+
def execute_and_return_status(command)
|
93
|
+
system(*command, out: File::NULL, err: File::NULL)
|
94
|
+
|
95
|
+
$CHILD_STATUS
|
96
|
+
end
|
97
|
+
|
86
98
|
# An error raised when any of the {Subprocesses} methods fail
|
87
|
-
#
|
99
|
+
#
|
88
100
|
# @attr_reader [Integer] status The return code of the process
|
89
101
|
# @attr_reader [String] command The command used to spawn the process
|
90
102
|
class SubprocessError < RuntimeError
|
91
103
|
attr_reader :status
|
92
104
|
attr_reader :command
|
93
|
-
|
105
|
+
|
94
106
|
def initialize(label, command, status, message = "#{label}: `#{command}` failed with status #{status.exitstatus}")
|
95
107
|
@status = status
|
96
108
|
@command = command
|
97
109
|
super(message)
|
98
110
|
end
|
99
111
|
end
|
100
|
-
|
101
|
-
private
|
102
|
-
|
112
|
+
|
103
113
|
def self.included(base)
|
104
114
|
base.include TinyCI::Logging
|
105
115
|
end
|
106
|
-
|
116
|
+
|
107
117
|
def self.extended(base)
|
108
118
|
base.extend TinyCI::Logging
|
109
119
|
end
|
110
|
-
|
111
120
|
end
|
112
121
|
end
|
data/lib/tinyci/symbolize.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module TinyCI
|
2
4
|
module Symbolize
|
3
5
|
# recursively make all keys of `hash` into symbols
|
@@ -7,7 +9,7 @@ module TinyCI
|
|
7
9
|
hash.each { |key, value| h[key.to_sym] = map_value(value) }
|
8
10
|
end
|
9
11
|
end
|
10
|
-
|
12
|
+
|
11
13
|
def map_value(thing)
|
12
14
|
case thing
|
13
15
|
when Hash
|
data/lib/tinyci/version.rb
CHANGED
data/lib/yard_plugin.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'redcarpet'
|
2
4
|
|
3
5
|
# This file fixes the mismatch between how github handles links to other
|
@@ -27,7 +29,13 @@ class CompatMarkdown
|
|
27
29
|
|
28
30
|
def initialize(text)
|
29
31
|
renderer = YARD::Templates::Helpers::HtmlHelper::MDLinkRenderer.new
|
30
|
-
|
32
|
+
opts = {
|
33
|
+
no_intra_emphasis: true,
|
34
|
+
gh_blockcode: true,
|
35
|
+
fenced_code_blocks: true,
|
36
|
+
autolink: true
|
37
|
+
}
|
38
|
+
markdown = Redcarpet::Markdown.new(renderer, opts)
|
31
39
|
@to_html = markdown.render(text)
|
32
40
|
end
|
33
41
|
end
|