diff options
37 files changed, 302 insertions, 136 deletions
diff --git a/app/assets/javascripts/boards/components/issue_card_inner.vue b/app/assets/javascripts/boards/components/issue_card_inner.vue index bdaed17fd09..274565adab0 100644 --- a/app/assets/javascripts/boards/components/issue_card_inner.vue +++ b/app/assets/javascripts/boards/components/issue_card_inner.vue @@ -177,9 +177,9 @@ export default { class="confidential-icon append-right-4" :aria-label="__('Confidential')" /> - <a :href="issue.path" :title="issue.title" class="js-no-trigger" @mousemove.stop> - {{ issue.title }} - </a> + <a :href="issue.path" :title="issue.title" class="js-no-trigger" @mousemove.stop>{{ + issue.title + }}</a> </h4> </div> <div v-if="showLabelFooter" class="board-card-labels prepend-top-4 d-flex flex-wrap"> @@ -225,7 +225,7 @@ export default { #{{ issue.iid }} </span> <span class="board-info-items prepend-top-8 d-inline-block"> - <issue-due-date v-if="issue.dueDate" :date="issue.dueDate" /> + <issue-due-date v-if="issue.dueDate" :date="issue.dueDate" :closed="issue.closed" /> <issue-time-estimate v-if="issue.timeEstimate" :estimate="issue.timeEstimate" /> <issue-card-weight v-if="validIssueWeight" diff --git a/app/assets/javascripts/boards/components/issue_due_date.vue b/app/assets/javascripts/boards/components/issue_due_date.vue index a32ebdab5e1..1d70c635c18 100644 --- a/app/assets/javascripts/boards/components/issue_due_date.vue +++ b/app/assets/javascripts/boards/components/issue_due_date.vue @@ -16,6 +16,11 @@ export default { GlTooltip, }, props: { + closed: { + type: Boolean, + required: false, + default: false, + }, date: { type: String, required: true, @@ -66,7 +71,7 @@ export default { return getDayDifference(today, this.issueDueDate); }, isPastDue() { - if (this.timeDifference >= 0) return false; + if (this.timeDifference >= 0 || this.closed) return false; return true; }, standardDateFormat() { @@ -92,7 +97,8 @@ export default { }}</time> </span> <gl-tooltip :target="() => $refs.issueDueDate" :placement="tooltipPlacement"> - <span class="bold">{{ __('Due date') }}</span> <br /> + <span class="bold">{{ __('Due date') }}</span> + <br /> <span :class="{ 'text-danger-muted': isPastDue }">{{ title }}</span> </gl-tooltip> </span> diff --git a/app/assets/javascripts/boards/models/issue.js b/app/assets/javascripts/boards/models/issue.js index 044d96a9aec..0e86359534b 100644 --- a/app/assets/javascripts/boards/models/issue.js +++ b/app/assets/javascripts/boards/models/issue.js @@ -19,6 +19,7 @@ class ListIssue { this.isFetching = { subscriptions: true, }; + this.closed = obj.closed; this.isLoading = {}; this.refreshData(obj, defaultAvatar); diff --git a/app/assets/javascripts/diffs/components/diff_file.vue b/app/assets/javascripts/diffs/components/diff_file.vue index f5051748f10..048dc274cf2 100644 --- a/app/assets/javascripts/diffs/components/diff_file.vue +++ b/app/assets/javascripts/diffs/components/diff_file.vue @@ -1,6 +1,6 @@ <script> import { mapActions, mapGetters, mapState } from 'vuex'; -import _ from 'underscore'; +import { escape as esc } from 'lodash'; import { GlLoadingIcon } from '@gitlab/ui'; import { __, sprintf } from '~/locale'; import createFlash from '~/flash'; @@ -46,7 +46,7 @@ export default { return sprintf( __('You can %{linkStart}view the blob%{linkEnd} instead.'), { - linkStart: `<a href="${_.escape(this.file.view_path)}">`, + linkStart: `<a href="${esc(this.file.view_path)}">`, linkEnd: '</a>', }, false, diff --git a/app/assets/javascripts/diffs/components/diff_file_header.vue b/app/assets/javascripts/diffs/components/diff_file_header.vue index 731c53a7339..d4270960f57 100644 --- a/app/assets/javascripts/diffs/components/diff_file_header.vue +++ b/app/assets/javascripts/diffs/components/diff_file_header.vue @@ -1,5 +1,5 @@ <script> -import _ from 'underscore'; +import { escape as esc } from 'lodash'; import { mapActions, mapGetters } from 'vuex'; import { GlButton, GlTooltipDirective, GlLoadingIcon } from '@gitlab/ui'; import { polyfillSticky } from '~/lib/utils/sticky'; @@ -91,7 +91,7 @@ export default { return this.expanded ? 'chevron-down' : 'chevron-right'; }, viewFileButtonText() { - const truncatedContentSha = _.escape(truncateSha(this.diffFile.content_sha)); + const truncatedContentSha = esc(truncateSha(this.diffFile.content_sha)); return sprintf( s__('MergeRequests|View file @ %{commitId}'), { commitId: truncatedContentSha }, @@ -99,7 +99,7 @@ export default { ); }, viewReplacedFileButtonText() { - const truncatedBaseSha = _.escape(truncateSha(this.diffFile.diff_refs.base_sha)); + const truncatedBaseSha = esc(truncateSha(this.diffFile.diff_refs.base_sha)); return sprintf( s__('MergeRequests|View replaced file @ %{commitId}'), { diff --git a/app/assets/javascripts/diffs/components/diff_stats.vue b/app/assets/javascripts/diffs/components/diff_stats.vue index 9d362ceb429..0234fc4f40e 100644 --- a/app/assets/javascripts/diffs/components/diff_stats.vue +++ b/app/assets/javascripts/diffs/components/diff_stats.vue @@ -1,7 +1,7 @@ <script> import Icon from '~/vue_shared/components/icon.vue'; import { n__ } from '~/locale'; -import { isNumber } from 'underscore'; +import { isNumber } from 'lodash'; export default { components: { Icon }, diff --git a/app/assets/javascripts/diffs/components/image_diff_overlay.vue b/app/assets/javascripts/diffs/components/image_diff_overlay.vue index 703a281308e..be7e6789216 100644 --- a/app/assets/javascripts/diffs/components/image_diff_overlay.vue +++ b/app/assets/javascripts/diffs/components/image_diff_overlay.vue @@ -1,6 +1,6 @@ <script> import { mapActions, mapGetters } from 'vuex'; -import _ from 'underscore'; +import { isArray } from 'lodash'; import imageDiffMixin from 'ee_else_ce/diffs/mixins/image_diff'; import Icon from '~/vue_shared/components/icon.vue'; @@ -46,7 +46,7 @@ export default { return this.getCommentFormForDiffFile(this.fileHash); }, allDiscussions() { - return _.isArray(this.discussions) ? this.discussions : [this.discussions]; + return isArray(this.discussions) ? this.discussions : [this.discussions]; }, }, methods: { diff --git a/app/assets/javascripts/diffs/components/no_changes.vue b/app/assets/javascripts/diffs/components/no_changes.vue index 47e9627a957..09cb542c3dc 100644 --- a/app/assets/javascripts/diffs/components/no_changes.vue +++ b/app/assets/javascripts/diffs/components/no_changes.vue @@ -1,6 +1,6 @@ <script> import { mapGetters } from 'vuex'; -import _ from 'underscore'; +import { escape as esc } from 'lodash'; import { GlButton } from '@gitlab/ui'; import { __, sprintf } from '~/locale'; @@ -24,8 +24,8 @@ export default { { ref_start: '<span class="ref-name">', ref_end: '</span>', - source_branch: _.escape(this.getNoteableData.source_branch), - target_branch: _.escape(this.getNoteableData.target_branch), + source_branch: esc(this.getNoteableData.source_branch), + target_branch: esc(this.getNoteableData.target_branch), }, false, ); diff --git a/app/assets/javascripts/diffs/store/utils.js b/app/assets/javascripts/diffs/store/utils.js index 29133c814ea..9c788e283b9 100644 --- a/app/assets/javascripts/diffs/store/utils.js +++ b/app/assets/javascripts/diffs/store/utils.js @@ -1,4 +1,4 @@ -import _ from 'underscore'; +import { property, isEqual } from 'lodash'; import { truncatePathMiddleToLength } from '~/lib/utils/text_utility'; import { diffModes, diffViewerModes } from '~/ide/constants'; import { @@ -442,7 +442,7 @@ export function isDiscussionApplicableToLine({ discussion, diffPosition, latestD const originalRefs = discussion.original_position; const refs = discussion.position; - return _.isEqual(refs, diffPositionCopy) || _.isEqual(originalRefs, diffPositionCopy); + return isEqual(refs, diffPositionCopy) || isEqual(originalRefs, diffPositionCopy); } // eslint-disable-next-line @@ -578,10 +578,10 @@ export const convertExpandLines = ({ for (let i = 0, diffLinesLength = diffLines.length; i < diffLinesLength; i += 1) { const line = diffLines[i]; - if (_.property(typeKey)(line) === 'match') { + if (property(typeKey)(line) === 'match') { const beforeLine = diffLines[i - 1]; const afterLine = diffLines[i + 1]; - const newLineProperty = _.property(newLineKey); + const newLineProperty = property(newLineKey); const beforeLineIndex = newLineProperty(beforeLine) || 0; const afterLineIndex = newLineProperty(afterLine) - 1 || dataLength; @@ -589,7 +589,7 @@ export const convertExpandLines = ({ ...data.slice(beforeLineIndex, afterLineIndex).map((l, index) => mapLine({ line: Object.assign(l, { hasForm: false, discussions: [] }), - oldLine: (_.property(oldLineKey)(beforeLine) || 0) + index + 1, + oldLine: (property(oldLineKey)(beforeLine) || 0) + index + 1, newLine: (newLineProperty(beforeLine) || 0) + index + 1, }), ), diff --git a/app/assets/stylesheets/pages/notes.scss b/app/assets/stylesheets/pages/notes.scss index 1a06ae1ed41..347addcec37 100644 --- a/app/assets/stylesheets/pages/notes.scss +++ b/app/assets/stylesheets/pages/notes.scss @@ -316,7 +316,7 @@ $note-form-margin-left: 72px; .btn.delete-description-history { position: absolute; top: 18px; - right: 0; + right: 10px; } pre { diff --git a/app/controllers/projects/graphs_controller.rb b/app/controllers/projects/graphs_controller.rb index 67d3f49af18..889dcefb65a 100644 --- a/app/controllers/projects/graphs_controller.rb +++ b/app/controllers/projects/graphs_controller.rb @@ -37,7 +37,8 @@ class Projects::GraphsController < Projects::ApplicationController private def get_commits - @commits = @project.repository.commits(@ref, limit: 2000, skip_merges: true) + @commits_limit = 2000 + @commits = @project.repository.commits(@ref, limit: @commits_limit, skip_merges: true) @commits_graph = Gitlab::Graphs::Commits.new(@commits) @commits_per_week_days = @commits_graph.commits_per_week_days @commits_per_time = @commits_graph.commits_per_time diff --git a/app/models/clusters/applications/runner.rb b/app/models/clusters/applications/runner.rb index 6a9cd77d356..4886f2debb1 100644 --- a/app/models/clusters/applications/runner.rb +++ b/app/models/clusters/applications/runner.rb @@ -3,7 +3,7 @@ module Clusters module Applications class Runner < ApplicationRecord - VERSION = '0.13.1' + VERSION = '0.14.0' self.table_name = 'clusters_applications_runners' diff --git a/app/serializers/issue_board_entity.rb b/app/serializers/issue_board_entity.rb index 13897279815..ea629d9d774 100644 --- a/app/serializers/issue_board_entity.rb +++ b/app/serializers/issue_board_entity.rb @@ -12,6 +12,9 @@ class IssueBoardEntity < Grape::Entity expose :project_id expose :relative_position expose :time_estimate + expose :closed do |issue| + issue.closed? + end expose :project do |issue| API::Entities::Project.represent issue.project, only: [:id, :path] diff --git a/app/views/award_emoji/_awards_block.html.haml b/app/views/award_emoji/_awards_block.html.haml index 793ddef2c58..a063fe54c99 100644 --- a/app/views/award_emoji/_awards_block.html.haml +++ b/app/views/award_emoji/_awards_block.html.haml @@ -16,5 +16,4 @@ %span{ class: "award-control-icon award-control-icon-neutral" }= sprite_icon('slight-smile') %span{ class: "award-control-icon award-control-icon-positive" }= sprite_icon('smiley') %span{ class: "award-control-icon award-control-icon-super-positive" }= sprite_icon('smile') - = icon('spinner spin', class: "award-control-icon award-control-icon-loading") = yield diff --git a/app/views/projects/graphs/charts.html.haml b/app/views/projects/graphs/charts.html.haml index b38449b3ab9..cb76e89f736 100644 --- a/app/views/projects/graphs/charts.html.haml +++ b/app/views/projects/graphs/charts.html.haml @@ -20,6 +20,7 @@ - end_time = capture do #{@commits_graph.end_date.strftime('%b %d')} = (_("Commit statistics for %{ref} %{start_time} - %{end_time}") % { ref: "<strong>#{h @ref}</strong>", start_time: start_time, end_time: end_time }).html_safe + = _("Excluding merge commits. Limited to %{limit} commits.") % {limit: number_with_delimiter(@commits_limit, delimiter: ',')} .col-md-6 .tree-ref-container diff --git a/changelogs/unreleased/205184-change-omniauth-log-format-to-json.yml b/changelogs/unreleased/205184-change-omniauth-log-format-to-json.yml new file mode 100644 index 00000000000..400640bf053 --- /dev/null +++ b/changelogs/unreleased/205184-change-omniauth-log-format-to-json.yml @@ -0,0 +1,5 @@ +--- +title: Change OmniAuth log format to JSON +merge_request: 25086 +author: +type: other diff --git a/changelogs/unreleased/28627-adjust-commit-stats-over-limit-indication.yml b/changelogs/unreleased/28627-adjust-commit-stats-over-limit-indication.yml new file mode 100644 index 00000000000..08ad9a7c183 --- /dev/null +++ b/changelogs/unreleased/28627-adjust-commit-stats-over-limit-indication.yml @@ -0,0 +1,5 @@ +--- +title: Add commits limit text at graphs page +merge_request: 24990 +author: +type: changed diff --git a/changelogs/unreleased/Resolve-Migrate--fa-spinner-app-views-award_emoji.yml b/changelogs/unreleased/Resolve-Migrate--fa-spinner-app-views-award_emoji.yml new file mode 100644 index 00000000000..cf1cce15919 --- /dev/null +++ b/changelogs/unreleased/Resolve-Migrate--fa-spinner-app-views-award_emoji.yml @@ -0,0 +1,5 @@ +--- +title: Remove spinner from app/views/award_emoji +merge_request: 25032 +author: nuwe1 +type: other diff --git a/changelogs/unreleased/closed-issue-weight-grey.yml b/changelogs/unreleased/closed-issue-weight-grey.yml new file mode 100644 index 00000000000..283f88aa606 --- /dev/null +++ b/changelogs/unreleased/closed-issue-weight-grey.yml @@ -0,0 +1,5 @@ +--- +title: Board issue due dates appear grey for closed past-due issues +merge_request: 25507 +author: rachelfox +type: fixed diff --git a/changelogs/unreleased/sh-fix-license-check-migration.yml b/changelogs/unreleased/sh-fix-license-check-migration.yml new file mode 100644 index 00000000000..95e15c2f303 --- /dev/null +++ b/changelogs/unreleased/sh-fix-license-check-migration.yml @@ -0,0 +1,5 @@ +--- +title: Fix upgrade failure in EE displaying license +merge_request: 25788 +author: +type: fixed diff --git a/changelogs/unreleased/update-gitlab-runner-helm-chart-to-0-14-0.yml b/changelogs/unreleased/update-gitlab-runner-helm-chart-to-0-14-0.yml new file mode 100644 index 00000000000..5342809ca07 --- /dev/null +++ b/changelogs/unreleased/update-gitlab-runner-helm-chart-to-0-14-0.yml @@ -0,0 +1,5 @@ +--- +title: Update GitLab Runner Helm Chart to 0.14.0 +merge_request: 25749 +author: +type: other diff --git a/config/initializers/0_license.rb b/config/initializers/0_license.rb index 5c4546f499f..19c71c34904 100644 --- a/config/initializers/0_license.rb +++ b/config/initializers/0_license.rb @@ -10,7 +10,7 @@ Gitlab.ee do end # Needed to run migration - if Gitlab::Database.cached_table_exists?('licenses') + if ActiveRecord::Base.connected? && ActiveRecord::Base.connection.table_exists?('licenses') message = LicenseHelper.license_message(signed_in: true, is_admin: true, in_html: false) if ::License.block_changes? && message.present? warn "WARNING: #{message}" diff --git a/config/initializers/omniauth.rb b/config/initializers/omniauth.rb index ef23ca065c6..0e4cb88b50f 100644 --- a/config/initializers/omniauth.rb +++ b/config/initializers/omniauth.rb @@ -16,3 +16,7 @@ OmniAuth.config.allowed_request_methods << :get if Gitlab.config.omniauth.auto_s OmniAuth.config.before_request_phase do |env| Gitlab::RequestForgeryProtection.call(env) end + +# Use json formatter +OmniAuth.config.logger.formatter = Gitlab::OmniauthLogging::JSONFormatter.new +OmniAuth.config.logger.level = Logger::ERROR if Rails.env.production? diff --git a/doc/.linting/vale/styles/gitlab/Contractions.yml b/doc/.linting/vale/styles/gitlab/Contractions.yml index 0f31f6b6aa9..5f389bd1ea4 100644 --- a/doc/.linting/vale/styles/gitlab/Contractions.yml +++ b/doc/.linting/vale/styles/gitlab/Contractions.yml @@ -1,35 +1,13 @@ --- -# `extends` indicates the Vale extension point being used. -# Full list of styles: https://errata-ai.github.io/vale/styles/ +# Checks for use of common and uncommon contractions. +# +# For a list of all options, see https://errata-ai.github.io/vale/styles/ extends: substitution - -# Substitution rules can display the matched and suggested strings in the -# message shown to the user. The first use of %s prints the suggested option, -# and the second use of %s displays what was found in the text. message: Use "%s" instead of "%s" in most cases. - -# Should a result be flagged as a suggestion, warning, or error? -# Results that fall below the MinAlertLevel set in -# https://gitlab.com/gitlab-org/gitlab/blob/master/.vale.ini won't be shown. +link: https://docs.gitlab.com/ee/development/documentation/styleguide.html#language level: suggestion - -# Should a match be case-insensitive or case-sensitive? -# Acceptable values are 'true' or 'false' -ignorecase: true - -# Should this rule be limited to a specific scope? If yes, uncomment the line. -# Possible scopes: https://errata-ai.github.io/vale/formats/#available-scopes -# scope: heading - -# Should this rule ignore normal word boundaries, such as \b ? -# Acceptable values are 'true' or 'false' nonword: false - -# What is the source for this rule? -link: https://docs.gitlab.com/ee/development/documentation/styleguide.html#language - -# The 'swap' section provides a list of values, one per line, in the form of -# $bad: $good +ignorecase: true swap: # Common contractions are ok @@ -73,4 +51,3 @@ swap: who'll: who will why's: why is why'll: why will - diff --git a/doc/.linting/vale/styles/gitlab/LatinTerms.yml b/doc/.linting/vale/styles/gitlab/LatinTerms.yml index 082b56147a4..8412631f8fe 100644 --- a/doc/.linting/vale/styles/gitlab/LatinTerms.yml +++ b/doc/.linting/vale/styles/gitlab/LatinTerms.yml @@ -1,35 +1,13 @@ --- -# `extends` indicates the Vale extension point being used. -# Full list of styles: https://errata-ai.github.io/vale/styles/ +# Checks for use of latin terms.. +# +# For a list of all options, see https://errata-ai.github.io/vale/styles/ extends: substitution - -# Substitution rules can display the matched and suggested strings in the -# message shown to the user. The first use of %s prints the suggested option, -# and the second use of %s displays what was found in the text. message: Use "%s" instead of "%s," but consider rewriting the sentence. - -# Should a result be flagged as a suggestion, warning, or error? -# Results that fall below the MinAlertLevel set in -# https://gitlab.com/gitlab-org/gitlab/blob/master/.vale.ini won't be shown. +link: https://docs.gitlab.com/ee/development/documentation/styleguide.html#language level: warning - -# Should a match be case-insensitive or case-sensitive? -# Acceptable values are 'true' or 'false' -ignorecase: true - -# Should this rule be limited to a specific scope? If yes, uncomment the line. -# Possible scopes: https://errata-ai.github.io/vale/formats/#available-scopes -# scope: heading - -# Should this rule ignore normal word boundaries, such as \b ? -# Acceptable values are 'true' or 'false' nonword: true - -# What is the source for this rule? -link: https://docs.gitlab.com/ee/development/documentation/styleguide.html#language - -# The 'swap' section provides a list of values, one per line, in the form of -# $bad: $good +ignorecase: true swap: e\.g\.: for example e\. g\.: for example diff --git a/doc/.linting/vale/styles/gitlab/Substitutions.yml b/doc/.linting/vale/styles/gitlab/Substitutions.yml index d9ae1dfcb07..1ddd2f8bf4e 100644 --- a/doc/.linting/vale/styles/gitlab/Substitutions.yml +++ b/doc/.linting/vale/styles/gitlab/Substitutions.yml @@ -1,35 +1,13 @@ --- -# `extends` indicates the Vale extension point being used. -# Full list of styles: https://errata-ai.github.io/vale/styles/ +# Checks for use of top misused terms at GitLab. +# +# For a list of all options, see https://errata-ai.github.io/vale/styles/ extends: substitution - -# Substitution rules can display the matched and suggested strings in the -# message shown to the user. The first use of %s prints the suggested option, -# and the second use of %s displays what was found in the text. message: Use "%s" instead of "%s." - -# Should a result be flagged as a suggestion, warning, or error? -# Results that fall below the MinAlertLevel set in -# https://gitlab.com/gitlab-org/gitlab/blob/master/.vale.ini won't be shown. +link: https://about.gitlab.com/handbook/communication/#top-misused-terms level: warning - -# Should a match be case-insensitive or case-sensitive? -# Acceptable values are 'true' or 'false' -ignorecase: true - -# Should this rule be limited to a specific scope? If yes, uncomment the line. -# Possible scopes: https://errata-ai.github.io/vale/formats/#available-scopes -# scope: heading - -# Should this rule ignore normal word boundaries, such as \b ? -# Acceptable values are 'true' or 'false' nonword: true - -# What is the source for this rule? -link: https://about.gitlab.com/handbook/communication/#top-misused-terms - -# The 'swap' section provides a list of values, one per line, in the form of -# $bad: $good +ignorecase: true swap: GitLabber: GitLab team member self hosted: self-managed diff --git a/doc/development/event_tracking/frontend.md b/doc/development/event_tracking/frontend.md index c767efc65b2..4139bf2322d 100644 --- a/doc/development/event_tracking/frontend.md +++ b/doc/development/event_tracking/frontend.md @@ -104,7 +104,7 @@ And if needed within the template, you can use the `track` method directly as we Custom event tracking and instrumentation can be added by directly calling the `Tracking.event` static function. The following example demonstrates tracking a click on a button by calling `Tracking.event` manually. ```javascript -import Tracking from `~/tracking`; +import Tracking from '~/tracking'; const button = document.getElementById('create_from_template_button'); button.addEventListener('click', () => { diff --git a/lib/gitlab/omniauth_logging/json_formatter.rb b/lib/gitlab/omniauth_logging/json_formatter.rb new file mode 100644 index 00000000000..cdd4da31803 --- /dev/null +++ b/lib/gitlab/omniauth_logging/json_formatter.rb @@ -0,0 +1,13 @@ +# frozen_string_literal: true + +require 'json' + +module Gitlab + module OmniauthLogging + class JSONFormatter + def call(severity, datetime, progname, msg) + { severity: severity, timestamp: datetime.utc.iso8601(3), pid: $$, progname: progname, message: msg }.to_json << "\n" + end + end + end +end diff --git a/lib/gitlab/reactive_cache_set_cache.rb b/lib/gitlab/reactive_cache_set_cache.rb new file mode 100644 index 00000000000..14d008c3dfb --- /dev/null +++ b/lib/gitlab/reactive_cache_set_cache.rb @@ -0,0 +1,30 @@ +# frozen_string_literal: true + +# Interface to the Redis-backed cache store to keep track of complete cache keys +# for a ReactiveCache resource. +module Gitlab + class ReactiveCacheSetCache < Gitlab::SetCache + attr_reader :expires_in + + def initialize(expires_in: 10.minutes) + @expires_in = expires_in + end + + def clear_cache!(key) + with do |redis| + keys = read(key).map { |value| "#{cache_type}#{value}" } + keys << cache_key(key) + + redis.pipelined do + keys.each_slice(1000) { |subset| redis.del(*subset) } + end + end + end + + private + + def cache_type + "#{Gitlab::Redis::Cache::CACHE_NAMESPACE}:" + end + end +end diff --git a/lib/gitlab/repository_set_cache.rb b/lib/gitlab/repository_set_cache.rb index 4797ec0b116..1e2d86b7ad2 100644 --- a/lib/gitlab/repository_set_cache.rb +++ b/lib/gitlab/repository_set_cache.rb @@ -2,7 +2,7 @@ # Interface to the Redis-backed cache store for keys that use a Redis set module Gitlab - class RepositorySetCache + class RepositorySetCache < Gitlab::SetCache attr_reader :repository, :namespace, :expires_in def initialize(repository, extra_namespace: nil, expires_in: 2.weeks) @@ -17,18 +17,6 @@ module Gitlab "#{type}:#{namespace}:set" end - def expire(key) - with { |redis| redis.del(cache_key(key)) } - end - - def exist?(key) - with { |redis| redis.exists(cache_key(key)) } - end - - def read(key) - with { |redis| redis.smembers(cache_key(key)) } - end - def write(key, value) full_key = cache_key(key) @@ -54,15 +42,5 @@ module Gitlab write(key, yield) end end - - def include?(key, value) - with { |redis| redis.sismember(cache_key(key), value) } - end - - private - - def with(&blk) - Gitlab::Redis::Cache.with(&blk) # rubocop:disable CodeReuse/ActiveRecord - end end end diff --git a/lib/gitlab/set_cache.rb b/lib/gitlab/set_cache.rb new file mode 100644 index 00000000000..0927a3e64bb --- /dev/null +++ b/lib/gitlab/set_cache.rb @@ -0,0 +1,55 @@ +# frozen_string_literal: true + +# Interface to the Redis-backed cache store to keep track of complete cache keys +# for a ReactiveCache resource. +module Gitlab + class SetCache + attr_reader :expires_in + + def initialize(expires_in: 2.weeks) + @expires_in = expires_in + end + + def cache_key(key) + "#{key}:set" + end + + def expire(key) + with { |redis| redis.del(cache_key(key)) } + end + + def exist?(key) + with { |redis| redis.exists(cache_key(key)) } + end + + def write(key, value) + with do |redis| + redis.pipelined do + redis.sadd(cache_key(key), value) + + redis.expire(cache_key(key), expires_in) + end + end + + value + end + + def read(key) + with { |redis| redis.smembers(cache_key(key)) } + end + + def include?(key, value) + with { |redis| redis.sismember(cache_key(key), value) } + end + + def ttl(key) + with { |redis| redis.ttl(cache_key(key)) } + end + + private + + def with(&blk) + Gitlab::Redis::Cache.with(&blk) # rubocop:disable CodeReuse/ActiveRecord + end + end +end diff --git a/locale/gitlab.pot b/locale/gitlab.pot index d0cb12da37c..f241503c40d 100644 --- a/locale/gitlab.pot +++ b/locale/gitlab.pot @@ -7951,6 +7951,9 @@ msgstr "" msgid "Except policy:" msgstr "" +msgid "Excluding merge commits. Limited to %{limit} commits." +msgstr "" + msgid "Excluding merge commits. Limited to 6,000 commits." msgstr "" diff --git a/spec/fixtures/api/schemas/entities/issue_board.json b/spec/fixtures/api/schemas/entities/issue_board.json index 09f66813c95..d7e3c45b13b 100644 --- a/spec/fixtures/api/schemas/entities/issue_board.json +++ b/spec/fixtures/api/schemas/entities/issue_board.json @@ -5,6 +5,7 @@ "iid": { "type": "integer" }, "title": { "type": "string" }, "confidential": { "type": "boolean" }, + "closed": { "type": "boolean" }, "due_date": { "type": "date" }, "project_id": { "type": "integer" }, "relative_position": { "type": ["integer", "null"] }, diff --git a/spec/frontend/boards/components/issue_due_date_spec.js b/spec/frontend/boards/components/issue_due_date_spec.js index 68e26b68f04..8cb1d963851 100644 --- a/spec/frontend/boards/components/issue_due_date_spec.js +++ b/spec/frontend/boards/components/issue_due_date_spec.js @@ -7,8 +7,8 @@ describe('Issue Due Date component', () => { let vm; let date; const Component = Vue.extend(IssueDueDate); - const createComponent = (dueDate = new Date()) => - mountComponent(Component, { date: dateFormat(dueDate, 'yyyy-mm-dd', true) }); + const createComponent = (dueDate = new Date(), closed = false) => + mountComponent(Component, { closed, date: dateFormat(dueDate, 'yyyy-mm-dd', true) }); beforeEach(() => { date = new Date(); @@ -56,10 +56,17 @@ describe('Issue Due Date component', () => { expect(vm.$el.querySelector('time').textContent.trim()).toEqual(dateFormat(date, format)); }); - it('should contain the correct `.text-danger` css class for overdue issue', () => { + it('should contain the correct `.text-danger` css class for overdue issue that is open', () => { date.setDate(date.getDate() - 17); vm = createComponent(date); expect(vm.$el.querySelector('time').classList.contains('text-danger')).toEqual(true); }); + + it('should not contain the `.text-danger` css class for overdue issue that is closed', () => { + date.setDate(date.getDate() - 17); + vm = createComponent(date, true); + + expect(vm.$el.querySelector('time').classList.contains('text-danger')).toEqual(false); + }); }); diff --git a/spec/lib/gitlab/omniauth_logging/json_formatter_spec.rb b/spec/lib/gitlab/omniauth_logging/json_formatter_spec.rb new file mode 100644 index 00000000000..36405daed5a --- /dev/null +++ b/spec/lib/gitlab/omniauth_logging/json_formatter_spec.rb @@ -0,0 +1,12 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe Gitlab::OmniauthLogging::JSONFormatter do + it "generates log in json format" do + Timecop.freeze(Time.utc(2019, 12, 04, 9, 10, 11, 123456)) do + expect(subject.call(:info, Time.now, 'omniauth', 'log message')) + .to eq %Q({"severity":"info","timestamp":"2019-12-04T09:10:11.123Z","pid":#{Process.pid},"progname":"omniauth","message":"log message"}\n) + end + end +end diff --git a/spec/lib/gitlab/reactive_cache_set_cache_spec.rb b/spec/lib/gitlab/reactive_cache_set_cache_spec.rb new file mode 100644 index 00000000000..58c8fd0c1c3 --- /dev/null +++ b/spec/lib/gitlab/reactive_cache_set_cache_spec.rb @@ -0,0 +1,74 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe Gitlab::ReactiveCacheSetCache, :clean_gitlab_redis_cache do + let_it_be(:project) { create(:project) } + let(:cache_prefix) { 'cache_prefix' } + let(:expires_in) { 10.minutes } + let(:cache) { described_class.new(expires_in: expires_in) } + + describe '#cache_key' do + subject { cache.cache_key(cache_prefix) } + + it 'includes the suffix' do + expect(subject).to eq "#{cache_prefix}:set" + end + end + + describe '#read' do + subject { cache.read(cache_prefix) } + + it { is_expected.to be_empty } + + context 'after item added' do + before do + cache.write(cache_prefix, 'test_item') + end + + it { is_expected.to contain_exactly('test_item') } + end + end + + describe '#write' do + it 'writes the value to the cache' do + cache.write(cache_prefix, 'test_item') + + expect(cache.read(cache_prefix)).to contain_exactly('test_item') + end + + it 'sets the expiry of the set' do + cache.write(cache_prefix, 'test_item') + + expect(cache.ttl(cache_prefix)).to be_within(1).of(expires_in.seconds) + end + end + + describe '#clear_cache!', :use_clean_rails_redis_caching do + it 'deletes the cached items' do + # Cached key and value + Rails.cache.write('test_item', 'test_value') + # Add key to set + cache.write(cache_prefix, 'test_item') + + expect(cache.read(cache_prefix)).to contain_exactly('test_item') + cache.clear_cache!(cache_prefix) + + expect(cache.read(cache_prefix)).to be_empty + end + end + + describe '#include?' do + subject { cache.include?(cache_prefix, 'test_item') } + + it { is_expected.to be(false) } + + context 'item added' do + before do + cache.write(cache_prefix, 'test_item') + end + + it { is_expected.to be(true) } + end + end +end diff --git a/spec/support/caching.rb b/spec/support/caching.rb index ecbe65f7e97..883d531550a 100644 --- a/spec/support/caching.rb +++ b/spec/support/caching.rb @@ -21,6 +21,21 @@ RSpec.configure do |config| ActionController::Base.cache_store = caching_store end + config.around(:each, :use_clean_rails_redis_caching) do |example| + original_null_store = Rails.cache + caching_config_hash = Gitlab::Redis::Cache.params + caching_config_hash[:namespace] = Gitlab::Redis::Cache::CACHE_NAMESPACE + Rails.cache = ActiveSupport::Cache::RedisCacheStore.new(caching_config_hash) + + redis_cache_cleanup! + + example.run + + redis_cache_cleanup! + + Rails.cache = original_null_store + end + config.around(:each, :use_sql_query_cache) do |example| ActiveRecord::Base.cache do example.run |