Class: GitRestart::Task

Inherits:
Object
  • Object
show all
Defined in:
lib/git-restart/task.rb

Overview

This class is used to define “Tasks”. Each task represents a set of commands, which it executes in chronological order, or until a task errors. Additionally, it will kill execution of tasks with a specified kill-signal when an update was detected from GitHub. The failure-status of the tasks can also be reported via Octokit, allowing this to be used as a simple CI or Test system for various languages.

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize {|_self| ... } ⇒ Task

Create a new Task. This function does not take any input values, instead, one has to set the class up inside the block! A validity check will be run directly after yield(), as such, at the very least the name and a valid signal must have been specified!

Yields:

  • (_self)

Yield Parameters:



99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
# File 'lib/git-restart/task.rb', line 99

def initialize()
	@statuschange_mutex = Mutex.new();

	@targets = Array.new();
	@watched = Array.new();

	@signal 	= "INT"
	@expect_clean_exit	= true;
	@exiting					= false;

	@lastStatus = 0;
	@chdir = File.dirname(runner().current_task_file);

	watch(File.basename(runner().current_task_file));

	yield(self);

	valid?

	@status_file ||= "/tmp/TaskLog_#{@name}_#{current_commit()}";

	if(runner().next_tasks[@name])
		raise TaskValidityError, "A task of name #{@name} already exists!"
	else
		runner().next_tasks[@name] = self;
	end
end

Instance Attribute Details

#activeObject

Whether or not this task is active. Usually set via #on_branches, but can be used to manually disable or enable this task based on config files, ENV variables etc.



44
45
46
# File 'lib/git-restart/task.rb', line 44

def active
  @active
end

#ci_taskObject

Defines this as a “CI_Task”. Such a task will always run on an update, regardless what files changed. Useful if you always want a status report on GitHub.



33
34
35
# File 'lib/git-restart/task.rb', line 33

def ci_task
  @ci_task
end

#expect_clean_exitObject

Whether or not to report failure if the currently running target has a non-zero exit status after having been killed. Only makes sense together with report_status



27
28
29
# File 'lib/git-restart/task.rb', line 27

def expect_clean_exit
  @expect_clean_exit
end

#lastStatusObject (readonly)

The last status-code of this Task. Used internally.



47
48
49
# File 'lib/git-restart/task.rb', line 47

def lastStatus
  @lastStatus
end

#nameObject

Name of the Task. Required. Used as unique ID, and to report status to GitHub



35
36
37
# File 'lib/git-restart/task.rb', line 35

def name
  @name
end

#report_statusObject

Whether or not to report failure/success status to GitHub using Octokit



29
30
31
# File 'lib/git-restart/task.rb', line 29

def report_status
  @report_status
end

#signalObject

The signal (as String, like Signal.list) to use to kill the process. Can be nil to disable killing



23
24
25
# File 'lib/git-restart/task.rb', line 23

def signal
  @signal
end

#status_fileObject

The file to use to retrieve a single-line status info for the “description” string of the GitHub status. Only the last non-indented line is used, which allows the output of Minitest to be used directly.



39
40
41
# File 'lib/git-restart/task.rb', line 39

def status_file
  @status_file
end

#status_messageObject (readonly)

The last status-message of this task. Used internally.



49
50
51
# File 'lib/git-restart/task.rb', line 49

def status_message
  @status_message
end

#targetsArray<String> (readonly)

The array of tasks to execute. Each target will be executed in the given order via Process.spawn.

Returns:

  • (Array<String>)


19
20
21
# File 'lib/git-restart/task.rb', line 19

def targets
  @targets
end

Class Method Details

.runnerObject

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



56
57
58
# File 'lib/git-restart/task.rb', line 56

def self.runner()
	return @runner;
end

.runner=(runner) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



52
53
54
# File 'lib/git-restart/task.rb', line 52

def self.runner=(runner)
	@runner = runner;
end

Instance Method Details

#_get_statuslineObject



168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
# File 'lib/git-restart/task.rb', line 168

def _get_statusline()
	return "No status specified" unless File.exist? @status_file

	sMsg = ""
	File.open(@status_file, "r") do |sFile|
		sFile.each_line do |l|
			l.chomp!
			next if l == "";
			next if l =~ /^\s+/;

			sMsg = l;
		end
	end

	return sMsg;
end

#branchString

Returns Name of the current branch.

Returns:

  • (String)

    Name of the current branch



65
66
67
# File 'lib/git-restart/task.rb', line 65

def branch()
	runner().current_branch();
end

#current_commitString

Returns Full SHA of the current commit.

Returns:

  • (String)

    Full SHA of the current commit



69
70
71
# File 'lib/git-restart/task.rb', line 69

def current_commit()
	runner().current_commit();
end

#joinObject

Wait for this task to finish execution. Either by naturally ending, or by being killed.



265
266
267
# File 'lib/git-restart/task.rb', line 265

def join()
	@executionThread.join();
end

#modifiedArray<String>

Returns A list of all files that were modified in the commit we are checking.

Returns:

  • (Array<String>)

    A list of all files that were modified in the commit we are checking



74
75
76
# File 'lib/git-restart/task.rb', line 74

def modified()
	runner().current_modified();
end

#on_branches(branches) ⇒ Object

Specify which branches to run on. Not needed if “active” is just set to true



89
90
91
92
93
# File 'lib/git-restart/task.rb', line 89

def on_branches(branches)
	[branches].flatten.each do |b|
		@active |= (b == branch());
	end
end

#runnerGitRestart::Runner

Returns Responsible Runner class.

Returns:



60
61
62
# File 'lib/git-restart/task.rb', line 60

def runner()
	return self.class.runner();
end

#startObject

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Starts this task. Once the task has been started it will run each given target one after another, waiting for each one to finish. If @report_status is set, it will also do just that. Task execution is handled within a thread, meaning that the function itself does not block.



203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
# File 'lib/git-restart/task.rb', line 203

def start()
	puts "Starting Task: #{@name}"

	if @targets.empty?
		_report_status(:success, "No tasks to run!");
		return
	end

	@executionThread = Thread.new do
		_report_status(:pending);

		_rm_logfile();
		@targets.each do |target|
			# Mutex to ensure there either is no task running or a PID given
			@statuschange_mutex.synchronize {
				break if @exiting
				options = {
					[:out, :err] => "/tmp/TaskLog_#{@name}_#{current_commit()}"
				}
				options[:chdir] = @chdir if @chdir

				@currentPID = Process.spawn(target, options);
			}

			status = Process.wait2(@currentPID)[1];
			@currentPID = nil;
			@lastStatus = status.exitstatus();

			break unless @lastStatus == 0;
		end

		if(@lastStatus == 0)
			_report_status(:success);
			_rm_logfile();
		elsif(!@exiting || @expect_clean_exit)
			_report_status(:failure);
		end
	end
	@executionThread.abort_on_exception = true;

	sleep 0.01
end

#stopObject

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Stop this task. Stopping it means immediately killing the currently running target with the specified signal, and not running any further targets. Except when nil is specified as signal, in which case the stop will be ignored!



251
252
253
254
255
256
257
258
259
260
261
# File 'lib/git-restart/task.rb', line 251

def stop()
	puts "Stopping Task: #{@name}"
	return if @signal.nil?

	@statuschange_mutex.synchronize {
		@exiting = true;
		if(p = @currentPID)
			Process.kill(@signal, p);
		end
	}
end

#triggered?Boolean

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Checks whether or not the current set of modified files would require this task to be (re)started. Always returns true if @ci_task is set, or if the runner just has been started using @start_on

Returns:

  • (Boolean)


131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
# File 'lib/git-restart/task.rb', line 131

def triggered?
	return true if modified().nil?
	return true if @ci_task

	@watched.each do |regEx|
		modified().each do |f|
			if regEx.to_s =~ /^\(\?\-mix:\\\/(.*)\)$/ then
				return true if f =~ Regexp.new($1);
			else
				next unless f =~ /#{Regexp.quote(@chdir)}(.*)/
				return true if $1 =~ regEx;
			end
		end
	end

	return false;
end

#valid?Boolean

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Checks whether or not this task has been set up properly. Currently only checks the name and abort signal.

Returns:

  • (Boolean)


152
153
154
155
156
157
158
159
160
# File 'lib/git-restart/task.rb', line 152

def valid?()
	unless Signal.list[@signal] or @signal.nil?
		raise TaskValidityError, "The specified kill-signal is not valid!"
	end

	unless @name
		raise TaskValidityError, "A name needs to be set for identification!"
	end
end

#watch(regEx) ⇒ Object

Use this function to specify which files trigger a restart for this Task Files can be specified as a RegEx, and can be “local/like.this” or “/reference/from/project.root”



80
81
82
83
84
85
86
# File 'lib/git-restart/task.rb', line 80

def watch(regEx)
	if(regEx.is_a? String)
		regEx = Regexp.quote(regEx);
	end

	@watched << Regexp.new(regEx);
end