houston-core 0.7.0 → 0.8.0.pre

Sign up to get free protection for your applications and to get access to all the features.
Files changed (99) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile.lock +45 -45
  3. data/app/assets/javascripts/houston/app/models/ticket.coffee +7 -5
  4. data/app/assets/javascripts/houston/app/views/new_ticket_view.coffee +1 -21
  5. data/app/assets/javascripts/houston/core/handlebars_helpers.coffee +0 -6
  6. data/app/assets/stylesheets/houston/application/commit.scss +16 -0
  7. data/app/assets/stylesheets/houston/application/navigation.scss +1 -0
  8. data/app/assets/stylesheets/houston/application/new_ticket_view.scss +0 -4
  9. data/app/assets/stylesheets/houston/application/projects.css.scss +0 -14
  10. data/app/assets/stylesheets/houston/application/release_form.scss +1 -1
  11. data/app/assets/stylesheets/houston/application/teams.scss +68 -0
  12. data/app/assets/templates/tickets/index.hbs +0 -1
  13. data/app/controllers/github/pulls_controller.rb +1 -0
  14. data/app/controllers/project_tickets_controller.rb +1 -5
  15. data/app/controllers/projects_controller.rb +10 -12
  16. data/app/controllers/teams_controller.rb +60 -0
  17. data/app/controllers/users_controller.rb +12 -12
  18. data/app/helpers/commit_helper.rb +3 -5
  19. data/app/helpers/exposure_helper.rb +1 -1
  20. data/app/helpers/ticket_helper.rb +0 -13
  21. data/app/interactors/ticket_report.rb +0 -7
  22. data/app/mailers/project_notification.rb +2 -23
  23. data/app/mailers/view_mailer.rb +0 -1
  24. data/app/models/ability.rb +28 -19
  25. data/app/models/commit.rb +0 -4
  26. data/app/models/project.rb +14 -29
  27. data/app/models/release.rb +0 -18
  28. data/app/models/role.rb +0 -22
  29. data/app/models/team.rb +43 -0
  30. data/app/models/team_user.rb +68 -0
  31. data/app/models/ticket.rb +2 -22
  32. data/app/models/user.rb +21 -30
  33. data/app/views/devise/sessions/new.html.erb +9 -7
  34. data/app/views/layouts/_mobile_navigation.html.erb +5 -3
  35. data/app/views/layouts/_navigation.html.erb +11 -10
  36. data/app/views/layouts/_tester_bar.html.erb +1 -1
  37. data/app/views/layouts/application.html.erb +1 -2
  38. data/app/views/project_tickets/_tickets.html.erb +0 -1
  39. data/app/views/project_tickets/index.xls.erb +0 -35
  40. data/app/views/project_tickets/new.html.erb +1 -2
  41. data/app/views/projects/_form.html.erb +7 -12
  42. data/app/views/projects/index.html.erb +10 -17
  43. data/app/views/releases/_changelog.html.erb +11 -14
  44. data/app/views/teams/_form.html.erb +45 -0
  45. data/app/views/teams/edit.html.erb +8 -0
  46. data/app/views/teams/index.html.erb +62 -0
  47. data/app/views/teams/new.html.erb +7 -0
  48. data/app/views/users/_form.html.erb +2 -11
  49. data/app/views/users/index.html.erb +8 -20
  50. data/app/views/users/new.html.erb +1 -1
  51. data/config/initializers/inflections.rb +7 -6
  52. data/config/routes.rb +19 -17
  53. data/db/migrate/20160812233255_repurpose_users_role.rb +16 -0
  54. data/db/migrate/20160813001242_create_teams.rb +42 -0
  55. data/db/structure.sql +110 -116
  56. data/lib/houston/boot.rb +0 -1
  57. data/lib/houston/boot/configuration.rb +26 -11
  58. data/lib/houston/boot/events.rb +0 -4
  59. data/lib/houston/version.rb +1 -1
  60. data/templates/new-instance/config/abilities.rb +68 -51
  61. data/templates/new-instance/config/conversations/mentions/unfurl_tasks.rb +1 -1
  62. data/templates/new-instance/config/events/deploy/notify_deployer_when_finished.rb +24 -16
  63. data/templates/new-instance/config/events/tests/email_when_completed.rb +11 -0
  64. data/templates/new-instance/config/integrations/ldap.rb +4 -0
  65. data/templates/new-instance/config/main.rb +10 -17
  66. data/templates/new-module/test/fixtures/users.yml +1 -2
  67. data/test/acceptance/creating_a_release_test.rb +1 -1
  68. data/test/factories/project_factory.rb +1 -0
  69. data/test/factories/user_factory.rb +3 -1
  70. data/test/fixtures/teams.yml +2 -0
  71. data/test/fixtures/teams_users.yml +5 -0
  72. data/test/fixtures/users.yml +1 -2
  73. data/test/integration/ci_integration_test.rb +2 -2
  74. data/test/support/config.rb +3 -5
  75. data/test/unit/controllers/deploys_controller_test.rb +11 -5
  76. data/test/unit/controllers/users_controller_test.rb +46 -0
  77. data/test/unit/models/release_test.rb +0 -9
  78. data/test/unit/models/serializer_test.rb +0 -8
  79. data/test/unit/models/ticket_test.rb +0 -32
  80. metadata +21 -24
  81. data/app/assets/javascripts/houston/app/table_row_expander.coffee +0 -52
  82. data/app/assets/javascripts/houston/app/views/problems_view.coffee +0 -114
  83. data/app/assets/stylesheets/houston/application/follow_up.scss +0 -44
  84. data/app/controllers/project_exceptions_controller.rb +0 -36
  85. data/app/controllers/project_pretickets_controller.rb +0 -27
  86. data/app/mailers/deploy_notification.rb +0 -33
  87. data/app/models/antecedent.rb +0 -15
  88. data/app/models/ticket_antecedent.rb +0 -39
  89. data/app/models/value_statement.rb +0 -9
  90. data/app/presenters/problem_presenter.rb +0 -49
  91. data/app/presenters/tester_presenter.rb +0 -15
  92. data/app/views/project_notification/follow_up.html.erb +0 -26
  93. data/app/views/project_pretickets/show.html.erb +0 -49
  94. data/app/views/releases/_antecedents.html.erb +0 -12
  95. data/config/initializers/hard_coded_knowledge.rb +0 -141
  96. data/db/migrate/20130427223925_create_project_quotas.rb +0 -14
  97. data/db/migrate/20140506035755_create_value_statements.rb +0 -9
  98. data/lib/houston/boot/ticket_antecedent_serializer.rb +0 -21
  99. data/test/unit/models/ticket_antecedents_test.rb +0 -38
@@ -10,7 +10,6 @@
10
10
  <!-- TMI: knowledge of roadmap module -->
11
11
  <a href="/roadmap/milestones/{{id}}">{{name}}</a>
12
12
  {{/milestone}}</td>
13
- <td class="ticket-antecedents">{{{summarizeAntecedents antecedents}}}</td>
14
13
  <td class="ticket-opened date">{{{formatDateWithYear openedAt}}}</td>
15
14
  <td class="ticket-closed date">{{{formatDateWithYear closedAt}}}</td>
16
15
  <td class="table-margin"></td>
@@ -2,6 +2,7 @@ class Github::PullsController < ApplicationController
2
2
 
3
3
  def index
4
4
  @pulls = Github::PullRequest.open.order(created_at: :desc).preload(:project, :user)
5
+ .find_all { |pull| can?(:read, pull) }
5
6
  @labels = @pulls.flat_map(&:labels).uniq { |label| label["name"] }.sort_by { |label| label["name"] }
6
7
  @selected_labels = params.fetch(:only, "").split(/,\s*/)
7
8
  @selected_labels = @labels.map { |label| label["name"] } if @selected_labels.none?
@@ -58,9 +58,6 @@ class ProjectTicketsController < ApplicationController
58
58
  return
59
59
  end
60
60
 
61
- @labels = []
62
- @labels = Houston::TMI::TICKET_LABELS_FOR_MEMBERS if @project.slug =~ /^360|members$/
63
- @labels = Houston::TMI::TICKET_LABELS_FOR_UNITE if @project.slug == "unite"
64
61
  Houston.benchmark "Load tickets" do
65
62
  @tickets = @project.tickets
66
63
  .pluck(:id, :summary, :number, :closed_at)
@@ -76,8 +73,7 @@ class ProjectTicketsController < ApplicationController
76
73
  if request.xhr?
77
74
  render json: MultiJson.dump({
78
75
  tickets: @tickets,
79
- project: { slug: @project.slug, ticketTrackerName: @project.ticket_tracker_name },
80
- labels: @labels
76
+ project: { slug: @project.slug, ticketTrackerName: @project.ticket_tracker_name }
81
77
  })
82
78
  else
83
79
  render
@@ -7,8 +7,6 @@ class ProjectsController < ApplicationController
7
7
  def index
8
8
  @title = "Projects"
9
9
  @projects = Project \
10
- .includes(:owners)
11
- .includes(:maintainers)
12
10
  .includes(:head)
13
11
  .unretired
14
12
  @test_runs = TestRun.most_recent.index_by(&:project_id)
@@ -23,13 +21,14 @@ class ProjectsController < ApplicationController
23
21
 
24
22
  def new
25
23
  @title = "New Project"
26
-
27
- @project = Project.new
28
- @project.roles.build(user: current_user) if @project.roles.none?
24
+ @team = Team.find params[:team_id]
25
+ @project = @team.projects.build
26
+ authorize! :create, @project
29
27
  end
30
28
 
31
29
  def new_from_github
32
- authorize! :create, Project
30
+ @team = Team.find params[:team_id]
31
+ authorize! :create, @team.projects.build
33
32
 
34
33
  existing_projects = Project.unscoped.where("props->>'git.location' LIKE '%github.com%'")
35
34
  github_repos = Houston.benchmark "Fetching repos" do
@@ -49,14 +48,15 @@ class ProjectsController < ApplicationController
49
48
 
50
49
 
51
50
  def create_from_github
52
- authorize! :create, Project
51
+ @team = Team.find params[:team_id]
52
+ authorize! :create, @team.projects.build
53
53
 
54
54
  repos = params.fetch(:repos, [])
55
55
  projects = Project.transaction do
56
56
  repos.map do |repo|
57
57
  owner, name = repo.split("/")
58
58
  title = name.humanize.gsub(/\b(?<!['’.`])[a-z]/) { $&.capitalize }.gsub("-", "::")
59
- Project.create!(
59
+ @team.projects.create!(
60
60
  name: title,
61
61
  slug: name,
62
62
  version_control_name: "Git",
@@ -65,7 +65,7 @@ class ProjectsController < ApplicationController
65
65
  end
66
66
 
67
67
  flash[:notice] = "#{projects.count} projects added"
68
- redirect_to projects_path
68
+ redirect_to teams_path
69
69
 
70
70
  rescue ActiveRecord::RecordInvalid
71
71
  flash[:error] = $!.message
@@ -75,8 +75,6 @@ class ProjectsController < ApplicationController
75
75
 
76
76
  def edit
77
77
  @project = Project.find_by_slug!(params[:id])
78
- @project.roles.build(user: current_user) if @project.roles.none?
79
-
80
78
  @title = "Edit #{@project.name}"
81
79
  end
82
80
 
@@ -85,7 +83,7 @@ class ProjectsController < ApplicationController
85
83
  @project = Project.new(project_attributes)
86
84
 
87
85
  if @project.save
88
- redirect_to projects_path, notice: 'Project was successfully created.'
86
+ redirect_to teams_path, notice: 'Project was successfully created.'
89
87
  else
90
88
  flash.now[:error] = @project.errors[:base].join("\n")
91
89
  render action: "new"
@@ -0,0 +1,60 @@
1
+ class TeamsController < ApplicationController
2
+ before_action :find_team, only: [:edit, :update]
3
+ load_and_authorize_resource
4
+
5
+
6
+ def index
7
+ @title = "Teams"
8
+ @teams = Team.all
9
+ end
10
+
11
+
12
+ def new
13
+ @title = "New Team"
14
+ @team = Team.new
15
+ @team.roles.build(user: current_user, roles: ["Team Owner"]) if @team.roles.none?
16
+ end
17
+
18
+
19
+ def create
20
+ @team = Team.new(team_attributes)
21
+
22
+ if @team.save
23
+ redirect_to teams_path, notice: "Team was successfully created."
24
+ else
25
+ flash.now[:error] = @team.errors[:base].join("\n")
26
+ render action: "new"
27
+ end
28
+ end
29
+
30
+
31
+ def edit
32
+ @title = "Edit #{@team.name}"
33
+ @team.roles.build(user: current_user, roles: ["Team Owner"]) if @team.roles.none?
34
+ end
35
+
36
+
37
+ def update
38
+ @team.props.merge! team_attributes.delete(:props) if team_attributes.key?(:props)
39
+
40
+ if @team.update_attributes(team_attributes)
41
+ redirect_to teams_path, notice: "Team was successfully updated."
42
+ else
43
+ flash.now[:error] = @team.errors[:base].join("\n")
44
+ render action: "edit"
45
+ end
46
+ end
47
+
48
+
49
+ private
50
+
51
+ def find_team
52
+ @team = Team.find(params[:id])
53
+ end
54
+
55
+ def team_attributes
56
+ params.fetch(:team)
57
+ # params.require(:team).permit(:name, :roles_attributes)
58
+ end
59
+
60
+ end
@@ -1,15 +1,11 @@
1
1
  class UsersController < ApplicationController
2
- before_filter :extract_administrator, :only => [:update, :create]
2
+ before_filter :extract_role, :only => [:update, :create]
3
3
  load_and_authorize_resource
4
4
 
5
5
 
6
6
  def index
7
- @title = "Team"
7
+ @title = "Users"
8
8
  @users = User.unretired
9
-
10
- @ticket_stats_by_user = @users.each_with_object({}) do |user, stats|
11
- stats[user] = stats_for_user(user)
12
- end
13
9
  end
14
10
 
15
11
 
@@ -43,7 +39,7 @@ class UsersController < ApplicationController
43
39
  if params[:send_invitation]
44
40
  User.invite!(params[:user])
45
41
  else
46
- @user.administrator = @administrator
42
+ @user.role = @role
47
43
  @user.save!
48
44
  end
49
45
 
@@ -57,7 +53,7 @@ class UsersController < ApplicationController
57
53
 
58
54
  def update
59
55
  @user = User.find(params[:id])
60
- @user.administrator = @administrator
56
+ @user.role = @role
61
57
 
62
58
  attributes = params[:user]
63
59
  attributes[:alias_emails] = attributes.fetch(:alias_emails, "").split.map(&:strip)
@@ -83,9 +79,13 @@ class UsersController < ApplicationController
83
79
  private
84
80
 
85
81
 
86
- def extract_administrator
87
- @administrator = params[:user].delete(:administrator) == "1"
88
- @administrator = false unless current_user.administrator?
82
+ def extract_role
83
+ @role = params[:user].delete(:role)
84
+ if current_user.owner?
85
+ @role = "Owner" if current_user.id == params[:id].to_i # Owners can't demote themselves
86
+ else
87
+ @role = "Member" # Others can't promote themselves
88
+ end
89
89
  end
90
90
 
91
91
 
@@ -106,7 +106,7 @@ private
106
106
 
107
107
  def user_params
108
108
  params.require(:user).permit(:first_name, :last_name, :email,
109
- :role, :password, :password_confirmation, :remember_me,
109
+ :password, :password_confirmation, :remember_me,
110
110
  :environments_subscribed_to, :view_options, :alias_emails)
111
111
  end
112
112
 
@@ -49,16 +49,14 @@ module CommitHelper
49
49
 
50
50
  message.gsub! Commit::EXTRA_ATTRIBUTE_PATTERN do |match|
51
51
  key, value = match.scan(Commit::EXTRA_ATTRIBUTE_PATTERN).first
52
- link_to_err(project, value) if key == "err"
52
+ format_extra_attribute(key, value)
53
53
  end
54
54
 
55
55
  message.html_safe
56
56
  end
57
57
 
58
- def link_to_err(project, err)
59
- link_to project.error_tracker_error_url(err), "target" => "_blank" do
60
- (image_tag(image_url("bug-fixed-32.png"), "data-tooltip-placement" => "right", rel: "tooltip", title: "View Exception in Errbit", width: 16, height: 16) + err).html_safe
61
- end
58
+ def format_extra_attribute(key, value)
59
+ "<span class=\"commit-extra-attribute\"><span class=\"commit-extra-attribute-key\">#{key}</span><span class=\"commit-extra-attribute-value\">#{value}</span></span>"
62
60
  end
63
61
 
64
62
  def commit_test_message(commit)
@@ -5,7 +5,7 @@ module ExposureHelper
5
5
  end
6
6
 
7
7
  def beta
8
- yield if current_user && current_user.administrator?
8
+ yield if current_user && current_user.owner?
9
9
  end
10
10
 
11
11
  end
@@ -22,17 +22,4 @@ module TicketHelper
22
22
  "#{feature}#{message}".html_safe
23
23
  end
24
24
 
25
-
26
-
27
- def format_antecedent(antecedent)
28
- case antecedent.kind
29
- when "Goldmine"; "Goldmine #{link_to_goldmine_case(antecedent.id)}".html_safe
30
- when "Errbit"; "Errbit #{link_to_err(antecedent.project, antecedent.id)}".html_safe
31
- end
32
- end
33
-
34
- def link_to_goldmine_case(number)
35
- link_to "##{number}", goldmine_case_number_url(number), target: "_blank"
36
- end
37
-
38
25
  end
@@ -8,16 +8,11 @@ class TicketReport
8
8
  :reporter_email,
9
9
  :reporter_first_name,
10
10
  :reporter_last_name,
11
- :antecedents,
12
11
  :opened_at,
13
12
  :closed_at,
14
13
  :milestone_id,
15
14
  :milestone_name)
16
15
 
17
- def antecedents
18
- (super || []).map { |s| TicketAntecedent.from_s(self, s) }
19
- end
20
-
21
16
  def reporter_name
22
17
  "#{reporter_first_name} #{reporter_last_name}"
23
18
  end
@@ -33,7 +28,6 @@ class TicketReport
33
28
  milestone: milestone_id && {
34
29
  id: milestone_id,
35
30
  name: milestone_name },
36
- antecedents: antecedents.map { |antecedent| { id: antecedent.id, kind: antecedent.kind } },
37
31
  openedAt: opened_at,
38
32
  closedAt: closed_at }
39
33
  end
@@ -55,7 +49,6 @@ class TicketReport
55
49
  "users.email",
56
50
  "users.first_name",
57
51
  "users.last_name",
58
- :antecedents,
59
52
  :created_at,
60
53
  :closed_at,
61
54
  "milestones.id",
@@ -10,22 +10,16 @@ class ProjectNotification < ViewMailer
10
10
  mail({
11
11
  from: release.user,
12
12
  to: options.fetch(:to, @release.notification_recipients),
13
- cc: options.fetch(:cc, @project.maintainers),
14
13
  subject: "new release to #{release.environment_name}",
15
14
  template: "new_release"
16
15
  })
17
16
  end
18
17
 
19
18
 
20
- def test_results(test_run, options={})
19
+ def test_results(test_run, recipients, options={})
21
20
  @test_run = test_run
22
21
  @project = test_run.project
23
22
 
24
- committers = test_run.commits_since_last_test_run.map { |commit| commit.author_email.downcase }
25
- recipients = (committers + Array(test_run.agent_email)).uniq \
26
- - @project.maintainers.map(&:email) \
27
- + @project.maintainers
28
-
29
23
  mail({
30
24
  to: recipients,
31
25
  subject: test_run_summary(test_run),
@@ -65,28 +59,13 @@ class ProjectNotification < ViewMailer
65
59
  @additional_info = options[:additional_info]
66
60
 
67
61
  mail({
68
- to: options.fetch(:to, @project.maintainers),
62
+ to: options.fetch(:to, @project.team_owners),
69
63
  subject: "configuration error",
70
64
  template: "ci_configuration_error"
71
65
  })
72
66
  end
73
67
 
74
68
 
75
- def follow_up(antecedent)
76
- @antecedent = antecedent
77
- @ticket = antecedent.ticket
78
- @project = @ticket.project
79
- @reporter = antecedent.reporter
80
- @customer = @antecedent.customer
81
-
82
- mail({
83
- to: @reporter,
84
- subject: "Sample Ticket follow-up",
85
- template: "follow_up"
86
- })
87
- end
88
-
89
-
90
69
  protected
91
70
 
92
71
 
@@ -23,7 +23,6 @@ class ViewMailer < ActionMailer::Base
23
23
  houston/application/markdown.scss
24
24
  houston/application/test_run.scss
25
25
  houston/application/releases.scss
26
- houston/application/follow_up.scss
27
26
  }
28
27
 
29
28
  helper_method :can?, :cannot?, :current_ability, :stylesheets
@@ -4,9 +4,30 @@ class Ability
4
4
 
5
5
 
6
6
  def initialize(user)
7
- if user && user.administrator?
8
- can :manage, :all
9
- elsif Houston.config.defines_abilities?
7
+ if user
8
+
9
+ # Owners can do everything
10
+
11
+ if user.owner?
12
+ can :manage, :all
13
+ return
14
+ end
15
+
16
+ # Admins can create teams
17
+
18
+ if user.admin?
19
+ can [:read, :create], Team
20
+ end
21
+
22
+ # Users get abilities based on their role
23
+ # in any teams they are members of
24
+
25
+ user.roles.each do |role|
26
+ Houston.config.configure_team_abilities(self, role)
27
+ end
28
+ end
29
+
30
+ if Houston.config.defines_abilities?
10
31
  Houston.config.configure_abilities(self, user)
11
32
  else
12
33
  default_abilities_for(user)
@@ -16,25 +37,13 @@ class Ability
16
37
 
17
38
 
18
39
  def default_abilities_for(user)
40
+ return unless user
19
41
 
20
- # Anyone can see everything
42
+ # If you're logged in, you can see everything
21
43
  can :read, :all
22
44
 
23
- if user
24
-
25
- # If you're logged in, you can update yourself
26
- can :update, user
27
-
28
- if user.developer?
29
-
30
- # Developers can manage projects and releases
31
- can :manage, Project
32
- can :manage, Release
33
- can :manage, Sprint
34
-
35
- end
36
- end
37
-
45
+ # If you're logged in, you can update yourself
46
+ can :update, user
38
47
  end
39
48
 
40
49
 
@@ -145,10 +145,6 @@ class Commit < ActiveRecord::Base
145
145
  parsed_message[:attributes]
146
146
  end
147
147
 
148
- def antecedents
149
- extra_attributes.fetch("err", []).map { |id| TicketAntecedent.new(self, "Errbit", id) }
150
- end
151
-
152
148
 
153
149
 
154
150
  def committer_hours