Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
be660fe1d2
commit
38149afcf9
37 changed files with 305 additions and 139 deletions
|
@ -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"
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -19,6 +19,7 @@ class ListIssue {
|
|||
this.isFetching = {
|
||||
subscriptions: true,
|
||||
};
|
||||
this.closed = obj.closed;
|
||||
this.isLoading = {};
|
||||
|
||||
this.refreshData(obj, defaultAvatar);
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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}'),
|
||||
{
|
||||
|
|
|
@ -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 },
|
||||
|
|
|
@ -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: {
|
||||
|
|
|
@ -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,
|
||||
);
|
||||
|
|
|
@ -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,
|
||||
}),
|
||||
),
|
||||
|
|
|
@ -316,7 +316,7 @@ $note-form-margin-left: 72px;
|
|||
.btn.delete-description-history {
|
||||
position: absolute;
|
||||
top: 18px;
|
||||
right: 0;
|
||||
right: 10px;
|
||||
}
|
||||
|
||||
pre {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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'
|
||||
|
||||
|
|
|
@ -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]
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Change OmniAuth log format to JSON
|
||||
merge_request: 25086
|
||||
author:
|
||||
type: other
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Add commits limit text at graphs page
|
||||
merge_request: 24990
|
||||
author:
|
||||
type: changed
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Remove spinner from app/views/award_emoji
|
||||
merge_request: 25032
|
||||
author: nuwe1
|
||||
type: other
|
5
changelogs/unreleased/closed-issue-weight-grey.yml
Normal file
5
changelogs/unreleased/closed-issue-weight-grey.yml
Normal file
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Board issue due dates appear grey for closed past-due issues
|
||||
merge_request: 25507
|
||||
author: rachelfox
|
||||
type: fixed
|
5
changelogs/unreleased/sh-fix-license-check-migration.yml
Normal file
5
changelogs/unreleased/sh-fix-license-check-migration.yml
Normal file
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Fix upgrade failure in EE displaying license
|
||||
merge_request: 25788
|
||||
author:
|
||||
type: fixed
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Update GitLab Runner Helm Chart to 0.14.0
|
||||
merge_request: 25749
|
||||
author:
|
||||
type: other
|
|
@ -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}"
|
||||
|
|
|
@ -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?
|
||||
|
|
|
@ -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.
|
||||
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
|
||||
level: suggestion
|
||||
nonword: false
|
||||
ignorecase: true
|
||||
swap:
|
||||
|
||||
# Common contractions are ok
|
||||
|
@ -73,4 +51,3 @@ swap:
|
|||
who'll: who will
|
||||
why's: why is
|
||||
why'll: why will
|
||||
|
||||
|
|
|
@ -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.
|
||||
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
|
||||
level: warning
|
||||
nonword: true
|
||||
ignorecase: true
|
||||
swap:
|
||||
e\.g\.: for example
|
||||
e\. g\.: for example
|
||||
|
|
|
@ -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.
|
||||
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
|
||||
level: warning
|
||||
nonword: true
|
||||
ignorecase: true
|
||||
swap:
|
||||
GitLabber: GitLab team member
|
||||
self hosted: self-managed
|
||||
|
|
|
@ -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', () => {
|
||||
|
|
13
lib/gitlab/omniauth_logging/json_formatter.rb
Normal file
13
lib/gitlab/omniauth_logging/json_formatter.rb
Normal file
|
@ -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
|
30
lib/gitlab/reactive_cache_set_cache.rb
Normal file
30
lib/gitlab/reactive_cache_set_cache.rb
Normal file
|
@ -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
|
|
@ -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
|
||||
|
|
55
lib/gitlab/set_cache.rb
Normal file
55
lib/gitlab/set_cache.rb
Normal file
|
@ -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
|
|
@ -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 ""
|
||||
|
||||
|
|
|
@ -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"] },
|
||||
|
|
|
@ -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);
|
||||
});
|
||||
});
|
||||
|
|
12
spec/lib/gitlab/omniauth_logging/json_formatter_spec.rb
Normal file
12
spec/lib/gitlab/omniauth_logging/json_formatter_spec.rb
Normal file
|
@ -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
|
74
spec/lib/gitlab/reactive_cache_set_cache_spec.rb
Normal file
74
spec/lib/gitlab/reactive_cache_set_cache_spec.rb
Normal file
|
@ -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
|
|
@ -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
|
||||
|
|
Loading…
Reference in a new issue