diff options
48 files changed, 502 insertions, 254 deletions
diff --git a/.scss-lint.yml b/.scss-lint.yml index 835a4a88c44..9bfc18b9698 100644 --- a/.scss-lint.yml +++ b/.scss-lint.yml @@ -65,7 +65,7 @@ linters: # Reports when you have an empty rule set. EmptyRule: - enabled: false + enabled: true # Reports when you have an @extend directive. ExtendDirective: diff --git a/CHANGELOG b/CHANGELOG index 062a8cc4553..a4794485476 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -2,9 +2,15 @@ Please view this file on the master branch, on stable branches it's out of date. v 8.8.0 (unreleased) - Remove future dates from contribution calendar graph. + - Fix error when visiting commit builds page before build was updated + - Add 'l' shortcut to open Label dropdown on issuables and 'i' to create new issue on a project v 8.7.1 (unreleased) - - Use the `can?` helper instead of `current_user.can?` + - Fix .gitlab-ci.yml parsing issue when hidde job is a template without script definition. !3849 + - Fix license detection to detect all license files, not only known licenses. !3878 + - Use the `can?` helper instead of `current_user.can?`. !3882 + - Prevent users from deleting Webhooks via API they do not own + - Fix Error 500 due to stale cache when projects are renamed or transferred v 8.7.0 - Gitlab::GitAccess and Gitlab::GitAccessWiki are now instrumented @@ -217,7 +217,7 @@ gem 'font-awesome-rails', '~> 4.2' gem 'gitlab_emoji', '~> 0.3.0' gem 'gon', '~> 6.0.1' gem 'jquery-atwho-rails', '~> 1.3.2' -gem 'jquery-rails', '~> 4.0.0' +gem 'jquery-rails', '~> 4.1.0' gem 'jquery-scrollto-rails', '~> 1.4.3' gem 'jquery-ui-rails', '~> 5.0.0' gem 'raphael-rails', '~> 2.1.2' diff --git a/Gemfile.lock b/Gemfile.lock index 7dd237b3d4c..679c52eff25 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -431,8 +431,8 @@ GEM json ipaddress (0.8.2) jquery-atwho-rails (1.3.2) - jquery-rails (4.0.5) - rails-dom-testing (~> 1.0) + jquery-rails (4.1.1) + rails-dom-testing (>= 1, < 3) railties (>= 4.2.0) thor (>= 0.14, < 2.0) jquery-scrollto-rails (1.4.3) @@ -952,7 +952,7 @@ DEPENDENCIES httparty (~> 0.13.3) influxdb (~> 0.2) jquery-atwho-rails (~> 1.3.2) - jquery-rails (~> 4.0.0) + jquery-rails (~> 4.1.0) jquery-scrollto-rails (~> 1.4.3) jquery-turbolinks (~> 2.1.0) jquery-ui-rails (~> 5.0.0) diff --git a/app/assets/javascripts/awards_handler.coffee b/app/assets/javascripts/awards_handler.coffee index af4462ece38..fcba9818726 100644 --- a/app/assets/javascripts/awards_handler.coffee +++ b/app/assets/javascripts/awards_handler.coffee @@ -1,5 +1,5 @@ class @AwardsHandler - constructor: (@get_emojis_url, @post_emoji_url, @noteable_type, @noteable_id, @aliases) -> + constructor: (@get_emojis_url, @post_emoji_url, @noteable_type, @noteable_id, @unicodes) -> $(".js-add-award").on "click", (event) => event.stopPropagation() event.preventDefault() @@ -31,6 +31,8 @@ class @AwardsHandler awards_handler.addAward emoji + $(this).trigger 'blur' + didUserClickEmoji: (that, emoji) -> if $(that).siblings("button:has([data-emoji=#{emoji}])").attr("data-original-title") $(that).siblings("button:has([data-emoji=#{emoji}])").attr("data-original-title").indexOf('me') > -1 @@ -55,7 +57,6 @@ class @AwardsHandler , 200 addAward: (emoji) -> - emoji = @normilizeEmojiName(emoji) @postEmoji emoji, => @addAwardToEmojiBar(emoji) @@ -64,7 +65,6 @@ class @AwardsHandler addAwardToEmojiBar: (emoji) -> @addEmojiToFrequentlyUsedList(emoji) - emoji = @normilizeEmojiName(emoji) if @exist(emoji) if @isActive(emoji) @decrementCounter(emoji) @@ -146,15 +146,7 @@ class @AwardsHandler $('.award-control').tooltip() resolveNameToCssClass: (emoji) -> - emoji_icon = $(".emoji-menu-content [data-emoji='#{emoji}']") - - if emoji_icon.length > 0 - unicodeName = emoji_icon.data("unicode-name") - else - # Find by alias - unicodeName = $(".emoji-menu-content [data-aliases*=':#{emoji}:']").data("unicode-name") - - "emoji-#{unicodeName}" + "emoji-#{@unicodes[emoji]}" postEmoji: (emoji, callback) -> $.post @post_emoji_url, { note: { @@ -173,9 +165,6 @@ class @AwardsHandler scrollTop: $('.awards').offset().top - 80 }, 200) - normilizeEmojiName: (emoji) -> - @aliases[emoji] || emoji - addEmojiToFrequentlyUsedList: (emoji) -> frequently_used_emojis = @getFrequentlyUsedEmojis() frequently_used_emojis.push(emoji) diff --git a/app/assets/javascripts/issuable_context.js.coffee b/app/assets/javascripts/issuable_context.js.coffee index 3a439b94c59..3c491ebfc4c 100644 --- a/app/assets/javascripts/issuable_context.js.coffee +++ b/app/assets/javascripts/issuable_context.js.coffee @@ -10,8 +10,8 @@ class @IssuableContext $(this).submit() $(document) - .off 'click', '.dropdown-content a' - .on 'click', '.dropdown-content a', (e) -> + .off 'click', '.issuable-sidebar .dropdown-content a' + .on 'click', '.issuable-sidebar .dropdown-content a', (e) -> e.preventDefault() $(document) diff --git a/app/assets/javascripts/right_sidebar.js.coffee b/app/assets/javascripts/right_sidebar.js.coffee index 67403554340..2d084b76cfe 100644 --- a/app/assets/javascripts/right_sidebar.js.coffee +++ b/app/assets/javascripts/right_sidebar.js.coffee @@ -1,10 +1,12 @@ class @Sidebar constructor: (currentUser) -> + @sidebar = $('aside') + @addEventListeners() addEventListeners: -> - $('aside').on('click', '.sidebar-collapsed-icon', @sidebarCollapseClicked) - $('.dropdown').on('hidden.gl.dropdown', @sidebarDropdownHidden) + @sidebar.on('click', '.sidebar-collapsed-icon', @, @sidebarCollapseClicked) + $('.dropdown').on('hidden.gl.dropdown', @, @onSidebarDropdownHidden) $('.dropdown').on('loading.gl.dropdown', @sidebarDropdownLoading) $('.dropdown').on('loaded.gl.dropdown', @sidebarDropdownLoaded) @@ -30,26 +32,56 @@ class @Sidebar else i.show() - sidebarCollapseClicked: (e) -> + sidebar = e.data e.preventDefault() $block = $(@).closest('.block') + sidebar.openDropdown($block); - $('aside') - .find('.gutter-toggle') - .trigger('click') - $editLink = $block.find('.edit-link') + openDropdown: (blockOrName) -> + $block = if _.isString(blockOrName) then @getBlock(blockOrName) else blockOrName + + $block.find('.edit-link').trigger('click') - if $editLink.length - $editLink.trigger('click') - $block.addClass('collapse-after-update') - $('.page-with-sidebar').addClass('with-overlay') + if not @isOpen() + @setCollapseAfterUpdate($block) + @toggleSidebar('open') - sidebarDropdownHidden: (e) -> + setCollapseAfterUpdate: ($block) -> + $block.addClass('collapse-after-update') + $('.page-with-sidebar').addClass('with-overlay') + + onSidebarDropdownHidden: (e) -> + sidebar = e.data + e.preventDefault() $block = $(@).closest('.block') + sidebar.sidebarDropdownHidden($block) + + sidebarDropdownHidden: ($block) -> if $block.hasClass('collapse-after-update') $block.removeClass('collapse-after-update') $('.page-with-sidebar').removeClass('with-overlay') - $('aside') - .find('.gutter-toggle') - .trigger('click')
\ No newline at end of file + @toggleSidebar('hide') + + triggerOpenSidebar: -> + @sidebar + .find('.js-sidebar-toggle') + .trigger('click') + + toggleSidebar: (action = 'toggle') -> + if action is 'toggle' + @triggerOpenSidebar() + + if action is 'open' + @triggerOpenSidebar() if not @isOpen() + + if action is 'hide' + @triggerOpenSidebar() is @isOpen() + + isOpen: -> + @sidebar.is('.right-sidebar-expanded') + + getBlock: (name) -> + @sidebar.find(".block.#{name}") + + diff --git a/app/assets/javascripts/shortcuts.js.coffee b/app/assets/javascripts/shortcuts.js.coffee index 100e3aac535..f3d66004138 100644 --- a/app/assets/javascripts/shortcuts.js.coffee +++ b/app/assets/javascripts/shortcuts.js.coffee @@ -2,34 +2,35 @@ class @Shortcuts constructor: -> @enabledHelp = [] Mousetrap.reset() - Mousetrap.bind('?', @selectiveHelp) + Mousetrap.bind('?', @onToggleHelp) Mousetrap.bind('s', Shortcuts.focusSearch) Mousetrap.bind(['ctrl+shift+p', 'command+shift+p'], @toggleMarkdownPreview) Mousetrap.bind('t', -> Turbolinks.visit(findFileURL)) if findFileURL? - selectiveHelp: (e) => - Shortcuts.showHelp(e, @enabledHelp) + onToggleHelp: (e) => + e.preventDefault() + @toggleHelp(@enabledHelp) toggleMarkdownPreview: (e) => $(document).triggerHandler('markdown-preview:toggle', [e]) - @showHelp: (e, location) -> - if $('#modal-shortcuts').length > 0 - $('#modal-shortcuts').modal('show') - else - url = '/help/shortcuts' - url = gon.relative_url_root + url if gon.relative_url_root? - $.ajax( - url: url, - dataType: 'script', - success: (e) -> - if location and location.length > 0 - $(l).show() for l in location - else - $('.hidden-shortcut').show() - $('.js-more-help-button').remove() - ) - e.preventDefault() + toggleHelp: (location) -> + $modal = $('#modal-shortcuts') + + if $modal.length + $modal.modal('toggle') + return + + $.ajax( + url: gon.shortcuts_path, + dataType: 'script', + success: (e) -> + if location and location.length > 0 + $(l).show() for l in location + else + $('.hidden-shortcut').show() + $('.js-more-help-button').remove() + ) @focusSearch: (e) -> $('#search').focus() diff --git a/app/assets/javascripts/shortcuts_issuable.coffee b/app/assets/javascripts/shortcuts_issuable.coffee index bbf02f1db24..ad9b3c1c6bf 100644 --- a/app/assets/javascripts/shortcuts_issuable.coffee +++ b/app/assets/javascripts/shortcuts_issuable.coffee @@ -4,18 +4,8 @@ class @ShortcutsIssuable extends ShortcutsNavigation constructor: (isMergeRequest) -> super() - Mousetrap.bind('a', -> - $('.block.assignee .edit-link').trigger('click') - return false - ) - Mousetrap.bind('m', -> - $('.block.milestone .edit-link').trigger('click') - return false - ) - Mousetrap.bind('r', => - @replyWithSelectedText() - return false - ) + Mousetrap.bind('a', @openSidebarDropdown.bind(@, 'assignee')) + Mousetrap.bind('m', @openSidebarDropdown.bind(@, 'milestone')) Mousetrap.bind('j', => @prevIssue() return false @@ -28,7 +18,7 @@ class @ShortcutsIssuable extends ShortcutsNavigation @editIssue() return false ) - + Mousetrap.bind('l', @openSidebarDropdown.bind(@, 'labels')) if isMergeRequest @enabledHelp.push('.hidden-shortcut.merge_requests') @@ -71,3 +61,7 @@ class @ShortcutsIssuable extends ShortcutsNavigation editIssue: -> $editBtn = $('.issuable-edit') Turbolinks.visit($editBtn.attr('href')) + + openSidebarDropdown: (name) -> + sidebar.openDropdown(name) + return false diff --git a/app/assets/javascripts/shortcuts_navigation.coffee b/app/assets/javascripts/shortcuts_navigation.coffee index 8decaedd87b..f39504e0645 100644 --- a/app/assets/javascripts/shortcuts_navigation.coffee +++ b/app/assets/javascripts/shortcuts_navigation.coffee @@ -14,6 +14,7 @@ class @ShortcutsNavigation extends Shortcuts Mousetrap.bind('g m', -> ShortcutsNavigation.findAndFollowLink('.shortcuts-merge_requests')) Mousetrap.bind('g w', -> ShortcutsNavigation.findAndFollowLink('.shortcuts-wiki')) Mousetrap.bind('g s', -> ShortcutsNavigation.findAndFollowLink('.shortcuts-snippets')) + Mousetrap.bind('i', -> ShortcutsNavigation.findAndFollowLink('.shortcuts-new-issue')) @enabledHelp.push('.hidden-shortcut.project') @findAndFollowLink: (selector) -> diff --git a/app/assets/stylesheets/framework/files.scss b/app/assets/stylesheets/framework/files.scss index 32cc15113f2..61d9954c6c8 100644 --- a/app/assets/stylesheets/framework/files.scss +++ b/app/assets/stylesheets/framework/files.scss @@ -84,10 +84,6 @@ } } - &.blob_file { - - } - &.blob-no-preview { background: #eee; text-shadow: 0 1px 2px #fff; diff --git a/app/assets/stylesheets/framework/markdown_area.scss b/app/assets/stylesheets/framework/markdown_area.scss index 704fa1ff800..fd885b38680 100644 --- a/app/assets/stylesheets/framework/markdown_area.scss +++ b/app/assets/stylesheets/framework/markdown_area.scss @@ -95,7 +95,7 @@ &.md-preview-holder { code { white-space: pre-wrap; - word-break: break-all; + word-break: keep-all; } } } diff --git a/app/assets/stylesheets/framework/selects.scss b/app/assets/stylesheets/framework/selects.scss index b2fab387e17..eae5f062dda 100644 --- a/app/assets/stylesheets/framework/selects.scss +++ b/app/assets/stylesheets/framework/selects.scss @@ -121,9 +121,6 @@ } } -.select2-container-multi .select2-choices .select2-search-choice { -} - .select2-drop-active { margin-top: 6px; font-size: 14px; diff --git a/app/assets/stylesheets/framework/timeline.scss b/app/assets/stylesheets/framework/timeline.scss index f0ec250de2b..29501069d27 100644 --- a/app/assets/stylesheets/framework/timeline.scss +++ b/app/assets/stylesheets/framework/timeline.scss @@ -11,7 +11,7 @@ border-bottom: 1px solid $border-white-light; &:target { - background: $row-hover; + background: $line-target-blue; } .avatar { diff --git a/app/assets/stylesheets/framework/variables.scss b/app/assets/stylesheets/framework/variables.scss index 30ca27ab104..ef37ade3b7b 100644 --- a/app/assets/stylesheets/framework/variables.scss +++ b/app/assets/stylesheets/framework/variables.scss @@ -168,8 +168,12 @@ $line-removed: #fbe9eb; $line-removed-dark: #fac5cd; $line-number-old: #f9d7dc; $line-number-new: #ddfbe6; +$line-number-select: #fbf2da; $match-line: #fafafa; $table-border-gray: #f0f0f0; +$line-target-blue: #eaf3fc; +$line-select-yellow: #fcf8e7; +$line-select-yellow-dark: #f0e2bd; /* * Fonts */ diff --git a/app/assets/stylesheets/highlight/monokai.scss b/app/assets/stylesheets/highlight/monokai.scss index 28253d4ccb4..80a509a7c1a 100644 --- a/app/assets/stylesheets/highlight/monokai.scss +++ b/app/assets/stylesheets/highlight/monokai.scss @@ -111,8 +111,6 @@ .vg { color: #f8f8f2 } /* Name.Variable.Global */ .vi { color: #f8f8f2 } /* Name.Variable.Instance */ .il { color: #ae81ff } /* Literal.Number.Integer.Long */ - - .gh { } /* Generic Heading & Diff Header */ .gu { color: #75715e; } /* Generic.Subheading & Diff Unified/Comment? */ .gd { color: #f92672; } /* Generic.Deleted & Diff Deleted */ .gi { color: #a6e22e; } /* Generic.Inserted & Diff Inserted */ diff --git a/app/assets/stylesheets/highlight/white.scss b/app/assets/stylesheets/highlight/white.scss index 1ff6ad75e07..31a4e3deaac 100644 --- a/app/assets/stylesheets/highlight/white.scss +++ b/app/assets/stylesheets/highlight/white.scss @@ -21,11 +21,6 @@ // Diff line .line_holder { - td.diff-line-num.hll:not(.empty-cell), - td.line_content.hll:not(.empty-cell) { - background-color: #f8eec7; - border-color: darken(#f8eec7, 15%); - } .diff-line-num { &.old { @@ -37,11 +32,16 @@ background-color: $line-number-new; border-color: $line-added-dark; } + + &.hll:not(.empty-cell) { + background-color: $line-number-select; + border-color: $line-select-yellow-dark; + } } .line_content { &.old { - background: $line-removed; + background-color: $line-removed; span.idiff { background-color: $line-removed-dark; @@ -58,7 +58,11 @@ &.match { color: $black-transparent; - background: $match-line; + background-color: $match-line; + } + + &.hll:not(.empty-cell) { + background-color: $line-select-yellow; } } } diff --git a/app/assets/stylesheets/pages/detail_page.scss b/app/assets/stylesheets/pages/detail_page.scss index 751a5ab4d92..3438dbe4958 100644 --- a/app/assets/stylesheets/pages/detail_page.scss +++ b/app/assets/stylesheets/pages/detail_page.scss @@ -40,6 +40,7 @@ .wiki { code { white-space: pre-wrap; + word-break: keep-all; } } } diff --git a/app/assets/stylesheets/pages/graph.scss b/app/assets/stylesheets/pages/graph.scss index 4e5c4ed84b6..f7f9a9bb770 100644 --- a/app/assets/stylesheets/pages/graph.scss +++ b/app/assets/stylesheets/pages/graph.scss @@ -18,9 +18,6 @@ } .graphs { - .graph-author-commits-count { - } - .graph-author-email { float: right; color: #777; diff --git a/app/assets/stylesheets/pages/notes.scss b/app/assets/stylesheets/pages/notes.scss index d54abe9bc02..55b1ad97eb0 100644 --- a/app/assets/stylesheets/pages/notes.scss +++ b/app/assets/stylesheets/pages/notes.scss @@ -109,6 +109,10 @@ ul.notes { border-color: darken(#f5f5f5, 8%); margin: 10px 0; } + + code { + word-break: keep-all; + } } a { diff --git a/app/helpers/projects_helper.rb b/app/helpers/projects_helper.rb index ab85694da3f..3d5e61d2c18 100644 --- a/app/helpers/projects_helper.rb +++ b/app/helpers/projects_helper.rb @@ -123,6 +123,18 @@ module ProjectsHelper end end + def license_short_name(project) + no_license_key = project.repository.license_key.nil? || + # Back-compat if cache contains 'no-license', can be removed in a few weeks + project.repository.license_key == 'no-license' + + return 'LICENSE' if no_license_key + + license = Licensee::License.new(project.repository.license_key) + + license.nickname || license.name + end + private def get_project_nav_tabs(project, current_user) @@ -320,14 +332,6 @@ module ProjectsHelper @ref || @repository.try(:root_ref) end - def license_short_name(project) - license = Licensee::License.new(project.repository.license_key) - - license.nickname || license.name - end - - private - def filename_path(project, filename) if project && blob = project.repository.send(filename) namespace_project_blob_path( diff --git a/app/models/project.rb b/app/models/project.rb index 7aa21b19e67..0420c6a61ae 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -820,13 +820,11 @@ class Project < ActiveRecord::Base wiki = Repository.new("#{old_path}.wiki", self) if repo.exists? - repo.expire_cache - repo.expire_emptiness_caches + repo.before_delete end if wiki.exists? - wiki.expire_cache - wiki.expire_emptiness_caches + wiki.before_delete end end diff --git a/app/models/repository.rb b/app/models/repository.rb index da751591103..61c8dce6060 100644 --- a/app/models/repository.rb +++ b/app/models/repository.rb @@ -466,8 +466,8 @@ class Repository return nil if !exists? || empty? cache.fetch(:license_blob) do - if licensee_project.license - blob_at_branch(root_ref, licensee_project.matched_file.filename) + tree(:head).blobs.find do |file| + file.name =~ /\A(licen[sc]e|copying)(\..+|\z)/i end end end @@ -476,7 +476,7 @@ class Repository return nil if !exists? || empty? cache.fetch(:license_key) do - licensee_project.license.try(:key) || 'no-license' + Licensee.license(path).try(:key) end end @@ -959,8 +959,4 @@ class Repository def cache @cache ||= RepositoryCache.new(path_with_namespace) end - - def licensee_project - @licensee_project ||= Licensee.project(path) - end end diff --git a/app/services/projects/transfer_service.rb b/app/services/projects/transfer_service.rb index 79a27f4af7e..111b3ec05ea 100644 --- a/app/services/projects/transfer_service.rb +++ b/app/services/projects/transfer_service.rb @@ -34,6 +34,8 @@ module Projects raise TransferError.new("Project with same path in target namespace already exists") end + project.expire_caches_before_rename(old_path) + # Apply new namespace id and visibility level project.namespace = new_namespace project.visibility_level = new_namespace.visibility_level unless project.visibility_level_allowed_by_group? diff --git a/app/views/events/_event.html.haml b/app/views/events/_event.html.haml index 4d20dd5830e..5d622582088 100644 --- a/app/views/events/_event.html.haml +++ b/app/views/events/_event.html.haml @@ -4,7 +4,12 @@ #{time_ago_with_tooltip(event.created_at)} = cache [event, current_application_settings, "v2.2"] do - = image_tag avatar_icon(event.author_email, 40), class: "avatar s40", alt:'' + - if event.author + = link_to user_path(event.author.username) do + = image_tag avatar_icon(event.author_email, 40), class: "avatar s40", alt:'' + - else + = image_tag avatar_icon(event.author_email, 40), class: "avatar s40", alt:'' + - if event.created_project? = render "events/event/created_project", event: event - elsif event.push? diff --git a/app/views/help/_shortcuts.html.haml b/app/views/help/_shortcuts.html.haml index da3c3711cdd..70e88da7aae 100644 --- a/app/views/help/_shortcuts.html.haml +++ b/app/views/help/_shortcuts.html.haml @@ -21,7 +21,7 @@ %tr %td.shortcut .key ? - %td Show this dialog + %td Show/hide this dialog %tr %td.shortcut - if browser.mac? @@ -169,6 +169,10 @@ %td.shortcut .key t %td Go to finding file + %tr + %td.shortcut + .key i + %td New issue .col-lg-4 %table.shortcut-mappings %tbody{ class: 'hidden-shortcut network', style: 'display:none' } @@ -241,6 +245,10 @@ %td.shortcut .key e %td Edit issue + %tr + %td.shortcut + .key l + %td Change Label %tbody{ class: 'hidden-shortcut merge_requests', style: 'display:none' } %tr %th @@ -261,3 +269,7 @@ %td.shortcut .key e %td Edit merge request + %tr + %td.shortcut + .key l + %td Change Label diff --git a/app/views/layouts/nav/_project.html.haml b/app/views/layouts/nav/_project.html.haml index a15b7758c4b..479bde33719 100644 --- a/app/views/layouts/nav/_project.html.haml +++ b/app/views/layouts/nav/_project.html.haml @@ -124,3 +124,8 @@ %li.hidden = link_to namespace_project_network_path(@project.namespace, @project, current_ref), title: 'Network', class: 'shortcuts-network' do Network + + -# Shortcut to create a new issue + %li.hidden + = link_to new_namespace_project_issue_path(@project.namespace, @project), class: 'shortcuts-new-issue' do + Create a new issue diff --git a/app/views/projects/commit/_ci_commit.html.haml b/app/views/projects/commit/_ci_commit.html.haml index 25714e6cb47..d3acd33116c 100644 --- a/app/views/projects/commit/_ci_commit.html.haml +++ b/app/views/projects/commit/_ci_commit.html.haml @@ -16,7 +16,7 @@ - if defined?(link_to_commit) && link_to_commit for commit = link_to ci_commit.short_sha, namespace_project_commit_path(@project.namespace, @project, ci_commit.sha), class: "monospace" - - if ci_commit.duration > 0 + - if ci_commit.duration in = time_interval_in_words ci_commit.duration diff --git a/app/views/shared/issuable/_sidebar.html.haml b/app/views/shared/issuable/_sidebar.html.haml index 04b834ba5d1..ed1b8a8da2a 100644 --- a/app/views/shared/issuable/_sidebar.html.haml +++ b/app/views/shared/issuable/_sidebar.html.haml @@ -166,5 +166,5 @@ new LabelsSelect(); new IssuableContext('#{escape_javascript(current_user.to_json(only: [:username, :id, :name]))}'); new Subscription('.subscription') - new Sidebar(); new DueDateSelect(); + sidebar = new Sidebar(); diff --git a/app/views/votes/_votes_block.html.haml b/app/views/votes/_votes_block.html.haml index dc249155b92..59e12798691 100644 --- a/app/views/votes/_votes_block.html.haml +++ b/app/views/votes/_votes_block.html.haml @@ -19,12 +19,12 @@ var post_emoji_url = "#{award_toggle_namespace_project_notes_path(@project.namespace, @project)}"; var noteable_type = "#{votable.class.name.underscore}"; var noteable_id = "#{votable.id}"; - var aliases = #{AwardEmoji.aliases.to_json}; + var unicodes = #{AwardEmoji.unicode.to_json}; window.awards_handler = new AwardsHandler( get_emojis_url, post_emoji_url, noteable_type, noteable_id, - aliases + unicodes ); diff --git a/doc/ci/docker/using_docker_images.md b/doc/ci/docker/using_docker_images.md index bd748f1b986..84212fb3c61 100644 --- a/doc/ci/docker/using_docker_images.md +++ b/doc/ci/docker/using_docker_images.md @@ -239,8 +239,8 @@ is specific to your project. Then create some service containers: ``` -docker run -d -n service-mysql mysql:latest -docker run -d -n service-postgres postgres:latest +docker run -d --name service-mysql mysql:latest +docker run -d --name service-postgres postgres:latest ``` This will create two service containers, named `service-mysql` and diff --git a/doc/ci/examples/php.md b/doc/ci/examples/php.md index aeadd6a448e..db077927126 100644 --- a/doc/ci/examples/php.md +++ b/doc/ci/examples/php.md @@ -40,7 +40,7 @@ repository with the following content: #!/bin/bash # We need to install dependencies only for Docker -[[ ! -e /.dockerinit ]] && exit 0 +[[ ! -e /.dockerenv ]] && [[ ! -e /.dockerinit ]] && exit 0 set -xe diff --git a/doc/monitoring/performance/grafana_configuration.md b/doc/monitoring/performance/grafana_configuration.md index a79c8d48d3b..168bd85c26a 100644 --- a/doc/monitoring/performance/grafana_configuration.md +++ b/doc/monitoring/performance/grafana_configuration.md @@ -59,34 +59,53 @@ This will drop you in to an InfluxDB interactive session. Copy the entire contents below and paste it in to the interactive session: ``` -CREATE RETENTION POLICY gitlab_30d ON gitlab DURATION 30d REPLICATION 1 DEFAULT -CREATE RETENTION POLICY seven_days ON gitlab DURATION 7d REPLICATION 1 -CREATE CONTINUOUS QUERY rails_transaction_counts_seven_days ON gitlab BEGIN SELECT count("duration") AS "count" INTO gitlab.seven_days.rails_transaction_counts FROM rails_transactions GROUP BY time(1m) END; -CREATE CONTINUOUS QUERY sidekiq_transaction_counts_seven_days ON gitlab BEGIN SELECT count("duration") AS "count" INTO gitlab.seven_days.sidekiq_transaction_counts FROM sidekiq_transactions GROUP BY time(1m) END; -CREATE CONTINUOUS QUERY rails_method_call_timings_seven_days ON gitlab BEGIN SELECT percentile("duration", 95.000) AS "duration_95th", percentile("duration", 99.000) AS "duration_99th", mean("duration") AS "duration_mean" INTO gitlab.seven_days.rails_method_call_timings FROM rails_method_calls GROUP BY time(1m) END; -CREATE CONTINUOUS QUERY sidekiq_method_call_timings_seven_days ON gitlab BEGIN SELECT percentile("duration", 95.000) AS "duration_95th", percentile("duration", 99.000) AS "duration_99th", mean("duration") AS "duration_mean" INTO gitlab.seven_days.sidekiq_method_call_timings FROM sidekiq_method_calls GROUP BY time(1m) END; -CREATE CONTINUOUS QUERY rails_method_call_timings_per_method_seven_days ON gitlab BEGIN SELECT percentile("duration", 95.000) AS duration_95th, percentile("duration", 99.000) AS duration_99th, mean("duration") AS duration_mean INTO gitlab.seven_days.rails_method_call_timings_per_method FROM rails_method_calls GROUP BY time(1m), method END; -CREATE CONTINUOUS QUERY sidekiq_method_call_timings_per_method_seven_days ON gitlab BEGIN SELECT percentile("duration", 95.000) AS duration_95th, percentile("duration", 99.000) AS duration_99th, mean("duration") AS duration_mean INTO gitlab.seven_days.sidekiq_method_call_timings_per_method FROM sidekiq_method_calls GROUP BY time(1m), method END; -CREATE CONTINUOUS QUERY rails_memory_usage_per_minute ON gitlab BEGIN SELECT percentile(value, 95.000) AS memory_95th, percentile(value, 99.000) AS memory_99th, mean(value) AS memory_mean INTO gitlab.seven_days.rails_memory_usage_per_minute FROM rails_memory_usage GROUP BY time(1m) END; -CREATE CONTINUOUS QUERY sidekiq_memory_usage_per_minute ON gitlab BEGIN SELECT percentile(value, 95.000) AS memory_95th, percentile(value, 99.000) AS memory_99th, mean(value) AS memory_mean INTO gitlab.seven_days.sidekiq_memory_usage_per_minute FROM sidekiq_memory_usage GROUP BY time(1m) END; -CREATE CONTINUOUS QUERY sidekiq_file_descriptors_per_minute ON gitlab BEGIN SELECT sum(value) AS value INTO gitlab.seven_days.sidekiq_file_descriptors_per_minute FROM sidekiq_file_descriptors GROUP BY time(1m) END; -CREATE CONTINUOUS QUERY rails_file_descriptors_per_minute ON gitlab BEGIN SELECT sum(value) AS value INTO gitlab.seven_days.rails_file_descriptors_per_minute FROM rails_file_descriptors GROUP BY time(1m) END; -CREATE CONTINUOUS QUERY rails_gc_counts_per_minute ON gitlab BEGIN SELECT sum(count) AS count INTO gitlab.seven_days.rails_gc_counts_per_minute FROM rails_gc_statistics GROUP BY time(1m) END; -CREATE CONTINUOUS QUERY sidekiq_gc_counts_per_minute ON gitlab BEGIN SELECT sum(count) AS count INTO gitlab.seven_days.sidekiq_gc_counts_per_minute FROM sidekiq_gc_statistics GROUP BY time(1m) END; -CREATE CONTINUOUS QUERY rails_gc_timings_per_minute ON gitlab BEGIN SELECT percentile(total_time, 95.000) AS duration_95th, percentile(total_time, 99.000) AS duration_99th, mean(total_time) AS duration_mean INTO gitlab.seven_days.rails_gc_timings_per_minute FROM rails_gc_statistics GROUP BY time(1m) END; -CREATE CONTINUOUS QUERY sidekiq_gc_timings_per_minute ON gitlab BEGIN SELECT percentile(total_time, 95.000) AS duration_95th, percentile(total_time, 99.000) AS duration_99th, mean(total_time) AS duration_mean INTO gitlab.seven_days.sidekiq_gc_timings_per_minute FROM sidekiq_gc_statistics GROUP BY time(1m) END; -CREATE CONTINUOUS QUERY rails_gc_major_minor_per_minute ON gitlab BEGIN SELECT sum(major_gc_count) AS major, sum(minor_gc_count) AS minor INTO gitlab.seven_days.rails_gc_major_minor_per_minute FROM rails_gc_statistics GROUP BY time(1m) END; -CREATE CONTINUOUS QUERY sidekiq_gc_major_minor_per_minute ON gitlab BEGIN SELECT sum(major_gc_count) AS major, sum(minor_gc_count) AS minor INTO gitlab.seven_days.sidekiq_gc_major_minor_per_minute FROM sidekiq_gc_statistics GROUP BY time(1m) END; -CREATE CONTINUOUS QUERY grape_internal_allowed_request_counts_per_minute ON gitlab BEGIN SELECT count("duration") AS count INTO gitlab.seven_days.grape_internal_allowed_request_counts_per_minute FROM rails_transactions WHERE request_uri = '/api/v3/internal/allowed' GROUP BY time(1m) END; -CREATE CONTINUOUS QUERY grape_internal_allowed_request_timings_per_minute ON gitlab BEGIN SELECT percentile("duration", 95) AS duration_95th, percentile("duration", 99) AS duration_99th, mean("duration") AS duration_mean INTO gitlab.seven_days.grape_internal_allowed_request_timings_per_minute FROM rails_transactions WHERE request_uri = '/api/v3/internal/allowed' GROUP BY time(1m) END; -CREATE CONTINUOUS QUERY grape_internal_allowed_sql_timings_per_minute ON gitlab BEGIN SELECT percentile(sql_duration, 95) AS duration_95th, percentile(sql_duration, 99) AS duration_99th, mean(sql_duration) AS duration_mean INTO gitlab.seven_days.grape_internal_allowed_sql_timings_per_minute FROM rails_transactions WHERE request_uri = '/api/v3/internal/allowed' GROUP BY time(1m) END; -CREATE CONTINUOUS QUERY grape_internal_authorized_keys_request_counts_per_minute ON gitlab BEGIN SELECT count("duration") AS count INTO gitlab.seven_days.grape_internal_authorized_keys_request_counts_per_minute FROM rails_transactions WHERE request_uri = '/api/v3/internal/authorized_keys' GROUP BY time(1m) END; -CREATE CONTINUOUS QUERY grape_internal_authorized_keys_request_timings_per_minute ON gitlab BEGIN SELECT percentile("duration", 95) AS duration_95th, percentile("duration", 99) AS duration_99th, mean("duration") AS duration_mean INTO gitlab.seven_days.grape_internal_authorized_keys_request_timings_per_minute FROM rails_transactions WHERE request_uri = '/api/v3/internal/authorized_keys' GROUP BY time(1m) END; -CREATE CONTINUOUS QUERY grape_internal_authorized_keys_sql_timings_per_minute ON gitlab BEGIN SELECT percentile(sql_duration, 95) AS duration_95th, percentile(sql_duration, 99) AS duration_99th, mean(sql_duration) AS duration_mean INTO gitlab.seven_days.grape_internal_authorized_keys_sql_timings_per_minute FROM rails_transactions WHERE request_uri = '/api/v3/internal/authorized_keys' GROUP BY time(1m) END; -CREATE CONTINUOUS QUERY rails_transaction_timings_seven_days ON gitlab BEGIN SELECT percentile("duration", 95.000) AS duration_95th, percentile("duration", 99.000) AS duration_99th, mean("duration") AS duration_mean, percentile(sql_duration, 95.000) AS sql_duration_95th, percentile(sql_duration, 99.000) AS sql_duration_99th, mean(sql_duration) AS sql_duration_mean, percentile(view_duration, 95.000) AS view_duration_95th, percentile(view_duration, 99.000) AS view_duration_99th, mean(view_duration) AS view_duration_mean, percentile(cache_read_duration, 99) AS cache_read_duration_99th, percentile(cache_read_duration, 95) AS cache_read_duration_95th, mean(cache_read_duration) AS cache_read_duration_mean, percentile(cache_write_duration, 99) AS cache_write_duration_99th, percentile(cache_write_duration, 95) AS cache_write_duration_95th, mean(cache_write_duration) AS cache_write_duration_mean, percentile(cache_delete_duration, 99) AS cache_delete_duration_99th, percentile(cache_delete_duration, 95) AS cache_delete_duration_95th, mean(cache_delete_duration) AS cache_delete_duration_mean, percentile(cache_exists_duration, 99) AS cache_exists_duration_99th, percentile(cache_exists_duration, 95) AS cache_exists_duration_95th, mean(cache_exists_duration) AS cache_exists_duration_mean, percentile(cache_duration, 99) AS cache_duration_99th, percentile(cache_duration, 95) AS cache_duration_95th, mean(cache_duration) AS cache_duration_mean INTO gitlab.seven_days.rails_transaction_timings FROM rails_transactions GROUP BY time(1m) END; -CREATE CONTINUOUS QUERY sidekiq_transaction_timings_seven_days ON gitlab BEGIN SELECT percentile("duration", 95.000) AS duration_95th, percentile("duration", 99.000) AS duration_99th, mean("duration") AS duration_mean, percentile(sql_duration, 95.000) AS sql_duration_95th, percentile(sql_duration, 99.000) AS sql_duration_99th, mean(sql_duration) AS sql_duration_mean, percentile(view_duration, 95.000) AS view_duration_95th, percentile(view_duration, 99.000) AS view_duration_99th, mean(view_duration) AS view_duration_mean, percentile(cache_read_duration, 99) AS cache_read_duration_99th, percentile(cache_read_duration, 95) AS cache_read_duration_95th, mean(cache_read_duration) AS cache_read_duration_mean, percentile(cache_write_duration, 99) AS cache_write_duration_99th, percentile(cache_write_duration, 95) AS cache_write_duration_95th, mean(cache_write_duration) AS cache_write_duration_mean, percentile(cache_delete_duration, 99) AS cache_delete_duration_99th, percentile(cache_delete_duration, 95) AS cache_delete_duration_95th, mean(cache_delete_duration) AS cache_delete_duration_mean, percentile(cache_exists_duration, 99) AS cache_exists_duration_99th, percentile(cache_exists_duration, 95) AS cache_exists_duration_95th, mean(cache_exists_duration) AS cache_exists_duration_mean, percentile(cache_duration, 99) AS cache_duration_99th, percentile(cache_duration, 95) AS cache_duration_95th, mean(cache_duration) AS cache_duration_mean INTO gitlab.seven_days.sidekiq_transaction_timings FROM sidekiq_transactions GROUP BY time(1m) END; -CREATE CONTINUOUS QUERY grape_transaction_counts_seven_days ON gitlab BEGIN SELECT count("duration") AS count INTO gitlab.seven_days.grape_transaction_counts FROM rails_transactions WHERE action !~ /.+/ GROUP BY time(1m) END; -CREATE CONTINUOUS QUERY grape_transaction_timings_seven_days ON gitlab BEGIN SELECT percentile("duration", 95.000) AS duration_95th, percentile("duration", 99.000) AS duration_99th, mean("duration") AS duration_mean, percentile(sql_duration, 95.000) AS sql_duration_95th, percentile(sql_duration, 99.000) AS sql_duration_99th, mean(sql_duration) AS sql_duration_mean, percentile(cache_read_duration, 99) AS cache_read_duration_99th, percentile(cache_read_duration, 95) AS cache_read_duration_95th, mean(cache_read_duration) AS cache_read_duration_mean, percentile(cache_write_duration, 99) AS cache_write_duration_99th, percentile(cache_write_duration, 95) AS cache_write_duration_95th, mean(cache_write_duration) AS cache_write_duration_mean, percentile(cache_delete_duration, 99) AS cache_delete_duration_99th, percentile(cache_delete_duration, 95) AS cache_delete_duration_95th, mean(cache_delete_duration) AS cache_delete_duration_mean, percentile(cache_exists_duration, 99) AS cache_exists_duration_99th, percentile(cache_exists_duration, 95) AS cache_exists_duration_95th, mean(cache_exists_duration) AS cache_exists_duration_mean, percentile(cache_duration, 99) AS cache_duration_99th, percentile(cache_duration, 95) AS cache_duration_95th, mean(cache_duration) AS cache_duration_mean INTO gitlab.seven_days.grape_transaction_timings FROM rails_transactions WHERE action !~ /.+/ GROUP BY time(1m) END; +CREATE RETENTION POLICY default ON gitlab DURATION 1h REPLICATION 1 DEFAULT +CREATE RETENTION POLICY downsampled ON gitlab DURATION 7d REPLICATION 1 +CREATE CONTINUOUS QUERY grape_git_timings_per_action ON gitlab BEGIN SELECT mean("duration") AS duration_mean, percentile("duration", 95) AS duration_95th, percentile("duration", 99) AS duration_99th INTO gitlab.downsampled.grape_git_timings_per_action FROM gitlab."default".rails_method_calls WHERE (action !~ /.+/ OR action =~ /^Grape#/) AND method =~ /^(Rugged|Gitlab::Git)/ GROUP BY time(1m), action END; +CREATE CONTINUOUS QUERY grape_markdown_render_timings_overall ON gitlab BEGIN SELECT mean(banzai_cached_render_real_time) AS cached_real_mean, percentile(banzai_cached_render_real_time, 95) AS cached_real_95th, percentile(banzai_cached_render_real_time, 99) AS cached_real_99th, mean(banzai_cached_render_cpu_time) AS cached_cpu_mean, percentile(banzai_cached_render_cpu_time, 95) AS cached_cpu_95th, percentile(banzai_cached_render_cpu_time, 99) AS cached_cpu_99th, sum(banzai_cached_render_call_count) AS cached_call_count, mean(banzai_cacheless_render_real_time) AS cacheless_real_mean, percentile(banzai_cacheless_render_real_time, 95) AS cacheless_real_95th, percentile(banzai_cacheless_render_real_time, 99) AS cacheless_real_99th, mean(banzai_cacheless_render_cpu_time) AS cacheless_cpu_mean, percentile(banzai_cacheless_render_cpu_time, 95) AS cacheless_cpu_95th, percentile(banzai_cacheless_render_cpu_time, 99) AS cacheless_cpu_99th, sum(banzai_cacheless_render_call_count) AS cacheless_call_count INTO gitlab.downsampled.grape_markdown_render_timings_overall FROM gitlab."default".rails_transactions WHERE (action !~ /.+/ OR action =~ /^Grape#/) AND (banzai_cached_render_call_count > 0 OR banzai_cacheless_render_call_count > 0) GROUP BY time(1m) END; +CREATE CONTINUOUS QUERY grape_markdown_render_timings_per_action ON gitlab BEGIN SELECT mean(banzai_cached_render_real_time) AS cached_real_mean, percentile(banzai_cached_render_real_time, 95) AS cached_real_95th, percentile(banzai_cached_render_real_time, 99) AS cached_real_99th, mean(banzai_cached_render_cpu_time) AS cached_cpu_mean, percentile(banzai_cached_render_cpu_time, 95) AS cached_cpu_95th, percentile(banzai_cached_render_cpu_time, 99) AS cached_cpu_99th, sum(banzai_cached_render_call_count) AS cached_call_count, mean(banzai_cacheless_render_real_time) AS cacheless_real_mean, percentile(banzai_cacheless_render_real_time, 95) AS cacheless_real_95th, percentile(banzai_cacheless_render_real_time, 99) AS cacheless_real_99th, mean(banzai_cacheless_render_cpu_time) AS cacheless_cpu_mean, percentile(banzai_cacheless_render_cpu_time, 95) AS cacheless_cpu_95th, percentile(banzai_cacheless_render_cpu_time, 99) AS cacheless_cpu_99th, sum(banzai_cacheless_render_call_count) AS cacheless_call_count INTO gitlab.downsampled.grape_markdown_render_timings_per_action FROM gitlab."default".rails_transactions WHERE (action !~ /.+/ OR action =~ /^Grape#/) AND (banzai_cached_render_call_count > 0 OR banzai_cacheless_render_call_count > 0) GROUP BY time(1m), action END; +CREATE CONTINUOUS QUERY grape_markdown_timings_overall ON gitlab BEGIN SELECT mean("duration") AS duration_mean, percentile("duration", 95) AS duration_95th, percentile("duration", 99) AS duration_99th INTO gitlab.downsampled.grape_markdown_timings_overall FROM gitlab."default".rails_method_calls WHERE (action !~ /.+/ OR action =~ /^Grape#/) AND method =~ /^Banzai/ GROUP BY time(1m) END; +CREATE CONTINUOUS QUERY grape_method_call_timings_per_action_and_method ON gitlab BEGIN SELECT mean("duration") AS duration_mean, percentile("duration", 95) AS duration_95th, percentile("duration", 99) AS duration_99th INTO gitlab.downsampled.grape_method_call_timings_per_action_and_method FROM gitlab."default".rails_method_calls WHERE action !~ /.+/ OR action =~ /^Grape#/ GROUP BY time(1m), method, action END; +CREATE CONTINUOUS QUERY grape_method_call_timings_per_method ON gitlab BEGIN SELECT mean("duration") AS duration_mean, percentile("duration", 95) AS duration_95th, percentile("duration", 99) AS duration_99th INTO gitlab.downsampled.grape_method_call_timings_per_method FROM gitlab."default".rails_method_calls WHERE action !~ /.+/ OR action =~ /^Grape#/ GROUP BY time(1m), method END; +CREATE CONTINUOUS QUERY grape_transaction_counts_overall ON gitlab BEGIN SELECT count("duration") AS count INTO gitlab.downsampled.grape_transaction_counts_overall FROM gitlab."default".rails_transactions WHERE action !~ /.+/ OR action =~ /^Grape#/ GROUP BY time(1m) END; +CREATE CONTINUOUS QUERY grape_transaction_counts_per_action ON gitlab BEGIN SELECT count("duration") AS count INTO gitlab.downsampled.grape_transaction_counts_per_action FROM gitlab."default".rails_transactions WHERE action !~ /.+/ OR action =~ /^Grape#/ GROUP BY time(1m), action END; +CREATE CONTINUOUS QUERY grape_transaction_timings_overall ON gitlab BEGIN SELECT mean("duration") AS duration_mean, percentile("duration", 95) AS duration_95th, percentile("duration", 99) AS duration_99th, mean(sql_duration) AS sql_duration_mean, percentile(sql_duration, 95) AS sql_duration_95th, percentile(sql_duration, 99) AS sql_duration_99th, mean(view_duration) AS view_duration_mean, percentile(view_duration, 95) AS view_duration_95th, percentile(view_duration, 99) AS view_duration_99th, mean(cache_read_duration) AS cache_read_duration_mean, percentile(cache_read_duration, 99) AS cache_read_duration_99th, percentile(cache_read_duration, 95) AS cache_read_duration_95th, mean(cache_write_duration) AS cache_write_duration_mean, percentile(cache_write_duration, 99) AS cache_write_duration_99th, percentile(cache_write_duration, 95) AS cache_write_duration_95th, mean(cache_delete_duration) AS cache_delete_duration_mean, percentile(cache_delete_duration, 99) AS cache_delete_duration_99th, percentile(cache_delete_duration, 95) AS cache_delete_duration_95th, mean(cache_exists_duration) AS cache_exists_duration_mean, percentile(cache_exists_duration, 99) AS cache_exists_duration_99th, percentile(cache_exists_duration, 95) AS cache_exists_duration_95th, mean(cache_duration) AS cache_duration_mean, percentile(cache_duration, 99) AS cache_duration_99th, percentile(cache_duration, 95) AS cache_duration_95th, mean(method_duration) AS method_duration_mean, percentile(method_duration, 99) AS method_duration_99th, percentile(method_duration, 95) AS method_duration_95th INTO gitlab.downsampled.grape_transaction_timings_overall FROM gitlab."default".rails_transactions WHERE action !~ /.+/ OR action =~ /^Grape#/ GROUP BY time(1m) END; +CREATE CONTINUOUS QUERY grape_transaction_timings_per_action ON gitlab BEGIN SELECT mean("duration") AS duration_mean, percentile("duration", 95) AS duration_95th, percentile("duration", 99) AS duration_99th, mean(sql_duration) AS sql_duration_mean, percentile(sql_duration, 95) AS sql_duration_95th, percentile(sql_duration, 99) AS sql_duration_99th, mean(view_duration) AS view_duration_mean, percentile(view_duration, 95) AS view_duration_95th, percentile(view_duration, 99) AS view_duration_99th, mean(cache_read_duration) AS cache_read_duration_mean, percentile(cache_read_duration, 99) AS cache_read_duration_99th, percentile(cache_read_duration, 95) AS cache_read_duration_95th, mean(cache_write_duration) AS cache_write_duration_mean, percentile(cache_write_duration, 99) AS cache_write_duration_99th, percentile(cache_write_duration, 95) AS cache_write_duration_95th, mean(cache_delete_duration) AS cache_delete_duration_mean, percentile(cache_delete_duration, 99) AS cache_delete_duration_99th, percentile(cache_delete_duration, 95) AS cache_delete_duration_95th, mean(cache_exists_duration) AS cache_exists_duration_mean, percentile(cache_exists_duration, 99) AS cache_exists_duration_99th, percentile(cache_exists_duration, 95) AS cache_exists_duration_95th, mean(cache_duration) AS cache_duration_mean, percentile(cache_duration, 99) AS cache_duration_99th, percentile(cache_duration, 95) AS cache_duration_95th, mean(method_duration) AS method_duration_mean, percentile(method_duration, 99) AS method_duration_99th, percentile(method_duration, 95) AS method_duration_95th INTO gitlab.downsampled.grape_transaction_timings_per_action FROM gitlab."default".rails_transactions WHERE action !~ /.+/ OR action =~ /^Grape#/ GROUP BY time(1m), action END; +CREATE CONTINUOUS QUERY rails_file_descriptor_counts ON gitlab BEGIN SELECT sum(value) AS count INTO gitlab.downsampled.rails_file_descriptor_counts FROM gitlab."default".rails_file_descriptors GROUP BY time(1m) END; +CREATE CONTINUOUS QUERY rails_gc_counts ON gitlab BEGIN SELECT sum(count) AS total, sum(minor_gc_count) AS minor, sum(major_gc_count) AS major INTO gitlab.downsampled.rails_gc_counts FROM gitlab."default".rails_gc_statistics GROUP BY time(1m) END; +CREATE CONTINUOUS QUERY rails_gc_timings ON gitlab BEGIN SELECT mean(total_time) AS duration_mean, percentile(total_time, 95) AS duration_95th, percentile(total_time, 99) AS duration_99th INTO gitlab.downsampled.rails_gc_timings FROM gitlab."default".rails_gc_statistics GROUP BY time(1m) END; +CREATE CONTINUOUS QUERY rails_git_timings_per_action ON gitlab BEGIN SELECT mean("duration") AS duration_mean, percentile("duration", 95) AS duration_95th, percentile("duration", 99) AS duration_99th INTO gitlab.downsampled.rails_git_timings_per_action FROM gitlab."default".rails_method_calls WHERE (action =~ /.+/ AND action !~ /^Grape#/) AND method =~ /^(Rugged|Gitlab::Git)/ GROUP BY time(1m), action END; +CREATE CONTINUOUS QUERY rails_markdown_render_timings_overall ON gitlab BEGIN SELECT mean(banzai_cached_render_real_time) AS cached_real_mean, percentile(banzai_cached_render_real_time, 95) AS cached_real_95th, percentile(banzai_cached_render_real_time, 99) AS cached_real_99th, mean(banzai_cached_render_cpu_time) AS cached_cpu_mean, percentile(banzai_cached_render_cpu_time, 95) AS cached_cpu_95th, percentile(banzai_cached_render_cpu_time, 99) AS cached_cpu_99th, sum(banzai_cached_render_call_count) AS cached_call_count, mean(banzai_cacheless_render_real_time) AS cacheless_real_mean, percentile(banzai_cacheless_render_real_time, 95) AS cacheless_real_95th, percentile(banzai_cacheless_render_real_time, 99) AS cacheless_real_99th, mean(banzai_cacheless_render_cpu_time) AS cacheless_cpu_mean, percentile(banzai_cacheless_render_cpu_time, 95) AS cacheless_cpu_95th, percentile(banzai_cacheless_render_cpu_time, 99) AS cacheless_cpu_99th, sum(banzai_cacheless_render_call_count) AS cacheless_call_count INTO gitlab.downsampled.rails_markdown_render_timings_overall FROM gitlab."default".rails_transactions WHERE (action =~ /.+/ AND action !~ /^Grape#/) AND (banzai_cached_render_call_count > 0 OR banzai_cacheless_render_call_count > 0) GROUP BY time(1m) END; +CREATE CONTINUOUS QUERY rails_markdown_render_timings_per_action ON gitlab BEGIN SELECT mean(banzai_cached_render_real_time) AS cached_real_mean, percentile(banzai_cached_render_real_time, 95) AS cached_real_95th, percentile(banzai_cached_render_real_time, 99) AS cached_real_99th, mean(banzai_cached_render_cpu_time) AS cached_cpu_mean, percentile(banzai_cached_render_cpu_time, 95) AS cached_cpu_95th, percentile(banzai_cached_render_cpu_time, 99) AS cached_cpu_99th, sum(banzai_cached_render_call_count) AS cached_call_count, mean(banzai_cacheless_render_real_time) AS cacheless_real_mean, percentile(banzai_cacheless_render_real_time, 95) AS cacheless_real_95th, percentile(banzai_cacheless_render_real_time, 99) AS cacheless_real_99th, mean(banzai_cacheless_render_cpu_time) AS cacheless_cpu_mean, percentile(banzai_cacheless_render_cpu_time, 95) AS cacheless_cpu_95th, percentile(banzai_cacheless_render_cpu_time, 99) AS cacheless_cpu_99th, sum(banzai_cacheless_render_call_count) AS cacheless_call_count INTO gitlab.downsampled.rails_markdown_render_timings_per_action FROM gitlab."default".rails_transactions WHERE (action =~ /.+/ AND action !~ /^Grape#/) AND (banzai_cached_render_call_count > 0 OR banzai_cacheless_render_call_count > 0) GROUP BY time(1m), action END; +CREATE CONTINUOUS QUERY rails_markdown_timings_overall ON gitlab BEGIN SELECT mean("duration") AS duration_mean, percentile("duration", 95) AS duration_95th, percentile("duration", 99) AS duration_99th INTO gitlab.downsampled.rails_markdown_timings_overall FROM gitlab."default".rails_method_calls WHERE (action =~ /.+/ AND action !~ /^Grape#/) AND method =~ /^Banzai/ GROUP BY time(1m) END; +CREATE CONTINUOUS QUERY rails_memory_usage_overall ON gitlab BEGIN SELECT mean(value) AS memory_mean, percentile(value, 95) AS memory_95th, percentile(value, 99) AS memory_99th INTO gitlab.downsampled.rails_memory_usage_overall FROM gitlab."default".rails_memory_usage GROUP BY time(1m) END; +CREATE CONTINUOUS QUERY rails_method_call_timings_per_action_and_method ON gitlab BEGIN SELECT mean("duration") AS duration_mean, percentile("duration", 95) AS duration_95th, percentile("duration", 99) AS duration_99th INTO gitlab.downsampled.rails_method_call_timings_per_action_and_method FROM gitlab."default".rails_method_calls WHERE action =~ /.+/ AND action !~ /^Grape#/ GROUP BY time(1m), method, action END; +CREATE CONTINUOUS QUERY rails_method_call_timings_per_method ON gitlab BEGIN SELECT mean("duration") AS duration_mean, percentile("duration", 95) AS duration_95th, percentile("duration", 99) AS duration_99th INTO gitlab.downsampled.rails_method_call_timings_per_method FROM gitlab."default".rails_method_calls WHERE action =~ /.+/ AND action !~ /^Grape#/ GROUP BY time(1m), method END; +CREATE CONTINUOUS QUERY rails_object_counts_overall ON gitlab BEGIN SELECT sum(count) AS count INTO gitlab.downsampled.rails_object_counts_overall FROM gitlab."default".rails_object_counts GROUP BY time(1m) END; +CREATE CONTINUOUS QUERY rails_object_counts_per_type ON gitlab BEGIN SELECT sum(count) AS count INTO gitlab.downsampled.rails_object_counts_per_type FROM gitlab."default".rails_object_counts GROUP BY time(1m), type END; +CREATE CONTINUOUS QUERY rails_transaction_counts_overall ON gitlab BEGIN SELECT count("duration") AS count INTO gitlab.downsampled.rails_transaction_counts_overall FROM gitlab."default".rails_transactions WHERE action =~ /.+/ AND action !~ /^Grape#/ GROUP BY time(1m) END; +CREATE CONTINUOUS QUERY rails_transaction_counts_per_action ON gitlab BEGIN SELECT count("duration") AS count INTO gitlab.downsampled.rails_transaction_counts_per_action FROM gitlab."default".rails_transactions WHERE action =~ /.+/ AND action !~ /^Grape#/ GROUP BY time(1m), action END; +CREATE CONTINUOUS QUERY rails_transaction_timings_overall ON gitlab BEGIN SELECT mean("duration") AS duration_mean, percentile("duration", 95) AS duration_95th, percentile("duration", 99) AS duration_99th, mean(sql_duration) AS sql_duration_mean, percentile(sql_duration, 95) AS sql_duration_95th, percentile(sql_duration, 99) AS sql_duration_99th, mean(view_duration) AS view_duration_mean, percentile(view_duration, 95) AS view_duration_95th, percentile(view_duration, 99) AS view_duration_99th, mean(cache_read_duration) AS cache_read_duration_mean, percentile(cache_read_duration, 99) AS cache_read_duration_99th, percentile(cache_read_duration, 95) AS cache_read_duration_95th, mean(cache_write_duration) AS cache_write_duration_mean, percentile(cache_write_duration, 99) AS cache_write_duration_99th, percentile(cache_write_duration, 95) AS cache_write_duration_95th, mean(cache_delete_duration) AS cache_delete_duration_mean, percentile(cache_delete_duration, 99) AS cache_delete_duration_99th, percentile(cache_delete_duration, 95) AS cache_delete_duration_95th, mean(cache_exists_duration) AS cache_exists_duration_mean, percentile(cache_exists_duration, 99) AS cache_exists_duration_99th, percentile(cache_exists_duration, 95) AS cache_exists_duration_95th, mean(cache_duration) AS cache_duration_mean, percentile(cache_duration, 99) AS cache_duration_99th, percentile(cache_duration, 95) AS cache_duration_95th, mean(method_duration) AS method_duration_mean, percentile(method_duration, 99) AS method_duration_99th, percentile(method_duration, 95) AS method_duration_95th INTO gitlab.downsampled.rails_transaction_timings_overall FROM gitlab."default".rails_transactions WHERE action =~ /.+/ AND action !~ /^Grape#/ GROUP BY time(1m) END; +CREATE CONTINUOUS QUERY rails_transaction_timings_per_action ON gitlab BEGIN SELECT mean("duration") AS duration_mean, percentile("duration", 95) AS duration_95th, percentile("duration", 99) AS duration_99th, mean(sql_duration) AS sql_duration_mean, percentile(sql_duration, 95) AS sql_duration_95th, percentile(sql_duration, 99) AS sql_duration_99th, mean(view_duration) AS view_duration_mean, percentile(view_duration, 95) AS view_duration_95th, percentile(view_duration, 99) AS view_duration_99th, mean(cache_read_duration) AS cache_read_duration_mean, percentile(cache_read_duration, 99) AS cache_read_duration_99th, percentile(cache_read_duration, 95) AS cache_read_duration_95th, mean(cache_write_duration) AS cache_write_duration_mean, percentile(cache_write_duration, 99) AS cache_write_duration_99th, percentile(cache_write_duration, 95) AS cache_write_duration_95th, mean(cache_delete_duration) AS cache_delete_duration_mean, percentile(cache_delete_duration, 99) AS cache_delete_duration_99th, percentile(cache_delete_duration, 95) AS cache_delete_duration_95th, mean(cache_exists_duration) AS cache_exists_duration_mean, percentile(cache_exists_duration, 99) AS cache_exists_duration_99th, percentile(cache_exists_duration, 95) AS cache_exists_duration_95th, mean(cache_duration) AS cache_duration_mean, percentile(cache_duration, 99) AS cache_duration_99th, percentile(cache_duration, 95) AS cache_duration_95th, mean(method_duration) AS method_duration_mean, percentile(method_duration, 99) AS method_duration_99th, percentile(method_duration, 95) AS method_duration_95th INTO gitlab.downsampled.rails_transaction_timings_per_action FROM gitlab."default".rails_transactions WHERE action =~ /.+/ AND action !~ /^Grape#/ GROUP BY time(1m), action END; +CREATE CONTINUOUS QUERY rails_view_timings_per_action_and_view ON gitlab BEGIN SELECT mean("duration") AS duration_mean, percentile("duration", 95) AS duration_95th, percentile("duration", 99) AS duration_99th INTO gitlab.downsampled.rails_view_timings_per_action_and_view FROM gitlab."default".rails_views WHERE action =~ /.+/ AND action !~ /^Grape#/ GROUP BY time(1m), action, view END; +CREATE CONTINUOUS QUERY sidekiq_file_descriptor_counts ON gitlab BEGIN SELECT sum(value) AS count INTO gitlab.downsampled.sidekiq_file_descriptor_counts FROM gitlab."default".sidekiq_file_descriptors GROUP BY time(1m) END; +CREATE CONTINUOUS QUERY sidekiq_gc_counts ON gitlab BEGIN SELECT sum(count) AS total, sum(minor_gc_count) AS minor, sum(major_gc_count) AS major INTO gitlab.downsampled.sidekiq_gc_counts FROM gitlab."default".sidekiq_gc_statistics GROUP BY time(1m) END; +CREATE CONTINUOUS QUERY sidekiq_gc_timings ON gitlab BEGIN SELECT mean(total_time) AS duration_mean, percentile(total_time, 95) AS duration_95th, percentile(total_time, 99) AS duration_99th INTO gitlab.downsampled.sidekiq_gc_timings FROM gitlab."default".sidekiq_gc_statistics GROUP BY time(1m) END; +CREATE CONTINUOUS QUERY sidekiq_git_timings_per_action ON gitlab BEGIN SELECT mean("duration") AS duration_mean, percentile("duration", 95) AS duration_95th, percentile("duration", 99) AS duration_99th INTO gitlab.downsampled.sidekiq_git_timings_per_action FROM gitlab."default".sidekiq_method_calls WHERE method =~ /^(Rugged|Gitlab::Git)/ GROUP BY time(1m), action END; +CREATE CONTINUOUS QUERY sidekiq_markdown_render_timings_overall ON gitlab BEGIN SELECT mean(banzai_cached_render_real_time) AS cached_real_mean, percentile(banzai_cached_render_real_time, 95) AS cached_real_95th, percentile(banzai_cached_render_real_time, 99) AS cached_real_99th, mean(banzai_cached_render_cpu_time) AS cached_cpu_mean, percentile(banzai_cached_render_cpu_time, 95) AS cached_cpu_95th, percentile(banzai_cached_render_cpu_time, 99) AS cached_cpu_99th, sum(banzai_cached_render_call_count) AS cached_call_count, mean(banzai_cacheless_render_real_time) AS cacheless_real_mean, percentile(banzai_cacheless_render_real_time, 95) AS cacheless_real_95th, percentile(banzai_cacheless_render_real_time, 99) AS cacheless_real_99th, mean(banzai_cacheless_render_cpu_time) AS cacheless_cpu_mean, percentile(banzai_cacheless_render_cpu_time, 95) AS cacheless_cpu_95th, percentile(banzai_cacheless_render_cpu_time, 99) AS cacheless_cpu_99th, sum(banzai_cacheless_render_call_count) AS cacheless_call_count INTO gitlab.downsampled.sidekiq_markdown_render_timings_overall FROM gitlab."default".sidekiq_transactions WHERE (banzai_cached_render_call_count > 0 OR banzai_cacheless_render_call_count > 0) GROUP BY time(1m) END; +CREATE CONTINUOUS QUERY sidekiq_markdown_render_timings_per_action ON gitlab BEGIN SELECT mean(banzai_cached_render_real_time) AS cached_real_mean, percentile(banzai_cached_render_real_time, 95) AS cached_real_95th, percentile(banzai_cached_render_real_time, 99) AS cached_real_99th, mean(banzai_cached_render_cpu_time) AS cached_cpu_mean, percentile(banzai_cached_render_cpu_time, 95) AS cached_cpu_95th, percentile(banzai_cached_render_cpu_time, 99) AS cached_cpu_99th, sum(banzai_cached_render_call_count) AS cached_call_count, mean(banzai_cacheless_render_real_time) AS cacheless_real_mean, percentile(banzai_cacheless_render_real_time, 95) AS cacheless_real_95th, percentile(banzai_cacheless_render_real_time, 99) AS cacheless_real_99th, mean(banzai_cacheless_render_cpu_time) AS cacheless_cpu_mean, percentile(banzai_cacheless_render_cpu_time, 95) AS cacheless_cpu_95th, percentile(banzai_cacheless_render_cpu_time, 99) AS cacheless_cpu_99th, sum(banzai_cacheless_render_call_count) AS cacheless_call_count INTO gitlab.downsampled.sidekiq_markdown_render_timings_per_action FROM gitlab."default".sidekiq_transactions WHERE (banzai_cached_render_call_count > 0 OR banzai_cacheless_render_call_count > 0) GROUP BY time(1m), action END; +CREATE CONTINUOUS QUERY sidekiq_markdown_timings_overall ON gitlab BEGIN SELECT mean("duration") AS duration_mean, percentile("duration", 95) AS duration_95th, percentile("duration", 99) AS duration_99th INTO gitlab.downsampled.sidekiq_markdown_timings_overall FROM gitlab."default".sidekiq_method_calls WHERE method =~ /^Banzai/ GROUP BY time(1m) END; +CREATE CONTINUOUS QUERY sidekiq_memory_usage_overall ON gitlab BEGIN SELECT mean(value) AS memory_mean, percentile(value, 95) AS memory_95th, percentile(value, 99) AS memory_99th INTO gitlab.downsampled.sidekiq_memory_usage_overall FROM gitlab."default".sidekiq_memory_usage GROUP BY time(1m) END; +CREATE CONTINUOUS QUERY sidekiq_method_call_timings_per_action_and_method ON gitlab BEGIN SELECT mean("duration") AS duration_mean, percentile("duration", 95) AS duration_95th, percentile("duration", 99) AS duration_99th INTO gitlab.downsampled.sidekiq_method_call_timings_per_action_and_method FROM gitlab."default".sidekiq_method_calls GROUP BY time(1m), method, action END; +CREATE CONTINUOUS QUERY sidekiq_method_call_timings_per_method ON gitlab BEGIN SELECT mean("duration") AS duration_mean, percentile("duration", 95) AS duration_95th, percentile("duration", 99) AS duration_99th INTO gitlab.downsampled.sidekiq_method_call_timings_per_method FROM gitlab."default".sidekiq_method_calls GROUP BY time(1m), method END; +CREATE CONTINUOUS QUERY sidekiq_object_counts_overall ON gitlab BEGIN SELECT sum(count) AS count INTO gitlab.downsampled.sidekiq_object_counts_overall FROM gitlab."default".sidekiq_object_counts GROUP BY time(1m) END; +CREATE CONTINUOUS QUERY sidekiq_object_counts_per_type ON gitlab BEGIN SELECT sum(count) AS count INTO gitlab.downsampled.sidekiq_object_counts_per_type FROM gitlab."default".sidekiq_object_counts GROUP BY time(1m), type END; +CREATE CONTINUOUS QUERY sidekiq_transaction_counts_overall ON gitlab BEGIN SELECT count("duration") AS count INTO gitlab.downsampled.sidekiq_transaction_counts_overall FROM gitlab."default".sidekiq_transactions GROUP BY time(1m) END; +CREATE CONTINUOUS QUERY sidekiq_transaction_counts_per_action ON gitlab BEGIN SELECT count("duration") AS count INTO gitlab.downsampled.sidekiq_transaction_counts_per_action FROM gitlab."default".sidekiq_transactions GROUP BY time(1m), action END; +CREATE CONTINUOUS QUERY sidekiq_transaction_timings_overall ON gitlab BEGIN SELECT mean("duration") AS duration_mean, percentile("duration", 95) AS duration_95th, percentile("duration", 99) AS duration_99th, mean(sql_duration) AS sql_duration_mean, percentile(sql_duration, 95) AS sql_duration_95th, percentile(sql_duration, 99) AS sql_duration_99th, mean(view_duration) AS view_duration_mean, percentile(view_duration, 95) AS view_duration_95th, percentile(view_duration, 99) AS view_duration_99th, mean(cache_read_duration) AS cache_read_duration_mean, percentile(cache_read_duration, 99) AS cache_read_duration_99th, percentile(cache_read_duration, 95) AS cache_read_duration_95th, mean(cache_write_duration) AS cache_write_duration_mean, percentile(cache_write_duration, 99) AS cache_write_duration_99th, percentile(cache_write_duration, 95) AS cache_write_duration_95th, mean(cache_delete_duration) AS cache_delete_duration_mean, percentile(cache_delete_duration, 99) AS cache_delete_duration_99th, percentile(cache_delete_duration, 95) AS cache_delete_duration_95th, mean(cache_exists_duration) AS cache_exists_duration_mean, percentile(cache_exists_duration, 99) AS cache_exists_duration_99th, percentile(cache_exists_duration, 95) AS cache_exists_duration_95th, mean(cache_duration) AS cache_duration_mean, percentile(cache_duration, 99) AS cache_duration_99th, percentile(cache_duration, 95) AS cache_duration_95th, mean(method_duration) AS method_duration_mean, percentile(method_duration, 99) AS method_duration_99th, percentile(method_duration, 95) AS method_duration_95th INTO gitlab.downsampled.sidekiq_transaction_timings_overall FROM gitlab."default".sidekiq_transactions GROUP BY time(1m) END; +CREATE CONTINUOUS QUERY sidekiq_transaction_timings_per_action ON gitlab BEGIN SELECT mean("duration") AS duration_mean, percentile("duration", 95) AS duration_95th, percentile("duration", 99) AS duration_99th, mean(sql_duration) AS sql_duration_mean, percentile(sql_duration, 95) AS sql_duration_95th, percentile(sql_duration, 99) AS sql_duration_99th, mean(view_duration) AS view_duration_mean, percentile(view_duration, 95) AS view_duration_95th, percentile(view_duration, 99) AS view_duration_99th, mean(cache_read_duration) AS cache_read_duration_mean, percentile(cache_read_duration, 99) AS cache_read_duration_99th, percentile(cache_read_duration, 95) AS cache_read_duration_95th, mean(cache_write_duration) AS cache_write_duration_mean, percentile(cache_write_duration, 99) AS cache_write_duration_99th, percentile(cache_write_duration, 95) AS cache_write_duration_95th, mean(cache_delete_duration) AS cache_delete_duration_mean, percentile(cache_delete_duration, 99) AS cache_delete_duration_99th, percentile(cache_delete_duration, 95) AS cache_delete_duration_95th, mean(cache_exists_duration) AS cache_exists_duration_mean, percentile(cache_exists_duration, 99) AS cache_exists_duration_99th, percentile(cache_exists_duration, 95) AS cache_exists_duration_95th, mean(cache_duration) AS cache_duration_mean, percentile(cache_duration, 99) AS cache_duration_99th, percentile(cache_duration, 95) AS cache_duration_95th, mean(method_duration) AS method_duration_mean, percentile(method_duration, 99) AS method_duration_99th, percentile(method_duration, 95) AS method_duration_95th INTO gitlab.downsampled.sidekiq_transaction_timings_per_action FROM gitlab."default".sidekiq_transactions GROUP BY time(1m), action END; +CREATE CONTINUOUS QUERY sidekiq_view_timings_per_action_and_view ON gitlab BEGIN SELECT mean("duration") AS duration_mean, percentile("duration", 95) AS duration_95th, percentile("duration", 99) AS duration_99th INTO gitlab.downsampled.sidekiq_view_timings_per_action_and_view FROM gitlab."default".sidekiq_views GROUP BY time(1m), action, view END; +CREATE CONTINUOUS QUERY web_transaction_counts_overall ON gitlab BEGIN SELECT count("duration") AS count INTO gitlab.downsampled.web_transaction_counts_overall FROM gitlab."default".rails_transactions GROUP BY time(1m) END; ``` ## Import Dashboards diff --git a/doc/workflow/shortcuts.png b/doc/workflow/shortcuts.png Binary files differindex 83e562d6929..beb6c53ec77 100644 --- a/doc/workflow/shortcuts.png +++ b/doc/workflow/shortcuts.png diff --git a/lib/api/project_hooks.rb b/lib/api/project_hooks.rb index cf9938d25a7..ccca65cbe1c 100644 --- a/lib/api/project_hooks.rb +++ b/lib/api/project_hooks.rb @@ -103,10 +103,10 @@ module API required_attributes! [:hook_id] begin - @hook = ProjectHook.find(params[:hook_id]) - @hook.destroy + @hook = user_project.hooks.destroy(params[:hook_id]) rescue # ProjectHook can raise Error if hook_id not found + not_found!("Error deleting hook #{params[:hook_id]}") end end end diff --git a/lib/award_emoji.rb b/lib/award_emoji.rb index 5f8ff01b0a9..b1aecc2e671 100644 --- a/lib/award_emoji.rb +++ b/lib/award_emoji.rb @@ -52,6 +52,10 @@ class AwardEmoji end end + def self.unicode + @unicode ||= emojis.map {|key, value| { key => emojis[key]["unicode"] } }.inject(:merge!) + end + def self.aliases @aliases ||= begin json_path = File.join(Rails.root, 'fixtures', 'emojis', 'aliases.json' ) diff --git a/lib/ci/gitlab_ci_yaml_processor.rb b/lib/ci/gitlab_ci_yaml_processor.rb index ff9887cba1e..504d3df9d34 100644 --- a/lib/ci/gitlab_ci_yaml_processor.rb +++ b/lib/ci/gitlab_ci_yaml_processor.rb @@ -61,23 +61,21 @@ module Ci @stages = @config[:stages] || @config[:types] @variables = @config[:variables] || {} @cache = @config[:cache] + @jobs = {} + @config.except!(*ALLOWED_YAML_KEYS) + @config.each { |name, param| add_job(name, param) } - # anything that doesn't have script is considered as unknown - @config.each do |name, param| - raise ValidationError, "Unknown parameter: #{name}" unless param.is_a?(Hash) && param.has_key?(:script) - end + raise ValidationError, "Please define at least one job" if @jobs.none? + end - unless @config.values.any?{|job| job.is_a?(Hash)} - raise ValidationError, "Please define at least one job" - end + def add_job(name, job) + return if name.to_s.start_with?('.') - @jobs = {} - @config.each do |key, job| - next if key.to_s.start_with?('.') - stage = job[:stage] || job[:type] || DEFAULT_STAGE - @jobs[key] = { stage: stage }.merge(job) - end + raise ValidationError, "Unknown parameter: #{name}" unless job.is_a?(Hash) && job.has_key?(:script) + + stage = job[:stage] || job[:type] || DEFAULT_STAGE + @jobs[name] = { stage: stage }.merge(job) end def build_job(name, job) @@ -112,8 +110,6 @@ module Ci true end - private - def validate_global! unless validate_array_of_strings(@before_script) raise ValidationError, "before_script should be an array of strings" diff --git a/lib/gitlab/gon_helper.rb b/lib/gitlab/gon_helper.rb index 5ebaad6ca6e..ab900b641c4 100644 --- a/lib/gitlab/gon_helper.rb +++ b/lib/gitlab/gon_helper.rb @@ -6,6 +6,7 @@ module Gitlab gon.default_issues_tracker = Project.new.default_issue_tracker.to_param gon.max_file_size = current_application_settings.max_attachment_size gon.relative_url_root = Gitlab.config.gitlab.relative_url_root + gon.shortcuts_path = help_shortcuts_path gon.user_color_scheme = Gitlab::ColorSchemes.for_user(current_user).css_class if current_user diff --git a/lib/support/nginx/gitlab b/lib/support/nginx/gitlab index 1324e4cd267..d521de28e8a 100644 --- a/lib/support/nginx/gitlab +++ b/lib/support/nginx/gitlab @@ -61,7 +61,8 @@ server { error_page 422 /422.html; error_page 500 /500.html; error_page 502 /502.html; - location ~ ^/(404|422|500|502)\.html$ { + error_page 503 /503.html; + location ~ ^/(404|422|500|502|503)\.html$ { root /home/git/gitlab/public; internal; } diff --git a/lib/support/nginx/gitlab-ssl b/lib/support/nginx/gitlab-ssl index af6ea9ed706..bf014b56cf6 100644 --- a/lib/support/nginx/gitlab-ssl +++ b/lib/support/nginx/gitlab-ssl @@ -105,7 +105,8 @@ server { error_page 422 /422.html; error_page 500 /500.html; error_page 502 /502.html; - location ~ ^/(404|422|500|502)\.html$ { + error_page 503 /503.html; + location ~ ^/(404|422|500|502|503)\.html$ { root /home/git/gitlab/public; internal; } diff --git a/public/503.html b/public/503.html new file mode 100644 index 00000000000..6ab1185658d --- /dev/null +++ b/public/503.html @@ -0,0 +1,54 @@ +<!DOCTYPE html> +<html> +<head> + <title>GitLab is not responding (503)</title> + <style> + body { + color: #666; + text-align: center; + font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; + margin: 0; + width: 800px; + margin: auto; + font-size: 14px; + } + + h1 { + font-size: 56px; + line-height: 100px; + font-weight: normal; + color: #456; + } + + h2 { + font-size: 24px; + color: #666; + line-height: 1.5em; + } + + h3 { + color: #456; + font-size: 20px; + font-weight: normal; + line-height: 28px; + } + + hr { + margin: 18px 0; + border: 0; + border-top: 1px solid #EEE; + border-bottom: 1px solid white; + } + </style> +</head> +<body> + <h1> + <img src="data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjEwIiBoZWlnaHQ9IjIxMCIgdmlld0JveD0iMCAwIDIxMCAyMTAiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+CiAgPHBhdGggZD0iTTEwNS4wNjE0IDIwMy42NTVsMzguNjQtMTE4LjkyMWgtNzcuMjhsMzguNjQgMTE4LjkyMXoiIGZpbGw9IiNlMjQzMjkiLz4KICA8cGF0aCBkPSJNMTA1LjA2MTQgMjAzLjY1NDhsLTM4LjY0LTExOC45MjFoLTU0LjE1M2w5Mi43OTMgMTE4LjkyMXoiIGZpbGw9IiNmYzZkMjYiLz4KICA8cGF0aCBkPSJNMTIuMjY4NSA4NC43MzQxbC0xMS43NDIgMzYuMTM5Yy0xLjA3MSAzLjI5Ni4xMDIgNi45MDcgMi45MDYgOC45NDRsMTAxLjYyOSA3My44MzgtOTIuNzkzLTExOC45MjF6IiBmaWxsPSIjZmNhMzI2Ii8+CiAgPHBhdGggZD0iTTEyLjI2ODUgODQuNzM0Mmg1NC4xNTNsLTIzLjI3My03MS42MjVjLTEuMTk3LTMuNjg2LTYuNDExLTMuNjg1LTcuNjA4IDBsLTIzLjI3MiA3MS42MjV6IiBmaWxsPSIjZTI0MzI5Ii8+CiAgPHBhdGggZD0iTTEwNS4wNjE0IDIwMy42NTQ4bDM4LjY0LTExOC45MjFoNTQuMTUzbC05Mi43OTMgMTE4LjkyMXoiIGZpbGw9IiNmYzZkMjYiLz4KICA8cGF0aCBkPSJNMTk3Ljg1NDQgODQuNzM0MWwxMS43NDIgMzYuMTM5YzEuMDcxIDMuMjk2LS4xMDIgNi45MDctMi45MDYgOC45NDRsLTEwMS42MjkgNzMuODM4IDkyLjc5My0xMTguOTIxeiIgZmlsbD0iI2ZjYTMyNiIvPgogIDxwYXRoIGQ9Ik0xOTcuODU0NCA4NC43MzQyaC01NC4xNTNsMjMuMjczLTcxLjYyNWMxLjE5Ny0zLjY4NiA2LjQxMS0zLjY4NSA3LjYwOCAwbDIzLjI3MiA3MS42MjV6IiBmaWxsPSIjZTI0MzI5Ii8+Cjwvc3ZnPgo=" alt="GitLab Logo"/><br /> + 503 + </h1> + <h3>Whoops, GitLab is currently unavailable.</h3> + <hr/> + <p>Try refreshing the page, or going back and attempting the action again.</p> + <p>Please contact your GitLab administrator if this problem persists.</p> +</body> +</html> diff --git a/spec/features/project/shortcuts_spec.rb b/spec/features/project/shortcuts_spec.rb new file mode 100644 index 00000000000..2595c4181e5 --- /dev/null +++ b/spec/features/project/shortcuts_spec.rb @@ -0,0 +1,21 @@ +require 'spec_helper' + +feature 'Project shortcuts', feature: true do + let(:project) { create(:project) } + let(:user) { create(:user) } + + describe 'On a project', js: true do + before do + project.team << [user, :master] + login_as user + visit namespace_project_path(project.namespace, project) + end + + describe 'pressing "i"' do + it 'redirects to new issue page' do + find('body').native.send_key('i') + expect(page).to have_content('New Issue') + end + end + end +end diff --git a/spec/features/projects/commit/builds_spec.rb b/spec/features/projects/commit/builds_spec.rb new file mode 100644 index 00000000000..40ba0bdc115 --- /dev/null +++ b/spec/features/projects/commit/builds_spec.rb @@ -0,0 +1,27 @@ +require 'spec_helper' + +feature 'project commit builds' do + given(:project) { create(:project) } + + background do + user = create(:user) + project.team << [user, :master] + login_as(user) + end + + context 'when no builds triggered yet' do + background do + create(:ci_commit, project: project, + sha: project.commit.sha, + ref: 'master') + end + + scenario 'user views commit builds page' do + visit builds_namespace_project_commit_path(project.namespace, + project, project.commit.sha) + + + expect(page).to have_content('Builds') + end + end +end diff --git a/spec/helpers/projects_helper_spec.rb b/spec/helpers/projects_helper_spec.rb index c258cfebd73..62389188d2c 100644 --- a/spec/helpers/projects_helper_spec.rb +++ b/spec/helpers/projects_helper_spec.rb @@ -105,4 +105,30 @@ describe ProjectsHelper do end end end + + describe '#license_short_name' do + let(:project) { create(:project) } + + context 'when project.repository has a license_key' do + it 'returns the nickname of the license if present' do + allow(project.repository).to receive(:license_key).and_return('agpl-3.0') + + expect(helper.license_short_name(project)).to eq('GNU AGPLv3') + end + + it 'returns the name of the license if nickname is not present' do + allow(project.repository).to receive(:license_key).and_return('mit') + + expect(helper.license_short_name(project)).to eq('MIT License') + end + end + + context 'when project.repository has no license_key but a license_blob' do + it 'returns LICENSE' do + allow(project.repository).to receive(:license_key).and_return(nil) + + expect(helper.license_short_name(project)).to eq('LICENSE') + end + end + end end diff --git a/spec/lib/ci/gitlab_ci_yaml_processor_spec.rb b/spec/lib/ci/gitlab_ci_yaml_processor_spec.rb index 643acf0303c..c7ab3185378 100644 --- a/spec/lib/ci/gitlab_ci_yaml_processor_spec.rb +++ b/spec/lib/ci/gitlab_ci_yaml_processor_spec.rb @@ -648,70 +648,131 @@ module Ci end describe "Hidden jobs" do - let(:config) do - YAML.dump({ - '.hidden_job' => { script: 'test' }, - 'normal_job' => { script: 'test' } - }) + let(:config_processor) { GitlabCiYamlProcessor.new(config) } + subject { config_processor.builds_for_stage_and_ref("test", "master") } + + shared_examples 'hidden_job_handling' do + it "doesn't create jobs that start with dot" do + expect(subject.size).to eq(1) + expect(subject.first).to eq({ + except: nil, + stage: "test", + stage_idx: 1, + name: :normal_job, + only: nil, + commands: "test", + tag_list: [], + options: {}, + when: "on_success", + allow_failure: false + }) + end end - let(:config_processor) { GitlabCiYamlProcessor.new(config) } + context 'when hidden job have a script definition' do + let(:config) do + YAML.dump({ + '.hidden_job' => { image: 'ruby:2.1', script: 'test' }, + 'normal_job' => { script: 'test' } + }) + end - subject { config_processor.builds_for_stage_and_ref("test", "master") } + it_behaves_like 'hidden_job_handling' + end - it "doesn't create jobs that starts with dot" do - expect(subject.size).to eq(1) - expect(subject.first).to eq({ - except: nil, - stage: "test", - stage_idx: 1, - name: :normal_job, - only: nil, - commands: "test", - tag_list: [], - options: {}, - when: "on_success", - allow_failure: false - }) + context "when hidden job doesn't have a script definition" do + let(:config) do + YAML.dump({ + '.hidden_job' => { image: 'ruby:2.1' }, + 'normal_job' => { script: 'test' } + }) + end + + it_behaves_like 'hidden_job_handling' end end describe "YAML Alias/Anchor" do - it "is correctly supported for jobs" do - config = <<EOT + let(:config_processor) { GitlabCiYamlProcessor.new(config) } + subject { config_processor.builds_for_stage_and_ref("build", "master") } + + shared_examples 'job_templates_handling' do + it "is correctly supported for jobs" do + expect(subject.size).to eq(2) + expect(subject.first).to eq({ + except: nil, + stage: "build", + stage_idx: 0, + name: :job1, + only: nil, + commands: "execute-script-for-job", + tag_list: [], + options: {}, + when: "on_success", + allow_failure: false + }) + expect(subject.second).to eq({ + except: nil, + stage: "build", + stage_idx: 0, + name: :job2, + only: nil, + commands: "execute-script-for-job", + tag_list: [], + options: {}, + when: "on_success", + allow_failure: false + }) + end + end + + context 'when template is a job' do + let(:config) do + <<EOT job1: &JOBTMPL + stage: build script: execute-script-for-job job2: *JOBTMPL EOT + end - config_processor = GitlabCiYamlProcessor.new(config) + it_behaves_like 'job_templates_handling' + end - expect(config_processor.builds_for_stage_and_ref("test", "master").size).to eq(2) - expect(config_processor.builds_for_stage_and_ref("test", "master").first).to eq({ - except: nil, - stage: "test", - stage_idx: 1, - name: :job1, - only: nil, - commands: "execute-script-for-job", - tag_list: [], - options: {}, - when: "on_success", - allow_failure: false - }) - expect(config_processor.builds_for_stage_and_ref("test", "master").second).to eq({ - except: nil, - stage: "test", - stage_idx: 1, - name: :job2, - only: nil, - commands: "execute-script-for-job", - tag_list: [], - options: {}, - when: "on_success", - allow_failure: false - }) + context 'when template is a hidden job' do + let(:config) do + <<EOT +.template: &JOBTMPL + stage: build + script: execute-script-for-job + +job1: *JOBTMPL + +job2: *JOBTMPL +EOT + end + + it_behaves_like 'job_templates_handling' + end + + context 'when job adds its own keys to a template definition' do + let(:config) do + <<EOT +.template: &JOBTMPL + stage: build + +job1: + <<: *JOBTMPL + script: execute-script-for-job + +job2: + <<: *JOBTMPL + script: execute-script-for-job +EOT + end + + it_behaves_like 'job_templates_handling' end end diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb index becc743de31..e33c7d62ff4 100644 --- a/spec/models/project_spec.rb +++ b/spec/models/project_spec.rb @@ -719,11 +719,8 @@ describe Project, models: true do with('foo.wiki', project). and_return(wiki) - expect(repo).to receive(:expire_cache) - expect(repo).to receive(:expire_emptiness_caches) - - expect(wiki).to receive(:expire_cache) - expect(wiki).to receive(:expire_emptiness_caches) + expect(repo).to receive(:before_delete) + expect(wiki).to receive(:before_delete) project.expire_caches_before_rename('foo') end diff --git a/spec/models/repository_spec.rb b/spec/models/repository_spec.rb index b561aa663d1..c19524a01f8 100644 --- a/spec/models/repository_spec.rb +++ b/spec/models/repository_spec.rb @@ -132,7 +132,6 @@ describe Repository, models: true do it { expect(subject.basename).to eq('a/b/c') } end end - end describe '#license_blob' do @@ -148,39 +147,18 @@ describe Repository, models: true do expect(repository.license_blob).to be_nil end - it 'favors license file with no extension' do - repository.commit_file(user, 'LICENSE', Licensee::License.new('mit').content, 'Add LICENSE', 'master', false) - repository.commit_file(user, 'LICENSE.md', Licensee::License.new('mit').content, 'Add LICENSE.md', 'master', false) - - expect(repository.license_blob.name).to eq('LICENSE') - end - - it 'favors .md file to .txt' do - repository.commit_file(user, 'LICENSE.md', Licensee::License.new('mit').content, 'Add LICENSE.md', 'master', false) - repository.commit_file(user, 'LICENSE.txt', Licensee::License.new('mit').content, 'Add LICENSE.txt', 'master', false) - - expect(repository.license_blob.name).to eq('LICENSE.md') - end - - it 'favors LICENCE to LICENSE' do - repository.commit_file(user, 'LICENSE', Licensee::License.new('mit').content, 'Add LICENSE', 'master', false) - repository.commit_file(user, 'LICENCE', Licensee::License.new('mit').content, 'Add LICENCE', 'master', false) - - expect(repository.license_blob.name).to eq('LICENCE') - end - - it 'favors LICENSE to COPYING' do - repository.commit_file(user, 'LICENSE', Licensee::License.new('mit').content, 'Add LICENSE', 'master', false) - repository.commit_file(user, 'COPYING', Licensee::License.new('mit').content, 'Add COPYING', 'master', false) + it 'detects license file with no recognizable open-source license content' do + repository.commit_file(user, 'LICENSE', 'Copyright!', 'Add LICENSE', 'master', false) expect(repository.license_blob.name).to eq('LICENSE') end - it 'favors LICENCE to COPYING' do - repository.commit_file(user, 'LICENCE', Licensee::License.new('mit').content, 'Add LICENCE', 'master', false) - repository.commit_file(user, 'COPYING', Licensee::License.new('mit').content, 'Add COPYING', 'master', false) + %w[LICENSE LICENCE LiCensE LICENSE.md LICENSE.foo COPYING COPYING.md].each do |filename| + it "detects '#{filename}'" do + repository.commit_file(user, filename, Licensee::License.new('mit').content, "Add #{filename}", 'master', false) - expect(repository.license_blob.name).to eq('LICENCE') + expect(repository.license_blob.name).to eq(filename) + end end end @@ -190,8 +168,14 @@ describe Repository, models: true do repository.remove_file(user, 'LICENSE', 'Remove LICENSE', 'master') end - it 'returns "no-license" when no license is detected' do - expect(repository.license_key).to eq('no-license') + it 'returns nil when no license is detected' do + expect(repository.license_key).to be_nil + end + + it 'detects license file with no recognizable open-source license content' do + repository.commit_file(user, 'LICENSE', 'Copyright!', 'Add LICENSE', 'master', false) + + expect(repository.license_key).to be_nil end it 'returns the license key' do diff --git a/spec/requests/api/project_hooks_spec.rb b/spec/requests/api/project_hooks_spec.rb index 142b637d291..ffb93bbb120 100644 --- a/spec/requests/api/project_hooks_spec.rb +++ b/spec/requests/api/project_hooks_spec.rb @@ -148,14 +148,24 @@ describe API::API, 'ProjectHooks', api: true do expect(response.status).to eq(200) end - it "should return success when deleting non existent hook" do + it "should return a 404 error when deleting non existent hook" do delete api("/projects/#{project.id}/hooks/42", user) - expect(response.status).to eq(200) + expect(response.status).to eq(404) end it "should return a 405 error if hook id not given" do delete api("/projects/#{project.id}/hooks", user) expect(response.status).to eq(405) end + + it "shold return a 404 if a user attempts to delete project hooks he/she does not own" do + test_user = create(:user) + other_project = create(:project) + other_project.team << [test_user, :master] + + delete api("/projects/#{other_project.id}/hooks/#{hook.id}", test_user) + expect(response.status).to eq(404) + expect(WebHook.exists?(hook.id)).to be_truthy + end end end |