From 4f72293aaf36de46a0bd1615e7a4b2da92414be8 Mon Sep 17 00:00:00 2001 From: Mark Fletcher Date: Thu, 11 Jul 2019 14:15:34 +0100 Subject: Danger asks for throughput labels --- danger/metadata/Dangerfile | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/danger/metadata/Dangerfile b/danger/metadata/Dangerfile index 1adca152736..f2d68e64eb6 100644 --- a/danger/metadata/Dangerfile +++ b/danger/metadata/Dangerfile @@ -1,5 +1,13 @@ # rubocop:disable Style/SignalException +THROUGHPUT_LABELS = [ + 'Community contribution', + 'security', + 'bug', + 'feature', + 'backstage' +].freeze + if gitlab.mr_body.size < 5 fail "Please provide a proper merge request description." end @@ -8,6 +16,10 @@ if gitlab.mr_labels.empty? fail "Please add labels to this merge request." end +if (THROUGHPUT_LABELS & gitlab.mr_labels).empty? + warn 'Please add a [throughput label](https://about.gitlab.com/handbook/engineering/management/throughput/#implementation) to this merge request.' +end + unless gitlab.mr_json["assignee"] warn "This merge request does not have any assignee yet. Setting an assignee clarifies who needs to take action on the merge request at any given time." end -- cgit v1.2.1 From ff0654b0b46df4d143c3ec6bb4fa92da34745e44 Mon Sep 17 00:00:00 2001 From: John Cai Date: Thu, 11 Jul 2019 09:53:38 -0700 Subject: Add unset_rugged rake task Adds an unset_rugged rake task that unsets all rugged feature flags. Also fixes the existing disable_rugged task to have it explicitly disable feature flags instead of just unsetting them. --- lib/tasks/gitlab/features.rake | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/lib/tasks/gitlab/features.rake b/lib/tasks/gitlab/features.rake index d88bcca0819..9cf568c07fe 100644 --- a/lib/tasks/gitlab/features.rake +++ b/lib/tasks/gitlab/features.rake @@ -10,14 +10,22 @@ namespace :gitlab do set_rugged_feature_flags(false) puts 'All Rugged feature flags were disabled.' end + + task unset_rugged: :environment do + set_rugged_feature_flags(nil) + puts 'All Rugged feature flags were unset.' + end end def set_rugged_feature_flags(status) Gitlab::Git::RuggedImpl::Repository::FEATURE_FLAGS.each do |flag| - if status - Feature.enable(flag) - else + case status + when nil Feature.get(flag).remove + when true + Feature.enable(flag) + when false + Feature.disable(flag) end end end -- cgit v1.2.1 From b9d43e27b294e0ac18421e4e0540ba2c5fd80d15 Mon Sep 17 00:00:00 2001 From: drew cimino Date: Tue, 25 Jun 2019 17:05:18 -0400 Subject: Added specs for Ci::Pipeline::Seed::Build - #included? when only: and except: both match --- spec/lib/gitlab/ci/pipeline/seed/build_spec.rb | 57 ++++++++++++++++++++++---- 1 file changed, 49 insertions(+), 8 deletions(-) diff --git a/spec/lib/gitlab/ci/pipeline/seed/build_spec.rb b/spec/lib/gitlab/ci/pipeline/seed/build_spec.rb index 7991e2f48b5..633000ec8fe 100644 --- a/spec/lib/gitlab/ci/pipeline/seed/build_spec.rb +++ b/spec/lib/gitlab/ci/pipeline/seed/build_spec.rb @@ -3,14 +3,9 @@ require 'spec_helper' describe Gitlab::Ci::Pipeline::Seed::Build do let(:project) { create(:project, :repository) } let(:pipeline) { create(:ci_empty_pipeline, project: project) } + let(:attributes) { { name: 'rspec', ref: 'master' } } - let(:attributes) do - { name: 'rspec', ref: 'master' } - end - - subject do - described_class.new(pipeline, attributes) - end + subject { described_class.new(pipeline, attributes) } describe '#attributes' do it 'returns hash attributes of a build' do @@ -76,7 +71,7 @@ describe Gitlab::Ci::Pipeline::Seed::Build do end end - describe 'applying only/except policies' do + describe 'applying job inclusion policies' do context 'when no branch policy is specified' do let(:attributes) { { name: 'rspec' } } @@ -95,6 +90,12 @@ describe Gitlab::Ci::Pipeline::Seed::Build do it { is_expected.to be_included } end + + context 'with both only and except policies' do + let(:attributes) { { name: 'rspec', only: { refs: %w(deploy) }, except: { refs: %(deploy) } } } + + it { is_expected.not_to be_included } + end end context 'when branch regexp policy does not match' do @@ -109,6 +110,12 @@ describe Gitlab::Ci::Pipeline::Seed::Build do it { is_expected.to be_included } end + + context 'with both only and except policies' do + let(:attributes) { { name: 'rspec', only: { refs: %w(/^deploy$/) }, except: { refs: %w(/^deploy$/) } } } + + it { is_expected.not_to be_included } + end end context 'when branch policy matches' do @@ -123,6 +130,12 @@ describe Gitlab::Ci::Pipeline::Seed::Build do it { is_expected.not_to be_included } end + + context 'when using both only and except policies' do + let(:attributes) { { name: 'rspec', only: { refs: %w(deploy master) }, except: { refs: %w(deploy master) } } } + + it { is_expected.not_to be_included } + end end context 'when keyword policy matches' do @@ -137,6 +150,12 @@ describe Gitlab::Ci::Pipeline::Seed::Build do it { is_expected.not_to be_included } end + + context 'when using both only and except policies' do + let(:attributes) { { name: 'rspec', only: { refs: %w(branches) }, except: { refs: %(branches) } } } + + it { is_expected.not_to be_included } + end end context 'when keyword policy does not match' do @@ -151,6 +170,12 @@ describe Gitlab::Ci::Pipeline::Seed::Build do it { is_expected.to be_included } end + + context 'when using both only and except policies' do + let(:attributes) { { name: 'rspec', only: { refs: %(tags) }, except: { refs: %(tags) } } } + + it { is_expected.not_to be_included } + end end context 'with source-keyword policy' do @@ -239,6 +264,14 @@ describe Gitlab::Ci::Pipeline::Seed::Build do it { is_expected.not_to be_included } end + + context 'when using both only and except policies' do + let(:attributes) do + { name: 'rspec', only: { refs: ["branches@#{pipeline.project_full_path}"] }, except: { refs: ["branches@#{pipeline.project_full_path}"] } } + end + + it { is_expected.not_to be_included } + end end context 'when repository path does not matches' do @@ -257,6 +290,14 @@ describe Gitlab::Ci::Pipeline::Seed::Build do it { is_expected.to be_included } end + + context 'when using both only and except policies' do + let(:attributes) do + { name: 'rspec', only: { refs: ['branches@fork'] }, except: { refs: ['branches@fork'] } } + end + + it { is_expected.not_to be_included } + end end end end -- cgit v1.2.1 From 24941101483421f2661c040be0fb7612df40d375 Mon Sep 17 00:00:00 2001 From: drew cimino Date: Tue, 25 Jun 2019 18:46:28 -0400 Subject: Polish for Ci::Pipeline::Seed::Build specs --- spec/lib/gitlab/ci/pipeline/seed/build_spec.rb | 205 +++++++++++++++++-------- 1 file changed, 143 insertions(+), 62 deletions(-) diff --git a/spec/lib/gitlab/ci/pipeline/seed/build_spec.rb b/spec/lib/gitlab/ci/pipeline/seed/build_spec.rb index 633000ec8fe..e0bff638233 100644 --- a/spec/lib/gitlab/ci/pipeline/seed/build_spec.rb +++ b/spec/lib/gitlab/ci/pipeline/seed/build_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitlab::Ci::Pipeline::Seed::Build do @@ -5,23 +7,24 @@ describe Gitlab::Ci::Pipeline::Seed::Build do let(:pipeline) { create(:ci_empty_pipeline, project: project) } let(:attributes) { { name: 'rspec', ref: 'master' } } - subject { described_class.new(pipeline, attributes) } + let(:seed_build) { described_class.new(pipeline, attributes) } describe '#attributes' do - it 'returns hash attributes of a build' do - expect(subject.attributes).to be_a Hash - expect(subject.attributes) - .to include(:name, :project, :ref) - end + subject { seed_build.attributes } + + it { is_expected.to be_a(Hash) } + it { is_expected.to include(:name, :project, :ref) } end describe '#bridge?' do + subject { seed_build.bridge? } + context 'when job is a bridge' do let(:attributes) do { name: 'rspec', ref: 'master', options: { trigger: 'my/project' } } end - it { is_expected.to be_bridge } + it { is_expected.to be_truthy } end context 'when trigger definition is empty' do @@ -29,20 +32,20 @@ describe Gitlab::Ci::Pipeline::Seed::Build do { name: 'rspec', ref: 'master', options: { trigger: '' } } end - it { is_expected.not_to be_bridge } + it { is_expected.to be_falsey } end context 'when job is not a bridge' do - it { is_expected.not_to be_bridge } + it { is_expected.to be_falsey } end end describe '#to_resource' do + subject { seed_build.to_resource } + context 'when job is not a bridge' do - it 'returns a valid build resource' do - expect(subject.to_resource).to be_a(::Ci::Build) - expect(subject.to_resource).to be_valid - end + it { is_expected.to be_a(::Ci::Build) } + it { is_expected.to be_valid } end context 'when job is a bridge' do @@ -50,49 +53,57 @@ describe Gitlab::Ci::Pipeline::Seed::Build do { name: 'rspec', ref: 'master', options: { trigger: 'my/project' } } end - it 'returns a valid bridge resource' do - expect(subject.to_resource).to be_a(::Ci::Bridge) - expect(subject.to_resource).to be_valid - end + it { is_expected.to be_a(::Ci::Bridge) } + it { is_expected.to be_valid } end it 'memoizes a resource object' do - build = subject.to_resource - - expect(build.object_id).to eq subject.to_resource.object_id + expect(subject.object_id).to eq seed_build.to_resource.object_id end it 'can not be persisted without explicit assignment' do - build = subject.to_resource - pipeline.save! - expect(build).not_to be_persisted + expect(subject).not_to be_persisted end end describe 'applying job inclusion policies' do + subject { seed_build } + context 'when no branch policy is specified' do - let(:attributes) { { name: 'rspec' } } + let(:attributes) do + { name: 'rspec' } + end it { is_expected.to be_included } end context 'when branch policy does not match' do context 'when using only' do - let(:attributes) { { name: 'rspec', only: { refs: ['deploy'] } } } + let(:attributes) do + { name: 'rspec', only: { refs: ['deploy'] } } + end it { is_expected.not_to be_included } end context 'when using except' do - let(:attributes) { { name: 'rspec', except: { refs: ['deploy'] } } } + let(:attributes) do + { name: 'rspec', except: { refs: ['deploy'] } } + end it { is_expected.to be_included } end context 'with both only and except policies' do - let(:attributes) { { name: 'rspec', only: { refs: %w(deploy) }, except: { refs: %(deploy) } } } + let(:attributes) do + { + name: 'rspec', + only: { refs: %w[deploy] }, + except: { refs: %w[deploy] } + } + end it { is_expected.not_to be_included } end @@ -100,19 +111,29 @@ describe Gitlab::Ci::Pipeline::Seed::Build do context 'when branch regexp policy does not match' do context 'when using only' do - let(:attributes) { { name: 'rspec', only: { refs: ['/^deploy$/'] } } } + let(:attributes) do + { name: 'rspec', only: { refs: %w[/^deploy$/] } } + end it { is_expected.not_to be_included } end context 'when using except' do - let(:attributes) { { name: 'rspec', except: { refs: ['/^deploy$/'] } } } + let(:attributes) do + { name: 'rspec', except: { refs: %w[/^deploy$/] } } + end it { is_expected.to be_included } end context 'with both only and except policies' do - let(:attributes) { { name: 'rspec', only: { refs: %w(/^deploy$/) }, except: { refs: %w(/^deploy$/) } } } + let(:attributes) do + { + name: 'rspec', + only: { refs: %w[/^deploy$/] }, + except: { refs: %w[/^deploy$/] } + } + end it { is_expected.not_to be_included } end @@ -120,19 +141,29 @@ describe Gitlab::Ci::Pipeline::Seed::Build do context 'when branch policy matches' do context 'when using only' do - let(:attributes) { { name: 'rspec', only: { refs: %w[deploy master] } } } + let(:attributes) do + { name: 'rspec', only: { refs: %w[deploy master] } } + end it { is_expected.to be_included } end context 'when using except' do - let(:attributes) { { name: 'rspec', except: { refs: %w[deploy master] } } } + let(:attributes) do + { name: 'rspec', except: { refs: %w[deploy master] } } + end it { is_expected.not_to be_included } end context 'when using both only and except policies' do - let(:attributes) { { name: 'rspec', only: { refs: %w(deploy master) }, except: { refs: %w(deploy master) } } } + let(:attributes) do + { + name: 'rspec', + only: { refs: %w[deploy master] }, + except: { refs: %w[deploy master] } + } + end it { is_expected.not_to be_included } end @@ -140,19 +171,29 @@ describe Gitlab::Ci::Pipeline::Seed::Build do context 'when keyword policy matches' do context 'when using only' do - let(:attributes) { { name: 'rspec', only: { refs: ['branches'] } } } + let(:attributes) do + { name: 'rspec', only: { refs: %w[branches] } } + end it { is_expected.to be_included } end context 'when using except' do - let(:attributes) { { name: 'rspec', except: { refs: ['branches'] } } } + let(:attributes) do + { name: 'rspec', except: { refs: %w[branches] } } + end it { is_expected.not_to be_included } end context 'when using both only and except policies' do - let(:attributes) { { name: 'rspec', only: { refs: %w(branches) }, except: { refs: %(branches) } } } + let(:attributes) do + { + name: 'rspec', + only: { refs: %w[branches] }, + except: { refs: %w[branches] } + } + end it { is_expected.not_to be_included } end @@ -160,19 +201,29 @@ describe Gitlab::Ci::Pipeline::Seed::Build do context 'when keyword policy does not match' do context 'when using only' do - let(:attributes) { { name: 'rspec', only: { refs: ['tags'] } } } + let(:attributes) do + { name: 'rspec', only: { refs: %w[tags] } } + end it { is_expected.not_to be_included } end context 'when using except' do - let(:attributes) { { name: 'rspec', except: { refs: ['tags'] } } } + let(:attributes) do + { name: 'rspec', except: { refs: %w[tags] } } + end it { is_expected.to be_included } end context 'when using both only and except policies' do - let(:attributes) { { name: 'rspec', only: { refs: %(tags) }, except: { refs: %(tags) } } } + let(:attributes) do + { + name: 'rspec', + only: { refs: %w[tags] }, + except: { refs: %w[tags] } + } + end it { is_expected.not_to be_included } end @@ -181,35 +232,47 @@ describe Gitlab::Ci::Pipeline::Seed::Build do context 'with source-keyword policy' do using RSpec::Parameterized - let(:pipeline) { build(:ci_empty_pipeline, ref: 'deploy', tag: false, source: source) } + let(:pipeline) do + create(:ci_empty_pipeline, ref: 'deploy', tag: false, source: source) + end context 'matches' do where(:keyword, :source) do [ - %w(pushes push), - %w(web web), - %w(triggers trigger), - %w(schedules schedule), - %w(api api), - %w(external external) + %w[pushes push], + %w[web web], + %w[triggers trigger], + %w[schedules schedule], + %w[api api], + %w[external external] ] end with_them do context 'using an only policy' do - let(:attributes) { { name: 'rspec', only: { refs: [keyword] } } } + let(:attributes) do + { name: 'rspec', only: { refs: [keyword] } } + end it { is_expected.to be_included } end context 'using an except policy' do - let(:attributes) { { name: 'rspec', except: { refs: [keyword] } } } + let(:attributes) do + { name: 'rspec', except: { refs: [keyword] } } + end it { is_expected.not_to be_included } end context 'using both only and except policies' do - let(:attributes) { { name: 'rspec', only: { refs: [keyword] }, except: { refs: [keyword] } } } + let(:attributes) do + { + name: 'rspec', + only: { refs: [keyword] }, + except: { refs: [keyword] } + } + end it { is_expected.not_to be_included } end @@ -218,29 +281,39 @@ describe Gitlab::Ci::Pipeline::Seed::Build do context 'non-matches' do where(:keyword, :source) do - %w(web trigger schedule api external).map { |source| ['pushes', source] } + - %w(push trigger schedule api external).map { |source| ['web', source] } + - %w(push web schedule api external).map { |source| ['triggers', source] } + - %w(push web trigger api external).map { |source| ['schedules', source] } + - %w(push web trigger schedule external).map { |source| ['api', source] } + - %w(push web trigger schedule api).map { |source| ['external', source] } + %w[web trigger schedule api external].map { |source| ['pushes', source] } + + %w[push trigger schedule api external].map { |source| ['web', source] } + + %w[push web schedule api external].map { |source| ['triggers', source] } + + %w[push web trigger api external].map { |source| ['schedules', source] } + + %w[push web trigger schedule external].map { |source| ['api', source] } + + %w[push web trigger schedule api].map { |source| ['external', source] } end with_them do context 'using an only policy' do - let(:attributes) { { name: 'rspec', only: { refs: [keyword] } } } + let(:attributes) do + { name: 'rspec', only: { refs: [keyword] } } + end it { is_expected.not_to be_included } end context 'using an except policy' do - let(:attributes) { { name: 'rspec', except: { refs: [keyword] } } } + let(:attributes) do + { name: 'rspec', except: { refs: [keyword] } } + end it { is_expected.to be_included } end context 'using both only and except policies' do - let(:attributes) { { name: 'rspec', only: { refs: [keyword] }, except: { refs: [keyword] } } } + let(:attributes) do + { + name: 'rspec', + only: { refs: [keyword] }, + except: { refs: [keyword] } + } + end it { is_expected.not_to be_included } end @@ -267,7 +340,11 @@ describe Gitlab::Ci::Pipeline::Seed::Build do context 'when using both only and except policies' do let(:attributes) do - { name: 'rspec', only: { refs: ["branches@#{pipeline.project_full_path}"] }, except: { refs: ["branches@#{pipeline.project_full_path}"] } } + { + name: 'rspec', + only: { refs: ["branches@#{pipeline.project_full_path}"] }, + except: { refs: ["branches@#{pipeline.project_full_path}"] } + } end it { is_expected.not_to be_included } @@ -277,7 +354,7 @@ describe Gitlab::Ci::Pipeline::Seed::Build do context 'when repository path does not matches' do context 'when using only' do let(:attributes) do - { name: 'rspec', only: { refs: ['branches@fork'] } } + { name: 'rspec', only: { refs: %w[branches@fork] } } end it { is_expected.not_to be_included } @@ -285,7 +362,7 @@ describe Gitlab::Ci::Pipeline::Seed::Build do context 'when using except' do let(:attributes) do - { name: 'rspec', except: { refs: ['branches@fork'] } } + { name: 'rspec', except: { refs: %w[branches@fork] } } end it { is_expected.to be_included } @@ -293,7 +370,11 @@ describe Gitlab::Ci::Pipeline::Seed::Build do context 'when using both only and except policies' do let(:attributes) do - { name: 'rspec', only: { refs: ['branches@fork'] }, except: { refs: ['branches@fork'] } } + { + name: 'rspec', + only: { refs: %w[branches@fork] }, + except: { refs: %w[branches@fork] } + } end it { is_expected.not_to be_included } -- cgit v1.2.1 From 3d171dc27163274b181fc0481065c681abae3186 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Mon, 15 Jul 2019 09:26:18 +0300 Subject: Remove old ignore_column in AR models Next models are affected: * Project * Namespace * Issue * Merge request * CI Trigger * CI Pipeline schedule Signed-off-by: Dmitriy Zaporozhets --- app/models/ci/pipeline_schedule.rb | 3 --- app/models/ci/trigger.rb | 3 --- app/models/issue.rb | 3 --- app/models/merge_request.rb | 5 ----- app/models/namespace.rb | 3 --- app/models/project.rb | 3 --- 6 files changed, 20 deletions(-) diff --git a/app/models/ci/pipeline_schedule.rb b/app/models/ci/pipeline_schedule.rb index ba8cea0cea9..42d4e86fe8d 100644 --- a/app/models/ci/pipeline_schedule.rb +++ b/app/models/ci/pipeline_schedule.rb @@ -4,11 +4,8 @@ module Ci class PipelineSchedule < ApplicationRecord extend Gitlab::Ci::Model include Importable - include IgnorableColumn include StripAttribute - ignore_column :deleted_at - belongs_to :project belongs_to :owner, class_name: 'User' has_one :last_pipeline, -> { order(id: :desc) }, class_name: 'Ci::Pipeline' diff --git a/app/models/ci/trigger.rb b/app/models/ci/trigger.rb index 8927bb9bc18..c7bfb9900c4 100644 --- a/app/models/ci/trigger.rb +++ b/app/models/ci/trigger.rb @@ -3,11 +3,8 @@ module Ci class Trigger < ApplicationRecord extend Gitlab::Ci::Model - include IgnorableColumn include Presentable - ignore_column :deleted_at - belongs_to :project belongs_to :owner, class_name: "User" diff --git a/app/models/issue.rb b/app/models/issue.rb index 982a94315bd..12d30389910 100644 --- a/app/models/issue.rb +++ b/app/models/issue.rb @@ -13,11 +13,8 @@ class Issue < ApplicationRecord include RelativePositioning include TimeTrackable include ThrottledTouch - include IgnorableColumn include LabelEventable - ignore_column :assignee_id, :branch_name, :deleted_at - DueDateStruct = Struct.new(:title, :name).freeze NoDueDate = DueDateStruct.new('No Due Date', '0').freeze AnyDueDate = DueDateStruct.new('Any Due Date', '').freeze diff --git a/app/models/merge_request.rb b/app/models/merge_request.rb index 53977748c30..34dca665852 100644 --- a/app/models/merge_request.rb +++ b/app/models/merge_request.rb @@ -7,7 +7,6 @@ class MergeRequest < ApplicationRecord include Noteable include Referable include Presentable - include IgnorableColumn include TimeTrackable include ManualInverseAssociation include EachBatch @@ -24,10 +23,6 @@ class MergeRequest < ApplicationRecord SORTING_PREFERENCE_FIELD = :merge_requests_sort - ignore_column :locked_at, - :ref_fetched, - :deleted_at - belongs_to :target_project, class_name: "Project" belongs_to :source_project, class_name: "Project" belongs_to :merge_user, class_name: "User" diff --git a/app/models/namespace.rb b/app/models/namespace.rb index 1d95590bac9..3ed4bf8e64a 100644 --- a/app/models/namespace.rb +++ b/app/models/namespace.rb @@ -8,13 +8,10 @@ class Namespace < ApplicationRecord include AfterCommitQueue include Storage::LegacyNamespace include Gitlab::SQL::Pattern - include IgnorableColumn include FeatureGate include FromUnion include Gitlab::Utils::StrongMemoize - ignore_column :deleted_at - # Prevent users from creating unreasonably deep level of nesting. # The number 20 was taken based on maximum nesting level of # Android repo (15) + some extra backup. diff --git a/app/models/project.rb b/app/models/project.rb index f6f7d373f91..2906aca75fc 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -31,7 +31,6 @@ class Project < ApplicationRecord include FeatureGate include OptionallySearch include FromUnion - include IgnorableColumn extend Gitlab::Cache::RequestCache extend Gitlab::ConfigHelper @@ -56,8 +55,6 @@ class Project < ApplicationRecord VALID_MIRROR_PORTS = [22, 80, 443].freeze VALID_MIRROR_PROTOCOLS = %w(http https ssh git).freeze - ignore_column :import_status, :import_jid, :import_error - cache_markdown_field :description, pipeline: :description delegate :feature_available?, :builds_enabled?, :wiki_enabled?, -- cgit v1.2.1 From a5ca1e488d350d48a42f757a765835dc1bf4663d Mon Sep 17 00:00:00 2001 From: Douglas Barbosa Alexandre Date: Fri, 12 Jul 2019 16:52:55 -0300 Subject: Update current limitations for automatic background verification --- .../geo/disaster_recovery/background_verification.md | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/doc/administration/geo/disaster_recovery/background_verification.md b/doc/administration/geo/disaster_recovery/background_verification.md index 8eee9427b56..27866b7536e 100644 --- a/doc/administration/geo/disaster_recovery/background_verification.md +++ b/doc/administration/geo/disaster_recovery/background_verification.md @@ -171,14 +171,21 @@ If the **primary** and **secondary** nodes have a checksum verification mismatch ## Current limitations -Until [issue #5064][ee-5064] is completed, background verification doesn't cover -CI job artifacts and traces, LFS objects, or user uploads in file storage. -Verify their integrity manually by following [these instructions][foreground-verification] -on both nodes, and comparing the output between them. +Automatic background verification doesn't cover attachments, LFS objects, +job artifacts, and user uploads in file storage. You can keep track of the +progress to include them in [ee-1430]. For now, you can verify their integrity +manually by following [these instructions][foreground-verification] on both +nodes, and comparing the output between them. + +In GitLab EE 12.1, Geo calculates checksums for attachments, LFS objects and +archived traces on secondary nodes after the transfer, compares it with the +stored checksums, and rejects transfers if mismatched. Please note that Geo +currently does not support an automatic way to verify these data if they have +been synced before GitLab EE 12.1. Data in object storage is **not verified**, as the object store is responsible for ensuring the integrity of the data. [reset-verification]: background_verification.md#reset-verification-for-projects-where-verification-has-failed [foreground-verification]: ../../raketasks/check.md -[ee-5064]: https://gitlab.com/gitlab-org/gitlab-ee/issues/5064 +[ee-1430]: https://gitlab.com/groups/gitlab-org/-/epics/1430 -- cgit v1.2.1 From 9b4b4e74130839062932083c214589c67ccfea51 Mon Sep 17 00:00:00 2001 From: Sanad Liaquat Date: Mon, 15 Jul 2019 22:32:43 +0500 Subject: Backport ee to ce --- qa/qa/page/project/sub_menus/common.rb | 6 +++++- qa/qa/resource/merge_request.rb | 3 +++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/qa/qa/page/project/sub_menus/common.rb b/qa/qa/page/project/sub_menus/common.rb index c94e1e85256..3c9e8085748 100644 --- a/qa/qa/page/project/sub_menus/common.rb +++ b/qa/qa/page/project/sub_menus/common.rb @@ -12,7 +12,11 @@ module QA end def within_submenu - within('.fly-out-list') do + if has_css?('.fly-out-list') + within('.fly-out-list') do + yield + end + else yield end end diff --git a/qa/qa/resource/merge_request.rb b/qa/qa/resource/merge_request.rb index 45cb317e0eb..7969de726e4 100644 --- a/qa/qa/resource/merge_request.rb +++ b/qa/qa/resource/merge_request.rb @@ -9,6 +9,7 @@ module QA :description, :source_branch, :target_branch, + :target_new_branch, :assignee, :milestone, :labels, @@ -27,6 +28,7 @@ module QA Repository::ProjectPush.fabricate! do |resource| resource.project = project resource.branch_name = 'master' + resource.new_branch = @target_new_branch resource.remote_branch = target_branch end end @@ -52,6 +54,7 @@ module QA @labels = [] @file_name = "added_file.txt" @file_content = "File Added" + @target_new_branch = true end def fabricate! -- cgit v1.2.1 From 119be7ffd12d72b0871357330145efbacef4d4e6 Mon Sep 17 00:00:00 2001 From: ddavison Date: Mon, 15 Jul 2019 15:54:05 -0700 Subject: Refactor more common Page Objects to use data tags Common usages within GitLab QA include login page, navbars and layouts --- app/views/devise/shared/_signup_box.html.haml | 14 ++++++------ app/views/doorkeeper/authorizations/new.html.haml | 2 +- qa/qa/page/main/oauth.rb | 4 ++-- qa/qa/page/main/sign_up.rb | 26 +++++++++++------------ 4 files changed, 23 insertions(+), 23 deletions(-) diff --git a/app/views/devise/shared/_signup_box.html.haml b/app/views/devise/shared/_signup_box.html.haml index 034273558bb..074edf645ba 100644 --- a/app/views/devise/shared/_signup_box.html.haml +++ b/app/views/devise/shared/_signup_box.html.haml @@ -7,26 +7,26 @@ = render "devise/shared/error_messages", resource: resource .name.form-group = f.label :name, _('Full name'), class: 'label-bold' - = f.text_field :name, class: "form-control top qa-new-user-name js-block-emoji js-validate-length", :data => { :max_length => max_name_length, :max_length_message => s_("SignUp|Name is too long (maximum is %{max_length} characters).") % { max_length: max_name_length } }, required: true, title: _("This field is required.") + = f.text_field :name, class: "form-control top js-block-emoji js-validate-length", :data => { :max_length => max_name_length, :max_length_message => s_("SignUp|Name is too long (maximum is %{max_length} characters).") % { max_length: max_name_length }, :qa_selector => 'new_user_name_field' }, required: true, title: _("This field is required.") .username.form-group = f.label :username, class: 'label-bold' - = f.text_field :username, class: "form-control middle qa-new-user-username js-block-emoji js-validate-length js-validate-username", :data => { :max_length => max_username_length, :max_length_message => s_("SignUp|Username is too long (maximum is %{max_length} characters).") % { max_length: max_username_length } }, pattern: Gitlab::PathRegex::NAMESPACE_FORMAT_REGEX_JS, required: true, title: _("Please create a username with only alphanumeric characters.") + = f.text_field :username, class: "form-control middle js-block-emoji js-validate-length js-validate-username", :data => { :max_length => max_username_length, :max_length_message => s_("SignUp|Username is too long (maximum is %{max_length} characters).") % { max_length: max_username_length }, :qa_selector => 'new_user_username_field' }, pattern: Gitlab::PathRegex::NAMESPACE_FORMAT_REGEX_JS, required: true, title: _("Please create a username with only alphanumeric characters.") %p.validation-error.gl-field-error-ignore.field-validation.hide= _('Username is already taken.') %p.validation-success.gl-field-error-ignore.field-validation.hide= _('Username is available.') %p.validation-pending.gl-field-error-ignore.field-validation.hide= _('Checking username availability...') .form-group = f.label :email, class: 'label-bold' - = f.email_field :email, class: "form-control middle qa-new-user-email", required: true, title: _("Please provide a valid email address.") + = f.email_field :email, class: "form-control middle", data: { qa_selector: 'new_user_email_field' }, required: true, title: _("Please provide a valid email address.") .form-group = f.label :email_confirmation, class: 'label-bold' - = f.email_field :email_confirmation, class: "form-control middle qa-new-user-email-confirmation", required: true, title: _("Please retype the email address.") + = f.email_field :email_confirmation, class: "form-control middle", data: { qa_selector: 'new_user_email_confirmation_field' }, required: true, title: _("Please retype the email address.") .form-group.append-bottom-20#password-strength = f.label :password, class: 'label-bold' - = f.password_field :password, class: "form-control bottom qa-new-user-password", required: true, pattern: ".{#{@minimum_password_length},}", title: _("Minimum length is %{minimum_password_length} characters.") % { minimum_password_length: @minimum_password_length } + = f.password_field :password, class: "form-control bottom", data: { qa_selector: 'new_user_password_field' }, required: true, pattern: ".{#{@minimum_password_length},}", title: _("Minimum length is %{minimum_password_length} characters.") % { minimum_password_length: @minimum_password_length } %p.gl-field-hint.text-secondary= _('Minimum length is %{minimum_password_length} characters') % { minimum_password_length: @minimum_password_length } - if Gitlab::CurrentSettings.current_application_settings.enforce_terms? .form-group - = check_box_tag :terms_opt_in, '1', false, required: true, class: 'qa-new-user-accept-terms' + = check_box_tag :terms_opt_in, '1', false, required: true, data: { qa_selector: 'new_user_accept_terms_checkbox' } = label_tag :terms_opt_in do - terms_link = link_to s_("I accept the|Terms of Service and Privacy Policy"), terms_path, target: "_blank" - accept_terms_label = _("I accept the %{terms_link}") % { terms_link: terms_link } @@ -36,4 +36,4 @@ - if show_recaptcha_sign_up? = recaptcha_tags .submit-container - = f.submit _("Register"), class: "btn-register btn qa-new-user-register-button" + = f.submit _("Register"), class: "btn-register btn", data: { qa_selector: 'new_user_register_button' } diff --git a/app/views/doorkeeper/authorizations/new.html.haml b/app/views/doorkeeper/authorizations/new.html.haml index dae9a7acf6b..5d57337a568 100644 --- a/app/views/doorkeeper/authorizations/new.html.haml +++ b/app/views/doorkeeper/authorizations/new.html.haml @@ -46,4 +46,4 @@ = 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" + = submit_tag _("Authorize"), class: "btn btn-success prepend-left-10", data: { qa_selector: 'authorization_button' } diff --git a/qa/qa/page/main/oauth.rb b/qa/qa/page/main/oauth.rb index 5f6ddb9a114..2b1a9ab2b6a 100644 --- a/qa/qa/page/main/oauth.rb +++ b/qa/qa/page/main/oauth.rb @@ -5,7 +5,7 @@ module QA module Main class OAuth < Page::Base view 'app/views/doorkeeper/authorizations/new.html.haml' do - element :authorization_button, 'submit_tag _("Authorize")' # rubocop:disable QA/ElementWithPattern + element :authorization_button end def needs_authorization? @@ -13,7 +13,7 @@ module QA end def authorize! - click_button 'Authorize' + click_element :authorization_button end end end diff --git a/qa/qa/page/main/sign_up.rb b/qa/qa/page/main/sign_up.rb index 46a105003d0..c47d2ce9c74 100644 --- a/qa/qa/page/main/sign_up.rb +++ b/qa/qa/page/main/sign_up.rb @@ -5,28 +5,28 @@ module QA module Main class SignUp < Page::Base view 'app/views/devise/shared/_signup_box.html.haml' do - element :new_user_name - element :new_user_username - element :new_user_email - element :new_user_email_confirmation - element :new_user_password + element :new_user_name_field + element :new_user_username_field + element :new_user_email_field + element :new_user_email_confirmation_field + element :new_user_password_field element :new_user_register_button - element :new_user_accept_terms + element :new_user_accept_terms_checkbox end def sign_up!(user) - fill_element :new_user_name, user.name - fill_element :new_user_username, user.username - fill_element :new_user_email, user.email - fill_element :new_user_email_confirmation, user.email - fill_element :new_user_password, user.password + fill_element :new_user_name_field, user.name + fill_element :new_user_username_field, user.username + fill_element :new_user_email_field, user.email + fill_element :new_user_email_confirmation_field, user.email + fill_element :new_user_password_field, user.password - check_element :new_user_accept_terms if has_element?(:new_user_accept_terms) + check_element :new_user_accept_terms_checkbox if has_element?(:new_user_accept_terms_checkbox) signed_in = retry_until do click_element :new_user_register_button - Page::Main::Menu.act { has_personal_area? } + Page::Main::Menu.perform(&:has_personal_area?) end raise "Failed to register and sign in" unless signed_in -- cgit v1.2.1 From 2a442ae7a89d5c6a683903043a171d40aed2dcb0 Mon Sep 17 00:00:00 2001 From: Woko Date: Tue, 16 Jul 2019 03:25:15 +0000 Subject: fix `register runner with services` --- doc/ci/docker/using_docker_images.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/ci/docker/using_docker_images.md b/doc/ci/docker/using_docker_images.md index 90565efe196..f9dcd6417e0 100644 --- a/doc/ci/docker/using_docker_images.md +++ b/doc/ci/docker/using_docker_images.md @@ -35,8 +35,8 @@ sudo gitlab-runner register \ --description "docker-ruby-2.1" \ --executor "docker" \ --docker-image ruby:2.1 \ - --docker-postgres latest \ - --docker-mysql latest + --docker-services postgres:latest \ + --docker-services mysql:latest ``` The registered runner will use the `ruby:2.1` Docker image and will run two -- cgit v1.2.1 From adece6f7f947aae14b60226cdb8c835d5a3fa684 Mon Sep 17 00:00:00 2001 From: Heinrich Lee Yu Date: Tue, 16 Jul 2019 14:51:56 +0800 Subject: Change time tracking units feature release version --- doc/workflow/time_tracking.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/workflow/time_tracking.md b/doc/workflow/time_tracking.md index 4286a3625a2..b55c6b2e3df 100644 --- a/doc/workflow/time_tracking.md +++ b/doc/workflow/time_tracking.md @@ -75,7 +75,7 @@ Default conversion rates are 1mo = 4w, 1w = 5d and 1d = 8h. ### Limit displayed units to hours -> Introduced in GitLab 12.0. +> Introduced in GitLab 12.1. The display of time units can be limited to hours through the option in **Admin Area > Settings > Preferences** under 'Localization'. -- cgit v1.2.1 From d589a4e8e1e54eb3810cc2c29649f34a632fd3e5 Mon Sep 17 00:00:00 2001 From: drew cimino Date: Tue, 16 Jul 2019 11:43:08 -0400 Subject: Build instead of create --- spec/lib/gitlab/ci/pipeline/seed/build_spec.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/lib/gitlab/ci/pipeline/seed/build_spec.rb b/spec/lib/gitlab/ci/pipeline/seed/build_spec.rb index e0bff638233..46ea0d7554b 100644 --- a/spec/lib/gitlab/ci/pipeline/seed/build_spec.rb +++ b/spec/lib/gitlab/ci/pipeline/seed/build_spec.rb @@ -233,7 +233,7 @@ describe Gitlab::Ci::Pipeline::Seed::Build do using RSpec::Parameterized let(:pipeline) do - create(:ci_empty_pipeline, ref: 'deploy', tag: false, source: source) + build(:ci_empty_pipeline, ref: 'deploy', tag: false, source: source) end context 'matches' do -- cgit v1.2.1 From 41b77136eec455c13357566ff959382a50bc4043 Mon Sep 17 00:00:00 2001 From: Annabel Dunstone Gray Date: Tue, 16 Jul 2019 16:03:29 +0000 Subject: Revert "Merge branch '61145-fix-button-dimensions' into 'master'" This reverts merge request !28545 --- app/assets/stylesheets/framework/animations.scss | 2 +- app/assets/stylesheets/framework/buttons.scss | 128 +++++++++------------ app/assets/stylesheets/framework/dropdowns.scss | 17 ++- app/assets/stylesheets/framework/variables.scss | 4 - app/assets/stylesheets/pages/commits.scss | 4 +- app/assets/stylesheets/pages/issuable.scss | 4 + app/assets/stylesheets/pages/issues.scss | 1 + app/assets/stylesheets/pages/note_form.scss | 1 + app/assets/stylesheets/pages/projects.scss | 3 +- app/assets/stylesheets/pages/tree.scss | 2 +- app/helpers/dropdowns_helper.rb | 2 +- .../projects/issues/import_csv/_button.html.haml | 2 +- app/views/shared/issuable/_feed_buttons.html.haml | 8 +- .../unreleased/61145-fix-button-dimensions.yml | 5 - spec/support/features/rss_shared_examples.rb | 4 +- 15 files changed, 89 insertions(+), 98 deletions(-) delete mode 100644 changelogs/unreleased/61145-fix-button-dimensions.yml diff --git a/app/assets/stylesheets/framework/animations.scss b/app/assets/stylesheets/framework/animations.scss index 6bc5632365f..6f5a2e561af 100644 --- a/app/assets/stylesheets/framework/animations.scss +++ b/app/assets/stylesheets/framework/animations.scss @@ -104,7 +104,7 @@ } .btn { - @include transition(border-color); + @include transition(background-color, border-color, color, box-shadow); } .dropdown-menu-toggle, diff --git a/app/assets/stylesheets/framework/buttons.scss b/app/assets/stylesheets/framework/buttons.scss index e0b6da31261..767832e242c 100644 --- a/app/assets/stylesheets/framework/buttons.scss +++ b/app/assets/stylesheets/framework/buttons.scss @@ -24,11 +24,12 @@ border-radius: $border-radius-default; font-size: $gl-font-size; font-weight: $gl-font-weight-normal; - padding: $gl-bordered-btn-vert-padding $gl-bordered-btn-horz-padding; + padding: $gl-vert-padding $gl-btn-padding; &:focus, &:active { background-color: $btn-active-gray; + box-shadow: $gl-btn-active-background; } } @@ -49,89 +50,77 @@ color: $text; } - &:not(:disabled):not(.disabled) { - &:hover { - box-shadow: inset 0 0 0 1px $hover-border, 0 2px 2px 0 $gl-btn-hover-shadow-light; - } + &:hover, + &:focus { + background-color: $hover-background; + border-color: $hover-border; + color: $hover-text; - &:focus { - box-shadow: inset 0 0 0 1px $hover-border, 0 0 4px 1px $blue-300; + > .icon { + color: $hover-text; } + } - &:hover, - &:focus { - background-color: $hover-background; - border-color: $hover-border; - color: $hover-text; + &:focus { + box-shadow: 0 0 4px 1px $blue-300; + } - > .icon { - color: $hover-text; - } - } + &:active { + background-color: $active-background; + border-color: $active-border; + box-shadow: inset 0 2px 4px 0 rgba($black, 0.2); + color: $active-text; - &:active, - &:active:focus { - background-color: $active-background; - border-color: $active-border; - box-shadow: inset 0 0 0 1px $hover-border, inset 0 2px 4px 0 rgba($black, 0.2); + > .icon { color: $active-text; + } - > .icon { - color: $active-text; - } + &:focus { + box-shadow: inset 0 2px 4px 0 rgba($black, 0.2); } } } -@mixin btn-color($light, $border-light, $normal, $border-normal, $dark, $border-dark, $color, $hover-shadow-color: $gl-btn-hover-shadow-dark) { +@mixin btn-color($light, $border-light, $normal, $border-normal, $dark, $border-dark, $color) { background-color: $light; border-color: $border-light; color: $color; - &:not(:disabled):not(.disabled) { - &:hover { - box-shadow: inset 0 0 0 1px $border-normal, 0 2px 2px 0 $hover-shadow-color; - } - - &:focus { - box-shadow: inset 0 0 0 1px $border-normal, 0 0 4px 1px $blue-300; - } + &:hover, + &:focus { + background-color: $normal; + border-color: $border-normal; + color: $color; + } - &:hover, - &:focus { - background-color: $normal; - border-color: $border-normal; - color: $color; - } + &:active, + &.active { + box-shadow: $gl-btn-active-background; - &:active, - &.active { - box-shadow: inset 0 2px 4px 0 $gl-btn-hover-shadow-dark; - background-color: $dark; - border-color: $border-dark; - color: $color; - } + background-color: $dark; + border-color: $border-dark; + color: $color; } } @mixin btn-green { - @include btn-color($green-500, $green-600, $green-500, $green-700, $green-600, $green-800, $white-light); + @include btn-color($green-500, $green-600, $green-600, $green-700, $green-700, $green-800, $white-light); } @mixin btn-blue { - @include btn-color($blue-500, $blue-600, $blue-500, $blue-700, $blue-600, $blue-800, $white-light); + @include btn-color($blue-500, $blue-600, $blue-600, $blue-700, $blue-700, $blue-800, $white-light); } @mixin btn-orange { - @include btn-color($orange-500, $orange-600, $orange-500, $orange-700, $orange-600, $orange-800, $white-light); + @include btn-color($orange-500, $orange-600, $orange-600, $orange-700, $orange-700, $orange-800, $white-light); } @mixin btn-red { - @include btn-color($red-500, $red-600, $red-500, $red-700, $red-600, $red-800, $white-light); + @include btn-color($red-500, $red-600, $red-600, $red-700, $red-700, $red-800, $white-light); } @mixin btn-white { - @include btn-color($white-light, $gray-400, $gray-200, $gray-400, $gl-gray-200, $gray-500, $gl-text-color, $gl-btn-hover-shadow-light); + @include btn-color($white-light, $border-color, $white-normal, $border-white-normal, $white-dark, $border-gray-dark, $gl-text-color); } @mixin btn-with-margin { @@ -160,20 +149,21 @@ color: $gl-text-color; white-space: nowrap; - line-height: $gl-btn-line-height; &:focus:active { outline: 0; } - &.btn-xs { - font-size: $gl-btn-xs-font-size; - line-height: $gl-btn-xs-line-height; + &.btn-sm { + padding: 4px 10px; + font-size: $gl-btn-small-font-size; + line-height: $gl-btn-small-line-height; } - &.btn-sm, &.btn-xs { - padding: 3px $gl-bordered-btn-vert-padding; + padding: 2px $gl-btn-padding; + font-size: $gl-btn-xs-font-size; + line-height: $gl-btn-xs-line-height; } &.btn-success, @@ -249,7 +239,7 @@ &.dropdown-toggle { .fa-caret-down { - margin: 0; + margin-left: 3px; } } @@ -282,7 +272,10 @@ } svg { - @include btn-svg; + height: 15px; + width: 15px; + position: relative; + top: 2px; } svg, @@ -337,12 +330,6 @@ &.btn-grouped { @include btn-with-margin; } - - .btn { - border-radius: $border-radius-default; - font-size: $gl-font-size; - line-height: $gl-btn-line-height; - } } .btn-clipboard { @@ -500,25 +487,18 @@ &:active, &:focus { color: $gl-text-color-secondary; - border: 1px solid $border-gray-normal-dashed; background-color: $white-normal; } } -.btn-svg { - padding: $gl-bordered-btn-vert-padding; - - svg { - @include btn-svg; - display: block; - } +.btn-svg svg { + @include btn-svg; } // All disabled buttons, regardless of color, type, etc %disabled { background-color: $gray-light !important; border-color: $gray-200 !important; - box-shadow: none; color: $gl-text-color-disabled !important; opacity: 1 !important; cursor: default !important; diff --git a/app/assets/stylesheets/framework/dropdowns.scss b/app/assets/stylesheets/framework/dropdowns.scss index 05afcecca05..29f63e9578d 100644 --- a/app/assets/stylesheets/framework/dropdowns.scss +++ b/app/assets/stylesheets/framework/dropdowns.scss @@ -8,6 +8,12 @@ } } +@mixin chevron-active { + .fa-chevron-down { + color: $gray-darkest; + } +} + @mixin set-visible { transform: translateY(0); display: block; @@ -43,6 +49,7 @@ .dropdown-toggle, .dropdown-menu-toggle { + @include chevron-active; border-color: $gray-darkest; } @@ -58,12 +65,12 @@ .dropdown-toggle, .confidential-merge-request-fork-group .dropdown-toggle { - padding: $gl-bordered-btn-vert-padding $gl-bordered-btn-horz-padding; + padding: 6px 8px 6px 10px; background-color: $white-light; color: $gl-text-color; font-size: 14px; - line-height: $gl-btn-line-height; text-align: left; + border: 1px solid $border-color; border-radius: $border-radius-base; white-space: nowrap; @@ -96,6 +103,10 @@ padding-right: 25px; } + .fa { + color: $gray-darkest; + } + .fa-chevron-down { font-size: $dropdown-chevron-size; position: relative; @@ -104,10 +115,12 @@ } &:hover { + @include chevron-active; border-color: $gray-darkest; } &:focus:active { + @include chevron-active; border-color: $dropdown-toggle-active-border-color; outline: 0; } diff --git a/app/assets/stylesheets/framework/variables.scss b/app/assets/stylesheets/framework/variables.scss index 047a9799c3f..c108f45622f 100644 --- a/app/assets/stylesheets/framework/variables.scss +++ b/app/assets/stylesheets/framework/variables.scss @@ -405,8 +405,6 @@ $tanuki-yellow: #fca326; */ $green-500-focus: rgba($green-500, 0.4); $gl-btn-active-background: rgba(0, 0, 0, 0.16); -$gl-btn-hover-shadow-dark: rgba($black, 0.2); -$gl-btn-hover-shadow-light: rgba($black, 0.1); $gl-btn-active-gradient: inset 0 2px 3px $gl-btn-active-background; /* @@ -483,8 +481,6 @@ $gl-btn-padding: 10px; $gl-btn-line-height: 16px; $gl-btn-vert-padding: 8px; $gl-btn-horz-padding: 12px; -$gl-bordered-btn-vert-padding: $gl-btn-vert-padding - 1px; -$gl-bordered-btn-horz-padding: $gl-btn-horz-padding - 1px; $gl-btn-small-font-size: 13px; $gl-btn-small-line-height: 18px; $gl-btn-xs-font-size: 13px; diff --git a/app/assets/stylesheets/pages/commits.scss b/app/assets/stylesheets/pages/commits.scss index 3d11aa58871..0b0a4e50146 100644 --- a/app/assets/stylesheets/pages/commits.scss +++ b/app/assets/stylesheets/pages/commits.scss @@ -214,10 +214,10 @@ .label, .btn { - padding: $gl-bordered-btn-vert-padding $gl-bordered-btn-horz-padding; + padding: $gl-vert-padding $gl-btn-padding; border: 1px $border-color solid; font-size: $gl-font-size; - line-height: $gl-btn-line-height; + line-height: $line-height-base; border-radius: 0; display: flex; align-items: center; diff --git a/app/assets/stylesheets/pages/issuable.scss b/app/assets/stylesheets/pages/issuable.scss index 66ea70e79da..6a0127eb51c 100644 --- a/app/assets/stylesheets/pages/issuable.scss +++ b/app/assets/stylesheets/pages/issuable.scss @@ -929,6 +929,10 @@ margin: 0; } } + + .dropdown-toggle > .icon { + margin: 0 3px; + } } .right-sidebar-collapsed { diff --git a/app/assets/stylesheets/pages/issues.scss b/app/assets/stylesheets/pages/issues.scss index e51ca44476c..8359a60ec9f 100644 --- a/app/assets/stylesheets/pages/issues.scss +++ b/app/assets/stylesheets/pages/issues.scss @@ -267,6 +267,7 @@ ul.related-merge-requests > li { .fa-caret-down { pointer-events: none; color: inherit; + margin-left: 0; } } } diff --git a/app/assets/stylesheets/pages/note_form.scss b/app/assets/stylesheets/pages/note_form.scss index 1d57a4a4784..c6bac33e888 100644 --- a/app/assets/stylesheets/pages/note_form.scss +++ b/app/assets/stylesheets/pages/note_form.scss @@ -417,6 +417,7 @@ table { i { color: $white-light; + padding-right: 2px; margin-top: 2px; } diff --git a/app/assets/stylesheets/pages/projects.scss b/app/assets/stylesheets/pages/projects.scss index 09a576c11cb..e453f4a2264 100644 --- a/app/assets/stylesheets/pages/projects.scss +++ b/app/assets/stylesheets/pages/projects.scss @@ -429,7 +429,7 @@ padding: 0; background: transparent; border: 0; - line-height: 2; + line-height: 34px; margin: 0; > li + li::before { @@ -792,6 +792,7 @@ .btn { margin-top: $gl-padding; + padding: $gl-btn-vert-padding $gl-btn-padding; line-height: $gl-btn-line-height; .icon { diff --git a/app/assets/stylesheets/pages/tree.scss b/app/assets/stylesheets/pages/tree.scss index 5c732ab0d1f..5664f46484e 100644 --- a/app/assets/stylesheets/pages/tree.scss +++ b/app/assets/stylesheets/pages/tree.scss @@ -90,7 +90,7 @@ .add-to-tree { vertical-align: top; - padding: $gl-bordered-btn-vert-padding; + padding: 8px; svg { top: 0; diff --git a/app/helpers/dropdowns_helper.rb b/app/helpers/dropdowns_helper.rb index fd94f07cc2c..64c5fae7d96 100644 --- a/app/helpers/dropdowns_helper.rb +++ b/app/helpers/dropdowns_helper.rb @@ -46,7 +46,7 @@ module DropdownsHelper def dropdown_toggle(toggle_text, data_attr, options = {}) default_label = data_attr[:default_label] - content_tag(:button, disabled: options[:disabled], class: "dropdown-menu-toggle btn #{options[:toggle_class] if options.key?(:toggle_class)}", id: (options[:id] if options.key?(:id)), type: "button", data: data_attr) do + content_tag(:button, disabled: options[:disabled], class: "dropdown-menu-toggle #{options[:toggle_class] if options.key?(:toggle_class)}", id: (options[:id] if options.key?(:id)), type: "button", data: data_attr) do output = content_tag(:span, toggle_text, class: "dropdown-toggle-text #{'is-default' if toggle_text == default_label}") output << icon('chevron-down') output.html_safe diff --git a/app/views/projects/issues/import_csv/_button.html.haml b/app/views/projects/issues/import_csv/_button.html.haml index 8442a53ed61..acc2c50294f 100644 --- a/app/views/projects/issues/import_csv/_button.html.haml +++ b/app/views/projects/issues/import_csv/_button.html.haml @@ -1,6 +1,6 @@ - type = local_assigns.fetch(:type, :icon) -%button.csv-import-button.btn.btn-svg{ title: _('Import CSV'), class: ('has-tooltip' if type == :icon), +%button.csv-import-button.btn{ title: _('Import CSV'), class: ('has-tooltip' if type == :icon), data: { toggle: 'modal', target: '.issues-import-modal' } } - if type == :icon = sprite_icon('upload') diff --git a/app/views/shared/issuable/_feed_buttons.html.haml b/app/views/shared/issuable/_feed_buttons.html.haml index c9506a3295c..83f60fa6fe2 100644 --- a/app/views/shared/issuable/_feed_buttons.html.haml +++ b/app/views/shared/issuable/_feed_buttons.html.haml @@ -1,4 +1,4 @@ -= link_to safe_params.merge(rss_url_options), class: 'btn btn-svg has-tooltip js-rss-button', data: { container: 'body' }, title: _('Subscribe to RSS feed') do - = sprite_icon('rss') -= link_to safe_params.merge(calendar_url_options), class: 'btn btn-svg has-tooltip', data: { container: 'body' }, title: _('Subscribe to calendar') do - = sprite_icon('calendar') += link_to safe_params.merge(rss_url_options), class: 'btn has-tooltip', data: { container: 'body' }, title: _('Subscribe to RSS feed') do + = icon('rss') += link_to safe_params.merge(calendar_url_options), class: 'btn has-tooltip', data: { container: 'body' }, title: _('Subscribe to calendar') do + = custom_icon('icon_calendar') diff --git a/changelogs/unreleased/61145-fix-button-dimensions.yml b/changelogs/unreleased/61145-fix-button-dimensions.yml deleted file mode 100644 index 8f209ceaa8e..00000000000 --- a/changelogs/unreleased/61145-fix-button-dimensions.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Updating button dimensions according to design spec -merge_request: 28545 -author: -type: fixed diff --git a/spec/support/features/rss_shared_examples.rb b/spec/support/features/rss_shared_examples.rb index 02d310a9afa..0de92aedba5 100644 --- a/spec/support/features/rss_shared_examples.rb +++ b/spec/support/features/rss_shared_examples.rb @@ -6,7 +6,7 @@ end shared_examples "it has an RSS button with current_user's feed token" do it "shows the RSS button with current_user's feed token" do - expect(page).to have_css("a:has(.fa-rss)[href*='feed_token=#{user.feed_token}'], .js-rss-button[href*='feed_token=#{user.feed_token}']") + expect(page).to have_css("a:has(.fa-rss)[href*='feed_token=#{user.feed_token}']") end end @@ -18,6 +18,6 @@ end shared_examples "it has an RSS button without a feed token" do it "shows the RSS button without a feed token" do - expect(page).to have_css("a:has(.fa-rss):not([href*='feed_token']), .js-rss-button:not([href*='feed_token'])") + expect(page).to have_css("a:has(.fa-rss):not([href*='feed_token'])") end end -- cgit v1.2.1 From ce40c12849c8977e285962f8752cd78ac64c92ea Mon Sep 17 00:00:00 2001 From: manojmj Date: Tue, 16 Jul 2019 14:52:40 +0530 Subject: CE: Read and write User "Admin notes" via API This change adds the ability to read and write admin notes for a user via the USER API --- doc/api/users.md | 24 +++++++++++++++++++++--- lib/api/users.rb | 8 ++++---- spec/requests/api/users_spec.rb | 8 ++++++++ 3 files changed, 33 insertions(+), 7 deletions(-) diff --git a/doc/api/users.md b/doc/api/users.md index 213d1865aca..1a7af38dc6e 100644 --- a/doc/api/users.md +++ b/doc/api/users.md @@ -147,6 +147,21 @@ GET /users ] ``` +Users on GitLab [Starter, Bronze, or higher](https://about.gitlab.com/pricing/) will also see the `shared_runners_minutes_limit`, `extra_shared_runners_minutes_limit`, and `note` parameters. + +```json +[ + { + "id": 1, + ... + "shared_runners_minutes_limit": 133, + "extra_shared_runners_minutes_limit": 133, + "note": "DMCA Request: 2018-11-05 | DMCA Violation | Abuse | https://gitlab.zendesk.com/agent/tickets/123" + ... + } +] +``` + Users on GitLab [Silver or higher](https://about.gitlab.com/pricing/) will also see the `group_saml` provider option: @@ -284,14 +299,15 @@ Example Responses: ``` Users on GitLab [Starter, Bronze, or higher](https://about.gitlab.com/pricing/) will also see -the `shared_runners_minutes_limit` and `extra_shared_runners_minutes_limit` parameters. +the `shared_runners_minutes_limit`, `extra_shared_runners_minutes_limit`, and `note` parameters. ```json { "id": 1, "username": "john_smith", "shared_runners_minutes_limit": 133, - "extra_shared_runners_minutes_limit": 133 + "extra_shared_runners_minutes_limit": 133, + "note": "DMCA Request: 2018-11-05 | DMCA Violation | Abuse | https://gitlab.zendesk.com/agent/tickets/123" ... } ``` @@ -304,7 +320,8 @@ see the `group_saml` option: "id": 1, "username": "john_smith", "shared_runners_minutes_limit": 133, - "extra_shared_runners_minutes_limit": 133 + "extra_shared_runners_minutes_limit": 133, + "note": "DMCA Request: 2018-11-05 | DMCA Violation | Abuse | https://gitlab.zendesk.com/agent/tickets/123" "identities": [ {"provider": "github", "extern_uid": "2435223452345"}, {"provider": "bitbucket", "extern_uid": "john.smith"}, @@ -399,6 +416,7 @@ Parameters: - `private_profile` (optional) - User's profile is private - true or false - `shared_runners_minutes_limit` (optional) - Pipeline minutes quota for this user **(STARTER)** - `extra_shared_runners_minutes_limit` (optional) - Extra pipeline minutes quota for this user **(STARTER)** +- `note` (optional) - Admin notes for this user **(STARTER)** On password update, user will be forced to change it upon next login. Note, at the moment this method does only return a `404` error, diff --git a/lib/api/users.rb b/lib/api/users.rb index 41418aa216c..e145bfdc96a 100644 --- a/lib/api/users.rb +++ b/lib/api/users.rb @@ -148,7 +148,7 @@ module API end desc 'Create a user. Available only for admins.' do - success Entities::UserPublic + success Entities::UserWithAdmin end params do requires :email, type: String, desc: 'The email of the user' @@ -168,7 +168,7 @@ module API user = ::Users::CreateService.new(current_user, params).execute(skip_authorization: true) if user.persisted? - present user, with: Entities::UserPublic, current_user: current_user + present user, with: Entities::UserWithAdmin, current_user: current_user else conflict!('Email has already been taken') if User .by_any_email(user.email.downcase) @@ -183,7 +183,7 @@ module API end desc 'Update a user. Available only for admins.' do - success Entities::UserPublic + success Entities::UserWithAdmin end params do requires :id, type: Integer, desc: 'The ID of the user' @@ -215,7 +215,7 @@ module API result = ::Users::UpdateService.new(current_user, user_params.merge(user: user)).execute if result[:status] == :success - present user, with: Entities::UserPublic, current_user: current_user + present user, with: Entities::UserWithAdmin, current_user: current_user else render_validation_error!(user) end diff --git a/spec/requests/api/users_spec.rb b/spec/requests/api/users_spec.rb index 46925daf40a..387efd882e5 100644 --- a/spec/requests/api/users_spec.rb +++ b/spec/requests/api/users_spec.rb @@ -448,6 +448,7 @@ describe API::Users do it "returns 201 Created on success" do post api("/users", admin), params: attributes_for(:user, projects_limit: 3) + expect(response).to match_response_schema('public_api/v4/user/admin') expect(response).to have_gitlab_http_status(201) end @@ -643,6 +644,13 @@ describe API::Users do describe "PUT /users/:id" do let!(:admin_user) { create(:admin) } + it "returns 200 OK on success" do + put api("/users/#{user.id}", admin), params: { bio: 'new test bio' } + + expect(response).to match_response_schema('public_api/v4/user/admin') + expect(response).to have_gitlab_http_status(200) + end + it "updates user with new bio" do put api("/users/#{user.id}", admin), params: { bio: 'new test bio' } -- cgit v1.2.1 From cea7ba513c6d623ef921fba07910e98cca71435b Mon Sep 17 00:00:00 2001 From: Sarah Yasonik Date: Tue, 16 Jul 2019 20:19:08 +0000 Subject: Rename Redactor classes to ReferenceRedactor --- config/initializers/zz_metrics.rb | 2 +- lib/banzai/filter/redactor_filter.rb | 32 ---- lib/banzai/filter/reference_redactor_filter.rb | 32 ++++ lib/banzai/object_renderer.rb | 2 +- lib/banzai/pipeline/post_process_pipeline.rb | 2 +- lib/banzai/redactor.rb | 131 ------------- lib/banzai/reference_redactor.rb | 131 +++++++++++++ lib/banzai/renderer.rb | 2 +- spec/lib/banzai/filter/redactor_filter_spec.rb | 205 --------------------- .../filter/reference_redactor_filter_spec.rb | 205 +++++++++++++++++++++ spec/lib/banzai/object_renderer_spec.rb | 8 +- spec/lib/banzai/redactor_spec.rb | 182 ------------------ spec/lib/banzai/reference_redactor_spec.rb | 182 ++++++++++++++++++ 13 files changed, 558 insertions(+), 558 deletions(-) delete mode 100644 lib/banzai/filter/redactor_filter.rb create mode 100644 lib/banzai/filter/reference_redactor_filter.rb delete mode 100644 lib/banzai/redactor.rb create mode 100644 lib/banzai/reference_redactor.rb delete mode 100644 spec/lib/banzai/filter/redactor_filter_spec.rb create mode 100644 spec/lib/banzai/filter/reference_redactor_filter_spec.rb delete mode 100644 spec/lib/banzai/redactor_spec.rb create mode 100644 spec/lib/banzai/reference_redactor_spec.rb diff --git a/config/initializers/zz_metrics.rb b/config/initializers/zz_metrics.rb index 5aa6f73c5c5..4f309094447 100644 --- a/config/initializers/zz_metrics.rb +++ b/config/initializers/zz_metrics.rb @@ -53,7 +53,7 @@ def instrument_classes(instrumentation) instrumentation.instrument_methods(Banzai::Querying) instrumentation.instrument_instance_methods(Banzai::ObjectRenderer) - instrumentation.instrument_instance_methods(Banzai::Redactor) + instrumentation.instrument_instance_methods(Banzai::ReferenceRedactor) [Issuable, Mentionable, Participable].each do |klass| instrumentation.instrument_instance_methods(klass) diff --git a/lib/banzai/filter/redactor_filter.rb b/lib/banzai/filter/redactor_filter.rb deleted file mode 100644 index 1f091f594f8..00000000000 --- a/lib/banzai/filter/redactor_filter.rb +++ /dev/null @@ -1,32 +0,0 @@ -# frozen_string_literal: true - -module Banzai - module Filter - # HTML filter that removes references to records that the current user does - # not have permission to view. - # - # Expected to be run in its own post-processing pipeline. - # - class RedactorFilter < HTML::Pipeline::Filter - def call - unless context[:skip_redaction] - context = RenderContext.new(project, current_user) - - Redactor.new(context).redact([doc]) - end - - doc - end - - private - - def current_user - context[:current_user] - end - - def project - context[:project] - end - end - end -end diff --git a/lib/banzai/filter/reference_redactor_filter.rb b/lib/banzai/filter/reference_redactor_filter.rb new file mode 100644 index 00000000000..485d3fd5fc7 --- /dev/null +++ b/lib/banzai/filter/reference_redactor_filter.rb @@ -0,0 +1,32 @@ +# frozen_string_literal: true + +module Banzai + module Filter + # HTML filter that removes references to records that the current user does + # not have permission to view. + # + # Expected to be run in its own post-processing pipeline. + # + class ReferenceRedactorFilter < HTML::Pipeline::Filter + def call + unless context[:skip_redaction] + context = RenderContext.new(project, current_user) + + ReferenceRedactor.new(context).redact([doc]) + end + + doc + end + + private + + def current_user + context[:current_user] + end + + def project + context[:project] + end + end + end +end diff --git a/lib/banzai/object_renderer.rb b/lib/banzai/object_renderer.rb index 75661ffa233..d6d29f4bfab 100644 --- a/lib/banzai/object_renderer.rb +++ b/lib/banzai/object_renderer.rb @@ -72,7 +72,7 @@ module Banzai # # Returns an Array containing the redacted documents. def redact_documents(documents) - redactor = Redactor.new(context) + redactor = ReferenceRedactor.new(context) redactor.redact(documents) end diff --git a/lib/banzai/pipeline/post_process_pipeline.rb b/lib/banzai/pipeline/post_process_pipeline.rb index 5c199453638..54af26b41be 100644 --- a/lib/banzai/pipeline/post_process_pipeline.rb +++ b/lib/banzai/pipeline/post_process_pipeline.rb @@ -12,7 +12,7 @@ module Banzai def self.internal_link_filters [ - Filter::RedactorFilter, + Filter::ReferenceRedactorFilter, Filter::InlineMetricsRedactorFilter, Filter::RelativeLinkFilter, Filter::IssuableStateFilter, diff --git a/lib/banzai/redactor.rb b/lib/banzai/redactor.rb deleted file mode 100644 index c2da7fec7cc..00000000000 --- a/lib/banzai/redactor.rb +++ /dev/null @@ -1,131 +0,0 @@ -# frozen_string_literal: true - -module Banzai - # Class for removing Markdown references a certain user is not allowed to - # view. - class Redactor - attr_reader :context - - # context - An instance of `Banzai::RenderContext`. - def initialize(context) - @context = context - end - - def user - context.current_user - end - - # Redacts the references in the given Array of documents. - # - # This method modifies the given documents in-place. - # - # documents - A list of HTML documents containing references to redact. - # - # Returns the documents passed as the first argument. - def redact(documents) - redact_cross_project_references(documents) unless can_read_cross_project? - - all_document_nodes = document_nodes(documents) - redact_document_nodes(all_document_nodes) - end - - # Redacts the given node documents - # - # data - An Array of a Hashes mapping an HTML document to nodes to redact. - def redact_document_nodes(all_document_nodes) - all_nodes = all_document_nodes.map { |x| x[:nodes] }.flatten - visible = nodes_visible_to_user(all_nodes) - metadata = [] - - all_document_nodes.each do |entry| - nodes_for_document = entry[:nodes] - - doc_data = { - document: entry[:document], - total_reference_count: nodes_for_document.count, - visible_reference_count: nodes_for_document.count - } - - metadata << doc_data - - nodes_for_document.each do |node| - next if visible.include?(node) - - doc_data[:visible_reference_count] -= 1 - redacted_content = redacted_node_content(node) - node.replace(redacted_content) - end - end - - metadata - end - - # Return redacted content of given node as either the original link ( tag), - # the original content (text), or the inner HTML of the node. - # - def redacted_node_content(node) - original_content = node.attr('data-original') - link_reference = node.attr('data-link-reference') - - # Build the raw tag just with a link as href and content if - # it's originally a link pattern. We shouldn't return a plain text href. - original_link = - if link_reference == 'true' - href = node.attr('href') - content = original_content - - %(#{content}) - end - - # The reference should be replaced by the original link's content, - # which is not always the same as the rendered one. - original_link || original_content || node.inner_html - end - - def redact_cross_project_references(documents) - extractor = Banzai::IssuableExtractor.new(context) - issuables = extractor.extract(documents) - - issuables.each do |node, issuable| - next if issuable.project == context.project_for_node(node) - - node['class'] = node['class'].gsub('has-tooltip', '') - node['title'] = nil - end - end - - # Returns the nodes visible to the current user. - # - # nodes - The input nodes to check. - # - # Returns a new Array containing the visible nodes. - def nodes_visible_to_user(nodes) - per_type = Hash.new { |h, k| h[k] = [] } - visible = Set.new - - nodes.each do |node| - per_type[node.attr('data-reference-type')] << node - end - - per_type.each do |type, nodes| - parser = Banzai::ReferenceParser[type].new(context) - - visible.merge(parser.nodes_visible_to_user(user, nodes)) - end - - visible - end - - def document_nodes(documents) - documents.map do |document| - { document: document, nodes: Querying.css(document, 'a.gfm[data-reference-type]') } - end - end - - private - - def can_read_cross_project? - Ability.allowed?(user, :read_cross_project) - end - end -end diff --git a/lib/banzai/reference_redactor.rb b/lib/banzai/reference_redactor.rb new file mode 100644 index 00000000000..eb5c35da375 --- /dev/null +++ b/lib/banzai/reference_redactor.rb @@ -0,0 +1,131 @@ +# frozen_string_literal: true + +module Banzai + # Class for removing Markdown references a certain user is not allowed to + # view. + class ReferenceRedactor + attr_reader :context + + # context - An instance of `Banzai::RenderContext`. + def initialize(context) + @context = context + end + + def user + context.current_user + end + + # Redacts the references in the given Array of documents. + # + # This method modifies the given documents in-place. + # + # documents - A list of HTML documents containing references to redact. + # + # Returns the documents passed as the first argument. + def redact(documents) + redact_cross_project_references(documents) unless can_read_cross_project? + + all_document_nodes = document_nodes(documents) + redact_document_nodes(all_document_nodes) + end + + # Redacts the given node documents + # + # data - An Array of a Hashes mapping an HTML document to nodes to redact. + def redact_document_nodes(all_document_nodes) + all_nodes = all_document_nodes.map { |x| x[:nodes] }.flatten + visible = nodes_visible_to_user(all_nodes) + metadata = [] + + all_document_nodes.each do |entry| + nodes_for_document = entry[:nodes] + + doc_data = { + document: entry[:document], + total_reference_count: nodes_for_document.count, + visible_reference_count: nodes_for_document.count + } + + metadata << doc_data + + nodes_for_document.each do |node| + next if visible.include?(node) + + doc_data[:visible_reference_count] -= 1 + redacted_content = redacted_node_content(node) + node.replace(redacted_content) + end + end + + metadata + end + + # Return redacted content of given node as either the original link ( tag), + # the original content (text), or the inner HTML of the node. + # + def redacted_node_content(node) + original_content = node.attr('data-original') + link_reference = node.attr('data-link-reference') + + # Build the raw tag just with a link as href and content if + # it's originally a link pattern. We shouldn't return a plain text href. + original_link = + if link_reference == 'true' + href = node.attr('href') + content = original_content + + %(#{content}) + end + + # The reference should be replaced by the original link's content, + # which is not always the same as the rendered one. + original_link || original_content || node.inner_html + end + + def redact_cross_project_references(documents) + extractor = Banzai::IssuableExtractor.new(context) + issuables = extractor.extract(documents) + + issuables.each do |node, issuable| + next if issuable.project == context.project_for_node(node) + + node['class'] = node['class'].gsub('has-tooltip', '') + node['title'] = nil + end + end + + # Returns the nodes visible to the current user. + # + # nodes - The input nodes to check. + # + # Returns a new Array containing the visible nodes. + def nodes_visible_to_user(nodes) + per_type = Hash.new { |h, k| h[k] = [] } + visible = Set.new + + nodes.each do |node| + per_type[node.attr('data-reference-type')] << node + end + + per_type.each do |type, nodes| + parser = Banzai::ReferenceParser[type].new(context) + + visible.merge(parser.nodes_visible_to_user(user, nodes)) + end + + visible + end + + def document_nodes(documents) + documents.map do |document| + { document: document, nodes: Querying.css(document, 'a.gfm[data-reference-type]') } + end + end + + private + + def can_read_cross_project? + Ability.allowed?(user, :read_cross_project) + end + end +end diff --git a/lib/banzai/renderer.rb b/lib/banzai/renderer.rb index 81f32ef5bcf..3cb9ec21e8f 100644 --- a/lib/banzai/renderer.rb +++ b/lib/banzai/renderer.rb @@ -134,7 +134,7 @@ module Banzai # # This method is used to perform state-dependent changes to a String of # HTML, such as removing references that the current user doesn't have - # permission to make (`RedactorFilter`). + # permission to make (`ReferenceRedactorFilter`). # # html - String to process # context - Hash of options to customize output diff --git a/spec/lib/banzai/filter/redactor_filter_spec.rb b/spec/lib/banzai/filter/redactor_filter_spec.rb deleted file mode 100644 index 919825a6102..00000000000 --- a/spec/lib/banzai/filter/redactor_filter_spec.rb +++ /dev/null @@ -1,205 +0,0 @@ -require 'spec_helper' - -describe Banzai::Filter::RedactorFilter do - include ActionView::Helpers::UrlHelper - include FilterSpecHelper - - it 'ignores non-GFM links' do - html = %(See Google) - doc = filter(html, current_user: build(:user)) - - expect(doc.css('a').length).to eq 1 - end - - def reference_link(data) - link_to('text', '', class: 'gfm', data: data) - end - - it 'skips when the skip_redaction flag is set' do - user = create(:user) - project = create(:project) - - link = reference_link(project: project.id, reference_type: 'test') - doc = filter(link, current_user: user, skip_redaction: true) - - expect(doc.css('a').length).to eq 1 - end - - context 'with data-project' do - let(:parser_class) do - Class.new(Banzai::ReferenceParser::BaseParser) do - self.reference_type = :test - end - end - - before do - allow(Banzai::ReferenceParser).to receive(:[]) - .with('test') - .and_return(parser_class) - end - - context 'valid projects' do - before do - allow_any_instance_of(Banzai::ReferenceParser::BaseParser).to receive(:can_read_reference?).and_return(true) - end - - it 'allows permitted Project references' do - user = create(:user) - project = create(:project) - project.add_maintainer(user) - - link = reference_link(project: project.id, reference_type: 'test') - doc = filter(link, current_user: user) - - expect(doc.css('a').length).to eq 1 - end - end - - context 'invalid projects' do - before do - allow_any_instance_of(Banzai::ReferenceParser::BaseParser).to receive(:can_read_reference?).and_return(false) - end - - it 'removes unpermitted references' do - user = create(:user) - project = create(:project) - - link = reference_link(project: project.id, reference_type: 'test') - doc = filter(link, current_user: user) - - expect(doc.css('a').length).to eq 0 - end - - it 'handles invalid references' do - link = reference_link(project: 12345, reference_type: 'test') - - expect { filter(link) }.not_to raise_error - end - end - end - - context 'with data-issue' do - context 'for confidential issues' do - it 'removes references for non project members' do - non_member = create(:user) - project = create(:project, :public) - issue = create(:issue, :confidential, project: project) - - link = reference_link(project: project.id, issue: issue.id, reference_type: 'issue') - doc = filter(link, current_user: non_member) - - expect(doc.css('a').length).to eq 0 - end - - it 'removes references for project members with guest role' do - member = create(:user) - project = create(:project, :public) - project.add_guest(member) - issue = create(:issue, :confidential, project: project) - - link = reference_link(project: project.id, issue: issue.id, reference_type: 'issue') - doc = filter(link, current_user: member) - - expect(doc.css('a').length).to eq 0 - end - - it 'allows references for author' do - author = create(:user) - project = create(:project, :public) - issue = create(:issue, :confidential, project: project, author: author) - - link = reference_link(project: project.id, issue: issue.id, reference_type: 'issue') - doc = filter(link, current_user: author) - - expect(doc.css('a').length).to eq 1 - end - - it 'allows references for assignee' do - assignee = create(:user) - project = create(:project, :public) - issue = create(:issue, :confidential, project: project, assignees: [assignee]) - - link = reference_link(project: project.id, issue: issue.id, reference_type: 'issue') - doc = filter(link, current_user: assignee) - - expect(doc.css('a').length).to eq 1 - end - - it 'allows references for project members' do - member = create(:user) - project = create(:project, :public) - project.add_developer(member) - issue = create(:issue, :confidential, project: project) - - link = reference_link(project: project.id, issue: issue.id, reference_type: 'issue') - doc = filter(link, current_user: member) - - expect(doc.css('a').length).to eq 1 - end - - it 'allows references for admin' do - admin = create(:admin) - project = create(:project, :public) - issue = create(:issue, :confidential, project: project) - - link = reference_link(project: project.id, issue: issue.id, reference_type: 'issue') - doc = filter(link, current_user: admin) - - expect(doc.css('a').length).to eq 1 - end - end - - it 'allows references for non confidential issues' do - user = create(:user) - project = create(:project, :public) - issue = create(:issue, project: project) - - link = reference_link(project: project.id, issue: issue.id, reference_type: 'issue') - doc = filter(link, current_user: user) - - expect(doc.css('a').length).to eq 1 - end - end - - context "for user references" do - context 'with data-group' do - it 'removes unpermitted Group references' do - user = create(:user) - group = create(:group, :private) - - link = reference_link(group: group.id, reference_type: 'user') - doc = filter(link, current_user: user) - - expect(doc.css('a').length).to eq 0 - end - - it 'allows permitted Group references' do - user = create(:user) - group = create(:group, :private) - group.add_developer(user) - - link = reference_link(group: group.id, reference_type: 'user') - doc = filter(link, current_user: user) - - expect(doc.css('a').length).to eq 1 - end - - it 'handles invalid Group references' do - link = reference_link(group: 12345, reference_type: 'user') - - expect { filter(link) }.not_to raise_error - end - end - - context 'with data-user' do - it 'allows any User reference' do - user = create(:user) - - link = reference_link(user: user.id, reference_type: 'user') - doc = filter(link) - - expect(doc.css('a').length).to eq 1 - end - end - end -end diff --git a/spec/lib/banzai/filter/reference_redactor_filter_spec.rb b/spec/lib/banzai/filter/reference_redactor_filter_spec.rb new file mode 100644 index 00000000000..e87440895e0 --- /dev/null +++ b/spec/lib/banzai/filter/reference_redactor_filter_spec.rb @@ -0,0 +1,205 @@ +require 'spec_helper' + +describe Banzai::Filter::ReferenceRedactorFilter do + include ActionView::Helpers::UrlHelper + include FilterSpecHelper + + it 'ignores non-GFM links' do + html = %(See Google) + doc = filter(html, current_user: build(:user)) + + expect(doc.css('a').length).to eq 1 + end + + def reference_link(data) + link_to('text', '', class: 'gfm', data: data) + end + + it 'skips when the skip_redaction flag is set' do + user = create(:user) + project = create(:project) + + link = reference_link(project: project.id, reference_type: 'test') + doc = filter(link, current_user: user, skip_redaction: true) + + expect(doc.css('a').length).to eq 1 + end + + context 'with data-project' do + let(:parser_class) do + Class.new(Banzai::ReferenceParser::BaseParser) do + self.reference_type = :test + end + end + + before do + allow(Banzai::ReferenceParser).to receive(:[]) + .with('test') + .and_return(parser_class) + end + + context 'valid projects' do + before do + allow_any_instance_of(Banzai::ReferenceParser::BaseParser).to receive(:can_read_reference?).and_return(true) + end + + it 'allows permitted Project references' do + user = create(:user) + project = create(:project) + project.add_maintainer(user) + + link = reference_link(project: project.id, reference_type: 'test') + doc = filter(link, current_user: user) + + expect(doc.css('a').length).to eq 1 + end + end + + context 'invalid projects' do + before do + allow_any_instance_of(Banzai::ReferenceParser::BaseParser).to receive(:can_read_reference?).and_return(false) + end + + it 'removes unpermitted references' do + user = create(:user) + project = create(:project) + + link = reference_link(project: project.id, reference_type: 'test') + doc = filter(link, current_user: user) + + expect(doc.css('a').length).to eq 0 + end + + it 'handles invalid references' do + link = reference_link(project: 12345, reference_type: 'test') + + expect { filter(link) }.not_to raise_error + end + end + end + + context 'with data-issue' do + context 'for confidential issues' do + it 'removes references for non project members' do + non_member = create(:user) + project = create(:project, :public) + issue = create(:issue, :confidential, project: project) + + link = reference_link(project: project.id, issue: issue.id, reference_type: 'issue') + doc = filter(link, current_user: non_member) + + expect(doc.css('a').length).to eq 0 + end + + it 'removes references for project members with guest role' do + member = create(:user) + project = create(:project, :public) + project.add_guest(member) + issue = create(:issue, :confidential, project: project) + + link = reference_link(project: project.id, issue: issue.id, reference_type: 'issue') + doc = filter(link, current_user: member) + + expect(doc.css('a').length).to eq 0 + end + + it 'allows references for author' do + author = create(:user) + project = create(:project, :public) + issue = create(:issue, :confidential, project: project, author: author) + + link = reference_link(project: project.id, issue: issue.id, reference_type: 'issue') + doc = filter(link, current_user: author) + + expect(doc.css('a').length).to eq 1 + end + + it 'allows references for assignee' do + assignee = create(:user) + project = create(:project, :public) + issue = create(:issue, :confidential, project: project, assignees: [assignee]) + + link = reference_link(project: project.id, issue: issue.id, reference_type: 'issue') + doc = filter(link, current_user: assignee) + + expect(doc.css('a').length).to eq 1 + end + + it 'allows references for project members' do + member = create(:user) + project = create(:project, :public) + project.add_developer(member) + issue = create(:issue, :confidential, project: project) + + link = reference_link(project: project.id, issue: issue.id, reference_type: 'issue') + doc = filter(link, current_user: member) + + expect(doc.css('a').length).to eq 1 + end + + it 'allows references for admin' do + admin = create(:admin) + project = create(:project, :public) + issue = create(:issue, :confidential, project: project) + + link = reference_link(project: project.id, issue: issue.id, reference_type: 'issue') + doc = filter(link, current_user: admin) + + expect(doc.css('a').length).to eq 1 + end + end + + it 'allows references for non confidential issues' do + user = create(:user) + project = create(:project, :public) + issue = create(:issue, project: project) + + link = reference_link(project: project.id, issue: issue.id, reference_type: 'issue') + doc = filter(link, current_user: user) + + expect(doc.css('a').length).to eq 1 + end + end + + context "for user references" do + context 'with data-group' do + it 'removes unpermitted Group references' do + user = create(:user) + group = create(:group, :private) + + link = reference_link(group: group.id, reference_type: 'user') + doc = filter(link, current_user: user) + + expect(doc.css('a').length).to eq 0 + end + + it 'allows permitted Group references' do + user = create(:user) + group = create(:group, :private) + group.add_developer(user) + + link = reference_link(group: group.id, reference_type: 'user') + doc = filter(link, current_user: user) + + expect(doc.css('a').length).to eq 1 + end + + it 'handles invalid Group references' do + link = reference_link(group: 12345, reference_type: 'user') + + expect { filter(link) }.not_to raise_error + end + end + + context 'with data-user' do + it 'allows any User reference' do + user = create(:user) + + link = reference_link(user: user.id, reference_type: 'user') + doc = filter(link) + + expect(doc.css('a').length).to eq 1 + end + end + end +end diff --git a/spec/lib/banzai/object_renderer_spec.rb b/spec/lib/banzai/object_renderer_spec.rb index 7b855251a74..e3e6e22568c 100644 --- a/spec/lib/banzai/object_renderer_spec.rb +++ b/spec/lib/banzai/object_renderer_spec.rb @@ -22,8 +22,8 @@ describe Banzai::ObjectRenderer do expect(object.user_visible_reference_count).to eq 0 end - it 'calls Banzai::Redactor to perform redaction' do - expect_any_instance_of(Banzai::Redactor).to receive(:redact).and_call_original + it 'calls Banzai::ReferenceRedactor to perform redaction' do + expect_any_instance_of(Banzai::ReferenceRedactor).to receive(:redact).and_call_original renderer.render([object], :note) end @@ -82,8 +82,8 @@ describe Banzai::ObjectRenderer do expect(cacheless_thing.redacted_title_html).to eq("Merge branch 'branch-merged' into 'master'") end - it 'calls Banzai::Redactor to perform redaction' do - expect_any_instance_of(Banzai::Redactor).to receive(:redact).and_call_original + it 'calls Banzai::ReferenceRedactor to perform redaction' do + expect_any_instance_of(Banzai::ReferenceRedactor).to receive(:redact).and_call_original renderer.render([cacheless_thing], :title) end diff --git a/spec/lib/banzai/redactor_spec.rb b/spec/lib/banzai/redactor_spec.rb deleted file mode 100644 index 718649e0e10..00000000000 --- a/spec/lib/banzai/redactor_spec.rb +++ /dev/null @@ -1,182 +0,0 @@ -require 'spec_helper' - -describe Banzai::Redactor do - let(:user) { create(:user) } - let(:project) { build(:project) } - let(:redactor) { described_class.new(Banzai::RenderContext.new(project, user)) } - - describe '#redact' do - context 'when reference not visible to user' do - before do - expect(redactor).to receive(:nodes_visible_to_user).and_return([]) - end - - it 'redacts an array of documents' do - doc1 = Nokogiri::HTML - .fragment('foo') - - doc2 = Nokogiri::HTML - .fragment('bar') - - redacted_data = redactor.redact([doc1, doc2]) - - expect(redacted_data.map { |data| data[:document] }).to eq([doc1, doc2]) - expect(redacted_data.map { |data| data[:visible_reference_count] }).to eq([0, 0]) - expect(doc1.to_html).to eq('foo') - expect(doc2.to_html).to eq('bar') - end - - it 'replaces redacted reference with inner HTML' do - doc = Nokogiri::HTML.fragment("foo") - redactor.redact([doc]) - expect(doc.to_html).to eq('foo') - end - - context 'when data-original attribute provided' do - let(:original_content) { 'foo' } - it 'replaces redacted reference with original content' do - doc = Nokogiri::HTML.fragment("bar") - redactor.redact([doc]) - expect(doc.to_html).to eq(original_content) - end - - it 'does not replace redacted reference with original content if href is given' do - html = "Marge" - doc = Nokogiri::HTML.fragment(html) - redactor.redact([doc]) - expect(doc.to_html).to eq('Marge') - end - - it 'uses the original content as the link content if given' do - html = "Marge" - doc = Nokogiri::HTML.fragment(html) - redactor.redact([doc]) - expect(doc.to_html).to eq('Homer') - end - end - end - - context 'when project is in pending delete' do - let!(:issue) { create(:issue, project: project) } - let(:redactor) { described_class.new(Banzai::RenderContext.new(project, user)) } - - before do - project.update(pending_delete: true) - end - - it 'redacts an issue attached' do - doc = Nokogiri::HTML.fragment("foo") - - redactor.redact([doc]) - - expect(doc.to_html).to eq('foo') - end - - it 'redacts an external issue' do - doc = Nokogiri::HTML.fragment("foo") - - redactor.redact([doc]) - - expect(doc.to_html).to eq('foo') - end - end - - context 'when reference visible to user' do - it 'does not redact an array of documents' do - doc1_html = 'foo' - doc1 = Nokogiri::HTML.fragment(doc1_html) - - doc2_html = 'bar' - doc2 = Nokogiri::HTML.fragment(doc2_html) - - nodes = redactor.document_nodes([doc1, doc2]).map { |x| x[:nodes] } - expect(redactor).to receive(:nodes_visible_to_user).and_return(nodes.flatten) - - redacted_data = redactor.redact([doc1, doc2]) - - expect(redacted_data.map { |data| data[:document] }).to eq([doc1, doc2]) - expect(redacted_data.map { |data| data[:visible_reference_count] }).to eq([1, 1]) - expect(doc1.to_html).to eq(doc1_html) - expect(doc2.to_html).to eq(doc2_html) - end - end - end - - context 'when the user cannot read cross project' do - include ActionView::Helpers::UrlHelper - let(:project) { create(:project) } - let(:other_project) { create(:project, :public) } - - def create_link(issuable) - type = issuable.class.name.underscore.downcase - link_to(issuable.to_reference, '', - class: 'gfm has-tooltip', - title: issuable.title, - data: { - reference_type: type, - "#{type}": issuable.id - }) - end - - before do - project.add_developer(user) - - allow(Ability).to receive(:allowed?).and_call_original - allow(Ability).to receive(:allowed?).with(user, :read_cross_project, :global) { false } - allow(Ability).to receive(:allowed?).with(user, :read_cross_project) { false } - end - - it 'skips links to issues within the same project' do - issue = create(:issue, project: project) - link = create_link(issue) - doc = Nokogiri::HTML.fragment(link) - - redactor.redact([doc]) - result = doc.css('a').last - - expect(result['class']).to include('has-tooltip') - expect(result['title']).to eq(issue.title) - end - - it 'removes info from a cross project reference' do - issue = create(:issue, project: other_project) - link = create_link(issue) - doc = Nokogiri::HTML.fragment(link) - - redactor.redact([doc]) - result = doc.css('a').last - - expect(result['class']).not_to include('has-tooltip') - expect(result['title']).to be_empty - end - end - - describe '#redact_nodes' do - it 'redacts an Array of nodes' do - doc = Nokogiri::HTML.fragment('foo') - node = doc.children[0] - - expect(redactor).to receive(:nodes_visible_to_user) - .with([node]) - .and_return(Set.new) - - redactor.redact_document_nodes([{ document: doc, nodes: [node] }]) - - expect(doc.to_html).to eq('foo') - end - end - - describe '#nodes_visible_to_user' do - it 'returns a Set containing the visible nodes' do - doc = Nokogiri::HTML.fragment('') - node = doc.children[0] - - expect_any_instance_of(Banzai::ReferenceParser::IssueParser) - .to receive(:nodes_visible_to_user) - .with(user, [node]) - .and_return([node]) - - expect(redactor.nodes_visible_to_user([node])).to eq(Set.new([node])) - end - end -end diff --git a/spec/lib/banzai/reference_redactor_spec.rb b/spec/lib/banzai/reference_redactor_spec.rb new file mode 100644 index 00000000000..a3b47c4d826 --- /dev/null +++ b/spec/lib/banzai/reference_redactor_spec.rb @@ -0,0 +1,182 @@ +require 'spec_helper' + +describe Banzai::ReferenceRedactor do + let(:user) { create(:user) } + let(:project) { build(:project) } + let(:redactor) { described_class.new(Banzai::RenderContext.new(project, user)) } + + describe '#redact' do + context 'when reference not visible to user' do + before do + expect(redactor).to receive(:nodes_visible_to_user).and_return([]) + end + + it 'redacts an array of documents' do + doc1 = Nokogiri::HTML + .fragment('foo') + + doc2 = Nokogiri::HTML + .fragment('bar') + + redacted_data = redactor.redact([doc1, doc2]) + + expect(redacted_data.map { |data| data[:document] }).to eq([doc1, doc2]) + expect(redacted_data.map { |data| data[:visible_reference_count] }).to eq([0, 0]) + expect(doc1.to_html).to eq('foo') + expect(doc2.to_html).to eq('bar') + end + + it 'replaces redacted reference with inner HTML' do + doc = Nokogiri::HTML.fragment("foo") + redactor.redact([doc]) + expect(doc.to_html).to eq('foo') + end + + context 'when data-original attribute provided' do + let(:original_content) { 'foo' } + it 'replaces redacted reference with original content' do + doc = Nokogiri::HTML.fragment("bar") + redactor.redact([doc]) + expect(doc.to_html).to eq(original_content) + end + + it 'does not replace redacted reference with original content if href is given' do + html = "Marge" + doc = Nokogiri::HTML.fragment(html) + redactor.redact([doc]) + expect(doc.to_html).to eq('Marge') + end + + it 'uses the original content as the link content if given' do + html = "Marge" + doc = Nokogiri::HTML.fragment(html) + redactor.redact([doc]) + expect(doc.to_html).to eq('Homer') + end + end + end + + context 'when project is in pending delete' do + let!(:issue) { create(:issue, project: project) } + let(:redactor) { described_class.new(Banzai::RenderContext.new(project, user)) } + + before do + project.update(pending_delete: true) + end + + it 'redacts an issue attached' do + doc = Nokogiri::HTML.fragment("foo") + + redactor.redact([doc]) + + expect(doc.to_html).to eq('foo') + end + + it 'redacts an external issue' do + doc = Nokogiri::HTML.fragment("foo") + + redactor.redact([doc]) + + expect(doc.to_html).to eq('foo') + end + end + + context 'when reference visible to user' do + it 'does not redact an array of documents' do + doc1_html = 'foo' + doc1 = Nokogiri::HTML.fragment(doc1_html) + + doc2_html = 'bar' + doc2 = Nokogiri::HTML.fragment(doc2_html) + + nodes = redactor.document_nodes([doc1, doc2]).map { |x| x[:nodes] } + expect(redactor).to receive(:nodes_visible_to_user).and_return(nodes.flatten) + + redacted_data = redactor.redact([doc1, doc2]) + + expect(redacted_data.map { |data| data[:document] }).to eq([doc1, doc2]) + expect(redacted_data.map { |data| data[:visible_reference_count] }).to eq([1, 1]) + expect(doc1.to_html).to eq(doc1_html) + expect(doc2.to_html).to eq(doc2_html) + end + end + end + + context 'when the user cannot read cross project' do + include ActionView::Helpers::UrlHelper + let(:project) { create(:project) } + let(:other_project) { create(:project, :public) } + + def create_link(issuable) + type = issuable.class.name.underscore.downcase + link_to(issuable.to_reference, '', + class: 'gfm has-tooltip', + title: issuable.title, + data: { + reference_type: type, + "#{type}": issuable.id + }) + end + + before do + project.add_developer(user) + + allow(Ability).to receive(:allowed?).and_call_original + allow(Ability).to receive(:allowed?).with(user, :read_cross_project, :global) { false } + allow(Ability).to receive(:allowed?).with(user, :read_cross_project) { false } + end + + it 'skips links to issues within the same project' do + issue = create(:issue, project: project) + link = create_link(issue) + doc = Nokogiri::HTML.fragment(link) + + redactor.redact([doc]) + result = doc.css('a').last + + expect(result['class']).to include('has-tooltip') + expect(result['title']).to eq(issue.title) + end + + it 'removes info from a cross project reference' do + issue = create(:issue, project: other_project) + link = create_link(issue) + doc = Nokogiri::HTML.fragment(link) + + redactor.redact([doc]) + result = doc.css('a').last + + expect(result['class']).not_to include('has-tooltip') + expect(result['title']).to be_empty + end + end + + describe '#redact_nodes' do + it 'redacts an Array of nodes' do + doc = Nokogiri::HTML.fragment('foo') + node = doc.children[0] + + expect(redactor).to receive(:nodes_visible_to_user) + .with([node]) + .and_return(Set.new) + + redactor.redact_document_nodes([{ document: doc, nodes: [node] }]) + + expect(doc.to_html).to eq('foo') + end + end + + describe '#nodes_visible_to_user' do + it 'returns a Set containing the visible nodes' do + doc = Nokogiri::HTML.fragment('') + node = doc.children[0] + + expect_any_instance_of(Banzai::ReferenceParser::IssueParser) + .to receive(:nodes_visible_to_user) + .with(user, [node]) + .and_return([node]) + + expect(redactor.nodes_visible_to_user([node])).to eq(Set.new([node])) + end + end +end -- cgit v1.2.1 From 9d5ce415cc1f541e810c1b3961bd1a01d25a4f68 Mon Sep 17 00:00:00 2001 From: Annabel Dunstone Gray Date: Tue, 16 Jul 2019 21:49:04 +0000 Subject: Revert "Merge branch 'button-bug-fixes' into 'master'" This reverts merge request !30678 --- app/assets/stylesheets/pages/projects.scss | 2 +- changelogs/unreleased/button-bug-fixes.yml | 5 ----- 2 files changed, 1 insertion(+), 6 deletions(-) delete mode 100644 changelogs/unreleased/button-bug-fixes.yml diff --git a/app/assets/stylesheets/pages/projects.scss b/app/assets/stylesheets/pages/projects.scss index e453f4a2264..c80beceae52 100644 --- a/app/assets/stylesheets/pages/projects.scss +++ b/app/assets/stylesheets/pages/projects.scss @@ -303,7 +303,7 @@ .count-badge-count, .count-badge-button { - border: 1px solid $gray-400; + border: 1px solid $border-color; line-height: 1; } diff --git a/changelogs/unreleased/button-bug-fixes.yml b/changelogs/unreleased/button-bug-fixes.yml deleted file mode 100644 index b63bfdf24ad..00000000000 --- a/changelogs/unreleased/button-bug-fixes.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Fix Project Badge Button Styles -merge_request: 30678 -author: -type: fixed -- cgit v1.2.1 From d87c6b634e8d138a4fc6f94df1b517e63ea32db0 Mon Sep 17 00:00:00 2001 From: Stan Hu Date: Tue, 16 Jul 2019 10:07:07 -0700 Subject: Bump fog-aws to v3.5.2 This will make it possible for Oracle Cloud to work with S3 by disabling Signature V4 streaming (https://github.com/fog/fog-aws/issues/523). Full CHANGELOG: https://github.com/fog/fog-aws/blob/master/CHANGELOG.md Closes https://gitlab.com/gitlab-org/gitlab-ce/issues/63041 --- Gemfile | 2 +- Gemfile.lock | 4 ++-- changelogs/unreleased/sh-bump-fog-aws.yml | 5 +++++ 3 files changed, 8 insertions(+), 3 deletions(-) create mode 100644 changelogs/unreleased/sh-bump-fog-aws.yml diff --git a/Gemfile b/Gemfile index 7845e9d57fa..8bffc2a973d 100644 --- a/Gemfile +++ b/Gemfile @@ -100,7 +100,7 @@ gem 'carrierwave', '~> 1.3' gem 'mini_magick' # for backups -gem 'fog-aws', '~> 3.3' +gem 'fog-aws', '~> 3.5' # Locked until fog-google resolves https://github.com/fog/fog-google/issues/421. # Also see config/initializers/fog_core_patch.rb. gem 'fog-core', '= 2.1.0' diff --git a/Gemfile.lock b/Gemfile.lock index beded888ffd..60939ae918c 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -253,7 +253,7 @@ GEM fog-json ipaddress (~> 0.8) xml-simple (~> 1.1) - fog-aws (3.3.0) + fog-aws (3.5.2) fog-core (~> 2.1) fog-json (~> 1.1) fog-xml (~> 0.1) @@ -1105,7 +1105,7 @@ DEPENDENCIES flipper-active_support_cache_store (~> 0.13.0) flowdock (~> 0.7) fog-aliyun (~> 0.3) - fog-aws (~> 3.3) + fog-aws (~> 3.5) fog-core (= 2.1.0) fog-google (~> 1.8) fog-local (~> 0.6) diff --git a/changelogs/unreleased/sh-bump-fog-aws.yml b/changelogs/unreleased/sh-bump-fog-aws.yml new file mode 100644 index 00000000000..a936b81ff02 --- /dev/null +++ b/changelogs/unreleased/sh-bump-fog-aws.yml @@ -0,0 +1,5 @@ +--- +title: Bump fog-aws to v3.5.2 +merge_request: 30803 +author: +type: fixed -- cgit v1.2.1 From e7648b04ca1d7ae231a5e80cd6b0fa295d023a9b Mon Sep 17 00:00:00 2001 From: Artur Trzop Date: Wed, 17 Jul 2019 00:31:22 +0000 Subject: Add 3rd party parallel tools section to docs --- doc/ci/examples/README.md | 1 + doc/ci/yaml/README.md | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/doc/ci/examples/README.md b/doc/ci/examples/README.md index 5a302392c54..9295dcfd4e0 100644 --- a/doc/ci/examples/README.md +++ b/doc/ci/examples/README.md @@ -37,6 +37,7 @@ The following table lists examples with step-by-step tutorials that are containe | Python on Heroku | [Test and deploy a Python application with GitLab CI/CD](test-and-deploy-python-application-to-heroku.md). | | Ruby on Heroku | [Test and deploy a Ruby application with GitLab CI/CD](test-and-deploy-ruby-application-to-heroku.md). | | Scala on Heroku | [Test and deploy a Scala application to Heroku](test-scala-application.md). | +| Parallel testing Ruby & JS | [GitLab CI parallel jobs testing for Ruby & JavaScript projects](https://docs.knapsackpro.com/2019/how-to-run-parallel-jobs-for-rspec-tests-on-gitlab-ci-pipeline-and-speed-up-ruby-javascript-testing). | ### Contributing examples diff --git a/doc/ci/yaml/README.md b/doc/ci/yaml/README.md index b1b193701c3..001f951ebb8 100644 --- a/doc/ci/yaml/README.md +++ b/doc/ci/yaml/README.md @@ -1779,6 +1779,10 @@ test: parallel: 5 ``` +TIP: **Tip:** +Parallelize tests suites across parallel jobs. +Different languages have different tools to facilitate this. + ### `trigger` **(PREMIUM)** > [Introduced](https://gitlab.com/gitlab-org/gitlab-ee/issues/8997) in [GitLab Premium](https://about.gitlab.com/pricing/) 11.8. -- cgit v1.2.1 From 443aad5f1c5c6aa61b92f68a22b96a38c72aaffa Mon Sep 17 00:00:00 2001 From: Marcia Ramos Date: Wed, 17 Jul 2019 00:39:22 +0000 Subject: Docs: update Cloudflare's redirect method for Pages --- .../custom_domains_ssl_tls_certification/index.md | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/doc/user/project/pages/custom_domains_ssl_tls_certification/index.md b/doc/user/project/pages/custom_domains_ssl_tls_certification/index.md index 6c0d3e9e9d3..219e141d72e 100644 --- a/doc/user/project/pages/custom_domains_ssl_tls_certification/index.md +++ b/doc/user/project/pages/custom_domains_ssl_tls_certification/index.md @@ -179,15 +179,26 @@ From that page, you can view, add, and remove them. ### Redirecting `www.domain.com` to `domain.com` with Cloudflare -If you use Cloudflare, you can redirect `www` to `domain.com` without adding both -`www.domain.com` and `domain.com` to GitLab. This happens due to a [Cloudflare feature that creates -a 301 redirect as a "page rule"](https://gitlab.com/gitlab-org/gitlab-ce/issues/48848#note_87314849) for redirecting `www.domain.com` to `domain.com`. In this case, -you can use the following setup: +If you use Cloudflare, you can redirect `www` to `domain.com` +without adding both `www.domain.com` and `domain.com` to GitLab. + +To do so, you can use Cloudflare's page rules associated to a +CNAME record to redirect `www.domain.com` to `domain.com`. You +can use the following setup: 1. In Cloudflare, create a DNS `A` record pointing `domain.com` to `35.185.44.232`. -1. In GitLab, add the domain to GitLab Pages. +1. In GitLab, add the domain to GitLab Pages and get the verification code. 1. In Cloudflare, create a DNS `TXT` record to verify your domain. +1. In GitLab, verify your domain. 1. In Cloudflare, create a DNS `CNAME` record pointing `www` to `domain.com`. +1. In Cloudflare, add a Page Rule pointing `www.domain,com` to `domain.com`: + - Navigate to your domain's dashboard and click **Page Rules** + on the top nav. + - Click **Create Page Rule**. + - Enter the domain `www.domain.com` and click **+ Add a Setting**. + - From the dropdown menu, choose **Forwarding URL**, then select the + status code **301 - Permanent Redirect**. + - Enter the destination URL `https://domain.com`. ## Adding an SSL/TLS certificate to Pages -- cgit v1.2.1 From 5c97713bcd5b8db4332b4702d0fc6524d02f4a74 Mon Sep 17 00:00:00 2001 From: Fabien Catteau Date: Wed, 17 Jul 2019 00:59:03 +0000 Subject: Propagate PIP index URL Propagate PIP_INDEX_URL, PIP_EXTRA_INDEX_URL to the dependency-scanning Docker image to support Python projects depending on custom Pypi registries. These variables will be consumed by the gemnasium-python analyzer. --- doc/user/application_security/dependency_scanning/index.md | 2 ++ lib/gitlab/ci/templates/Security/Dependency-Scanning.gitlab-ci.yml | 2 ++ 2 files changed, 4 insertions(+) diff --git a/doc/user/application_security/dependency_scanning/index.md b/doc/user/application_security/dependency_scanning/index.md index 0dd0fd3f136..09bd306363c 100644 --- a/doc/user/application_security/dependency_scanning/index.md +++ b/doc/user/application_security/dependency_scanning/index.md @@ -149,6 +149,8 @@ using environment variables. | `DS_DOCKER_CLIENT_NEGOTIATION_TIMEOUT` | Time limit for Docker client negotiation. Timeouts are parsed using Go's [`ParseDuration`](https://golang.org/pkg/time/#ParseDuration). Valid time units are `ns`, `us` (or `µs`), `ms`, `s`, `m`, `h`. For example, `300ms`, `1.5h`, or `2h45m`. | | `DS_PULL_ANALYZER_IMAGE_TIMEOUT` | Time limit when pulling the image of an analyzer. Timeouts are parsed using Go's [`ParseDuration`](https://golang.org/pkg/time/#ParseDuration). Valid time units are `ns`, `us` (or `µs`), `ms`, `s`, `m`, `h`. For example, `300ms`, `1.5h`, or `2h45m`. | | `DS_RUN_ANALYZER_TIMEOUT` | Time limit when running an analyzer. Timeouts are parsed using Go's [`ParseDuration`](https://golang.org/pkg/time/#ParseDuration). Valid time units are `ns`, `us` (or `µs`), `ms`, `s`, `m`, `h`. For example, `300ms`, `1.5h`, or `2h45m`. | +| `PIP_INDEX_URL` | Base URL of Python Package Index (default https://pypi.org/simple). | +| `PIP_EXTRA_INDEX_URL` | Array of [extra URLs](https://pip.pypa.io/en/stable/reference/pip_install/#cmdoption-extra-index-url) of package indexes to use in addition to `PIP_INDEX_URL`. Comma separated. | ## Reports JSON format diff --git a/lib/gitlab/ci/templates/Security/Dependency-Scanning.gitlab-ci.yml b/lib/gitlab/ci/templates/Security/Dependency-Scanning.gitlab-ci.yml index f176771775e..89eccce69f6 100644 --- a/lib/gitlab/ci/templates/Security/Dependency-Scanning.gitlab-ci.yml +++ b/lib/gitlab/ci/templates/Security/Dependency-Scanning.gitlab-ci.yml @@ -41,6 +41,8 @@ dependency_scanning: DS_PULL_ANALYZER_IMAGE_TIMEOUT \ DS_RUN_ANALYZER_TIMEOUT \ DS_PYTHON_VERSION \ + PIP_INDEX_URL \ + PIP_EXTRA_INDEX_URL \ ) \ --volume "$PWD:/code" \ --volume /var/run/docker.sock:/var/run/docker.sock \ -- cgit v1.2.1 From 55ab098eb1a778e794de8afb2773645405a11a7b Mon Sep 17 00:00:00 2001 From: Elliot Rushton Date: Wed, 17 Jul 2019 04:19:00 +0000 Subject: Add tip about stripping ANSI color codes --- doc/user/project/pipelines/settings.md | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/doc/user/project/pipelines/settings.md b/doc/user/project/pipelines/settings.md index e60da6a3e59..df82daa3da3 100644 --- a/doc/user/project/pipelines/settings.md +++ b/doc/user/project/pipelines/settings.md @@ -89,6 +89,22 @@ in the jobs table. A few examples of known coverage tools for a variety of languages can be found in the pipelines settings page. +### Removing color codes + +Some test coverage tools output with ANSI color codes that won't be +parsed correctly by the regular expression and will cause coverage +parsing to fail. + +If your coverage tool doesn't provide an option to disable color +codes in the output, you can pipe the output of the coverage tool through a +small one line script that will strip the color codes off. + +For example: + +```bash +lein cloverage | perl -pe 's/\e\[?.*?[\@-~]//g' +``` + ## Visibility of pipelines Access to pipelines and job details (including output of logs and artifacts) -- cgit v1.2.1 From e4fe6868d86f3093e5682470511a14536bde8d71 Mon Sep 17 00:00:00 2001 From: Russell Dickenson Date: Wed, 17 Jul 2019 05:33:52 +0000 Subject: Documented autocomplete characters - Added a table listing all autocomplete characters. - Added a link to the autocomplete characters docs, from the Projects feature list. - Added an example of how autocomplete would behave for `Users and groups`, including two screenshots. --- doc/user/project/autocomplete_characters.md | 48 +++++++++++++++++++++ .../img/autocomplete_characters_example1_v12_0.png | Bin 0 -> 17510 bytes .../img/autocomplete_characters_example2_v12_0.png | Bin 0 -> 14623 bytes doc/user/project/index.md | 3 ++ 4 files changed, 51 insertions(+) create mode 100644 doc/user/project/autocomplete_characters.md create mode 100755 doc/user/project/img/autocomplete_characters_example1_v12_0.png create mode 100755 doc/user/project/img/autocomplete_characters_example2_v12_0.png diff --git a/doc/user/project/autocomplete_characters.md b/doc/user/project/autocomplete_characters.md new file mode 100644 index 00000000000..9ebf7f821a1 --- /dev/null +++ b/doc/user/project/autocomplete_characters.md @@ -0,0 +1,48 @@ +# Autocomplete characters + +The autocomplete characters provide a quick way of entering field values into +Markdown fields. When you start typing a word in a Markdown field with one of +the following characters, GitLab progressively autocompletes against a set of +matching values. The string matching is not case sensitive. + +| Character | Autocompletes | +| :-------- | :------------ | +| `~` | Labels | +| `%` | Milestones | +| `@` | Users and groups | +| `#` | Issues | +| `!` | Merge requests | +| `&` | Epics | +| `$` | Snippets | +| `:` | Emoji | +| `/` | Quick Actions | + +Up to 5 of the most relevant matches are displayed in a popup list. When you +select an item from the list, the value is entered in the field. The more +characters you enter, the more precise the matches are. + +Autocomplete characters are useful when combined with [Quick Actions](quick_actions.md). + +## Example + +Assume your GitLab instance includes the following users: + +| Username | Name | +| :-------------- | :--- | +| alessandra | Rosy Grant | +| lawrence.white | Kelsey Kerluke | +| leanna | Rosemarie Rogahn | +| logan_gutkowski | Lee Wuckert | +| shelba | Josefine Haley | + +In an Issue comment, entering `@l` results in the following popup list +appearing. Note that user `shelba` is not included, because the list includes +only the 5 users most relevant to the Issue. + +![Popup list which includes users whose username or name contains the letter `l`](img/autocomplete_characters_example1_v12_0.png) + +If you continue to type, `@le`, the popup list changes to the following. The +popup now only includes users where `le` appears in their username, or a word in +their name. + +![Popup list which includes users whose username or name contains the string `le`](img/autocomplete_characters_example2_v12_0.png) diff --git a/doc/user/project/img/autocomplete_characters_example1_v12_0.png b/doc/user/project/img/autocomplete_characters_example1_v12_0.png new file mode 100755 index 00000000000..9c6fa923b80 Binary files /dev/null and b/doc/user/project/img/autocomplete_characters_example1_v12_0.png differ diff --git a/doc/user/project/img/autocomplete_characters_example2_v12_0.png b/doc/user/project/img/autocomplete_characters_example2_v12_0.png new file mode 100755 index 00000000000..b2e8a782a0b Binary files /dev/null and b/doc/user/project/img/autocomplete_characters_example2_v12_0.png differ diff --git a/doc/user/project/index.md b/doc/user/project/index.md index 0ffa69b6b78..7307c5b8991 100644 --- a/doc/user/project/index.md +++ b/doc/user/project/index.md @@ -52,6 +52,9 @@ When you create a project in GitLab, you'll have access to a large number of templates for issue and merge request description fields for your project - [Slash commands (quick actions)](quick_actions.md): Textual shortcuts for common actions on issues or merge requests +- [Autocomplete characters](autocomplete_characters.md): Autocomplete + references to users, groups, issues, merge requests, and other GitLab + elements. - [Web IDE](web_ide/index.md) **GitLab CI/CD:** -- cgit v1.2.1 From 34c6f2723c3bc44aba1d9d886522fdfe8db6a9f6 Mon Sep 17 00:00:00 2001 From: Guillaume Grossetie Date: Wed, 10 Jul 2019 10:30:10 +0200 Subject: Preserve footnote link ids --- ...4645-asciidoctor-preserve-footnote-link-ids.yml | 5 +++ lib/banzai/filter/ascii_doc_sanitization_filter.rb | 33 +++++++++++--- spec/lib/gitlab/asciidoc_spec.rb | 50 ++++++++++++++++++++++ 3 files changed, 83 insertions(+), 5 deletions(-) create mode 100644 changelogs/unreleased/64645-asciidoctor-preserve-footnote-link-ids.yml diff --git a/changelogs/unreleased/64645-asciidoctor-preserve-footnote-link-ids.yml b/changelogs/unreleased/64645-asciidoctor-preserve-footnote-link-ids.yml new file mode 100644 index 00000000000..5427a035478 --- /dev/null +++ b/changelogs/unreleased/64645-asciidoctor-preserve-footnote-link-ids.yml @@ -0,0 +1,5 @@ +--- +title: "Preserve footnote link ids in Asciidoctor" +merge_request: 30790 +author: Guillaume Grossetie +type: added \ No newline at end of file diff --git a/lib/banzai/filter/ascii_doc_sanitization_filter.rb b/lib/banzai/filter/ascii_doc_sanitization_filter.rb index d8d63075752..9105e86ad04 100644 --- a/lib/banzai/filter/ascii_doc_sanitization_filter.rb +++ b/lib/banzai/filter/ascii_doc_sanitization_filter.rb @@ -8,12 +8,18 @@ module Banzai class AsciiDocSanitizationFilter < Banzai::Filter::BaseSanitizationFilter # Section anchor link pattern SECTION_LINK_REF_PATTERN = /\A#{Gitlab::Asciidoc::DEFAULT_ADOC_ATTRS['idprefix']}(:?[[:alnum:]]|-|_)+\z/.freeze + SECTION_HEADINGS = %w(h2 h3 h4 h5 h6).freeze + + # Footnote link patterns + FOOTNOTE_LINK_ID_PATTERNS = { + a: /\A_footnoteref_\d+\z/, + div: /\A_footnotedef_\d+\z/ + }.freeze # Classes used by Asciidoctor to style components ADMONITION_CLASSES = %w(fa icon-note icon-tip icon-warning icon-caution icon-important).freeze CALLOUT_CLASSES = ['conum'].freeze CHECKLIST_CLASSES = %w(fa fa-check-square-o fa-square-o).freeze - LIST_CLASSES = %w(checklist none no-bullet unnumbered unstyled).freeze ELEMENT_CLASSES_WHITELIST = { @@ -26,8 +32,6 @@ module Banzai a: ['anchor'].freeze }.freeze - ALLOWED_HEADERS = %w(h2 h3 h4 h5 h6).freeze - def customize_whitelist(whitelist) # Allow marks whitelist[:elements].push('mark') @@ -44,20 +48,39 @@ module Banzai whitelist[:transformers].push(self.class.remove_element_classes) # Allow `id` in heading elements for section anchors - ALLOWED_HEADERS.each do |header| + SECTION_HEADINGS.each do |header| whitelist[:attributes][header] = %w(id) end whitelist[:transformers].push(self.class.remove_non_heading_ids) + # Allow `id` in footnote elements + FOOTNOTE_LINK_ID_PATTERNS.keys.each do |element| + whitelist[:attributes][element.to_s].push('id') + end + whitelist[:transformers].push(self.class.remove_non_footnote_ids) + whitelist end class << self + def remove_non_footnote_ids + lambda do |env| + node = env[:node] + + return unless (pattern = FOOTNOTE_LINK_ID_PATTERNS[node.name.to_sym]) + return unless node.has_attribute?('id') + + return if node['id'] =~ pattern + + node.remove_attribute('id') + end + end + def remove_non_heading_ids lambda do |env| node = env[:node] - return unless ALLOWED_HEADERS.any?(node.name) + return unless SECTION_HEADINGS.any?(node.name) return unless node.has_attribute?('id') return if node['id'] =~ SECTION_LINK_REF_PATTERN diff --git a/spec/lib/gitlab/asciidoc_spec.rb b/spec/lib/gitlab/asciidoc_spec.rb index 5293732ead1..cbd4a509a55 100644 --- a/spec/lib/gitlab/asciidoc_spec.rb +++ b/spec/lib/gitlab/asciidoc_spec.rb @@ -110,6 +110,56 @@ module Gitlab expect(render(input, context)).to include(output.strip) end + + it 'removes non footnote def ids' do + input = <<~ADOC + ++++ +
Footnote definition
+ ++++ + ADOC + + output = <<~HTML +
Footnote definition
+ HTML + + expect(render(input, context)).to include(output.strip) + end + + it 'removes non footnote ref ids' do + input = <<~ADOC + ++++ + Footnote reference + ++++ + ADOC + + output = <<~HTML + Footnote reference + HTML + + expect(render(input, context)).to include(output.strip) + end + end + + context 'with footnotes' do + it 'preserves ids and links' do + input = <<~ADOC + This paragraph has a footnote.footnote:[This is the text of the footnote.] + ADOC + + output = <<~HTML +
+

This paragraph has a footnote.[1]

+
+
+
+
+ 1. This is the text of the footnote. +
+
+ HTML + + expect(render(input, context)).to include(output.strip) + end end context 'with section anchors' do -- cgit v1.2.1 From f8afb3805cf8cd12085c0e93bc6dad111afbd9c2 Mon Sep 17 00:00:00 2001 From: Rajendra kadam Date: Wed, 17 Jul 2019 06:41:26 +0000 Subject: Fetch latest link in the description for zoom link, add more tests and remove frontend spec unnecessary tests --- .../javascripts/issue_show/components/app.vue | 7 ++- .../issue_show/components/pinned_links.vue | 31 +++---------- app/helpers/issuables_helper.rb | 4 ++ changelogs/unreleased/issue-zoom-url.yml | 5 +++ lib/gitlab/zoom_link_extractor.rb | 21 +++++++++ .../issue_show/components/pinned_links_spec.js | 52 ++-------------------- spec/helpers/issuables_helper_spec.rb | 41 +++++++++++++++++ spec/lib/gitlab/zoom_link_extractor_spec.rb | 24 ++++++++++ 8 files changed, 110 insertions(+), 75 deletions(-) create mode 100644 changelogs/unreleased/issue-zoom-url.yml create mode 100644 lib/gitlab/zoom_link_extractor.rb create mode 100644 spec/lib/gitlab/zoom_link_extractor_spec.rb diff --git a/app/assets/javascripts/issue_show/components/app.vue b/app/assets/javascripts/issue_show/components/app.vue index de2a9664cde..9ca38d6bbfa 100644 --- a/app/assets/javascripts/issue_show/components/app.vue +++ b/app/assets/javascripts/issue_show/components/app.vue @@ -55,6 +55,11 @@ export default { required: false, default: true, }, + zoomMeetingUrl: { + type: String, + required: false, + default: null, + }, issuableRef: { type: String, required: true, @@ -342,7 +347,7 @@ export default { :title-text="state.titleText" :show-inline-edit-button="showInlineEditButton" /> - + a.href); - }, - // Detect links matching the following formats: - // Zoom Start links: https://zoom.us/s/ - // Zoom Join links: https://zoom.us/j/ - // Personal Zoom links: https://zoom.us/my/ - // Vanity Zoom links: https://gitlab.zoom.us/j/ (also /s and /my) - zoomHref() { - const zoomRegex = /^https:\/\/([\w\d-]+\.)?zoom\.us\/(s|j|my)\/.+/; - return this.linksInDescription.reduce((acc, currentLink) => { - let lastLink = acc; - if (zoomRegex.test(currentLink)) { - lastLink = currentLink; - } - return lastLink; - }, ''); + required: false, + default: null, }, }, };