Add latest changes from gitlab-org/gitlab@master

This commit is contained in:
GitLab Bot 2021-06-24 18:07:15 +00:00
parent 8a37720edf
commit ff8299c65d
20 changed files with 141 additions and 64 deletions

View file

@ -1,4 +1,5 @@
import $ from 'jquery';
import initVueAlerts from '~/vue_alerts';
import NoEmojiValidator from '../../../emoji/no_emoji_validator';
import LengthValidator from './length_validator';
import OAuthRememberMe from './oauth_remember_me';
@ -19,4 +20,5 @@ document.addEventListener('DOMContentLoaded', () => {
// Save the URL fragment from the current window location. This will be present if the user was
// redirected to sign-in after attempting to access a protected URL that included a fragment.
preserveUrlFragment(window.location.hash);
initVueAlerts();
});

View file

@ -1,11 +1,14 @@
<script>
/* eslint-disable vue/no-v-html */
import { GlAlert } from '@gitlab/ui';
import { GlAlert, GlSafeHtmlDirective as SafeHtml } from '@gitlab/ui';
export default {
name: 'DismissibleAlert',
components: {
GlAlert,
},
directives: {
SafeHtml,
},
props: {
html: {
type: String,
@ -28,6 +31,6 @@ export default {
<template>
<gl-alert v-if="!isDismissed" v-bind="$attrs" @dismiss="dismiss" v-on="$listeners">
<div v-html="html"></div>
<div v-safe-html="html"></div>
</gl-alert>
</template>

View file

@ -13,8 +13,16 @@ class Groups::ApplicationController < ApplicationController
before_action :set_sorting
requires_cross_project_access
helper_method :can_manage_members?
private
def can_manage_members?(group = @group)
strong_memoize(:can_manage_members) do
can?(current_user, :admin_group_member, group)
end
end
def group
@group ||= find_routable!(Group, params[:group_id] || params[:id])
end

View file

@ -22,8 +22,6 @@ class Groups::GroupMembersController < Groups::ApplicationController
feature_category :authentication_and_authorization
helper_method :can_manage_members?
def index
@sort = params[:sort].presence || sort_value_name
@ -53,12 +51,6 @@ class Groups::GroupMembersController < Groups::ApplicationController
private
def can_manage_members?
strong_memoize(:can_manage_members) do
can?(current_user, :admin_group_member, @group)
end
end
def present_invited_members(invited_members)
present_members(invited_members
.page(params[:invited_members_page])

View file

@ -1,7 +1,8 @@
- if can?(current_user, :admin_group_member, group)
.js-invite-members-modal{ data: { id: group.id,
name: group.name,
is_project: 'false',
access_levels: GroupMember.access_level_roles.to_json,
default_access_level: Gitlab::Access::GUEST,
help_link: help_page_url('user/permissions') }.merge(group_select_data(group)) }
- return unless can_manage_members?(group)
.js-invite-members-modal{ data: { id: group.id,
name: group.name,
is_project: 'false',
access_levels: GroupMember.access_level_roles.to_json,
default_access_level: Gitlab::Access::GUEST,
help_link: help_page_url('user/permissions') }.merge(group_select_data(group)) }

View file

@ -4,6 +4,8 @@
- flash.each do |key, value|
- if key == 'toast' && value
.js-toast-message{ data: { message: value } }
- elsif value == I18n.t('devise.failure.unconfirmed')
= render 'shared/confirm_your_email_alert'
- elsif value
%div{ class: "flash-#{key} mb-2" }
= sprite_icon(icons[key], css_class: 'align-middle mr-1') unless icons[key].nil?

View file

@ -9,4 +9,4 @@
event: 'click_button',
label: 'invite_members_empty_project' } }
= render 'shared/issuable/invite_members_trigger', project: @project
= render 'projects/invite_members_modal', project: @project

View file

@ -1,7 +1,8 @@
- if can_invite_members_for_project?(project)
.js-invite-members-modal{ data: { id: project.id,
name: project.name,
is_project: 'true',
access_levels: ProjectMember.access_level_roles.to_json,
default_access_level: Gitlab::Access::GUEST,
help_link: help_page_url('user/permissions') } }
- return unless can_import_members?
.js-invite-members-modal{ data: { id: project.id,
name: project.name,
is_project: 'true',
access_levels: ProjectMember.access_level_roles.to_json,
default_access_level: Gitlab::Access::GUEST,
help_link: help_page_url('user/permissions') } }

View file

@ -4,4 +4,4 @@
- page_title "#{@issue.title} (#{@issue.to_reference})", _("Issues")
= render 'projects/issuable/show', issuable: @issue, api_awards_path: award_emoji_issue_api_path(@issue)
= render 'shared/issuable/invite_members_trigger', project: @project
= render 'projects/invite_members_modal', project: @project

View file

@ -96,5 +96,5 @@
#js-review-bar
= render 'shared/issuable/invite_members_trigger', project: @project
= render 'projects/invite_members_modal', project: @project

View file

@ -0,0 +1,7 @@
.js-vue-alert{ 'v-cloak': true,
data: { dismissible: 'true',
title: _('Please confirm your email address'),
primary_button_text: _('Resend confirmation email'),
primary_button_link: new_user_confirmation_path,
variant: 'warning'} }
= (_("To continue, you need to select the link in the confirmation email we sent to verify your email address. If you didn't get our email, select %{strongStart}Resend confirmation email.%{strongEnd}") % { strongStart: '<strong>', strongEnd: '</strong>' }).html_safe

View file

@ -1,8 +0,0 @@
- return unless can_import_members?
.js-invite-members-modal{ data: { id: project.id,
name: project.name,
is_project: 'true',
access_levels: ProjectMember.access_level_roles.to_json,
default_access_level: Gitlab::Access::GUEST,
help_link: help_page_url('user/permissions') } }

View file

@ -31,7 +31,7 @@ sent to the primary (unless necessary), the primary (`db3`) hardly has any load.
## Requirements
For load balancing to work you will need at least PostgreSQL 11 or newer,
For load balancing to work, you need at least PostgreSQL 11 or newer,
[**MySQL is not supported**](../install/requirements.md#database). You also need to make sure that you have
at least 1 secondary in [hot standby](https://www.postgresql.org/docs/11/hot-standby.html) mode.
@ -42,7 +42,7 @@ you should put a load balancer in front of every database, and have GitLab conne
to those load balancers.
For example, say you have a primary (`db1.gitlab.com`) and two secondaries,
`db2.gitlab.com` and `db3.gitlab.com`. For this setup you will need to have 3
`db2.gitlab.com` and `db3.gitlab.com`. For this setup, you need to have 3
load balancers, one for every host. For example:
- `primary.gitlab.com` forwards to `db1.gitlab.com`
@ -56,7 +56,7 @@ means forwarding should now happen as follows:
- `secondary1.gitlab.com` forwards to `db1.gitlab.com`
- `secondary2.gitlab.com` forwards to `db3.gitlab.com`
GitLab does not take care of this for you, so you will need to do so yourself.
GitLab does not take care of this for you, so you need to do so yourself.
Finally, load balancing requires that GitLab can connect to all hosts using the
same credentials and port as configured in the
@ -72,7 +72,7 @@ different ports or credentials for different hosts is not supported.
## Enabling load balancing
For the environment in which you want to use load balancing, you'll need to add
the following. This will balance the load between `host1.example.com` and
the following. This balances the load between `host1.example.com` and
`host2.example.com`.
**In Omnibus installations:**
@ -176,15 +176,15 @@ The following options can be set:
| `disconnect_timeout` | The time in seconds after which an old connection is closed, after the list of hosts was updated. | 120 |
| `use_tcp` | Lookup DNS resources using TCP instead of UDP | false |
If `record_type` is set to `SRV`, GitLab will continue to use a round-robin algorithm
and will ignore the `weight` and `priority` in the record. Since SRV records usually
return hostnames instead of IPs, GitLab will look for the IPs of returned hostnames
If `record_type` is set to `SRV`, then GitLab continues to use round-robin algorithm
and ignores the `weight` and `priority` in the record. Since SRV records usually
return hostnames instead of IPs, GitLab needs to look for the IPs of returned hostnames
in the additional section of the SRV response. If no IP is found for a hostname, GitLab
will query the configured `nameserver` for ANY record for each such hostname looking for A or AAAA
needs to query the configured `nameserver` for ANY record for each such hostname looking for A or AAAA
records, eventually dropping this hostname from rotation if it can't resolve its IP.
The `interval` value specifies the _minimum_ time between checks. If the A
record has a TTL greater than this value, then service discovery will honor said
record has a TTL greater than this value, then service discovery honors said
TTL. For example, if the TTL of the A record is 90 seconds, then service
discovery waits at least 90 seconds before checking the A record again.

View file

@ -102,6 +102,30 @@ curl --request PUT \
"https://gitlab.example.com/api/v4/projects/1/packages/nuget"
```
## Upload a symbol package file
> Introduced in GitLab 12.8.
Upload a NuGet symbol package file (`.snupkg`):
```plaintext
PUT projects/:id/packages/nuget/symbolpackage
```
| Attribute | Type | Required | Description |
| ----------------- | ------ | -------- | ----------- |
| `id` | string | yes | The ID or full path of the project. |
| `package_name` | string | yes | The name of the package. |
| `package_version` | string | yes | The version of the package. |
| `package_filename`| string | yes | The name of the file. |
```shell
curl --request PUT \
--upload-file path/to/mynugetpkg.1.3.0.17.snupkg \
--user <username>:<personal_access_token> \
"https://gitlab.example.com/api/v4/projects/1/packages/nuget/symbolpackage"
```
## Route prefix
For the remaining routes, there are two sets of identical routes that each make requests in
@ -193,6 +217,11 @@ Example response:
"@id": "https://gitlab.example.com/api/v4/projects/1/packages/nuget",
"@type": "PackagePublish/2.0.0",
"comment": "Push and delete (or unlist) packages."
},
{
"@id": "https://gitlab.example.com/api/v4/projects/1/packages/nuget/symbolpackage",
"@type": "SymbolPackagePublish/4.9.0",
"comment": "Push symbol packages."
}
]
}

View file

@ -144,7 +144,7 @@ See also:
Learn more about:
- [Why you might chose GitLab CI/CD](https://about.gitlab.com/blog/2016/10/17/gitlab-ci-oohlala/).
- [Why you might choose GitLab CI/CD](https://about.gitlab.com/blog/2016/10/17/gitlab-ci-oohlala/).
- [Reasons you might migrate from another platform](https://about.gitlab.com/blog/2016/07/22/building-our-web-app-on-gitlab-ci/).
- [5 Teams that made the switch to GitLab CI/CD](https://about.gitlab.com/blog/2019/04/25/5-teams-that-made-the-switch-to-gitlab-ci-cd/)

View file

@ -39,6 +39,13 @@ and has its own dedicated IP address (`192.237.158.143`).
The IP address for `mg.gitlab.com` is subject to change at any time.
### Service Desk custom mailbox
On GitLab.com there's a mailbox configured for Service Desk with the email adress:
`contact-project+%{key}@incoming.gitlab.com`. To use this mailbox, configure the
[custom suffix](../project/service_desk.md#configuring-a-custom-email-address-suffix) in project
settings.
## Backups
[See our backup strategy](https://about.gitlab.com/handbook/engineering/infrastructure/production/#backups).

View file

@ -24290,6 +24290,9 @@ msgstr ""
msgid "Please complete your profile with email address"
msgstr ""
msgid "Please confirm your email address"
msgstr ""
msgid "Please contact an admin to register runners."
msgstr ""
@ -33895,6 +33898,9 @@ msgstr ""
msgid "To connect an SVN repository, check out %{svn_link}."
msgstr ""
msgid "To continue, you need to select the link in the confirmation email we sent to verify your email address. If you didn't get our email, select %{strongStart}Resend confirmation email.%{strongEnd}"
msgstr ""
msgid "To define internal users, first enable new users set to external"
msgstr ""

View file

@ -97,6 +97,8 @@ RSpec.describe 'Login' do
describe 'with an unconfirmed email address' do
let!(:user) { create(:user, confirmed_at: nil) }
let(:grace_period) { 2.days }
let(:alert_title) { 'Please confirm your email address' }
let(:alert_message) { "To continue, you need to select the link in the confirmation email we sent to verify your email address. If you didn't get our email, select Resend confirmation email" }
before do
stub_application_setting(send_user_confirmation_email: true)
@ -109,13 +111,14 @@ RSpec.describe 'Login' do
gitlab_sign_in(user)
expect(page).not_to have_content(I18n.t('devise.failure.unconfirmed'))
expect(page).not_to have_content(alert_title)
expect(page).not_to have_content(alert_message)
expect(page).not_to have_link('Resend confirmation email', href: new_user_confirmation_path)
end
end
context 'when the confirmation grace period is expired' do
it 'prevents the user from logging in and renders a resend confirmation email link' do
it 'prevents the user from logging in and renders a resend confirmation email link', :js do
travel_to((grace_period + 1.day).from_now) do
expect(authentication_metrics)
.to increment(:user_unauthenticated_counter)
@ -123,7 +126,8 @@ RSpec.describe 'Login' do
gitlab_sign_in(user)
expect(page).to have_content(I18n.t('devise.failure.unconfirmed'))
expect(page).to have_content(alert_title)
expect(page).to have_content(alert_message)
expect(page).to have_link('Resend confirmation email', href: new_user_confirmation_path)
end
end
@ -889,6 +893,8 @@ RSpec.describe 'Login' do
context 'when sending confirmation email and not yet confirmed' do
let!(:user) { create(:user, confirmed_at: nil) }
let(:grace_period) { 2.days }
let(:alert_title) { 'Please confirm your email address' }
let(:alert_message) { "To continue, you need to select the link in the confirmation email we sent to verify your email address. If you didn't get our email, select Resend confirmation email" }
before do
stub_application_setting(send_user_confirmation_email: true)
@ -906,7 +912,7 @@ RSpec.describe 'Login' do
end
context "when not having confirmed within Devise's allow_unconfirmed_access_for time" do
it 'does not allow login and shows a flash alert to confirm the email address' do
it 'does not allow login and shows a flash alert to confirm the email address', :js do
travel_to((grace_period + 1.day).from_now) do
expect(authentication_metrics)
.to increment(:user_unauthenticated_counter)
@ -915,7 +921,9 @@ RSpec.describe 'Login' do
gitlab_sign_in(user)
expect(current_path).to eq new_user_session_path
expect(page).to have_content(I18n.t('devise.failure.unconfirmed'))
expect(page).to have_content(alert_title)
expect(page).to have_content(alert_message)
expect(page).to have_link('Resend confirmation email', href: new_user_confirmation_path)
end
end
end

View file

@ -28,8 +28,8 @@ describe('VueAlerts', () => {
alerts
.map(
(x) => `
<div class="js-vue-alert"
data-dismissible="${x.dismissible}"
<div class="js-vue-alert"
data-dismissible="${x.dismissible}"
data-title="${x.title}"
data-primary-button-text="${x.primaryButtonText}"
data-primary-button-link="${x.primaryButtonLink}"

View file

@ -5,18 +5,12 @@ import DismissibleAlert from '~/vue_shared/components/dismissible_alert.vue';
const TEST_HTML = 'Hello World! <strong>Foo</strong>';
describe('vue_shared/components/dismissible_alert', () => {
const testAlertProps = {
primaryButtonText: 'Lorem ipsum',
primaryButtonLink: '/lorem/ipsum',
};
let wrapper;
const createComponent = (props = {}) => {
wrapper = shallowMount(DismissibleAlert, {
propsData: {
html: TEST_HTML,
...testAlertProps,
...props,
},
});
@ -28,16 +22,13 @@ describe('vue_shared/components/dismissible_alert', () => {
const findAlert = () => wrapper.find(GlAlert);
describe('with default', () => {
describe('default', () => {
beforeEach(() => {
createComponent();
});
it('shows alert', () => {
const alert = findAlert();
expect(alert.exists()).toBe(true);
expect(alert.props()).toEqual(expect.objectContaining(testAlertProps));
expect(findAlert().exists()).toBe(true);
});
it('shows given HTML', () => {
@ -54,4 +45,32 @@ describe('vue_shared/components/dismissible_alert', () => {
});
});
});
describe('with additional props', () => {
const testAlertProps = {
dismissible: true,
title: 'Mock Title',
primaryButtonText: 'Lorem ipsum',
primaryButtonLink: '/lorem/ipsum',
variant: 'warning',
};
beforeEach(() => {
createComponent(testAlertProps);
});
it('passes other props', () => {
expect(findAlert().props()).toEqual(expect.objectContaining(testAlertProps));
});
});
describe('with unsafe HTML', () => {
beforeEach(() => {
createComponent({ html: '<a onclick="alert("XSS")">Link</a>' });
});
it('removes unsafe HTML', () => {
expect(findAlert().html()).toContain('<a>Link</a>');
});
});
});