Add latest changes from gitlab-org/gitlab@master

This commit is contained in:
GitLab Bot 2021-03-12 15:09:33 +00:00
parent 26e44c6225
commit 006000e366
45 changed files with 283 additions and 126 deletions

View File

@ -43,6 +43,17 @@ rules:
promise/always-return: off
promise/no-callback-in-promise: off
'@gitlab/no-global-event-off': error
no-param-reassign:
- error
- props: true
ignorePropertyModificationsFor:
- acc
- accumulator
- el
- element
- state
ignorePropertyModificationsForRegex:
- '^draft'
import/order:
- error
- groups:

View File

@ -104,10 +104,8 @@ export default {
const { projects: previousProjects } = previousResult;
return produce(previousResult, (draftData) => {
/* eslint-disable no-param-reassign */
draftData.projects.nodes = [...previousProjects.nodes, ...newProjects.nodes];
draftData.projects.pageInfo = newProjects.pageInfo;
/* eslint-enable no-param-reassign */
});
},
});

View File

@ -27,10 +27,8 @@ const resolvers = {
const sourceData = cache.readQuery({ query: getCurrentIntegrationQuery });
const data = produce(sourceData, (draftData) => {
if (id === null) {
// eslint-disable-next-line no-param-reassign
draftData.currentIntegration = null;
} else {
// eslint-disable-next-line no-param-reassign
draftData.currentIntegration = {
id,
name,

View File

@ -15,7 +15,6 @@ const deleteIntegrationFromStore = (store, query, { httpIntegrationDestroy }, va
});
const data = produce(sourceData, (draftData) => {
// eslint-disable-next-line no-param-reassign
draftData.project.alertManagementIntegrations.nodes = draftData.project.alertManagementIntegrations.nodes.filter(
({ id }) => id !== integration.id,
);
@ -46,7 +45,6 @@ const addIntegrationToStore = (
});
const data = produce(sourceData, (draftData) => {
// eslint-disable-next-line no-param-reassign
draftData.project.alertManagementIntegrations.nodes = [
integration,
...draftData.project.alertManagementIntegrations.nodes,
@ -72,7 +70,6 @@ const addHttpIntegrationToStore = (store, query, { httpIntegrationCreate }, vari
});
const data = produce(sourceData, (draftData) => {
// eslint-disable-next-line no-param-reassign
draftData.project.alertManagementHttpIntegrations.nodes = [
integration,
...draftData.project.alertManagementHttpIntegrations.nodes,

View File

@ -7,7 +7,7 @@ import {
GlIntersectionObserver,
GlLoadingIcon,
} from '@gitlab/ui';
import { mapActions, mapState } from 'vuex';
import { mapActions, mapState, mapGetters } from 'vuex';
import { s__ } from '~/locale';
import { featureAccessLevel } from '~/pages/projects/shared/permissions/constants';
import { ListType } from '../constants';
@ -49,7 +49,8 @@ export default {
};
},
computed: {
...mapState(['groupProjects', 'groupProjectsFlags']),
...mapState(['groupProjectsFlags']),
...mapGetters(['activeGroupProjects']),
selectedProjectName() {
return this.selectedProject.name || this.$options.i18n.dropdownText;
},
@ -65,7 +66,7 @@ export default {
};
},
isFetchResultEmpty() {
return this.groupProjects.length === 0;
return this.activeGroupProjects.length === 0;
},
hasNextPage() {
return this.groupProjectsFlags.pageInfo?.hasNextPage;
@ -84,7 +85,7 @@ export default {
methods: {
...mapActions(['fetchGroupProjects', 'setSelectedProject']),
selectProject(projectId) {
this.selectedProject = this.groupProjects.find((project) => project.id === projectId);
this.selectedProject = this.activeGroupProjects.find((project) => project.id === projectId);
this.setSelectedProject(this.selectedProject);
},
loadMoreProjects() {
@ -113,7 +114,7 @@ export default {
:placeholder="$options.i18n.searchPlaceholder"
/>
<gl-dropdown-item
v-for="project in groupProjects"
v-for="project in activeGroupProjects"
v-show="!groupProjectsFlags.isLoading"
:key="project.id"
:name="project.name"

View File

@ -25,6 +25,7 @@ export default {
with_shared: false,
include_subgroups: true,
order_by: 'similarity',
archived: false,
},
components: {
GlLoadingIcon,

View File

@ -8,6 +8,7 @@ query getGroupProjects($fullPath: ID!, $search: String, $after: String) {
name
fullPath
nameWithNamespace
archived
}
pageInfo {
...PageInfo

View File

@ -29,6 +29,10 @@ export default {
return referencePath.slice(0, referencePath.indexOf('#'));
},
activeGroupProjects: (state) => {
return state.groupProjects.filter((p) => !p.archived);
},
getListByLabelId: (state) => (labelId) => {
if (!labelId) {
return null;

View File

@ -20,7 +20,6 @@ const resolvers = {
const sourceData = cache.readQuery({ query: activeDiscussionQuery });
const data = produce(sourceData, (draftData) => {
// eslint-disable-next-line no-param-reassign
draftData.activeDiscussion = {
__typename: 'ActiveDiscussion',
id,

View File

@ -41,7 +41,6 @@ const addNewVersionToStore = (store, query, version) => {
const sourceData = store.readQuery(query);
const data = produce(sourceData, (draftData) => {
// eslint-disable-next-line no-param-reassign
draftData.project.issue.designCollection.versions.nodes = [
version,
...draftData.project.issue.designCollection.versions.nodes,
@ -168,7 +167,6 @@ const addNewDesignToStore = (store, designManagementUpload, query) => {
nodes: newVersions,
},
};
// eslint-disable-next-line no-param-reassign
draftData.project.issue.designCollection = updatedDesigns;
});
@ -182,7 +180,6 @@ const moveDesignInStore = (store, designManagementMove, query) => {
const sourceData = store.readQuery(query);
const data = produce(sourceData, (draftData) => {
// eslint-disable-next-line no-param-reassign
draftData.project.issue.designCollection.designs =
designManagementMove.designCollection.designs;
});

View File

@ -21,8 +21,7 @@ export const addInProgressImportToStore = (store, jiraImportStart, fullPath) =>
store.writeQuery({
...queryDetails,
data: produce(sourceData, (draftData) => {
draftData.project.jiraImportStatus = IMPORT_STATE.SCHEDULED; // eslint-disable-line no-param-reassign
// eslint-disable-next-line no-param-reassign
draftData.project.jiraImportStatus = IMPORT_STATE.SCHEDULED;
draftData.project.jiraImports.nodes = [
...sourceData.project.jiraImports.nodes,
jiraImportStart.jiraImport,

View File

@ -86,7 +86,6 @@ export default {
const originalMetricQuery = this.graphData.metrics[0];
const metricQuery = produce(originalMetricQuery, (draftQuery) => {
// eslint-disable-next-line no-param-reassign
draftQuery.result[0].values = draftQuery.result[0].values.map(([x, y]) => [
x,
y + this.yOffset,

View File

@ -9,7 +9,6 @@ export const updateGroupPackageSettings = (fullPath) => (client, { data: updated
const sourceData = client.readQuery(queryAndParams);
const data = produce(sourceData, (draftState) => {
// eslint-disable-next-line no-param-reassign
draftState.group.packageSettings = {
...updatedData.updateNamespacePackageSettings.packageSettings,
};

View File

@ -29,7 +29,6 @@ export default {
});
const data = produce(sourceData, (draftState) => {
// eslint-disable-next-line no-param-reassign
draftState.containerRepository.status =
destroyContainerRepository.containerRepository.status;
});

View File

@ -9,7 +9,6 @@ export const updateContainerExpirationPolicy = (projectPath) => (client, { data:
const sourceData = client.readQuery(queryAndParams);
const data = produce(sourceData, (draftState) => {
// eslint-disable-next-line no-param-reassign
draftState.project.containerExpirationPolicy = {
...updatedData.updateContainerExpirationPolicy.containerExpirationPolicy,
};

View File

@ -95,7 +95,6 @@ export default {
});
const data = produce(sourceData, (draftData) => {
// eslint-disable-next-line no-param-reassign
draftData.workspace.issuable.confidential = !this.confidential;
});

View File

@ -87,11 +87,8 @@ export default {
});
const data = produce(sourceData, (draftState) => {
// eslint-disable-next-line no-param-reassign
draftState.project.mergeRequest.mergeableDiscussionsState = mergeableDiscussionsState;
// eslint-disable-next-line no-param-reassign
draftState.project.mergeRequest.workInProgress = workInProgress;
// eslint-disable-next-line no-param-reassign
draftState.project.mergeRequest.title = title;
});

View File

@ -116,7 +116,6 @@ export default {
});
const data = produce(sourceData, (draftData) => {
// eslint-disable-next-line no-param-reassign
draftData.project.alertManagementAlerts.nodes[0].todos.nodes = [];
});

View File

@ -20,7 +20,6 @@ export default (selector) => {
toggleSidebarStatus: (_, __, { cache }) => {
const sourceData = cache.readQuery({ query: sidebarStatusQuery });
const data = produce(sourceData, (draftData) => {
// eslint-disable-next-line no-param-reassign
draftData.sidebarStatus = !draftData.sidebarStatus;
});
cache.writeQuery({ query: sidebarStatusQuery, data });

View File

@ -343,7 +343,7 @@ module InProductMarketingHelper
end
end
def inline_image_link(folder, image, **options)
def inline_image_link(folder, image, options)
attachments.inline[image] = File.read(Rails.root.join("app/assets/images", folder, image))
image_tag attachments[image].url, **options
end

View File

@ -159,8 +159,17 @@ class Wiki
find_page(SIDEBAR, version)
end
def find_file(name, version = 'HEAD')
wiki.file(name, version)
def find_file(name, version = 'HEAD', load_content: true)
if Feature.enabled?(:gitaly_find_file, user, default_enabled: :yaml)
data_limit = load_content ? -1 : 0
blobs = repository.blobs_at([[version, name]], blob_size_limit: data_limit)
return if blobs.empty?
Gitlab::Git::WikiFile.from_blob(blobs.first)
else
wiki.file(name, version)
end
end
def create_page(title, content, format = :markdown, message = nil)

View File

@ -177,8 +177,9 @@
%td{ style: "padding: 10px 20px 30px 20px; font-family: 'Source Sans Pro', helvetica, arial, sans-serif; color:#000000; font-size: 18px; line-height: 24px;" }
%p{ style: "margin: 0 0 20px 0;" }
= in_product_marketing_body_line1(@track, @series, format: :html).html_safe
%p{ style: "margin: 0 0 20px 0;" }
= in_product_marketing_body_line2(@track, @series, format: :html).html_safe
- in_product_marketing_body_line2(@track, @series, format: :html)&.tap do |line|
%p{ style: "margin: 0 0 20px 0;" }
= line.html_safe
%tr
%td{ align: "center", style: "padding: 10px 20px 80px 20px; font-family: 'Source Sans Pro', helvetica, arial, sans-serif;" }
.cta_link= cta_link(@track, @series, @group, format: :html)

View File

@ -0,0 +1,5 @@
---
title: Hide archived projects from group boards project select dropdown
merge_request: 56452
author:
type: changed

View File

@ -0,0 +1,8 @@
---
name: gitaly_find_file
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/56321
rollout_issue_url:
milestone: '13.10'
type: development
group: group::editor
default_enabled: false

View File

@ -1,16 +1,19 @@
---
key_path: signup_enabled
description: Whether public signup is enabled
product_section: growth
product_stage: growth
product_group: group::product intelligence
product_category: collection
product_section: dev
product_stage: manage
product_group: group::access
product_category: authentication_and_authorization
value_type: boolean
status: data_available
time_frame: none
data_source:
data_source: database
distribution:
- ce
- ee
tier:
- free
- premium
- ultimate
skip_validation: true

View File

@ -39,3 +39,30 @@ See [this video](https://youtu.be/-BkEhghP-kM) for an in-depth overview and inve
```
Please note that `toMatchObject` actually changes the nature of the assertion and won't fail if some items are **missing** from the expectation.
### Script issues
## `core-js` errors when running scripts within the GitLab repository
The following command assumes you've set up the GitLab repository in the
`~/workspace/gdk` directory. When running scripts within the GitLab repository,
such as code transformations, you might run into issues with `core-js` like this:
```shell
~/workspace/gdk/gitlab/node_modules/core-js/modules/es.global-this.js:7
$({
^
TypeError: $ is not a function
at Object.<anonymous> (~/workspace/gdk/gitlab/node_modules/core-js/modules/es.global-this.js:6:1)
at Module._compile (internal/modules/cjs/loader.js:1063:30)
at Module._compile (~/workspace/gdk/gitlab/node_modules/pirates/lib/index.js:99:24)
at Module._extensions..js (internal/modules/cjs/loader.js:1092:10)
at Object.newLoader [as .js] (~/workspace/gdk/gitlab/node_modules/pirates/lib/index.js:104:7)
at Module.load (internal/modules/cjs/loader.js:928:32)
at Function.Module._load (internal/modules/cjs/loader.js:769:14)
at Module.require (internal/modules/cjs/loader.js:952:19)
at require (internal/modules/cjs/helpers.js:88:18)
at Object.<anonymous> (~/workspace/gdk/gitlab/node_modules/core-js/modules/esnext.global-this.js:2:1)
```
**Remedy - Try moving the script into a separate repository and point to it to files in the GitLab repository**

View File

@ -289,7 +289,7 @@ For example, to add support for files referenced by a `Widget` model with a
t.binary :verification_checksum
t.binary :verification_checksum_mismatched
t.string :verification_failure, limit: 255
t.text :last_sync_failure
t.string :last_sync_failure, limit: 255
t.index :widget_id, name: :index_widget_registry_on_widget_id, unique: true
t.index :retry_at
@ -303,8 +303,6 @@ For example, to add support for files referenced by a `Widget` model with a
end
end
end
add_text_limit :widget_registry, :last_sync_failure, 255
end
def down
@ -940,7 +938,7 @@ For example, to add support for files referenced by a `Gizmos` model with a
t.bigint :gizmo_id, null: false
t.integer :state, default: 0, null: false, limit: 2
t.integer :retry_count, default: 0, limit: 2
t.text :last_sync_failure
t.string :last_sync_failure, limit: 255
t.boolean :force_to_redownload
t.boolean :missing_on_primary
@ -948,8 +946,6 @@ For example, to add support for files referenced by a `Gizmos` model with a
t.index :retry_at
t.index :state
end
add_text_limit :gizmo_registry, :last_sync_failure, 255
end
def down

View File

@ -13610,11 +13610,11 @@ Whether public signup is enabled
[YAML definition](https://gitlab.com/gitlab-org/gitlab/-/blob/master/config/metrics/settings/20210204124918_signup_enabled.yml)
Group: `group::product intelligence`
Group: `group::access`
Status: `data_available`
Tiers: `free`
Tiers: `free`, `premium`, `ultimate`
### `topology.duration_s`

View File

@ -100,7 +100,7 @@ module Banzai
if url?(content)
path = content
elsif file = wiki.find_file(content)
elsif file = wiki.find_file(content, load_content: false)
path = ::File.join(wiki_base_path, file.path)
end

View File

@ -12,6 +12,19 @@ module Gitlab
@name = gitaly_file.name
@path = gitaly_file.path
end
def self.from_blob(blob)
hash = {
name: File.basename(blob.name),
mime_type: blob.mime_type,
path: blob.path,
raw_data: blob.data
}
gitaly_file = Gitlab::GitalyClient::WikiFile.new(hash)
Gitlab::Git::WikiFile.new(gitaly_file)
end
end
end
end

View File

@ -25,10 +25,10 @@ module Gitlab
end
def event(category, action, label: nil, property: nil, value: nil, context: [], project: nil, user: nil, namespace: nil) # rubocop:disable Metrics/ParameterLists
context += [Tracking::StandardContext.new(project: project, user: user, namespace: namespace).to_context]
contexts = [Tracking::StandardContext.new(project: project, user: user, namespace: namespace).to_context, *context]
snowplow.event(category, action, label: label, property: property, value: value, context: context)
product_analytics.event(category, action, label: label, property: property, value: value, context: context)
snowplow.event(category, action, label: label, property: property, value: value, context: contexts)
product_analytics.event(category, action, label: label, property: property, value: value, context: contexts)
end
def self_describing_event(schema_url, data:, context: nil)

View File

@ -56,9 +56,9 @@
"@babel/preset-env": "^7.10.1",
"@gitlab/at.js": "1.5.7",
"@gitlab/favicon-overlay": "2.0.0",
"@gitlab/svgs": "1.184.0",
"@gitlab/svgs": "1.185.0",
"@gitlab/tributejs": "1.0.0",
"@gitlab/ui": "28.6.0",
"@gitlab/ui": "28.9.1",
"@gitlab/visual-review-tools": "1.6.1",
"@rails/actioncable": "^6.0.3-4",
"@rails/ujs": "^6.0.3-4",

View File

@ -56,7 +56,7 @@ RSpec.describe 'GitLab Markdown Benchmark', :aggregate_failures do
it 'benchmarks several pipelines' do
path = 'images/example.jpg'
gitaly_wiki_file = Gitlab::GitalyClient::WikiFile.new(path: path)
allow(wiki).to receive(:find_file).with(path).and_return(Gitlab::Git::WikiFile.new(gitaly_wiki_file))
allow(wiki).to receive(:find_file).with(path, load_content: false).and_return(Gitlab::Git::WikiFile.new(gitaly_wiki_file))
allow(wiki).to receive(:wiki_base_path) { '/namespace1/gitlabhq/wikis' }
puts "\n--> Benchmarking Full, Wiki, and Plain pipelines\n"

View File

@ -290,7 +290,7 @@ RSpec.describe 'GitLab Markdown', :aggregate_failures do
path = 'images/example.jpg'
gitaly_wiki_file = Gitlab::GitalyClient::WikiFile.new(path: path)
expect(@wiki).to receive(:find_file).with(path).and_return(Gitlab::Git::WikiFile.new(gitaly_wiki_file))
expect(@wiki).to receive(:find_file).with(path, load_content: false).and_return(Gitlab::Git::WikiFile.new(gitaly_wiki_file))
allow(@wiki).to receive(:wiki_base_path) { '/namespace1/gitlabhq/wikis' }
@html = markdown(@feat.raw_markdown, { pipeline: :wiki, wiki: @wiki, page_slug: @wiki_page.slug })

View File

@ -351,6 +351,7 @@ export const issues = {
[mockIssue4.id]: mockIssue4,
};
// The response from group project REST API
export const mockRawGroupProjects = [
{
id: 0,
@ -366,17 +367,34 @@ export const mockRawGroupProjects = [
},
];
export const mockGroupProjects = [
{
id: 0,
name: 'Example Project',
nameWithNamespace: 'Awesome Group / Example Project',
fullPath: 'awesome-group/example-project',
},
{
id: 1,
name: 'Foobar Project',
nameWithNamespace: 'Awesome Group / Foobar Project',
fullPath: 'awesome-group/foobar-project',
},
// The response from GraphQL endpoint
export const mockGroupProject1 = {
id: 0,
name: 'Example Project',
nameWithNamespace: 'Awesome Group / Example Project',
fullPath: 'awesome-group/example-project',
archived: false,
};
export const mockGroupProject2 = {
id: 1,
name: 'Foobar Project',
nameWithNamespace: 'Awesome Group / Foobar Project',
fullPath: 'awesome-group/foobar-project',
archived: false,
};
export const mockArchivedGroupProject = {
id: 2,
name: 'Archived Project',
nameWithNamespace: 'Awesome Group / Archived Project',
fullPath: 'awesome-group/archived-project',
archived: true,
};
export const mockGroupProjects = [mockGroupProject1, mockGroupProject2];
export const mockActiveGroupProjects = [
{ ...mockGroupProject1, archived: false },
{ ...mockGroupProject2, archived: false },
];

View File

@ -27,6 +27,7 @@ const mockDefaultFetchOptions = {
with_shared: false,
include_subgroups: true,
order_by: 'similarity',
archived: false,
};
const itemsPerPage = 20;

View File

@ -1,30 +1,17 @@
import { GlDropdown, GlDropdownItem, GlSearchBoxByType, GlLoadingIcon } from '@gitlab/ui';
import { createLocalVue, mount } from '@vue/test-utils';
import { mount } from '@vue/test-utils';
import Vue from 'vue';
import Vuex from 'vuex';
import ProjectSelect from '~/boards/components/project_select.vue';
import defaultState from '~/boards/stores/state';
import { mockList, mockGroupProjects } from './mock_data';
import { mockList, mockActiveGroupProjects } from './mock_data';
const localVue = createLocalVue();
localVue.use(Vuex);
const actions = {
fetchGroupProjects: jest.fn(),
setSelectedProject: jest.fn(),
};
const createStore = (state = defaultState) => {
return new Vuex.Store({
state,
actions,
});
};
const mockProjectsList1 = mockGroupProjects.slice(0, 1);
const mockProjectsList1 = mockActiveGroupProjects.slice(0, 1);
describe('ProjectSelect component', () => {
let wrapper;
let store;
const findLabel = () => wrapper.find("[data-testid='header-label']");
const findGlDropdown = () => wrapper.find(GlDropdown);
@ -36,20 +23,37 @@ describe('ProjectSelect component', () => {
const findInMenuLoadingIcon = () => wrapper.find("[data-testid='dropdown-text-loading-icon']");
const findEmptySearchMessage = () => wrapper.find("[data-testid='empty-result-message']");
const createWrapper = (state = {}) => {
const store = createStore({
groupProjects: [],
groupProjectsFlags: {
isLoading: false,
pageInfo: {
hasNextPage: false,
const createStore = ({ state, activeGroupProjects }) => {
Vue.use(Vuex);
store = new Vuex.Store({
state: {
defaultState,
groupProjectsFlags: {
isLoading: false,
pageInfo: {
hasNextPage: false,
},
},
...state,
},
...state,
actions: {
fetchGroupProjects: jest.fn(),
setSelectedProject: jest.fn(),
},
getters: {
activeGroupProjects: () => activeGroupProjects,
},
});
};
const createWrapper = ({ state = {}, activeGroupProjects = [] } = {}) => {
createStore({
state,
activeGroupProjects,
});
wrapper = mount(ProjectSelect, {
localVue,
propsData: {
list: mockList,
},
@ -93,7 +97,7 @@ describe('ProjectSelect component', () => {
describe('when dropdown menu is open', () => {
describe('by default', () => {
beforeEach(() => {
createWrapper({ groupProjects: mockGroupProjects });
createWrapper({ activeGroupProjects: mockActiveGroupProjects });
});
it('shows GlSearchBoxByType with default attributes', () => {
@ -128,7 +132,7 @@ describe('ProjectSelect component', () => {
describe('when a project is selected', () => {
beforeEach(() => {
createWrapper({ groupProjects: mockProjectsList1 });
createWrapper({ activeGroupProjects: mockProjectsList1 });
findFirstGlDropdownItem().find('button').trigger('click');
});
@ -142,7 +146,7 @@ describe('ProjectSelect component', () => {
describe('when projects are loading', () => {
beforeEach(() => {
createWrapper({ groupProjectsFlags: { isLoading: true } });
createWrapper({ state: { groupProjectsFlags: { isLoading: true } } });
});
it('displays and hides gl-loading-icon while and after fetching data', () => {

View File

@ -7,6 +7,8 @@ import {
mockIssuesByListId,
issues,
mockLists,
mockGroupProject1,
mockArchivedGroupProject,
} from '../mock_data';
describe('Boards - Getters', () => {
@ -165,4 +167,14 @@ describe('Boards - Getters', () => {
expect(getters.getListByTitle(boardsState)('To Do')).toEqual(mockLists[1]);
});
});
describe('activeGroupProjects', () => {
const state = {
groupProjects: [mockGroupProject1, mockArchivedGroupProject],
};
it('returns only returns non-archived group projects', () => {
expect(getters.activeGroupProjects(state)).toEqual([mockGroupProject1]);
});
});
});

View File

@ -22,7 +22,7 @@ RSpec.describe Banzai::Filter::GollumTagsFilter do
path: 'images/image.jpg',
raw_data: '')
wiki_file = Gitlab::Git::WikiFile.new(gollum_file_double)
expect(wiki).to receive(:find_file).with('images/image.jpg').and_return(wiki_file)
expect(wiki).to receive(:find_file).with('images/image.jpg', load_content: false).and_return(wiki_file)
tag = '[[images/image.jpg]]'
doc = filter("See #{tag}", wiki: wiki)
@ -31,7 +31,7 @@ RSpec.describe Banzai::Filter::GollumTagsFilter do
end
it 'does not creates img tag if image does not exist' do
expect(wiki).to receive(:find_file).with('images/image.jpg').and_return(nil)
expect(wiki).to receive(:find_file).with('images/image.jpg', load_content: false).and_return(nil)
tag = '[[images/image.jpg]]'
doc = filter("See #{tag}", wiki: wiki)

View File

@ -61,8 +61,8 @@ RSpec.describe Gitlab::Tracking do
expect(args[:property]).to eq('property')
expect(args[:value]).to eq(1.5)
expect(args[:context].length).to eq(2)
expect(args[:context].first).to eq(other_context)
expect(args[:context].last.to_json[:schema]).to eq(Gitlab::Tracking::StandardContext::GITLAB_STANDARD_SCHEMA_URL)
expect(args[:context].first.to_json[:schema]).to eq(Gitlab::Tracking::StandardContext::GITLAB_STANDARD_SCHEMA_URL)
expect(args[:context].last).to eq(other_context)
end
described_class.event('category', 'action', label: 'label', property: 'property', value: 1.5,

View File

@ -0,0 +1,44 @@
# frozen_string_literal: true
require 'spec_helper'
require 'email_spec'
RSpec.describe Emails::InProductMarketing do
include EmailSpec::Matchers
include InProductMarketingHelper
let_it_be(:user) { create(:user) }
let_it_be(:group) { create(:group) }
describe '#in_product_marketing_email' do
using RSpec::Parameterized::TableSyntax
where(:track, :series) do
:create | 0
:create | 1
:create | 2
:verify | 0
:verify | 1
:verify | 2
:trial | 0
:trial | 1
:trial | 2
:team | 0
:team | 1
:team | 2
end
with_them do
subject { Notify.in_product_marketing_email(user.id, group.id, track, series) }
it 'has the correct subject and content' do
aggregate_failures do
is_expected.to have_subject(subject_line(track, series))
is_expected.to have_body_text(in_product_marketing_title(track, series))
is_expected.to have_body_text(in_product_marketing_subtitle(track, series))
is_expected.to have_body_text(in_product_marketing_cta_text(track, series))
end
end
end
end
end

View File

@ -354,27 +354,47 @@ RSpec.shared_examples 'wiki model' do
subject.repository.create_file(user, 'image.png', image, branch_name: subject.default_branch, message: 'add image')
end
it 'returns the latest version of the file if it exists' do
file = subject.find_file('image.png')
shared_examples 'find_file results' do
it 'returns the latest version of the file if it exists' do
file = subject.find_file('image.png')
expect(file.mime_type).to eq('image/png')
expect(file.mime_type).to eq('image/png')
end
it 'returns nil if the page does not exist' do
expect(subject.find_file('non-existent')).to eq(nil)
end
it 'returns a Gitlab::Git::WikiFile instance' do
file = subject.find_file('image.png')
expect(file).to be_a Gitlab::Git::WikiFile
end
it 'returns the whole file' do
file = subject.find_file('image.png')
image.rewind
expect(file.raw_data.b).to eq(image.read.b)
end
end
it 'returns nil if the page does not exist' do
expect(subject.find_file('non-existent')).to eq(nil)
it_behaves_like 'find_file results'
context 'when load_content is disabled' do
it 'includes the file data in the Gitlab::Git::WikiFile' do
file = subject.find_file('image.png', load_content: false)
expect(file.raw_data).to be_empty
end
end
it 'returns a Gitlab::Git::WikiFile instance' do
file = subject.find_file('image.png')
context 'when feature flag :gitaly_find_file is disabled' do
before do
stub_feature_flags(gitaly_find_file: false)
end
expect(file).to be_a Gitlab::Git::WikiFile
end
it 'returns the whole file' do
file = subject.find_file('image.png')
image.rewind
expect(file.raw_data.b).to eq(image.read.b)
it_behaves_like 'find_file results'
end
end

View File

@ -236,7 +236,7 @@ RSpec.describe Tooling::Danger::ProjectHelper do
subject { project_helper.all_ee_changes }
it 'returns all changed files starting with ee/' do
expect(project_helper).to receive(:all_changed_files).and_return(%w[fr/ee/beer.rb ee/wine.rb ee/lib/ido.rb ee.k])
expect(fake_helper).to receive(:all_changed_files).and_return(%w[fr/ee/beer.rb ee/wine.rb ee/lib/ido.rb ee.k])
is_expected.to match_array(%w[ee/wine.rb ee/lib/ido.rb])
end

View File

@ -149,7 +149,7 @@ module Tooling
end
def all_ee_changes
all_changed_files.grep(%r{\Aee/})
helper.all_changed_files.grep(%r{\Aee/})
end
def project_name

View File

@ -897,20 +897,20 @@
stylelint-declaration-strict-value "1.7.7"
stylelint-scss "3.18.0"
"@gitlab/svgs@1.184.0":
version "1.184.0"
resolved "https://registry.yarnpkg.com/@gitlab/svgs/-/svgs-1.184.0.tgz#7fe90309999b987362eb1649aa91df24748d3df1"
integrity sha512-K8r5jhnjWR4347j2ADFek7yLgs+MDGqm9cjvwT04aa1vSfhvheLqyKGUy1yz8v7RzXC0Mev6+RT1AbK7m6Ay+w==
"@gitlab/svgs@1.185.0":
version "1.185.0"
resolved "https://registry.yarnpkg.com/@gitlab/svgs/-/svgs-1.185.0.tgz#15b5c6d680b5fcfc2deb2a5decef427939e34ed7"
integrity sha512-1XIyOm8MyTZi8H0v9WVnqVDziTLH8Q5H/fKfBj+nzprHNYvJj2fvz+EV9N5luF90KTzlQf1QYCbHWe2zKLZuUw==
"@gitlab/tributejs@1.0.0":
version "1.0.0"
resolved "https://registry.yarnpkg.com/@gitlab/tributejs/-/tributejs-1.0.0.tgz#672befa222aeffc83e7d799b0500a7a4418e59b8"
integrity sha512-nmKw1+hB6MHvlmPz63yPwVs1qQkycHwsKgxpEbzmky16Y6mL4EJMk3w1b8QlOAF/AIAzjCERPhe/R4MJiohbZw==
"@gitlab/ui@28.6.0":
version "28.6.0"
resolved "https://registry.yarnpkg.com/@gitlab/ui/-/ui-28.6.0.tgz#dae21f072cbf898bfa87dcefbef951c2811ecba0"
integrity sha512-6LvPoQbSzbY9kmP3y84eQj48w6XzgLktSBX0NM2IB3/sZzEtFlpLpnqmv6cWhS2V1HAM7xW6nLZ4SGyM3JRhvA==
"@gitlab/ui@28.9.1":
version "28.9.1"
resolved "https://registry.yarnpkg.com/@gitlab/ui/-/ui-28.9.1.tgz#7d4d4502ff09fca19ab815504f80afbf03dd2fc1"
integrity sha512-+JqkpwzkKBnxo4KkC8XSPEJ5Au9y+TIOE7w9I5o+04krgWCbZKNqaiKZkg2IqSlo/sZSfvihXZMhEVc/JXf7HQ==
dependencies:
"@babel/standalone" "^7.0.0"
"@gitlab/vue-toasted" "^1.3.0"