Commit e77f238e661fdff86f4ee94c1c8262012ba592b5

Authored by Jared Pace
1 parent a689d49b
Exists in master and in 1 other branch production

Rename Project to App

Showing 44 changed files with 479 additions and 479 deletions   Show diff stats
app/controllers/apps_controller.rb 0 → 100644
... ... @@ -0,0 +1,50 @@
  1 +class AppsController < ApplicationController
  2 +
  3 + def index
  4 + @apps = App.all
  5 + end
  6 +
  7 + def show
  8 + @app = App.find(params[:id])
  9 + @errs = @app.errs.paginate
  10 + end
  11 +
  12 + def new
  13 + @app = App.new
  14 + @app.watchers.build
  15 + end
  16 +
  17 + def edit
  18 + @app = App.find(params[:id])
  19 + @app.watchers.build if @app.watchers.none?
  20 + end
  21 +
  22 + def create
  23 + @app = App.new(params[:app])
  24 +
  25 + if @app.save
  26 + flash[:success] = 'Great success! Configure your app with the API key below'
  27 + redirect_to app_path(@app)
  28 + else
  29 + render :new
  30 + end
  31 + end
  32 +
  33 + def update
  34 + @app = App.find(params[:id])
  35 +
  36 + if @app.update_attributes!(params[:app])
  37 + flash[:success] = "Good news everyone! '#{@app.name}' was successfully updated."
  38 + redirect_to app_path(@app)
  39 + else
  40 + render :edit
  41 + end
  42 + end
  43 +
  44 + def destroy
  45 + @app = App.find(params[:id])
  46 + @app.destroy
  47 + flash[:success] = "'#{@app.name}' was successfully destroyed."
  48 + redirect_to apps_path
  49 + end
  50 +end
... ...
app/controllers/deploys_controller.rb
1 1 class DeploysController < ApplicationController
2 2  
3 3 def create
4   - @project = Project.find_by_api_key!(params[:api_key])
5   - @deploy = @project.deploys.create!({
  4 + @app = App.find_by_api_key!(params[:api_key])
  5 + @deploy = @app.deploys.create!({
6 6 :username => params[:deploy][:local_username],
7 7 :environment => params[:deploy][:rails_env],
8 8 :repository => params[:deploy][:scm_repository],
... ...
app/controllers/errs_controller.rb
... ... @@ -9,15 +9,15 @@ class ErrsController &lt; ApplicationController
9 9 end
10 10  
11 11 def show
12   - @project = Project.find(params[:project_id])
13   - @err = @project.errs.find(params[:id])
  12 + @app = App.find(params[:app_id])
  13 + @err = @app.errs.find(params[:id])
14 14 @notices = @err.notices.ordered.paginate(:page => (params[:notice] || @err.notices.count), :per_page => 1)
15 15 @notice = @notices.first
16 16 end
17 17  
18 18 def resolve
19   - @project = Project.find(params[:project_id])
20   - @err = @project.errs.unresolved.find(params[:id])
  19 + @app = App.find(params[:app_id])
  20 + @err = @app.errs.unresolved.find(params[:id])
21 21  
22 22 # Deal with bug in mogoid where find is returning an Enumberable obj
23 23 @err = @err.first if @err.respond_to?(:first)
... ...
app/controllers/projects_controller.rb
... ... @@ -1,50 +0,0 @@
1   -class ProjectsController < ApplicationController
2   -
3   - def index
4   - @projects = Project.all
5   - end
6   -
7   - def show
8   - @project = Project.find(params[:id])
9   - @errs = @project.errs.paginate
10   - end
11   -
12   - def new
13   - @project = Project.new
14   - @project.watchers.build
15   - end
16   -
17   - def edit
18   - @project = Project.find(params[:id])
19   - @project.watchers.build if @project.watchers.none?
20   - end
21   -
22   - def create
23   - @project = Project.new(params[:project])
24   -
25   - if @project.save
26   - flash[:success] = 'Great success! Configure your project with the API key below'
27   - redirect_to project_path(@project)
28   - else
29   - render :new
30   - end
31   - end
32   -
33   - def update
34   - @project = Project.find(params[:id])
35   -
36   - if @project.update_attributes(params[:project])
37   - flash[:success] = "Good news everyone! '#{@project.name}' was successfully updated."
38   - redirect_to project_path(@project)
39   - else
40   - render :edit
41   - end
42   - end
43   -
44   - def destroy
45   - @project = Project.find(params[:id])
46   - @project.destroy
47   - flash[:success] = "'#{@project.name}' was successfully destroyed."
48   - redirect_to projects_path
49   - end
50   -end
app/mailers/mailer.rb
1 1 class Mailer < ActionMailer::Base
2   - default :from => App.email_from
3   - default_url_options[:host] = App.host
  2 + default :from => Errbit::Config.email_from
  3 + default_url_options[:host] = Errbit::Config.host
4 4  
5 5 def error_notification(notice)
6 6 @notice = notice
7   - @project = notice.err.project
  7 + @app = notice.err.app
8 8  
9 9 mail({
10   - :to => @project.watchers.map(&:email),
11   - :subject => "[#{@project.name}] #{@notice.err.message}"
  10 + :to => @app.watchers.map(&:email),
  11 + :subject => "[#{@app.name}] #{@notice.err.message}"
12 12 })
13 13 end
14 14  
15 15 def deploy_notification(deploy)
16 16 @deploy = deploy
17   - @project = deploy.project
  17 + @app = deploy.app
18 18  
19 19 mail({
20   - :to => @project.watchers.map(&:email),
21   - :subject => "[#{@project.name}] Deployed to #{@deploy.environment} by #{@deploy.username}"
  20 + :to => @app.watchers.map(&:email),
  21 + :subject => "[#{@app.name}] Deployed to #{@deploy.environment} by #{@deploy.username}"
22 22 })
23 23 end
24 24  
... ...
app/models/app.rb 0 → 100644
... ... @@ -0,0 +1,36 @@
  1 +class App
  2 + include Mongoid::Document
  3 + include Mongoid::Timestamps
  4 +
  5 + field :name, :type => String
  6 + field :api_key
  7 + field :resolve_errs_on_deploy, :type => Boolean, :default => false
  8 + key :name
  9 +
  10 + embeds_many :watchers
  11 + embeds_many :deploys
  12 + references_many :errs, :dependent => :destroy
  13 +
  14 + before_validation :generate_api_key, :on => :create
  15 +
  16 + validates_presence_of :name, :api_key
  17 + validates_uniqueness_of :name, :api_key, :allow_blank => true, :on => :create
  18 +
  19 + accepts_nested_attributes_for :watchers, :allow_destroy => true,
  20 + :reject_if => proc { |attrs| attrs.all? { |k, v| v.blank? } }
  21 +
  22 + def self.find_by_api_key!(key)
  23 + where(:api_key => key).first || raise(Mongoid::Errors::DocumentNotFound.new(self,key))
  24 + end
  25 +
  26 + def last_deploy_at
  27 + deploys.last && deploys.last.created_at
  28 + end
  29 +
  30 + protected
  31 +
  32 + def generate_api_key
  33 + self.api_key ||= ActiveSupport::SecureRandom.hex
  34 + end
  35 +
  36 +end
... ...
app/models/deploy.rb
... ... @@ -7,10 +7,10 @@ class Deploy
7 7 field :environment
8 8 field :revision
9 9  
10   - embedded_in :project, :inverse_of => :deploys
  10 + embedded_in :app, :inverse_of => :deploys
11 11  
12 12 after_create :deliver_notification, :if => :should_notify?
13   - after_create :resolve_project_errs, :if => :should_resolve_project_errs?
  13 + after_create :resolve_app_errs, :if => :should_resolve_app_errs?
14 14  
15 15 validates_presence_of :username, :environment
16 16  
... ... @@ -18,18 +18,18 @@ class Deploy
18 18 Mailer.deploy_notification(self).deliver
19 19 end
20 20  
21   - def resolve_project_errs
22   - project.errs.unresolved.each {|err| err.resolve!}
  21 + def resolve_app_errs
  22 + app.errs.unresolved.each {|err| err.resolve!}
23 23 end
24 24  
25 25 protected
26 26  
27 27 def should_notify?
28   - project.watchers.any?
  28 + app.watchers.any?
29 29 end
30 30  
31   - def should_resolve_project_errs?
32   - project.resolve_errs_on_deploy?
  31 + def should_resolve_app_errs?
  32 + app.resolve_errs_on_deploy?
33 33 end
34 34  
35 35 end
... ...
app/models/err.rb
... ... @@ -10,7 +10,7 @@ class Err
10 10 field :last_notice_at, :type => DateTime
11 11 field :resolved, :type => Boolean, :default => false
12 12  
13   - referenced_in :project
  13 + referenced_in :app
14 14 embeds_many :notices
15 15  
16 16 validates_presence_of :klass, :environment
... ... @@ -20,8 +20,8 @@ class Err
20 20 scope :ordered, order_by(:last_notice_at.desc)
21 21  
22 22 def self.for(attrs)
23   - project = attrs.delete(:project)
24   - project.errs.unresolved.where(attrs).first || project.errs.create!(attrs)
  23 + app = attrs.delete(:app)
  24 + app.errs.unresolved.where(attrs).first || app.errs.create!(attrs)
25 25 end
26 26  
27 27 def resolve!
... ...
app/models/notice.rb
... ... @@ -21,13 +21,13 @@ class Notice
21 21  
22 22 def self.from_xml(hoptoad_xml)
23 23 hoptoad_notice = Hoptoad::V2.parse_xml(hoptoad_xml)
24   - project = Project.find_by_api_key!(hoptoad_notice['api-key'])
  24 + app = App.find_by_api_key!(hoptoad_notice['api-key'])
25 25  
26 26 hoptoad_notice['request']['component'] = 'unknown' if hoptoad_notice['request']['component'].blank?
27 27 hoptoad_notice['request']['action'] = nil if hoptoad_notice['request']['action'].blank?
28 28  
29 29 error = Err.for({
30   - :project => project,
  30 + :app => app,
31 31 :klass => hoptoad_notice['error']['class'],
32 32 :component => hoptoad_notice['request']['component'],
33 33 :action => hoptoad_notice['request']['action'],
... ... @@ -71,7 +71,7 @@ class Notice
71 71 protected
72 72  
73 73 def should_notify?
74   - App.email_at_notices.include?(err.notices.count) && err.project.watchers.any?
  74 + Errbit::Config.email_at_notices.include?(err.notices.count) && err.app.watchers.any?
75 75 end
76 76  
77 77 end
78 78 \ No newline at end of file
... ...
app/models/project.rb
... ... @@ -1,36 +0,0 @@
1   -class Project
2   - include Mongoid::Document
3   - include Mongoid::Timestamps
4   -
5   - field :name, :type => String
6   - field :api_key
7   - field :resolve_errs_on_deploy, :type => Boolean, :default => false
8   - key :name
9   -
10   - embeds_many :watchers
11   - embeds_many :deploys
12   - references_many :errs, :dependent => :destroy
13   -
14   - before_validation :generate_api_key, :on => :create
15   -
16   - validates_presence_of :name, :api_key
17   - validates_uniqueness_of :name, :api_key, :allow_blank => true
18   -
19   - accepts_nested_attributes_for :watchers, :allow_destroy => true,
20   - :reject_if => proc { |attrs| attrs.all? { |k, v| v.blank? } }
21   -
22   - def self.find_by_api_key!(key)
23   - where(:api_key => key).first || raise(Mongoid::Errors::DocumentNotFound.new(self,key))
24   - end
25   -
26   - def last_deploy_at
27   - deploys.last && deploys.last.created_at
28   - end
29   -
30   - protected
31   -
32   - def generate_api_key
33   - self.api_key ||= ActiveSupport::SecureRandom.hex
34   - end
35   -
36   -end
app/models/watcher.rb
... ... @@ -4,7 +4,7 @@ class Watcher
4 4  
5 5 field :email
6 6  
7   - embedded_in :project, :inverse_of => :watchers
  7 + embedded_in :app, :inverse_of => :watchers
8 8  
9 9 validates_presence_of :email
10 10  
... ...
app/views/apps/_configuration_instructions.html.haml 0 → 100644
... ... @@ -0,0 +1,21 @@
  1 +%pre
  2 + %code
  3 + :preserve
  4 +
  5 + # Require the hoptoad_notifier gem in you App.
  6 + #
  7 + # Rails 3 - In your Gemfile
  8 + # gem 'hoptoad_notifier'
  9 + #
  10 + # Rails 2 - In environment.rb
  11 + # config.gem 'hoptoad_notifier'
  12 + #
  13 + # Then add the following to config/initializers/hoptoad.rb
  14 + HoptoadNotifier.configure do |config|
  15 + config.api_key = '#{app.api_key}'
  16 + config.host = '#{request.host}'
  17 + config.port = #{request.port}
  18 + # Note: Deployment notifications only work on port 80
  19 + end
  20 +
  21 +
0 22 \ No newline at end of file
... ...
app/views/apps/_fields.html.haml 0 → 100644
... ... @@ -0,0 +1,14 @@
  1 +%div.required
  2 + = f.label :name
  3 + = f.text_field :name
  4 +
  5 +%div.checkbox
  6 + = f.check_box :resolve_errs_on_deploy
  7 + = f.label :resolve_errs_on_deploy, 'Resolve errors on deploy'
  8 +
  9 +%fieldset.nested-wrapper
  10 + %legend Watchers
  11 + - f.fields_for :watchers do |w|
  12 + %div.nested
  13 + = w.label :email
  14 + = w.text_field :email
0 15 \ No newline at end of file
... ...
app/views/apps/edit.html.haml 0 → 100644
... ... @@ -0,0 +1,8 @@
  1 +- content_for :title, 'Edit App'
  2 +- content_for :action_bar, link_to('cancel', app_path(@app))
  3 +
  4 += form_for @app do |f|
  5 +
  6 + = render 'fields', :f => f
  7 +
  8 + %div= f.submit 'Update'
0 9 \ No newline at end of file
... ...
app/views/apps/index.html.haml 0 → 100644
... ... @@ -0,0 +1,26 @@
  1 +- content_for :title, 'Apps'
  2 +- content_for :action_bar do
  3 + %span= link_to('Add a New App', new_app_path, :class => 'add')
  4 +
  5 +%table.apps
  6 + %thead
  7 + %tr
  8 + %th Name
  9 + %th Last Deploy
  10 + %th Errors
  11 + %tbody
  12 + - @apps.each do |app|
  13 + %tr
  14 + %td.name= link_to app.name, app_path(app)
  15 + %td.deploy= app.last_deploy_at ? app.last_deploy_at.to_s(:micro) : 'n/a'
  16 + %td.count
  17 + - if app.errs.any?
  18 + = link_to app.errs.unresolved.count, app_errs_path(app)
  19 + - else
  20 + \-
  21 + - if @apps.none?
  22 + %tr
  23 + %td{:colspan => 3}
  24 + %em
  25 + No apps here.
  26 + = link_to 'Click here to create your first one', new_app_path
0 27 \ No newline at end of file
... ...
app/views/apps/new.html.haml 0 → 100644
... ... @@ -0,0 +1,8 @@
  1 +- content_for :title, 'Add App'
  2 +- content_for :action_bar, link_to('cancel', apps_path)
  3 +
  4 += form_for @app do |f|
  5 +
  6 + = render 'fields', :f => f
  7 +
  8 + %div= f.submit 'Add'
0 9 \ No newline at end of file
... ...
app/views/apps/show.html.haml 0 → 100644
... ... @@ -0,0 +1,31 @@
  1 +- content_for :title, @app.name
  2 +- content_for :meta do
  3 + %strong Errors Caught:
  4 + = @app.errs.count
  5 + %strong API Key:
  6 + = @app.api_key
  7 +- content_for :action_bar do
  8 + = link_to 'edit', edit_app_path(@app)
  9 + |
  10 + = link_to 'destroy', app_path(@app), :method => :delete, :confirm => 'Seriously?'
  11 +
  12 +- if @app.errs.none?
  13 + %h3 Setup your app
  14 + = render 'configuration_instructions', :app => @app
  15 +
  16 +%h3 Watchers
  17 +%table.watchers
  18 + %thead
  19 + %tr
  20 + %th Email
  21 + %tbody
  22 + - @app.watchers.each do |watcher|
  23 + %tr
  24 + %td= watcher.email
  25 + - if @app.watchers.none?
  26 + %tr
  27 + %td
  28 + %em Sadly, no one is watching this app
  29 +
  30 +%h3 Errors
  31 += render 'errs/table', :errs => @errs
0 32 \ No newline at end of file
... ...
app/views/errs/_table.html.haml
... ... @@ -2,8 +2,8 @@
2 2 %thead
3 3 %tr
4 4 %th
5   - - unless @project
6   - %th Project
  5 + - unless @app
  6 + %th App
7 7 %th What &amp; Where
8 8 %th Latest
9 9 %th Deploy
... ... @@ -13,15 +13,15 @@
13 13 %tr
14 14 %td.environment
15 15 %abbr{:title => err.environment}= err.environment.chars.first.upcase
16   - - unless @project
17   - %td.project= err.project.name
  16 + - unless @app
  17 + %td.app= err.app.name
18 18 %td.message
19   - = link_to err.message, project_err_path(err.project, err)
  19 + = link_to err.message, app_err_path(err.app, err)
20 20 %em= err.where
21 21 %td.latest #{time_ago_in_words(err.last_notice_at)} ago
22   - %td.deploy= err.project.last_deploy_at ? err.project.last_deploy_at.to_s(:micro) : 'n/a'
  22 + %td.deploy= err.app.last_deploy_at ? err.app.last_deploy_at.to_s(:micro) : 'n/a'
23 23 %td.count= err.notices.count
24 24 - if errs.none?
25 25 %tr
26   - %td{:colspan => (@project ? 5 : 6)}
  26 + %td{:colspan => (@app ? 5 : 6)}
27 27 %em No errors have been caught, yet
28 28 \ No newline at end of file
... ...
app/views/errs/show.html.haml
... ... @@ -11,9 +11,9 @@
11 11 - content_for :action_bar do
12 12 = will_paginate @notices, :param_name => :notice, :page_links => false
13 13 .float-left viewing occurrence #{@notices.current_page} of #{@notices.total_pages}
14   - = link_to "back to '#{@project.name}'", project_path(@project)
  14 + = link_to "back to '#{@app.name}'", app_path(@app)
15 15 |
16   - = link_to 'resolve', resolve_project_err_path(@project, @err), :method => :put, :confirm => 'Seriously?' if @err.unresolved?
  16 + = link_to 'resolve', resolve_app_err_path(@app, @err), :method => :put, :confirm => 'Seriously?' if @err.unresolved?
17 17  
18 18 %h3#summary Summary
19 19 = render 'notices/summary', :notice => @notice
... ...
app/views/mailer/deploy_notification.text.erb
1   -<%= @project.name %> was just deployed to <%= @deploy.environment %> by <%= @deploy.username %>.
  1 +<%= @app.name %> was just deployed to <%= @deploy.environment %> by <%= @deploy.username %>.
2 2  
3 3 Details:
4 4  
5   - What: <%= @project.name %><%= "@#{@deploy.revision}" unless @deploy.revision.blank? %>
  5 + What: <%= @app.name %><%= "@#{@deploy.revision}" unless @deploy.revision.blank? %>
6 6 When: <%= @deploy.created_at.to_s %>
7 7 From: <%= @deploy.repository.blank? ? 'n/a' : @deploy.repository %>
8 8  
... ...
app/views/mailer/error_notification.text.erb
... ... @@ -2,6 +2,6 @@ An error has just occurred in &lt;%= @notice.err.environment %&gt;: &lt;%= @notice.err.me
2 2  
3 3 This error has occurred <%= pluralize @notice.err.notices.count, 'time' %>. You should really look into it here:
4 4  
5   - <%= project_err_notice_url(@project, @notice.err, @notice) %>
  5 + <%= app_err_notice_url(@app, @notice.err, @notice) %>
6 6  
7 7 <%= render :partial => 'signature' %>
8 8 \ No newline at end of file
... ...
app/views/notices/_backtrace.html.haml
... ... @@ -8,8 +8,8 @@
8 8 %td
9 9 %ul.lines
10 10 - lines.each do |line|
11   - - in_project = line['file'].gsub!('[PROJECT_ROOT]','') && !line['file'].match(/^\/vendor\//)
12   - %li{:class => (in_project ? 'in-project' : nil)}
  11 + - in_app = line['file'].gsub!('[PROJECT_ROOT]','') && !line['file'].match(/^\/vendor\//)
  12 + %li{:class => (in_app ? 'in-app' : nil)}
13 13 = line['file']
14 14 &rarr;
15 15 %strong= line['method']
16 16 \ No newline at end of file
... ...
app/views/projects/_configuration_instructions.html.haml
... ... @@ -1,21 +0,0 @@
1   -%pre
2   - %code
3   - :preserve
4   -
5   - # Require the hoptoad_notifier gem in you App.
6   - #
7   - # Rails 3 - In your Gemfile
8   - # gem 'hoptoad_notifier'
9   - #
10   - # Rails 2 - In environment.rb
11   - # config.gem 'hoptoad_notifier'
12   - #
13   - # Then add the following to config/initializers/hoptoad.rb
14   - HoptoadNotifier.configure do |config|
15   - config.api_key = '#{project.api_key}'
16   - config.host = '#{request.host}'
17   - config.port = #{request.port}
18   - # Note: Deployment notifications only work on port 80
19   - end
20   -
21   -
22 0 \ No newline at end of file
app/views/projects/_fields.html.haml
... ... @@ -1,14 +0,0 @@
1   -%div.required
2   - = f.label :name
3   - = f.text_field :name
4   -
5   -%div.checkbox
6   - = f.check_box :resolve_errs_on_deploy
7   - = f.label :resolve_errs_on_deploy, 'Resolve errors on deploy'
8   -
9   -%fieldset.nested-wrapper
10   - %legend Watchers
11   - - f.fields_for :watchers do |w|
12   - %div.nested
13   - = w.label :email
14   - = w.text_field :email
15 0 \ No newline at end of file
app/views/projects/edit.html.haml
... ... @@ -1,8 +0,0 @@
1   -- content_for :title, 'Edit Project'
2   -- content_for :action_bar, link_to('cancel', project_path(@project))
3   -
4   -= form_for @project do |f|
5   -
6   - = render 'fields', :f => f
7   -
8   - %div= f.submit 'Update'
9 0 \ No newline at end of file
app/views/projects/index.html.haml
... ... @@ -1,26 +0,0 @@
1   -- content_for :title, 'Apps'
2   -- content_for :action_bar do
3   - %span= link_to('Add a New App', new_project_path, :class => 'add')
4   -
5   -%table.projects
6   - %thead
7   - %tr
8   - %th Name
9   - %th Last Deploy
10   - %th Errors
11   - %tbody
12   - - @projects.each do |project|
13   - %tr
14   - %td.name= link_to project.name, project_path(project)
15   - %td.deploy= project.last_deploy_at ? project.last_deploy_at.to_s(:micro) : 'n/a'
16   - %td.count
17   - - if project.errs.any?
18   - = link_to project.errs.unresolved.count, project_errs_path(project)
19   - - else
20   - \-
21   - - if @projects.none?
22   - %tr
23   - %td{:colspan => 3}
24   - %em
25   - No projects here.
26   - = link_to 'Click here to create your first one', new_project_path
27 0 \ No newline at end of file
app/views/projects/new.html.haml
... ... @@ -1,8 +0,0 @@
1   -- content_for :title, 'Add Project'
2   -- content_for :action_bar, link_to('cancel', projects_path)
3   -
4   -= form_for @project do |f|
5   -
6   - = render 'fields', :f => f
7   -
8   - %div= f.submit 'Add'
9 0 \ No newline at end of file
app/views/projects/show.html.haml
... ... @@ -1,31 +0,0 @@
1   -- content_for :title, @project.name
2   -- content_for :meta do
3   - %strong Errors Caught:
4   - = @project.errs.count
5   - %strong API Key:
6   - = @project.api_key
7   -- content_for :action_bar do
8   - = link_to 'edit', edit_project_path(@project)
9   - |
10   - = link_to 'destroy', project_path(@project), :method => :delete, :confirm => 'Seriously?'
11   -
12   -- if @project.errs.none?
13   - %h3 Setup your app
14   - = render 'configuration_instructions', :project => @project
15   -
16   -%h3 Watchers
17   -%table.watchers
18   - %thead
19   - %tr
20   - %th Email
21   - %tbody
22   - - @project.watchers.each do |watcher|
23   - %tr
24   - %td= watcher.email
25   - - if @project.watchers.none?
26   - %tr
27   - %td
28   - %em Sadly, no one is watching this project
29   -
30   -%h3 Errors
31   -= render 'errs/table', :errs => @errs
32 0 \ No newline at end of file
app/views/shared/_navigation.html.haml
1 1 #nav-bar
2 2 %ul
3 3 //%li= link_to 'Dashboard', admin_dashboard_path, :class => active_if_here(:dashboards)
4   - %li.projects{:class => active_if_here(:projects)}= link_to 'Apps', projects_path
  4 + %li.apps{:class => active_if_here(:apps)}= link_to 'Apps', apps_path
5 5 %li.errors{:class => active_if_here(:errs)}= link_to 'Errs', errs_path
6 6 %div.clear
7 7 \ No newline at end of file
... ...
config/initializers/load_config.rb
... ... @@ -5,4 +5,4 @@ config = YAML.load(yaml)
5 5  
6 6 config.merge!(config.delete(Rails.env)) if config.has_key?(Rails.env)
7 7  
8   -::App = OpenStruct.new(config)
9 8 \ No newline at end of file
  9 +Errbit::Config = OpenStruct.new(config)
10 10 \ No newline at end of file
... ...
config/routes.rb
... ... @@ -12,7 +12,7 @@ Errbit::Application.routes.draw do
12 12 resources :notices, :only => [:show]
13 13 resources :deploys, :only => [:show]
14 14  
15   - resources :projects do
  15 + resources :apps do
16 16 resources :errs do
17 17 resources :notices
18 18 member do
... ... @@ -21,6 +21,6 @@ Errbit::Application.routes.draw do
21 21 end
22 22 end
23 23  
24   - root :to => 'projects#index'
  24 + root :to => 'apps#index'
25 25  
26 26 end
... ...
public/stylesheets/application.css
... ... @@ -86,7 +86,7 @@ header #site-name {
86 86 background: transparent 10px 8px no-repeat;
87 87 }
88 88 #nav-bar li a:hover { color: #666;}
89   -#nav-bar li.projects a { background-image: url(images/icons/briefcase.png); }
  89 +#nav-bar li.apps a { background-image: url(images/icons/briefcase.png); }
90 90 #nav-bar li.errors a { background-image: url(images/icons/error.png); }
91 91 #nav-bar li:hover {
92 92 box-shadow: 0 0 3px #69c;
... ... @@ -283,10 +283,10 @@ pre {
283 283 color: #AAA;
284 284 }
285 285  
286   -/* Projects Table */
287   -table.projects tbody tr:hover td ,table.errs tbody tr:hover td { background-color: #F2F2F2;}
  286 +/* Apps Table */
  287 +table.apps tbody tr:hover td ,table.errs tbody tr:hover td { background-color: #F2F2F2;}
288 288  
289   -table.projects td.name, table.errs td.message {
  289 +table.apps td.name, table.errs td.message {
290 290 width: 100%;
291 291 }
292 292 td.deploy {
... ... @@ -349,7 +349,7 @@ table.backtrace ul.lines {
349 349 table.backtrace li {
350 350 white-space: nowrap;
351 351 }
352   -table.backtrace li.in-project {
  352 +table.backtrace li.in-app {
353 353 color: #2adb2e;
354 354 background-color: #2f2f2f;
355 355 }
356 356 \ No newline at end of file
... ...
spec/controllers/apps_controller_spec.rb 0 → 100644
... ... @@ -0,0 +1,128 @@
  1 +require 'spec_helper'
  2 +
  3 +describe AppsController do
  4 +
  5 + describe "GET /apps" do
  6 + it 'finds all apps' do
  7 + 3.times { Factory(:app) }
  8 + apps = App.all
  9 + get :index
  10 + assigns(:apps).should == apps
  11 + end
  12 + end
  13 +
  14 + describe "GET /apps/:id" do
  15 + it 'finds the app' do
  16 + app = Factory(:app)
  17 + get :show, :id => app.id
  18 + assigns(:app).should == app
  19 + end
  20 + end
  21 +
  22 + describe "GET /apps/new" do
  23 + it 'instantiates a new app with a prebuilt watcher' do
  24 + get :new
  25 + assigns(:app).should be_a(App)
  26 + assigns(:app).should be_new_record
  27 + assigns(:app).watchers.should_not be_empty
  28 + end
  29 + end
  30 +
  31 + describe "GET /apps/:id/edit" do
  32 + it 'finds the correct app' do
  33 + app = Factory(:app)
  34 + get :edit, :id => app.id
  35 + assigns(:app).should == app
  36 + end
  37 + end
  38 +
  39 + describe "POST /apps" do
  40 + before do
  41 + @app = Factory(:app)
  42 + App.stub(:new).and_return(@app)
  43 + end
  44 +
  45 + context "when the create is successful" do
  46 + before do
  47 + @app.should_receive(:save).and_return(true)
  48 + end
  49 +
  50 + it "should redirect to the app page" do
  51 + post :create, :app => {}
  52 + response.should redirect_to(app_path(@app))
  53 + end
  54 +
  55 + it "should display a message" do
  56 + post :create, :app => {}
  57 + request.flash[:success].should match(/success/)
  58 + end
  59 + end
  60 +
  61 + context "when the create is unsuccessful" do
  62 + it "should render the new page" do
  63 + @app.should_receive(:save).and_return(false)
  64 + post :create, :app => {}
  65 + response.should render_template(:new)
  66 + end
  67 + end
  68 + end
  69 +
  70 + describe "PUT /apps/:id" do
  71 + before do
  72 + @app = Factory(:app)
  73 + App.stub(:find).with(@app.id).and_return(@app)
  74 + end
  75 +
  76 + context "when the update is successful" do
  77 + before do
  78 + @app.should_receive(:update_attributes).and_return(true)
  79 + end
  80 +
  81 + it "should redirect to the app page" do
  82 + put :update, :id => @app.id, :app => {}
  83 + response.should redirect_to(app_path(@app))
  84 + end
  85 +
  86 + it "should display a message" do
  87 + put :update, :id => @app.id, :app => {}
  88 + request.flash[:success].should match(/success/)
  89 + end
  90 + end
  91 +
  92 + context "when the update is unsuccessful" do
  93 + it "should render the edit page" do
  94 + @app.should_receive(:update_attributes).and_return(false)
  95 + put :update, :id => @app.id, :app => {}
  96 + response.should render_template(:edit)
  97 + end
  98 + end
  99 + end
  100 +
  101 + describe "DELETE /apps/:id" do
  102 + before do
  103 + @app = Factory(:app)
  104 + App.stub(:find).with(@app.id).and_return(@app)
  105 + end
  106 +
  107 + it "should find the app" do
  108 + delete :destroy, :id => @app.id
  109 + assigns(:app).should == @app
  110 + end
  111 +
  112 + it "should destroy the app" do
  113 + @app.should_receive(:destroy)
  114 + delete :destroy, :id => @app.id
  115 + end
  116 +
  117 + it "should display a message" do
  118 + delete :destroy, :id => @app.id
  119 + request.flash[:success].should match(/success/)
  120 + end
  121 +
  122 + it "should redirect to the apps page" do
  123 + delete :destroy, :id => @app.id
  124 + response.should redirect_to(apps_path)
  125 + end
  126 + end
  127 +
  128 +end
... ...
spec/controllers/deploys_controller_spec.rb
... ... @@ -10,17 +10,17 @@ describe DeploysController do
10 10 'rails_env' => 'production',
11 11 'scm_revision' => '19d77837eef37902cf5df7e4445c85f392a8d0d5'
12 12 }
13   - @project = Factory(:project_with_watcher, :api_key => 'APIKEY')
  13 + @app = Factory(:app_with_watcher, :api_key => 'APIKEY')
14 14 end
15 15  
16   - it 'finds the project via the api key' do
17   - Project.should_receive(:find_by_api_key!).with('APIKEY').and_return(@project)
  16 + it 'finds the app via the api key' do
  17 + App.should_receive(:find_by_api_key!).with('APIKEY').and_return(@app)
18 18 post :create, :deploy => @params, :api_key => 'APIKEY'
19 19 end
20 20  
21 21 it 'creates a deploy' do
22   - Project.stub(:find_by_api_key!).and_return(@project)
23   - @project.deploys.should_receive(:create!).
  22 + App.stub(:find_by_api_key!).and_return(@app)
  23 + @app.deploys.should_receive(:create!).
24 24 with({
25 25 :username => 'john.doe',
26 26 :environment => 'production',
... ... @@ -33,8 +33,8 @@ describe DeploysController do
33 33 it 'sends an email notification', :focused => true do
34 34 post :create, :deploy => @params, :api_key => 'APIKEY'
35 35 email = ActionMailer::Base.deliveries.last
36   - email.to.should include(@project.watchers.first.email)
37   - email.subject.should == "[#{@project.name}] Deployed to production by john.doe"
  36 + email.to.should include(@app.watchers.first.email)
  37 + email.subject.should == "[#{@app.name}] Deployed to production by john.doe"
38 38 end
39 39  
40 40 end
... ...
spec/controllers/errs_controller_spec.rb
... ... @@ -2,8 +2,8 @@ require &#39;spec_helper&#39;
2 2  
3 3 describe ErrsController do
4 4  
5   - let(:project) { Factory(:project) }
6   - let(:err) { Factory(:err, :project => project) }
  5 + let(:app) { Factory(:app) }
  6 + let(:err) { Factory(:err, :app => app) }
7 7  
8 8 describe "GET /errs" do
9 9 it "gets a paginated list of unresolved errors" do
... ... @@ -30,61 +30,61 @@ describe ErrsController do
30 30 end
31 31 end
32 32  
33   - describe "GET /projects/:project_id/errs/:id" do
  33 + describe "GET /apps/:app_id/errs/:id" do
34 34 before do
35 35 3.times { Factory(:notice, :err => err)}
36 36 end
37 37  
38   - it "finds the project" do
39   - get :show, :project_id => project.id, :id => err.id
40   - assigns(:project).should == project
  38 + it "finds the app" do
  39 + get :show, :app_id => app.id, :id => err.id
  40 + assigns(:app).should == app
41 41 end
42 42  
43 43 it "finds the err" do
44   - get :show, :project_id => project.id, :id => err.id
  44 + get :show, :app_id => app.id, :id => err.id
45 45 assigns(:err).should == err
46 46 end
47 47  
48 48 it "paginates the notices, 1 at a time" do
49   - Project.stub(:find).with(project.id).and_return(project)
50   - project.errs.stub(:find).with(err.id).and_return(err)
  49 + App.stub(:find).with(app.id).and_return(app)
  50 + app.errs.stub(:find).with(err.id).and_return(err)
51 51 err.notices.should_receive(:ordered).and_return(proxy = stub('proxy'))
52 52 proxy.should_receive(:paginate).with(:page => 3, :per_page => 1).
53 53 and_return(WillPaginate::Collection.new(1,1) << err.notices.first)
54   - get :show, :project_id => project.id, :id => err.id
  54 + get :show, :app_id => app.id, :id => err.id
55 55 end
56 56 end
57 57  
58   - describe "PUT /projects/:project_id/errs/:id/resolve" do
  58 + describe "PUT /apps/:app_id/errs/:id/resolve" do
59 59 before do
60 60 @err = Factory(:err)
61   - Project.stub(:find).with(@err.project.id).and_return(@err.project)
62   - @err.project.errs.stub(:unresolved).
  61 + App.stub(:find).with(@err.app.id).and_return(@err.app)
  62 + @err.app.errs.stub(:unresolved).
63 63 and_return(stub('proxy', :find => @err))
64 64 @err.stub(:resolve!)
65 65 end
66 66  
67   - it 'finds the project and the err' do
68   - Project.should_receive(:find).with(@err.project.id).and_return(@err.project)
69   - @err.project.errs.should_receive(:unresolved).
  67 + it 'finds the app and the err' do
  68 + App.should_receive(:find).with(@err.app.id).and_return(@err.app)
  69 + @err.app.errs.should_receive(:unresolved).
70 70 and_return(mock('proxy', :find => @err))
71   - put :resolve, :project_id => @err.project.id, :id => @err.id
72   - assigns(:project).should == @err.project
  71 + put :resolve, :app_id => @err.app.id, :id => @err.id
  72 + assigns(:app).should == @err.app
73 73 assigns(:err).should == @err
74 74 end
75 75  
76 76 it "should resolve the issue" do
77 77 @err.should_receive(:resolve!).and_return(true)
78   - put :resolve, :project_id => @err.project.id, :id => @err.id
  78 + put :resolve, :app_id => @err.app.id, :id => @err.id
79 79 end
80 80  
81 81 it "should display a message" do
82   - put :resolve, :project_id => @err.project.id, :id => @err.id
  82 + put :resolve, :app_id => @err.app.id, :id => @err.id
83 83 request.flash[:success].should match(/Great news/)
84 84 end
85 85  
86 86 it "should redirect do the errs page" do
87   - put :resolve, :project_id => @err.project.id, :id => @err.id
  87 + put :resolve, :app_id => @err.app.id, :id => @err.id
88 88 response.should redirect_to(errs_path)
89 89 end
90 90 end
... ...
spec/controllers/notices_controller_spec.rb
... ... @@ -5,8 +5,8 @@ describe NoticesController do
5 5 context 'POST[XML] notices#create' do
6 6 before do
7 7 @xml = Rails.root.join('spec','fixtures','hoptoad_test_notice.xml').read
8   - @project = Factory(:project_with_watcher)
9   - Project.stub(:find_by_api_key!).and_return(@project)
  8 + @app = Factory(:app_with_watcher)
  9 + App.stub(:find_by_api_key!).and_return(@app)
10 10 @notice = Notice.from_xml(@xml)
11 11  
12 12 request.env['Content-type'] = 'text/xml'
... ... @@ -22,7 +22,7 @@ describe NoticesController do
22 22 it "sends a notification email" do
23 23 post :create
24 24 email = ActionMailer::Base.deliveries.last
25   - email.to.should include(@project.watchers.first.email)
  25 + email.to.should include(@app.watchers.first.email)
26 26 email.subject.should include(@notice.err.message)
27 27 end
28 28 end
... ...
spec/controllers/projects_controller_spec.rb
... ... @@ -1,128 +0,0 @@
1   -require 'spec_helper'
2   -
3   -describe ProjectsController do
4   -
5   - describe "GET /projects" do
6   - it 'finds all projects' do
7   - 3.times { Factory(:project) }
8   - projects = Project.all
9   - get :index
10   - assigns(:projects).should == projects
11   - end
12   - end
13   -
14   - describe "GET /projects/:id" do
15   - it 'finds the project' do
16   - project = Factory(:project)
17   - get :show, :id => project.id
18   - assigns(:project).should == project
19   - end
20   - end
21   -
22   - describe "GET /projects/new" do
23   - it 'instantiates a new project with a prebuilt watcher' do
24   - get :new
25   - assigns(:project).should be_a(Project)
26   - assigns(:project).should be_new_record
27   - assigns(:project).watchers.should_not be_empty
28   - end
29   - end
30   -
31   - describe "GET /projects/:id/edit" do
32   - it 'finds the correct project' do
33   - project = Factory(:project)
34   - get :edit, :id => project.id
35   - assigns(:project).should == project
36   - end
37   - end
38   -
39   - describe "POST /projects" do
40   - before do
41   - @project = Factory(:project)
42   - Project.stub(:new).and_return(@project)
43   - end
44   -
45   - context "when the create is successful" do
46   - before do
47   - @project.should_receive(:save).and_return(true)
48   - end
49   -
50   - it "should redirect to the project page" do
51   - post :create, :project => {}
52   - response.should redirect_to(project_path(@project))
53   - end
54   -
55   - it "should display a message" do
56   - post :create, :project => {}
57   - request.flash[:success].should match(/success/)
58   - end
59   - end
60   -
61   - context "when the create is unsuccessful" do
62   - it "should render the new page" do
63   - @project.should_receive(:save).and_return(false)
64   - post :create, :project => {}
65   - response.should render_template(:new)
66   - end
67   - end
68   - end
69   -
70   - describe "PUT /projects/:id" do
71   - before do
72   - @project = Factory(:project)
73   - Project.stub(:find).with(@project.id).and_return(@project)
74   - end
75   -
76   - context "when the update is successful" do
77   - before do
78   - @project.should_receive(:update_attributes).and_return(true)
79   - end
80   -
81   - it "should redirect to the project page" do
82   - put :update, :id => @project.id, :project => {}
83   - response.should redirect_to(project_path(@project))
84   - end
85   -
86   - it "should display a message" do
87   - put :update, :id => @project.id, :project => {}
88   - request.flash[:success].should match(/success/)
89   - end
90   - end
91   -
92   - context "when the update is unsuccessful" do
93   - it "should render the edit page" do
94   - @project.should_receive(:update_attributes).and_return(false)
95   - put :update, :id => @project.id, :project => {}
96   - response.should render_template(:edit)
97   - end
98   - end
99   - end
100   -
101   - describe "DELETE /projects/:id" do
102   - before do
103   - @project = Factory(:project)
104   - Project.stub(:find).with(@project.id).and_return(@project)
105   - end
106   -
107   - it "should find the project" do
108   - delete :destroy, :id => @project.id
109   - assigns(:project).should == @project
110   - end
111   -
112   - it "should destroy the project" do
113   - @project.should_receive(:destroy)
114   - delete :destroy, :id => @project.id
115   - end
116   -
117   - it "should display a message" do
118   - delete :destroy, :id => @project.id
119   - request.flash[:success].should match(/success/)
120   - end
121   -
122   - it "should redirect to the projects page" do
123   - delete :destroy, :id => @project.id
124   - response.should redirect_to(projects_path)
125   - end
126   - end
127   -
128   -end
spec/factories/err_factories.rb
1 1 Factory.define :err do |e|
2   - e.project {|p| p.association :project}
  2 + e.app {|p| p.association :app}
3 3 e.klass 'FooError'
4 4 e.component 'foo'
5 5 e.action 'bar'
... ...
spec/factories/project_factories.rb
1   -Factory.sequence(:project_name) {|n| "Project ##{n}"}
  1 +Factory.sequence(:app_name) {|n| "App ##{n}"}
2 2 Factory.sequence(:email) {|n| "email#{n}@example.com"}
3 3  
4   -Factory.define(:project) do |p|
5   - p.name { Factory.next :project_name }
  4 +Factory.define(:app) do |p|
  5 + p.name { Factory.next :app_name }
6 6 end
7 7  
8   -Factory.define(:project_with_watcher, :parent => :project) do |p|
9   - p.after_create {|project|
10   - Factory(:watcher, :project => project)
  8 +Factory.define(:app_with_watcher, :parent => :app) do |p|
  9 + p.after_create {|app|
  10 + Factory(:watcher, :app => app)
11 11 }
12 12 end
13 13  
14 14 Factory.define(:watcher) do |w|
15   - w.project {|p| p.association :project}
  15 + w.app {|p| p.association :app}
16 16 w.email { Factory.next :email }
17 17 end
18 18  
19 19 Factory.define(:deploy) do |d|
20   - d.project {|p| p.association :project}
  20 + d.app {|p| p.association :app}
21 21 d.username 'clyde.frog'
22 22 d.repository 'git@github.com/jdpace/errbit.git'
23 23 d.environment 'production'
... ...
spec/models/app_spec.rb 0 → 100644
... ... @@ -0,0 +1,41 @@
  1 +require 'spec_helper'
  2 +
  3 +describe App do
  4 +
  5 + context 'validations' do
  6 + it 'requires a name' do
  7 + app = Factory.build(:app, :name => nil)
  8 + app.should_not be_valid
  9 + app.errors[:name].should include("can't be blank")
  10 + end
  11 +
  12 + it 'requires unique names' do
  13 + Factory(:app, :name => 'Errbit')
  14 + app = Factory.build(:app, :name => 'Errbit')
  15 + app.should_not be_valid
  16 + app.errors[:name].should include('is already taken')
  17 + end
  18 +
  19 + it 'requires unique api_keys' do
  20 + Factory(:app, :api_key => 'APIKEY')
  21 + app = Factory.build(:app, :api_key => 'APIKEY')
  22 + app.should_not be_valid
  23 + app.errors[:api_key].should include('is already taken')
  24 + end
  25 + end
  26 +
  27 + context 'being created' do
  28 + it 'generates a new api-key' do
  29 + app = Factory.build(:app)
  30 + app.api_key.should be_nil
  31 + app.save
  32 + app.api_key.should_not be_nil
  33 + end
  34 +
  35 + it 'generates a correct api-key' do
  36 + app = Factory(:app)
  37 + app.api_key.should match(/^[a-f0-9]{32}$/)
  38 + end
  39 + end
  40 +
  41 +end
... ...
spec/models/deploy_spec.rb
... ... @@ -20,24 +20,24 @@ describe Deploy do
20 20 it 'should send an email notification' do
21 21 Mailer.should_receive(:deploy_notification).
22 22 and_return(mock('email', :deliver => true))
23   - Factory(:deploy, :project => Factory(:project_with_watcher))
  23 + Factory(:deploy, :app => Factory(:app_with_watcher))
24 24 end
25 25  
26   - context 'when the project has resolve_errs_on_deploy set to false' do
27   - it 'should not resolve the projects errs' do
28   - project = Factory(:project, :resolve_errs_on_deploy => false)
29   - @errs = 3.times.inject([]) {|errs,_| errs << Factory(:err, :resolved => false, :project => project)}
30   - Factory(:deploy, :project => project)
31   - project.reload.errs.none?{|err| err.resolved?}.should == true
  26 + context 'when the app has resolve_errs_on_deploy set to false' do
  27 + it 'should not resolve the apps errs' do
  28 + app = Factory(:app, :resolve_errs_on_deploy => false)
  29 + @errs = 3.times.inject([]) {|errs,_| errs << Factory(:err, :resolved => false, :app => app)}
  30 + Factory(:deploy, :app => app)
  31 + app.reload.errs.none?{|err| err.resolved?}.should == true
32 32 end
33 33 end
34 34  
35   - context 'when the project has resolve_errs_on_deploy set to true' do
36   - it 'should not resolve the projects errs' do
37   - project = Factory(:project, :resolve_errs_on_deploy => true)
38   - @errs = 3.times.inject([]) {|errs,_| errs << Factory(:err, :resolved => false, :project => project)}
39   - Factory(:deploy, :project => project)
40   - project.reload.errs.all?{|err| err.resolved?}.should == true
  35 + context 'when the app has resolve_errs_on_deploy set to true' do
  36 + it 'should not resolve the apps errs' do
  37 + app = Factory(:app, :resolve_errs_on_deploy => true)
  38 + @errs = 3.times.inject([]) {|errs,_| errs << Factory(:err, :resolved => false, :app => app)}
  39 + Factory(:deploy, :app => app)
  40 + app.reload.errs.all?{|err| err.resolved?}.should == true
41 41 end
42 42 end
43 43 end
... ...
spec/models/err_spec.rb
... ... @@ -18,9 +18,9 @@ describe Err do
18 18  
19 19 context '#for' do
20 20 before do
21   - @project = Factory(:project)
  21 + @app = Factory(:app)
22 22 @conditions = {
23   - :project => @project,
  23 + :app => @app,
24 24 :klass => 'Whoops',
25 25 :component => 'Foo',
26 26 :action => 'bar',
... ... @@ -33,12 +33,12 @@ describe Err do
33 33 Err.for(@conditions).should == existing
34 34 end
35 35  
36   - it 'assigns the returned error to the given project' do
37   - Err.for(@conditions).project.should == @project
  36 + it 'assigns the returned error to the given app' do
  37 + Err.for(@conditions).app.should == @app
38 38 end
39 39  
40 40 it 'creates a new error if a matching one does not already exist' do
41   - Err.where(@conditions.except(:project)).exists?.should == false
  41 + Err.where(@conditions.except(:app)).exists?.should == false
42 42 lambda {
43 43 Err.for(@conditions)
44 44 }.should change(Err,:count).by(1)
... ...
spec/models/notice_spec.rb
... ... @@ -25,18 +25,18 @@ describe Notice do
25 25 context '#from_xml' do
26 26 before do
27 27 @xml = Rails.root.join('spec','fixtures','hoptoad_test_notice.xml').read
28   - @project = Factory(:project, :api_key => 'APIKEY')
  28 + @app = Factory(:app, :api_key => 'APIKEY')
29 29 Digest::MD5.stub(:hexdigest).and_return('fingerprintdigest')
30 30 end
31 31  
32   - it 'finds the correct project' do
  32 + it 'finds the correct app' do
33 33 @notice = Notice.from_xml(@xml)
34   - @notice.err.project.should == @project
  34 + @notice.err.app.should == @app
35 35 end
36 36  
37 37 it 'finds the correct error for the notice' do
38 38 Err.should_receive(:for).with({
39   - :project => @project,
  39 + :app => @app,
40 40 :klass => 'HoptoadTestingException',
41 41 :component => 'application',
42 42 :action => 'verify',
... ... @@ -87,11 +87,11 @@ describe Notice do
87 87  
88 88 describe "email notifications" do
89 89 before do
90   - @project = Factory(:project_with_watcher)
91   - @error = Factory(:err, :project => @project)
  90 + @app = Factory(:app_with_watcher)
  91 + @error = Factory(:err, :app => @app)
92 92 end
93 93  
94   - App.email_at_notices.each do |threshold|
  94 + Errbit::Config.email_at_notices.each do |threshold|
95 95 it "sends an email notification after #{threshold} notice(s)" do
96 96 @error.notices.stub(:count).and_return(threshold)
97 97 Mailer.should_receive(:error_notification).
... ...
spec/models/project_spec.rb
... ... @@ -1,41 +0,0 @@
1   -require 'spec_helper'
2   -
3   -describe Project do
4   -
5   - context 'validations' do
6   - it 'requires a name' do
7   - project = Factory.build(:project, :name => nil)
8   - project.should_not be_valid
9   - project.errors[:name].should include("can't be blank")
10   - end
11   -
12   - it 'requires unique names' do
13   - Factory(:project, :name => 'Errbit')
14   - project = Factory.build(:project, :name => 'Errbit')
15   - project.should_not be_valid
16   - project.errors[:name].should include('is already taken')
17   - end
18   -
19   - it 'requires unique api_keys' do
20   - Factory(:project, :api_key => 'APIKEY')
21   - project = Factory.build(:project, :api_key => 'APIKEY')
22   - project.should_not be_valid
23   - project.errors[:api_key].should include('is already taken')
24   - end
25   - end
26   -
27   - context 'being created' do
28   - it 'generates a new api-key' do
29   - project = Factory.build(:project)
30   - project.api_key.should be_nil
31   - project.save
32   - project.api_key.should_not be_nil
33   - end
34   -
35   - it 'generates a correct api-key' do
36   - project = Factory(:project)
37   - project.api_key.should match(/^[a-f0-9]{32}$/)
38   - end
39   - end
40   -
41   -end