diff options
49 files changed, 375 insertions, 136 deletions
diff --git a/CHANGELOG b/CHANGELOG index 57d612dc7e2..4221fb9df55 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,7 +1,11 @@ Please view this file on the master branch, on stable branches it's out of date. v 8.4.0 (unreleased) + - Autocomplete data is now always loaded, instead of when focusing a comment text area (Yorick Peterse) + - Improved performance of finding issues for an entire group (Yorick Peterse) + - Added custom application performance measuring system powered by InfluxDB (Yorick Peterse) - Bump fog to 1.36.0 (Stan Hu) + - Add user's last used IP addresses to admin page (Stan Hu) - Add housekeeping function to project settings page - The default GitLab logo now acts as a loading indicator - Fix caching issue where build status was not updating in project dashboard (Stan Hu) @@ -40,6 +44,9 @@ v 8.4.0 (unreleased) - Allow subsequent validations in CI Linter - Fix Encoding::CompatibilityError bug when markdown content has some complex URL (Jason Lee) +v 8.3.4 + - Use gitlab-workhorse 0.5.4 (fixes API routing bug) + v 8.3.3 - Preserve CE behavior with JIRA integration by only calling API if URL is set - Fix duplicated branch creation/deletion events when using Web UI (Stan Hu) @@ -53,6 +60,7 @@ v 8.3.3 - Fix Error 500 when visiting build page of project with nil runners_token (Stan Hu) - Use WOFF versions of SourceSansPro fonts - Fix regression when builds were not generated for tags created through web/api interface + - Fix: maintain milestone filter between Open and Closed tabs (Greg Smethells) v 8.3.2 - Disable --follow in `git log` to avoid loading duplicate commit data in infinite scroll (Stan Hu) diff --git a/GITLAB_WORKHORSE_VERSION b/GITLAB_WORKHORSE_VERSION index be14282b7ff..7d8568351b4 100644 --- a/GITLAB_WORKHORSE_VERSION +++ b/GITLAB_WORKHORSE_VERSION @@ -1 +1 @@ -0.5.3 +0.5.4 @@ -247,7 +247,7 @@ group :development, :test do gem 'byebug', platform: :mri gem 'pry-rails' - gem 'awesome_print', '~> 1.2.0' + gem 'awesome_print', '~> 1.2.0', require: false gem 'fuubar', '~> 2.0.0' gem 'database_cleaner', '~> 1.4.0' diff --git a/app/assets/javascripts/issue.js.coffee b/app/assets/javascripts/issue.js.coffee index c256ec8f41b..0d26c58a81d 100644 --- a/app/assets/javascripts/issue.js.coffee +++ b/app/assets/javascripts/issue.js.coffee @@ -16,12 +16,16 @@ class @Issue $(document).on 'tasklist:changed', '.detail-page-description .js-task-list-container', @updateTaskList initIssueBtnEventListeners: -> + _this = @ issueFailMessage = 'Unable to update this issue at this time.' $('a.btn-close, a.btn-reopen').on 'click', (e) -> e.preventDefault() e.stopImmediatePropagation() $this = $(this) isClose = $this.hasClass('btn-close') + shouldSubmit = $this.hasClass('btn-comment') + if shouldSubmit + _this.submitNoteForm($this.closest('form')) $this.prop('disabled', true) url = $this.attr('href') $.ajax @@ -32,12 +36,13 @@ class @Issue new Flash(issueFailMessage, 'alert') success: (data, textStatus, jqXHR) -> if data.saved - $this.addClass('hidden') if isClose + $('a.btn-close').addClass('hidden') $('a.btn-reopen').removeClass('hidden') $('div.status-box-closed').removeClass('hidden') $('div.status-box-open').addClass('hidden') else + $('a.btn-reopen').addClass('hidden') $('a.btn-close').removeClass('hidden') $('div.status-box-closed').addClass('hidden') $('div.status-box-open').removeClass('hidden') @@ -45,6 +50,11 @@ class @Issue new Flash(issueFailMessage, 'alert') $this.prop('disabled', false) + submitNoteForm: (form) => + noteText = form.find("textarea.js-note-text").val() + if noteText.trim().length > 0 + form.submit() + disableTaskList: -> $('.detail-page-description .js-task-list-container').taskList('disable') $(document).off 'tasklist:changed', '.detail-page-description .js-task-list-container' diff --git a/app/assets/javascripts/merge_request.js.coffee b/app/assets/javascripts/merge_request.js.coffee index 9047587db81..ed0bf2b3f48 100644 --- a/app/assets/javascripts/merge_request.js.coffee +++ b/app/assets/javascripts/merge_request.js.coffee @@ -19,6 +19,7 @@ class @MergeRequest # Prevent duplicate event bindings @disableTaskList() + @initMRBtnListeners() if $("a.btn-close").length @initTaskList() @@ -43,6 +44,27 @@ class @MergeRequest $('.detail-page-description .js-task-list-container').taskList('enable') $(document).on 'tasklist:changed', '.detail-page-description .js-task-list-container', @updateTaskList + initMRBtnListeners: -> + _this = @ + $('a.btn-close, a.btn-reopen').on 'click', (e) -> + $this = $(this) + if $this.data('submitted') + return + e.preventDefault() + e.stopImmediatePropagation() + shouldSubmit = $this.hasClass('btn-comment') + console.log("shouldSubmit") + if shouldSubmit + _this.submitNoteForm($this.closest('form'),$this) + + submitNoteForm: (form, $button) => + noteText = form.find("textarea.js-note-text").val() + if noteText.trim().length > 0 + form.submit() + $button.data('submitted',true) + $button.trigger('click') + + disableTaskList: -> $('.detail-page-description .js-task-list-container').taskList('disable') $(document).off 'tasklist:changed', '.detail-page-description .js-task-list-container' diff --git a/app/assets/javascripts/notes.js.coffee b/app/assets/javascripts/notes.js.coffee index 9e5204bfeeb..8ba00ecbbab 100644 --- a/app/assets/javascripts/notes.js.coffee +++ b/app/assets/javascripts/notes.js.coffee @@ -33,8 +33,6 @@ class @Notes $(document).on "click", ".note-edit-cancel", @cancelEdit # Reopen and close actions for Issue/MR combined with note form submit - $(document).on "click", ".js-note-target-reopen", @targetReopen - $(document).on "click", ".js-note-target-close", @targetClose $(document).on "click", ".js-comment-button", @updateCloseButton $(document).on "keyup", ".js-note-text", @updateTargetButtons @@ -512,17 +510,6 @@ class @Notes visibilityChange: => @refresh() - targetReopen: (e) => - @submitNoteForm($(e.target).parents('form')) - - targetClose: (e) => - @submitNoteForm($(e.target).parents('form')) - - submitNoteForm: (form) => - noteText = form.find(".js-note-text").val() - if noteText.trim().length > 0 - form.submit() - updateCloseButton: (e) => textarea = $(e.target) form = textarea.parents('form') @@ -531,7 +518,6 @@ class @Notes updateTargetButtons: (e) => textarea = $(e.target) form = textarea.parents('form') - if textarea.val().trim().length > 0 form.find('.js-note-target-reopen').text('Comment & reopen') form.find('.js-note-target-close').text('Comment & close') diff --git a/app/assets/stylesheets/framework/lists.scss b/app/assets/stylesheets/framework/lists.scss index 1c74e525a60..bbdb1c038c5 100644 --- a/app/assets/stylesheets/framework/lists.scss +++ b/app/assets/stylesheets/framework/lists.scss @@ -74,7 +74,7 @@ /** light list with border-bottom between li **/ -ul.bordered-list { +ul.bordered-list, ul.unstyled-list { @include basic-list; &.top-list { @@ -88,6 +88,10 @@ ul.bordered-list { } } +ul.unstyled-list > li { + border-bottom: none; +} + ul.task-list { li.task-list-item { list-style-type: none; diff --git a/app/assets/stylesheets/framework/variables.scss b/app/assets/stylesheets/framework/variables.scss index af75123b0af..d0ff3248ce1 100644 --- a/app/assets/stylesheets/framework/variables.scss +++ b/app/assets/stylesheets/framework/variables.scss @@ -24,6 +24,7 @@ $gl-gray: #5a5a5a; $gl-padding: 16px; $gl-padding-top:10px; $gl-avatar-size: 46px; +$secondary-text: #7f8fa4; /* * Color schema diff --git a/app/assets/stylesheets/pages/issues.scss b/app/assets/stylesheets/pages/issues.scss index a02a3a72e79..1e1af662850 100644 --- a/app/assets/stylesheets/pages/issues.scss +++ b/app/assets/stylesheets/pages/issues.scss @@ -144,3 +144,8 @@ form.edit-issue { .issue-form .select2-container { width: 250px !important; } + +.issue-closed-by-widget { + color: $secondary-text; + margin-left: 52px; +}
\ No newline at end of file diff --git a/app/controllers/admin/abuse_reports_controller.rb b/app/controllers/admin/abuse_reports_controller.rb index 38a5a9fca08..2463cfa87be 100644 --- a/app/controllers/admin/abuse_reports_controller.rb +++ b/app/controllers/admin/abuse_reports_controller.rb @@ -6,11 +6,9 @@ class Admin::AbuseReportsController < Admin::ApplicationController def destroy abuse_report = AbuseReport.find(params[:id]) - if params[:remove_user] - abuse_report.user.destroy - end - + abuse_report.remove_user if params[:remove_user] abuse_report.destroy + render nothing: true end end diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index 2b9bad9c9ea..436fbcd4138 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -205,7 +205,7 @@ module ApplicationHelper def time_ago_with_tooltip(time, placement: 'top', html_class: 'time_ago', skip_js: false) element = content_tag :time, time.to_s, class: "#{html_class} js-timeago js-timeago-pending", - datetime: time.getutc.iso8601, + datetime: time.to_time.getutc.iso8601, title: time.in_time_zone.to_s(:medium), data: { toggle: 'tooltip', placement: placement, container: 'body' } @@ -266,7 +266,7 @@ module ApplicationHelper state: params[:state], scope: params[:scope], label_name: params[:label_name], - milestone_id: params[:milestone_id], + milestone_title: params[:milestone_title], assignee_id: params[:assignee_id], author_id: params[:author_id], sort: params[:sort], diff --git a/app/helpers/notes_helper.rb b/app/helpers/notes_helper.rb index 5f0c921413a..53c543c28c5 100644 --- a/app/helpers/notes_helper.rb +++ b/app/helpers/notes_helper.rb @@ -67,7 +67,7 @@ module NotesHelper line_type: line_type } - button_tag class: 'btn reply-btn js-discussion-reply-button', + button_tag class: 'btn btn-nr reply-btn js-discussion-reply-button', data: data, title: 'Add a reply' do link_text = icon('comment') link_text << ' Reply' diff --git a/app/models/abuse_report.rb b/app/models/abuse_report.rb index 55864236b2f..2bc15c60d57 100644 --- a/app/models/abuse_report.rb +++ b/app/models/abuse_report.rb @@ -19,6 +19,11 @@ class AbuseReport < ActiveRecord::Base validates :message, presence: true validates :user_id, uniqueness: true + def remove_user + user.block + user.destroy + end + def notify return unless self.persisted? diff --git a/app/models/project_services/irker_service.rb b/app/models/project_services/irker_service.rb index bd9b580038f..04c714bfaad 100644 --- a/app/models/project_services/irker_service.rb +++ b/app/models/project_services/irker_service.rb @@ -73,9 +73,10 @@ class IrkerService < Service 'irc[s]://irc.network.net[:port]/#channel. Special cases: if '\ 'you want the channel to be a nickname instead, append ",isnick" to ' \ 'the channel name; if the channel is protected by a secret password, ' \ - ' append "?key=secretpassword" to the URI. Note that if you specify a ' \ - ' default IRC URI to prepend before each recipient, you can just give ' \ - ' a channel name.' }, + ' append "?key=secretpassword" to the URI (Note that due to a bug, if you ' \ + ' want to use a password, you have to omit the "#" on the channel). If you ' \ + ' specify a default IRC URI to prepend before each recipient, you can just ' \ + ' give a channel name.' }, { type: 'checkbox', name: 'colorize_messages' }, ] end diff --git a/app/services/system_hooks_service.rb b/app/services/system_hooks_service.rb index 6dc854ec33d..ea2b26ccb52 100644 --- a/app/services/system_hooks_service.rb +++ b/app/services/system_hooks_service.rb @@ -47,7 +47,8 @@ class SystemHooksService data.merge!({ name: model.name, email: model.email, - user_id: model.id + user_id: model.id, + username: model.username }) when ProjectMember data.merge!(project_member_data(model)) @@ -99,8 +100,10 @@ class SystemHooksService project_path: model.project.path, project_path_with_namespace: model.project.path_with_namespace, project_id: model.project.id, + user_username: model.user.username, user_name: model.user.name, user_email: model.user.email, + user_id: model.user.id, access_level: model.human_access, project_visibility: Project.visibility_levels.key(model.project.visibility_level_field).downcase } @@ -111,6 +114,7 @@ class SystemHooksService group_name: model.group.name, group_path: model.group.path, group_id: model.group.id, + user_username: model.user.username, user_name: model.user.name, user_email: model.user.email, user_id: model.user.id, diff --git a/app/views/admin/labels/index.html.haml b/app/views/admin/labels/index.html.haml index d67454c03e7..3c57e3dc174 100644 --- a/app/views/admin/labels/index.html.haml +++ b/app/views/admin/labels/index.html.haml @@ -1,5 +1,5 @@ - page_title "Labels" -= link_to new_admin_label_path, class: "pull-right btn btn-new" do += link_to new_admin_label_path, class: "pull-right btn btn-nr btn-new" do New label %h3.page-title Labels diff --git a/app/views/admin/projects/show.html.haml b/app/views/admin/projects/show.html.haml index 0c986af4a95..d734e60682a 100644 --- a/app/views/admin/projects/show.html.haml +++ b/app/views/admin/projects/show.html.haml @@ -1,7 +1,7 @@ - page_title @project.name_with_namespace, "Projects" %h3.page-title Project: #{@project.name_with_namespace} - = link_to edit_project_path(@project), class: "btn pull-right" do + = link_to edit_project_path(@project), class: "btn btn-nr pull-right" do %i.fa.fa-pencil-square-o Edit %hr diff --git a/app/views/admin/users/_head.html.haml b/app/views/admin/users/_head.html.haml index 5e17b018163..bc44b1b1d8e 100644 --- a/app/views/admin/users/_head.html.haml +++ b/app/views/admin/users/_head.html.haml @@ -7,8 +7,8 @@ .pull-right - unless @user == current_user || @user.blocked? - = link_to 'Impersonate', impersonate_admin_user_path(@user), method: :post, class: "btn btn-grouped btn-info" - = link_to edit_admin_user_path(@user), class: "btn btn-grouped" do + = link_to 'Impersonate', impersonate_admin_user_path(@user), method: :post, class: "btn btn-nr btn-grouped btn-info" + = link_to edit_admin_user_path(@user), class: "btn btn-nr btn-grouped" do %i.fa.fa-pencil-square-o Edit %hr diff --git a/app/views/admin/users/show.html.haml b/app/views/admin/users/show.html.haml index 2c2450d4117..2bdbae19588 100644 --- a/app/views/admin/users/show.html.haml +++ b/app/views/admin/users/show.html.haml @@ -71,6 +71,14 @@ No %li + %span.light Current sign-in IP: + %strong + - if @user.current_sign_in_ip + = @user.current_sign_in_ip + - else + never + + %li %span.light Current sign-in at: %strong - if @user.current_sign_in_at @@ -79,6 +87,14 @@ never %li + %span.light Last sign-in IP: + %strong + - if @user.last_sign_in_ip + = @user.last_sign_in_ip + - else + never + + %li %span.light Last sign-in at: %strong - if @user.last_sign_in_at diff --git a/app/views/dashboard/milestones/show.html.haml b/app/views/dashboard/milestones/show.html.haml index 4316c358dcb..49a558e8ac9 100644 --- a/app/views/dashboard/milestones/show.html.haml +++ b/app/views/dashboard/milestones/show.html.haml @@ -16,7 +16,7 @@ - if @milestone.complete? && @milestone.active? .alert.alert-success.prepend-top-default - %span All issues for this milestone are closed. You may close the milestone now. + %span All issues for this milestone are closed. Navigate to the project to close the milestone. .table-holder %table.table diff --git a/app/views/projects/issues/_closed_by_box.html.haml b/app/views/projects/issues/_closed_by_box.html.haml index de415ae51a4..38469ed4774 100644 --- a/app/views/projects/issues/_closed_by_box.html.haml +++ b/app/views/projects/issues/_closed_by_box.html.haml @@ -1,2 +1,4 @@ -.issue-closed-by-widget.gray-content-block.second-block.white - This issue will be closed automatically when merge request #{markdown(merge_requests_sentence(@closed_by_merge_requests), pipeline: :gfm)} is accepted. +.issue-closed-by-widget.second-block + - pluralized_mr_this = merge_request_count > 1 ? "these" : "this" + - pluralized_mr_is = merge_request_count > 1 ? "are" : "is" + When #{pluralized_mr_this} merge #{"request".pluralize(merge_request_count)} #{pluralized_mr_is} accepted, this issue will be closed automatically. diff --git a/app/views/projects/issues/_discussion.html.haml b/app/views/projects/issues/_discussion.html.haml index dc434cf38c4..673020a4e30 100644 --- a/app/views/projects/issues/_discussion.html.haml +++ b/app/views/projects/issues/_discussion.html.haml @@ -1,9 +1,7 @@ - content_for :note_actions do - if can?(current_user, :update_issue, @issue) - - if @issue.closed? - = link_to 'Reopen Issue', issue_path(@issue, issue: {state_event: :reopen}, status_only: true), method: :put, class: 'btn btn-nr btn-grouped btn-reopen js-note-target-reopen', title: 'Reopen Issue' - - else - = link_to 'Close Issue', issue_path(@issue, issue: {state_event: :close}, status_only: true), method: :put, class: 'btn btn-nr btn-grouped btn-close js-note-target-close', title: 'Close Issue' + = link_to 'Reopen Issue', issue_path(@issue, issue: {state_event: :reopen}, status_only: true, format: 'json'), data: {no_turbolink: true}, class: "btn btn-nr btn-grouped btn-reopen btn-comment js-note-target-reopen #{issue_button_visibility(@issue, false)}", title: 'Reopen Issue' + = link_to 'Close Issue', issue_path(@issue, issue: {state_event: :close}, status_only: true, format: 'json'), data: {no_turbolink: true}, class: "btn btn-nr btn-grouped btn-close btn-comment js-note-target-close #{issue_button_visibility(@issue, true)}", title: 'Close Issue' #notes = render 'projects/notes/notes_with_form' diff --git a/app/views/projects/issues/_merge_requests.html.haml b/app/views/projects/issues/_merge_requests.html.haml index 254968e4f67..640a1962ffc 100644 --- a/app/views/projects/issues/_merge_requests.html.haml +++ b/app/views/projects/issues/_merge_requests.html.haml @@ -1,7 +1,7 @@ -if @merge_requests.any? %h2.merge-requests-title = pluralize(@merge_requests.count, 'Related Merge Request') - %ul.bordered-list + %ul.unstyled-list - has_any_ci = @merge_requests.any?(&:ci_commit) - @merge_requests.each do |merge_request| %li @@ -11,7 +11,7 @@ - elsif has_any_ci = icon('blank fw') %span.merge-request-id - \##{merge_request.iid} + \!#{merge_request.iid} %span.merge-request-info %strong = link_to_gfm merge_request.title, merge_request_path(merge_request), class: "row_title" @@ -24,3 +24,5 @@ MERGED - elsif merge_request.closed? CLOSED + - if @closed_by_merge_requests.present? + = render partial: 'projects/issues/closed_by_box', locals: {merge_request_count: @merge_requests.count} diff --git a/app/views/projects/issues/show.html.haml b/app/views/projects/issues/show.html.haml index f931a0d3b92..7ed898ce72f 100644 --- a/app/views/projects/issues/show.html.haml +++ b/app/views/projects/issues/show.html.haml @@ -53,9 +53,6 @@ .gray-content-block.second-block.oneline-block = render 'votes/votes_block', votable: @issue - - if @closed_by_merge_requests.present? - = render 'projects/issues/closed_by_box' - .row %section.col-md-9 .issuable-discussion diff --git a/app/views/projects/merge_requests/_discussion.html.haml b/app/views/projects/merge_requests/_discussion.html.haml index bff3c3b283d..1c7de94acfd 100644 --- a/app/views/projects/merge_requests/_discussion.html.haml +++ b/app/views/projects/merge_requests/_discussion.html.haml @@ -1,8 +1,8 @@ - content_for :note_actions do - if can?(current_user, :update_merge_request, @merge_request) - if @merge_request.open? - = link_to 'Close', merge_request_path(@merge_request, merge_request: {state_event: :close }), method: :put, class: "btn btn-nr btn-grouped btn-close close-mr-link js-note-target-close", title: "Close merge request" + = link_to 'Close', merge_request_path(@merge_request, merge_request: {state_event: :close }), method: :put, class: "btn btn-nr btn-comment btn-grouped btn-close close-mr-link js-note-target-close", title: "Close merge request" - if @merge_request.closed? - = link_to 'Reopen', merge_request_path(@merge_request, merge_request: {state_event: :reopen }), method: :put, class: "btn btn-nr btn-grouped btn-reopen reopen-mr-link js-note-target-reopen", title: "Reopen merge request" + = link_to 'Reopen', merge_request_path(@merge_request, merge_request: {state_event: :reopen }), method: :put, class: "btn btn-nr btn-comment btn-grouped btn-reopen reopen-mr-link js-note-target-reopen", title: "Reopen merge request" #notes= render "projects/notes/notes_with_form" diff --git a/app/views/projects/notes/_edit_form.html.haml b/app/views/projects/notes/_edit_form.html.haml index 3ccda1b381c..5d78652befa 100644 --- a/app/views/projects/notes/_edit_form.html.haml +++ b/app/views/projects/notes/_edit_form.html.haml @@ -6,5 +6,5 @@ = render 'projects/notes/hints' .note-form-actions - = f.submit 'Save Comment', class: 'btn btn-primary btn-save btn-grouped js-comment-button' - = link_to 'Cancel', '#', class: 'btn btn-cancel note-edit-cancel' + = f.submit 'Save Comment', class: 'btn btn-nr btn-save btn-grouped js-comment-button' + = link_to 'Cancel', '#', class: 'btn btn-nr btn-cancel note-edit-cancel' diff --git a/app/views/projects/notes/_form.html.haml b/app/views/projects/notes/_form.html.haml index acb6dc52a8e..f10a4145d62 100644 --- a/app/views/projects/notes/_form.html.haml +++ b/app/views/projects/notes/_form.html.haml @@ -15,4 +15,4 @@ .note-form-actions.clearfix = f.submit 'Add Comment', class: "btn btn-nr btn-create comment-btn btn-grouped js-comment-button" = yield(:note_actions) - %a.btn.btn-cancel.js-close-discussion-note-form Cancel + %a.btn.btn-nr.btn-cancel.js-close-discussion-note-form Cancel diff --git a/config/initializers/haml.rb b/config/initializers/haml.rb index 1516476815a..7e8ddb3716b 100644 --- a/config/initializers/haml.rb +++ b/config/initializers/haml.rb @@ -1,7 +1 @@ Haml::Template.options[:ugly] = true - -# Remove the `:coffee` and `:coffeescript` filters -# -# See https://git.io/vztMu and http://stackoverflow.com/a/17571242/223897 -Haml::Filters.remove_filter('coffee') -Haml::Filters.remove_filter('coffeescript') diff --git a/doc/api/projects.md b/doc/api/projects.md index 37d74216c1b..241229221db 100644 --- a/doc/api/projects.md +++ b/doc/api/projects.md @@ -76,7 +76,10 @@ Parameters: "updated_at": "2013-09-30T13: 46: 02Z" }, "archived": false, - "avatar_url": "http://example.com/uploads/project/avatar/4/uploads/avatar.png" + "avatar_url": "http://example.com/uploads/project/avatar/4/uploads/avatar.png", + "shared_runners_enabled": true, + "forks_count": 0, + "star_count": 0 }, { "id": 6, @@ -129,7 +132,11 @@ Parameters: } }, "archived": false, - "avatar_url": null + "avatar_url": null, + "shared_runners_enabled": true, + "forks_count": 0, + "star_count": 0, + "runners_token": "b8547b1dc37721d05889db52fa2f02" } ] ``` @@ -244,7 +251,11 @@ Parameters: } }, "archived": false, - "avatar_url": "http://example.com/uploads/project/avatar/3/uploads/avatar.png" + "avatar_url": "http://example.com/uploads/project/avatar/3/uploads/avatar.png", + "shared_runners_enabled": true, + "forks_count": 0, + "star_count": 0, + "runners_token": "b8bc4a7a29eb76ea83cf79e4908c2b" } ``` diff --git a/doc/install/installation.md b/doc/install/installation.md index 8c4e092c636..e645445df2a 100644 --- a/doc/install/installation.md +++ b/doc/install/installation.md @@ -231,9 +231,9 @@ sudo usermod -aG redis git ### Clone the Source # Clone GitLab repository - sudo -u git -H git clone https://gitlab.com/gitlab-org/gitlab-ce.git -b 8-3-stable gitlab + sudo -u git -H git clone https://gitlab.com/gitlab-org/gitlab-ce.git -b 8-4-stable gitlab -**Note:** You can change `8-3-stable` to `master` if you want the *bleeding edge* version, but never install master on a production server! +**Note:** You can change `8-4-stable` to `master` if you want the *bleeding edge* version, but never install master on a production server! ### Configure It @@ -348,7 +348,7 @@ GitLab Shell is an SSH access and repository management software developed speci cd /home/git sudo -u git -H git clone https://gitlab.com/gitlab-org/gitlab-workhorse.git cd gitlab-workhorse - sudo -u git -H git checkout 0.5.3 + sudo -u git -H git checkout 0.5.4 sudo -u git -H make ### Initialize Database and Activate Advanced Features diff --git a/doc/integration/shibboleth.md b/doc/integration/shibboleth.md index 6258e5f1030..a0be3dd4e5c 100644 --- a/doc/integration/shibboleth.md +++ b/doc/integration/shibboleth.md @@ -1,8 +1,8 @@ # Shibboleth OmniAuth Provider -This documentation is for enabling shibboleth with gitlab-omnibus package. +This documentation is for enabling shibboleth with omnibus-gitlab package. -In order to enable Shibboleth support in gitlab we need to use Apache instead of Nginx (It may be possible to use Nginx, however I did not found way to easily configure Nginx that is bundled in gitlab-omnibus package). Apache uses mod_shib2 module for shibboleth authentication and can pass attributes as headers to omniauth-shibboleth provider. +In order to enable Shibboleth support in gitlab we need to use Apache instead of Nginx (It may be possible to use Nginx, however I did not found way to easily configure Nginx that is bundled in omnibus-gitlab package). Apache uses mod_shib2 module for shibboleth authentication and can pass attributes as headers to omniauth-shibboleth provider. To enable the Shibboleth OmniAuth provider you must: diff --git a/doc/release/patch.md b/doc/release/patch.md index 3022e375aca..1c921439156 100644 --- a/doc/release/patch.md +++ b/doc/release/patch.md @@ -24,7 +24,7 @@ Use the following template: - Picked into respective `stable` branches: - [ ] Merge `x-y-stable` into `x-y-stable-ee` - [ ] release-tools: `x.y.z` -- gitlab-omnibus +- omnibus-gitlab - [ ] `x.y.z+ee.0` - [ ] `x.y.z+ce.0` - [ ] Deploy diff --git a/doc/system_hooks/system_hooks.md b/doc/system_hooks/system_hooks.md index 49f98ded046..612376e3a49 100644 --- a/doc/system_hooks/system_hooks.md +++ b/doc/system_hooks/system_hooks.md @@ -96,6 +96,7 @@ X-Gitlab-Event: System Hook "project_path_with_namespace": "jsmith/storecloud", "user_email": "johnsmith@gmail.com", "user_name": "John Smith", + "user_username": "johnsmith", "user_id": 41, "project_visibility": "private", } @@ -115,6 +116,7 @@ X-Gitlab-Event: System Hook "project_path_with_namespace": "jsmith/storecloud", "user_email": "johnsmith@gmail.com", "user_name": "John Smith", + "user_username": "johnsmith", "user_id": 41, "project_visibility": "private", } @@ -129,6 +131,7 @@ X-Gitlab-Event: System Hook "email": "js@gitlabhq.com", "event_name": "user_create", "name": "John Smith", + "username": "js", "user_id": 41 } ``` @@ -142,6 +145,7 @@ X-Gitlab-Event: System Hook "email": "js@gitlabhq.com", "event_name": "user_destroy", "name": "John Smith", + "username": "js", "user_id": 41 } ``` @@ -215,6 +219,7 @@ X-Gitlab-Event: System Hook "group_path": "storecloud", "user_email": "johnsmith@gmail.com", "user_name": "John Smith", + "user_username": "johnsmith", "user_id": 41 } ``` @@ -231,6 +236,7 @@ X-Gitlab-Event: System Hook "group_path": "storecloud", "user_email": "johnsmith@gmail.com", "user_name": "John Smith", + "user_username": "johnsmith", "user_id": 41 } ``` diff --git a/doc/update/8.2-to-8.3.md b/doc/update/8.2-to-8.3.md index a3950df5fef..2ca4e1f3770 100644 --- a/doc/update/8.2-to-8.3.md +++ b/doc/update/8.2-to-8.3.md @@ -78,7 +78,7 @@ which should already be on your system from GitLab 8.1. ```bash cd /home/git/gitlab-workhorse sudo -u git -H git fetch --all -sudo -u git -H git checkout 0.5.3 +sudo -u git -H git checkout 0.5.4 sudo -u git -H make ``` diff --git a/doc/update/8.3-to-8.4.md b/doc/update/8.3-to-8.4.md new file mode 100644 index 00000000000..1cbeab3eca3 --- /dev/null +++ b/doc/update/8.3-to-8.4.md @@ -0,0 +1,148 @@ +# From 8.3 to 8.4 + +### 1. Stop server + + sudo service gitlab stop + +### 2. Backup + +```bash +cd /home/git/gitlab +sudo -u git -H bundle exec rake gitlab:backup:create RAILS_ENV=production +``` + +### 3. Get latest code + +```bash +sudo -u git -H git fetch --all +sudo -u git -H git checkout -- db/schema.rb # local changes will be restored automatically +``` + +For GitLab Community Edition: + +```bash +sudo -u git -H git checkout 8-4-stable +``` + +OR + +For GitLab Enterprise Edition: + +```bash +sudo -u git -H git checkout 8-4-stable-ee +``` + +### 4. Update gitlab-shell + +```bash +cd /home/git/gitlab-shell +sudo -u git -H git fetch --all +sudo -u git -H git checkout v2.6.9 +``` + +### 5. Update gitlab-workhorse + +Install and compile gitlab-workhorse. This requires [Go 1.5](https://golang.org/dl) +which should already be on your system from GitLab 8.1. + +```bash +cd /home/git/gitlab-workhorse +sudo -u git -H git fetch --all +sudo -u git -H git checkout 0.5.4 +sudo -u git -H make +``` + +### 6. Install libs, migrations, etc. + +```bash +cd /home/git/gitlab + +# MySQL installations (note: the line below states '--without postgres') +sudo -u git -H bundle install --without postgres development test --deployment + +# PostgreSQL installations (note: the line below states '--without mysql') +sudo -u git -H bundle install --without mysql development test --deployment + +# Run database migrations +sudo -u git -H bundle exec rake db:migrate RAILS_ENV=production + +# Clean up assets and cache +sudo -u git -H bundle exec rake assets:clean assets:precompile cache:clear RAILS_ENV=production + +``` + +### 7. Update configuration files + +#### New configuration options for `gitlab.yml` + +There are new configuration options available for [`gitlab.yml`](config/gitlab.yml.example). View them with the command below and apply them manually to your current `gitlab.yml`: + +```sh +git diff origin/8-3-stable:config/gitlab.yml.example origin/8-4-stable:config/gitlab.yml.example +``` + +#### Nginx configuration + +GitLab 8.3 introduced major changes in the NGINX configuration. Ensure you're +still up-to-date with the latest changes: + +```sh +# For HTTPS configurations +git diff origin/8-3-stable:lib/support/nginx/gitlab-ssl origin/8-4-stable:lib/support/nginx/gitlab-ssl + +# For HTTP configurations +git diff origin/8-3-stable:lib/support/nginx/gitlab origin/8-4-stable:lib/support/nginx/gitlab +``` + +If you are using Apache instead of NGINX please see the updated [Apache templates]. +Also note that because Apache does not support upstreams behind Unix sockets you +will need to let gitlab-workhorse listen on a TCP port. You can do this +via [/etc/default/gitlab]. + +[Apache templates]: https://gitlab.com/gitlab-org/gitlab-recipes/tree/master/web-server/apache +[/etc/default/gitlab]: https://gitlab.com/gitlab-org/gitlab-ce/blob/8-4-stable/lib/support/init.d/gitlab.default.example#L34 + +#### Init script + +We updated the init script for GitLab in order to pass new +configuration options to gitlab-workhorse. We let gitlab-workhorse +connect to the Rails application via a Unix domain socket and we tell +it where the 'public' directory of GitLab is. + +``` +cd /home/git/gitlab +sudo cp lib/support/init.d/gitlab /etc/init.d/gitlab +``` + +### 8. Start application + + sudo service gitlab start + sudo service nginx restart + +### 9. Check application status + +Check if GitLab and its environment are configured correctly: + + sudo -u git -H bundle exec rake gitlab:env:info RAILS_ENV=production + +To make sure you didn't miss anything run a more thorough check: + + sudo -u git -H bundle exec rake gitlab:check RAILS_ENV=production + +If all items are green, then congratulations, the upgrade is complete! + +## Things went south? Revert to previous version (8.3) + +### 1. Revert the code to the previous version + +Follow the [upgrade guide from 8.2 to 8.3](8.2-to-8.3.md), except for the +database migration (the backup is already migrated to the previous version). + +### 2. Restore from the backup + +```bash +cd /home/git/gitlab +sudo -u git -H bundle exec rake gitlab:backup:restore RAILS_ENV=production +``` + +If you have more than one backup `*.tar` file(s) please add `BACKUP=timestamp_of_backup` to the command above. diff --git a/doc/update/patch_versions.md b/doc/update/patch_versions.md index c19ee49f9e0..a10e62877ba 100644 --- a/doc/update/patch_versions.md +++ b/doc/update/patch_versions.md @@ -48,6 +48,7 @@ sudo -u git -H git checkout v`cat /home/git/gitlab/GITLAB_SHELL_VERSION` -b v`ca cd /home/git/gitlab-workhorse sudo -u git -H git fetch sudo -u git -H git checkout `cat /home/git/gitlab/GITLAB_WORKHORSE_VERSION` -b `cat /home/git/gitlab/GITLAB_WORKHORSE_VERSION` +sudo -u git -H make ``` ### 5. Install libs, migrations, etc. diff --git a/lib/api/entities.rb b/lib/api/entities.rb index 26e7c956e8f..e3bc3316ce5 100644 --- a/lib/api/entities.rb +++ b/lib/api/entities.rb @@ -71,6 +71,7 @@ module API expose :avatar_url expose :star_count, :forks_count expose :open_issues_count, if: lambda { |project, options| project.issues_enabled? && project.default_issues_tracker? } + expose :runners_token, if: lambda { |_project, options| options[:user_can_admin_project] } end class ProjectMember < UserBasic diff --git a/lib/api/projects.rb b/lib/api/projects.rb index 8b1390e3289..71bb342f844 100644 --- a/lib/api/projects.rb +++ b/lib/api/projects.rb @@ -69,7 +69,8 @@ module API # Example Request: # GET /projects/:id get ":id" do - present user_project, with: Entities::ProjectWithAccess, user: current_user + present user_project, with: Entities::ProjectWithAccess, user: current_user, + user_can_admin_project: can?(current_user, :admin_project, user_project) end # Get events for a single project @@ -118,7 +119,8 @@ module API attrs = map_public_to_visibility_level(attrs) @project = ::Projects::CreateService.new(current_user, attrs).execute if @project.saved? - present @project, with: Entities::Project + present @project, with: Entities::Project, + user_can_admin_project: can?(current_user, :admin_project, @project) else if @project.errors[:limit_reached].present? error!(@project.errors[:limit_reached], 403) @@ -163,7 +165,8 @@ module API attrs = map_public_to_visibility_level(attrs) @project = ::Projects::CreateService.new(user, attrs).execute if @project.saved? - present @project, with: Entities::Project + present @project, with: Entities::Project, + user_can_admin_project: can?(current_user, :admin_project, @project) else render_validation_error!(@project) end @@ -182,8 +185,9 @@ module API if @forked_project.errors.any? conflict!(@forked_project.errors.messages) else - present @forked_project, with: Entities::Project - end + present @forked_project, with: Entities::Project, + user_can_admin_project: can?(current_user, :admin_project, @forked_project) + end end # Update an existing project @@ -229,7 +233,8 @@ module API if user_project.errors.any? render_validation_error!(user_project) else - present user_project, with: Entities::Project + present user_project, with: Entities::Project, + user_can_admin_project: can?(current_user, :admin_project, user_project) end end diff --git a/lib/gitlab/metrics.rb b/lib/gitlab/metrics.rb index 44356a0e42c..cdf7c168ff2 100644 --- a/lib/gitlab/metrics.rb +++ b/lib/gitlab/metrics.rb @@ -36,20 +36,6 @@ module Gitlab @pool end - # Returns a relative path and line number based on the last application call - # frame. - def self.last_relative_application_frame - frame = caller_locations.find do |l| - l.path.start_with?(RAILS_ROOT) && !l.path.start_with?(METRICS_ROOT) - end - - if frame - return frame.path.sub(PATH_REGEX, ''), frame.lineno - else - return nil, nil - end - end - def self.submit_metrics(metrics) prepared = prepare_metrics(metrics) diff --git a/lib/gitlab/metrics/subscribers/action_view.rb b/lib/gitlab/metrics/subscribers/action_view.rb index 7c0105d543a..2e9dd4645e3 100644 --- a/lib/gitlab/metrics/subscribers/action_view.rb +++ b/lib/gitlab/metrics/subscribers/action_view.rb @@ -33,16 +33,8 @@ module Gitlab def tags_for(event) path = relative_path(event.payload[:identifier]) - tags = { view: path } - file, line = Metrics.last_relative_application_frame - - if file and line - tags[:file] = file - tags[:line] = line - end - - tags + { view: path } end def current_transaction diff --git a/lib/gitlab/metrics/transaction.rb b/lib/gitlab/metrics/transaction.rb index 86606b1c6d6..2578ddc49f4 100644 --- a/lib/gitlab/metrics/transaction.rb +++ b/lib/gitlab/metrics/transaction.rb @@ -23,20 +23,29 @@ module Gitlab @values = Hash.new(0) @tags = {} @action = action + + @memory_before = 0 + @memory_after = 0 end def duration @finished_at ? (@finished_at - @started_at) * 1000.0 : 0.0 end + def allocated_memory + @memory_after - @memory_before + end + def run Thread.current[THREAD_KEY] = self - @started_at = Time.now + @memory_before = System.memory_usage + @started_at = Time.now yield ensure - @finished_at = Time.now + @memory_after = System.memory_usage + @finished_at = Time.now Thread.current[THREAD_KEY] = nil end @@ -65,7 +74,7 @@ module Gitlab end def track_self - values = { duration: duration } + values = { duration: duration, allocated_memory: allocated_memory } @values.each do |name, value| values[name] = value diff --git a/lib/tasks/gitlab/task_helpers.rake b/lib/tasks/gitlab/task_helpers.rake index ebe516ec879..8c63877e51c 100644 --- a/lib/tasks/gitlab/task_helpers.rake +++ b/lib/tasks/gitlab/task_helpers.rake @@ -2,6 +2,8 @@ module Gitlab class TaskAbortedByUserError < StandardError; end end +String.disable_colorization = true unless STDOUT.isatty + namespace :gitlab do # Ask if the user wants to continue diff --git a/spec/helpers/application_helper_spec.rb b/spec/helpers/application_helper_spec.rb index efc850eb705..30e353148a8 100644 --- a/spec/helpers/application_helper_spec.rb +++ b/spec/helpers/application_helper_spec.rb @@ -285,6 +285,10 @@ describe ApplicationHelper do it 'allows the script tag to be excluded' do expect(element(skip_js: true)).not_to include 'script' end + + it 'converts to Time' do + expect { helper.time_ago_with_tooltip(Date.today) }.not_to raise_error + end end describe 'render_markup' do diff --git a/spec/javascripts/issue_spec.js.coffee b/spec/javascripts/issue_spec.js.coffee index b85fadcbe82..86ba9dd8e96 100644 --- a/spec/javascripts/issue_spec.js.coffee +++ b/spec/javascripts/issue_spec.js.coffee @@ -44,7 +44,7 @@ describe 'reopen/close issue', -> expect($('div.status-box-closed')).toBeVisible() expect($('div.status-box-open')).toBeHidden() - it 'fails to closes an issue with success:false', -> + it 'fails to close an issue with success:false', -> spyOn(jQuery, 'ajax').and.callFake (req) -> expect(req.type).toBe('PUT') diff --git a/spec/lib/gitlab/metrics/subscribers/action_view_spec.rb b/spec/lib/gitlab/metrics/subscribers/action_view_spec.rb index 05e4fbbeb51..0695c5ce096 100644 --- a/spec/lib/gitlab/metrics/subscribers/action_view_spec.rb +++ b/spec/lib/gitlab/metrics/subscribers/action_view_spec.rb @@ -14,19 +14,12 @@ describe Gitlab::Metrics::Subscribers::ActionView do before do allow(subscriber).to receive(:current_transaction).and_return(transaction) - - allow(Gitlab::Metrics).to receive(:last_relative_application_frame). - and_return(['app/views/x.html.haml', 4]) end describe '#render_template' do it 'tracks rendering of a template' do values = { duration: 2.1 } - tags = { - view: 'app/views/x.html.haml', - file: 'app/views/x.html.haml', - line: 4 - } + tags = { view: 'app/views/x.html.haml' } expect(transaction).to receive(:increment). with(:view_duration, 2.1) diff --git a/spec/lib/gitlab/metrics/transaction_spec.rb b/spec/lib/gitlab/metrics/transaction_spec.rb index 6bdeb719491..1d5a51a157e 100644 --- a/spec/lib/gitlab/metrics/transaction_spec.rb +++ b/spec/lib/gitlab/metrics/transaction_spec.rb @@ -11,6 +11,14 @@ describe Gitlab::Metrics::Transaction do end end + describe '#allocated_memory' do + it 'returns the allocated memory in bytes' do + transaction.run { 'a' * 32 } + + expect(transaction.allocated_memory).to be_a_kind_of(Numeric) + end + end + describe '#run' do it 'yields the supplied block' do expect { |b| transaction.run(&b) }.to yield_control @@ -43,8 +51,10 @@ describe Gitlab::Metrics::Transaction do transaction.increment(:time, 1) transaction.increment(:time, 2) + values = { duration: 0.0, time: 3, allocated_memory: a_kind_of(Numeric) } + expect(transaction).to receive(:add_metric). - with('transactions', { duration: 0.0, time: 3 }, {}) + with('transactions', values, {}) transaction.track_self end @@ -54,8 +64,14 @@ describe Gitlab::Metrics::Transaction do it 'sets a value' do transaction.set(:number, 10) + values = { + duration: 0.0, + number: 10, + allocated_memory: a_kind_of(Numeric) + } + expect(transaction).to receive(:add_metric). - with('transactions', { duration: 0.0, number: 10 }, {}) + with('transactions', values, {}) transaction.track_self end @@ -80,8 +96,13 @@ describe Gitlab::Metrics::Transaction do describe '#track_self' do it 'adds a metric for the transaction itself' do + values = { + duration: transaction.duration, + allocated_memory: a_kind_of(Numeric) + } + expect(transaction).to receive(:add_metric). - with('transactions', { duration: transaction.duration }, {}) + with('transactions', values, {}) transaction.track_self end @@ -104,7 +125,7 @@ describe Gitlab::Metrics::Transaction do hash = { series: 'rails_transactions', tags: { action: 'Foo#bar' }, - values: { duration: 0.0 }, + values: { duration: 0.0, allocated_memory: a_kind_of(Numeric) }, timestamp: an_instance_of(Fixnum) } diff --git a/spec/lib/gitlab/metrics_spec.rb b/spec/lib/gitlab/metrics_spec.rb index c2782f95c8e..0ec8a6dc5cb 100644 --- a/spec/lib/gitlab/metrics_spec.rb +++ b/spec/lib/gitlab/metrics_spec.rb @@ -13,15 +13,6 @@ describe Gitlab::Metrics do end end - describe '.last_relative_application_frame' do - it 'returns an Array containing a file path and line number' do - file, line = described_class.last_relative_application_frame - - expect(line).to eq(__LINE__ - 2) - expect(file).to eq('spec/lib/gitlab/metrics_spec.rb') - end - end - describe '#submit_metrics' do it 'prepares and writes the metrics to InfluxDB' do connection = double(:connection) diff --git a/spec/models/abuse_report_spec.rb b/spec/models/abuse_report_spec.rb index 46cab1644c7..f9be8fcbcfe 100644 --- a/spec/models/abuse_report_spec.rb +++ b/spec/models/abuse_report_spec.rb @@ -29,6 +29,22 @@ RSpec.describe AbuseReport, type: :model do it { is_expected.to validate_uniqueness_of(:user_id) } end + describe '#remove_user' do + it 'blocks the user' do + report = build(:abuse_report) + + allow(report.user).to receive(:destroy) + + expect { report.remove_user }.to change { report.user.blocked? }.to(true) + end + + it 'removes the user' do + report = build(:abuse_report) + + expect { report.remove_user }.to change { User.count }.by(-1) + end + end + describe '#notify' do it 'delivers' do expect(AbuseReportMailer).to receive(:notify).with(subject.id). diff --git a/spec/services/system_hooks_service_spec.rb b/spec/services/system_hooks_service_spec.rb index 4455ae7b321..fef211ded50 100644 --- a/spec/services/system_hooks_service_spec.rb +++ b/spec/services/system_hooks_service_spec.rb @@ -9,54 +9,54 @@ describe SystemHooksService, services: true do let(:group_member) { create(:group_member) } context 'event data' do - it { expect(event_data(user, :create)).to include(:event_name, :name, :created_at, :updated_at, :email, :user_id) } - it { expect(event_data(user, :destroy)).to include(:event_name, :name, :created_at, :updated_at, :email, :user_id) } + it { expect(event_data(user, :create)).to include(:event_name, :name, :created_at, :updated_at, :email, :user_id, :username) } + it { expect(event_data(user, :destroy)).to include(:event_name, :name, :created_at, :updated_at, :email, :user_id, :username) } it { expect(event_data(project, :create)).to include(:event_name, :name, :created_at, :updated_at, :path, :project_id, :owner_name, :owner_email, :project_visibility) } it { expect(event_data(project, :destroy)).to include(:event_name, :name, :created_at, :updated_at, :path, :project_id, :owner_name, :owner_email, :project_visibility) } - it { expect(event_data(project_member, :create)).to include(:event_name, :created_at, :updated_at, :project_name, :project_path, :project_path_with_namespace, :project_id, :user_name, :user_email, :access_level, :project_visibility) } - it { expect(event_data(project_member, :destroy)).to include(:event_name, :created_at, :updated_at, :project_name, :project_path, :project_path_with_namespace, :project_id, :user_name, :user_email, :access_level, :project_visibility) } + it { expect(event_data(project_member, :create)).to include(:event_name, :created_at, :updated_at, :project_name, :project_path, :project_path_with_namespace, :project_id, :user_name, :user_username, :user_email, :user_id, :access_level, :project_visibility) } + it { expect(event_data(project_member, :destroy)).to include(:event_name, :created_at, :updated_at, :project_name, :project_path, :project_path_with_namespace, :project_id, :user_name, :user_username, :user_email, :user_id, :access_level, :project_visibility) } it { expect(event_data(key, :create)).to include(:username, :key, :id) } it { expect(event_data(key, :destroy)).to include(:username, :key, :id) } it do project.old_path_with_namespace = 'renamed_from_path' expect(event_data(project, :rename)).to include( - :event_name, :name, :created_at, :updated_at, :path, :project_id, - :owner_name, :owner_email, :project_visibility, + :event_name, :name, :created_at, :updated_at, :path, :project_id, + :owner_name, :owner_email, :project_visibility, :old_path_with_namespace - ) + ) end it do project.old_path_with_namespace = 'transfered_from_path' expect(event_data(project, :transfer)).to include( - :event_name, :name, :created_at, :updated_at, :path, :project_id, - :owner_name, :owner_email, :project_visibility, + :event_name, :name, :created_at, :updated_at, :path, :project_id, + :owner_name, :owner_email, :project_visibility, :old_path_with_namespace - ) + ) end it do expect(event_data(group, :create)).to include( - :event_name, :name, :created_at, :updated_at, :path, :group_id, + :event_name, :name, :created_at, :updated_at, :path, :group_id, :owner_name, :owner_email ) end it do expect(event_data(group, :destroy)).to include( - :event_name, :name, :created_at, :updated_at, :path, :group_id, + :event_name, :name, :created_at, :updated_at, :path, :group_id, :owner_name, :owner_email ) end it do expect(event_data(group_member, :create)).to include( - :event_name, :created_at, :updated_at, :group_name, :group_path, - :group_id, :user_id, :user_name, :user_email, :group_access + :event_name, :created_at, :updated_at, :group_name, :group_path, + :group_id, :user_id, :user_username, :user_name, :user_email, :group_access ) end it do expect(event_data(group_member, :destroy)).to include( - :event_name, :created_at, :updated_at, :group_name, :group_path, - :group_id, :user_id, :user_name, :user_email, :group_access + :event_name, :created_at, :updated_at, :group_name, :group_path, + :group_id, :user_id, :user_username, :user_name, :user_email, :group_access ) end end |