git-restart 0.0.1.pre.dev

Sign up to get free protection for your applications and to get access to all the features.
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: []