From fd88b0ca56b3a4230902f76a7b049228e53e6bb0 Mon Sep 17 00:00:00 2001 From: Tony Rom Date: Thu, 16 Nov 2017 21:10:15 +0300 Subject: Add `pipelines` endpoint to merge requests API --- changelogs/unreleased/39214__pipeline_api.yml | 5 +++ doc/api/merge_requests.md | 26 +++++++++++++++ lib/api/merge_requests.rb | 15 +++++++++ .../api/schemas/public_api/v4/pipelines.json | 4 +++ spec/requests/api/merge_requests_spec.rb | 37 ++++++++++++++++++++++ 5 files changed, 87 insertions(+) create mode 100644 changelogs/unreleased/39214__pipeline_api.yml create mode 100644 spec/fixtures/api/schemas/public_api/v4/pipelines.json diff --git a/changelogs/unreleased/39214__pipeline_api.yml b/changelogs/unreleased/39214__pipeline_api.yml new file mode 100644 index 00000000000..18ee2e43798 --- /dev/null +++ b/changelogs/unreleased/39214__pipeline_api.yml @@ -0,0 +1,5 @@ +--- +title: Add `pipelines` endpoint to merge requests API +merge_request: 15454 +author: Tony Rom +type: added diff --git a/doc/api/merge_requests.md b/doc/api/merge_requests.md index 880b0ed2c65..a3261cf7ee4 100644 --- a/doc/api/merge_requests.md +++ b/doc/api/merge_requests.md @@ -431,6 +431,32 @@ Parameters: } ``` +## List MR pipelines + +Get a list of merge request pipelines. + +``` +GET /projects/:id/merge_requests/:merge_request_iid/pipelines +``` + +Parameters: + +- `id` (required) - The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) owned by the authenticated user +- `merge_request_iid` (required) - The internal ID of the merge request + +Example of response + +```json +[ + { + "id": 77, + "sha": "959e04d7c7a30600c894bd3c0cd0e1ce7f42c11d", + "ref": "master", + "status": "success" + } +] +``` + ## Create MR Creates a new merge request. diff --git a/lib/api/merge_requests.rb b/lib/api/merge_requests.rb index d34886fca2e..77c563ec0b4 100644 --- a/lib/api/merge_requests.rb +++ b/lib/api/merge_requests.rb @@ -24,6 +24,12 @@ module API .preload(:notes, :author, :assignee, :milestone, :latest_merge_request_diff, :labels, :timelogs) end + def merge_request_pipelines_with_access(access_level = :read_pipeline) + authorize! access_level, user_project + mr = find_merge_request_with_access(params[:merge_request_iid]) + mr.all_pipelines + end + params :merge_requests_params do optional :state, type: String, values: %w[opened closed merged all], default: 'all', desc: 'Return opened, closed, merged, or all merge requests' @@ -203,6 +209,15 @@ module API present merge_request, with: Entities::MergeRequestChanges, current_user: current_user end + desc 'Get the merge request pipelines' do + success Entities::PipelineBasic + end + get ':id/merge_requests/:merge_request_iid/pipelines' do + pipelines = merge_request_pipelines_with_access + + present paginate(pipelines), with: Entities::PipelineBasic + end + desc 'Update a merge request' do success Entities::MergeRequest end diff --git a/spec/fixtures/api/schemas/public_api/v4/pipelines.json b/spec/fixtures/api/schemas/public_api/v4/pipelines.json new file mode 100644 index 00000000000..8b08a00f708 --- /dev/null +++ b/spec/fixtures/api/schemas/public_api/v4/pipelines.json @@ -0,0 +1,4 @@ +{ + "type": "array", + "items": { "$ref": "pipeline/basic.json" } +} diff --git a/spec/requests/api/merge_requests_spec.rb b/spec/requests/api/merge_requests_spec.rb index 91616da6d9a..4278e32dc78 100644 --- a/spec/requests/api/merge_requests_spec.rb +++ b/spec/requests/api/merge_requests_spec.rb @@ -525,6 +525,43 @@ describe API::MergeRequests do end end + describe 'GET /projects/:id/merge_requests/:merge_request_iid/pipelines' do + context 'when authorized' do + let!(:pipeline) { create(:ci_empty_pipeline, project: project, user: user, ref: merge_request.source_branch, sha: merge_request.diff_head_sha) } + let!(:pipeline2) { create(:ci_empty_pipeline, project: project) } + + it 'returns a paginated array of corresponding pipelines' do + get api("/projects/#{project.id}/merge_requests/#{merge_request.iid}/pipelines") + + expect(response).to have_gitlab_http_status(200) + expect(response).to include_pagination_headers + expect(json_response).to be_an Array + expect(json_response.count).to eq(1) + expect(json_response.first['id']).to eq(pipeline.id) + end + + it 'exposes basic attributes' do + get api("/projects/#{project.id}/merge_requests/#{merge_request.iid}/pipelines") + + expect(response).to have_gitlab_http_status(200) + expect(response).to match_response_schema('public_api/v4/pipelines') + end + end + + context 'when unauthorized' do + it 'returns 403' do + project = create(:project, public_builds: false) + merge_request = create(:merge_request, :simple, source_project: project) + guest = create(:user) + project.team << [guest, :guest] + + get api("/projects/#{project.id}/merge_requests/#{merge_request.iid}/pipelines", guest) + + expect(response).to have_gitlab_http_status(403) + end + end + end + describe "POST /projects/:id/merge_requests" do context 'between branches projects' do it "returns merge_request" do -- cgit v1.2.1 From 754c4d97e591c96dbe8e6525227deeaf21cf7987 Mon Sep 17 00:00:00 2001 From: Winnie Hellmann Date: Mon, 18 Dec 2017 12:37:48 +0000 Subject: Remove wrong padding from pipelines.scss --- app/assets/stylesheets/pages/pipelines.scss | 1 - 1 file changed, 1 deletion(-) diff --git a/app/assets/stylesheets/pages/pipelines.scss b/app/assets/stylesheets/pages/pipelines.scss index 9805fc4f882..bf8e515a3b7 100644 --- a/app/assets/stylesheets/pages/pipelines.scss +++ b/app/assets/stylesheets/pages/pipelines.scss @@ -792,7 +792,6 @@ button.mini-pipeline-graph-dropdown-toggle { // link to the build .mini-pipeline-graph-dropdown-item { - padding: 3px 7px 4px; align-items: center; clear: both; display: flex; -- cgit v1.2.1 From b570b34787b9a83e6af4e39a1e7445f86ff20911 Mon Sep 17 00:00:00 2001 From: Vincent Lae Date: Thu, 21 Dec 2017 13:07:54 +0000 Subject: fix example in ci ssh_keys documentation --- doc/ci/ssh_keys/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/ci/ssh_keys/README.md b/doc/ci/ssh_keys/README.md index df0e1521150..b8df0bfba20 100644 --- a/doc/ci/ssh_keys/README.md +++ b/doc/ci/ssh_keys/README.md @@ -181,7 +181,7 @@ before_script: ## Assuming you created the SSH_KNOWN_HOSTS variable, uncomment the ## following two lines. ## - - echo "$SSH_KNOWN_HOSTS" > ~/.ssh/known_hosts' + - echo "$SSH_KNOWN_HOSTS" > ~/.ssh/known_hosts - chmod 644 ~/.ssh/known_hosts ## -- cgit v1.2.1 From 32424e461bebebae2ad1bf302e8fb0d375771135 Mon Sep 17 00:00:00 2001 From: Grzegorz Bizon Date: Fri, 22 Dec 2017 11:51:25 +0100 Subject: Add QA sanity selectors scenario entrypoint --- qa/qa.rb | 4 ++++ qa/qa/scenario/test/sanity/selectors.rb | 14 ++++++++++++++ 2 files changed, 18 insertions(+) create mode 100644 qa/qa/scenario/test/sanity/selectors.rb diff --git a/qa/qa.rb b/qa/qa.rb index 340f5e35c67..6a878400287 100644 --- a/qa/qa.rb +++ b/qa/qa.rb @@ -56,6 +56,10 @@ module QA module Integration autoload :Mattermost, 'qa/scenario/test/integration/mattermost' end + + module Sanity + autoload :Selectors, 'qa/scenario/test/sanity/selectors' + end end end diff --git a/qa/qa/scenario/test/sanity/selectors.rb b/qa/qa/scenario/test/sanity/selectors.rb new file mode 100644 index 00000000000..892bb2966c7 --- /dev/null +++ b/qa/qa/scenario/test/sanity/selectors.rb @@ -0,0 +1,14 @@ +module QA + module Scenario + module Test + module Sanity + class Selectors < Scenario::Template + include Scenario::Bootable + + def perform(*) + end + end + end + end + end +end -- cgit v1.2.1 From 208411ee6242931670bdef5a8c92d34dee18498e Mon Sep 17 00:00:00 2001 From: Grzegorz Bizon Date: Fri, 22 Dec 2017 11:54:08 +0100 Subject: Add QA classes that represent view partials and elements --- qa/qa.rb | 2 ++ qa/qa/page/element.rb | 6 ++++++ qa/qa/page/view.rb | 6 ++++++ 3 files changed, 14 insertions(+) create mode 100644 qa/qa/page/element.rb create mode 100644 qa/qa/page/view.rb diff --git a/qa/qa.rb b/qa/qa.rb index 6a878400287..fb3b646564a 100644 --- a/qa/qa.rb +++ b/qa/qa.rb @@ -70,6 +70,8 @@ module QA # module Page autoload :Base, 'qa/page/base' + autoload :View, 'qa/page/view' + autoload :Element, 'qa/page/element' module Main autoload :Login, 'qa/page/main/login' diff --git a/qa/qa/page/element.rb b/qa/qa/page/element.rb new file mode 100644 index 00000000000..c634e834c96 --- /dev/null +++ b/qa/qa/page/element.rb @@ -0,0 +1,6 @@ +module QA + module Page + class Element + end + end +end diff --git a/qa/qa/page/view.rb b/qa/qa/page/view.rb new file mode 100644 index 00000000000..076e4b8061b --- /dev/null +++ b/qa/qa/page/view.rb @@ -0,0 +1,6 @@ +module QA + module Page + class View + end + end +end -- cgit v1.2.1 From 856917520de2b1b254400b4501b4b98991280736 Mon Sep 17 00:00:00 2001 From: Grzegorz Bizon Date: Fri, 22 Dec 2017 13:01:12 +0100 Subject: Add domain specific language to define QA page elements --- qa/qa/page/base.rb | 21 +++++++++++++++++++++ qa/qa/page/element.rb | 26 ++++++++++++++++++++++++++ qa/qa/page/view.rb | 6 ++++++ qa/spec/page/base_spec.rb | 35 +++++++++++++++++++++++++++++++++++ 4 files changed, 88 insertions(+) create mode 100644 qa/spec/page/base_spec.rb diff --git a/qa/qa/page/base.rb b/qa/qa/page/base.rb index 99eba02b6e3..4f79f24a629 100644 --- a/qa/qa/page/base.rb +++ b/qa/qa/page/base.rb @@ -5,6 +5,9 @@ module QA class Base include Capybara::DSL include Scenario::Actable + extend SingleForwardable + + def_delegators :evaluator, :view, :views def refresh visit current_url @@ -40,6 +43,24 @@ module QA def self.path raise NotImplementedError end + + def self.evaluator + @evaluator ||= Page::Base::DSL.new + end + + class DSL + attr_reader :views + + def initialize + @views = [] + end + + def view(path, &block) + Page::Element.evaluate(&block).tap do |elements| + @views.push(Page::View.new(path, elements)) + end + end + end end end end diff --git a/qa/qa/page/element.rb b/qa/qa/page/element.rb index c634e834c96..e8e537070cb 100644 --- a/qa/qa/page/element.rb +++ b/qa/qa/page/element.rb @@ -1,6 +1,32 @@ module QA module Page class Element + attr_reader :name + + def initialize(name, pattern) + @name = name + @pattern = pattern + end + + def self.evaluate(&block) + Page::Element::DSL.new.tap do |evaluator| + evaluator.instance_exec(&block) + + return evaluator.elements + end + end + + class DSL + attr_reader :elements + + def initialize + @elements = [] + end + + def element(name, pattern) + @elements.push(Page::Element.new(name, pattern)) + end + end end end end diff --git a/qa/qa/page/view.rb b/qa/qa/page/view.rb index 076e4b8061b..c54a0d738bc 100644 --- a/qa/qa/page/view.rb +++ b/qa/qa/page/view.rb @@ -1,6 +1,12 @@ module QA module Page class View + attr_reader :path, :elements + + def initialize(path, elements) + @path = path + @elements = elements + end end end end diff --git a/qa/spec/page/base_spec.rb b/qa/spec/page/base_spec.rb new file mode 100644 index 00000000000..31ff9e258a1 --- /dev/null +++ b/qa/spec/page/base_spec.rb @@ -0,0 +1,35 @@ +describe QA::Page::Base do + describe 'page helpers' do + it 'exposes helpful page helpers' do + expect(subject).to respond_to :refresh, :wait, :scroll_to + end + end + + describe 'DSL for defining view partials', '.view' do + subject do + Class.new(described_class) do + view 'path/to/some/view.html.haml' do + element :something, 'string pattern' + element :something_else, /regexp pattern/ + end + + view 'path/to/some/_partial.html.haml' do + element :something, 'string pattern' + end + end + end + + it 'makes it possible to define page views' do + expect(subject.views.size).to eq 2 + expect(subject.views).to all(be_an_instance_of QA::Page::View) + end + + it 'populates views objects with data about elements' do + subject.views.first.elements.tap do |elements| + expect(elements.size).to eq 2 + expect(elements).to all(be_an_instance_of QA::Page::Element) + expect(elements.map(&:name)).to eq [:something, :something_else] + end + end + end +end -- cgit v1.2.1 From b51ba96e4dddd847e42f0e41c3e1df2ff58d42e4 Mon Sep 17 00:00:00 2001 From: Grzegorz Bizon Date: Fri, 22 Dec 2017 13:13:09 +0100 Subject: Move QA elements DSL as it belongs to different class --- qa/qa/page/base.rb | 4 ++-- qa/qa/page/element.rb | 20 -------------------- qa/qa/page/view.rb | 18 ++++++++++++++++++ 3 files changed, 20 insertions(+), 22 deletions(-) diff --git a/qa/qa/page/base.rb b/qa/qa/page/base.rb index 4f79f24a629..d67407e7408 100644 --- a/qa/qa/page/base.rb +++ b/qa/qa/page/base.rb @@ -56,8 +56,8 @@ module QA end def view(path, &block) - Page::Element.evaluate(&block).tap do |elements| - @views.push(Page::View.new(path, elements)) + Page::View.evaluate(&block).tap do |view| + @views.push(Page::View.new(path, view.elements)) end end end diff --git a/qa/qa/page/element.rb b/qa/qa/page/element.rb index e8e537070cb..fae5c81fbc2 100644 --- a/qa/qa/page/element.rb +++ b/qa/qa/page/element.rb @@ -7,26 +7,6 @@ module QA @name = name @pattern = pattern end - - def self.evaluate(&block) - Page::Element::DSL.new.tap do |evaluator| - evaluator.instance_exec(&block) - - return evaluator.elements - end - end - - class DSL - attr_reader :elements - - def initialize - @elements = [] - end - - def element(name, pattern) - @elements.push(Page::Element.new(name, pattern)) - end - end end end end diff --git a/qa/qa/page/view.rb b/qa/qa/page/view.rb index c54a0d738bc..adec88e9918 100644 --- a/qa/qa/page/view.rb +++ b/qa/qa/page/view.rb @@ -7,6 +7,24 @@ module QA @path = path @elements = elements end + + def self.evaluate(&block) + Page::View::DSL.new.tap do |evaluator| + evaluator.instance_exec(&block) + end + end + + class DSL + attr_reader :elements + + def initialize + @elements = [] + end + + def element(name, pattern) + @elements.push(Page::Element.new(name, pattern)) + end + end end end end -- cgit v1.2.1 From 87a36a74ff0e011a69d49f4b2411cae17f975ca9 Mon Sep 17 00:00:00 2001 From: "Ricketts, M (Mike)" Date: Fri, 22 Dec 2017 13:39:06 +0000 Subject: Remove .ssh/environment file that now breaks the gitlab:check rake task --- changelogs/unreleased/38540-ssh-env-file.yml | 6 ++++++ lib/tasks/gitlab/shell.rake | 10 ---------- 2 files changed, 6 insertions(+), 10 deletions(-) create mode 100644 changelogs/unreleased/38540-ssh-env-file.yml diff --git a/changelogs/unreleased/38540-ssh-env-file.yml b/changelogs/unreleased/38540-ssh-env-file.yml new file mode 100644 index 00000000000..5ada0ede76d --- /dev/null +++ b/changelogs/unreleased/38540-ssh-env-file.yml @@ -0,0 +1,6 @@ +--- +title: 'Closes #38540 - Remove .ssh/environment file that now breaks the gitlab:check + rake task' +merge_request: +author: +type: fixed diff --git a/lib/tasks/gitlab/shell.rake b/lib/tasks/gitlab/shell.rake index 0e6aed32c52..12ae4199b69 100644 --- a/lib/tasks/gitlab/shell.rake +++ b/lib/tasks/gitlab/shell.rake @@ -54,16 +54,6 @@ namespace :gitlab do # (Re)create hooks Rake::Task['gitlab:shell:create_hooks'].invoke - # Required for debian packaging with PKGR: Setup .ssh/environment with - # the current PATH, so that the correct ruby version gets loaded - # Requires to set "PermitUserEnvironment yes" in sshd config (should not - # be an issue since it is more than likely that there are no "normal" - # user accounts on a gitlab server). The alternative is for the admin to - # install a ruby (1.9.3+) in the global path. - File.open(File.join(user_home, ".ssh", "environment"), "w+") do |f| - f.puts "PATH=#{ENV['PATH']}" - end - Gitlab::Shell.ensure_secret_token! end -- cgit v1.2.1 From 481f461380d4919077c543c51f58e37337167706 Mon Sep 17 00:00:00 2001 From: Grzegorz Bizon Date: Fri, 22 Dec 2017 15:22:54 +0100 Subject: Add implementation for matching view elements in QA --- qa/qa/page/base.rb | 4 ++++ qa/qa/page/element.rb | 12 ++++++++++ qa/qa/page/validator.rb | 18 ++++++++++++++ qa/qa/page/view.rb | 21 ++++++++++++++++ qa/spec/page/view_spec.rb | 61 +++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 116 insertions(+) create mode 100644 qa/qa/page/validator.rb create mode 100644 qa/spec/page/view_spec.rb diff --git a/qa/qa/page/base.rb b/qa/qa/page/base.rb index d67407e7408..48ac0569596 100644 --- a/qa/qa/page/base.rb +++ b/qa/qa/page/base.rb @@ -48,6 +48,10 @@ module QA @evaluator ||= Page::Base::DSL.new end + def self.validator + Page::Validator.new(self) + end + class DSL attr_reader :views diff --git a/qa/qa/page/element.rb b/qa/qa/page/element.rb index fae5c81fbc2..c47776bb2f6 100644 --- a/qa/qa/page/element.rb +++ b/qa/qa/page/element.rb @@ -7,6 +7,18 @@ module QA @name = name @pattern = pattern end + + def expression? + @pattern.is_a?(Regexp) + end + + def matches?(line) + if expression? + line =~ pattern + else + line.includes?(pattern) + end + end end end end diff --git a/qa/qa/page/validator.rb b/qa/qa/page/validator.rb new file mode 100644 index 00000000000..bd9511595c5 --- /dev/null +++ b/qa/qa/page/validator.rb @@ -0,0 +1,18 @@ +module QA + module Page + class Validator + def initialize(page) + @page = page + @views = page.views + end + + def errors + @errors ||= @views.map do |view| + end + end + + def message + end + end + end +end diff --git a/qa/qa/page/view.rb b/qa/qa/page/view.rb index adec88e9918..ec20045e26d 100644 --- a/qa/qa/page/view.rb +++ b/qa/qa/page/view.rb @@ -8,6 +8,27 @@ module QA @elements = elements end + def pathname + Pathname.new(File.join( __dir__, '../../../', @path)) + .cleanpath.expand_path + end + + def errors + ## + # Reduce required elements by streaming views and making assertions on + # elements' patterns. + # + @missing ||= @elements.dup.tap do |elements| + File.new(pathname.to_s).foreach do |line| + elements.reject! { |element| element.matches?(line) } + end + end + + @missing.map do |missing| + "Missing element `#{missing}` in `#{pathname}` view partial!" + end + end + def self.evaluate(&block) Page::View::DSL.new.tap do |evaluator| evaluator.instance_exec(&block) diff --git a/qa/spec/page/view_spec.rb b/qa/spec/page/view_spec.rb new file mode 100644 index 00000000000..27e83d35de1 --- /dev/null +++ b/qa/spec/page/view_spec.rb @@ -0,0 +1,61 @@ +describe QA::Page::View do + let(:element) do + double('element', name: :something, pattern: /some element/) + end + + subject { described_class.new('some/file.html', [element]) } + + describe '.evaluate' do + it 'evaluates a block and returns a DSL object' do + results = described_class.evaluate do + element :something, 'my pattern' + element :something_else, /another pattern/ + end + + expect(results.elements.size).to eq 2 + end + end + + describe '#pathname' do + it 'returns an absolute and clean path to the view' do + expect(subject.pathname.to_s).not_to include 'qa/page/' + expect(subject.pathname.to_s).to include 'some/file.html' + end + end + + describe '#errors' do + let(:file) { spy('file') } + + before do + allow(File).to receive(:new).and_return(file) + end + + context 'when pattern is found' do + before do + allow(file).to receive(:foreach) + .and_yield('some element').once + allow(element).to receive(:matches?) + .with('some element').and_return(true) + end + + it 'walks through the view and asserts on elements existence' do + expect(subject.errors).to be_empty + end + end + + context 'when pattern has not been found' do + before do + allow(file).to receive(:foreach) + .and_yield('some element').once + allow(element).to receive(:matches?) + .with('some element').and_return(false) + end + + it 'returns an array of errors related to missing elements' do + expect(subject.errors).not_to be_empty + expect(subject.errors.first) + .to match %r(Missing element `.*` in `.*/some/file.html` view) + end + end + end +end -- cgit v1.2.1 From d69e4541a4874208590a7387186f8929143fd2af Mon Sep 17 00:00:00 2001 From: Grzegorz Bizon Date: Fri, 22 Dec 2017 15:40:46 +0100 Subject: Use composite pattern to return page view errors --- qa/qa/page/base.rb | 4 ++-- qa/qa/page/element.rb | 13 ++++++------- qa/qa/page/validator.rb | 18 ------------------ qa/qa/page/view.rb | 4 ++-- qa/spec/page/base_spec.rb | 17 ++++++++++++++++- qa/spec/page/element_spec.rb | 34 ++++++++++++++++++++++++++++++++++ qa/spec/page/view_spec.rb | 4 ++++ 7 files changed, 64 insertions(+), 30 deletions(-) delete mode 100644 qa/qa/page/validator.rb create mode 100644 qa/spec/page/element_spec.rb diff --git a/qa/qa/page/base.rb b/qa/qa/page/base.rb index 48ac0569596..9064c78b792 100644 --- a/qa/qa/page/base.rb +++ b/qa/qa/page/base.rb @@ -48,8 +48,8 @@ module QA @evaluator ||= Page::Base::DSL.new end - def self.validator - Page::Validator.new(self) + def self.errors + @errors ||= views.map(&:errors).flatten end class DSL diff --git a/qa/qa/page/element.rb b/qa/qa/page/element.rb index c47776bb2f6..173fdbf6d36 100644 --- a/qa/qa/page/element.rb +++ b/qa/qa/page/element.rb @@ -8,15 +8,14 @@ module QA @pattern = pattern end - def expression? - @pattern.is_a?(Regexp) - end - def matches?(line) - if expression? - line =~ pattern + case @pattern + when Regexp + !!(line =~ @pattern) + when String + line.include?(@pattern) else - line.includes?(pattern) + raise ArgumentError, 'Pattern should be either String or Regexp!' end end end diff --git a/qa/qa/page/validator.rb b/qa/qa/page/validator.rb deleted file mode 100644 index bd9511595c5..00000000000 --- a/qa/qa/page/validator.rb +++ /dev/null @@ -1,18 +0,0 @@ -module QA - module Page - class Validator - def initialize(page) - @page = page - @views = page.views - end - - def errors - @errors ||= @views.map do |view| - end - end - - def message - end - end - end -end diff --git a/qa/qa/page/view.rb b/qa/qa/page/view.rb index ec20045e26d..b988b179e8f 100644 --- a/qa/qa/page/view.rb +++ b/qa/qa/page/view.rb @@ -15,8 +15,8 @@ module QA def errors ## - # Reduce required elements by streaming views and making assertions on - # elements' patterns. + # Reduce required elements by streaming view and making assertions on + # elements' existence. # @missing ||= @elements.dup.tap do |elements| File.new(pathname.to_s).foreach do |line| diff --git a/qa/spec/page/base_spec.rb b/qa/spec/page/base_spec.rb index 31ff9e258a1..63445d8f7bf 100644 --- a/qa/spec/page/base_spec.rb +++ b/qa/spec/page/base_spec.rb @@ -5,7 +5,7 @@ describe QA::Page::Base do end end - describe 'DSL for defining view partials', '.view' do + describe '.view', 'DSL for defining view partials' do subject do Class.new(described_class) do view 'path/to/some/view.html.haml' do @@ -32,4 +32,19 @@ describe QA::Page::Base do end end end + + describe '.errors' do + let(:view) { double('view') } + + before do + allow(described_class).to receive(:views) + .and_return([view]) + + allow(view).to receive(:errors).and_return(['some error']) + end + + it 'iterates views composite and returns errors' do + expect(described_class.errors).to eq ['some error'] + end + end end diff --git a/qa/spec/page/element_spec.rb b/qa/spec/page/element_spec.rb new file mode 100644 index 00000000000..238c4d1ac66 --- /dev/null +++ b/qa/spec/page/element_spec.rb @@ -0,0 +1,34 @@ +describe QA::Page::Element do + context 'when pattern is an expression' do + subject { described_class.new(:something, /button 'Sign in'/) } + + it 'is correctly matches against a string' do + expect(subject.matches?("button 'Sign in'")).to be true + end + + it 'does not match if string does not match against a pattern' do + expect(subject.matches?("button 'Sign out'")).to be false + end + end + + context 'when pattern is a string' do + subject { described_class.new(:something, 'button') } + + it 'is correctly matches against a string' do + expect(subject.matches?('some button in the view')).to be true + end + + it 'does not match if string does not match against a pattern' do + expect(subject.matches?('text_field :name')).to be false + end + end + + context 'when pattern is not supported' do + subject { described_class.new(:something, [/something/]) } + + it 'raises an error' do + expect { subject.matches?('some line') } + .to raise_error ArgumentError + end + end +end diff --git a/qa/spec/page/view_spec.rb b/qa/spec/page/view_spec.rb index 27e83d35de1..6a78e32db68 100644 --- a/qa/spec/page/view_spec.rb +++ b/qa/spec/page/view_spec.rb @@ -57,5 +57,9 @@ describe QA::Page::View do .to match %r(Missing element `.*` in `.*/some/file.html` view) end end + + context 'when view partial has not been found' do + pending + end end end -- cgit v1.2.1 From d2c2f93fe6ed557ecfbc53afedef899dd49b244d Mon Sep 17 00:00:00 2001 From: Grzegorz Bizon Date: Fri, 22 Dec 2017 16:09:00 +0100 Subject: Append page validation error if view partial is missing --- qa/qa/page/view.rb | 6 +++++- qa/spec/page/view_spec.rb | 51 ++++++++++++++++++++++++++++------------------- 2 files changed, 36 insertions(+), 21 deletions(-) diff --git a/qa/qa/page/view.rb b/qa/qa/page/view.rb index b988b179e8f..fa0ed8be9d9 100644 --- a/qa/qa/page/view.rb +++ b/qa/qa/page/view.rb @@ -9,11 +9,15 @@ module QA end def pathname - Pathname.new(File.join( __dir__, '../../../', @path)) + @pathname ||= Pathname.new(File.join( __dir__, '../../../', @path)) .cleanpath.expand_path end def errors + unless pathname.readable? + return ["Missing view partial `#{pathname}`!"] + end + ## # Reduce required elements by streaming view and making assertions on # elements' existence. diff --git a/qa/spec/page/view_spec.rb b/qa/spec/page/view_spec.rb index 6a78e32db68..dd38b171ad5 100644 --- a/qa/spec/page/view_spec.rb +++ b/qa/spec/page/view_spec.rb @@ -30,36 +30,47 @@ describe QA::Page::View do allow(File).to receive(:new).and_return(file) end - context 'when pattern is found' do + context 'when view partial is present' do before do - allow(file).to receive(:foreach) - .and_yield('some element').once - allow(element).to receive(:matches?) - .with('some element').and_return(true) + allow(subject.pathname).to receive(:readable?) + .and_return(true) end - it 'walks through the view and asserts on elements existence' do - expect(subject.errors).to be_empty - end - end + context 'when pattern is found' do + before do + allow(file).to receive(:foreach) + .and_yield('some element').once + allow(element).to receive(:matches?) + .with('some element').and_return(true) + end - context 'when pattern has not been found' do - before do - allow(file).to receive(:foreach) - .and_yield('some element').once - allow(element).to receive(:matches?) - .with('some element').and_return(false) + it 'walks through the view and asserts on elements existence' do + expect(subject.errors).to be_empty + end end - it 'returns an array of errors related to missing elements' do - expect(subject.errors).not_to be_empty - expect(subject.errors.first) - .to match %r(Missing element `.*` in `.*/some/file.html` view) + context 'when pattern has not been found' do + before do + allow(file).to receive(:foreach) + .and_yield('some element').once + allow(element).to receive(:matches?) + .with('some element').and_return(false) + end + + it 'returns an array of errors related to missing elements' do + expect(subject.errors).not_to be_empty + expect(subject.errors.first) + .to match %r(Missing element `.*` in `.*/some/file.html` view) + end end end context 'when view partial has not been found' do - pending + it 'returns an error when it is not able to find the partial' do + expect(subject.errors).to be_one + expect(subject.errors.first) + .to match %r(Missing view partial `.*/some/file.html`!) + end end end end -- cgit v1.2.1 From 8139895b4362817cf947431fab9c95ce223b87ae Mon Sep 17 00:00:00 2001 From: Lin Jen-Shin Date: Mon, 25 Dec 2017 18:20:50 +0800 Subject: Use `Gitlab::Utils::Override` over defined?(super) --- doc/development/ee_features.md | 17 ++-- lib/gitlab/utils/override.rb | 111 +++++++++++++++++++++++ lib/tasks/dev.rake | 5 ++ lib/tasks/lint.rake | 12 +++ scripts/static-analysis | 5 +- spec/lib/gitlab/utils/override_spec.rb | 158 +++++++++++++++++++++++++++++++++ 6 files changed, 299 insertions(+), 9 deletions(-) create mode 100644 lib/gitlab/utils/override.rb create mode 100644 spec/lib/gitlab/utils/override_spec.rb diff --git a/doc/development/ee_features.md b/doc/development/ee_features.md index 1af839a27e1..b4b5b47c099 100644 --- a/doc/development/ee_features.md +++ b/doc/development/ee_features.md @@ -87,9 +87,9 @@ still having access the class's implementation with `super`. There are a few gotchas with it: -- you should always add a `raise NotImplementedError unless defined?(super)` - guard clause in the "overrider" method to ensure that if the method gets - renamed in CE, the EE override won't be silently forgotten. +- you should always `extend ::Gitlab::Utils::Override` and use `override` to + guard the "overrider" method to ensure that if the method gets renamed in + CE, the EE override won't be silently forgotten. - when the "overrider" would add a line in the middle of the CE implementation, you should refactor the CE method and split it in smaller methods. Or create a "hook" method that is empty in CE, @@ -134,6 +134,9 @@ There are a few gotchas with it: guards: ``` ruby module EE::Base + extend ::Gitlab::Utils::Override + + override :do_something def do_something # Follow the above pattern to call super and extend it end @@ -174,10 +177,11 @@ implementation: ```ruby module EE - class ApplicationController - def after_sign_out_path_for(resource) - raise NotImplementedError unless defined?(super) + module ApplicationController + extend ::Gitlab::Utils::Override + override :after_sign_out_path_for + def after_sign_out_path_for(resource) if Gitlab::Geo.secondary? Gitlab::Geo.primary_node.oauth_logout_url(@geo_logout_state) else @@ -209,7 +213,6 @@ In EE, the implementation `ee/app/models/ee/users.rb` would be: ```ruby def full_private_access? - raise NotImplementedError unless defined?(super) super || auditor? end ``` diff --git a/lib/gitlab/utils/override.rb b/lib/gitlab/utils/override.rb new file mode 100644 index 00000000000..8bf6bcb1fe2 --- /dev/null +++ b/lib/gitlab/utils/override.rb @@ -0,0 +1,111 @@ +module Gitlab + module Utils + module Override + class Extension + def self.verify_class!(klass, method_name) + instance_method_defined?(klass, method_name) || + raise( + NotImplementedError.new( + "#{klass}\##{method_name} doesn't exist!")) + end + + def self.instance_method_defined?(klass, name, include_super: true) + klass.instance_methods(include_super).include?(name) || + klass.private_instance_methods(include_super).include?(name) + end + + attr_reader :subject + + def initialize(subject) + @subject = subject + end + + def add_method_name(method_name) + method_names << method_name + end + + def add_class(klass) + classes << klass + end + + def verify! + classes.each do |klass| + index = klass.ancestors.index(subject) + parents = klass.ancestors.drop(index + 1) + + method_names.each do |method_name| + parents.any? do |parent| + self.class.instance_method_defined?( + parent, method_name, include_super: false) + end || + raise( + NotImplementedError.new( + "#{klass}\##{method_name} doesn't exist!")) + end + end + end + + private + + def method_names + @method_names ||= [] + end + + def classes + @classes ||= [] + end + end + + # Instead of writing patterns like this: + # + # def f + # raise NotImplementedError unless defined?(super) + # + # true + # end + # + # We could write it like: + # + # extend ::Gitlab::Utils::Override + # + # override :f + # def f + # true + # end + # + # This would make sure we're overriding something. See: + # https://gitlab.com/gitlab-org/gitlab-ee/issues/1819 + def override(method_name) + return unless ENV['STATIC_VERIFICATION'] + + if is_a?(Class) + Extension.verify_class!(self, method_name) + else # We delay the check for modules + Override.extensions[self] ||= Extension.new(self) + Override.extensions[self].add_method_name(method_name) + end + end + + def included(base = nil) + return super if base.nil? # Rails concern, ignoring it + + super + + if base.is_a?(Class) # We could check for Class in `override` + # This could be `nil` if `override` was never called + Override.extensions[self]&.add_class(base) + end + end + + alias_method :prepended, :included + + def self.extensions + @extensions ||= {} + end + + def self.verify! + extensions.values.each(&:verify!) + end + end + end +end diff --git a/lib/tasks/dev.rake b/lib/tasks/dev.rake index e65609d7001..4beb94eeb8e 100644 --- a/lib/tasks/dev.rake +++ b/lib/tasks/dev.rake @@ -7,4 +7,9 @@ namespace :dev do Rake::Task["gitlab:setup"].invoke Rake::Task["gitlab:shell:setup"].invoke end + + desc "GitLab | Eager load application" + task load: :environment do + Rails.application.eager_load! + end end diff --git a/lib/tasks/lint.rake b/lib/tasks/lint.rake index 7b63e93db0e..3ab406eff2c 100644 --- a/lib/tasks/lint.rake +++ b/lib/tasks/lint.rake @@ -1,5 +1,17 @@ unless Rails.env.production? namespace :lint do + task :static_verification_env do + ENV['STATIC_VERIFICATION'] = 'true' + end + + desc "GitLab | lint | Static verification" + task static_verification: %w[ + lint:static_verification_env + dev:load + ] do + Gitlab::Utils::Override.verify! + end + desc "GitLab | lint | Lint JavaScript files using ESLint" task :javascript do Rake::Task['eslint'].invoke diff --git a/scripts/static-analysis b/scripts/static-analysis index 2a2bc67800d..9690b42c788 100755 --- a/scripts/static-analysis +++ b/scripts/static-analysis @@ -10,9 +10,10 @@ tasks = [ %w[bundle exec license_finder], %w[yarn run eslint], %w[bundle exec rubocop --parallel], - %w[scripts/lint-conflicts.sh], %w[bundle exec rake gettext:lint], - %w[scripts/lint-changelog-yaml] + %w[bundle exec rake lint:static_verification], + %w[scripts/lint-changelog-yaml], + %w[scripts/lint-conflicts.sh] ] failed_tasks = tasks.reduce({}) do |failures, task| diff --git a/spec/lib/gitlab/utils/override_spec.rb b/spec/lib/gitlab/utils/override_spec.rb new file mode 100644 index 00000000000..7c97cee982a --- /dev/null +++ b/spec/lib/gitlab/utils/override_spec.rb @@ -0,0 +1,158 @@ +require 'spec_helper' + +describe Gitlab::Utils::Override do + let(:base) { Struct.new(:good) } + + let(:derived) { Class.new(base).tap { |m| m.extend described_class } } + let(:extension) { Module.new.tap { |m| m.extend described_class } } + + let(:prepending_class) { base.tap { |m| m.prepend extension } } + let(:including_class) { base.tap { |m| m.include extension } } + + let(:klass) { subject } + + def good(mod) + mod.module_eval do + override :good + def good + super.succ + end + end + + mod + end + + def bad(mod) + mod.module_eval do + override :bad + def bad + true + end + end + + mod + end + + shared_examples 'checking as intended' do + it 'checks ok for overriding method' do + good(subject) + result = klass.new(0).good + + expect(result).to eq(1) + described_class.verify! + end + + it 'raises NotImplementedError when it is not overriding anything' do + expect do + bad(subject) + klass.new(0).bad + described_class.verify! + end.to raise_error(NotImplementedError) + end + end + + shared_examples 'nothing happened' do + it 'does not complain when it is overriding something' do + good(subject) + result = klass.new(0).good + + expect(result).to eq(1) + described_class.verify! + end + + it 'does not complain when it is not overriding anything' do + bad(subject) + result = klass.new(0).bad + + expect(result).to eq(true) + described_class.verify! + end + end + + before do + # Make sure we're not touching the internal cache + allow(described_class).to receive(:extensions).and_return({}) + end + + describe '#override' do + context 'when STATIC_VERIFICATION is set' do + before do + stub_env('STATIC_VERIFICATION', 'true') + end + + context 'when subject is a class' do + subject { derived } + + it_behaves_like 'checking as intended' + end + + context 'when subject is a module, and class is prepending it' do + subject { extension } + let(:klass) { prepending_class } + + it_behaves_like 'checking as intended' + end + + context 'when subject is a module, and class is including it' do + subject { extension } + let(:klass) { including_class } + + it 'raises NotImplementedError because it is not overriding it' do + expect do + good(subject) + klass.new(0).good + described_class.verify! + end.to raise_error(NotImplementedError) + end + + it 'raises NotImplementedError when it is not overriding anything' do + expect do + bad(subject) + klass.new(0).bad + described_class.verify! + end.to raise_error(NotImplementedError) + end + end + end + end + + context 'when STATIC_VERIFICATION is not set' do + before do + stub_env('STATIC_VERIFICATION', nil) + end + + context 'when subject is a class' do + subject { derived } + + it_behaves_like 'nothing happened' + end + + context 'when subject is a module, and class is prepending it' do + subject { extension } + let(:klass) { prepending_class } + + it_behaves_like 'nothing happened' + end + + context 'when subject is a module, and class is including it' do + subject { extension } + let(:klass) { including_class } + + it 'does not complain when it is overriding something' do + good(subject) + result = klass.new(0).good + + expect(result).to eq(0) + described_class.verify! + end + + it 'does not complain when it is not overriding anything' do + bad(subject) + result = klass.new(0).bad + + expect(result).to eq(true) + described_class.verify! + end + end + end +end -- cgit v1.2.1 From f4bd9c0b5e1eafe6de855d73bfb606909229f382 Mon Sep 17 00:00:00 2001 From: Lin Jen-Shin Date: Tue, 26 Dec 2017 14:36:33 +0800 Subject: Skip sha_attribute if we're checking statically --- app/models/concerns/sha_attribute.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/app/models/concerns/sha_attribute.rb b/app/models/concerns/sha_attribute.rb index 67ecf470f7e..703a72c355c 100644 --- a/app/models/concerns/sha_attribute.rb +++ b/app/models/concerns/sha_attribute.rb @@ -3,6 +3,7 @@ module ShaAttribute module ClassMethods def sha_attribute(name) + return if ENV['STATIC_VERIFICATION'] return unless table_exists? column = columns.find { |c| c.name == name.to_s } -- cgit v1.2.1 From e5eb6710cb07ddc9dc7ac1731663349ee699d7db Mon Sep 17 00:00:00 2001 From: Drew Blessing Date: Wed, 27 Dec 2017 20:06:50 +0000 Subject: Add note about only 20 commits being included in push payload --- doc/user/project/integrations/webhooks.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/doc/user/project/integrations/webhooks.md b/doc/user/project/integrations/webhooks.md index eafdd28071d..82175c70e49 100644 --- a/doc/user/project/integrations/webhooks.md +++ b/doc/user/project/integrations/webhooks.md @@ -54,6 +54,12 @@ Below are described the supported events. Triggered when you push to the repository except when pushing tags. +> **Note:** When more than 20 commits are pushed at once, the `commits` web hook + attribute will only contain the first 20 for performance reasons. Loading + detailed commit data is expensive. Note that despite only 20 commits being + present in the `commits` attribute, the `total_commits_count` attribute will + contain the actual total. + **Request header**: ``` -- cgit v1.2.1 From ea7f6fa80bb9699585a330f084331ea0f74500de Mon Sep 17 00:00:00 2001 From: Robert Speicher Date: Thu, 28 Dec 2017 16:46:10 -0600 Subject: Fix the header level for the Changelog Arguments documentation --- doc/development/changelog.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/development/changelog.md b/doc/development/changelog.md index 48cffc0dd18..18f4177a5e5 100644 --- a/doc/development/changelog.md +++ b/doc/development/changelog.md @@ -127,7 +127,7 @@ type: If you're working on the GitLab EE repository, the entry will be added to `changelogs/unreleased-ee/` instead. -#### Arguments +### Arguments | Argument | Shorthand | Purpose | | ----------------- | --------- | ---------------------------------------------------------------------------------------------------------- | -- cgit v1.2.1 From 3d5e4e34ca30f083e0f6ea0bbfe1a28c2f8f4b63 Mon Sep 17 00:00:00 2001 From: Onuwa Nnachi Isaac Date: Tue, 2 Jan 2018 19:06:11 +0100 Subject: Fix typo in writing_documentation.md --- doc/development/writing_documentation.md | 4 ++-- doc/doc | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) create mode 120000 doc/doc diff --git a/doc/development/writing_documentation.md b/doc/development/writing_documentation.md index 43a79ffcaa5..133ac0234cf 100644 --- a/doc/development/writing_documentation.md +++ b/doc/development/writing_documentation.md @@ -15,7 +15,7 @@ request introducing these changes must be accompanied by the documentation (either updating existing ones or creating new ones). This is also valid when changes are introduced to the UI. -The one resposible for writing the first piece of documentation is the developer who +The one responsible for writing the first piece of documentation is the developer who wrote the code. It's the job of the Product Manager to ensure all features are shipped with its docs, whether is a small or big change. At the pace GitLab evolves, this is the only way to keep the docs up-to-date. If you have any questions about it, @@ -31,7 +31,7 @@ Every major feature (regardless if present in GitLab Community or Enterprise edi should present, at the beginning of the document, two main sections: **overview** and **use cases**. Every GitLab EE-only feature should also contain these sections. -**Overview**: at the name suggests, the goal here is to provide an overview of the feature. +**Overview**: as the name suggests, the goal here is to provide an overview of the feature. Describe what is it, what it does, why it is important/cool/nice-to-have, what problem it solves, and what you can do with this feature that you couldn't do before. diff --git a/doc/doc b/doc/doc new file mode 120000 index 00000000000..e78a24e7fe6 --- /dev/null +++ b/doc/doc @@ -0,0 +1 @@ +/home/isaac/apps/opensource/GitLab/gitlab-ce/doc \ No newline at end of file -- cgit v1.2.1 From cc171725b6feafc62b42c2570e72e51f67b1d4d5 Mon Sep 17 00:00:00 2001 From: Takuya Noguchi Date: Wed, 3 Jan 2018 03:59:48 +0900 Subject: Make project README containers wider on fixed layout --- app/assets/stylesheets/framework/files.scss | 2 +- changelogs/unreleased/41600-wider-project-readme-on-fixed-layout.yml | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) create mode 100644 changelogs/unreleased/41600-wider-project-readme-on-fixed-layout.yml diff --git a/app/assets/stylesheets/framework/files.scss b/app/assets/stylesheets/framework/files.scss index 1588036aeae..223a8b3ba2f 100644 --- a/app/assets/stylesheets/framework/files.scss +++ b/app/assets/stylesheets/framework/files.scss @@ -18,7 +18,7 @@ margin: $gl-padding 0; &.limited-width-container .file-content { - max-width: $limited-layout-width-sm; + max-width: $limited-layout-width; margin-left: auto; margin-right: auto; diff --git a/changelogs/unreleased/41600-wider-project-readme-on-fixed-layout.yml b/changelogs/unreleased/41600-wider-project-readme-on-fixed-layout.yml new file mode 100644 index 00000000000..e50f6046b17 --- /dev/null +++ b/changelogs/unreleased/41600-wider-project-readme-on-fixed-layout.yml @@ -0,0 +1,5 @@ +--- +title: Make project README containers wider on fixed layout +merge_request: 16181 +author: Takuya Noguchi +type: fixed -- cgit v1.2.1 From ca2351073420ec9b45642388b78f2462aec7b11d Mon Sep 17 00:00:00 2001 From: Robert Speicher Date: Tue, 2 Jan 2018 14:20:42 -0600 Subject: Update rack-cors from 0.4.0 to 1.0.2 --- Gemfile | 2 +- Gemfile.lock | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Gemfile b/Gemfile index 5ed0f93be75..f4098d26290 100644 --- a/Gemfile +++ b/Gemfile @@ -78,7 +78,7 @@ gem 'github-linguist', '~> 4.7.0', require: 'linguist' # API gem 'grape', '~> 1.0' gem 'grape-entity', '~> 0.6.0' -gem 'rack-cors', '~> 0.4.0', require: 'rack/cors' +gem 'rack-cors', '~> 1.0.0', require: 'rack/cors' # Disable strong_params so that Mash does not respond to :permitted? gem 'hashie-forbidden_attributes' diff --git a/Gemfile.lock b/Gemfile.lock index 3cffed4901b..b5c233946ef 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -651,7 +651,7 @@ GEM rack (>= 0.4) rack-attack (4.4.1) rack - rack-cors (0.4.0) + rack-cors (1.0.2) rack-oauth2 (1.2.3) activesupport (>= 2.3) attr_required (>= 0.0.5) @@ -1126,7 +1126,7 @@ DEPENDENCIES pry-byebug (~> 3.4.1) pry-rails (~> 0.3.4) rack-attack (~> 4.4.1) - rack-cors (~> 0.4.0) + rack-cors (~> 1.0.0) rack-oauth2 (~> 1.2.1) rack-proxy (~> 0.6.0) rails (= 4.2.10) @@ -1205,4 +1205,4 @@ DEPENDENCIES wikicloth (= 0.8.1) BUNDLED WITH - 1.16.0 + 1.16.1 -- cgit v1.2.1 From 4963f39141208b91be52f7ae6dbdc2d885b4db3c Mon Sep 17 00:00:00 2001 From: George Tsiolis Date: Wed, 3 Jan 2018 21:04:42 +0200 Subject: Fix dashboard projects nav links height --- app/views/dashboard/projects/_nav.html.haml | 2 +- changelogs/unreleased/fix-dashboard-projects-nav-links-height.yml | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) create mode 100644 changelogs/unreleased/fix-dashboard-projects-nav-links-height.yml diff --git a/app/views/dashboard/projects/_nav.html.haml b/app/views/dashboard/projects/_nav.html.haml index 3701e1c0578..c18077bc66f 100644 --- a/app/views/dashboard/projects/_nav.html.haml +++ b/app/views/dashboard/projects/_nav.html.haml @@ -1,4 +1,4 @@ -.top-area +.nav-block %ul.nav-links = nav_link(html_options: { class: ("active" unless params[:personal].present?) }) do = link_to s_('DashboardProjects|All'), dashboard_projects_path diff --git a/changelogs/unreleased/fix-dashboard-projects-nav-links-height.yml b/changelogs/unreleased/fix-dashboard-projects-nav-links-height.yml new file mode 100644 index 00000000000..2f6a07bb234 --- /dev/null +++ b/changelogs/unreleased/fix-dashboard-projects-nav-links-height.yml @@ -0,0 +1,5 @@ +--- +title: Fix dashboard projects nav links height +merge_request: 16204 +author: George Tsiolis +type: fixed -- cgit v1.2.1 From b299198e1eb5e1f26d5267f4a64944e600086d6b Mon Sep 17 00:00:00 2001 From: Filipa Lacerda Date: Wed, 3 Jan 2018 23:14:55 +0000 Subject: Adds `eslint-plugin-vue`, fixes linter errors and adds docs --- .eslintrc | 9 +- app/assets/javascripts/blob/notebook/index.js | 76 ++++---- app/assets/javascripts/blob/pdf/index.js | 6 +- app/assets/javascripts/boards/boards_bundle.js | 18 +- .../clusters/components/applications.vue | 32 ++-- app/assets/javascripts/commit/image_file.js | 194 ++++++++++----------- .../cycle_analytics/cycle_analytics_bundle.js | 20 +-- app/assets/javascripts/deploy_keys/index.js | 6 +- .../environments/components/environment_item.vue | 3 +- .../filtered_search/recent_searches_root.js | 6 +- .../javascripts/groups/components/group_folder.vue | 6 +- .../javascripts/groups/components/item_stats.vue | 7 +- .../ide/components/repo_commit_section.vue | 4 +- app/assets/javascripts/ide/index.js | 10 +- .../issue_show/components/description.vue | 6 +- app/assets/javascripts/jobs/job_details_bundle.js | 12 +- .../merge_conflicts/merge_conflicts_bundle.js | 2 +- .../monitoring/components/empty_state.vue | 6 +- .../javascripts/notes/components/comment_form.vue | 14 +- .../notes/components/noteable_discussion.vue | 3 +- .../components/graph/dropdown_job_component.vue | 3 +- .../pipelines/components/pipeline_url.vue | 12 +- .../javascripts/pipelines/components/stage.vue | 4 +- .../pipelines/pipeline_details_bundle.js | 12 +- .../javascripts/pipelines/pipelines_bundle.js | 6 +- .../account/components/delete_account_modal.vue | 3 +- .../confidential/confidential_issue_sidebar.vue | 5 +- .../sidebar/components/lock/lock_issue_sidebar.vue | 3 +- doc/development/fe_guide/style_guide_js.md | 14 +- package.json | 1 + spec/javascripts/boards/issue_card_spec.js | 6 +- .../vue_shared/components/markdown/field_spec.js | 6 +- yarn.lock | 44 +++++ 33 files changed, 333 insertions(+), 226 deletions(-) diff --git a/.eslintrc b/.eslintrc index 44ad6a4896c..a419dc521e8 100644 --- a/.eslintrc +++ b/.eslintrc @@ -4,7 +4,10 @@ "browser": true, "es6": true }, - "extends": "airbnb-base", + "extends": [ + "airbnb-base", + "plugin:vue/recommended" + ], "globals": { "__webpack_public_path__": true, "_": false, @@ -12,7 +15,9 @@ "gon": false, "localStorage": false }, - "parser": "babel-eslint", + "parserOptions": { + "parser": "babel-eslint" + }, "plugins": [ "filenames", "import", diff --git a/app/assets/javascripts/blob/notebook/index.js b/app/assets/javascripts/blob/notebook/index.js index 57b031956e8..6f1350e80fc 100644 --- a/app/assets/javascripts/blob/notebook/index.js +++ b/app/assets/javascripts/blob/notebook/index.js @@ -8,6 +8,9 @@ export default () => { new Vue({ el, + components: { + notebookLab, + }, data() { return { error: false, @@ -16,8 +19,41 @@ export default () => { json: {}, }; }, - components: { - notebookLab, + mounted() { + if (gon.katex_css_url) { + const katexStyles = document.createElement('link'); + katexStyles.setAttribute('rel', 'stylesheet'); + katexStyles.setAttribute('href', gon.katex_css_url); + document.head.appendChild(katexStyles); + } + + if (gon.katex_js_url) { + const katexScript = document.createElement('script'); + katexScript.addEventListener('load', () => { + this.loadFile(); + }); + katexScript.setAttribute('src', gon.katex_js_url); + document.head.appendChild(katexScript); + } else { + this.loadFile(); + } + }, + methods: { + loadFile() { + axios.get(el.dataset.endpoint) + .then(res => res.data) + .then((data) => { + this.json = data; + this.loading = false; + }) + .catch((e) => { + if (e.status !== 200) { + this.loadError = true; + } + + this.error = true; + }); + }, }, template: `
@@ -46,41 +82,5 @@ export default () => {

`, - methods: { - loadFile() { - axios.get(el.dataset.endpoint) - .then(res => res.data) - .then((data) => { - this.json = data; - this.loading = false; - }) - .catch((e) => { - if (e.status !== 200) { - this.loadError = true; - } - - this.error = true; - }); - }, - }, - mounted() { - if (gon.katex_css_url) { - const katexStyles = document.createElement('link'); - katexStyles.setAttribute('rel', 'stylesheet'); - katexStyles.setAttribute('href', gon.katex_css_url); - document.head.appendChild(katexStyles); - } - - if (gon.katex_js_url) { - const katexScript = document.createElement('script'); - katexScript.addEventListener('load', () => { - this.loadFile(); - }); - katexScript.setAttribute('src', gon.katex_js_url); - document.head.appendChild(katexScript); - } else { - this.loadFile(); - } - }, }); }; diff --git a/app/assets/javascripts/blob/pdf/index.js b/app/assets/javascripts/blob/pdf/index.js index 7109f356540..70136cc4087 100644 --- a/app/assets/javascripts/blob/pdf/index.js +++ b/app/assets/javascripts/blob/pdf/index.js @@ -7,6 +7,9 @@ export default () => { return new Vue({ el, + components: { + pdfLab, + }, data() { return { error: false, @@ -15,9 +18,6 @@ export default () => { pdf: el.dataset.endpoint, }; }, - components: { - pdfLab, - }, methods: { onLoad() { this.loading = false; diff --git a/app/assets/javascripts/boards/boards_bundle.js b/app/assets/javascripts/boards/boards_bundle.js index 679c883cdcf..90166b3d3d1 100644 --- a/app/assets/javascripts/boards/boards_bundle.js +++ b/app/assets/javascripts/boards/boards_bundle.js @@ -171,19 +171,14 @@ $(() => { }); gl.IssueBoardsModalAddBtn = new Vue({ - mixins: [gl.issueBoards.ModalMixins], el: document.getElementById('js-add-issues-btn'), + mixins: [gl.issueBoards.ModalMixins], data() { return { modal: ModalStore.store, store: Store.state, }; }, - watch: { - disabled() { - this.updateTooltip(); - }, - }, computed: { disabled() { if (!this.store) { @@ -199,6 +194,14 @@ $(() => { return ''; }, }, + watch: { + disabled() { + this.updateTooltip(); + }, + }, + mounted() { + this.updateTooltip(); + }, methods: { updateTooltip() { const $tooltip = $(this.$refs.addIssuesButton); @@ -217,9 +220,6 @@ $(() => { } }, }, - mounted() { - this.updateTooltip(); - }, template: `