perkins 0.0.3 → 0.0.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (73) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +3 -0
  3. data/Gemfile +1 -0
  4. data/README.md +11 -8
  5. data/Rakefile +1 -18
  6. data/config/database.yml +19 -0
  7. data/db/migrate/20150130143050_create_builds.rb +1 -1
  8. data/db/migrate/20150220143051_add_build_status_to_build_reports.rb +10 -0
  9. data/db/migrate/20150220143053_add_commit_to_build_reports.rb +10 -0
  10. data/db/migrate/20150220143054_add_hook_id_to_repo.rb +10 -0
  11. data/db/schema.rb +4 -2
  12. data/examples/Capfile +17 -0
  13. data/examples/Gemfile +14 -1
  14. data/examples/Gemfile.lock +45 -19
  15. data/examples/Procfile +8 -3
  16. data/examples/README.md +12 -0
  17. data/examples/boot.rb +5 -4
  18. data/examples/config.ru +2 -11
  19. data/examples/{database.yml → config/database.example.yml} +0 -0
  20. data/examples/config/database.yml +27 -0
  21. data/examples/config/deploy.rb +78 -0
  22. data/examples/config/deploy/staging.rb +61 -0
  23. data/examples/{rainbows.rb → config/rainbows/development.rb} +1 -1
  24. data/examples/config/rainbows/production.rb +56 -0
  25. data/examples/{sidekiq.yml → config/sidekiq.yml} +0 -0
  26. data/examples/db/schema.rb +43 -0
  27. data/examples/rakefile +8 -0
  28. data/lib/perkins/application.rb +1 -1
  29. data/lib/perkins/assets.rb +3 -3
  30. data/lib/perkins/assets/javascripts/app.js +1 -0
  31. data/lib/perkins/assets/javascripts/perkings.js.coffee +14 -9
  32. data/lib/perkins/assets/javascripts/perkins/helpers.js.coffee +2 -2
  33. data/lib/perkins/assets/javascripts/perkins/m/models.js.coffee +15 -9
  34. data/lib/perkins/assets/javascripts/perkins/router.js.coffee +1 -0
  35. data/lib/perkins/assets/javascripts/perkins/v/my_repos.js.coffee +1 -1
  36. data/lib/perkins/assets/javascripts/perkins/v/orgs.js.coffee +1 -1
  37. data/lib/perkins/assets/javascripts/perkins/v/repo.js.coffee +38 -5
  38. data/lib/perkins/assets/javascripts/templates/repo.hamlc +5 -14
  39. data/lib/perkins/assets/javascripts/templates/repos/build_row.hamlc +10 -5
  40. data/lib/perkins/assets/javascripts/templates/repos/config.hamlc +23 -13
  41. data/lib/perkins/assets/javascripts/templates/repos/report_detail.hamlc +6 -6
  42. data/lib/perkins/assets/javascripts/vendor/eventsource.polyfill.js +512 -0
  43. data/lib/perkins/build/script.rb +2 -1
  44. data/lib/perkins/build/script/go.rb +1 -1
  45. data/lib/perkins/build/script/ruby.rb +1 -1
  46. data/lib/perkins/build/script/stages.rb +0 -1
  47. data/lib/perkins/build_report.rb +27 -7
  48. data/lib/perkins/build_worker.rb +10 -15
  49. data/lib/perkins/git_loader_worker.rb +1 -14
  50. data/lib/perkins/repo.rb +106 -21
  51. data/lib/perkins/runner.rb +57 -12
  52. data/lib/perkins/server.rb +42 -46
  53. data/lib/perkins/socket_server.rb +38 -0
  54. data/lib/perkins/version.rb +1 -1
  55. data/lib/tasks/db_tasks.rake +35 -0
  56. data/perkins.gemspec +16 -19
  57. data/spec/README.md +3 -0
  58. data/spec/lib/build/build_spec.rb +7 -3
  59. data/spec/lib/repo_spec.rb +23 -32
  60. data/spec/lib/runner_spec.rb +52 -2
  61. data/spec/lib/server_spec.rb +15 -6
  62. data/spec/spec_helper.rb +6 -5
  63. metadata +21 -57
  64. data/.DS_Store +0 -0
  65. data/lib/perkins/views/builds.haml +0 -43
  66. data/lib/perkins/views/menu.haml +0 -18
  67. data/lib/perkins/views/orgs.haml +0 -101
  68. data/lib/perkins/views/profile.haml +0 -31
  69. data/lib/perkins/views/repos/config.haml +0 -72
  70. data/lib/perkins/views/repos/github.haml +0 -45
  71. data/lib/perkins/views/repos/menu.haml +0 -17
  72. data/lib/perkins/views/repos/repo.haml +0 -64
  73. data/lib/perkins/views/repos/spinner.haml +0 -3
@@ -157,7 +157,8 @@ module Perkins
157
157
  end
158
158
 
159
159
  def template(filename)
160
- @working_dir = @repo.working_dir + @repo.name
160
+ @working_dir = @repo.working_dir + @repo.download_name
161
+ #puts "REPO REPO #{@working_dir}"
161
162
  ERB.new(File.read(File.expand_path(filename, TEMPLATES_PATH))).result(binding)
162
163
  end
163
164
 
@@ -42,7 +42,7 @@ module Perkins
42
42
  # `go` commands.
43
43
  source_path = repo.url.gsub(/https\:\/\/|\.git/, "")
44
44
  source_owner_path = source_path.split('/')[0..1].join("/")
45
- local_path = self.repo.working_dir + self.repo.name
45
+ local_path = self.repo.working_dir + self.repo.download_name
46
46
  "export GOPATH=#{HOME_DIR}/gopath:$GOPATH && " <<
47
47
  #binding.pry
48
48
  "mkdir -p #{HOME_DIR}/gopath/src/#{source_owner_path} && " <<
@@ -8,7 +8,7 @@ module Perkins
8
8
  }
9
9
 
10
10
  include Jdk
11
- #include RVM
11
+ include RVM
12
12
  include Bundler
13
13
 
14
14
  def announce
@@ -18,7 +18,6 @@ module Perkins
18
18
  end
19
19
 
20
20
  def call_custom_stage(stage)
21
- #binding.pry
22
21
  @config.send(stage).present? ? cmd(@config.send(stage)) : self.send(stage)
23
22
  end
24
23
 
@@ -2,9 +2,24 @@ module Perkins
2
2
  class BuildReport < ActiveRecord::Base
3
3
  belongs_to :repo
4
4
 
5
- def commit
6
- self.repo.load_git
7
- @commit ||= Perkins::Commit.new(self.sha, self.repo)
5
+ after_create :enqueue
6
+
7
+ serialize :commit
8
+
9
+ def enqueue
10
+ BuildWorker.perform_async(self.id, sha, branch )
11
+ end
12
+
13
+ #def formatted_commit
14
+ #self.repo.load_git
15
+ # self.commit ||= $github_client.commits(repo.name, sha)
16
+ # Perkins::Commit.new(self.commit)
17
+ #end
18
+
19
+ def retrieve_commit_info
20
+ hsh = $github_client.commits(repo.name, sha).first.to_attrs
21
+ self.commit = hsh
22
+ self.save
8
23
  end
9
24
 
10
25
  def send_github_status(sha)
@@ -17,7 +32,7 @@ module Perkins
17
32
 
18
33
  unless fields = options[:only]
19
34
  fields = [:id, :sha, :commit, :branch, :build_time,
20
- :status, :duration, :build_time, :response]
35
+ :status, :duration, :build_time, :response, :build_status]
21
36
  end
22
37
 
23
38
  fields.each { |k| data[k] = send(k) }
@@ -25,10 +40,7 @@ module Perkins
25
40
  data
26
41
  end
27
42
 
28
-
29
-
30
43
  # Status report to GITHUB repo
31
-
32
44
  def build_status_report(sha)
33
45
  $github_client.create_status(
34
46
  self.repo.name, sha,
@@ -53,5 +65,13 @@ module Perkins
53
65
  "#{Perkins::Application.instance.sse_endpoint}/repos/#{repo.name}/builds/#{self.id}"
54
66
  end
55
67
 
68
+ def start!
69
+ update_attribute(:build_status, "started")
70
+ end
71
+
72
+ def stop!
73
+ update_attribute(:build_status, "stopped")
74
+ end
75
+
56
76
  end
57
77
  end
@@ -6,33 +6,28 @@ module Perkins
6
6
 
7
7
  include Sidekiq::Worker
8
8
 
9
- def perform(repo_id, sha, branch)
10
- repo = Perkins::Repo.find(repo_id)
11
- #it actually clone repo and instantiates git data
9
+ def perform(report_id, sha, branch)
10
+ report = Perkins::BuildReport.find(report_id)
11
+ report.retrieve_commit_info
12
+ repo = report.repo
13
+ repo.virtual_sha = "-#{report.id}-#{sha}"
14
+ #repo.build_runner_config
15
+ #it actually clone repo and instantiates git data & check travis.yml
12
16
  repo.load_git
13
17
 
14
18
  return if repo.runner.blank?
15
-
19
+ repo.runner.report = report
16
20
  repo.runner.sha = sha
17
21
  repo.runner.branch = branch
18
22
 
19
- send_sse({repo: {id: repo.id, name: repo.name , status: "start"} })
23
+ repo.send_sse(status: "start")
20
24
 
21
25
  repo.runner.run(sha)
22
26
 
23
27
  report = repo.build_reports.find_by(sha: sha)
24
28
  report.send_github_status(sha)
25
29
 
26
- send_sse({repo: {id: repo.id, name: repo.name , status: "stop", report: report } })
27
- end
28
-
29
- def send_sse(msg)
30
- url = "#{Perkins::Application.instance.sse_endpoint}/sse"
31
- puts "send sse post to #{url} with msg: #{msg.to_json}".pink
32
- postData = Net::HTTP.post_form(
33
- URI.parse(url),
34
- {'msg'=> msg.to_json }
35
- )
30
+ repo.send_sse({ status: "stop", report: report })
36
31
  end
37
32
 
38
33
  end
@@ -8,22 +8,9 @@ module Perkins
8
8
 
9
9
  def perform(repo_id)
10
10
  repo = Perkins::Repo.find(repo_id)
11
+ #return if repo.downloading? or repo.downloaded?
11
12
  #it actually clone repo and instantiates git data
12
- send_sse({repo: {id: repo.id, name: repo.name , status: "downloading"} })
13
-
14
13
  repo.load_git
15
-
16
- send_sse({repo: {id: repo.id, name: repo.name , status: "downloaded" } })
17
14
  end
18
-
19
- def send_sse(msg)
20
- url = "#{Perkins::Application.instance.sse_endpoint}/sse"
21
- puts "send sse post to #{url} with msg: #{msg.to_json}".pink
22
- postData = Net::HTTP.post_form(
23
- URI.parse(url),
24
- {'msg'=> msg.to_json }
25
- )
26
- end
27
-
28
15
  end
29
16
  end
@@ -2,7 +2,7 @@ require "git"
2
2
  module Perkins
3
3
  class Repo < ActiveRecord::Base
4
4
  attr_accessor :git
5
- attr_accessor :new_commit, :runner
5
+ attr_accessor :new_commit, :runner, :virtual_sha
6
6
 
7
7
  has_many :build_reports, class_name: 'Perkins::BuildReport'
8
8
  serialize :github_data, ActiveSupport::HashWithIndifferentAccess
@@ -31,7 +31,7 @@ module Perkins
31
31
  repo.url = r[:clone_url]
32
32
  repo.name = r[:full_name]
33
33
  repo.gb_id = r[:id]
34
- repo.working_dir = DEFAULT_DIR
34
+ repo.working_dir ||= DEFAULT_DIR
35
35
  repo.save
36
36
  end
37
37
 
@@ -41,9 +41,10 @@ module Perkins
41
41
 
42
42
  def self.store_from_github(repo)
43
43
  #repo
44
- repo.working_dir = DEFAULT_DIR #this should be configurable from app
44
+ repo.working_dir ||= DEFAULT_DIR #this should be configurable from app
45
45
  repo.cached = false
46
46
  repo.save
47
+ repo
47
48
  end
48
49
 
49
50
  def self.initialize_from_store(opts)
@@ -52,7 +53,7 @@ module Perkins
52
53
  repo.name = opts["name"]
53
54
  repo.github_data = opts["github_data"]
54
55
  repo.gb_id = opts["github_data"]["id"]
55
- repo.working_dir = DEFAULT_DIR #this should be configurable from app
56
+ repo.working_dir ||= DEFAULT_DIR #this should be configurable from app
56
57
  repo
57
58
  end
58
59
 
@@ -60,31 +61,103 @@ module Perkins
60
61
  clone_or_load
61
62
  end
62
63
 
63
- def downloaded?
64
- self.download_status.present? && self.download_status == "downloaded"
64
+ #def downloaded?
65
+ # self.download_status == "downloaded"
66
+ #end
67
+
68
+ #def downloading?
69
+ # self.download_status == "downloading"
70
+ #end
71
+
72
+ def download!
73
+ # we need this only in the context of the first clone
74
+ # in the context of builds we are not going to notice
75
+ # the user that we are cloning the repo
76
+ if self.virtual_sha.present?
77
+ send_sse( status: "downloading")
78
+ #self.update_column(:download_status, "downloading")
79
+ end
80
+
81
+ #clone repo
82
+ ssh_url = self.github_data["ssh_url"]
83
+ Git.clone(ssh_url, download_name, :path => working_dir)
84
+ open
85
+
86
+ #TODO: fix this & handle with care
87
+ begin
88
+ add_hook #permissions issue
89
+ rescue Exception => e
90
+ puts e.message
91
+ end
92
+
93
+ send_sse(status: "downloaded") if self.virtual_sha.present?
94
+ end
95
+
96
+ def download_name
97
+ [name, self.virtual_sha].join
98
+ end
99
+
100
+ def add_hook(url=nil)
101
+ url = hook_url if url.blank?
102
+
103
+ if hook_id.blank?
104
+ res = $github_client.create_hook(
105
+ self.name,
106
+ 'web',
107
+ { :url => url, :content_type => 'json'},
108
+ { :events => ['push', 'pull_request'],
109
+ :active => true}
110
+ )
111
+ self.update_attribute(:hook_id, res[:id]) if res[:id].present?
112
+ end
113
+ end
114
+
115
+ def edit_hook(url)
116
+
117
+ url = hook_url if url.blank?
118
+
119
+ hook = get_hook
120
+
121
+ if hook.present?
122
+ res = $github_client.edit_hook(
123
+ self.name,
124
+ hook["id"],
125
+ 'web',
126
+ {:url => url, :content_type => 'json'},
127
+ {:active => true}
128
+ )
129
+ self.update_attribute(:hook_id, res[:id]) if res[:id].present?
130
+ end
131
+ end
132
+
133
+ def hook_url
134
+ u = Perkins::Application.instance.sse_endpoint
135
+ p = Perkins::Application.instance.port == "80" ? nil : Perkins::Application.instance.port
136
+ host = [u, p].compact.join(":")
137
+ url = "#{host}/repos/receiver.json"
65
138
  end
66
139
 
67
- def downloading?
68
- self.download_status.present? && self.download_status == "downloading"
140
+ def get_hook
141
+ return {} if self.hook_id.blank?
142
+ $github_client.hook(self.name, self.hook_id)
69
143
  end
70
144
 
71
145
  def clone_or_load
72
146
  if exists?
73
147
  open
74
148
  else
75
- ssh_url = self.github_data["ssh_url"]
76
- Git.clone(ssh_url, name, :path => working_dir)
77
- open
149
+ download!
78
150
  end
79
151
  end
80
152
 
81
153
  def open
82
154
  self.git = Git.open(local_path) # :log => Logger.new(STDOUT)
83
- build_runner_config(self.check_config_existence) if self.check_config_existence
84
- self.update_column(:download_status, "downloaded")
155
+ build_runner_config
156
+ #self.update_column(:download_status, "downloaded") #unless self.downloaded?
85
157
  end
86
158
 
87
159
  def check_config_existence
160
+ #puts "CURRENT GIT DIR: #{self.git.dir.path} !!!!!"
88
161
  config = self.git.chdir{
89
162
  if File.exist?(".travis.yml")
90
163
  config = Travis::Yaml.parse( File.open(".travis.yml").read )
@@ -101,7 +174,7 @@ module Perkins
101
174
  end
102
175
 
103
176
  def local_path
104
- self.working_dir + self.name.to_s
177
+ [ self.working_dir , self.download_name].join
105
178
  end
106
179
 
107
180
  def branches
@@ -109,7 +182,8 @@ module Perkins
109
182
  end
110
183
 
111
184
  #http://docs.travis-ci.com/user/build-configuration/#The-Build-Matrix
112
- def build_runner_config(config)
185
+ def build_runner_config
186
+ config = self.check_config_existence
113
187
  runner = Runner.new()
114
188
  runner.config = config
115
189
  runner.repo = self
@@ -129,18 +203,23 @@ module Perkins
129
203
  end
130
204
 
131
205
  def add_commit(sha, branch)
132
- if runner_branch.include?(branch)
206
+ #if runner_branch.include?(branch)
133
207
  #@new_commit = Perkins::Commit.new(sha, self)
134
208
  #@new_commit.branch = branch
135
209
  #enqueue_commit(@new_commit)
136
210
  enqueue_commit(sha, branch)
137
- else
138
- puts "skipping commit from branch #{branch}"
139
- end
211
+ #else
212
+ # puts "skipping commit from branch #{branch}"
213
+ #end
140
214
  end
141
215
 
142
216
  def enqueue_commit(sha, branch)
143
- BuildWorker.perform_async(self.id, sha, branch )
217
+ report = Perkins::BuildReport.new
218
+ report.sha = sha
219
+ report.branch = branch
220
+
221
+ self.build_reports << report
222
+ self.save
144
223
  end
145
224
 
146
225
  def http_url
@@ -154,7 +233,13 @@ module Perkins
154
233
  build_reports.last.id if build_reports.any?
155
234
  end
156
235
 
157
-
236
+ def send_sse(msg)
237
+ opts = {repo: {id: self.id, name: self.name }}
238
+ opts[:repo].merge!(msg) if msg.is_a?(Hash)
239
+ json_opts = opts.to_json
240
+ puts "Notify #{json_opts}".yellow
241
+ Redis.current.publish("message.", json_opts)
242
+ end
158
243
 
159
244
  end
160
245
 
@@ -2,22 +2,34 @@
2
2
  module Perkins
3
3
  class Runner
4
4
 
5
- attr_accessor :repo, :command, :config, :sha, :branch
5
+ #include Process
6
+
7
+ attr_accessor :repo, :report, :command, :config, :sha, :branch
6
8
  attr_reader :build_time, :duration, :response, :status, :current_build
7
9
 
8
10
  def exec(cmd)
9
11
  result = run_script(cmd)
10
- puts result
11
- process_status = $?
12
-
13
- if successful_command?(process_status) || config_command_with_empty_value?(result,process_status)
14
- @response = result
12
+ @response = result.join("")
13
+
14
+ if result.last.chomp.include?("with 0")
15
15
  @status = true
16
- return result
16
+ elsif result.last.chomp.include?("with 1")
17
+ @status = false
17
18
  else
18
- @response = result
19
+ puts "status result not found!!"
19
20
  @status = false
20
21
  end
22
+
23
+ #puts result
24
+ #process_status = $?
25
+ #if successful_command?(process_status) || config_command_with_empty_value?(result,process_status)
26
+ # @response = result
27
+ # @status = true
28
+ # return result
29
+ #else
30
+ # @response = result
31
+ # @status = false
32
+ #end
21
33
  end
22
34
 
23
35
  def run_script(source)
@@ -28,33 +40,67 @@ module Perkins
28
40
  File.open(script, 'w') { |f| f.write(source) }
29
41
  FileUtils.chmod(0755, script)
30
42
  Bundler.with_clean_env{
31
- `bash #{script} 2>&1`.chomp
43
+ pipe_command("#{script} 2>&1")
44
+ #`bash #{script} 2>&1`.chomp
32
45
  }
33
46
  end
34
47
 
48
+ def pipe_command(cmd)
49
+ output = []
50
+ r, io = IO.pipe
51
+ pid = fork do
52
+ @process = system(cmd, out: io, err: :out)
53
+ end
54
+ io.close
55
+ r.each_line{|l|
56
+ puts l.yellow
57
+ output << l
58
+ #puts "CURRENT DIR: #{Dir.pwd} !!!!!"
59
+ #puts "CURRENT GIT DIR: #{repo.git.dir.path} !!!!!"
60
+ #puts "#{repo.download_name} !!!!!!!"
61
+ #updates each time, this should trigger event to interface to refresh
62
+ @current_report.update_column(:response, output.join(""))
63
+ }
64
+ #Process.waitpid(p1) #this is to get the $ exitstatus
65
+ output
66
+ end
67
+
35
68
  def run(sha)
36
69
  self.sha = sha
37
70
  start_build
71
+ self.repo.virtual_sha = "-#{@current_report.id}-#{self.sha}"
72
+ #it actually clone repo and instantiates git data
73
+ repo.load_git
74
+
38
75
  script = Perkins::Build::script(config, repo)
39
76
  sh = script.compile
77
+
40
78
  repo.git.chdir do
79
+ #puts "CURRENT DIR: #{Dir.pwd} !!!!!"
80
+ #puts "CURRENT GIT DIR: #{repo.git.dir.path} !!!!!"
41
81
  git_update(sha)
42
82
  set_build_stats do
43
83
  puts "perform build".green
44
84
  self.exec(sh)
45
85
  end
46
86
  end
47
- store_report
87
+ #store_report
48
88
  stop_build
49
89
  end
50
90
 
51
91
  def start_build
52
92
  @running = true
93
+ store_report
94
+ @current_report.start!
53
95
  @repo.update_column(:build_status, "started")
54
96
  end
55
97
 
56
98
  def stop_build
57
99
  @running = false
100
+ @current_report.stop!
101
+
102
+ @current_report.update_attributes(self.to_report)
103
+
58
104
  @repo.update_column(:build_status, "stopped")
59
105
  end
60
106
 
@@ -103,8 +149,7 @@ module Perkins
103
149
  end
104
150
 
105
151
  def store_report
106
- r = Perkins::BuildReport.new(self.to_report)
107
- repo.build_reports << r
152
+ @current_report = Perkins::BuildReport.find(report)
108
153
  end
109
154
 
110
155
  def get_builds