Commit 6cc04088 authored by Achilleas Pipinellis's avatar Achilleas Pipinellis

Merge branch 'ce-to-ee-2018-06-25' into 'master'

CE upstream - 2018-06-25 09:23 UTC

See merge request gitlab-org/gitlab-ee!6260
parents df96df05 454ee9f8
...@@ -11,7 +11,6 @@ export default class U2FAuthenticate { ...@@ -11,7 +11,6 @@ export default class U2FAuthenticate {
constructor(container, form, u2fParams, fallbackButton, fallbackUI) { constructor(container, form, u2fParams, fallbackButton, fallbackUI) {
this.u2fUtils = null; this.u2fUtils = null;
this.container = container; this.container = container;
this.renderNotSupported = this.renderNotSupported.bind(this);
this.renderAuthenticated = this.renderAuthenticated.bind(this); this.renderAuthenticated = this.renderAuthenticated.bind(this);
this.renderError = this.renderError.bind(this); this.renderError = this.renderError.bind(this);
this.renderInProgress = this.renderInProgress.bind(this); this.renderInProgress = this.renderInProgress.bind(this);
...@@ -41,7 +40,6 @@ export default class U2FAuthenticate { ...@@ -41,7 +40,6 @@ export default class U2FAuthenticate {
this.signRequests = u2fParams.sign_requests.map(request => _(request).omit('challenge')); this.signRequests = u2fParams.sign_requests.map(request => _(request).omit('challenge'));
this.templates = { this.templates = {
notSupported: '#js-authenticate-u2f-not-supported',
setup: '#js-authenticate-u2f-setup', setup: '#js-authenticate-u2f-setup',
inProgress: '#js-authenticate-u2f-in-progress', inProgress: '#js-authenticate-u2f-in-progress',
error: '#js-authenticate-u2f-error', error: '#js-authenticate-u2f-error',
...@@ -55,7 +53,7 @@ export default class U2FAuthenticate { ...@@ -55,7 +53,7 @@ export default class U2FAuthenticate {
this.u2fUtils = utils; this.u2fUtils = utils;
this.renderInProgress(); this.renderInProgress();
}) })
.catch(() => this.renderNotSupported()); .catch(() => this.switchToFallbackUI());
} }
authenticate() { authenticate() {
...@@ -96,10 +94,6 @@ export default class U2FAuthenticate { ...@@ -96,10 +94,6 @@ export default class U2FAuthenticate {
this.fallbackButton.classList.add('hidden'); this.fallbackButton.classList.add('hidden');
} }
renderNotSupported() {
return this.renderTemplate('notSupported');
}
switchToFallbackUI() { switchToFallbackUI() {
this.fallbackButton.classList.add('hidden'); this.fallbackButton.classList.add('hidden');
this.container[0].classList.add('hidden'); this.container[0].classList.add('hidden');
......
...@@ -527,7 +527,7 @@ ...@@ -527,7 +527,7 @@
.header-user { .header-user {
.dropdown-menu { .dropdown-menu {
width: auto; width: auto;
min-width: 160px; min-width: unset;
margin-top: 4px; margin-top: 4px;
color: $gl-text-color; color: $gl-text-color;
left: auto; left: auto;
......
...@@ -2033,6 +2033,10 @@ class Project < ActiveRecord::Base ...@@ -2033,6 +2033,10 @@ class Project < ActiveRecord::Base
end end
request_cache(:any_lfs_file_locks?) { self.id } request_cache(:any_lfs_file_locks?) { self.id }
def auto_cancel_pending_pipelines?
auto_cancel_pending_pipelines == 'enabled'
end
private private
def storage def storage
......
...@@ -17,6 +17,11 @@ ...@@ -17,6 +17,11 @@
= link_to _("Help"), help_path = link_to _("Help"), help_path
- if current_user_menu?(:help) || current_user_menu?(:settings) || current_user_menu?(:profile) - if current_user_menu?(:help) || current_user_menu?(:settings) || current_user_menu?(:profile)
%li.divider %li.divider
%li
= link_to "https://about.gitlab.com/contributing", target: '_blank', class: 'text-nowrap' do
= _("Contribute to GitLab")
= icon('external-link')
%li.divider
- if current_user_menu?(:sign_out) - if current_user_menu?(:sign_out)
%li %li
= link_to _("Sign out"), destroy_user_session_path, class: "sign-out-link" = link_to _("Sign out"), destroy_user_session_path, class: "sign-out-link"
...@@ -4,10 +4,12 @@ ...@@ -4,10 +4,12 @@
.form-group .form-group
= f.label :key, class: 'label-light' = f.label :key, class: 'label-light'
= f.text_area :key, class: "form-control", rows: 8, required: true, placeholder: "Don't paste the private part of the SSH key. Paste the public part, which is usually contained in the file '~/.ssh/id_rsa.pub' and begins with 'ssh-rsa'." %p= _("Paste your public SSH key, which is usually contained in the file '~/.ssh/id_rsa.pub' and begins with 'ssh-rsa'. Don't use your private SSH key.")
= f.text_area :key, class: "form-control", rows: 8, required: true, placeholder: 'Typically starts with "ssh-rsa …"'
.form-group .form-group
= f.label :title, class: 'label-light' = f.label :title, class: 'label-light'
= f.text_field :title, class: "form-control", required: true = f.text_field :title, class: "form-control", required: true, placeholder: 'e.g. My MacBook key'
%p.form-text.text-muted= _('Name your individual key via a title')
.prepend-top-default .prepend-top-default
= f.submit 'Add key', class: "btn btn-create" = f.submit 'Add key', class: "btn btn-create"
...@@ -11,10 +11,11 @@ ...@@ -11,10 +11,11 @@
%h5.prepend-top-0 %h5.prepend-top-0
Add an SSH key Add an SSH key
%p.profile-settings-content %p.profile-settings-content
Before you can add an SSH key you need to - generate_link_url = help_page_path("ssh/README", anchor: 'generating-a-new-ssh-key-pair')
= link_to "generate one", help_page_path("ssh/README", anchor: 'generating-a-new-ssh-key-pair') - existing_link_url = help_page_path("ssh/README", anchor: 'locating-an-existing-ssh-key-pair')
or use an - generate_link_start = '<a href="%{url}" target="_blank" rel="noopener noreferrer">'.html_safe % { url: generate_link_url }
= link_to "existing key.", help_page_path("ssh/README", anchor: 'locating-an-existing-ssh-key-pair') - existing_link_start = '<a href="%{url}" target="_blank" rel="noopener noreferrer">'.html_safe % { url: existing_link_url }
= _('To add an SSH key you need to %{generate_link_start}generate one%{link_end} or use an %{existing_link_start}existing key%{link_end}.').html_safe % { generate_link_start: generate_link_start, existing_link_start: existing_link_start, link_end: '</a>'.html_safe }
= render 'form' = render 'form'
%hr %hr
%h5 %h5
......
...@@ -2,9 +2,6 @@ ...@@ -2,9 +2,6 @@
%a.btn.btn-block.btn-info#js-login-2fa-device{ href: '#' } Sign in via 2FA code %a.btn.btn-block.btn-info#js-login-2fa-device{ href: '#' } Sign in via 2FA code
-# haml-lint:disable InlineJavaScript -# haml-lint:disable InlineJavaScript
%script#js-authenticate-u2f-not-supported{ type: "text/template" }
%p Your browser doesn't support U2F. Please use Google Chrome desktop (version 41 or newer).
%script#js-authenticate-u2f-in-progress{ type: "text/template" } %script#js-authenticate-u2f-in-progress{ type: "text/template" }
%p Trying to communicate with your device. Plug it in (if you haven't already) and press the button on the device now. %p Trying to communicate with your device. Plug it in (if you haven't already) and press the button on the device now.
......
---
title: Improve U2F workflow when using unsupported browsers
merge_request: 19938
author: Jan Beckmann
type: changed
---
title: Update new SSH key page to improve copy
merge_request: 19994
author:
type: other
---
title: Add a link to the contributing page in the user dropdown
merge_request: 19708
author:
type: added
...@@ -134,4 +134,4 @@ We're currently evaluating this feature on dev.gitalb.org or staging.gitlab.com ...@@ -134,4 +134,4 @@ We're currently evaluating this feature on dev.gitalb.org or staging.gitlab.com
- TBD - TBD
[ce-44935]: https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/18169 [ce-18169]: https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/18169
\ No newline at end of file
...@@ -38,3 +38,4 @@ semicolon, comma, or a new line. ...@@ -38,3 +38,4 @@ semicolon, comma, or a new line.
![Domain Blacklist](img/domain_blacklist.png) ![Domain Blacklist](img/domain_blacklist.png)
[ce-5259]: https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/5259 [ce-5259]: https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/5259
[ce-598]: https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/598
...@@ -9,6 +9,10 @@ The [Bitbucket integration][bb-import] must be first enabled in order to be ...@@ -9,6 +9,10 @@ The [Bitbucket integration][bb-import] must be first enabled in order to be
able to import your projects from Bitbucket. Ask your GitLab administrator able to import your projects from Bitbucket. Ask your GitLab administrator
to enable this if not already. to enable this if not already.
>**Note:**
The BitBucket importer currently only works with BitBucket's cloud offering
(bitbucket.org) and does not work with BitBucket Server (aka Stash).
- At its current state, the Bitbucket importer can import: - At its current state, the Bitbucket importer can import:
- the repository description (GitLab 7.7+) - the repository description (GitLab 7.7+)
- the Git repository data (GitLab 7.7+) - the Git repository data (GitLab 7.7+)
......
...@@ -8,4 +8,6 @@ You can delete an issue by editing it and clicking on the delete button. ...@@ -8,4 +8,6 @@ You can delete an issue by editing it and clicking on the delete button.
![delete issue - button](img/delete_issue.png) ![delete issue - button](img/delete_issue.png)
>**Note:** Only [project owners](../../permissions.md) can delete issues. >**Note:** Only [project owners](../../permissions.md) can delete issues.
\ No newline at end of file
[ce-2982]: https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/2982
\ No newline at end of file
...@@ -40,6 +40,15 @@ describe 'Signup' do ...@@ -40,6 +40,15 @@ describe 'Signup' do
expect(find('.username')).to have_css '.gl-field-error-outline' expect(find('.username')).to have_css '.gl-field-error-outline'
end end
it 'shows an error message on submit if the username contains special characters' do
fill_in 'new_user_username', with: 'new$user!username'
wait_for_requests
click_button "Register"
expect(page).to have_content("Please create a username with only alphanumeric characters.")
end
end end
context 'with no errors' do context 'with no errors' do
......
...@@ -6,7 +6,7 @@ import MockU2FDevice from './mock_u2f_device'; ...@@ -6,7 +6,7 @@ import MockU2FDevice from './mock_u2f_device';
describe('U2FAuthenticate', function () { describe('U2FAuthenticate', function () {
preloadFixtures('u2f/authenticate.html.raw'); preloadFixtures('u2f/authenticate.html.raw');
beforeEach((done) => { beforeEach(() => {
loadFixtures('u2f/authenticate.html.raw'); loadFixtures('u2f/authenticate.html.raw');
this.u2fDevice = new MockU2FDevice(); this.u2fDevice = new MockU2FDevice();
this.container = $('#js-authenticate-u2f'); this.container = $('#js-authenticate-u2f');
...@@ -19,46 +19,70 @@ describe('U2FAuthenticate', function () { ...@@ -19,46 +19,70 @@ describe('U2FAuthenticate', function () {
document.querySelector('#js-login-2fa-device'), document.querySelector('#js-login-2fa-device'),
document.querySelector('.js-2fa-form'), document.querySelector('.js-2fa-form'),
); );
});
// bypass automatic form submission within renderAuthenticated describe('with u2f unavailable', () => {
spyOn(this.component, 'renderAuthenticated').and.returnValue(true); beforeEach(() => {
spyOn(this.component, 'switchToFallbackUI');
this.oldu2f = window.u2f;
window.u2f = null;
});
this.component.start().then(done).catch(done.fail); afterEach(() => {
}); window.u2f = this.oldu2f;
});
it('allows authenticating via a U2F device', () => { it('falls back to normal 2fa', (done) => {
const inProgressMessage = this.container.find('p'); this.component.start().then(() => {
expect(inProgressMessage.text()).toContain('Trying to communicate with your device'); expect(this.component.switchToFallbackUI).toHaveBeenCalled();
this.u2fDevice.respondToAuthenticateRequest({ done();
deviceData: 'this is data from the device', }).catch(done.fail);
}); });
expect(this.component.renderAuthenticated).toHaveBeenCalledWith('{"deviceData":"this is data from the device"}');
}); });
describe('errors', () => { describe('with u2f available', () => {
it('displays an error message', () => { beforeEach((done) => {
const setupButton = this.container.find('#js-login-u2f-device'); // bypass automatic form submission within renderAuthenticated
setupButton.trigger('click'); spyOn(this.component, 'renderAuthenticated').and.returnValue(true);
this.u2fDevice.respondToAuthenticateRequest({ this.u2fDevice = new MockU2FDevice();
errorCode: 'error!',
}); this.component.start().then(done).catch(done.fail);
const errorMessage = this.container.find('p');
return expect(errorMessage.text()).toContain('There was a problem communicating with your device');
}); });
return it('allows retrying authentication after an error', () => {
let setupButton = this.container.find('#js-login-u2f-device'); it('allows authenticating via a U2F device', () => {
setupButton.trigger('click'); const inProgressMessage = this.container.find('p');
this.u2fDevice.respondToAuthenticateRequest({ expect(inProgressMessage.text()).toContain('Trying to communicate with your device');
errorCode: 'error!',
});
const retryButton = this.container.find('#js-u2f-try-again');
retryButton.trigger('click');
setupButton = this.container.find('#js-login-u2f-device');
setupButton.trigger('click');
this.u2fDevice.respondToAuthenticateRequest({ this.u2fDevice.respondToAuthenticateRequest({
deviceData: 'this is data from the device', deviceData: 'this is data from the device',
}); });
expect(this.component.renderAuthenticated).toHaveBeenCalledWith('{"deviceData":"this is data from the device"}'); expect(this.component.renderAuthenticated).toHaveBeenCalledWith('{"deviceData":"this is data from the device"}');
}); });
describe('errors', () => {
it('displays an error message', () => {
const setupButton = this.container.find('#js-login-u2f-device');
setupButton.trigger('click');
this.u2fDevice.respondToAuthenticateRequest({
errorCode: 'error!',
});
const errorMessage = this.container.find('p');
return expect(errorMessage.text()).toContain('There was a problem communicating with your device');
});
return it('allows retrying authentication after an error', () => {
let setupButton = this.container.find('#js-login-u2f-device');
setupButton.trigger('click');
this.u2fDevice.respondToAuthenticateRequest({
errorCode: 'error!',
});
const retryButton = this.container.find('#js-u2f-try-again');
retryButton.trigger('click');
setupButton = this.container.find('#js-login-u2f-device');
setupButton.trigger('click');
this.u2fDevice.respondToAuthenticateRequest({
deviceData: 'this is data from the device',
});
expect(this.component.renderAuthenticated).toHaveBeenCalledWith('{"deviceData":"this is data from the device"}');
});
});
}); });
}); });
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment