git-restart 0.0.14.pre.dev → 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 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"