git-restart 0.0.1.pre.dev

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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: d328a8601625a761e52bce62d042e047403c2eef
4
+ data.tar.gz: e5fe83b3019317b259f91ddb31e6841b6b30e050
5
+ SHA512:
6
+ metadata.gz: 229b49c059c88712e46f35f79466a3442992045b334a1f6fe5f03b620bee9cba408436548170982947e39484e27e3f5e757c1fa1082692231dfd4f586403f054
7
+ data.tar.gz: b4938804dc08b11107088aba4b7ab57f5e429431c580c9368bdef86918e024ed44fb0bae264aad225ab56bca666bc9ec94346cbddba07221bd7506c7e8db151b
data/bin/git-restart ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/ruby
2
+
3
+ require 'mqtt/sub_handler.rb'
4
+ require 'git-restart/runner.rb'
5
+
6
+ puts "Starting runner ..."
7
+
8
+ target = ARGV[0] | ".gitrun"
9
+
10
+ raise ArgumentError, "No valid task file specified!" unless File.exist? target
11
+
12
+ load target
13
+
14
+ GitRestart::Task.runner.mqtt.lock_and_listen
@@ -0,0 +1,165 @@
1
+
2
+ require 'mqtt/sub_handler'
3
+ require 'git'
4
+
5
+ require_relative "task.rb"
6
+
7
+ module GitRestart
8
+ class Runner
9
+ attr_accessor :name
10
+
11
+ attr_accessor :repo, :branches, :exclude_branches, :start_on
12
+
13
+ attr_reader :next_tasks
14
+ attr_reader :current_task_file
15
+
16
+ def current_commit()
17
+ @git.object("HEAD^").sha;
18
+ end
19
+ def current_branch()
20
+ @git.current_branch();
21
+ end
22
+ def current_modified()
23
+ @current_modified;
24
+ end
25
+
26
+ def initialize()
27
+ GitRestart::Task.runner = self;
28
+
29
+ @current_tasks = Hash.new();
30
+ @next_tasks = Hash.new();
31
+
32
+ @branches = Array.new();
33
+ @exclude_branches = Array.new();
34
+
35
+ @branchQueue = Queue.new();
36
+
37
+ @git = Git.open(".");
38
+
39
+ yield(self);
40
+
41
+ @listenedSub = @mqtt.subscribe_to "GitHub/#{@repo}" do |data|
42
+ puts "Received data: #{data}"
43
+ begin
44
+ data = JSON.parse(data, symbolize_names: true);
45
+ rescue
46
+ next;
47
+ end
48
+
49
+ puts "Processing data #{data}"
50
+
51
+ next unless data[:branch];
52
+ if(not @branches.empty?)
53
+ next unless @branches.include? data[:branch];
54
+ elsif(not @exclude_branches.empty?)
55
+ next if @exclude_branches.include? data[:branch];
56
+ end
57
+
58
+ puts "Queueing data!"
59
+
60
+ @branchQueue << data;
61
+ end
62
+
63
+ autostart();
64
+ _start_task_thread();
65
+ end
66
+
67
+ def update_status(name, newStatus, message = nil)
68
+ end
69
+
70
+ def _start_task_thread()
71
+ @taskThread = Thread.new do
72
+ loop do
73
+ newData = @branchQueue.pop;
74
+
75
+ puts "Popped data: #{newData}"
76
+
77
+ @current_modified = newData[:touched];
78
+ _switch_to(newData[:branch], newData[:head_commit]);
79
+ end
80
+ end.abort_on_exception = true;
81
+ end
82
+
83
+ def _stop_tasks(taskList)
84
+ taskList.each do |name, t|
85
+ t.stop();
86
+ end
87
+ taskList.each do |name, t|
88
+ t.join();
89
+ @current_tasks.delete(name);
90
+ end
91
+ end
92
+ def _stop_all_tasks()
93
+ _stop_tasks(@current_tasks);
94
+ end
95
+ def _stop_triggered_tasks()
96
+ _stop_tasks(@current_tasks.select {|k,v| v.triggered?});
97
+ end
98
+
99
+ def _generate_next_tasks()
100
+ puts "Generating new tasks..."
101
+ @next_tasks = Hash.new();
102
+
103
+ taskFiles = `find ./ -nowarn -iname "*.gittask"`
104
+ taskFiles.split("\n").each do |t|
105
+ puts "Looking at: #{t}"
106
+ t.gsub!(/^\.\//,"");
107
+ @current_task_file = t;
108
+
109
+ # TODO Add proper error reporting
110
+ begin
111
+ load(t);
112
+ rescue ScriptError, StandardError
113
+ puts("File #{t} could not be loaded!");
114
+ rescue GitRestart::TaskValidityError
115
+ puts("Task-File #{t} is not configured properly!");
116
+ end
117
+ end
118
+
119
+ puts "Finished loading! Next tasks are: #{@next_tasks}"
120
+ end
121
+
122
+ def _start_next_tasks()
123
+ _generate_next_tasks();
124
+
125
+ puts "Starting next tasks!"
126
+ @next_tasks.each do |name, t|
127
+ next unless t.active;
128
+ next unless t.triggered?
129
+
130
+ t.start();
131
+ @current_tasks[name] = t;
132
+ end
133
+ end
134
+
135
+ def _switch_to(branch, commit = nil)
136
+ puts "Switching to branch: #{branch}, commit: #{commit}"
137
+ @git.fetch();
138
+
139
+ if(branch != current_branch())
140
+ _stop_all_tasks();
141
+ else
142
+ _stop_triggered_tasks();
143
+ end
144
+ @git.checkout(branch);
145
+ @git.reset_hard(commit);
146
+
147
+ @git.merge("origin/#{branch}");
148
+
149
+ _start_next_tasks();
150
+ end
151
+
152
+ def autostart()
153
+ return unless @start_on;
154
+ @branchQueue << {branch: @start_on};
155
+ end
156
+
157
+ def mqtt=(mqtt)
158
+ if(mqtt.is_a? String)
159
+ @mqtt = MQTT::SubHandler.new(mqtt);
160
+ else
161
+ @mqtt = mqtt;
162
+ end
163
+ end
164
+ end
165
+ end
@@ -0,0 +1,165 @@
1
+
2
+ module GitRestart
3
+ class TaskValidityError < StandardError
4
+ end
5
+
6
+ class Task
7
+ attr_reader :targets
8
+
9
+ attr_accessor :signal
10
+ attr_accessor :expect_clean_exit
11
+ attr_accessor :report_status
12
+ attr_accessor :ci_task
13
+ attr_accessor :name, :status_file
14
+
15
+ attr_accessor :active
16
+
17
+ attr_reader :lastStatus
18
+ attr_reader :status_message
19
+
20
+ attr_reader :mqtt
21
+
22
+ def self.runner=(runner)
23
+ @runner = runner;
24
+ end
25
+ def self.runner()
26
+ return @runner;
27
+ end
28
+ def runner()
29
+ return self.class.runner();
30
+ end
31
+
32
+ def branch()
33
+ runner().current_branch();
34
+ end
35
+ def modified()
36
+ runner().current_modified();
37
+ end
38
+
39
+ def watch(regEx)
40
+ if(regEx.is_a? String)
41
+ regEx = Regexp.quote(regEx);
42
+ end
43
+
44
+ @watched << Regexp.new(regEx);
45
+ end
46
+
47
+ def on_branches(branches)
48
+ [branches].flatten.each do |b|
49
+ @active |= (b == branch());
50
+ end
51
+ end
52
+
53
+ def initialize()
54
+ @statuschange_mutex = Mutex.new();
55
+
56
+ @targets = Array.new();
57
+ @watched = Array.new();
58
+
59
+ @signal = "INT"
60
+ @expect_clean_exit = true;
61
+ @exiting = false;
62
+
63
+ @lastStatus = 0;
64
+ @chdir = File.dirname(runner().current_task_file);
65
+
66
+ watch(File.basename(runner().current_task_file));
67
+
68
+ yield(self);
69
+
70
+ valid?
71
+
72
+ if(runner().next_tasks[@name])
73
+ raise TaskValidityError, "A task of name #{@name} already exists!"
74
+ else
75
+ runner().next_tasks[@name] = self;
76
+ end
77
+ end
78
+
79
+ def triggered?
80
+ return true if modified().nil?
81
+ return true if @ci_task
82
+
83
+ @watched.each do |regEx|
84
+ modified().each do |f|
85
+ next unless f =~ /#{Regexp.quote(@chdir)}(.*)/
86
+ return true if $1 =~ regEx;
87
+ end
88
+ end
89
+
90
+ return false;
91
+ end
92
+
93
+ def valid?()
94
+ unless Signal.list[@signal] or @signal.nil?
95
+ raise TaskValidityError, "The specified kill-signal is not valid!"
96
+ end
97
+
98
+ unless @name
99
+ raise TaskValidityError, "A name needs to be set for identification!"
100
+ end
101
+ end
102
+
103
+ def _report_status(status, message = nil)
104
+ @status_message = ""
105
+
106
+ return unless @report_status
107
+
108
+ runner().update_status(@name, status, message);
109
+ puts "Task #{@name} assumed a new status: #{status}#{message ? " MSG:#{message}" : ""}"
110
+ end
111
+ private :_report_status
112
+
113
+ def start()
114
+ puts "Starting Task: #{@name}"
115
+
116
+ return if @targets.empty?
117
+ sleep 0.01
118
+
119
+ @executionThread = Thread.new do
120
+ _report_status(:pending);
121
+
122
+ @targets.each do |target|
123
+ @statuschange_mutex.synchronize {
124
+ break if @exiting
125
+ options = {
126
+ [:in, :out, :err] => "/dev/null"
127
+ }
128
+ options[:chdir] = @chdir if @chdir
129
+
130
+ @currentPID = Process.spawn(target, options);
131
+ }
132
+
133
+ status = Process.wait2(@currentPID)[1];
134
+ @currentPID = nil;
135
+ @lastStatus = status.exitstatus();
136
+
137
+ break unless @lastStatus == 0;
138
+ end
139
+
140
+ if(@lastStatus == 0)
141
+ _report_status(:success);
142
+ elsif(!@exiting || @expect_clean_exit)
143
+ _report_status(:failure);
144
+ end
145
+ end
146
+ @executionThread.abort_on_exception = true;
147
+ end
148
+
149
+ def stop()
150
+ puts "Stopping Task: #{@name}"
151
+ return if @signal.nil?
152
+
153
+ @statuschange_mutex.synchronize {
154
+ @exiting = true;
155
+ if(p = @currentPID)
156
+ Process.kill(@signal, p);
157
+ end
158
+ }
159
+ end
160
+
161
+ def join()
162
+ @executionThread.join();
163
+ end
164
+ end
165
+ end
metadata ADDED
@@ -0,0 +1,118 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: git-restart
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1.pre.dev
5
+ platform: ruby
6
+ authors:
7
+ - Xasin
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2018-08-05 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: mqtt-sub_handler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: git
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '1.4'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '1.4'
41
+ - !ruby/object:Gem::Dependency
42
+ name: minitest
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: guard
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: guard-minitest
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ description: |-
84
+ This gem can be used to (re)start scripts whenever a GitHub push event is recorded.
85
+ The exit status of scripts can be monitored, and a failure can be sent back, making this capable of running simple tests too!
86
+ email:
87
+ executables: []
88
+ extensions: []
89
+ extra_rdoc_files: []
90
+ files:
91
+ - bin/git-restart
92
+ - lib/git-restart/runner.rb
93
+ - lib/git-restart/task.rb
94
+ homepage: https://github.com/XasWorks/XasCode/tree/master/Ruby/GitRestart
95
+ licenses:
96
+ - GPL-3.0
97
+ metadata: {}
98
+ post_install_message:
99
+ rdoc_options: []
100
+ require_paths:
101
+ - lib
102
+ required_ruby_version: !ruby/object:Gem::Requirement
103
+ requirements:
104
+ - - ">="
105
+ - !ruby/object:Gem::Version
106
+ version: '0'
107
+ required_rubygems_version: !ruby/object:Gem::Requirement
108
+ requirements:
109
+ - - ">"
110
+ - !ruby/object:Gem::Version
111
+ version: 1.3.1
112
+ requirements: []
113
+ rubyforge_project:
114
+ rubygems_version: 2.6.14.1
115
+ signing_key:
116
+ specification_version: 4
117
+ summary: "(Re)start scripts and monitor them on a GitHub push"
118
+ test_files: []