Add latest changes from gitlab-org/gitlab@master

This commit is contained in:
GitLab Bot 2020-09-23 15:10:14 +00:00
parent a071c2888d
commit e0b023e388
57 changed files with 581 additions and 172 deletions

View File

@ -19,7 +19,7 @@
- node --version
- run_timed_command "retry yarn install --frozen-lockfile"
- free -m
- run_timed_command "bin/rake gitlab:assets:compile > assets-compile.log 2>&1"
- run_timed_command "bin/rake gitlab:assets:compile"
- run_timed_command "scripts/clean-old-cached-assets"
compile-production-assets:
@ -34,7 +34,6 @@ compile-production-assets:
name: webpack-report
expire_in: 31d
paths:
- assets-compile.log
# These assets are used in multiple locations:
# - in `build-assets-image` job to create assets image for packaging systems
# - GitLab UI for integration tests: https://gitlab.com/gitlab-org/gitlab-ui/-/blob/e88493b3c855aea30bf60baee692a64606b0eb1e/.storybook/preview-head.pug#L1
@ -51,7 +50,6 @@ compile-test-assets:
artifacts:
expire_in: 7d
paths:
- assets-compile.log
- public/assets/
- node_modules/@gitlab/svgs/dist/icons.json # app/helpers/icons_helper.rb uses this file
when: always

View File

@ -949,9 +949,6 @@ Rails/SaveBang:
- 'spec/lib/gitlab/email/handler/create_note_handler_spec.rb'
- 'spec/lib/gitlab/email/handler/unsubscribe_handler_spec.rb'
- 'spec/lib/gitlab/gfm/reference_rewriter_spec.rb'
- 'spec/lib/gitlab/git/object_pool_spec.rb'
- 'spec/lib/gitlab/git/remote_mirror_spec.rb'
- 'spec/lib/gitlab/git/repository_spec.rb'
- 'spec/lib/gitlab/git_access_spec.rb'
- 'spec/lib/gitlab/gitaly_client/object_pool_service_spec.rb'
- 'spec/lib/gitlab/gitaly_client/repository_service_spec.rb'

View File

@ -284,7 +284,6 @@ gem 'fast_blank'
gem 'gitlab-chronic', '~> 0.10.5'
gem 'gitlab_chronic_duration', '~> 0.10.6.2'
gem 'webpack-rails', '~> 0.9.10'
gem 'rack-proxy', '~> 0.6.0'
gem 'sassc-rails', '~> 2.1.0'

View File

@ -1218,8 +1218,6 @@ GEM
addressable (>= 2.3.6)
crack (>= 0.3.2)
hashdiff
webpack-rails (0.9.11)
railties (>= 3.2.0)
websocket-driver (0.7.1)
websocket-extensions (>= 0.1.0)
websocket-extensions (0.1.5)
@ -1499,7 +1497,6 @@ DEPENDENCIES
vmstat (~> 2.3.0)
webauthn (~> 2.3)
webmock (~> 3.5.1)
webpack-rails (~> 0.9.10)
wikicloth (= 0.8.1)
yajl-ruby (~> 1.4.1)

View File

@ -201,7 +201,13 @@ export default {
<section v-else>
<ancestor-notice />
<gl-table :items="clusters" :fields="fields" stacked="md" class="qa-clusters-table">
<gl-table
:items="clusters"
:fields="fields"
stacked="md"
class="qa-clusters-table"
data-testid="cluster_list_table"
>
<template #cell(name)="{ item }">
<div :class="[contentAlignClasses, 'js-status']">
<img

View File

@ -474,7 +474,7 @@ export default {
<div
v-if="showTreeList"
:style="{ width: `${treeWidth}px` }"
class="diff-tree-list js-diff-tree-list mr-3"
class="diff-tree-list js-diff-tree-list px-3 pr-md-0"
>
<panel-resizer
:size.sync="treeWidth"
@ -487,7 +487,7 @@ export default {
<tree-list :hide-file-stats="hideFileStats" />
</div>
<div
class="diff-files-holder"
class="col-12 col-md-auto diff-files-holder"
:class="{
[CENTERED_LIMITED_CONTAINER_CLASSES]: isLimitedContainer,
}"

View File

@ -50,7 +50,7 @@ export default {
</script>
<template>
<div v-if="!isDismissed" data-testid="root" :class="containerClasses">
<div v-if="!isDismissed" data-testid="root" :class="containerClasses" class="col-12">
<gl-alert
:dismissible="true"
:title="__('Some changes are not shown')"

View File

@ -1,8 +1,12 @@
<script>
import { GlIcon } from '@gitlab/ui';
import { n__ } from '../../locale';
import { MAX_CHILDREN_COUNT } from '../constants';
export default {
components: {
GlIcon,
},
props: {
parentGroup: {
type: Object,
@ -45,7 +49,7 @@ export default {
/>
<li v-if="hasMoreChildren" class="group-row">
<a :href="parentGroup.relativePath" class="group-row-contents has-more-items py-2">
<i class="fa fa-external-link" aria-hidden="true"> </i> {{ moreChildrenStats }}
<gl-icon name="external-link" aria-hidden="true" /> {{ moreChildrenStats }}
</a>
</li>
</ul>

View File

@ -1,14 +1,8 @@
import $ from 'jquery';
import MiniPipelineGraph from '~/mini_pipeline_graph_dropdown';
import { initCommitBoxInfo } from '~/projects/commit_box/info';
import initPipelines from '~/commit/pipelines/pipelines_bundle';
import { fetchCommitMergeRequests } from '~/commit_merge_requests';
document.addEventListener('DOMContentLoaded', () => {
new MiniPipelineGraph({
container: '.js-commit-pipeline-graph',
}).bindEvents();
// eslint-disable-next-line no-jquery/no-load
$('.commit-info.branches').load(document.querySelector('.js-commit-box').dataset.commitPath);
fetchCommitMergeRequests();
initCommitBoxInfo();
initPipelines();
});

View File

@ -4,10 +4,8 @@ import $ from 'jquery';
import Diff from '~/diff';
import ZenMode from '~/zen_mode';
import ShortcutsNavigation from '~/behaviors/shortcuts/shortcuts_navigation';
import MiniPipelineGraph from '~/mini_pipeline_graph_dropdown';
import initNotes from '~/init_notes';
import initChangesDropdown from '~/init_changes_dropdown';
import { fetchCommitMergeRequests } from '~/commit_merge_requests';
import '~/sourcegraph/load';
import { handleLocationHash } from '~/lib/utils/common_utils';
import axios from '~/lib/utils/axios_utils';
@ -15,6 +13,7 @@ import syntaxHighlight from '~/syntax_highlight';
import flash from '~/flash';
import { __ } from '~/locale';
import loadAwardsHandler from '~/awards_handler';
import { initCommitBoxInfo } from '~/projects/commit_box/info';
document.addEventListener('DOMContentLoaded', () => {
const hasPerfBar = document.querySelector('.with-performance-bar');
@ -22,13 +21,10 @@ document.addEventListener('DOMContentLoaded', () => {
initChangesDropdown(document.querySelector('.navbar-gitlab').offsetHeight + performanceHeight);
new ZenMode();
new ShortcutsNavigation();
new MiniPipelineGraph({
container: '.js-commit-pipeline-graph',
}).bindEvents();
initCommitBoxInfo();
initNotes();
// eslint-disable-next-line no-jquery/no-load
$('.commit-info.branches').load(document.querySelector('.js-commit-box').dataset.commitPath);
fetchCommitMergeRequests();
const filesContainer = $('.js-diffs-batch');

View File

@ -1,5 +1,6 @@
import $ from 'jquery';
import axios from '~/lib/utils/axios_utils';
import { Rails } from '~/lib/utils/rails_ujs';
import { deprecatedCreateFlash as flash } from '../flash';
import { parseBoolean } from '~/lib/utils/common_utils';
import TimezoneDropdown, {
@ -48,9 +49,13 @@ export default class Profile {
}
submitForm() {
return $(this)
.parents('form')
.submit();
const $form = $(this).parents('form');
if ($form.data('remote')) {
Rails.fire($form[0], 'submit');
} else {
$form.submit();
}
}
onSubmitForm(e) {

View File

@ -0,0 +1,18 @@
import { loadBranches } from './load_branches';
import { fetchCommitMergeRequests } from '~/commit_merge_requests';
import MiniPipelineGraph from '~/mini_pipeline_graph_dropdown';
export const initCommitBoxInfo = (containerSelector = '.js-commit-box-info') => {
const containerEl = document.querySelector(containerSelector);
// Display commit related branches
loadBranches(containerEl);
// Related merge requests to this commit
fetchCommitMergeRequests();
// Display pipeline info for this commit
new MiniPipelineGraph({
container: '.js-commit-pipeline-graph',
}).bindEvents();
};

View File

@ -0,0 +1,20 @@
import axios from 'axios';
import { sanitize } from '~/lib/dompurify';
import { __ } from '~/locale';
export const loadBranches = containerEl => {
if (!containerEl) {
return;
}
const { commitPath } = containerEl.dataset;
const branchesEl = containerEl.querySelector('.commit-info.branches');
axios
.get(commitPath)
.then(({ data }) => {
branchesEl.innerHTML = sanitize(data);
})
.catch(() => {
branchesEl.textContent = __('Failed to load branches. Please try again.');
});
};

View File

@ -1,6 +1,6 @@
<script>
import $ from 'jquery';
import { GlLoadingIcon } from '@gitlab/ui';
import { GlButton } from '@gitlab/ui';
import { mapActions } from 'vuex';
import { __ } from '~/locale';
import { deprecatedCreateFlash as Flash } from '~/flash';
@ -8,7 +8,7 @@ import eventHub from '../../event_hub';
export default {
components: {
GlLoadingIcon,
GlButton,
},
props: {
fullPath: {
@ -64,18 +64,18 @@ export default {
<template>
<div class="sidebar-item-warning-message-actions">
<button type="button" class="btn btn-default gl-mr-3" @click="closeForm">
<gl-button class="gl-mr-3" @click="closeForm">
{{ __('Cancel') }}
</button>
<button
type="button"
class="btn btn-close"
data-testid="confidential-toggle"
</gl-button>
<gl-button
category="secondary"
variant="warning"
:disabled="isLoading"
:loading="isLoading"
data-testid="confidential-toggle"
@click.prevent="submitForm"
>
<gl-loading-icon v-if="isLoading" inline />
{{ toggleButtonText }}
</button>
</gl-button>
</div>
</template>

View File

@ -1,12 +1,9 @@
<script>
/* eslint-disable vue/no-v-html */
import { isEmpty } from 'lodash';
import { GlIcon, GlButton, GlSprintf, GlLink } from '@gitlab/ui';
import successSvg from 'icons/_icon_status_success.svg';
import warningSvg from 'icons/_icon_status_warning.svg';
import readyToMergeMixin from 'ee_else_ce/vue_merge_request_widget/mixins/ready_to_merge';
import simplePoll from '~/lib/utils/simple_poll';
import { __, sprintf } from '~/locale';
import { __ } from '~/locale';
import MergeRequest from '../../../merge_request';
import { refreshUserMergeRequestCounts } from '~/commons/nav/user_merge_requests';
import { deprecatedCreateFlash as Flash } from '../../../flash';
@ -59,8 +56,6 @@ export default {
commitMessage: this.mr.commitMessage,
squashBeforeMerge: this.mr.squashIsSelected,
isSquashReadOnly: this.mr.squashIsReadonly,
successSvg,
warningSvg,
squashCommitMessage: this.mr.squashCommitMessage,
};
},
@ -147,16 +142,7 @@ export default {
return !this.mr.ffOnlyEnabled;
},
shaMismatchLink() {
const href = this.mr.mergeRequestDiffsPath;
return sprintf(
__('New changes were added. %{linkStart}Reload the page to review them%{linkEnd}'),
{
linkStart: `<a href="${href}">`,
linkEnd: '</a>',
},
false,
);
return this.mr.mergeRequestDiffsPath;
},
},
methods: {
@ -331,7 +317,7 @@ export default {
@click.prevent="handleMergeButtonClick(true)"
>
<span class="media">
<span class="merge-opt-icon" aria-hidden="true" v-html="successSvg"></span>
<gl-icon name="status_success" class="merge-opt-icon" aria-hidden="true" />
<span class="media-body merge-opt-title">{{ autoMergeText }}</span>
</span>
</a>
@ -349,7 +335,7 @@ export default {
@click.prevent="handleMergeImmediatelyButtonClick"
>
<span class="media">
<span class="merge-opt-icon" aria-hidden="true" v-html="warningSvg"></span>
<gl-icon name="status_warning" class="merge-opt-icon" aria-hidden="true" />
<span class="media-body merge-opt-title">{{ __('Merge immediately') }}</span>
</span>
</a>
@ -400,7 +386,17 @@ export default {
</div>
<div v-if="mr.isSHAMismatch" class="d-flex align-items-center mt-2 js-sha-mismatch">
<gl-icon name="warning-solid" class="text-warning mr-1" />
<span class="text-warning" v-html="shaMismatchLink"></span>
<span class="text-warning">
<gl-sprintf
:message="
__('New changes were added. %{linkStart}Reload the page to review them%{linkEnd}')
"
>
<template #link="{ content }">
<gl-link :href="mr.mergeRequestDiffsPath">{{ content }}</gl-link>
</template>
</gl-sprintf>
</span>
</div>
</div>
</div>

View File

@ -257,6 +257,38 @@
content: '\f127';
}
.fa-file-pdf-o::before {
content: '\f1c1';
}
.fa-file-word-o::before {
content: '\f1c2';
}
.fa-file-excel-o::before {
content: '\f1c3';
}
.fa-file-powerpoint-o::before {
content: '\f1c4';
}
.fa-file-image-o::before {
content: '\f1c5';
}
.fa-file-archive-o::before {
content: '\f1c6';
}
.fa-file-audio-o::before {
content: '\f1c7';
}
.fa-file-video-o::before {
content: '\f1c8';
}
.sr-only {
position: absolute;
width: 1px;

View File

@ -127,9 +127,4 @@
@include gl-w-full;
}
}
// TODO: Abstract to `@gitlab/ui` utility set: https://gitlab.com/gitlab-org/gitlab-ui/-/issues/921
.gl-fill-green-500 {
fill: $green-500;
}
}

View File

@ -770,8 +770,6 @@ $mr-widget-min-height: 69px;
position: -webkit-sticky;
position: sticky;
top: $header-height + $mr-tabs-height;
margin-left: -16px;
width: calc(100% + 32px);
.mr-version-menus-container {
flex-wrap: nowrap;
@ -868,6 +866,13 @@ $mr-widget-min-height: 69px;
}
}
.container-fluid {
// Negative margins for mobile/tablet screen
.diffs.tab-pane {
margin: 0 (-$gl-padding);
}
}
// Wrap MR tabs/buttons so you don't have to scroll on desktop
@include media-breakpoint-down(md) {
.merge-request-tabs-container,

View File

@ -5,20 +5,11 @@ module Projects
class PackagesController < Projects::ApplicationController
include PackagesAccess
before_action :authorize_destroy_package!, only: [:destroy]
def show
@package = project.packages.find(params[:id])
@package_files = @package.package_files.recent
@maven_metadatum = @package.maven_metadatum
end
def destroy
@package = project.packages.find(params[:id])
@package.destroy
redirect_to project_packages_path(@project), status: :found, notice: _('Package was removed')
end
end
end
end

View File

@ -51,7 +51,7 @@ module PackagesHelper
{
resource_id: resource.id,
page_type: type,
empty_list_help_url: help_page_path('administration/packages/index'),
empty_list_help_url: help_page_path('user/packages/package_registry/index'),
empty_list_illustration: image_path('illustrations/no-packages.svg'),
coming_soon_json: packages_coming_soon_data(resource).to_json
}

View File

@ -5,7 +5,13 @@ class AuditEvent < ApplicationRecord
include IgnorableColumns
include BulkInsertSafe
PARALLEL_PERSISTENCE_COLUMNS = [:author_name, :entity_path, :target_details, :target_type].freeze
PARALLEL_PERSISTENCE_COLUMNS = [
:author_name,
:entity_path,
:target_details,
:target_type,
:target_id
].freeze
ignore_column :type, remove_with: '13.6', remove_after: '2020-11-22'

View File

@ -12,7 +12,7 @@
= s_('ClusterIntegration|Kubernetes clusters can be used to deploy applications and to provide Review Apps for this project')
= render 'clusters/clusters/buttons'
- if Feature.enabled?(:clusters_list_redesign)
- if Feature.enabled?(:clusters_list_redesign, default_enabled: true)
#js-clusters-list-app{ data: js_clusters_list_data(clusterable.index_path(format: :json)) }
- else
- if @has_ancestor_clusters
@ -20,7 +20,7 @@
= s_('ClusterIntegration|Clusters are utilized by selecting the nearest ancestor with a matching environment scope. For example, project clusters will override group clusters.')
%strong
= link_to _('More information'), help_page_path('user/group/clusters/index', anchor: 'cluster-precedence')
.clusters-table.js-clusters-list
.clusters-table.js-clusters-list{ data: { testid: 'cluster_list_table' } }
.gl-responsive-table-row.table-row-header{ role: "row" }
.table-section.section-60{ role: "rowheader" }
= s_("ClusterIntegration|Kubernetes cluster")

View File

@ -1,6 +1,6 @@
- can_collaborate = can_collaborate_with_project?(@project)
.page-content-header.js-commit-box{ 'data-commit-path' => branches_project_commit_path(@project, @commit.id) }
.page-content-header
.header-main-content
= render partial: 'signature', object: @commit.signature
%strong
@ -58,7 +58,7 @@
%pre.commit-description<
= preserve(markdown_field(@commit, :description))
.info-well
.info-well.js-commit-box-info{ 'data-commit-path' => branches_project_commit_path(@project, @commit.id) }
.well-segment.branch-info
.icon-container.commit-icon
= custom_icon("icon_commit")

View File

@ -10,9 +10,9 @@
= form_for [@project, @hook], as: :hook, url: project_hook_path(@project, @hook) do |f|
= render partial: 'shared/web_hooks/form', locals: { form: f, hook: @hook }
%span>= f.submit 'Save changes', class: 'btn btn-success gl-mr-3'
= f.submit 'Save changes', class: 'btn gl-button btn-success gl-mr-3'
= render 'shared/web_hooks/test_button', hook: @hook
= link_to _('Delete'), project_hook_path(@project, @hook), method: :delete, class: 'btn btn-remove float-right', data: { confirm: _('Are you sure?') }
= link_to _('Delete'), project_hook_path(@project, @hook), method: :delete, class: 'btn gl-button btn-danger float-right', data: { confirm: _('Are you sure?') }
%hr

View File

@ -0,0 +1,5 @@
---
title: Display cluster list node information
merge_request: 42396
author:
type: added

View File

@ -0,0 +1,5 @@
---
title: Update confidential form buttons to gl-button
merge_request: 40893
author:
type: changed

View File

@ -0,0 +1,5 @@
---
title: Eliminate extra spacing on MR diffs from mobile/tablet screen
merge_request: 42821
author: Takuya Noguchi
type: fixed

View File

@ -0,0 +1,5 @@
---
title: Add missing fontawesome file icon classes
merge_request: 43091
author:
type: added

View File

@ -0,0 +1,5 @@
---
title: Empty state Packages UI links to user docs
merge_request: 43009
author:
type: fixed

View File

@ -0,0 +1,5 @@
---
title: Drop column instance_statistics_visibility_private
merge_request: 42969
author:
type: deprecated

View File

@ -0,0 +1,5 @@
---
title: Replace fa-external-link with GitLab SVG in group folder
merge_request: 43128
author:
type: changed

View File

@ -0,0 +1,5 @@
---
title: Fixes Rails/SaveBang cop for spec files in spec/lib/gitlab/git/*
merge_request: 43013
author: Rajendra Kadam
type: other

View File

@ -152,12 +152,18 @@ module Gitlab
config.active_record.schema_format = :sql
# Configure webpack
config.webpack = ActiveSupport::OrderedOptions.new
config.webpack.config_file = "config/webpack.config.js"
config.webpack.output_dir = "public/assets/webpack"
config.webpack.public_path = "assets/webpack"
config.webpack.manifest_filename = "manifest.json"
# Webpack dev server configuration is handled in initializers/static_files.rb
config.webpack.dev_server = ActiveSupport::OrderedOptions.new
config.webpack.dev_server.enabled = false
config.webpack.dev_server.host = 'localhost'
config.webpack.dev_server.port = 3808
config.webpack.dev_server.https = false
config.action_mailer.delivery_job = "ActionMailer::MailDeliveryJob"

View File

@ -1,7 +1,7 @@
---
name: clusters_list_redesign
introduced_by_url:
rollout_issue_url:
group:
introduced_by_url:
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/220182
group: Configure
type: development
default_enabled: false
default_enabled: true

View File

@ -21,9 +21,7 @@ if app.config.public_file_server.enabled
settings = {
enabled: true,
host: dev_server.host,
port: dev_server.port,
manifest_host: dev_server.host,
manifest_port: dev_server.port
port: dev_server.port
}
if Rails.env.development?

View File

@ -0,0 +1,13 @@
# frozen_string_literal: true
class RemoveInstanceStatisticsVisibilityPrivateFromApplicationSettings < ActiveRecord::Migration[6.0]
DOWNTIME = false
def up
remove_column :application_settings, :instance_statistics_visibility_private
end
def down
add_column :application_settings, :instance_statistics_visibility_private, :boolean, default: false, null: false
end
end

View File

@ -0,0 +1 @@
c55f27f817afc60462e5dc43755a4ddd76f1399f5e461bab4b36bf5e5b26ce0a

View File

@ -9146,7 +9146,6 @@ CREATE TABLE application_settings (
snowplow_enabled boolean DEFAULT false NOT NULL,
snowplow_collector_hostname character varying,
snowplow_cookie_domain character varying,
instance_statistics_visibility_private boolean DEFAULT false NOT NULL,
web_ide_clientside_preview_enabled boolean DEFAULT false NOT NULL,
user_show_add_ssh_key_message boolean DEFAULT true NOT NULL,
custom_project_templates_group_id integer,

View File

@ -588,6 +588,52 @@ Refer to the documentation for your SAML Identity Provider for information on ho
The [Generated passwords for users created through integrated authentication](../security/passwords_for_integrated_authentication_methods.md) guide provides an overview of how GitLab generates and sets passwords for users created via SAML.
## Configuring Group SAML on a self-managed GitLab instance **(PREMIUM ONLY)**
For information on the GitLab.com implementation, please see the [SAML SSO for GitLab.com groups page](../user/group/saml_sso).
Group SAML SSO helps if you need to allow access via multiple SAML identity providers, but as a multi-tenant solution is less suited to cases where you administer your own GitLab instance.
To proceed with configuring Group SAML SSO instead, you'll need to enable the `group_saml` OmniAuth provider. This can be done from:
- `gitlab.rb` for [Omnibus GitLab installations](#omnibus-installations).
- `gitlab/config/gitlab.yml` for [source installations](#source-installations).
### Limitations
Group SAML on a self-managed instance is limited when compared to the recommended
[instance-wide SAML](../user/group/saml_sso/index.md). The recommended solution allows you to take advantage of:
- [LDAP compatibility](../administration/auth/ldap/index.md).
- [LDAP Group Sync](../user/group/index.md#manage-group-memberships-via-ldap).
- [Required groups](#required-groups).
- [Admin groups](#admin-groups).
- [Auditor groups](#auditor-groups).
### Omnibus installations
1. Make sure GitLab is
[configured with HTTPS](../install/installation.md#using-https).
1. Enable OmniAuth and the `group_saml` provider in `gitlab.rb`:
```ruby
gitlab_rails['omniauth_enabled'] = true
gitlab_rails['omniauth_providers'] = [{ name: 'group_saml' }]
```
### Source installations
1. Make sure GitLab is
[configured with HTTPS](../install/installation.md#using-https).
1. Enable OmniAuth and the `group_saml` provider in `gitlab/config/gitlab.yml`:
```yaml
omniauth:
enabled: true
providers:
- { name: 'group_saml' }
```
## Troubleshooting
You can find the base64-encoded SAML Response in the [`production_json.log`](../administration/logs.md#production_jsonlog).

View File

@ -14,6 +14,9 @@ Similar to [project-level](../../project/clusters/index.md) and
group-level Kubernetes clusters allow you to connect a Kubernetes cluster to
your group, enabling you to use the same cluster across multiple projects.
To view your group level Kubernetes clusters, navigate to your project and select
**Kubernetes** from the left-hand menu.
## Installing applications
GitLab can install and manage some applications in your group-level

View File

@ -5,7 +5,7 @@ group: Access
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#designated-technical-writers
---
# SAML SSO for GitLab.com groups **(PREMIUM)**
# SAML SSO for GitLab.com groups **(SILVER ONLY)**
> Introduced in GitLab 11.0.
@ -256,53 +256,6 @@ For example, to unlink the `MyOrg` account, the following **Disconnect** button
| Issuer | How GitLab identifies itself to the identity provider. Also known as a "Relying party trust identifier". |
| Certificate fingerprint | Used to confirm that communications over SAML are secure by checking that the server is signing communications with the correct certificate. Also known as a certificate thumbprint. |
## Configuring on a self-managed GitLab instance **(PREMIUM ONLY)**
For self-managed GitLab instances we strongly recommend using the
[instance-wide SAML OmniAuth Provider](../../../integration/saml.md) instead.
Group SAML SSO helps if you need to allow access via multiple SAML identity providers, but as a multi-tenant solution is less suited to cases where you administer your own GitLab instance.
To proceed with configuring Group SAML SSO instead, you'll need to enable the `group_saml` OmniAuth provider. This can be done from:
- `gitlab.rb` for [Omnibus GitLab installations](#omnibus-installations).
- `gitlab/config/gitlab.yml` for [source installations](#source-installations).
### Limitations
Group SAML on a self-managed instance is limited when compared to the recommended
[instance-wide SAML](../../../integration/saml.md). The recommended solution allows you to take advantage of:
- [LDAP compatibility](../../../administration/auth/ldap/index.md).
- [LDAP Group Sync](../index.md#manage-group-memberships-via-ldap).
- [Required groups](../../../integration/saml.md#required-groups).
- [Admin groups](../../../integration/saml.md#admin-groups).
- [Auditor groups](../../../integration/saml.md#auditor-groups).
### Omnibus installations
1. Make sure GitLab is
[configured with HTTPS](../../../install/installation.md#using-https).
1. Enable OmniAuth and the `group_saml` provider in `gitlab.rb`:
```ruby
gitlab_rails['omniauth_enabled'] = true
gitlab_rails['omniauth_providers'] = [{ name: 'group_saml' }]
```
### Source installations
1. Make sure GitLab is
[configured with HTTPS](../../../install/installation.md#using-https).
1. Enable OmniAuth and the `group_saml` provider in `gitlab/config/gitlab.yml`:
```yaml
omniauth:
enabled: true
providers:
- { name: 'group_saml' }
```
## Passwords for users created via SAML SSO for Groups
The [Generated passwords for users created through integrated authentication](../../../security/passwords_for_integrated_authentication_methods.md) guide provides an overview of how GitLab generates and sets passwords for users created via SAML SSO for Groups.

View File

@ -10,6 +10,8 @@ instance-level Kubernetes clusters allow you to connect a Kubernetes cluster to
the GitLab instance, which enables you to use the same cluster across multiple
projects.
The instance level Kubernetes clusters can be found in the top menu by navigating to your instance's **{admin}** **Admin Area > Kubernetes**.
## Cluster precedence
GitLab will try to match clusters in the following order:

View File

@ -31,6 +31,11 @@ Besides integration at the project level, Kubernetes clusters can also be
integrated at the [group level](../../group/clusters/index.md) or
[GitLab instance level](../../instance/clusters/index.md).
To view your project level Kubernetes clusters, navigate to **Operations > Kubernetes**
from your project. On this page, you can [add a new cluster](#adding-and-removing-clusters)
and view information about your existing clusters, such as nodes count and rough estimates
of memory and CPU usage.
## Setting up
### Supported cluster versions

View File

@ -1,16 +1,31 @@
# frozen_string_literal: true
require 'webpack/rails/manifest'
require 'net/http'
require 'uri'
module Gitlab
module Webpack
class Manifest < ::Webpack::Rails::Manifest
# Raised if a supplied asset does not exist in the webpack manifest
class Manifest
# Raised if we can't read our webpack manifest for whatever reason
class ManifestLoadError < StandardError
def initialize(message, orig)
super "#{message} (original error #{orig})"
end
end
# Raised if webpack couldn't build one of your entry points
class WebpackError < StandardError
def initialize(errors)
super "Error in webpack compile, details follow below:\n#{errors.join("\n\n")}"
end
end
# Raised if a supplied entry point does not exist in the webpack manifest
AssetMissingError = Class.new(StandardError)
class << self
def entrypoint_paths(source)
raise ::Webpack::Rails::Manifest::WebpackError, manifest["errors"] unless manifest_bundled?
raise WebpackError, manifest["errors"] unless manifest_bundled?
dll_assets = manifest.fetch("dllAssets", [])
entrypoint = manifest["entrypoints"][source]
@ -20,10 +35,79 @@ module Gitlab
[dll_assets, entrypoint["assets"]].flatten.reject { |p| p =~ /.*\.map$/ }.map do |p|
"/#{::Rails.configuration.webpack.public_path}/#{p}"
end
else
raise AssetMissingError, "Can't find asset '#{source}' in webpack manifest"
end
end
def asset_paths(source)
raise WebpackError, manifest["errors"] unless manifest_bundled?
paths = manifest["assetsByChunkName"][source]
if paths
# Can be either a string or an array of strings.
# Do not include source maps as they are not javascript
[paths].flatten.reject { |p| p =~ /.*\.map$/ }.map do |p|
"/#{::Rails.configuration.webpack.public_path}/#{p}"
end
else
raise AssetMissingError, "Can't find entry point '#{source}' in webpack manifest"
end
end
private
def manifest_bundled?
!manifest["errors"].any? { |error| error.include? "Module build failed" }
end
def manifest
if ::Rails.configuration.webpack.dev_server.enabled
# Don't cache if we're in dev server mode, manifest may change ...
load_manifest
else
# ... otherwise cache at class level, as JSON loading/parsing can be expensive
@manifest ||= load_manifest
end
end
def load_manifest
data = if ::Rails.configuration.webpack.dev_server.enabled
load_dev_server_manifest
else
load_static_manifest
end
Gitlab::Json.parse(data)
end
def load_dev_server_manifest
host = ::Rails.configuration.webpack.dev_server.host
port = ::Rails.configuration.webpack.dev_server.port
http = Net::HTTP.new(host, port)
http.use_ssl = ::Rails.configuration.webpack.dev_server.https
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
http.get(dev_server_path).body
rescue => e
raise ManifestLoadError.new("Could not load manifest from webpack-dev-server at http://#{host}:#{port}#{dev_server_path} - is it running, and is stats-webpack-plugin loaded?", e)
end
def load_static_manifest
File.read(static_manifest_path)
rescue => e
raise ManifestLoadError.new("Could not load compiled manifest from #{static_manifest_path} - have you run `rake webpack:compile`?", e)
end
def static_manifest_path
::Rails.root.join(
::Rails.configuration.webpack.output_dir,
::Rails.configuration.webpack.manifest_filename
)
end
def dev_server_path
"/#{::Rails.configuration.webpack.public_path}/#{::Rails.configuration.webpack.manifest_filename}"
end
end
end
end

View File

@ -81,7 +81,7 @@ namespace :gitlab do
if head_assets_md5 != master_assets_md5 || !public_assets_webpack_dir_exists
FileUtils.rm_r(Tasks::Gitlab::Assets::PUBLIC_ASSETS_WEBPACK_DIR) if public_assets_webpack_dir_exists
Rake::Task['webpack:compile'].invoke
system('yarn webpack')
end
end

View File

@ -17999,9 +17999,6 @@ msgstr ""
msgid "Package type must be PyPi"
msgstr ""
msgid "Package was removed"
msgstr ""
msgid "PackageRegistry|%{name} version %{version} was created %{datetime}"
msgstr ""

View File

@ -39,7 +39,7 @@ RSpec.describe 'Issues > User sees live update', :js do
expect(page).to have_css('.sidebar-item-warning-message')
within('.sidebar-item-warning-message') do
find('.btn-close').click
find('[data-testid="confidential-toggle"]').click
end
wait_for_requests

View File

@ -11,7 +11,36 @@ RSpec.describe 'Clusters', :js do
before do
project.add_maintainer(user)
gitlab_sign_in(user)
stub_feature_flags(clusters_list_redesign: false)
end
context 'when clusters_list_redesign feature flag is disabled' do
before do
stub_feature_flags(clusters_list_redesign: false)
end
context 'when user does not have a cluster and visits cluster index page' do
before do
visit project_clusters_path(project)
end
it 'sees empty state' do
expect(page).to have_link('Add Kubernetes cluster')
expect(page).to have_selector('.empty-state')
end
end
context 'when user has a cluster and visits cluster index page' do
let!(:cluster) { create(:cluster, :project, :provided_by_gcp) }
let(:project) { cluster.project }
before do
visit project_clusters_path(project)
end
it 'user sees a table with one cluster' do
expect(page).to have_selector('[data-testid="cluster_list_table"] .card-body', count: 1)
end
end
end
context 'when user does not have a cluster and visits cluster index page' do
@ -196,8 +225,7 @@ RSpec.describe 'Clusters', :js do
end
it 'user sees a table with one cluster' do
# One is the header row, the other the cluster row
expect(page).to have_selector('.gl-responsive-table-row', count: 2)
expect(page).to have_selector('[data-testid="cluster_list_table"] tbody tr', count: 1)
end
context 'when user clicks on a cluster' do

View File

@ -50,7 +50,7 @@ describe('CollapsedFilesWarning', () => {
({ limited, containerClasses }) => {
createComponent({ limited });
expect(wrapper.classes()).toEqual(containerClasses);
expect(wrapper.classes()).toEqual(['col-12'].concat(containerClasses));
},
);

View File

@ -0,0 +1,68 @@
import axios from 'axios';
import waitForPromises from 'helpers/wait_for_promises';
import MockAdapter from 'axios-mock-adapter';
import { loadBranches } from '~/projects/commit_box/info/load_branches';
const mockCommitPath = '/commit/abcd/branches';
const mockBranchesRes =
'<a href="/-/commits/master">master</a><span><a href="/-/commits/my-branch">my-branch</a></span>';
describe('~/projects/commit_box/info/load_branches', () => {
let mock;
let el;
beforeEach(() => {
mock = new MockAdapter(axios);
mock.onGet(mockCommitPath).reply(200, mockBranchesRes);
el = document.createElement('div');
el.dataset.commitPath = mockCommitPath;
el.innerHTML = '<div class="commit-info branches"><span class="spinner"/></div>';
});
it('loads and renders branches info', async () => {
loadBranches(el);
await waitForPromises();
expect(el.innerHTML).toBe(`<div class="commit-info branches">${mockBranchesRes}</div>`);
});
it('does not load when no container is provided', async () => {
loadBranches(null);
await waitForPromises();
expect(mock.history.get).toHaveLength(0);
});
describe('when braches request returns unsafe content', () => {
beforeEach(() => {
mock
.onGet(mockCommitPath)
.reply(200, '<a onload="alert(\'xss!\');" href="/-/commits/master">master</a>');
});
it('displays sanitized html', async () => {
loadBranches(el);
await waitForPromises();
expect(el.innerHTML).toBe(
'<div class="commit-info branches"><a href="/-/commits/master">master</a></div>',
);
});
});
describe('when braches request fails', () => {
beforeEach(() => {
mock.onGet(mockCommitPath).reply(500, 'Error!');
});
it('attempts to load and renders an error', async () => {
loadBranches(el);
await waitForPromises();
expect(el.innerHTML).toBe(
'<div class="commit-info branches">Failed to load branches. Please try again.</div>',
);
});
});
});

View File

@ -1,5 +1,4 @@
import { shallowMount } from '@vue/test-utils';
import { GlLoadingIcon } from '@gitlab/ui';
import waitForPromises from 'helpers/wait_for_promises';
import EditFormButtons from '~/sidebar/components/confidential/edit_form_buttons.vue';
import eventHub from '~/sidebar/event_hub';
@ -56,11 +55,11 @@ describe('Edit Form Buttons', () => {
});
it('disables the toggle button', () => {
expect(findConfidentialToggle().attributes('disabled')).toBe('disabled');
expect(findConfidentialToggle().props('disabled')).toBe(true);
});
it('finds the GlLoadingIcon', () => {
expect(wrapper.find(GlLoadingIcon).exists()).toBe(true);
it('sets loading on the toggle button', () => {
expect(findConfidentialToggle().props('loading')).toBe(true);
});
});
@ -99,7 +98,7 @@ describe('Edit Form Buttons', () => {
describe('when succeeds', () => {
beforeEach(() => {
createComponent({ data: { isLoading: false }, props: { confidential: true } });
findConfidentialToggle().trigger('click');
findConfidentialToggle().vm.$emit('click', new Event('click'));
});
it('dispatches the correct action', () => {
@ -109,9 +108,9 @@ describe('Edit Form Buttons', () => {
});
});
it('resets loading', () => {
it('resets loading on the toggle button', () => {
return waitForPromises().then(() => {
expect(wrapper.find(GlLoadingIcon).exists()).toBe(false);
expect(findConfidentialToggle().props('loading')).toBe(false);
});
});
@ -135,7 +134,7 @@ describe('Edit Form Buttons', () => {
props: { confidential: true },
resolved: false,
});
findConfidentialToggle().trigger('click');
findConfidentialToggle().vm.$emit('click', new Event('click'));
});
it('calls flash with the correct message', () => {

View File

@ -101,8 +101,6 @@ describe('ReadyToMerge', () => {
expect(vm.isMakingRequest).toBeFalsy();
expect(vm.isMergingImmediately).toBeFalsy();
expect(vm.commitMessage).toBe(vm.mr.commitMessage);
expect(vm.successSvg).toBeDefined();
expect(vm.warningSvg).toBeDefined();
});
});

View File

@ -19,7 +19,7 @@ RSpec.describe Gitlab::Git::ObjectPool do
describe '#create' do
before do
subject.create
subject.create # rubocop:disable Rails/SaveBang
end
context "when the pool doesn't exist yet" do
@ -31,7 +31,7 @@ RSpec.describe Gitlab::Git::ObjectPool do
context 'when the pool already exists' do
it 'raises an FailedPrecondition' do
expect do
subject.create
subject.create # rubocop:disable Rails/SaveBang
end.to raise_error(GRPC::FailedPrecondition)
end
end

View File

@ -16,7 +16,7 @@ RSpec.describe Gitlab::Git::RemoteMirror do
.to receive(:update_remote_mirror)
.with(ref_name, ['master'], ssh_key: 'KEY', known_hosts: 'KNOWN HOSTS', keep_divergent_refs: true)
remote_mirror.update
remote_mirror.update # rubocop:disable Rails/SaveBang
end
it 'wraps gitaly errors' do
@ -24,7 +24,7 @@ RSpec.describe Gitlab::Git::RemoteMirror do
.to receive(:update_remote_mirror)
.and_raise(StandardError)
expect { remote_mirror.update }.to raise_error(StandardError)
expect { remote_mirror.update }.to raise_error(StandardError) # rubocop:disable Rails/SaveBang
end
end
end

View File

@ -2079,7 +2079,7 @@ RSpec.describe Gitlab::Git::Repository, :seed_helper do
let(:object_pool_rugged) { Rugged::Repository.new(object_pool_path) }
before do
object_pool.create
object_pool.create # rubocop:disable Rails/SaveBang
end
it 'does not raise an error when disconnecting a non-linked repository' do

View File

@ -0,0 +1,106 @@
# frozen_string_literal: true
require 'spec_helper'
require 'json'
RSpec.describe Gitlab::Webpack::Manifest do
let(:manifest) do
<<-EOF
{
"errors": [],
"assetsByChunkName": {
"entry1": [ "entry1.js", "entry1-a.js" ],
"entry2": "entry2.js"
}
}
EOF
end
shared_examples_for "a valid manifest" do
it "returns single entry asset paths from the manifest" do
expect(Gitlab::Webpack::Manifest.asset_paths("entry2")).to eq(["/public_path/entry2.js"])
end
it "returns multiple entry asset paths from the manifest" do
expect(Gitlab::Webpack::Manifest.asset_paths("entry1")).to eq(["/public_path/entry1.js", "/public_path/entry1-a.js"])
end
it "errors on a missing entry point" do
expect { Gitlab::Webpack::Manifest.asset_paths("herp") }.to raise_error(Gitlab::Webpack::Manifest::AssetMissingError)
end
end
before do
# Test that config variables work while we're here
::Rails.configuration.webpack.dev_server.host = 'hostname'
::Rails.configuration.webpack.dev_server.port = 2000
::Rails.configuration.webpack.manifest_filename = "my_manifest.json"
::Rails.configuration.webpack.public_path = "public_path"
::Rails.configuration.webpack.output_dir = "manifest_output"
end
context "with dev server enabled" do
before do
::Rails.configuration.webpack.dev_server.enabled = true
stub_request(:get, "http://hostname:2000/public_path/my_manifest.json").to_return(body: manifest, status: 200)
end
describe ".asset_paths" do
it_behaves_like "a valid manifest"
it "errors if we can't find the manifest" do
::Rails.configuration.webpack.manifest_filename = "broken.json"
stub_request(:get, "http://hostname:2000/public_path/broken.json").to_raise(SocketError)
expect { Gitlab::Webpack::Manifest.asset_paths("entry1") }.to raise_error(Gitlab::Webpack::Manifest::ManifestLoadError)
end
describe "webpack errors" do
context "when webpack has 'Module build failed' errors in its manifest" do
it "errors" do
error_manifest = Gitlab::Json.parse(manifest).merge("errors" => [
"somethingModule build failed something",
"I am an error"
]).to_json
stub_request(:get, "http://hostname:2000/public_path/my_manifest.json").to_return(body: error_manifest, status: 200)
expect { Gitlab::Webpack::Manifest.asset_paths("entry1") }.to raise_error(Gitlab::Webpack::Manifest::WebpackError)
end
end
context "when webpack does not have 'Module build failed' errors in its manifest" do
it "does not error" do
error_manifest = Gitlab::Json.parse(manifest).merge("errors" => ["something went wrong"]).to_json
stub_request(:get, "http://hostname:2000/public_path/my_manifest.json").to_return(body: error_manifest, status: 200)
expect { Gitlab::Webpack::Manifest.asset_paths("entry1") }.not_to raise_error
end
end
it "does not error if errors is present but empty" do
error_manifest = Gitlab::Json.parse(manifest).merge("errors" => []).to_json
stub_request(:get, "http://hostname:2000/public_path/my_manifest.json").to_return(body: error_manifest, status: 200)
expect { Gitlab::Webpack::Manifest.asset_paths("entry1") }.not_to raise_error
end
end
end
end
context "with dev server disabled" do
before do
::Rails.configuration.webpack.dev_server.enabled = false
allow(File).to receive(:read).with(::Rails.root.join("manifest_output/my_manifest.json")).and_return(manifest)
end
describe ".asset_paths" do
it_behaves_like "a valid manifest"
it "errors if we can't find the manifest" do
::Rails.configuration.webpack.manifest_filename = "broken.json"
allow(File).to receive(:read).with(::Rails.root.join("manifest_output/broken.json")).and_raise(Errno::ENOENT)
expect { Gitlab::Webpack::Manifest.asset_paths("entry1") }.to raise_error(Gitlab::Webpack::Manifest::ManifestLoadError)
end
end
end
end

View File

@ -123,6 +123,10 @@ RSpec.configure do |config|
port: session.server.port,
protocol: 'http')
# CSRF protection is disabled by default. We only enable this for JS specs because some forms
# require Javascript to set the CSRF token.
allow_any_instance_of(ActionController::Base).to receive(:protect_against_forgery?).and_return(true)
# reset window size between tests
unless session.current_window.size == CAPYBARA_WINDOW_SIZE
begin