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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 6eb1eb18f538b107ff746a74bd5e915d086d7a42
4
- data.tar.gz: 7f027170a97419f103005c983818a53f533df720
3
+ metadata.gz: 89f6a4a1fa9ad535f9a80f69fc2729e28fa4c077
4
+ data.tar.gz: '09e3329d30be30ea60511e894dc0f1e0ba44375b'
5
5
  SHA512:
6
- metadata.gz: 66c6d72431590ae182bb58498d826a4601fbb9e8f1af8f2fb65fc00e5517b2bac2ce814943f2a64b29351de683fea521ab036bdfaa4b1bbe3fe0c504a68f3574
7
- data.tar.gz: fa56dd81445f2858f4d547286332c7132ec461e8e44a67f60791720b8d9f44c66eb6b4670ff0e1eedfc2afaee22d0b0e67c035ff6206c1df26c0711f1a3bba68
6
+ metadata.gz: e46803d3834a7fec3c2166f8864d45b746de31b0ca9d6e87c839ab806a4b5943ff822739ef209d447d7e45aa4a88d8dd77b812b478f7ac8d042b1a08983965e8
7
+ data.tar.gz: 6e883c22e0dd8b1ee5c09a2c51a193d67ff82c2abcdbc33f3ed1232bdf73d3373b8835365d1a248b242b985e0eae30226f1d008a9375318aefc43e2bc0b134a6
@@ -8,9 +8,9 @@ puts "Starting runner ..."
8
8
  $taskfiles = Array.new();
9
9
  target = ".gitrun"
10
10
  ARGV.each do |t|
11
- if(File.extname(t) == ".gitrun")
11
+ if(t =~ /\.gitrun$/)
12
12
  target = t;
13
- elsif(File.extname(t) == ".gittask")
13
+ else
14
14
  $taskfiles << t;
15
15
  end
16
16
  end
@@ -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
- attr_accessor :repo, :branches, :exclude_branches, :start_on
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 #{@name} assumed a new status: #{newStatus}#{message ? " MSG:#{message}" : ""}"
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: "#{@name}/#{name}".gsub(" ", "_"),
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)
@@ -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
- attr_accessor :name, :status_file
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
- next unless f =~ /#{Regexp.quote(@chdir)}(.*)/
84
- return true if $1 =~ regEx;
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
- @status_message = ""
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] => "/dev/null"
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.14.pre.dev
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-08-17 00:00:00.000000000 Z
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: 1.3.1
126
+ version: '0'
127
127
  requirements: []
128
128
  rubyforge_project:
129
- rubygems_version: 2.6.14.1
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"