git-restart 0.0.14.pre.dev → 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/bin/git-restart +2 -2
- data/lib/git-restart/runner.rb +44 -4
- data/lib/git-restart/task.rb +109 -6
- metadata +5 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 89f6a4a1fa9ad535f9a80f69fc2729e28fa4c077
|
4
|
+
data.tar.gz: '09e3329d30be30ea60511e894dc0f1e0ba44375b'
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e46803d3834a7fec3c2166f8864d45b746de31b0ca9d6e87c839ab806a4b5943ff822739ef209d447d7e45aa4a88d8dd77b812b478f7ac8d042b1a08983965e8
|
7
|
+
data.tar.gz: 6e883c22e0dd8b1ee5c09a2c51a193d67ff82c2abcdbc33f3ed1232bdf73d3373b8835365d1a248b242b985e0eae30226f1d008a9375318aefc43e2bc0b134a6
|
data/bin/git-restart
CHANGED
data/lib/git-restart/runner.rb
CHANGED
@@ -8,23 +8,41 @@ require_relative "task.rb"
|
|
8
8
|
|
9
9
|
module GitRestart
|
10
10
|
class Runner
|
11
|
+
# Sets a name for this Runner, used for reporting to GitHub
|
11
12
|
attr_accessor :name
|
12
13
|
|
13
|
-
|
14
|
+
# Which repository to listen to. Uses "Owner/Repo" syntax.
|
15
|
+
attr_accessor :repo
|
16
|
+
# A white- and blacklist of branches. If neither are specified, all are used.
|
17
|
+
# If the whitelist is used, only it is considered.
|
18
|
+
attr_accessor :branches, :exclude_branches
|
19
|
+
# Which branch to start on.
|
20
|
+
# This not only makes the system switch branch, but it will also execute
|
21
|
+
# ALL active tasks. Very useful for auto-updating servers.
|
22
|
+
attr_accessor :start_on
|
23
|
+
# A list of tasks that this Runner will actually look at.
|
24
|
+
# If nil, all tasks are allowed.
|
14
25
|
attr_accessor :allowed_tasks
|
15
26
|
|
16
27
|
attr_reader :next_tasks
|
17
28
|
attr_reader :current_task_file
|
18
29
|
|
30
|
+
# The MQTT::SubHandler to use to listen to GitHub updates.
|
31
|
+
# Can be specified as either MQTT::SubHandler class or String, the latter
|
32
|
+
# will be interpreted as URI
|
19
33
|
attr_reader :mqtt
|
34
|
+
# Octokit to use for optional status reporting
|
20
35
|
attr_accessor :octokit
|
21
36
|
|
37
|
+
# @return [String] Full SHA of the current commit
|
22
38
|
def current_commit()
|
23
39
|
@git.object("HEAD").sha;
|
24
40
|
end
|
41
|
+
# @return [String] Name of the current branch
|
25
42
|
def current_branch()
|
26
43
|
@git.current_branch();
|
27
44
|
end
|
45
|
+
# @return [Array<String>] A list of all files that were modified in the commit we are checking
|
28
46
|
def current_modified()
|
29
47
|
@current_modified;
|
30
48
|
end
|
@@ -77,20 +95,24 @@ module GitRestart
|
|
77
95
|
}
|
78
96
|
end
|
79
97
|
|
98
|
+
# Update the GitHub status for the task of given name, with optional status message
|
99
|
+
# Only prints a line if no octokit is specified
|
80
100
|
def update_status(name, newStatus, message = nil)
|
81
|
-
puts "Task #{
|
101
|
+
puts "Task #{name} assumed a new status: #{newStatus}#{message ? " MSG:#{message}" : ""}"
|
82
102
|
|
83
103
|
return unless @octokit;
|
84
104
|
|
85
105
|
begin
|
86
106
|
@octokit.create_status(@repo, current_commit(), newStatus, {
|
87
|
-
context: "#{
|
107
|
+
context: "#{name}/#{name}".gsub(" ", "_"),
|
88
108
|
description: message,
|
89
109
|
})
|
90
110
|
rescue
|
91
111
|
end
|
92
112
|
end
|
93
113
|
|
114
|
+
# Start the task responsible for queueing and executing the individual
|
115
|
+
# task stop, branch switch, task start cycles
|
94
116
|
def _start_task_thread()
|
95
117
|
@taskThread = Thread.new do
|
96
118
|
loop do
|
@@ -101,7 +123,9 @@ module GitRestart
|
|
101
123
|
end
|
102
124
|
end.abort_on_exception = true;
|
103
125
|
end
|
126
|
+
private :_start_task_thread
|
104
127
|
|
128
|
+
# Stop all tasks of the given hash, not list. Waits for them to stop.
|
105
129
|
def _stop_tasks(taskList)
|
106
130
|
taskList.each do |name, t|
|
107
131
|
t.stop();
|
@@ -111,19 +135,27 @@ module GitRestart
|
|
111
135
|
@current_tasks.delete(name);
|
112
136
|
end
|
113
137
|
end
|
138
|
+
private :_stop_tasks
|
114
139
|
def _stop_all_tasks()
|
115
140
|
_stop_tasks(@current_tasks);
|
116
141
|
end
|
142
|
+
private :_stop_all_tasks
|
143
|
+
# Stop all tasks that have marked themselves as affected by the
|
144
|
+
# current set of file-changes. This way, applications are only
|
145
|
+
# restarted when their own files have been altered.
|
117
146
|
def _stop_triggered_tasks()
|
118
147
|
_stop_tasks(@current_tasks.select {|k,v| v.triggered?});
|
119
148
|
end
|
149
|
+
private :_stop_triggered_tasks
|
120
150
|
|
151
|
+
# Scan through the file-tree for .gittask files, or use the @allowed_tasks
|
152
|
+
# list of tasks.
|
121
153
|
def _generate_next_tasks()
|
122
154
|
puts "Generating new tasks..."
|
123
155
|
@next_tasks = Hash.new();
|
124
156
|
|
125
157
|
taskFiles = `find ./ -nowarn -iname "*.gittask"`
|
126
|
-
taskFiles.split("\n").each do |t|
|
158
|
+
[taskFiles.split("\n"), @allowed_tasks].flatten.each do |t|
|
127
159
|
puts "Looking at: #{t}"
|
128
160
|
t.gsub!(/^\.\//,"");
|
129
161
|
@current_task_file = t;
|
@@ -145,7 +177,10 @@ module GitRestart
|
|
145
177
|
|
146
178
|
puts "Finished loading! Next tasks: #{@next_tasks.keys}"
|
147
179
|
end
|
180
|
+
private :_generate_next_tasks
|
148
181
|
|
182
|
+
# Start all new tasks that have marked themselves as affected by the current
|
183
|
+
# set of filechanges
|
149
184
|
def _start_next_tasks()
|
150
185
|
_generate_next_tasks();
|
151
186
|
|
@@ -158,7 +193,10 @@ module GitRestart
|
|
158
193
|
@current_tasks[name] = t;
|
159
194
|
end
|
160
195
|
end
|
196
|
+
private :_start_next_tasks
|
161
197
|
|
198
|
+
# Perform an entire cycle of git fetch & checkout, stop tasks, pull, restart.
|
199
|
+
# *CAUTION* A HARD RESET IS USED HERE
|
162
200
|
def _switch_to(branch, commit = nil)
|
163
201
|
puts "\n\nSwitching to branch: #{branch}#{commit ? ",commit: #{commit}" : ""}"
|
164
202
|
|
@@ -180,11 +218,13 @@ module GitRestart
|
|
180
218
|
|
181
219
|
_start_next_tasks();
|
182
220
|
end
|
221
|
+
private :_switch_to
|
183
222
|
|
184
223
|
def autostart()
|
185
224
|
return unless @start_on;
|
186
225
|
@branchQueue << {branch: @start_on};
|
187
226
|
end
|
227
|
+
private :autostart
|
188
228
|
|
189
229
|
def mqtt=(mqtt)
|
190
230
|
if(mqtt.is_a? String)
|
data/lib/git-restart/task.rb
CHANGED
@@ -1,39 +1,82 @@
|
|
1
1
|
|
2
|
+
# @author Xasin
|
2
3
|
module GitRestart
|
4
|
+
# The Error-Class used to signal when a Task is set up wrong
|
3
5
|
class TaskValidityError < StandardError
|
4
6
|
end
|
5
7
|
|
8
|
+
# This class is used to define "Tasks". Each task represents
|
9
|
+
# a set of commands, which it executes in chronological order, or until
|
10
|
+
# a task errors.
|
11
|
+
# Additionally, it will kill execution of tasks with a specified kill-signal
|
12
|
+
# when an update was detected from GitHub.
|
13
|
+
# The failure-status of the tasks can also be reported via Octokit, allowing this
|
14
|
+
# to be used as a simple CI or Test system for various languages.
|
6
15
|
class Task
|
16
|
+
# The array of tasks to execute. Each target will be executed in the given
|
17
|
+
# order via `Process.spawn`.
|
18
|
+
# @return [Array<String>]
|
7
19
|
attr_reader :targets
|
8
20
|
|
21
|
+
# The signal (as String, like Signal.list) to use to kill the process.
|
22
|
+
# Can be nil to disable killing
|
9
23
|
attr_accessor :signal
|
24
|
+
# Whether or not to report failure if the currently running target
|
25
|
+
# has a non-zero exit status after having been killed. Only makes sense
|
26
|
+
# together with report_status
|
10
27
|
attr_accessor :expect_clean_exit
|
28
|
+
# Whether or not to report failure/success status to GitHub using Octokit
|
11
29
|
attr_accessor :report_status
|
30
|
+
# Defines this as a "CI_Task". Such a task will always run on an update,
|
31
|
+
# regardless what files changed. Useful if you always want a status report
|
32
|
+
# on GitHub.
|
12
33
|
attr_accessor :ci_task
|
13
|
-
|
14
|
-
|
34
|
+
# Name of the Task. *Required*. Used as *unique* ID, and to report status to GitHub
|
35
|
+
attr_accessor :name
|
36
|
+
# The file to use to retrieve a single-line status info for the "description"
|
37
|
+
# string of the GitHub status. Only the last *non-indented* line is used,
|
38
|
+
# which allows the output of Minitest to be used directly.
|
39
|
+
attr_accessor :status_file
|
40
|
+
|
41
|
+
# Whether or not this task is active. Usually set via #on_branches,
|
42
|
+
# but can be used to manually disable or enable this task based on
|
43
|
+
# config files, ENV variables etc.
|
15
44
|
attr_accessor :active
|
16
45
|
|
46
|
+
# The last status-code of this Task. Used internally.
|
17
47
|
attr_reader :lastStatus
|
48
|
+
# The last status-message of this task. Used internally.
|
18
49
|
attr_reader :status_message
|
19
50
|
|
51
|
+
# @api private
|
20
52
|
def self.runner=(runner)
|
21
53
|
@runner = runner;
|
22
54
|
end
|
55
|
+
# @api private
|
23
56
|
def self.runner()
|
24
57
|
return @runner;
|
25
58
|
end
|
59
|
+
# @return [GitRestart::Runner] Responsible Runner class
|
26
60
|
def runner()
|
27
61
|
return self.class.runner();
|
28
62
|
end
|
29
63
|
|
64
|
+
# @return [String] Name of the current branch
|
30
65
|
def branch()
|
31
66
|
runner().current_branch();
|
32
67
|
end
|
68
|
+
# @return [String] Full SHA of the current commit
|
69
|
+
def current_commit()
|
70
|
+
runner().current_commit();
|
71
|
+
end
|
72
|
+
|
73
|
+
# @return [Array<String>] A list of all files that were modified in the commit we are checking
|
33
74
|
def modified()
|
34
75
|
runner().current_modified();
|
35
76
|
end
|
36
77
|
|
78
|
+
# Use this function to specify which files trigger a restart for this Task
|
79
|
+
# Files can be specified as a RegEx, and can be "local/like.this" or "/reference/from/project.root"
|
37
80
|
def watch(regEx)
|
38
81
|
if(regEx.is_a? String)
|
39
82
|
regEx = Regexp.quote(regEx);
|
@@ -42,12 +85,17 @@ module GitRestart
|
|
42
85
|
@watched << Regexp.new(regEx);
|
43
86
|
end
|
44
87
|
|
88
|
+
# Specify which branches to run on. Not needed if "active" is just set to true
|
45
89
|
def on_branches(branches)
|
46
90
|
[branches].flatten.each do |b|
|
47
91
|
@active |= (b == branch());
|
48
92
|
end
|
49
93
|
end
|
50
94
|
|
95
|
+
# Create a new Task. This function does not take any input values, instead,
|
96
|
+
# one has to set the class up inside the block!
|
97
|
+
# A validity check will be run directly after yield(), as such, at the very least
|
98
|
+
# the name and a valid signal must have been specified!
|
51
99
|
def initialize()
|
52
100
|
@statuschange_mutex = Mutex.new();
|
53
101
|
|
@@ -67,6 +115,8 @@ module GitRestart
|
|
67
115
|
|
68
116
|
valid?
|
69
117
|
|
118
|
+
@status_file ||= "/tmp/TaskLog_#{@name}_#{current_commit()}";
|
119
|
+
|
70
120
|
if(runner().next_tasks[@name])
|
71
121
|
raise TaskValidityError, "A task of name #{@name} already exists!"
|
72
122
|
else
|
@@ -74,20 +124,31 @@ module GitRestart
|
|
74
124
|
end
|
75
125
|
end
|
76
126
|
|
127
|
+
# Checks whether or not the current set of modified files would require this
|
128
|
+
# task to be (re)started. Always returns true if @ci_task is set, or if
|
129
|
+
# the runner just has been started using @start_on
|
130
|
+
# @api private
|
77
131
|
def triggered?
|
78
132
|
return true if modified().nil?
|
79
133
|
return true if @ci_task
|
80
134
|
|
81
135
|
@watched.each do |regEx|
|
82
136
|
modified().each do |f|
|
83
|
-
|
84
|
-
|
137
|
+
if regEx.to_s =~ /^\(\?\-mix:\\\/(.*)\)$/ then
|
138
|
+
return true if f =~ Regexp.new($1);
|
139
|
+
else
|
140
|
+
next unless f =~ /#{Regexp.quote(@chdir)}(.*)/
|
141
|
+
return true if $1 =~ regEx;
|
142
|
+
end
|
85
143
|
end
|
86
144
|
end
|
87
145
|
|
88
146
|
return false;
|
89
147
|
end
|
90
148
|
|
149
|
+
# Checks whether or not this task has been set up properly. Currently only
|
150
|
+
# checks the name and abort signal.
|
151
|
+
# @api private
|
91
152
|
def valid?()
|
92
153
|
unless Signal.list[@signal] or @signal.nil?
|
93
154
|
raise TaskValidityError, "The specified kill-signal is not valid!"
|
@@ -98,8 +159,33 @@ module GitRestart
|
|
98
159
|
end
|
99
160
|
end
|
100
161
|
|
162
|
+
def _rm_logfile()
|
163
|
+
if File.exist?("/tmp/TaskLog_#{@name}_#{current_commit()}") then
|
164
|
+
File.delete("/tmp/TaskLog_#{@name}_#{current_commit()}");
|
165
|
+
end
|
166
|
+
end
|
167
|
+
private :_rm_logfile
|
168
|
+
def _get_statusline()
|
169
|
+
return "No status specified" unless File.exist? @status_file
|
170
|
+
|
171
|
+
sMsg = ""
|
172
|
+
File.open(@status_file, "r") do |sFile|
|
173
|
+
sFile.each_line do |l|
|
174
|
+
l.chomp!
|
175
|
+
next if l == "";
|
176
|
+
next if l =~ /^\s+/;
|
177
|
+
|
178
|
+
sMsg = l;
|
179
|
+
end
|
180
|
+
end
|
181
|
+
|
182
|
+
return sMsg;
|
183
|
+
end
|
184
|
+
private :_rm_logfile
|
185
|
+
|
101
186
|
def _report_status(status, message = nil)
|
102
|
-
|
187
|
+
message ||= _get_statusline();
|
188
|
+
@status_message = message;
|
103
189
|
|
104
190
|
return unless @report_status
|
105
191
|
|
@@ -107,6 +193,13 @@ module GitRestart
|
|
107
193
|
end
|
108
194
|
private :_report_status
|
109
195
|
|
196
|
+
# Starts this task.
|
197
|
+
# Once the task has been started it will run each given
|
198
|
+
# target one after another, waiting for each one to finish. If @report_status
|
199
|
+
# is set, it will also do just that.
|
200
|
+
# Task execution is handled within a thread, meaning that the function
|
201
|
+
# itself does not block.
|
202
|
+
# @api private
|
110
203
|
def start()
|
111
204
|
puts "Starting Task: #{@name}"
|
112
205
|
|
@@ -118,11 +211,13 @@ module GitRestart
|
|
118
211
|
@executionThread = Thread.new do
|
119
212
|
_report_status(:pending);
|
120
213
|
|
214
|
+
_rm_logfile();
|
121
215
|
@targets.each do |target|
|
216
|
+
# Mutex to ensure there either is no task running or a PID given
|
122
217
|
@statuschange_mutex.synchronize {
|
123
218
|
break if @exiting
|
124
219
|
options = {
|
125
|
-
[:out, :err] => "/
|
220
|
+
[:out, :err] => "/tmp/TaskLog_#{@name}_#{current_commit()}"
|
126
221
|
}
|
127
222
|
options[:chdir] = @chdir if @chdir
|
128
223
|
|
@@ -138,6 +233,7 @@ module GitRestart
|
|
138
233
|
|
139
234
|
if(@lastStatus == 0)
|
140
235
|
_report_status(:success);
|
236
|
+
_rm_logfile();
|
141
237
|
elsif(!@exiting || @expect_clean_exit)
|
142
238
|
_report_status(:failure);
|
143
239
|
end
|
@@ -147,6 +243,11 @@ module GitRestart
|
|
147
243
|
sleep 0.01
|
148
244
|
end
|
149
245
|
|
246
|
+
# Stop this task.
|
247
|
+
# Stopping it means immediately killing the currently running target with
|
248
|
+
# the specified signal, and not running any further targets.
|
249
|
+
# *Except* when nil is specified as signal, in which case the stop will be ignored!
|
250
|
+
# @api private
|
150
251
|
def stop()
|
151
252
|
puts "Stopping Task: #{@name}"
|
152
253
|
return if @signal.nil?
|
@@ -159,6 +260,8 @@ module GitRestart
|
|
159
260
|
}
|
160
261
|
end
|
161
262
|
|
263
|
+
# Wait for this task to finish execution.
|
264
|
+
# Either by naturally ending, or by being killed.
|
162
265
|
def join()
|
163
266
|
@executionThread.join();
|
164
267
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: git-restart
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0
|
4
|
+
version: 0.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Xasin
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2018-
|
11
|
+
date: 2018-09-05 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: mqtt-sub_handler
|
@@ -121,12 +121,12 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
121
121
|
version: '0'
|
122
122
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
123
123
|
requirements:
|
124
|
-
- - "
|
124
|
+
- - ">="
|
125
125
|
- !ruby/object:Gem::Version
|
126
|
-
version:
|
126
|
+
version: '0'
|
127
127
|
requirements: []
|
128
128
|
rubyforge_project:
|
129
|
-
rubygems_version: 2.
|
129
|
+
rubygems_version: 2.5.2.1
|
130
130
|
signing_key:
|
131
131
|
specification_version: 4
|
132
132
|
summary: "(Re)start scripts and monitor them on a GitHub push"
|