diff options
52 files changed, 361 insertions, 228 deletions
diff --git a/app/assets/javascripts/filtered_search/filtered_search_manager.js b/app/assets/javascripts/filtered_search/filtered_search_manager.js index 9fea563370f..57d247e11a9 100644 --- a/app/assets/javascripts/filtered_search/filtered_search_manager.js +++ b/app/assets/javascripts/filtered_search/filtered_search_manager.js @@ -16,10 +16,14 @@ class FilteredSearchManager { this.recentSearchesStore = new RecentSearchesStore({ isLocalStorageAvailable: RecentSearchesService.isAvailable(), }); - let recentSearchesKey = 'issue-recent-searches'; + const searchHistoryDropdownElement = document.querySelector('.js-filtered-search-history-dropdown'); + const projectPath = searchHistoryDropdownElement ? + searchHistoryDropdownElement.dataset.projectFullPath : 'project'; + let recentSearchesPagePrefix = 'issue-recent-searches'; if (page === 'merge_requests') { - recentSearchesKey = 'merge-request-recent-searches'; + recentSearchesPagePrefix = 'merge-request-recent-searches'; } + const recentSearchesKey = `${projectPath}-${recentSearchesPagePrefix}`; this.recentSearchesService = new RecentSearchesService(recentSearchesKey); // Fetch recent searches from localStorage @@ -47,7 +51,7 @@ class FilteredSearchManager { this.recentSearchesRoot = new RecentSearchesRoot( this.recentSearchesStore, this.recentSearchesService, - document.querySelector('.js-filtered-search-history-dropdown'), + searchHistoryDropdownElement, ); this.recentSearchesRoot.init(); diff --git a/app/assets/javascripts/filtered_search/stores/recent_searches_store.js b/app/assets/javascripts/filtered_search/stores/recent_searches_store.js index 066be69766a..35fc15e4c87 100644 --- a/app/assets/javascripts/filtered_search/stores/recent_searches_store.js +++ b/app/assets/javascripts/filtered_search/stores/recent_searches_store.js @@ -3,6 +3,7 @@ import _ from 'underscore'; class RecentSearchesStore { constructor(initialState = {}) { this.state = Object.assign({ + isLocalStorageAvailable: true, recentSearches: [], }, initialState); } diff --git a/app/assets/javascripts/lib/utils/common_utils.js b/app/assets/javascripts/lib/utils/common_utils.js index 2f682fbd2fb..7e62773ae6c 100644 --- a/app/assets/javascripts/lib/utils/common_utils.js +++ b/app/assets/javascripts/lib/utils/common_utils.js @@ -135,7 +135,10 @@ gl.utils.getUrlParamsArray = function () { // We can trust that each param has one & since values containing & will be encoded // Remove the first character of search as it is always ? - return window.location.search.slice(1).split('&'); + return window.location.search.slice(1).split('&').map((param) => { + const split = param.split('='); + return [decodeURI(split[0]), split[1]].join('='); + }); }; gl.utils.isMetaKey = function(e) { diff --git a/app/assets/javascripts/notes.js b/app/assets/javascripts/notes.js index f143bfbfc29..92868bfe75d 100644 --- a/app/assets/javascripts/notes.js +++ b/app/assets/javascripts/notes.js @@ -47,6 +47,7 @@ const normalizeNewlines = function(str) { this.keydownNoteText = this.keydownNoteText.bind(this); this.toggleCommitList = this.toggleCommitList.bind(this); this.postComment = this.postComment.bind(this); + this.clearFlashWrapper = this.clearFlash.bind(this); this.notes_url = notes_url; this.note_ids = note_ids; @@ -57,6 +58,7 @@ const normalizeNewlines = function(str) { this.notesCountBadge || (this.notesCountBadge = $(".issuable-details").find(".notes-tab .badge")); this.basePollingInterval = 15000; this.maxPollingSteps = 4; + this.flashErrors = []; this.cleanBinding(); this.addBinding(); @@ -298,7 +300,7 @@ const normalizeNewlines = function(str) { if (!noteEntity.valid) { if (noteEntity.errors.commands_only) { - new Flash(noteEntity.errors.commands_only, 'notice', this.parentTimeline); + this.addFlash(noteEntity.errors.commands_only, 'notice', this.parentTimeline); this.refresh(); } return; @@ -551,14 +553,14 @@ const normalizeNewlines = function(str) { return this.renderNote(note); }; - Notes.prototype.addNoteError = ($form) => { + Notes.prototype.addNoteError = function($form) { let formParentTimeline; if ($form.hasClass('js-main-target-form')) { formParentTimeline = $form.parents('.timeline'); } else if ($form.hasClass('js-discussion-note-form')) { formParentTimeline = $form.closest('.discussion-notes').find('.notes'); } - return new Flash('Your comment could not be submitted! Please check your network connection and try again.', 'alert', formParentTimeline); + return this.addFlash('Your comment could not be submitted! Please check your network connection and try again.', 'alert', formParentTimeline); }; Notes.prototype.updateNoteError = $parentTimeline => new Flash('Your comment could not be updated! Please check your network connection and try again.'); @@ -1101,6 +1103,15 @@ const normalizeNewlines = function(str) { }); }; + Notes.prototype.addFlash = function(...flashParams) { + this.flashErrors.push(new Flash(...flashParams)); + }; + + Notes.prototype.clearFlash = function() { + this.flashErrors.forEach(flash => flash.flashContainer.remove()); + this.flashErrors = []; + }; + Notes.prototype.cleanForm = function($form) { // Remove JS classes that are not needed here $form @@ -1279,6 +1290,8 @@ const normalizeNewlines = function(str) { .then((note) => { // Submission successful! remove placeholder $notesContainer.find(`#${uniqueId}`).remove(); + // Clear previous form errors + this.clearFlashWrapper(); // Check if this was discussion comment if (isDiscussionForm) { diff --git a/app/assets/stylesheets/framework/nav.scss b/app/assets/stylesheets/framework/nav.scss index 64e6ab391b6..d2f6a227128 100644 --- a/app/assets/stylesheets/framework/nav.scss +++ b/app/assets/stylesheets/framework/nav.scss @@ -24,10 +24,10 @@ } @mixin scrolling-links() { - white-space: nowrap; overflow-x: auto; overflow-y: hidden; -webkit-overflow-scrolling: touch; + display: flex; &::-webkit-scrollbar { display: none; @@ -35,6 +35,7 @@ } .nav-links { + display: flex; padding: 0; margin: 0; list-style: none; @@ -42,17 +43,16 @@ border-bottom: 1px solid $border-color; li { - display: inline-block; + display: flex; a { - display: inline-block; padding: $gl-btn-padding; padding-bottom: 11px; - margin-bottom: -1px; font-size: 14px; line-height: 28px; color: $gl-text-color-secondary; border-bottom: 2px solid transparent; + white-space: nowrap; &:hover, &:active, @@ -85,10 +85,10 @@ .container-fluid { background-color: $gray-normal; margin-bottom: 0; + display: flex; } li { - &.active a { border-bottom: none; color: $link-underline-blue; @@ -137,9 +137,9 @@ } .nav-links { - display: inline-block; margin-bottom: 0; border-bottom: none; + float: left; &.wide { width: 100%; @@ -337,6 +337,10 @@ border-bottom: none; height: 51px; + @media (min-width: $screen-sm-min) { + justify-content: center; + } + li { a { padding-top: 10px; @@ -347,6 +351,7 @@ .scrolling-tabs-container { position: relative; + overflow: hidden; .nav-links { @include scrolling-links(); @@ -484,10 +489,7 @@ .inner-page-scroll-tabs { position: relative; - - .nav-links { - padding-bottom: 1px; - } + overflow: hidden; .fade-right { @include fade(left, $white-light); diff --git a/app/assets/stylesheets/pages/issuable.scss b/app/assets/stylesheets/pages/issuable.scss index 2b9a7e43f0f..0184208ab82 100644 --- a/app/assets/stylesheets/pages/issuable.scss +++ b/app/assets/stylesheets/pages/issuable.scss @@ -23,16 +23,6 @@ .merge-manually { @extend .fixed-width-container; } - - .merge-request-tabs-holder { - &.affix { - border-bottom: 1px solid $border-color; - - .nav-links { - border: 0; - } - } - } } .merge-request-details { diff --git a/app/assets/stylesheets/pages/merge_requests.scss b/app/assets/stylesheets/pages/merge_requests.scss index 61b13745f63..d208e54207e 100644 --- a/app/assets/stylesheets/pages/merge_requests.scss +++ b/app/assets/stylesheets/pages/merge_requests.scss @@ -693,6 +693,7 @@ top: $header-height; z-index: 100; background-color: $white-light; + border-bottom: 1px solid $border-color; @media(min-width: $screen-sm-min) { position: sticky; @@ -712,6 +713,16 @@ padding-right: $gl-padding; } } + + .nav-links { + border: 0; + } +} + +.merge-request-tabs { + display: flex; + margin-bottom: 0; + padding: 0; } .limit-container-width { @@ -722,6 +733,15 @@ } } +.merge-request-tabs-container { + display: flex; + justify-content: space-between; + + @media (max-width: $screen-xs-max) { + flex-direction: column-reverse; + } +} + .limit-container-width:not(.container-limited) { .merge-request-tabs-holder:not(.affix) { .merge-request-tabs-container { diff --git a/app/assets/stylesheets/pages/notes.scss b/app/assets/stylesheets/pages/notes.scss index 0600bb1cb1a..5b6aa9d74f6 100644 --- a/app/assets/stylesheets/pages/notes.scss +++ b/app/assets/stylesheets/pages/notes.scss @@ -609,6 +609,15 @@ ul.notes { } .line-resolve-all-container { + @media (min-width: $screen-sm-min) { + margin-right: 0; + padding-left: $gl-padding; + } + + > div { + white-space: nowrap; + } + .btn-group { margin-left: -4px; } diff --git a/app/assets/stylesheets/pages/pipelines.scss b/app/assets/stylesheets/pages/pipelines.scss index e4f5ab26b4d..292584eba28 100644 --- a/app/assets/stylesheets/pages/pipelines.scss +++ b/app/assets/stylesheets/pages/pipelines.scss @@ -191,7 +191,6 @@ } .commit-title { - margin-top: 4px; max-width: 225px; overflow: hidden; white-space: nowrap; @@ -224,7 +223,7 @@ .duration, .finished-at { color: $gl-text-color-secondary; - margin: 4px 0; + margin: 0; white-space: nowrap; .fa { diff --git a/app/helpers/submodule_helper.rb b/app/helpers/submodule_helper.rb index b739554a7a4..09b73eee8cf 100644 --- a/app/helpers/submodule_helper.rb +++ b/app/helpers/submodule_helper.rb @@ -7,6 +7,10 @@ module SubmoduleHelper def submodule_links(submodule_item, ref = nil, repository = @repository) url = repository.submodule_url_for(ref, submodule_item.path) + if url == '.' || url == './' + url = File.join(Gitlab.config.gitlab.url, @project.full_path) + end + if url =~ /([^\/:]+)\/([^\/]+(?:\.git)?)\Z/ namespace, project = $1, $2 project.sub!(/\.git\z/, '') diff --git a/app/models/ci/build.rb b/app/models/ci/build.rb index 760ec8e5919..3c4a4d93349 100644 --- a/app/models/ci/build.rb +++ b/app/models/ci/build.rb @@ -300,8 +300,8 @@ module Ci def execute_hooks return unless project build_data = Gitlab::DataBuilder::Build.build(self) - project.execute_hooks(build_data.dup, :job_hooks) - project.execute_services(build_data.dup, :job_hooks) + project.execute_hooks(build_data.dup, :build_hooks) + project.execute_services(build_data.dup, :build_hooks) PagesService.new(build_data).execute project.running_or_pending_build_count(force: true) end diff --git a/app/models/hooks/project_hook.rb b/app/models/hooks/project_hook.rb index ee6165fd32d..c631e7a7df5 100644 --- a/app/models/hooks/project_hook.rb +++ b/app/models/hooks/project_hook.rb @@ -5,7 +5,7 @@ class ProjectHook < WebHook scope :confidential_issue_hooks, -> { where(confidential_issues_events: true) } scope :note_hooks, -> { where(note_events: true) } scope :merge_request_hooks, -> { where(merge_requests_events: true) } - scope :job_hooks, -> { where(job_events: true) } + scope :build_hooks, -> { where(build_events: true) } scope :pipeline_hooks, -> { where(pipeline_events: true) } scope :wiki_page_hooks, -> { where(wiki_page_events: true) } end diff --git a/app/models/hooks/web_hook.rb b/app/models/hooks/web_hook.rb index a165fdc312f..7cf03aabd6f 100644 --- a/app/models/hooks/web_hook.rb +++ b/app/models/hooks/web_hook.rb @@ -8,7 +8,7 @@ class WebHook < ActiveRecord::Base default_value_for :note_events, false default_value_for :merge_requests_events, false default_value_for :tag_push_events, false - default_value_for :job_events, false + default_value_for :build_events, false default_value_for :pipeline_events, false default_value_for :repository_update_events, false default_value_for :enable_ssl_verification, true diff --git a/app/models/service.rb b/app/models/service.rb index 8916f88076e..c71a7d169ec 100644 --- a/app/models/service.rb +++ b/app/models/service.rb @@ -12,7 +12,7 @@ class Service < ActiveRecord::Base default_value_for :merge_requests_events, true default_value_for :tag_push_events, true default_value_for :note_events, true - default_value_for :job_events, true + default_value_for :build_events, true default_value_for :pipeline_events, true default_value_for :wiki_page_events, true @@ -40,7 +40,7 @@ class Service < ActiveRecord::Base scope :confidential_issue_hooks, -> { where(confidential_issues_events: true, active: true) } scope :merge_request_hooks, -> { where(merge_requests_events: true, active: true) } scope :note_hooks, -> { where(note_events: true, active: true) } - scope :job_hooks, -> { where(job_events: true, active: true) } + scope :build_hooks, -> { where(build_events: true, active: true) } scope :pipeline_hooks, -> { where(pipeline_events: true, active: true) } scope :wiki_page_hooks, -> { where(wiki_page_events: true, active: true) } scope :external_issue_trackers, -> { issue_trackers.active.without_defaults } diff --git a/app/views/admin/hooks/index.html.haml b/app/views/admin/hooks/index.html.haml index e92b8bc39f4..3338b677bf5 100644 --- a/app/views/admin/hooks/index.html.haml +++ b/app/views/admin/hooks/index.html.haml @@ -27,7 +27,7 @@ = link_to 'Remove', admin_hook_path(hook), data: { confirm: 'Are you sure?' }, method: :delete, class: 'btn btn-remove btn-sm' .monospace= hook.url %div - - %w(repository_update_events push_events tag_push_events issues_events note_events merge_requests_events job_events).each do |trigger| + - %w(repository_update_events push_events tag_push_events issues_events note_events merge_requests_events build_events).each do |trigger| - if hook.send(trigger) %span.label.label-gray= trigger.titleize %span.label.label-gray SSL Verification: #{hook.enable_ssl_verification ? 'enabled' : 'disabled'} diff --git a/app/views/projects/merge_requests/_show.html.haml b/app/views/projects/merge_requests/_show.html.haml index 25b8567b78f..b7515e1d91f 100644 --- a/app/views/projects/merge_requests/_show.html.haml +++ b/app/views/projects/merge_requests/_show.html.haml @@ -27,40 +27,42 @@ = render 'award_emoji/awards_block', awardable: @merge_request, inline: true .merge-request-tabs-holder{ class: ("js-tabs-affix" unless ENV['RAILS_ENV'] == 'test') } - .merge-request-tabs-container.scrolling-tabs-container.inner-page-scroll-tabs - .fade-left= icon('angle-left') - .fade-right= icon('angle-right') - %ul.merge-request-tabs.nav-links.scrolling-tabs - %li.notes-tab - = link_to namespace_project_merge_request_path(@project.namespace, @project, @merge_request), data: { target: 'div#notes', action: 'notes', toggle: 'tab' } do - Discussion - %span.badge= @merge_request.related_notes.user.count - - if @merge_request.source_project - %li.commits-tab - = link_to commits_namespace_project_merge_request_path(@project.namespace, @project, @merge_request), data: { target: 'div#commits', action: 'commits', toggle: 'tab' } do - Commits - %span.badge= @commits_count - - if @pipelines.any? - %li.pipelines-tab - = link_to pipelines_namespace_project_merge_request_path(@project.namespace, @project, @merge_request), data: { target: '#pipelines', action: 'pipelines', toggle: 'tab' } do - Pipelines - %span.badge= @pipelines.size - %li.diffs-tab - = link_to diffs_namespace_project_merge_request_path(@project.namespace, @project, @merge_request), data: { target: 'div#diffs', action: 'diffs', toggle: 'tab' } do - Changes - %span.badge= @merge_request.diff_size - %li#resolve-count-app.line-resolve-all-container.pull-right.prepend-top-10.hidden-xs{ "v-cloak" => true } - %resolve-count{ "inline-template" => true, ":logged-out" => "#{current_user.nil?}" } - %div - .line-resolve-all{ "v-show" => "discussionCount > 0", - ":class" => "{ 'has-next-btn': !loggedOut && resolvedDiscussionCount !== discussionCount }" } - %span.line-resolve-btn.is-disabled{ type: "button", - ":class" => "{ 'is-active': resolvedDiscussionCount === discussionCount }" } - = render "shared/icons/icon_status_success.svg" - %span.line-resolve-text - {{ resolvedDiscussionCount }}/{{ discussionCount }} {{ resolvedCountText }} resolved - = render "discussions/new_issue_for_all_discussions", merge_request: @merge_request - = render "discussions/jump_to_next" + .merge-request-tabs-container + .scrolling-tabs-container.inner-page-scroll-tabs.is-smaller + .fade-left= icon('angle-left') + .fade-right= icon('angle-right') + .nav-links.scrolling-tabs + %ul.merge-request-tabs + %li.notes-tab + = link_to namespace_project_merge_request_path(@project.namespace, @project, @merge_request), data: { target: 'div#notes', action: 'notes', toggle: 'tab' } do + Discussion + %span.badge= @merge_request.related_notes.user.count + - if @merge_request.source_project + %li.commits-tab + = link_to commits_namespace_project_merge_request_path(@project.namespace, @project, @merge_request), data: { target: 'div#commits', action: 'commits', toggle: 'tab' } do + Commits + %span.badge= @commits_count + - if @pipelines.any? + %li.pipelines-tab + = link_to pipelines_namespace_project_merge_request_path(@project.namespace, @project, @merge_request), data: { target: '#pipelines', action: 'pipelines', toggle: 'tab' } do + Pipelines + %span.badge= @pipelines.size + %li.diffs-tab + = link_to diffs_namespace_project_merge_request_path(@project.namespace, @project, @merge_request), data: { target: 'div#diffs', action: 'diffs', toggle: 'tab' } do + Changes + %span.badge= @merge_request.diff_size + #resolve-count-app.line-resolve-all-container.prepend-top-10{ "v-cloak" => true } + %resolve-count{ "inline-template" => true, ":logged-out" => "#{current_user.nil?}" } + %div + .line-resolve-all{ "v-show" => "discussionCount > 0", + ":class" => "{ 'has-next-btn': !loggedOut && resolvedDiscussionCount !== discussionCount }" } + %span.line-resolve-btn.is-disabled{ type: "button", + ":class" => "{ 'is-active': resolvedDiscussionCount === discussionCount }" } + = render "shared/icons/icon_status_success.svg" + %span.line-resolve-text + {{ resolvedDiscussionCount }}/{{ discussionCount }} {{ resolvedCountText }} resolved + = render "discussions/new_issue_for_all_discussions", merge_request: @merge_request + = render "discussions/jump_to_next" .tab-content#diff-notes-app #notes.notes.tab-pane.voting_notes diff --git a/app/views/projects/settings/integrations/_project_hook.html.haml b/app/views/projects/settings/integrations/_project_hook.html.haml index a6640592dba..8dc276a3bec 100644 --- a/app/views/projects/settings/integrations/_project_hook.html.haml +++ b/app/views/projects/settings/integrations/_project_hook.html.haml @@ -3,7 +3,7 @@ .col-md-8.col-lg-7 %strong.light-header= hook.url %div - - %w(push_events tag_push_events issues_events confidential_issues_events note_events merge_requests_events job_events pipeline_events wiki_page_events).each do |trigger| + - %w(push_events tag_push_events issues_events confidential_issues_events note_events merge_requests_events build_events pipeline_events wiki_page_events).each do |trigger| - if hook.send(trigger) %span.label.label-gray.deploy-project-label= trigger.titleize .col-md-4.col-lg-5.text-right-lg.prepend-top-5 diff --git a/app/views/shared/issuable/_search_bar.html.haml b/app/views/shared/issuable/_search_bar.html.haml index 622e2f33eea..0e535117353 100644 --- a/app/views/shared/issuable/_search_bar.html.haml +++ b/app/views/shared/issuable/_search_bar.html.haml @@ -19,7 +19,7 @@ dropdown_class: "filtered-search-history-dropdown", content_class: "filtered-search-history-dropdown-content", title: "Recent searches" }) do - .js-filtered-search-history-dropdown + .js-filtered-search-history-dropdown{ data: { project_full_path: @project.full_path } } .filtered-search-box-input-container .scroll-container %ul.tokens-container.list-unstyled diff --git a/app/views/shared/web_hooks/_form.html.haml b/app/views/shared/web_hooks/_form.html.haml index 1f0e7629fb4..37c3e61912c 100644 --- a/app/views/shared/web_hooks/_form.html.haml +++ b/app/views/shared/web_hooks/_form.html.haml @@ -54,10 +54,10 @@ %p.light This URL will be triggered when a merge request is created/updated/merged %li - = form.check_box :job_events, class: 'pull-left' + = form.check_box :build_events, class: 'pull-left' .prepend-left-20 - = form.label :job_events, class: 'list-label' do - %strong Job events + = form.label :build_events, class: 'list-label' do + %strong Jobs events %p.light This URL will be triggered when the job status changes %li diff --git a/changelogs/unreleased/24373-warning-message-go-away.yml b/changelogs/unreleased/24373-warning-message-go-away.yml new file mode 100644 index 00000000000..c0f2fd260ba --- /dev/null +++ b/changelogs/unreleased/24373-warning-message-go-away.yml @@ -0,0 +1,4 @@ +--- +title: 'Notes: Warning message should go away once resolved' +merge_request: 10823 +author: Jacopo Beschi @jacopo-beschi diff --git a/changelogs/unreleased/31106-tabs-alignment.yml b/changelogs/unreleased/31106-tabs-alignment.yml new file mode 100644 index 00000000000..53da08cc32d --- /dev/null +++ b/changelogs/unreleased/31106-tabs-alignment.yml @@ -0,0 +1,4 @@ +--- +title: prevent nav tabs from wrapping to new line +merge_request: +author: diff --git a/changelogs/unreleased/31902-namespace-recent-searches-to-project.yml b/changelogs/unreleased/31902-namespace-recent-searches-to-project.yml new file mode 100644 index 00000000000..e00eb6d8f72 --- /dev/null +++ b/changelogs/unreleased/31902-namespace-recent-searches-to-project.yml @@ -0,0 +1,4 @@ +--- +title: Scope issue/merge request recent searches to project +merge_request: +author: diff --git a/changelogs/unreleased/bvl-rename-build-events-to-job-events.yml b/changelogs/unreleased/bvl-rename-build-events-to-job-events.yml deleted file mode 100644 index 2ce01a71361..00000000000 --- a/changelogs/unreleased/bvl-rename-build-events-to-job-events.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Rename build_events to job_events -merge_request: 11287 -author: diff --git a/changelogs/unreleased/omega-submodules.yml b/changelogs/unreleased/omega-submodules.yml new file mode 100644 index 00000000000..1488eb72174 --- /dev/null +++ b/changelogs/unreleased/omega-submodules.yml @@ -0,0 +1,4 @@ +--- +title: 'Repository browser: handle in-repository submodule urls' +merge_request: +author: David Turner diff --git a/config/environments/production.rb b/config/environments/production.rb index a9d8ac4b6d4..82a19085b1d 100644 --- a/config/environments/production.rb +++ b/config/environments/production.rb @@ -16,7 +16,7 @@ Rails.application.configure do # config.assets.css_compressor = :sass # Don't fallback to assets pipeline if a precompiled asset is missed - config.assets.compile = true + config.assets.compile = false # Generate digests for assets URLs config.assets.digest = true diff --git a/db/migrate/20170511082759_rename_web_hooks_build_events_to_job_events.rb b/db/migrate/20170511082759_rename_web_hooks_build_events_to_job_events.rb deleted file mode 100644 index a2320a911b7..00000000000 --- a/db/migrate/20170511082759_rename_web_hooks_build_events_to_job_events.rb +++ /dev/null @@ -1,18 +0,0 @@ -# See http://doc.gitlab.com/ce/development/migration_style_guide.html -# for more information on how to write migrations for GitLab. - -class RenameWebHooksBuildEventsToJobEvents < ActiveRecord::Migration - include Gitlab::Database::MigrationHelpers - - DOWNTIME = false - - disable_ddl_transaction! - - def up - rename_column_concurrently :web_hooks, :build_events, :job_events - end - - def down - cleanup_concurrent_column_rename :web_hooks, :job_events, :build_events - end -end diff --git a/db/migrate/20170511083824_rename_services_build_events_to_job_events.rb b/db/migrate/20170511083824_rename_services_build_events_to_job_events.rb deleted file mode 100644 index 303d47078e7..00000000000 --- a/db/migrate/20170511083824_rename_services_build_events_to_job_events.rb +++ /dev/null @@ -1,18 +0,0 @@ -# See http://doc.gitlab.com/ce/development/migration_style_guide.html -# for more information on how to write migrations for GitLab. - -class RenameServicesBuildEventsToJobEvents < ActiveRecord::Migration - include Gitlab::Database::MigrationHelpers - - DOWNTIME = false - - disable_ddl_transaction! - - def up - rename_column_concurrently :services, :build_events, :job_events - end - - def down - cleanup_concurrent_column_rename :services, :job_events, :build_events - end -end diff --git a/db/post_migrate/20170511100900_cleanup_rename_web_hooks_build_events_to_job_events.rb b/db/post_migrate/20170511100900_cleanup_rename_web_hooks_build_events_to_job_events.rb deleted file mode 100644 index 281be90163a..00000000000 --- a/db/post_migrate/20170511100900_cleanup_rename_web_hooks_build_events_to_job_events.rb +++ /dev/null @@ -1,18 +0,0 @@ -# See http://doc.gitlab.com/ce/development/migration_style_guide.html -# for more information on how to write migrations for GitLab. - -class CleanupRenameWebHooksBuildEventsToJobEvents < ActiveRecord::Migration - include Gitlab::Database::MigrationHelpers - - DOWNTIME = false - - disable_ddl_transaction! - - def up - cleanup_concurrent_column_rename :web_hooks, :build_events, :job_events - end - - def down - rename_column_concurrently :web_hooks, :job_events, :build_events - end -end diff --git a/db/post_migrate/20170511101000_cleanup_rename_services_build_events_to_job_events.rb b/db/post_migrate/20170511101000_cleanup_rename_services_build_events_to_job_events.rb deleted file mode 100644 index 5d26df5688f..00000000000 --- a/db/post_migrate/20170511101000_cleanup_rename_services_build_events_to_job_events.rb +++ /dev/null @@ -1,18 +0,0 @@ -# See http://doc.gitlab.com/ce/development/migration_style_guide.html -# for more information on how to write migrations for GitLab. - -class CleanupRenameServicesBuildEventsToJobEvents < ActiveRecord::Migration - include Gitlab::Database::MigrationHelpers - - DOWNTIME = false - - disable_ddl_transaction! - - def up - cleanup_concurrent_column_rename :services, :build_events, :job_events - end - - def down - rename_column_concurrently :services, :job_events, :build_events - end -end diff --git a/db/schema.rb b/db/schema.rb index 513e3696646..a683521c84b 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -11,7 +11,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 20170511101000) do +ActiveRecord::Schema.define(version: 20170508190732) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" @@ -1125,13 +1125,13 @@ ActiveRecord::Schema.define(version: 20170511101000) do t.boolean "merge_requests_events", default: true t.boolean "tag_push_events", default: true t.boolean "note_events", default: true, null: false + t.boolean "build_events", default: false, null: false t.string "category", default: "common", null: false t.boolean "default", default: false t.boolean "wiki_page_events", default: true t.boolean "pipeline_events", default: false, null: false t.boolean "confidential_issues_events", default: true, null: false t.boolean "commit_events", default: true, null: false - t.boolean "job_events", default: false, null: false end add_index "services", ["project_id"], name: "index_services_on_project_id", using: :btree @@ -1401,11 +1401,11 @@ ActiveRecord::Schema.define(version: 20170511101000) do t.boolean "tag_push_events", default: false t.boolean "note_events", default: false, null: false t.boolean "enable_ssl_verification", default: true + t.boolean "build_events", default: false, null: false t.boolean "wiki_page_events", default: false, null: false t.string "token" t.boolean "pipeline_events", default: false, null: false t.boolean "confidential_issues_events", default: false, null: false - t.boolean "job_events", default: false, null: false t.boolean "repository_update_events", default: false, null: false end diff --git a/doc/api/services.md b/doc/api/services.md index f77d15c2ea1..0f42c256099 100644 --- a/doc/api/services.md +++ b/doc/api/services.md @@ -516,7 +516,7 @@ Example response: "merge_requests_events": true, "tag_push_events": true, "note_events": true, - "job_events": true, + "build_events": true, "pipeline_events": true, "properties": { "token": "9koXpg98eAheJpvBs5tK" diff --git a/lib/api/entities.rb b/lib/api/entities.rb index 01cc8e8e1ca..3fc2b453eb6 100644 --- a/lib/api/entities.rb +++ b/lib/api/entities.rb @@ -60,7 +60,7 @@ module API class ProjectHook < Hook expose :project_id, :issues_events, :merge_requests_events expose :note_events, :pipeline_events, :wiki_page_events - expose :job_events + expose :build_events, as: :job_events end class BasicProjectDetails < Grape::Entity @@ -470,7 +470,7 @@ module API expose :id, :title, :created_at, :updated_at, :active expose :push_events, :issues_events, :merge_requests_events expose :tag_push_events, :note_events, :pipeline_events - expose :job_events + expose :build_events, as: :job_events # Expose serialized properties expose :properties do |service, options| field_names = service.fields. diff --git a/lib/api/project_hooks.rb b/lib/api/project_hooks.rb index 7a345289617..87dfd1573a4 100644 --- a/lib/api/project_hooks.rb +++ b/lib/api/project_hooks.rb @@ -54,6 +54,7 @@ module API end post ":id/hooks" do hook_params = declared_params(include_missing: false) + hook_params[:build_events] = hook_params.delete(:job_events) { false } hook = user_project.hooks.new(hook_params) @@ -77,6 +78,7 @@ module API hook = user_project.hooks.find(params.delete(:hook_id)) update_params = declared_params(include_missing: false) + update_params[:build_events] = update_params.delete(:job_events) if update_params[:job_events] if hook.update_attributes(update_params) present hook, with: Entities::ProjectHook diff --git a/lib/api/v3/entities.rb b/lib/api/v3/entities.rb index 332f233bf5e..56a9b019f1b 100644 --- a/lib/api/v3/entities.rb +++ b/lib/api/v3/entities.rb @@ -238,8 +238,7 @@ module API class ProjectService < Grape::Entity expose :id, :title, :created_at, :updated_at, :active expose :push_events, :issues_events, :merge_requests_events - expose :tag_push_events, :note_events, :pipeline_events - expose :job_events, as: :build_events + expose :tag_push_events, :note_events, :build_events, :pipeline_events # Expose serialized properties expose :properties do |service, options| field_names = service.fields. @@ -251,8 +250,7 @@ module API class ProjectHook < ::API::Entities::Hook expose :project_id, :issues_events, :merge_requests_events - expose :note_events, :pipeline_events, :wiki_page_events - expose :job_events, as: :build_events + expose :note_events, :build_events, :pipeline_events, :wiki_page_events end class Issue < ::API::Entities::Issue diff --git a/lib/gitlab/database/migration_helpers.rb b/lib/gitlab/database/migration_helpers.rb index f3476dadec8..e76c9abbe04 100644 --- a/lib/gitlab/database/migration_helpers.rb +++ b/lib/gitlab/database/migration_helpers.rb @@ -283,7 +283,6 @@ module Gitlab add_column(table, new, new_type, limit: old_col.limit, - null: old_col.null, precision: old_col.precision, scale: old_col.scale) @@ -307,6 +306,8 @@ module Gitlab update_column_in_batches(table, new, Arel::Table.new(table)[old]) + change_column_null(table, new, false) unless old_col.null + copy_indexes(table, old, new) copy_foreign_keys(table, old, new) end diff --git a/lib/gitlab/git/repository.rb b/lib/gitlab/git/repository.rb index 7a051444603..d380c5021ee 100644 --- a/lib/gitlab/git/repository.rb +++ b/lib/gitlab/git/repository.rb @@ -116,7 +116,7 @@ module Gitlab # Returns the number of valid branches def branch_count - Gitlab::GitalyClient.migrate(:branch_names) do |is_enabled| + gitaly_migrate(:branch_names) do |is_enabled| if is_enabled gitaly_ref_client.count_branch_names else @@ -135,7 +135,7 @@ module Gitlab # Returns the number of valid tags def tag_count - Gitlab::GitalyClient.migrate(:tag_names) do |is_enabled| + gitaly_migrate(:tag_names) do |is_enabled| if is_enabled gitaly_ref_client.count_tag_names else @@ -473,7 +473,7 @@ module Gitlab def ref_name_for_sha(ref_path, sha) # NOTE: This feature is intentionally disabled until # https://gitlab.com/gitlab-org/gitaly/issues/180 is resolved - # Gitlab::GitalyClient.migrate(:find_ref_name) do |is_enabled| + # gitaly_migrate(:find_ref_name) do |is_enabled| # if is_enabled # gitaly_ref_client.find_ref_name(sha, ref_path) # else diff --git a/spec/factories/project_hooks.rb b/spec/factories/project_hooks.rb index cd754ea235f..0210e871a63 100644 --- a/spec/factories/project_hooks.rb +++ b/spec/factories/project_hooks.rb @@ -14,7 +14,7 @@ FactoryGirl.define do issues_events true confidential_issues_events true note_events true - job_events true + build_events true pipeline_events true wiki_page_events true end diff --git a/spec/features/issues/create_issue_for_discussions_in_merge_request_spec.rb b/spec/features/issues/create_issue_for_discussions_in_merge_request_spec.rb index dc13cab2cd1..24e2419b5ce 100644 --- a/spec/features/issues/create_issue_for_discussions_in_merge_request_spec.rb +++ b/spec/features/issues/create_issue_for_discussions_in_merge_request_spec.rb @@ -14,7 +14,7 @@ feature 'Resolving all open discussions in a merge request from an issue', featu end it 'shows a button to resolve all discussions by creating a new issue' do - within('li#resolve-count-app') do + within('#resolve-count-app') do expect(page).to have_link "Resolve all discussions in new issue", href: new_namespace_project_issue_path(project.namespace, project, merge_request_to_resolve_discussions_of: merge_request.iid) end end diff --git a/spec/features/issues/filtered_search/recent_searches_spec.rb b/spec/features/issues/filtered_search/recent_searches_spec.rb index 08fe3b4553b..09f228bcf49 100644 --- a/spec/features/issues/filtered_search/recent_searches_spec.rb +++ b/spec/features/issues/filtered_search/recent_searches_spec.rb @@ -3,17 +3,17 @@ require 'spec_helper' describe 'Recent searches', js: true, feature: true do include FilteredSearchHelpers - let!(:group) { create(:group) } - let!(:project) { create(:project, group: group) } - let!(:user) { create(:user) } + let(:project_1) { create(:empty_project, :public) } + let(:project_2) { create(:empty_project, :public) } + let(:project_1_local_storage_key) { "#{project_1.full_path}-issue-recent-searches" } before do Capybara.ignore_hidden_elements = false - project.add_master(user) - group.add_developer(user) - create(:issue, project: project) - login_as(user) + create(:issue, project: project_1) + create(:issue, project: project_2) + # Visit any fast-loading page so we can clear local storage without a DOM exception + visit '/404' remove_recent_searches end @@ -22,7 +22,7 @@ describe 'Recent searches', js: true, feature: true do end it 'searching adds to recent searches' do - visit namespace_project_issues_path(project.namespace, project) + visit namespace_project_issues_path(project_1.namespace, project_1) input_filtered_search('foo', submit: true) input_filtered_search('bar', submit: true) @@ -35,8 +35,8 @@ describe 'Recent searches', js: true, feature: true do end it 'visiting URL with search params adds to recent searches' do - visit namespace_project_issues_path(project.namespace, project, label_name: 'foo', search: 'bar') - visit namespace_project_issues_path(project.namespace, project, label_name: 'qux', search: 'garply') + visit namespace_project_issues_path(project_1.namespace, project_1, label_name: 'foo', search: 'bar') + visit namespace_project_issues_path(project_1.namespace, project_1, label_name: 'qux', search: 'garply') items = all('.filtered-search-history-dropdown-item', visible: false) @@ -46,9 +46,9 @@ describe 'Recent searches', js: true, feature: true do end it 'saved recent searches are restored last on the list' do - set_recent_searches('["saved1", "saved2"]') + set_recent_searches(project_1_local_storage_key, '["saved1", "saved2"]') - visit namespace_project_issues_path(project.namespace, project, search: 'foo') + visit namespace_project_issues_path(project_1.namespace, project_1, search: 'foo') items = all('.filtered-search-history-dropdown-item', visible: false) @@ -58,9 +58,27 @@ describe 'Recent searches', js: true, feature: true do expect(items[2].text).to eq('saved2') end + it 'searches are scoped to projects' do + visit namespace_project_issues_path(project_1.namespace, project_1) + + input_filtered_search('foo', submit: true) + input_filtered_search('bar', submit: true) + + visit namespace_project_issues_path(project_2.namespace, project_2) + + input_filtered_search('more', submit: true) + input_filtered_search('things', submit: true) + + items = all('.filtered-search-history-dropdown-item', visible: false) + + expect(items.count).to eq(2) + expect(items[0].text).to eq('things') + expect(items[1].text).to eq('more') + end + it 'clicking item fills search input' do - set_recent_searches('["foo", "bar"]') - visit namespace_project_issues_path(project.namespace, project) + set_recent_searches(project_1_local_storage_key, '["foo", "bar"]') + visit namespace_project_issues_path(project_1.namespace, project_1) all('.filtered-search-history-dropdown-item', visible: false)[0].trigger('click') wait_for_filtered_search('foo') @@ -69,8 +87,8 @@ describe 'Recent searches', js: true, feature: true do end it 'clear recent searches button, clears recent searches' do - set_recent_searches('["foo"]') - visit namespace_project_issues_path(project.namespace, project) + set_recent_searches(project_1_local_storage_key, '["foo"]') + visit namespace_project_issues_path(project_1.namespace, project_1) items_before = all('.filtered-search-history-dropdown-item', visible: false) @@ -83,8 +101,8 @@ describe 'Recent searches', js: true, feature: true do end it 'shows flash error when failed to parse saved history' do - set_recent_searches('fail') - visit namespace_project_issues_path(project.namespace, project) + set_recent_searches(project_1_local_storage_key, 'fail') + visit namespace_project_issues_path(project_1.namespace, project_1) expect(find('.flash-alert')).to have_text('An error occured while parsing recent searches') end diff --git a/spec/features/projects/settings/integration_settings_spec.rb b/spec/features/projects/settings/integration_settings_spec.rb index d3232f0cc16..7909234556e 100644 --- a/spec/features/projects/settings/integration_settings_spec.rb +++ b/spec/features/projects/settings/integration_settings_spec.rb @@ -52,7 +52,6 @@ feature 'Integration settings', feature: true do fill_in 'hook_url', with: url check 'Tag push events' check 'Enable SSL verification' - check 'Job events' click_button 'Add webhook' @@ -60,7 +59,6 @@ feature 'Integration settings', feature: true do expect(page).to have_content('SSL Verification: enabled') expect(page).to have_content('Push Events') expect(page).to have_content('Tag Push Events') - expect(page).to have_content('Job events') end scenario 'edit existing webhook' do diff --git a/spec/helpers/submodule_helper_spec.rb b/spec/helpers/submodule_helper_spec.rb index 9da33792659..18935be95c9 100644 --- a/spec/helpers/submodule_helper_spec.rb +++ b/spec/helpers/submodule_helper_spec.rb @@ -81,6 +81,19 @@ describe SubmoduleHelper do end end + context 'in-repository submodule' do + let(:group) { create(:group, name: "Master Project", path: "master-project") } + let(:project) { create(:empty_project, group: group) } + before do + self.instance_variable_set(:@project, project) + end + + it 'in-repository' do + stub_url('./') + expect(submodule_links(submodule_item)).to eq(["/master-project/#{project.path}", "/master-project/#{project.path}/tree/hash"]) + end + end + context 'submodule on gitlab.com' do it 'detects ssh' do stub_url('git@gitlab.com:gitlab-org/gitlab-ce.git') diff --git a/spec/javascripts/lib/utils/common_utils_spec.js b/spec/javascripts/lib/utils/common_utils_spec.js index 5eb147ed888..42a9067ade5 100644 --- a/spec/javascripts/lib/utils/common_utils_spec.js +++ b/spec/javascripts/lib/utils/common_utils_spec.js @@ -41,6 +41,16 @@ require('~/lib/utils/common_utils'); const paramsArray = gl.utils.getUrlParamsArray(); expect(paramsArray[0][0] !== '?').toBe(true); }); + + it('should decode params', () => { + history.pushState('', '', '?label_name%5B%5D=test'); + + expect( + gl.utils.getUrlParamsArray()[0], + ).toBe('label_name[]=test'); + + history.pushState('', '', '?'); + }); }); describe('gl.utils.handleLocationHash', () => { diff --git a/spec/javascripts/notes_spec.js b/spec/javascripts/notes_spec.js index 8243a9c991a..87745ea9817 100644 --- a/spec/javascripts/notes_spec.js +++ b/spec/javascripts/notes_spec.js @@ -14,6 +14,7 @@ import '~/notes'; gl.utils = gl.utils || {}; describe('Notes', function() { + const FLASH_TYPE_ALERT = 'alert'; var commentsTemplate = 'issues/issue_with_comment.html.raw'; preloadFixtures(commentsTemplate); @@ -498,5 +499,33 @@ import '~/notes'; expect($tempNote.find('.timeline-content').hasClass('discussion')).toBeTruthy(); }); }); + + describe('appendFlash', () => { + beforeEach(() => { + this.notes = new Notes(); + }); + + it('shows a flash message', () => { + this.notes.addFlash('Error message', FLASH_TYPE_ALERT, this.notes.parentTimeline); + + expect(document.querySelectorAll('.flash-alert').length).toBe(1); + }); + }); + + describe('clearFlash', () => { + beforeEach(() => { + $(document).off('ajax:success'); + this.notes = new Notes(); + }); + + it('removes all the associated flash messages', () => { + this.notes.addFlash('Error message 1', FLASH_TYPE_ALERT, this.notes.parentTimeline); + this.notes.addFlash('Error message 2', FLASH_TYPE_ALERT, this.notes.parentTimeline); + + this.notes.clearFlash(); + + expect(document.querySelectorAll('.flash-alert').length).toBe(0); + }); + }); }); }).call(window); diff --git a/spec/lib/gitlab/database/migration_helpers_spec.rb b/spec/lib/gitlab/database/migration_helpers_spec.rb index d6535f97665..dfa3ae9142e 100644 --- a/spec/lib/gitlab/database/migration_helpers_spec.rb +++ b/spec/lib/gitlab/database/migration_helpers_spec.rb @@ -382,7 +382,6 @@ describe Gitlab::Database::MigrationHelpers, lib: true do expect(model).to receive(:add_column). with(:users, :new, :integer, limit: old_column.limit, - null: old_column.null, precision: old_column.precision, scale: old_column.scale) @@ -391,6 +390,8 @@ describe Gitlab::Database::MigrationHelpers, lib: true do expect(model).to receive(:update_column_in_batches) + expect(model).to receive(:change_column_null).with(:users, :new, false) + expect(model).to receive(:copy_indexes).with(:users, :old, :new) expect(model).to receive(:copy_foreign_keys).with(:users, :old, :new) @@ -408,7 +409,6 @@ describe Gitlab::Database::MigrationHelpers, lib: true do expect(model).to receive(:add_column). with(:users, :new, :integer, limit: old_column.limit, - null: old_column.null, precision: old_column.precision, scale: old_column.scale) @@ -417,6 +417,8 @@ describe Gitlab::Database::MigrationHelpers, lib: true do expect(model).to receive(:update_column_in_batches) + expect(model).to receive(:change_column_null).with(:users, :new, false) + expect(model).to receive(:copy_indexes).with(:users, :old, :new) expect(model).to receive(:copy_foreign_keys).with(:users, :old, :new) diff --git a/spec/lib/gitlab/import_export/project.json b/spec/lib/gitlab/import_export/project.json index e3599d6fe59..fdbb6a0556d 100644 --- a/spec/lib/gitlab/import_export/project.json +++ b/spec/lib/gitlab/import_export/project.json @@ -6997,7 +6997,7 @@ "merge_requests_events": true, "tag_push_events": true, "note_events": true, - "job_events": true, + "build_events": true, "type": "TeamcityService", "category": "ci", "default": false, @@ -7041,7 +7041,7 @@ "merge_requests_events": true, "tag_push_events": true, "note_events": true, - "job_events": true, + "build_events": true, "type": "RedmineService", "category": "issue_tracker", "default": false, @@ -7063,7 +7063,7 @@ "merge_requests_events": true, "tag_push_events": true, "note_events": true, - "job_events": true, + "build_events": true, "type": "PushoverService", "category": "common", "default": false, @@ -7085,7 +7085,7 @@ "merge_requests_events": true, "tag_push_events": true, "note_events": true, - "job_events": true, + "build_events": true, "type": "PivotalTrackerService", "category": "common", "default": false, @@ -7108,7 +7108,7 @@ "merge_requests_events": true, "tag_push_events": true, "note_events": true, - "job_events": true, + "build_events": true, "type": "JiraService", "category": "issue_tracker", "default": false, @@ -7130,7 +7130,7 @@ "merge_requests_events": true, "tag_push_events": true, "note_events": true, - "job_events": true, + "build_events": true, "type": "IrkerService", "category": "common", "default": false, @@ -7174,7 +7174,7 @@ "merge_requests_events": true, "tag_push_events": true, "note_events": true, - "job_events": true, + "build_events": true, "type": "GemnasiumService", "category": "common", "default": false, @@ -7196,7 +7196,7 @@ "merge_requests_events": true, "tag_push_events": true, "note_events": true, - "job_events": true, + "build_events": true, "type": "FlowdockService", "category": "common", "default": false, @@ -7218,7 +7218,7 @@ "merge_requests_events": true, "tag_push_events": true, "note_events": true, - "job_events": true, + "build_events": true, "type": "ExternalWikiService", "category": "common", "default": false, @@ -7240,7 +7240,7 @@ "merge_requests_events": true, "tag_push_events": true, "note_events": true, - "job_events": true, + "build_events": true, "type": "EmailsOnPushService", "category": "common", "default": false, @@ -7262,7 +7262,7 @@ "merge_requests_events": true, "tag_push_events": true, "note_events": true, - "job_events": true, + "build_events": true, "type": "DroneCiService", "category": "ci", "default": false, @@ -7284,7 +7284,7 @@ "merge_requests_events": true, "tag_push_events": true, "note_events": true, - "job_events": true, + "build_events": true, "type": "CustomIssueTrackerService", "category": "issue_tracker", "default": false, @@ -7306,7 +7306,7 @@ "merge_requests_events": true, "tag_push_events": true, "note_events": true, - "job_events": true, + "build_events": true, "type": "CampfireService", "category": "common", "default": false, @@ -7328,7 +7328,7 @@ "merge_requests_events": true, "tag_push_events": true, "note_events": true, - "job_events": true, + "build_events": true, "type": "BuildkiteService", "category": "ci", "default": false, @@ -7350,7 +7350,7 @@ "merge_requests_events": true, "tag_push_events": true, "note_events": true, - "job_events": true, + "build_events": true, "type": "BambooService", "category": "ci", "default": false, @@ -7372,7 +7372,7 @@ "merge_requests_events": true, "tag_push_events": true, "note_events": true, - "job_events": true, + "build_events": true, "type": "AssemblaService", "category": "common", "default": false, @@ -7394,7 +7394,7 @@ "merge_requests_events": true, "tag_push_events": true, "note_events": true, - "job_events": true, + "build_events": true, "type": "AssemblaService", "category": "common", "default": false, @@ -7416,7 +7416,7 @@ "merge_requests_events": true, "tag_push_events": true, "note_events": true, - "job_events": true, + "build_events": true, "category": "common", "default": false, "wiki_page_events": true, diff --git a/spec/lib/gitlab/import_export/relation_factory_spec.rb b/spec/lib/gitlab/import_export/relation_factory_spec.rb index 5417c7534ea..744fed44925 100644 --- a/spec/lib/gitlab/import_export/relation_factory_spec.rb +++ b/spec/lib/gitlab/import_export/relation_factory_spec.rb @@ -33,7 +33,7 @@ describe Gitlab::ImportExport::RelationFactory, lib: true do 'tag_push_events' => false, 'note_events' => true, 'enable_ssl_verification' => true, - 'job_events' => false, + 'build_events' => false, 'wiki_page_events' => true, 'token' => token } diff --git a/spec/lib/gitlab/import_export/safe_model_attributes.yml b/spec/lib/gitlab/import_export/safe_model_attributes.yml index c22fba11225..2b95f76e045 100644 --- a/spec/lib/gitlab/import_export/safe_model_attributes.yml +++ b/spec/lib/gitlab/import_export/safe_model_attributes.yml @@ -292,7 +292,7 @@ Service: - tag_push_events - note_events - pipeline_events -- job_events +- build_events - category - default - wiki_page_events @@ -312,7 +312,7 @@ ProjectHook: - note_events - pipeline_events - enable_ssl_verification -- job_events +- build_events - wiki_page_events - token - group_id diff --git a/spec/lib/gitlab/prometheus/queries/deployment_query_spec.rb b/spec/lib/gitlab/prometheus/queries/deployment_query_spec.rb index cc7d7e57f06..d957dd932c4 100644 --- a/spec/lib/gitlab/prometheus/queries/deployment_query_spec.rb +++ b/spec/lib/gitlab/prometheus/queries/deployment_query_spec.rb @@ -8,27 +8,28 @@ describe Gitlab::Prometheus::Queries::DeploymentQuery, lib: true do subject { described_class.new(client) } around do |example| - Timecop.freeze { example.run } + time_without_subsecond_values = Time.local(2008, 9, 1, 12, 0, 0) + Timecop.freeze(time_without_subsecond_values) { example.run } end it 'sends appropriate queries to prometheus' do - start_time_matcher = be_within(0.5).of((deployment.created_at - 30.minutes).to_f) - stop_time_matcher = be_within(0.5).of((deployment.created_at + 30.minutes).to_f) - created_at_matcher = be_within(0.5).of(deployment.created_at.to_f) + start_time = (deployment.created_at - 30.minutes).to_f + stop_time = (deployment.created_at + 30.minutes).to_f + created_at = deployment.created_at.to_f expect(client).to receive(:query_range).with('avg(container_memory_usage_bytes{container_name!="POD",environment="environment-slug"}) / 2^20', - start: start_time_matcher, stop: stop_time_matcher) + start: start_time, stop: stop_time) expect(client).to receive(:query).with('avg(avg_over_time(container_memory_usage_bytes{container_name!="POD",environment="environment-slug"}[30m]))', - time: created_at_matcher) + time: created_at) expect(client).to receive(:query).with('avg(avg_over_time(container_memory_usage_bytes{container_name!="POD",environment="environment-slug"}[30m]))', - time: stop_time_matcher) + time: stop_time) expect(client).to receive(:query_range).with('avg(rate(container_cpu_usage_seconds_total{container_name!="POD",environment="environment-slug"}[2m])) * 100', - start: start_time_matcher, stop: stop_time_matcher) + start: start_time, stop: stop_time) expect(client).to receive(:query).with('avg(rate(container_cpu_usage_seconds_total{container_name!="POD",environment="environment-slug"}[30m])) * 100', - time: created_at_matcher) + time: created_at) expect(client).to receive(:query).with('avg(rate(container_cpu_usage_seconds_total{container_name!="POD",environment="environment-slug"}[30m])) * 100', - time: stop_time_matcher) + time: stop_time) expect(subject.query(deployment.id)).to eq(memory_values: nil, memory_before: nil, memory_after: nil, cpu_values: nil, cpu_before: nil, cpu_after: nil) diff --git a/spec/migrations/migrate_build_events_to_pipeline_events_spec.rb b/spec/migrations/migrate_build_events_to_pipeline_events_spec.rb new file mode 100644 index 00000000000..57eb03e3c80 --- /dev/null +++ b/spec/migrations/migrate_build_events_to_pipeline_events_spec.rb @@ -0,0 +1,74 @@ +require 'spec_helper' +require Rails.root.join('db', 'post_migrate', '20170301205640_migrate_build_events_to_pipeline_events.rb') + +# This migration uses multiple threads, and thus different transactions. This +# means data created in this spec may not be visible to some threads. To work +# around this we use the TRUNCATE cleaning strategy. +describe MigrateBuildEventsToPipelineEvents, truncate: true do + let(:migration) { described_class.new } + let(:project_with_pipeline_service) { create(:empty_project) } + let(:project_with_build_service) { create(:empty_project) } + + before do + ActiveRecord::Base.connection.execute <<-SQL + INSERT INTO services (properties, build_events, pipeline_events, type) + VALUES + ('{"notify_only_broken_builds":true}', true, false, 'SlackService') + , ('{"notify_only_broken_builds":true}', true, false, 'MattermostService') + , ('{"notify_only_broken_builds":true}', true, false, 'HipchatService') + ; + SQL + + ActiveRecord::Base.connection.execute <<-SQL + INSERT INTO services + (properties, build_events, pipeline_events, type, project_id) + VALUES + ('{"notify_only_broken_builds":true}', true, false, + 'BuildsEmailService', #{project_with_pipeline_service.id}) + , ('{"notify_only_broken_pipelines":true}', false, true, + 'PipelinesEmailService', #{project_with_pipeline_service.id}) + , ('{"notify_only_broken_builds":true}', true, false, + 'BuildsEmailService', #{project_with_build_service.id}) + ; + SQL + end + + describe '#up' do + before do + silence_migration = Module.new do + # rubocop:disable Rails/Delegate + def execute(query) + connection.execute(query) + end + end + + migration.extend(silence_migration) + migration.up + end + + it 'migrates chat service properly' do + [SlackService, MattermostService, HipchatService].each do |service| + expect(service.count).to eq(1) + + verify_service_record(service.first) + end + end + + it 'migrates pipelines email service only if it has none before' do + Project.find_each do |project| + pipeline_service_count = + project.services.where(type: 'PipelinesEmailService').count + + expect(pipeline_service_count).to eq(1) + + verify_service_record(project.pipelines_email_service) + end + end + + def verify_service_record(service) + expect(service.notify_only_broken_pipelines).to be(true) + expect(service.build_events).to be(false) + expect(service.pipeline_events).to be(true) + end + end +end diff --git a/spec/requests/api/project_hooks_spec.rb b/spec/requests/api/project_hooks_spec.rb index 0f9330b062d..aee0e17a153 100644 --- a/spec/requests/api/project_hooks_spec.rb +++ b/spec/requests/api/project_hooks_spec.rb @@ -60,7 +60,7 @@ describe API::ProjectHooks, 'ProjectHooks' do expect(json_response['merge_requests_events']).to eq(hook.merge_requests_events) expect(json_response['tag_push_events']).to eq(hook.tag_push_events) expect(json_response['note_events']).to eq(hook.note_events) - expect(json_response['job_events']).to eq(hook.job_events) + expect(json_response['job_events']).to eq(hook.build_events) expect(json_response['pipeline_events']).to eq(hook.pipeline_events) expect(json_response['wiki_page_events']).to eq(hook.wiki_page_events) expect(json_response['enable_ssl_verification']).to eq(hook.enable_ssl_verification) @@ -148,7 +148,7 @@ describe API::ProjectHooks, 'ProjectHooks' do expect(json_response['merge_requests_events']).to eq(hook.merge_requests_events) expect(json_response['tag_push_events']).to eq(hook.tag_push_events) expect(json_response['note_events']).to eq(hook.note_events) - expect(json_response['job_events']).to eq(hook.job_events) + expect(json_response['job_events']).to eq(hook.build_events) expect(json_response['pipeline_events']).to eq(hook.pipeline_events) expect(json_response['wiki_page_events']).to eq(hook.wiki_page_events) expect(json_response['enable_ssl_verification']).to eq(hook.enable_ssl_verification) diff --git a/spec/requests/api/v3/project_hooks_spec.rb b/spec/requests/api/v3/project_hooks_spec.rb index 1969d1c7f2b..a3a4c77d09d 100644 --- a/spec/requests/api/v3/project_hooks_spec.rb +++ b/spec/requests/api/v3/project_hooks_spec.rb @@ -58,7 +58,7 @@ describe API::ProjectHooks, 'ProjectHooks' do expect(json_response['merge_requests_events']).to eq(hook.merge_requests_events) expect(json_response['tag_push_events']).to eq(hook.tag_push_events) expect(json_response['note_events']).to eq(hook.note_events) - expect(json_response['build_events']).to eq(hook.job_events) + expect(json_response['build_events']).to eq(hook.build_events) expect(json_response['pipeline_events']).to eq(hook.pipeline_events) expect(json_response['wiki_page_events']).to eq(hook.wiki_page_events) expect(json_response['enable_ssl_verification']).to eq(hook.enable_ssl_verification) @@ -143,7 +143,7 @@ describe API::ProjectHooks, 'ProjectHooks' do expect(json_response['merge_requests_events']).to eq(hook.merge_requests_events) expect(json_response['tag_push_events']).to eq(hook.tag_push_events) expect(json_response['note_events']).to eq(hook.note_events) - expect(json_response['build_events']).to eq(hook.job_events) + expect(json_response['build_events']).to eq(hook.build_events) expect(json_response['pipeline_events']).to eq(hook.pipeline_events) expect(json_response['wiki_page_events']).to eq(hook.wiki_page_events) expect(json_response['enable_ssl_verification']).to eq(hook.enable_ssl_verification) diff --git a/spec/support/filtered_search_helpers.rb b/spec/support/filtered_search_helpers.rb index 36be0bb6bf8..37cc308e613 100644 --- a/spec/support/filtered_search_helpers.rb +++ b/spec/support/filtered_search_helpers.rb @@ -73,11 +73,11 @@ module FilteredSearchHelpers end def remove_recent_searches - execute_script('window.localStorage.removeItem(\'issue-recent-searches\');') + execute_script('window.localStorage.clear();') end - def set_recent_searches(input) - execute_script("window.localStorage.setItem('issue-recent-searches', '#{input}');") + def set_recent_searches(key, input) + execute_script("window.localStorage.setItem('#{key}', '#{input}');") end def wait_for_filtered_search(text) |