diff options
24 files changed, 187 insertions, 58 deletions
diff --git a/app/assets/javascripts/boards/components/modal/index.js b/app/assets/javascripts/boards/components/modal/index.js index 1d36519c75c..96af69e7a36 100644 --- a/app/assets/javascripts/boards/components/modal/index.js +++ b/app/assets/javascripts/boards/components/modal/index.js @@ -1,8 +1,8 @@ /* global ListIssue */ import Vue from 'vue'; -import queryData from '../../utils/query_data'; -import loadingIcon from '../../../vue_shared/components/loading_icon.vue'; +import queryData from '~/boards/utils/query_data'; +import loadingIcon from '~/vue_shared/components/loading_icon.vue'; import './header'; import './list'; import './footer'; diff --git a/app/assets/javascripts/pipelines/components/graph/graph_component.vue b/app/assets/javascripts/pipelines/components/graph/graph_component.vue index 77cbaeb43ef..66bc1d1979c 100644 --- a/app/assets/javascripts/pipelines/components/graph/graph_component.vue +++ b/app/assets/javascripts/pipelines/components/graph/graph_component.vue @@ -1,7 +1,7 @@ <script> + import loadingIcon from '~/vue_shared/components/loading_icon.vue'; + import '~/flash'; import stageColumnComponent from './stage_column_component.vue'; - import loadingIcon from '../../../vue_shared/components/loading_icon.vue'; - import '../../../flash'; export default { props: { diff --git a/app/assets/javascripts/vue_merge_request_widget/dependencies.js b/app/assets/javascripts/vue_merge_request_widget/dependencies.js index fe5e1bbb55c..546a3f625c7 100644 --- a/app/assets/javascripts/vue_merge_request_widget/dependencies.js +++ b/app/assets/javascripts/vue_merge_request_widget/dependencies.js @@ -1,7 +1,7 @@ /** * This file is the centerpiece of an attempt to reduce potential conflicts * between the CE and EE versions of the MR widget. EE additions to the MR widget should - * be contained in the ./vue_merge_request_widget/ee directory, and should **extend** + * be contained in the ee/vue_merge_request_widget directory, and should **extend** * rather than mutate CE MR Widget code. * * This file should be the only source of conflicts between EE and CE. EE-only components should diff --git a/app/assets/stylesheets/framework/dropdowns.scss b/app/assets/stylesheets/framework/dropdowns.scss index bd4bd541c3a..02e0ba74158 100644 --- a/app/assets/stylesheets/framework/dropdowns.scss +++ b/app/assets/stylesheets/framework/dropdowns.scss @@ -728,6 +728,10 @@ @mixin new-style-dropdown { .dropdown-menu, .dropdown-menu-nav { + .divider { + margin: 6px 0; + } + li { padding: 0 1px; diff --git a/app/assets/stylesheets/new_nav.scss b/app/assets/stylesheets/new_nav.scss index 1c4a84de7ec..795ee91af8b 100644 --- a/app/assets/stylesheets/new_nav.scss +++ b/app/assets/stylesheets/new_nav.scss @@ -312,6 +312,10 @@ header.navbar-gitlab-new { // TODO: fallback to global style .dropdown-menu { + .divider { + margin: 6px 0; + } + li { padding: 0 1px; diff --git a/app/models/repository.rb b/app/models/repository.rb index 4e9fe759fdc..2dd48290e58 100644 --- a/app/models/repository.rb +++ b/app/models/repository.rb @@ -613,17 +613,26 @@ class Repository end def last_commit_for_path(sha, path) - sha = last_commit_id_for_path(sha, path) - commit(sha) + raw_repository.gitaly_migrate(:last_commit_for_path) do |is_enabled| + if is_enabled + last_commit_for_path_by_gitaly(sha, path) + else + last_commit_for_path_by_rugged(sha, path) + end + end end - # Gitaly migration: https://gitlab.com/gitlab-org/gitaly/issues/383 def last_commit_id_for_path(sha, path) key = path.blank? ? "last_commit_id_for_path:#{sha}" : "last_commit_id_for_path:#{sha}:#{Digest::SHA1.hexdigest(path)}" cache.fetch(key) do - args = %W(#{Gitlab.config.git.bin_path} rev-list --max-count=1 #{sha} -- #{path}) - Gitlab::Popen.popen(args, path_to_repo).first.strip + raw_repository.gitaly_migrate(:last_commit_for_path) do |is_enabled| + if is_enabled + last_commit_for_path_by_gitaly(sha, path).id + else + last_commit_id_for_path_by_shelling_out(sha, path) + end + end end end @@ -1138,6 +1147,21 @@ class Repository Rugged::Commit.create(rugged, params) end + def last_commit_for_path_by_gitaly(sha, path) + c = raw_repository.gitaly_commit_client.last_commit_for_path(sha, path) + commit(c) + end + + def last_commit_for_path_by_rugged(sha, path) + sha = last_commit_id_for_path_by_shelling_out(sha, path) + commit(sha) + end + + def last_commit_id_for_path_by_shelling_out(sha, path) + args = %W(#{Gitlab.config.git.bin_path} rev-list --max-count=1 #{sha} -- #{path}) + Gitlab::Popen.popen(args, path_to_repo).first.strip + end + def repository_storage_path @project.repository_storage_path end diff --git a/app/views/layouts/nav/_new_admin_sidebar.html.haml b/app/views/layouts/nav/_new_admin_sidebar.html.haml index e2f6e9c1aa2..54ea39a2d36 100644 --- a/app/views/layouts/nav/_new_admin_sidebar.html.haml +++ b/app/views/layouts/nav/_new_admin_sidebar.html.haml @@ -110,7 +110,7 @@ = nav_link(controller: :spam_logs) do = link_to admin_spam_logs_path, title: "Spam Logs" do .nav-icon-container - = custom_icon('mr_bold') + = custom_icon('spam_logs') %span.nav-item-name Spam Logs diff --git a/app/views/layouts/nav/_new_project_sidebar.html.haml b/app/views/layouts/nav/_new_project_sidebar.html.haml index 8e246b6e91f..8d821c1796c 100644 --- a/app/views/layouts/nav/_new_project_sidebar.html.haml +++ b/app/views/layouts/nav/_new_project_sidebar.html.haml @@ -76,7 +76,7 @@ = nav_link(controller: %w[projects/registry/repositories]) do = link_to project_container_registry_index_path(@project), title: 'Container Registry', class: 'shortcuts-container-registry' do .nav-icon-container - = custom_icon('mr_bold') + = custom_icon('container_registry') %span.nav-item-name Registry diff --git a/app/views/shared/icons/_container_registry.svg b/app/views/shared/icons/_container_registry.svg new file mode 100644 index 00000000000..56d62aab670 --- /dev/null +++ b/app/views/shared/icons/_container_registry.svg @@ -0,0 +1 @@ +<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><path d="m16 11.764v-8.764c0-1.657-1.343-3-3-3h-10c-1.657 0-3 1.343-3 3v8.764c.531-.475 1.232-.764 2-.764v-8c0-.552.448-1 1-1h10c.552 0 1 .448 1 1v8c.768 0 1.469.289 2 .764m-14 .236h12c1.105 0 2 .895 2 2 0 1.105-.895 2-2 2h-12c-1.105 0-2-.895-2-2 0-1.105.895-2 2-2m10 1c-.552 0-1 .448-1 1 0 .552.448 1 1 1 .552 0 1-.448 1-1 0-.552-.448-1-1-1"/></svg> diff --git a/app/views/shared/icons/_spam_logs.svg b/app/views/shared/icons/_spam_logs.svg new file mode 100644 index 00000000000..80ee0eb3856 --- /dev/null +++ b/app/views/shared/icons/_spam_logs.svg @@ -0,0 +1 @@ +<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16"><path d="M8.75.433l5.428 3.134a1.5 1.5 0 0 1 .75 1.299v6.268a1.5 1.5 0 0 1-.75 1.299L8.75 15.567a1.5 1.5 0 0 1-1.5 0l-5.428-3.134a1.5 1.5 0 0 1-.75-1.299V4.866a1.5 1.5 0 0 1 .75-1.299L7.25.433a1.5 1.5 0 0 1 1.5 0zM3.072 5.155v5.69L8 13.691l4.928-2.846v-5.69L8 2.309 3.072 5.155zM8 4a1 1 0 0 1 1 1v3a1 1 0 1 1-2 0V5a1 1 0 0 1 1-1zm0 8a1 1 0 1 1 0-2 1 1 0 0 1 0 2z"/></svg> diff --git a/config/application.rb b/config/application.rb index 1c13cc81270..f7145566262 100644 --- a/config/application.rb +++ b/config/application.rb @@ -23,13 +23,13 @@ module Gitlab # https://github.com/rails/rails/blob/v4.2.6/railties/lib/rails/engine.rb#L687 # This is a nice reference article on autoloading/eager loading: # http://blog.arkency.com/2014/11/dont-forget-about-eager-load-when-extending-autoload - config.eager_load_paths.push(*%W(#{config.root}/lib + config.eager_load_paths.push(*%W[#{config.root}/lib #{config.root}/app/models/hooks #{config.root}/app/models/members #{config.root}/app/models/project_services #{config.root}/app/workers/concerns #{config.root}/app/services/concerns - #{config.root}/app/finders/concerns)) + #{config.root}/app/finders/concerns]) config.generators.templates.push("#{config.root}/generator_templates") diff --git a/doc/development/fe_guide/style_guide_js.md b/doc/development/fe_guide/style_guide_js.md index 149a0159680..6ade3231fac 100644 --- a/doc/development/fe_guide/style_guide_js.md +++ b/doc/development/fe_guide/style_guide_js.md @@ -11,7 +11,7 @@ See [our current .eslintrc][eslintrc] for specific rules and patterns. #### ESlint -1. **Never** disable eslint rules unless you have a good reason. +1. **Never** disable eslint rules unless you have a good reason. You may see a lot of legacy files with `/* eslint-disable some-rule, some-other-rule */` at the top, but legacy files are a special case. Any time you develop a new feature or refactor an existing one, you should abide by the eslint rules. @@ -100,26 +100,44 @@ followed by any global declarations, then a blank newline prior to any imports o export default Foo; ``` -1. Relative paths: Unless you are writing a test, always reference other scripts using -relative paths instead of `~` - * In **app/assets/javascripts**: +1. Relative paths: when importing a module in the same directory, a child +directory, or an immediate parent directory prefer relative paths. When +importing a module which is two or more levels up, prefer either `~/` or `ee/` +. - ```javascript - // bad - import Foo from '~/foo' +In **app/assets/javascripts/my-feature/subdir**: - // good - import Foo from '../foo'; - ``` - * In **spec/javascripts**: +``` javascript +// bad +import Foo from '~/my-feature/foo'; +import Bar from '~/my-feature/subdir/bar'; +import Bin from '~/my-feature/subdir/lib/bin'; - ```javascript - // bad - import Foo from '../../app/assets/javascripts/foo' +// good +import Foo from '../foo'; +import Bar from './bar'; +import Bin from './lib/bin'; +``` - // good - import Foo from '~/foo'; - ``` +In **spec/javascripts**: + +``` javascript +// bad +import Foo from '../../app/assets/javascripts/my-feature/foo'; + +// good +import Foo from '~/my-feature/foo'; +``` + +When referencing an **EE component**: + +``` javascript +// bad +import Foo from '../../../../../ee/app/assets/javascripts/my-feature/ee-foo'; + +// good +import Foo from 'ee/my-feature/foo'; +``` 1. Avoid using IIFE. Although we have a lot of examples of files which wrap their contents in IIFEs (immediately-invoked function expressions), @@ -465,7 +483,7 @@ A forEach will cause side effects, it will be mutating the array being iterated. #### Vue and Boostrap 1. Tooltips: Do not rely on `has-tooltip` class name for Vue components - ```javascript + ```javascript // bad <span class="has-tooltip" diff --git a/doc/install/installation.md b/doc/install/installation.md index 8ded607bcab..22aedb5403e 100644 --- a/doc/install/installation.md +++ b/doc/install/installation.md @@ -168,8 +168,10 @@ are out of date, so we'll need to install through the following commands: curl --location https://deb.nodesource.com/setup_7.x | sudo bash - sudo apt-get install -y nodejs - # install yarn - curl --location https://yarnpkg.com/install.sh | bash - + curl --silent --show-error https://dl.yarnpkg.com/debian/pubkey.gpg | sudo apt-key add - + echo "deb https://dl.yarnpkg.com/debian/ stable main" | sudo tee /etc/apt/sources.list.d/yarn.list + sudo apt-get update + sudo apt-get install yarn Visit the official websites for [node](https://nodejs.org/en/download/package-manager/) and [yarn](https://yarnpkg.com/en/docs/install/) if you have any trouble with these steps. diff --git a/doc/update/8.17-to-9.0.md b/doc/update/8.17-to-9.0.md index 6308317b1f2..4d3ababaa41 100644 --- a/doc/update/8.17-to-9.0.md +++ b/doc/update/8.17-to-9.0.md @@ -65,7 +65,10 @@ Since 8.17, GitLab requires the use of yarn `>= v0.17.0` to manage JavaScript dependencies. ```bash -curl --location https://yarnpkg.com/install.sh | bash - +curl --silent --show-error https://dl.yarnpkg.com/debian/pubkey.gpg | sudo apt-key add - +echo "deb https://dl.yarnpkg.com/debian/ stable main" | sudo tee /etc/apt/sources.list.d/yarn.list +sudo apt-get update +sudo apt-get install yarn ``` More information can be found on the [yarn website](https://yarnpkg.com/en/docs/install). diff --git a/doc/update/9.0-to-9.1.md b/doc/update/9.0-to-9.1.md index 2d597894517..2b4a7bed27f 100644 --- a/doc/update/9.0-to-9.1.md +++ b/doc/update/9.0-to-9.1.md @@ -65,7 +65,10 @@ Since 8.17, GitLab requires the use of yarn `>= v0.17.0` to manage JavaScript dependencies. ```bash -curl --location https://yarnpkg.com/install.sh | bash - +curl --silent --show-error https://dl.yarnpkg.com/debian/pubkey.gpg | sudo apt-key add - +echo "deb https://dl.yarnpkg.com/debian/ stable main" | sudo tee /etc/apt/sources.list.d/yarn.list +sudo apt-get update +sudo apt-get install yarn ``` More information can be found on the [yarn website](https://yarnpkg.com/en/docs/install). diff --git a/doc/update/9.1-to-9.2.md b/doc/update/9.1-to-9.2.md index 225a4dcc924..f38547bba1a 100644 --- a/doc/update/9.1-to-9.2.md +++ b/doc/update/9.1-to-9.2.md @@ -65,7 +65,10 @@ Since 8.17, GitLab requires the use of yarn `>= v0.17.0` to manage JavaScript dependencies. ```bash -curl --location https://yarnpkg.com/install.sh | bash - +curl --silent --show-error https://dl.yarnpkg.com/debian/pubkey.gpg | sudo apt-key add - +echo "deb https://dl.yarnpkg.com/debian/ stable main" | sudo tee /etc/apt/sources.list.d/yarn.list +sudo apt-get update +sudo apt-get install yarn ``` More information can be found on the [yarn website](https://yarnpkg.com/en/docs/install). diff --git a/doc/update/9.2-to-9.3.md b/doc/update/9.2-to-9.3.md index 910539acc70..373f43eb3bb 100644 --- a/doc/update/9.2-to-9.3.md +++ b/doc/update/9.2-to-9.3.md @@ -65,7 +65,10 @@ Since 8.17, GitLab requires the use of yarn `>= v0.17.0` to manage JavaScript dependencies. ```bash -curl --location https://yarnpkg.com/install.sh | bash - +curl --silent --show-error https://dl.yarnpkg.com/debian/pubkey.gpg | sudo apt-key add - +echo "deb https://dl.yarnpkg.com/debian/ stable main" | sudo tee /etc/apt/sources.list.d/yarn.list +sudo apt-get update +sudo apt-get install yarn ``` More information can be found on the [yarn website](https://yarnpkg.com/en/docs/install). diff --git a/doc/update/9.3-to-9.4.md b/doc/update/9.3-to-9.4.md index 9540c36e7d0..b167f0737aa 100644 --- a/doc/update/9.3-to-9.4.md +++ b/doc/update/9.3-to-9.4.md @@ -65,7 +65,10 @@ Since 8.17, GitLab requires the use of yarn `>= v0.17.0` to manage JavaScript dependencies. ```bash -curl --location https://yarnpkg.com/install.sh | bash - +curl --silent --show-error https://dl.yarnpkg.com/debian/pubkey.gpg | sudo apt-key add - +echo "deb https://dl.yarnpkg.com/debian/ stable main" | sudo tee /etc/apt/sources.list.d/yarn.list +sudo apt-get update +sudo apt-get install yarn ``` More information can be found on the [yarn website](https://yarnpkg.com/en/docs/install). diff --git a/lib/gitlab/git/repository.rb b/lib/gitlab/git/repository.rb index 1c3beb5e834..734aed8fbc1 100644 --- a/lib/gitlab/git/repository.rb +++ b/lib/gitlab/git/repository.rb @@ -1006,6 +1006,11 @@ module Gitlab end.sort_by(&:name) end + def last_commit_for_path_by_rugged(sha, path) + sha = last_commit_id_for_path(sha, path) + commit(sha) + end + def tags_from_gitaly gitaly_ref_client.tags end diff --git a/lib/gitlab/gitaly_client/commit_service.rb b/lib/gitlab/gitaly_client/commit_service.rb index 1ae13677b42..ac6817e6d0e 100644 --- a/lib/gitlab/gitaly_client/commit_service.rb +++ b/lib/gitlab/gitaly_client/commit_service.rb @@ -97,6 +97,20 @@ module Gitlab GitalyClient.call(@repository.storage, :commit_service, :count_commits, request).count end + def last_commit_for_path(revision, path) + request = Gitaly::LastCommitForPathRequest.new( + repository: @gitaly_repo, + revision: revision.force_encoding(Encoding::ASCII_8BIT), + path: path.to_s.force_encoding(Encoding::ASCII_8BIT) + ) + + gitaly_commit = GitalyClient.call(@repository.storage, :commit_service, :last_commit_for_path, request).commit + return unless gitaly_commit + + commit = GitalyClient::Commit.new(@repository, gitaly_commit) + Gitlab::Git::Commit.new(commit) + end + def between(from, to) request = Gitaly::CommitsBetweenRequest.new( repository: @gitaly_repo, diff --git a/spec/models/repository_spec.rb b/spec/models/repository_spec.rb index 764f548be45..f876baaa805 100644 --- a/spec/models/repository_spec.rb +++ b/spec/models/repository_spec.rb @@ -139,24 +139,44 @@ describe Repository do end describe '#last_commit_for_path' do - subject { repository.last_commit_for_path(sample_commit.id, '.gitignore').id } + shared_examples 'getting last commit for path' do + subject { repository.last_commit_for_path(sample_commit.id, '.gitignore').id } - it { is_expected.to eq('c1acaa58bbcbc3eafe538cb8274ba387047b69f8') } + it { is_expected.to eq('c1acaa58bbcbc3eafe538cb8274ba387047b69f8') } + end + + context 'when Gitaly feature last_commit_for_path is enabled' do + it_behaves_like 'getting last commit for path' + end + + context 'when Gitaly feature last_commit_for_path is disabled', skip_gitaly_mock: true do + it_behaves_like 'getting last commit for path' + end end describe '#last_commit_id_for_path' do - subject { repository.last_commit_id_for_path(sample_commit.id, '.gitignore') } + shared_examples 'getting last commit ID for path' do + subject { repository.last_commit_id_for_path(sample_commit.id, '.gitignore') } - it "returns last commit id for a given path" do - is_expected.to eq('c1acaa58bbcbc3eafe538cb8274ba387047b69f8') + it "returns last commit id for a given path" do + is_expected.to eq('c1acaa58bbcbc3eafe538cb8274ba387047b69f8') + end + + it "caches last commit id for a given path" do + cache = repository.send(:cache) + key = "last_commit_id_for_path:#{sample_commit.id}:#{Digest::SHA1.hexdigest('.gitignore')}" + + expect(cache).to receive(:fetch).with(key).and_return('c1acaa5') + is_expected.to eq('c1acaa5') + end end - it "caches last commit id for a given path" do - cache = repository.send(:cache) - key = "last_commit_id_for_path:#{sample_commit.id}:#{Digest::SHA1.hexdigest('.gitignore')}" + context 'when Gitaly feature last_commit_for_path is enabled' do + it_behaves_like 'getting last commit ID for path' + end - expect(cache).to receive(:fetch).with(key).and_return('c1acaa5') - is_expected.to eq('c1acaa5') + context 'when Gitaly feature last_commit_for_path is disabled', skip_gitaly_mock: true do + it_behaves_like 'getting last commit ID for path' end end diff --git a/spec/requests/api/merge_requests_spec.rb b/spec/requests/api/merge_requests_spec.rb index d8dfe71342d..9eda6836ded 100644 --- a/spec/requests/api/merge_requests_spec.rb +++ b/spec/requests/api/merge_requests_spec.rb @@ -293,6 +293,26 @@ describe API::MergeRequests do expect(json_response.length).to eq(0) end + it 'returns an array of labeled merge requests that are merged for a milestone' do + bug_label = create(:label, title: 'bug', color: '#FFAABB', project: project) + + mr1 = create(:merge_request, state: "merged", source_project: project, target_project: project, milestone: milestone) + mr2 = create(:merge_request, state: "merged", source_project: project, target_project: project, milestone: milestone1) + mr3 = create(:merge_request, state: "closed", source_project: project, target_project: project, milestone: milestone1) + _mr = create(:merge_request, state: "merged", source_project: project, target_project: project, milestone: milestone1) + + create(:label_link, label: bug_label, target: mr1) + create(:label_link, label: bug_label, target: mr2) + create(:label_link, label: bug_label, target: mr3) + + get api("/projects/#{project.id}/merge_requests?labels=#{bug_label.title}&milestone=#{milestone1.title}&state=merged", user) + + expect(response).to have_http_status(200) + expect(json_response).to be_an Array + expect(json_response.length).to eq(1) + expect(json_response.first['id']).to eq(mr2.id) + end + context "with ordering" do before do @mr_later = mr_with_later_created_and_updated_at_time diff --git a/spec/support/api/schema_matcher.rb b/spec/support/api/schema_matcher.rb index 67599f77adb..6591d56e473 100644 --- a/spec/support/api/schema_matcher.rb +++ b/spec/support/api/schema_matcher.rb @@ -1,23 +1,25 @@ -def schema_path(schema) - schema_directory = "#{Dir.pwd}/spec/fixtures/api/schemas" - "#{schema_directory}/#{schema}.json" +module SchemaPath + def self.expand(schema, dir = '') + Rails.root.join('spec', dir, "fixtures/api/schemas/#{schema}.json").to_s + end end -RSpec::Matchers.define :match_response_schema do |schema, **options| +RSpec::Matchers.define :match_response_schema do |schema, dir: '', **options| match do |response| - @errors = JSON::Validator.fully_validate(schema_path(schema), response.body, options) + @errors = JSON::Validator.fully_validate( + SchemaPath.expand(schema, dir), response.body, options) @errors.empty? end failure_message do |response| - "didn't match the schema defined by #{schema_path(schema)}" \ + "didn't match the schema defined by #{SchemaPath.expand(schema, dir)}" \ " The validation errors were:\n#{@errors.join("\n")}" end end -RSpec::Matchers.define :match_schema do |schema, **options| +RSpec::Matchers.define :match_schema do |schema, dir: '', **options| match do |data| - JSON::Validator.validate!(schema_path(schema), data, options) + JSON::Validator.validate!(SchemaPath.expand(schema, dir), data, options) end end diff --git a/spec/support/test_env.rb b/spec/support/test_env.rb index bed78928f14..c1298ed9cae 100644 --- a/spec/support/test_env.rb +++ b/spec/support/test_env.rb @@ -229,7 +229,6 @@ module TestEnv # Otherwise they'd be created by the first test, often timing out and # causing a transient test failure def eager_load_driver_server - return unless ENV['CI'] return unless defined?(Capybara) puts "Starting the Capybara driver server..." |