houston-core 0.7.0.beta4 → 0.7.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (52) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +4 -2
  3. data/.travis.yml +50 -0
  4. data/Gemfile +1 -2
  5. data/Gemfile.lock +1 -7
  6. data/README.md +21 -9
  7. data/app/assets/stylesheets/houston/application/actions.scss +25 -4
  8. data/app/assets/stylesheets/houston/application/sprint.scss +1 -1
  9. data/app/assets/stylesheets/houston/application/test.scss +1 -1
  10. data/app/assets/stylesheets/houston/application/test_run.scss +2 -2
  11. data/app/assets/stylesheets/houston/application/timeline.scss +1 -1
  12. data/app/assets/stylesheets/houston/core/roboto.scss.erb +2 -2
  13. data/app/controllers/actions_controller.rb +13 -5
  14. data/app/controllers/errors_controller.rb +2 -2
  15. data/app/controllers/releases_controller.rb +1 -1
  16. data/app/controllers/triggers_controller.rb +1 -1
  17. data/app/helpers/actions_helper.rb +36 -1
  18. data/app/helpers/navigation_helper.rb +6 -1
  19. data/app/models/github/pull_request.rb +13 -4
  20. data/app/models/task.rb +1 -1
  21. data/app/presenters/task_presenter.rb +6 -6
  22. data/app/views/actions/_actions.html.erb +12 -0
  23. data/app/views/actions/index.html.erb +19 -12
  24. data/app/views/actions/running.html.erb +47 -0
  25. data/app/views/actions/show.html.erb +13 -14
  26. data/app/views/errors/_actions.html.erb +1 -1
  27. data/app/views/errors/index.html.erb +5 -1
  28. data/app/views/layouts/_navigation.html.erb +10 -5
  29. data/config/initializers/add_navigation_renderers.rb +8 -6
  30. data/config/initializers/houston_deliver.rb +16 -0
  31. data/config/routes.rb +1 -0
  32. data/db/structure.sql +1 -1
  33. data/houston-core.gemspec +1 -1
  34. data/lib/generators/module_generator.rb +5 -1
  35. data/lib/houston/boot/actions.rb +4 -1
  36. data/lib/houston/boot/configuration.rb +8 -1
  37. data/lib/houston/boot/extensions.rb +35 -9
  38. data/lib/houston/boot/serializer.rb +6 -1
  39. data/lib/houston/version.rb +1 -1
  40. data/script/cibuild +2 -2
  41. data/templates/new-module/lib/houston/%name%.rb +30 -7
  42. data/test/acceptance/creating_a_release_test.rb +14 -21
  43. data/test/data/bare_repo.git/FETCH_HEAD +1 -1
  44. data/test/data/bare_repo.git/objects/60/3a4970ec7ed5eb3f7a578850c21b7162424465 +1 -0
  45. data/test/data/bare_repo.git/objects/b9/1a4fe778398bc87b29842ca84a2727b4763c9d +1 -0
  46. data/test/data/bare_repo.git/objects/ba/b88c00ec62b5f30bf720ab1136401d1f9d2310 +2 -0
  47. data/test/data/bare_repo.git/refs/heads/master +1 -1
  48. data/test/integration/commits_api_test.rb +1 -0
  49. data/test/test_helper.rb +2 -2
  50. data/test/unit/models/sprint_test.rb +1 -1
  51. data/tmp/.keep +0 -0
  52. metadata +16 -5
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: f6c7d2f0537e31c913013579570a403c3ed71e62
4
- data.tar.gz: bae46e8b42c70baaeebef413cfe6b38fdc72aab1
3
+ metadata.gz: 7313503e6891a81d74ee02d5c9b06315dce2df20
4
+ data.tar.gz: aa75366ce3181bebdb91e6f883a1c8879adbcdf9
5
5
  SHA512:
6
- metadata.gz: 01c289fcc4cd1aaff9496d2273b3703d87184f9ec4d1742f518fdf0d3861215cae4ef92889ba952fa3e7a6b3fe09ed3d8c2278cd30b61aee1601900e24b055fd
7
- data.tar.gz: b2f67d2a12797f57aa6e246889c051b6a68ac5733eb743c433e75f21f12b3beb00def052249166e4c258c9af992abed167248d31b115e389bfd29cc274438e02
6
+ metadata.gz: db72d7a2dcc0808d565cd6a2262e63d1ab0ffb8b144b4a701086126d92c6f1f9ceb944352209ed35bbf5d8a5777ecf80c6186ac9e986ae1ebbf319a6f89bf537
7
+ data.tar.gz: 4a99188cdd551613eac66106a3b0a86e79df16a64dc6f019e74137fb9bccd562ebc0fde7c4a78e575283aeaeb7ee3f00619a74fd9c1cc5b0f6c167ee41ce24a4
data/.gitignore CHANGED
@@ -8,8 +8,10 @@
8
8
  /.bundle
9
9
 
10
10
  # Ignore all logfiles and tempfiles.
11
- /log/*.log
12
- /tmp
11
+ /log/*
12
+ /tmp/*
13
+ !/log/.keep
14
+ !/tmp/.keep
13
15
 
14
16
  # Ignore built gems
15
17
  /pkg
data/.travis.yml ADDED
@@ -0,0 +1,50 @@
1
+ # .travis.yml
2
+ language: ruby
3
+
4
+ # By default, Travis clones the last 50 commits
5
+ # git:
6
+ # depth: 50
7
+
8
+ rvm:
9
+
10
+ # I would use 2.3.0, but Travis loads that binary on-demand
11
+ # whereas it has the 2.2.0 binary handy for the Ruby VM.
12
+ # This saves about 20 seconds.
13
+ - 2.2.0
14
+
15
+ addons:
16
+
17
+ # Travis's default version is 9.1; but Houston uses jsonb columns
18
+ postgresql: "9.4"
19
+
20
+ services:
21
+ - postgresql
22
+
23
+ before_install:
24
+
25
+ # This fixes a bug with the build:
26
+ # https://github.com/travis-ci/travis-ci/issues/5239
27
+ - gem update bundler
28
+
29
+ # This is required so that the Rugged gem can
30
+ # build libgit2 with support for the SSH protocol
31
+ - sudo apt-get install libssh2-1-dev
32
+
33
+ before_script:
34
+
35
+ # Create the test database
36
+ - psql -c 'create database houston_core_test;' -U postgres
37
+
38
+ # Give the VM public and private SSH keys.
39
+ # These aren't secret: we don't need to authenticate as anyone,
40
+ # we just need the keys to be able to clone a public repo from
41
+ # GitHub via the SSH protocol.
42
+ - echo -e "Host *\n\tStrictHostKeyChecking no\n" >> ~/.ssh/config
43
+ - echo -e "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDkTcgXnHuqR0gbwegnr9Zxz4hTkjjV/SpgJNPJz7mo/HKNbx0rqjj1P0yGR053R9GSFFim2ut4NK9DPPUkQdyucw+DoLkYRHJmlJ4BNa9NTCD0sl+eSXO2969kZojCYSOgbmkCJx8mdgTwhzdgE/jhBrsY0hPE6pRTlU+H68/zeNdJUAIJf0LLXOm3hpTKLA19VICltl/j9VvBJpgRHdBylXEyL8HokYpjkQQk1ZXj3m7Nlo8yDdg4VcljOJWC+Xh8kxRMfK5x/VRVsYKCQXN5QlzKeqf7USRDUS/7mFoPUBW+d4kwKtGxRsWuIL2yeqzifZUTOgsh9+ZWAWxWffQZ your_email@example.com" > ~/.ssh/id_rsa.pub
44
+ - echo -e "-----BEGIN RSA PRIVATE KEY-----\nMIIEpAIBAAKCAQEA5E3IF5x7qkdIG8HoJ6/Wcc+IU5I41f0qYCTTyc+5qPxyjW8d\nK6o49T9MhkdOd0fRkhRYptrreDSvQzz1JEHcrnMPg6C5GERyZpSeATWvTUwg9LJf\nnklztvevZGaIwmEjoG5pAicfJnYE8Ic3YBP44Qa7GNITxOqUU5VPh+vP83jXSVAC\nCX9Cy1zpt4aUyiwNfVSApbZf4/VbwSaYER3QcpVxMi/B6JGKY5EEJNWV495uzZaP\nMg3YOFXJYziVgvl4fJMUTHyucf1UVbGCgkFzeUJcynqn+1EkQ1Ev+5haD1AVvneJ\nMCrRsUbFriC9snqs4n2VEzoLIffmVgFsVn30GQIDAQABAoIBAQDPQm2sQbti0mN8\nD4Uawl8D40v30n8WhUa7EbPTOmlqKAQ2sfDhex9KRbTLEmEBmImA/Eee8o9iCTIy\n8Fv8Fm6pUHt9G6Pti/XvemwW3Q3QNpSUkHqN0FDkgecQVqVBEb6uHo3mDm4RFINX\neOmkp30BjIK9/blEw1D0sFALLOEUPaDdPMwiXtFgqfrFSgpDET3TvQIwZ2LxxTm0\ncNmP3sCSlZHJNkZI4hBEWaaXR+V5/+C1qblDCo5blAWTcX3UzqrwUUJgFi6VnBuh\n7S9Q6+CEIU+4JRyWQNmY8YgZFaAp6IOr/kyfPxTP1+UEVVgcLn3WDYwfG9og0tmz\nfzlruAgBAoGBAPfz73Pey86tNZEanhJhbX8gVjzy2hvyhT0paHg0q/H6c1VWOtUH\nOwZ3Ns2xAZqJhlDqCHnQYSCZDly042U/theP4N8zo1APb4Yg4qdmXF9QE1+2M03r\nkS6138gU/CSCLf8pCYa6pA/GmsaXxloeJGLvT4fzOZRsVav80/92XHRhAoGBAOu2\nmKh4Gr1EjgN9QNbk9cQTSFDtlBEqO/0pTepvL73UvNp/BAn4iYZFU4WnklFVBSWc\nL84Sc732xU12TAbTTUsa6E7W29pS8u7zVTxlIdQIIU5pzDyU1pNNk2kpxzte5p3Y\nPDtniPFsoYLWoH0LpsKL93t2pLAj+IOkE6f3XBq5AoGAIKaYo5N1FxQr952frx/x\nQUpK0N/R5Ng8v18SiLG26rhmM5iVSrQXC7TrHI7wfR8a9tC6qP/NqnM9NuwC/bQ0\nEEo7/GhaWxKNRwZRkmWiSFLNGk9t1hbtGU+N1lUdFtmloPIQdRNiw0kN3JTj474Q\nYI7O1EItFORnK6yxZfR6HEECgYEA1CT7MGUoa8APsMRCXyaiq15Pb8bjxK8mXquW\nHLEFXuzhLCW1FORDoj0y9s/iuKC0iS0ROX8R/J7k5NrbgikbH8WP36UxKkYNr1IC\nHOFImPTYRSKjVsL+fIUNb1DSp3S6SsYbL7v3XJJQqtlQiDq8U8x1aQFXJ9C4EoLR\nzhKrKsECgYBtU/TSF/TATZY5XtrN9O+HX1Fbz70Ci8XgvioheVI2fezOcXPRzDcC\nOYPaCMNKA5E8gHdg4s0TN7uDvKTJ+KhSg2V7gZ39A28dHrJaRX7Nz4k6t2uEBjX9\na1JidpAIbJ+3w7+hj6L299tVZvS+Y/6Dz/uuEQGXfJg/l/5CCvQPsA==\n-----END RSA PRIVATE KEY-----" > ~/.ssh/id_rsa
45
+ - chmod 600 ~/.ssh/id_rsa*
46
+ - eval `ssh-agent -s`
47
+ - ssh-add ~/.ssh/id_rsa
48
+
49
+ script:
50
+ - script/cibuild
data/Gemfile CHANGED
@@ -16,9 +16,8 @@ group :test do
16
16
  gem "webmock", require: "webmock/minitest"
17
17
  gem "factory_girl_rails"
18
18
  gem "test_after_commit"
19
-
19
+
20
20
  # For Jenkins
21
- gem "therubyracer"
22
21
  gem "simplecov-json", require: false
23
22
  gem "minitest-reporters", require: false
24
23
  gem "minitest-reporters-turn_reporter", require: false
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- houston-core (0.7.0.beta4)
4
+ houston-core (0.7.0)
5
5
  activerecord-import
6
6
  activerecord-pluck_in_batches
7
7
  addressable (~> 2.3.8)
@@ -192,7 +192,6 @@ GEM
192
192
  jwt (1.5.4)
193
193
  launchy (2.4.3)
194
194
  addressable (~> 2.3)
195
- libv8 (3.16.14.13)
196
195
  loofah (2.0.3)
197
196
  nokogiri (>= 1.5.9)
198
197
  mail (2.6.4)
@@ -282,7 +281,6 @@ GEM
282
281
  thor (>= 0.18.1, < 2.0)
283
282
  rake (11.2.2)
284
283
  redcarpet (3.3.4)
285
- ref (2.0.0)
286
284
  responders (2.2.0)
287
285
  railties (>= 4.2.0, < 5.1)
288
286
  rest-client (1.8.0)
@@ -326,9 +324,6 @@ GEM
326
324
  activerecord
327
325
  test_after_commit (1.0.0)
328
326
  activerecord (>= 3.2)
329
- therubyracer (0.12.2)
330
- libv8 (~> 3.16.14.0)
331
- ref
332
327
  thor (0.19.1)
333
328
  thread_safe (0.3.5)
334
329
  tilt (2.0.5)
@@ -367,7 +362,6 @@ DEPENDENCIES
367
362
  shoulda-context
368
363
  simplecov-json
369
364
  test_after_commit
370
- therubyracer
371
365
  timecop
372
366
  webmock
373
367
 
data/README.md CHANGED
@@ -1,10 +1,14 @@
1
- # Houston Core [![Code Climate](https://codeclimate.com/github/houston/houston-core.png)](https://codeclimate.com/github/houston/houston-core)
1
+ # Houston Core
2
2
 
3
- ##### Mission Control for your projects and team
3
+ [![Gem Version](https://badge.fury.io/rb/houston-core.svg)](https://rubygems.org/gems/houston-core)
4
+ [![Code Climate](https://codeclimate.com/github/houston/houston-core.svg)](https://codeclimate.com/github/houston/houston-core)
5
+ [![Build Status](https://travis-ci.org/houston/houston-core.svg)](https://travis-ci.org/houston/houston-core)
6
+
7
+ Mission Control for your projects and teams.
4
8
 
5
9
  Houston interfaces with your version-control, ticket-tracking, continuous integration, and other systems to stitch together a picture of your projects and teams.
6
10
 
7
- It makes it easy to set up **triggers** and **notifications** like:
11
+ It makes it easy to set up **[triggers](https://github.com/houston/houston-core/wiki/Triggers)** to perform tasks like:
8
12
 
9
13
  - Resolving an exception report when a commit that mentions it is deployed
10
14
  - Slacking team members when a pull request is labeled or unlabeled
@@ -12,23 +16,26 @@ It makes it easy to set up **triggers** and **notifications** like:
12
16
 
13
17
  And it provides a foundation for custom views like **dashboards** and **reports**.
14
18
 
15
- Houston is also extensible through **[Modules](https://github.com/houston/houston-core/wiki/Modules)**.
16
-
19
+ Houston is also extensible through **[Modules](https://github.com/houston/houston-core/wiki/Modules)** like:
17
20
 
21
+ - [Houston::Slack](https://github.com/houston/houston-slack), which gives Houston the ability to listen to messages—and respond—via Slack
22
+ - [Houston::Alerts](https://github.com/houston/houston-alerts), which gives Houston the ability to treat tasks from arbitrary sources as a unified queue
23
+ - [Houston::Feedback](https://github.com/houston/houston-feedback), which adds a view for quickly importing, tagging, and searching customer feedback
24
+ - [Houston::Roadmaps](https://github.com/houston/houston-roadmaps), which adds a view for planning project milestones
18
25
 
19
- ## Getting Started with Houston
20
26
 
21
- ##### System Requirements
27
+ ## Requirements
22
28
 
23
29
  To use Houston, you must have
24
30
 
25
31
  - [Ruby 2.0+](https://www.ruby-lang.org/en/downloads)
26
32
  - [Postgres 9.4+](http://www.postgresql.org/download)
27
33
 
28
- ##### Hello World
34
+
35
+ ## Getting Started
29
36
 
30
37
  1. Install houston-core
31
-
38
+
32
39
  ```
33
40
  gem install houston-core
34
41
  ```
@@ -52,3 +59,8 @@ To use Houston, you must have
52
59
  ```
53
60
  bundle exec rails server
54
61
  ```
62
+
63
+
64
+ ## License
65
+
66
+ Houston is released under the [MIT License](http://www.opensource.org/licenses/MIT).
@@ -8,8 +8,29 @@ td.action-reliability {
8
8
  padding-right: 16px !important;
9
9
  }
10
10
 
11
- .action-success-rate {
12
- font-size: 0.75em;
13
- line-height: 20px;
14
- float: right;
11
+ .action-params {
12
+ pre {
13
+ border: none;
14
+ border-radius: 0;
15
+ background: 0;
16
+ font-size: 12px;
17
+ line-height: 16px;
18
+ max-width: 600px;
19
+ white-space: pre;
20
+ overflow-x: scroll;
21
+ margin: 0;
22
+ }
23
+
24
+ .action-params-short {
25
+ display: inline-block;
26
+ vertical-align: middle;
27
+ cursor: pointer;
28
+ margin: -6px -8px;
29
+
30
+ &:hover {
31
+ background: rgba(0, 136, 204, 0.08);
32
+ color: #0088cc;
33
+ }
34
+ }
35
+ .action-params-full { display: none; }
15
36
  }
@@ -56,7 +56,7 @@ h2.light {
56
56
  .task-worker { white-space: nowrap; }
57
57
 
58
58
  #average_effort {
59
- font-weight: 800;
59
+ font-weight: 700;
60
60
  }
61
61
  }
62
62
 
@@ -60,7 +60,7 @@
60
60
  .project-tests tbody {
61
61
  .test-suite-name {
62
62
  color: #777;
63
- font-weight: 800;
63
+ font-weight: 700;
64
64
  }
65
65
 
66
66
  .test-name {
@@ -24,7 +24,7 @@ h2.test-result-banner {
24
24
  font-size: 1.5em;
25
25
  margin: 0;
26
26
 
27
- .test-result-committer { font-weight: 800; }
27
+ .test-result-committer { font-weight: 700; }
28
28
  img { width: 1em; height: 1em; }
29
29
  }
30
30
  }
@@ -126,7 +126,7 @@ h2.test-result-banner {
126
126
  text-transform: uppercase;
127
127
  border-radius: 2px;
128
128
  color: white;
129
- font-weight: 800;
129
+ font-weight: 700;
130
130
  text-indent: 0;
131
131
 
132
132
  &.pass { color: #5DB64C; } // grass
@@ -186,7 +186,7 @@ $lightGray: #eee;
186
186
 
187
187
  .ticket-resolution {
188
188
  font-size: 0.88em;
189
- font-weight: 800;
189
+ font-weight: 700;
190
190
  color: #aaa;
191
191
 
192
192
  &::after { content: ':'; }
@@ -27,7 +27,7 @@
27
27
  url('<%= font_path("roboto-bold-webfont.woff") %>') format('woff'),
28
28
  url('<%= font_path("roboto-bold-webfont.ttf") %>') format('truetype'),
29
29
  url('<%= font_path("roboto-bold-webfont.svg") %>#robotobold') format('svg');
30
- font-weight: 800;
30
+ font-weight: 700;
31
31
  font-style: normal;
32
32
  }
33
33
 
@@ -71,7 +71,7 @@
71
71
  url('<%= font_path("roboto-bolditalic-webfont.woff") %>') format('woff'),
72
72
  url('<%= font_path("roboto-bolditalic-webfont.ttf") %>') format('truetype'),
73
73
  url('<%= font_path("roboto-bolditalic-webfont.svg") %>#robotobold_italic') format('svg');
74
- font-weight: 800;
74
+ font-weight: 700;
75
75
  font-style: italic;
76
76
  }
77
77
 
@@ -1,9 +1,10 @@
1
1
  class ActionsController < ApplicationController
2
2
 
3
3
  def index
4
- authorize! :show, :actions
4
+ authorize! :read, Action
5
5
 
6
- actions_by_name = Houston.actions.names.each_with_object({}) { |name, map| map[name] = { name: name } }
6
+ actions_by_name = Houston.actions.to_a.each_with_object({}) { |action, map|
7
+ map[action.name] = { name: action.name, required_params: action.required_params } }
7
8
  actions = Action.where(name: actions_by_name.keys)
8
9
 
9
10
  most_recent_actions = actions.joins(<<-SQL)
@@ -25,13 +26,20 @@ class ActionsController < ApplicationController
25
26
  end
26
27
 
27
28
  def show
28
- authorize! :show, :actions
29
+ authorize! :read, Action
29
30
  @action_name = params[:slug]
30
- @actions = Action.where(name: @action_name).preload(:error)
31
+ @actions = Action.where(name: @action_name).preload(:error).limit(50)
32
+ @actions = @actions.where(Action.arel_table[:started_at].lt(params[:before])) if params[:before]
33
+ render partial: "actions/actions" if request.xhr?
34
+ end
35
+
36
+ def running
37
+ authorize! :read, Action
38
+ @actions = Action.where(finished_at: nil)
31
39
  end
32
40
 
33
41
  def run
34
- authorize! :run, :actions
42
+ authorize! :run, Action
35
43
  Houston.actions.run params[:slug]
36
44
  redirect_to "/actions", notice: "#{params[:slug]} is running"
37
45
  end
@@ -1,8 +1,8 @@
1
1
  class ErrorsController < ApplicationController
2
2
 
3
3
  def index
4
- authorize! :show, Error
5
- @actions = Action.reorder(finished_at: :desc).where.not(error_id: nil).includes(:error).limit(50)
4
+ authorize! :read, Action
5
+ @actions = Action.reorder(finished_at: :desc).where.not(error_id: nil).preload(:error).limit(50)
6
6
  @actions = @actions.where(Action.arel_table[:finished_at].lt(params[:before])) if params[:before]
7
7
  render partial: "errors/actions" if request.xhr?
8
8
  end
@@ -50,7 +50,7 @@ class ReleasesController < ApplicationController
50
50
  authorize! :create, @release
51
51
 
52
52
  if @release.save
53
- ProjectNotification.release(@release).deliver! if params[:send_release_email]
53
+ Houston.deliver! ProjectNotification.release(@release) if params[:send_release_email]
54
54
  @release.tickets.resolve_all! if params[:resolve_tickets]
55
55
 
56
56
  redirect_to @release
@@ -1,7 +1,7 @@
1
1
  class TriggersController < ApplicationController
2
2
 
3
3
  def index
4
- authorize! :show, :triggers
4
+ authorize! :read, Action
5
5
  @triggers = Houston.triggers
6
6
  end
7
7
 
@@ -1,7 +1,42 @@
1
1
  module ActionsHelper
2
2
 
3
3
  def format_action_params(params)
4
- MultiJson.dump params
4
+ return "<pre>{}</pre>".html_safe if params == {}
5
+ <<-HTML.html_safe
6
+ <div class="action-params-short">
7
+ <pre>{ #{params.keys.map(&:inspect).join(", ")} }</pre>
8
+ </div>
9
+ <div class="action-params-full">
10
+ <pre>#{_add_white_space Houston::ParamsSerializer.new.dump(params)}</pre>
11
+ </div>
12
+ HTML
13
+ end
14
+
15
+ def _add_white_space(json)
16
+ scanner = StringScanner.new(json)
17
+ output = ""
18
+ indent = 0
19
+ until scanner.eos?
20
+ match = scanner.scan(/(?:[\[\]\{\}":,]|[^\[\]\{\}":,]+)/)
21
+ case match
22
+ when "{", "["
23
+ indent += 2
24
+ output << "#{match}\n#{" " * indent}"
25
+ when "}", "]"
26
+ indent -= 2
27
+ output << "\n#{" " * indent}#{match}"
28
+ when "\""
29
+ # hopefully this grabs the entire string
30
+ output << "\"" << scanner.scan(/.*?(?<!\\)"/)
31
+ when ":"
32
+ output << ": "
33
+ when ","
34
+ output << ",\n#{" " * indent}"
35
+ else
36
+ output << match
37
+ end
38
+ end
39
+ output
5
40
  end
6
41
 
7
42
  end
@@ -2,7 +2,9 @@ module NavigationHelper
2
2
 
3
3
  def render_navigation(key)
4
4
  renderer = Houston.get_navigation_renderer(key)
5
- instance_eval &renderer
5
+ return unless renderer.permitted?(current_ability)
6
+
7
+ render_nav_link renderer.name, renderer.path, icon: renderer.icon
6
8
  rescue KeyError
7
9
  Rails.logger.error "\e[31;1mThere is no navigation renderer named #{key.inspect}\e[0m"
8
10
  nil
@@ -20,6 +22,9 @@ module NavigationHelper
20
22
  return unless feature.permitted?(current_ability, current_project)
21
23
 
22
24
  render_nav_link feature.name, feature.project_path(current_project), icon: feature.icon
25
+ rescue KeyError
26
+ Rails.logger.error "\e[31;1mThere is no project feature named #{feature.inspect}\e[0m"
27
+ nil
23
28
  end
24
29
 
25
30
  def render_nav_menu(name, items: [], icon: "fa-circle-thin")
@@ -4,7 +4,7 @@ module Github
4
4
 
5
5
  self.table_name = "pull_requests"
6
6
 
7
- attr_readonly :project_id, :user_id, :repo, :number, :username, :base_ref, :base_sha, :url
7
+ attr_readonly :project_id, :user_id, :repo, :number, :username, :base_ref, :url
8
8
  attr_accessor :actor
9
9
 
10
10
  belongs_to :project
@@ -19,12 +19,14 @@ module Github
19
19
 
20
20
  after_create do
21
21
  Houston.observer.fire "github:pull:opened", pull_request: self
22
+ true
22
23
  end
23
24
 
24
25
  after_update do
25
26
  Houston.observer.fire "github:pull:updated", pull_request: self, changes: changes
26
27
  Houston.observer.fire "github:pull:closed", pull_request: self if closed_at_changed? && closed_at
27
28
  Houston.observer.fire "github:pull:reopened", pull_request: self if closed_at_changed? && !closed_at
29
+ true
28
30
  end
29
31
 
30
32
  validates :project_id, :title, :number, :repo, :url, :base_ref, :base_sha, :head_ref, :head_sha, :username, presence: true
@@ -88,8 +90,10 @@ module Github
88
90
 
89
91
  def sync!(projects = Project.unretired)
90
92
  expected_pulls = fetch!(projects)
93
+ existing_pulls = Houston.benchmark "Loading pull requests" do
94
+ open.where(project_id: projects.ids).to_a
95
+ end
91
96
  Houston.benchmark "Syncing pull requests" do
92
- existing_pulls = all.to_a
93
97
 
94
98
  # Fetch unexpected pulls so that we know
95
99
  # when they were closed and whether they
@@ -108,10 +112,15 @@ module Github
108
112
  expected_pr["base"]["repo"]["name"] == existing_pr.repo &&
109
113
  expected_pr["number"] == existing_pr.number }
110
114
 
115
+ # Maybe the pull request was closed?
116
+ existing_pr ||= where(repo: expected_pr["base"]["repo"]["name"], number: expected_pr["number"]).first
117
+
111
118
  existing_pr ||= Github::PullRequest.new
112
119
  existing_pr.merge_attributes(expected_pr)
113
- unless existing_pr.save
114
- Rails.logger.warn "\e[31m[pulls] Invalid PR: #{existing_pr.errors.full_messages.join("; ")}\e[0m"
120
+ if existing_pr.changes.any?
121
+ unless existing_pr.save
122
+ Rails.logger.warn "\e[31m[pulls] Invalid PR: #{existing_pr.errors.full_messages.join("; ")}\e[0m"
123
+ end
115
124
  end
116
125
  existing_pr
117
126
  end