Skip to content
Snippets Groups Projects
Commit 50ae4065 authored by GitLab Bot's avatar GitLab Bot
Browse files

Add latest changes from gitlab-org/gitlab@master

parent be37a0ee
No related branches found
No related tags found
No related merge requests found
Showing with 463 additions and 11 deletions
Loading
Loading
@@ -15,8 +15,7 @@ to be marked as `Accepting Merge Requests`. Please include screenshots or
wireframes of the proposed feature if it will also change the UI.
 
Merge requests should be submitted to the appropriate project at GitLab.com, for example
[GitLab CE](https://gitlab.com/gitlab-org/gitlab-foss/merge_requests),
[GitLab EE](https://gitlab.com/gitlab-org/gitlab/merge_requests),
[GitLab](https://gitlab.com/gitlab-org/gitlab/merge_requests),
[GitLab Runner](https://gitlab.com/gitlab-org/gitlab-runner/merge_requests),
[GitLab Omnibus](https://gitlab.com/gitlab-org/omnibus-gitlab/merge_requests), etc.
 
Loading
Loading
@@ -227,6 +226,7 @@ requirements.
1. [Changelog entry added](../changelog.md), if necessary.
1. Reviewed by relevant (UX/FE/BE/tech writing) reviewers and all concerns are addressed.
1. Merged by a project maintainer.
1. Create an issue in the [infrastructure issue tracker](https://gitlab.com/gitlab-com/gl-infra/infrastructure/issues) to inform the Infrastructure department when your contribution is changing default settings or introduces a new setting, if relevant.
1. Confirmed to be working in the [Canary stage](https://about.gitlab.com/handbook/engineering/#canary-testing) or on GitLab.com once the contribution is deployed.
1. Added to the [release post](https://about.gitlab.com/handbook/marketing/blog/release-posts/),
if relevant.
Loading
Loading
Loading
Loading
@@ -771,6 +771,9 @@ nicely on different mobile devices.
To make things easier for the user, always add a full code block for things that can be
useful to copy and paste, as they can easily do it with the button on code blocks.
- Add a blank line above and below code blocks.
- When providing a shell command and its output, prefix the shell command with `$` and
leave a blank line between the command and the output.
- When providing a command without output, don't prefix the shell command with `$`.
- For regular code blocks, always use a highlighting class corresponding to the
language for better readability. Examples:
 
Loading
Loading
@@ -795,7 +798,8 @@ nicely on different mobile devices.
- To display raw Markdown instead of rendered Markdown, you can use triple backticks
with `md`, like the `Markdown code` example above, unless you want to include triple
backticks in the code block as well. In that case, use triple tildes (`~~~`) instead.
- [Syntax highlighting for code blocks](https://github.com/rouge-ruby/rouge/wiki/List-of-supported-languages-and-lexers) is available for many languages.
- [Syntax highlighting for code blocks](https://github.com/rouge-ruby/rouge/wiki/List-of-supported-languages-and-lexers)
is available for many languages. Use `shell` instead of `bash` or `sh` for shell output.
- For a complete reference on code blocks, check the [Kramdown guide](https://about.gitlab.com/handbook/product/technical-writing/markdown-guide/#code-blocks).
 
## GitLab SVG icons
Loading
Loading
Loading
Loading
@@ -54,6 +54,17 @@ By default, this seeds an average of 10 issues per week for the last 52 weeks
per project. All issues will also be randomly labeled with team, type, severity,
and priority.
 
#### Seeding groups with sub-groups
You can seed groups with sub-groups that contain milestones/projects/issues
with the `gitlab:seed:group_seed` task:
```shell
bin/rake "gitlab:seed:group_seed[subgroup_depth, username]"
```
Group are additionally seeded with epics if GitLab instance has epics feature available.
### Automation
 
If you're very sure that you want to **wipe the current database** and refill
Loading
Loading
Loading
Loading
@@ -132,6 +132,10 @@ module API
expose(:jobs_enabled) { |project, options| project.feature_available?(:builds, options[:current_user]) }
expose(:snippets_enabled) { |project, options| project.feature_available?(:snippets, options[:current_user]) }
 
expose(:can_create_merge_request_in) do |project, options|
Ability.allowed?(options[:current_user], :create_merge_request_in, project)
end
expose(:issues_access_level) { |project, options| project.project_feature.string_access_level(:issues) }
expose(:repository_access_level) { |project, options| project.project_feature.string_access_level(:repository) }
expose(:merge_requests_access_level) { |project, options| project.project_feature.string_access_level(:merge_requests) }
Loading
Loading
# frozen_string_literal: true
# Seed test groups with:
# 1. 2 Subgroups per level
# 1. 2 Users & group members per group
# 1. 2 Epics, 2 Milestones & 2 Projects per group
# 1. Project issues
#
# It also assigns each project's issue with one of group's or ascendants
# groups milestone & epic.
#
# @param subgroups_depth - number of subgroup levels
# @param username - user creating subgroups (i.e. GitLab admin)
#
# @example
# bundle exec rake "gitlab:seed:group_seed[5, root]"
#
namespace :gitlab do
namespace :seed do
desc 'Seed groups with sub-groups/projects/epics/milestones for Group Import testing'
task :group_seed, [:subgroups_depth, :username] => :gitlab_environment do |_t, args|
require 'sidekiq/testing'
GroupSeeder.new(
subgroups_depth: args.subgroups_depth,
username: args.username
).seed
end
end
end
class GroupSeeder
PROJECT_URL = 'https://gitlab.com/gitlab-org/gitlab-test.git'
attr_reader :all_group_ids
def initialize(subgroups_depth:, username:)
@subgroups_depth = subgroups_depth.to_i
@user = User.find_by_username(username)
@group_names = Set.new
@resource_count = 2
@all_groups = {}
@all_group_ids = []
end
def seed
create_groups
puts 'Done!'
end
def create_groups
create_root_group
create_sub_groups
create_users_and_members
create_epics if Gitlab.ee?
create_labels
create_milestones
Sidekiq::Testing.inline! do
create_projects
end
end
def create_users_and_members
all_group_ids.each do |group_id|
@resource_count.times do |_|
user = create_user
create_member(user.id, group_id)
end
end
end
def create_root_group
root_group = ::Groups::CreateService.new(@user, group_params).execute
track_group_id(1, root_group.id)
end
def create_sub_groups
(2..@subgroups_depth).each do |level|
parent_level = level - 1
current_level = level
parent_groups = @all_groups[parent_level]
parent_groups.each do |parent_id|
@resource_count.times do |_|
sub_group = ::Groups::CreateService.new(@user, group_params(parent_id: parent_id)).execute
track_group_id(current_level, sub_group.id)
end
end
end
end
def track_group_id(depth_level, group_id)
@all_groups[depth_level] ||= []
@all_groups[depth_level] << group_id
@all_group_ids << group_id
end
def group_params(parent_id: nil)
name = unique_name
{
name: name,
path: name,
parent_id: parent_id
}
end
def unique_name
name = ffaker_name
name = ffaker_name until @group_names.add?(name)
name
end
def ffaker_name
FFaker::Lorem.characters(5)
end
def create_user
User.create!(
username: FFaker::Internet.user_name,
name: FFaker::Name.name,
email: FFaker::Internet.email,
confirmed_at: DateTime.now,
password: Devise.friendly_token
)
end
def create_member(user_id, group_id)
roles = Gitlab::Access.values
GroupMember.create(user_id: user_id, access_level: roles.sample, source_id: group_id)
end
def create_epics
all_group_ids.each do |group_id|
@resource_count.times do |_|
group = Group.find(group_id)
epic_params = {
title: FFaker::Lorem.sentence(6),
description: FFaker::Lorem.paragraphs(3).join("\n\n"),
author: group.users.sample,
group: group
}
Epic.create!(epic_params)
end
end
end
def create_labels
all_group_ids.each do |group_id|
@resource_count.times do |_|
group = Group.find(group_id)
label_title = FFaker::Product.brand
Labels::CreateService.new(title: label_title, color: "##{Digest::MD5.hexdigest(label_title)[0..5]}").execute(group: group)
end
end
end
def create_milestones
all_group_ids.each do |group_id|
@resource_count.times do |i|
group = Group.find(group_id)
milestone_params = {
title: "v#{i}.0",
description: FFaker::Lorem.sentence,
state: [:active, :closed].sample
}
Milestones::CreateService.new(group, group.members.sample, milestone_params).execute
end
end
end
def create_projects
all_group_ids.each do |group_id|
group = Group.find(group_id)
@resource_count.times do |i|
_, project_path = PROJECT_URL.split('/')[-2..-1]
project_path.gsub!('.git', '')
params = {
import_url: PROJECT_URL,
namespace_id: group.id,
name: project_path.titleize + FFaker::Lorem.characters(10),
description: FFaker::Lorem.sentence,
visibility_level: 0,
skip_disk_validation: true
}
project = nil
Sidekiq::Worker.skipping_transaction_check do
project = ::Projects::CreateService.new(@user, params).execute
project.send(:_run_after_commit_queue)
project.import_state.send(:_run_after_commit_queue)
project.repository.expire_all_method_caches
end
create_project_issues(project)
assign_issues_to_epics_and_milestones(project)
end
end
end
def create_project_issues(project)
seeder = Quality::Seeders::Issues.new(project: project)
seeder.seed(backfill_weeks: 2, average_issues_per_week: 2)
end
def assign_issues_to_epics_and_milestones(project)
group_ids = project.group.self_and_ancestors.map(&:id)
project.issues.each do |issue|
issue_params = {
milestone: Milestone.where(group: group_ids).sample
}
issue_params[:epic] = Epic.where(group: group_ids).sample if Gitlab.ee?
issue.update(issue_params)
end
end
end
Loading
Loading
@@ -6035,6 +6035,9 @@ msgstr ""
msgid "Default project deletion protection"
msgstr ""
 
msgid "Default projects limit"
msgstr ""
msgid "Default: Directly import the Google Code email address or username"
msgstr ""
 
Loading
Loading
@@ -10470,6 +10473,9 @@ msgstr ""
msgid "Is blocked by"
msgstr ""
 
msgid "Is this GitLab trial for your company?"
msgstr ""
msgid "Is using license seat:"
msgstr ""
 
Loading
Loading
@@ -11628,6 +11634,9 @@ msgstr ""
msgid "Maximum delay (Minutes)"
msgstr ""
 
msgid "Maximum duration of a session."
msgstr ""
msgid "Maximum job timeout"
msgstr ""
 
Loading
Loading
@@ -11646,12 +11655,24 @@ msgstr ""
msgid "Maximum number of mirrors that can be synchronizing at the same time."
msgstr ""
 
msgid "Maximum number of projects."
msgstr ""
msgid "Maximum page reached"
msgstr ""
 
msgid "Maximum push size (MB)"
msgstr ""
 
msgid "Maximum size limit for a single commit."
msgstr ""
msgid "Maximum size limit for each repository."
msgstr ""
msgid "Maximum size of individual attachments in comments."
msgstr ""
msgid "Maximum time between updates that a mirror can have when scheduled to synchronize."
msgstr ""
 
Loading
Loading
@@ -17024,9 +17045,6 @@ msgstr ""
msgid "Session duration (minutes)"
msgstr ""
 
msgid "Session expiration, projects limit and attachment size."
msgstr ""
msgid "Set %{epic_ref} as the parent epic."
msgstr ""
 
Loading
Loading
@@ -17066,6 +17084,9 @@ msgstr ""
msgid "Set parent epic to an epic"
msgstr ""
 
msgid "Set projects and maximum size limits, session duration, user options, and check feature availability for namespace plan."
msgstr ""
msgid "Set requirements for a user to sign-in. Enable mandatory two-factor authentication."
msgstr ""
 
Loading
Loading
Loading
Loading
@@ -83,15 +83,15 @@ describe 'User updates wiki page' do
end
 
it 'updates the commit message as the title is changed', :js do
fill_in(:wiki_title, with: 'Wiki title')
fill_in(:wiki_title, with: '& < > \ \ { } &')
 
expect(page).to have_field('wiki[message]', with: 'Update Wiki title')
expect(page).to have_field('wiki[message]', with: 'Update & < > \ \ { } &')
end
 
it 'does not allow XSS', :js do
fill_in(:wiki_title, with: '<script>')
it 'correctly escapes the commit message entities', :js do
fill_in(:wiki_title, with: 'Wiki title')
 
expect(page).to have_field('wiki[message]', with: 'Update &lt;script&gt;')
expect(page).to have_field('wiki[message]', with: 'Update Wiki title')
end
 
it 'shows a validation error message' do
Loading
Loading
Loading
Loading
@@ -129,6 +129,18 @@ describe 'User views a wiki page' do
end
end
 
context 'when a page has XSS in its message' do
before do
wiki_page.update(message: '<script>alert(true)<script>', content: 'XSS update')
end
it 'safely displays the message' do
visit(project_wiki_history_path(project, wiki_page))
expect(page).to have_content('<script>alert(true)<script>')
end
end
context 'when page has invalid content encoding' do
let(:content) { (+'whatever').force_encoding('ISO-8859-1') }
 
Loading
Loading
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`Dashboard template matches the default snapshot 1`] = `
<div
class="prometheus-graphs"
data-qa-selector="prometheus_graphs"
>
<div
class="prometheus-graphs-header gl-p-3 pb-0 border-bottom bg-gray-light"
>
<div
class="row"
>
<gl-form-group-stub
class="col-sm-12 col-md-6 col-lg-2"
label="Dashboard"
label-for="monitor-dashboards-dropdown"
label-size="sm"
>
<dashboards-dropdown-stub
class="mb-0 d-flex"
defaultbranch="master"
id="monitor-dashboards-dropdown"
selecteddashboard="[object Object]"
toggle-class="dropdown-menu-toggle"
/>
</gl-form-group-stub>
<gl-form-group-stub
class="col-sm-6 col-md-6 col-lg-2"
label="Environment"
label-for="monitor-environments-dropdown"
label-size="sm"
>
<gl-dropdown-stub
class="mb-0 d-flex"
data-qa-selector="environments_dropdown"
id="monitor-environments-dropdown"
menu-class="monitor-environment-dropdown-menu"
text="production"
toggle-class="dropdown-menu-toggle"
>
<div
class="d-flex flex-column overflow-hidden"
>
<gl-dropdown-header-stub
class="text-center"
>
Environment
</gl-dropdown-header-stub>
<gl-dropdown-divider-stub />
<!---->
<div
class="flex-fill overflow-auto"
/>
<!---->
</div>
</gl-dropdown-stub>
</gl-form-group-stub>
<gl-form-group-stub
class="col-sm-6 col-md-6 col-lg-4"
label="Show last"
label-for="monitor-time-window-dropdown"
label-size="sm"
>
<date-time-picker-stub
end="2020-01-01T18:57:47.000Z"
start="2020-01-01T18:27:47.000Z"
timewindows="[object Object]"
/>
</gl-form-group-stub>
<!---->
</div>
</div>
<empty-state-stub
clusterspath="/path/to/clusters"
documentationpath="/path/to/docs"
emptygettingstartedsvgpath="/path/to/getting-started.svg"
emptyloadingsvgpath="/path/to/loading.svg"
emptynodatasmallsvgpath="/path/to/no-data-small.svg"
emptynodatasvgpath="/path/to/no-data.svg"
emptyunabletoconnectsvgpath="/path/to/unable-to-connect.svg"
selectedstate="gettingStarted"
settingspath="/path/to/settings"
/>
</div>
`;
import { shallowMount } from '@vue/test-utils';
import MockAdapter from 'axios-mock-adapter';
import axios from '~/lib/utils/axios_utils';
import Dashboard from '~/monitoring/components/dashboard.vue';
import { createStore } from '~/monitoring/stores';
import { propsData } from '../init_utils';
jest.mock('~/lib/utils/url_utility', () => ({
getParameterValues: jest.fn().mockImplementation(param => {
if (param === 'start') return ['2020-01-01T18:27:47.000Z'];
if (param === 'end') return ['2020-01-01T18:57:47.000Z'];
return [];
}),
}));
describe('Dashboard template', () => {
let wrapper;
let store;
let mock;
beforeEach(() => {
store = createStore();
mock = new MockAdapter(axios);
});
afterEach(() => {
if (wrapper) {
wrapper.destroy();
wrapper = null;
}
mock.restore();
});
it('matches the default snapshot', () => {
wrapper = shallowMount(Dashboard, {
propsData: { ...propsData },
methods: {
fetchData: jest.fn(),
},
store,
});
expect(wrapper.element).toMatchSnapshot();
});
});
Loading
Loading
@@ -1340,6 +1340,7 @@ describe API::Projects do
expect(json_response['path']).to be_present
expect(json_response['issues_enabled']).to be_present
expect(json_response['merge_requests_enabled']).to be_present
expect(json_response['can_create_merge_request_in']).to be_present
expect(json_response['wiki_enabled']).to be_present
expect(json_response['jobs_enabled']).to be_present
expect(json_response['snippets_enabled']).to be_present
Loading
Loading
@@ -1390,6 +1391,7 @@ describe API::Projects do
expect(json_response['path']).to be_present
expect(json_response['issues_enabled']).to be_present
expect(json_response['merge_requests_enabled']).to be_present
expect(json_response['can_create_merge_request_in']).to be_present
expect(json_response['wiki_enabled']).to be_present
expect(json_response['jobs_enabled']).to be_present
expect(json_response['snippets_enabled']).to be_present
Loading
Loading
# frozen_string_literal: true
require 'rake_helper'
describe 'gitlab:seed:group_seed rake task', :sidekiq do
let(:username) { 'group_seed' }
let!(:user) { create(:user, username: username) }
let(:task_params) { [2, username] }
before do
Rake.application.rake_require('tasks/gitlab/seed/group_seed')
end
subject { run_rake_task('gitlab:seed:group_seed', task_params) }
it 'performs group seed successfully' do
expect { subject }.not_to raise_error
group = user.groups.first
expect(user.groups.count).to be 3
expect(group.projects.count).to be 2
expect(group.members.count).to be 3
expect(group.milestones.count).to be 2
end
end
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment