perkins 0.0.3 → 0.0.5

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.
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