tinyci 0.4 → 0.5.1
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 +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
|