diff options
19 files changed, 280 insertions, 169 deletions
diff --git a/app/assets/stylesheets/framework/modal.scss b/app/assets/stylesheets/framework/modal.scss index d1f00d3ee2c..5b581780447 100644 --- a/app/assets/stylesheets/framework/modal.scss +++ b/app/assets/stylesheets/framework/modal.scss @@ -16,6 +16,14 @@ body.modal-open { overflow: hidden; } +.modal-no-backdrop { + @extend .modal-dialog; + + .modal-content { + box-shadow: none; + } +} + @media (min-width: $screen-md-min) { .modal-dialog { width: 860px; diff --git a/app/services/groups/nested_create_service.rb b/app/services/groups/nested_create_service.rb index 8d793f5c02e..d6f08fc3cce 100644 --- a/app/services/groups/nested_create_service.rb +++ b/app/services/groups/nested_create_service.rb @@ -15,6 +15,10 @@ module Groups return group end + if group_path.include?('/') && !Group.supports_nested_groups? + raise 'Nested groups are not supported on MySQL' + end + create_group_path end diff --git a/app/views/doorkeeper/authorizations/new.html.haml b/app/views/doorkeeper/authorizations/new.html.haml index 82aa51f9778..8ba88906714 100644 --- a/app/views/doorkeeper/authorizations/new.html.haml +++ b/app/views/doorkeeper/authorizations/new.html.haml @@ -1,39 +1,43 @@ -%h3.page-title Authorization required %main{ :role => "main" } - %p.h4 - Authorize - %strong.text-info= @pre_auth.client.name - to use your account? + .modal-no-backdrop + .modal-content + .modal-header + %h3.page-title + Authorize + = link_to @pre_auth.client.name, @pre_auth.redirect_uri, target: '_blank', rel: 'noopener noreferrer' + to use your account? - - if current_user.admin? - .text-warning.prepend-top-20 - %p - = icon("exclamation-triangle fw") - You are an admin, which means granting access to - %strong= @pre_auth.client.name - will allow them to interact with GitLab as an admin as well. Proceed with caution. - - - if @pre_auth.scopes - #oauth-permissions - %p This application will be able to: - %ul.text-info - - @pre_auth.scopes.each do |scope| - %li= t scope, scope: [:doorkeeper, :scopes] - %hr/ - .actions - = form_tag oauth_authorization_path, method: :post do - = hidden_field_tag :client_id, @pre_auth.client.uid - = hidden_field_tag :redirect_uri, @pre_auth.redirect_uri - = hidden_field_tag :state, @pre_auth.state - = hidden_field_tag :response_type, @pre_auth.response_type - = hidden_field_tag :scope, @pre_auth.scope - = hidden_field_tag :nonce, @pre_auth.nonce - = submit_tag "Authorize", class: "btn btn-success wide pull-left" - = form_tag oauth_authorization_path, method: :delete do - = hidden_field_tag :client_id, @pre_auth.client.uid - = hidden_field_tag :redirect_uri, @pre_auth.redirect_uri - = hidden_field_tag :state, @pre_auth.state - = hidden_field_tag :response_type, @pre_auth.response_type - = hidden_field_tag :scope, @pre_auth.scope - = hidden_field_tag :nonce, @pre_auth.nonce - = submit_tag "Deny", class: "btn btn-danger prepend-left-10" + .modal-body + - if current_user.admin? + .text-warning + %p + = icon("exclamation-triangle fw") + You are an admin, which means granting access to + %strong= @pre_auth.client.name + will allow them to interact with GitLab as an admin as well. Proceed with caution. + %p + You are about to authorize + = link_to @pre_auth.client.name, @pre_auth.redirect_uri, target: '_blank', rel: 'noopener noreferrer' + to use your account. + - if @pre_auth.scopes + This application will be able to: + %ul + - @pre_auth.scopes.each do |scope| + %li= t scope, scope: [:doorkeeper, :scopes] + .form-actions.text-right + = form_tag oauth_authorization_path, method: :delete, class: 'inline' do + = hidden_field_tag :client_id, @pre_auth.client.uid + = hidden_field_tag :redirect_uri, @pre_auth.redirect_uri + = hidden_field_tag :state, @pre_auth.state + = hidden_field_tag :response_type, @pre_auth.response_type + = hidden_field_tag :scope, @pre_auth.scope + = hidden_field_tag :nonce, @pre_auth.nonce + = submit_tag "Deny", class: "btn btn-danger" + = form_tag oauth_authorization_path, method: :post, class: 'inline' do + = hidden_field_tag :client_id, @pre_auth.client.uid + = hidden_field_tag :redirect_uri, @pre_auth.redirect_uri + = hidden_field_tag :state, @pre_auth.state + = hidden_field_tag :response_type, @pre_auth.response_type + = hidden_field_tag :scope, @pre_auth.scope + = hidden_field_tag :nonce, @pre_auth.nonce + = submit_tag "Authorize", class: "btn btn-success prepend-left-10" diff --git a/changelogs/unreleased/35721-auth-style-confirmation.yml b/changelogs/unreleased/35721-auth-style-confirmation.yml new file mode 100644 index 00000000000..9963f76e845 --- /dev/null +++ b/changelogs/unreleased/35721-auth-style-confirmation.yml @@ -0,0 +1,5 @@ +--- +title: restyling of OAuth authorization confirmation +merge_request: +author: Jacopo Beschi @jacopo-beschi +type: changed diff --git a/changelogs/unreleased/docs-document-version-for-group-milestones-api.yml b/changelogs/unreleased/docs-document-version-for-group-milestones-api.yml new file mode 100644 index 00000000000..d75c46313f4 --- /dev/null +++ b/changelogs/unreleased/docs-document-version-for-group-milestones-api.yml @@ -0,0 +1,5 @@ +--- +title: Document version Group Milestones API introduced +merge_request: +author: +type: changed diff --git a/changelogs/unreleased/replace_spinach_search_code-feature.yml b/changelogs/unreleased/replace_spinach_search_code-feature.yml new file mode 100644 index 00000000000..28d2108c871 --- /dev/null +++ b/changelogs/unreleased/replace_spinach_search_code-feature.yml @@ -0,0 +1,5 @@ +--- +title: Replace 'source/search_code.feature' spinach test with an rspec analog +merge_request: 13697 +author: blackst0ne +type: other diff --git a/config/webpack.config.js b/config/webpack.config.js index 8aa938d538e..7d63a42d7d8 100644 --- a/config/webpack.config.js +++ b/config/webpack.config.js @@ -170,7 +170,7 @@ var config = { if (chunk.name) { return chunk.name; } - return chunk.modules.map((m) => { + return chunk.mapModules((m) => { var chunkPath = m.request.split('!').pop(); return path.relative(m.context, chunkPath); }).join('_'); diff --git a/doc/administration/auth/authentiq.md b/doc/administration/auth/authentiq.md index 1528f1d2b17..252ff1f4b15 100644 --- a/doc/administration/auth/authentiq.md +++ b/doc/administration/auth/authentiq.md @@ -4,7 +4,7 @@ To enable the Authentiq OmniAuth provider for passwordless authentication you mu Authentiq will generate a Client ID and the accompanying Client Secret for you to use. -1. Get your Client credentials (Client ID and Client Secret) at [Authentiq](https://www.authentiq.com/register). +1. Get your Client credentials (Client ID and Client Secret) at [Authentiq](https://www.authentiq.com/developers). 2. On your GitLab server, open the configuration file: diff --git a/doc/api/group_milestones.md b/doc/api/group_milestones.md index dbfc7529125..a96fb3124fc 100644 --- a/doc/api/group_milestones.md +++ b/doc/api/group_milestones.md @@ -1,5 +1,8 @@ # Group milestones API +> **Notes:** +> [Introduced][ce-12819] in GitLab 9.5. + ## List group milestones Returns a list of group milestones. @@ -118,3 +121,5 @@ Parameters: - `id` (required) - The ID or [URL-encoded path of the group](README.md#namespaced-path-encoding) owned by the authenticated user - `milestone_id` (required) - The ID of a group milestone + +[ce-12819]: https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/12819 diff --git a/doc/ci/variables/README.md b/doc/ci/variables/README.md index e55a92dbb71..234dc530db0 100644 --- a/doc/ci/variables/README.md +++ b/doc/ci/variables/README.md @@ -86,6 +86,11 @@ To follow conventions of naming across GitLab, and to futher move away from the `build` term and toward `job` CI variables have been renamed for the 9.0 release. +>**Note:** +Starting with GitLab 9.0, we have deprecated the `$CI_BUILD_*` variables. **You are +strongly advised to use the new variables as we will remove the old ones in +future GitLab releases.** + | 8.x name | 9.0+ name | | --------------------- |------------------------ | | `CI_BUILD_ID` | `CI_JOB_ID` | diff --git a/doc/development/doc_styleguide.md b/doc/development/doc_styleguide.md index 90d1d9657b9..798f40eef3d 100644 --- a/doc/development/doc_styleguide.md +++ b/doc/development/doc_styleguide.md @@ -113,13 +113,12 @@ merge request. ## Links -- If a link makes the paragraph to span across multiple lines, do not use - the regular Markdown approach: `[Text](https://example.com)`. Instead use - `[Text][identifier]` and at the very bottom of the document add: - `[identifier]: https://example.com`. This is another way to create Markdown - links which keeps the document clear and concise. Bonus points if you also - add an alternative text: `[identifier]: https://example.com "Alternative text"` - that appears when hovering your mouse on a link +- Use the regular inline link markdown markup `[Text](https://example.com)`. + It's easier to read, review, and maintain. +- If there's a link that repeats several times through the same document, + you can use `[Text][identifier]` and at the bottom of the section or the + document add: `[identifier]: https://example.com`, in which case, we do + encourage you to also add an alternative text: `[identifier]: https://example.com "Alternative text"` that appears when hovering your mouse on a link. ### Linking to inline docs diff --git a/doc/user/index.md b/doc/user/index.md index e9ec603f2f1..f239a15d441 100644 --- a/doc/user/index.md +++ b/doc/user/index.md @@ -119,6 +119,13 @@ When performing inline reviews to implementations to your codebase through merge requests you can gather feedback through [resolvable discussions](discussions/index.md#resolvable-discussions). +### GitLab Flavored Markdown (GFM) + +Read through the [GFM documentation](markdown.md) to learn how to apply +the best of GitLab Flavored Markdown in your discussions, comments, +issues and merge requests descriptions, and everywhere else GMF is +supported. + ## Todos Never forget to reply to your collaborators. [GitLab Todos](../workflow/todos.md) diff --git a/features/project/source/search_code.feature b/features/project/source/search_code.feature deleted file mode 100644 index 4f9dcea249f..00000000000 --- a/features/project/source/search_code.feature +++ /dev/null @@ -1,15 +0,0 @@ -Feature: Project Source Search Code - Background: - Given I sign in as a user - - Scenario: Search for term "coffee" - Given I own project "Shop" - And I visit project source page - When I search for term "coffee" - Then I should see files from repository containing "coffee" - - Scenario: Search on empty project - Given I own an empty project - And I visit my project's home page - When I search for term "coffee" - Then I should see empty result diff --git a/features/steps/project/source/search_code.rb b/features/steps/project/source/search_code.rb deleted file mode 100644 index feee756d7ec..00000000000 --- a/features/steps/project/source/search_code.rb +++ /dev/null @@ -1,19 +0,0 @@ -class Spinach::Features::ProjectSourceSearchCode < Spinach::FeatureSteps - include SharedAuthentication - include SharedProject - include SharedPaths - - step 'I search for term "coffee"' do - fill_in "search", with: "coffee" - click_button "Go" - end - - step 'I should see files from repository containing "coffee"' do - expect(page).to have_content 'coffee' - expect(page).to have_content 'CONTRIBUTING.md' - end - - step 'I should see empty result' do - expect(page).to have_content "We couldn't find any" - end -end diff --git a/features/steps/shared/paths.rb b/features/steps/shared/paths.rb index 830263fd038..be69a96c3ee 100644 --- a/features/steps/shared/paths.rb +++ b/features/steps/shared/paths.rb @@ -304,10 +304,6 @@ module SharedPaths visit project_commits_path(@project, 'stable', { limit: 5 }) end - step 'I visit project source page' do - visit project_tree_path(@project, root_ref) - end - step 'I visit blob file from repo' do visit project_blob_path(@project, File.join(sample_commit.id, sample_blob.path)) end diff --git a/spec/features/projects/files/find_files_spec.rb b/spec/features/projects/files/find_files_spec.rb deleted file mode 100644 index 57d67b28920..00000000000 --- a/spec/features/projects/files/find_files_spec.rb +++ /dev/null @@ -1,23 +0,0 @@ -require 'spec_helper' - -feature 'Find files button in the tree header' do - given(:user) { create(:user) } - given(:project) { create(:project, :repository) } - - background do - sign_in(user) - project.team << [user, :developer] - end - - scenario 'project main screen' do - visit project_path(project) - - expect(page).to have_selector('.tree-controls .shortcuts-find-file') - end - - scenario 'project tree screen' do - visit project_tree_path(project, project.default_branch) - - expect(page).to have_selector('.tree-controls .shortcuts-find-file') - end -end diff --git a/spec/features/projects/files/user_searches_for_files_spec.rb b/spec/features/projects/files/user_searches_for_files_spec.rb new file mode 100644 index 00000000000..a105685bca7 --- /dev/null +++ b/spec/features/projects/files/user_searches_for_files_spec.rb @@ -0,0 +1,58 @@ +require 'spec_helper' + +describe 'User searches for files' do + let(:user) { create(:user) } + let(:project) { create(:project, :repository) } + + before do + sign_in(user) + end + + describe 'project main screen' do + context 'when project is empty' do + let(:empty_project) { create(:project) } + + before do + empty_project.add_developer(user) + visit project_path(empty_project) + end + + it 'does not show any result' do + fill_in('search', with: 'coffee') + click_button('Go') + + expect(page).to have_content("We couldn't find any") + end + end + + context 'when project is not empty' do + before do + project.add_developer(user) + visit project_path(project) + end + + it 'shows "Find file" button' do + expect(page).to have_selector('.tree-controls .shortcuts-find-file') + end + end + end + + describe 'project tree screen' do + before do + project.add_developer(user) + visit project_tree_path(project, project.default_branch) + end + + it 'shows "Find file" button' do + expect(page).to have_selector('.tree-controls .shortcuts-find-file') + end + + it 'shows found files' do + fill_in('search', with: 'coffee') + click_button('Go') + + expect(page).to have_content('coffee') + expect(page).to have_content('CONTRIBUTING.md') + end + end +end diff --git a/spec/lib/gitlab/bare_repository_importer_spec.rb b/spec/lib/gitlab/bare_repository_importer_spec.rb index 892f2dafc96..36d1844b5b1 100644 --- a/spec/lib/gitlab/bare_repository_importer_spec.rb +++ b/spec/lib/gitlab/bare_repository_importer_spec.rb @@ -2,67 +2,99 @@ require 'spec_helper' describe Gitlab::BareRepositoryImporter, repository: true do subject(:importer) { described_class.new('default', project_path) } - let(:project_path) { 'a-group/a-sub-group/a-project' } + let!(:admin) { create(:admin) } before do allow(described_class).to receive(:log) end - describe '.execute' do - it 'creates a project for a repository in storage' do - FileUtils.mkdir_p(File.join(TestEnv.repos_path, "#{project_path}.git")) - fake_importer = double + shared_examples 'importing a repository' do + describe '.execute' do + it 'creates a project for a repository in storage' do + FileUtils.mkdir_p(File.join(TestEnv.repos_path, "#{project_path}.git")) + fake_importer = double - expect(described_class).to receive(:new).with('default', project_path) - .and_return(fake_importer) - expect(fake_importer).to receive(:create_project_if_needed) + expect(described_class).to receive(:new).with('default', project_path) + .and_return(fake_importer) + expect(fake_importer).to receive(:create_project_if_needed) - described_class.execute - end + described_class.execute + end - it 'skips wiki repos' do - FileUtils.mkdir_p(File.join(TestEnv.repos_path, 'the-group', 'the-project.wiki.git')) + it 'skips wiki repos' do + FileUtils.mkdir_p(File.join(TestEnv.repos_path, 'the-group', 'the-project.wiki.git')) - expect(described_class).to receive(:log).with(' * Skipping wiki repo') - expect(described_class).not_to receive(:new) + expect(described_class).to receive(:log).with(' * Skipping wiki repo') + expect(described_class).not_to receive(:new) - described_class.execute + described_class.execute + end end - end - describe '#initialize' do - context 'without admin users' do - let(:admin) { nil } + describe '#initialize' do + context 'without admin users' do + let(:admin) { nil } - it 'raises an error' do - expect { importer }.to raise_error(Gitlab::BareRepositoryImporter::NoAdminError) + it 'raises an error' do + expect { importer }.to raise_error(Gitlab::BareRepositoryImporter::NoAdminError) + end end end - end - describe '#create_project_if_needed' do - it 'starts an import for a project that did not exist' do - expect(importer).to receive(:create_project) + describe '#create_project_if_needed' do + it 'starts an import for a project that did not exist' do + expect(importer).to receive(:create_project) + + importer.create_project_if_needed + end + + it 'skips importing when the project already exists' do + project = create(:project, path: 'a-project', namespace: existing_group) + + expect(importer).not_to receive(:create_project) + expect(importer).to receive(:log).with(" * #{project.name} (#{project_path}) exists") + + importer.create_project_if_needed + end + + it 'creates a project with the correct path in the database' do + importer.create_project_if_needed - importer.create_project_if_needed + expect(Project.find_by_full_path(project_path)).not_to be_nil + end end + end + + context 'with subgroups', :nested_groups do + let(:project_path) { 'a-group/a-sub-group/a-project' } - it 'skips importing when the project already exists' do + let(:existing_group) do group = create(:group, path: 'a-group') - subgroup = create(:group, path: 'a-sub-group', parent: group) - project = create(:project, path: 'a-project', namespace: subgroup) + create(:group, path: 'a-sub-group', parent: group) + end - expect(importer).not_to receive(:create_project) - expect(importer).to receive(:log).with(" * #{project.name} (a-group/a-sub-group/a-project) exists") + it_behaves_like 'importing a repository' + end - importer.create_project_if_needed - end + context 'without subgroups' do + let(:project_path) { 'a-group/a-project' } + let(:existing_group) { create(:group, path: 'a-group') } - it 'creates a project with the correct path in the database' do - importer.create_project_if_needed + it_behaves_like 'importing a repository' + end + + context 'when subgroups are not available' do + let(:project_path) { 'a-group/a-sub-group/a-project' } + + before do + expect(Group).to receive(:supports_nested_groups?) { false } + end - expect(Project.find_by_full_path(project_path)).not_to be_nil + describe '#create_project_if_needed' do + it 'raises an error' do + expect { importer.create_project_if_needed }.to raise_error('Nested groups are not supported on MySQL') + end end end end diff --git a/spec/services/groups/nested_create_service_spec.rb b/spec/services/groups/nested_create_service_spec.rb index 6d11edb5842..6491fb34777 100644 --- a/spec/services/groups/nested_create_service_spec.rb +++ b/spec/services/groups/nested_create_service_spec.rb @@ -2,52 +2,87 @@ require 'spec_helper' describe Groups::NestedCreateService do let(:user) { create(:user) } - let(:params) { { group_path: 'a-group/a-sub-group' } } subject(:service) { described_class.new(user, params) } - describe "#execute" do - it 'returns the group if it already existed' do - parent = create(:group, path: 'a-group', owner: user) - child = create(:group, path: 'a-sub-group', parent: parent, owner: user) + shared_examples 'with a visibility level' do + it 'creates the group with correct visibility level' do + allow(Gitlab::CurrentSettings.current_application_settings) + .to receive(:default_group_visibility) { Gitlab::VisibilityLevel::INTERNAL } + + group = service.execute - expect(service.execute).to eq(child) + expect(group.visibility_level).to eq(Gitlab::VisibilityLevel::INTERNAL) end - it 'reuses a parent if it already existed', :nested_groups do - parent = create(:group, path: 'a-group') - parent.add_owner(user) + context 'adding a visibility level ' do + it 'overwrites the visibility level' do + service = described_class.new(user, params.merge(visibility_level: Gitlab::VisibilityLevel::PRIVATE)) + + group = service.execute - expect(service.execute.parent).to eq(parent) + expect(group.visibility_level).to eq(Gitlab::VisibilityLevel::PRIVATE) + end end + end + + describe 'without subgroups' do + let(:params) { { group_path: 'a-group' } } - it 'creates group and subgroup in the database', :nested_groups do - service.execute + before do + allow(Group).to receive(:supports_nested_groups?) { false } + end - parent = Group.find_by_full_path('a-group') - child = parent.children.find_by(path: 'a-sub-group') + it 'creates the group' do + group = service.execute - expect(parent).not_to be_nil - expect(child).not_to be_nil + expect(group).to be_persisted end - it 'creates the group with correct visibility level' do - allow(Gitlab::CurrentSettings.current_application_settings) - .to receive(:default_group_visibility) { Gitlab::VisibilityLevel::INTERNAL } + it 'returns the group if it already existed' do + existing_group = create(:group, path: 'a-group') - group = service.execute + expect(service.execute).to eq(existing_group) + end - expect(group.visibility_level).to eq(Gitlab::VisibilityLevel::INTERNAL) + it 'raises an error when tring to create a subgroup' do + service = described_class.new(user, group_path: 'a-group/a-sub-group') + + expect { service.execute }.to raise_error('Nested groups are not supported on MySQL') end - context 'adding a visibility level ' do - let(:params) { { group_path: 'a-group/a-sub-group', visibility_level: Gitlab::VisibilityLevel::PRIVATE } } + it_behaves_like 'with a visibility level' + end - it 'overwrites the visibility level' do - group = service.execute + describe 'with subgroups', :nested_groups do + let(:params) { { group_path: 'a-group/a-sub-group' } } - expect(group.visibility_level).to eq(Gitlab::VisibilityLevel::PRIVATE) + describe "#execute" do + it 'returns the group if it already existed' do + parent = create(:group, path: 'a-group', owner: user) + child = create(:group, path: 'a-sub-group', parent: parent, owner: user) + + expect(service.execute).to eq(child) end + + it 'reuses a parent if it already existed' do + parent = create(:group, path: 'a-group') + parent.add_owner(user) + + expect(service.execute.parent).to eq(parent) + end + + it 'creates group and subgroup in the database' do + service.execute + + parent = Group.find_by_full_path('a-group') + child = parent.children.find_by(path: 'a-sub-group') + + expect(parent).not_to be_nil + expect(child).not_to be_nil + end + + it_behaves_like 'with a visibility level' end end end |