Commit c8df22c5 authored by GitLab Bot's avatar GitLab Bot

Add latest changes from gitlab-org/gitlab@master

parent 9345f698
...@@ -35,6 +35,6 @@ export default { ...@@ -35,6 +35,6 @@ export default {
<template> <template>
<file-row :file="file" v-bind="$attrs" v-on="$listeners"> <file-row :file="file" v-bind="$attrs" v-on="$listeners">
<file-row-stats v-if="showFileRowStats" :file="file" class="mr-1" /> <file-row-stats v-if="showFileRowStats" :file="file" class="mr-1" />
<changed-file-icon :file="file" :size="16" /> <changed-file-icon :file="file" :size="16" :show-tooltip="true" />
</file-row> </file-row>
</template> </template>
<script> <script>
import { GlTooltipDirective } from '@gitlab/ui'; import { GlTooltipDirective } from '@gitlab/ui';
import Icon from '~/vue_shared/components/icon.vue'; import Icon from '~/vue_shared/components/icon.vue';
import { __ } from '~/locale';
import { getCommitIconMap } from '~/ide/utils'; import { getCommitIconMap } from '~/ide/utils';
import { __ } from '~/locale';
export default { export default {
components: { components: {
...@@ -49,9 +49,17 @@ export default { ...@@ -49,9 +49,17 @@ export default {
return `${this.changedIcon} float-left d-block`; return `${this.changedIcon} float-left d-block`;
}, },
tooltipTitle() { tooltipTitle() {
if (!this.showTooltip || !this.file.changed) return undefined; if (!this.showTooltip) {
return undefined;
} else if (this.file.deleted) {
return __('Deleted');
} else if (this.file.tempFile) {
return __('Added');
} else if (this.file.changed) {
return __('Modified');
}
return this.file.tempFile ? __('Added') : __('Modified'); return undefined;
}, },
showIcon() { showIcon() {
return ( return (
......
...@@ -236,7 +236,11 @@ module Ci ...@@ -236,7 +236,11 @@ module Ci
after_transition any => [:success, :failed] do |pipeline| after_transition any => [:success, :failed] do |pipeline|
pipeline.run_after_commit do pipeline.run_after_commit do
PipelineUpdateCiRefStatusWorker.perform_async(pipeline.id) if Feature.enabled?(:ci_pipeline_fixed_notifications)
PipelineUpdateCiRefStatusWorker.perform_async(pipeline.id)
else
PipelineNotificationWorker.perform_async(pipeline.id)
end
end end
end end
......
...@@ -17,6 +17,8 @@ class Snippet < ApplicationRecord ...@@ -17,6 +17,8 @@ class Snippet < ApplicationRecord
include HasRepository include HasRepository
extend ::Gitlab::Utils::Override extend ::Gitlab::Utils::Override
MAX_FILE_COUNT = 1
ignore_column :repository_storage, remove_with: '12.10', remove_after: '2020-03-22' ignore_column :repository_storage, remove_with: '12.10', remove_after: '2020-03-22'
cache_markdown_field :title, pipeline: :single_line cache_markdown_field :title, pipeline: :single_line
......
...@@ -23,6 +23,7 @@ ...@@ -23,6 +23,7 @@
#{ paragraph.html_safe } #{ paragraph.html_safe }
.col-lg-8 .col-lg-8
- notification_setting.email_events.each_with_index do |event, index| - notification_setting.email_events.each_with_index do |event, index|
- next if event == :fixed_pipeline && Feature.disabled?(:ci_pipeline_fixed_notifications)
- field_id = "#{notifications_menu_identifier("modal", notification_setting)}_notification_setting[#{event}]" - field_id = "#{notifications_menu_identifier("modal", notification_setting)}_notification_setting[#{event}]"
.form-group .form-group
.form-check{ class: ("prepend-top-0" if index == 0) } .form-check{ class: ("prepend-top-0" if index == 0) }
......
---
title: Add tooltip to modification icon in the file tree
merge_request: 27158
author:
type: other
---
title: Introduce a feature flag for Notifications for when pipelines are fixed
merge_request: 26682
author: Jacopo Beschi @jacopo-beschi
type: changed
...@@ -54,6 +54,8 @@ management between systems: ...@@ -54,6 +54,8 @@ management between systems:
### Improving NFS performance with GitLab ### Improving NFS performance with GitLab
#### Improving NFS performance with Unicorn
NOTE: **Note:** From GitLab 12.1, it will automatically be detected if Rugged can and should be used per storage. NOTE: **Note:** From GitLab 12.1, it will automatically be detected if Rugged can and should be used per storage.
If you previously enabled Rugged using the feature flag, you will need to unset the feature flag by using: If you previously enabled Rugged using the feature flag, you will need to unset the feature flag by using:
...@@ -64,6 +66,16 @@ sudo gitlab-rake gitlab:features:unset_rugged ...@@ -64,6 +66,16 @@ sudo gitlab-rake gitlab:features:unset_rugged
If the Rugged feature flag is explicitly set to either true or false, GitLab will use the value explicitly set. If the Rugged feature flag is explicitly set to either true or false, GitLab will use the value explicitly set.
#### Improving NFS performance with Puma
NOTE: **Note:** From GitLab 12.7, Rugged auto-detection is disabled if Puma thread count is greater than 1.
If you want to use Rugged with Puma, it is recommended to [set Puma thread count to 1](https://docs.gitlab.com/omnibus/settings/puma.html#puma-settings).
If you want to use Rugged with Puma thread count more than 1, Rugged can be enabled using the [feature flag](../../development/gitaly.md#legacy-rugged-code)
If the Rugged feature flag is explicitly set to either true or false, GitLab will use the value explicitly set.
### Known issues ### Known issues
On some customer systems, we have seen NFS clients slow precipitously due to On some customer systems, we have seen NFS clients slow precipitously due to
......
...@@ -188,6 +188,9 @@ With Visual Reviews, you can provide a feedback form to your Review Apps so ...@@ -188,6 +188,9 @@ With Visual Reviews, you can provide a feedback form to your Review Apps so
that reviewers can post comments directly from the app back to the merge request that reviewers can post comments directly from the app back to the merge request
that spawned the Review App. that spawned the Review App.
NOTE: **Note:** Visual Reviews currently only work for public projects. Support for private
and internal projects [is planned](https://gitlab.com/gitlab-org/gitlab/-/issues/42750).
### Configuring Visual Reviews ### Configuring Visual Reviews
Ensure that the `anonymous_visual_review_feedback` feature flag is enabled. Ensure that the `anonymous_visual_review_feedback` feature flag is enabled.
......
...@@ -181,11 +181,11 @@ Complementary reads: ...@@ -181,11 +181,11 @@ Complementary reads:
- [Externalization](i18n/externalization.md) - [Externalization](i18n/externalization.md)
- [Translation](i18n/translation.md) - [Translation](i18n/translation.md)
## Event tracking guides ## Telemetry guides
- [Introduction](event_tracking/index.md) - [Introduction](../telemetry/index.md)
- [Frontend tracking guide](event_tracking/frontend.md) - [Frontend tracking guide](../telemetry/frontend.md)
- [Backend tracking guide](event_tracking/backend.md) - [Backend tracking guide](../telemetry/backend.md)
## Experiment Guide ## Experiment Guide
......
...@@ -55,7 +55,7 @@ The author then adds a comment to this piece of code and adds a link to the issu ...@@ -55,7 +55,7 @@ The author then adds a comment to this piece of code and adds a link to the issu
end end
``` ```
- Track necessary events. See the [event tracking guide](../event_tracking/index.md) for details. - Track necessary events. See the [telemetry guide](../../telemetry/index.md) for details.
- After the merge request is merged, use [`chatops`](../../ci/chatops/README.md) to enable the feature flag and start the experiment. For visibility, please run the command in the `#s_growth` channel: - After the merge request is merged, use [`chatops`](../../ci/chatops/README.md) to enable the feature flag and start the experiment. For visibility, please run the command in the `#s_growth` channel:
``` ```
......
--- ---
redirect_to: '../event_tracking/index.md' redirect_to: '../../telemetry/index.md'
--- ---
This document was moved to [another location](../event_tracking/frontend.md). This document was moved to [another location](../../telemetry/index.md).
...@@ -5,7 +5,7 @@ blocks of Ruby code. Method instrumentation is the primary form of ...@@ -5,7 +5,7 @@ blocks of Ruby code. Method instrumentation is the primary form of
instrumentation with block-based instrumentation only being used when we want to instrumentation with block-based instrumentation only being used when we want to
drill down to specific regions of code within a method. drill down to specific regions of code within a method.
Please refer to [Event tracking](event_tracking/index.md) if you are tracking product usage patterns. Please refer to [Telemetry](../telemetry/index.md) if you are tracking product usage patterns.
## Instrumenting Methods ## Instrumenting Methods
......
...@@ -44,7 +44,7 @@ From the backend, the events that are tracked will likely consist of things like ...@@ -44,7 +44,7 @@ From the backend, the events that are tracked will likely consist of things like
See [Backend tracking guide](backend.md). See [Backend tracking guide](backend.md).
Also, see [Instrumenting Ruby code](../instrumentation.md) if you are instrumenting application performance metrics for Ruby code. Also, see [Instrumenting Ruby code](../development/instrumentation.md) if you are instrumenting application performance metrics for Ruby code.
## Enabling tracking ## Enabling tracking
......
...@@ -5,7 +5,7 @@ type: reference, howto ...@@ -5,7 +5,7 @@ type: reference, howto
# Epics **(PREMIUM)** # Epics **(PREMIUM)**
> - Introduced in [GitLab Ultimate](https://about.gitlab.com/pricing/) 10.2. > - Introduced in [GitLab Ultimate](https://about.gitlab.com/pricing/) 10.2.
> - In [GitLab 12.8](https://gitlab.com/gitlab-org/gitlab/issues/37081), single-level Epics were moved to Premium tier. > - In [GitLab 12.8](https://gitlab.com/gitlab-org/gitlab/issues/37081), single-level Epics were moved to the Premium tier.
Epics let you manage your portfolio of projects more efficiently and with less Epics let you manage your portfolio of projects more efficiently and with less
effort by tracking groups of issues that share a theme, across projects and effort by tracking groups of issues that share a theme, across projects and
......
...@@ -2,9 +2,10 @@ ...@@ -2,9 +2,10 @@
type: reference type: reference
--- ---
# Roadmap **(ULTIMATE)** # Roadmap **(PREMIUM)**
> Introduced in [GitLab Ultimate](https://about.gitlab.com/pricing/) 10.5. > - Introduced in [GitLab Ultimate](https://about.gitlab.com/pricing/) 10.5.
> - In [GitLab 12.9](https://gitlab.com/gitlab-org/gitlab/issues/198062), Roadmaps were moved to the Premium tier.
An Epic within a group containing **Start date** and/or **Due date** An Epic within a group containing **Start date** and/or **Due date**
can be visualized in a form of a timeline (e.g. a Gantt chart). The Epics Roadmap page can be visualized in a form of a timeline (e.g. a Gantt chart). The Epics Roadmap page
...@@ -35,7 +36,8 @@ Roadmaps can also be [visualized inside an epic](../epics/index.md#roadmap-in-ep ...@@ -35,7 +36,8 @@ Roadmaps can also be [visualized inside an epic](../epics/index.md#roadmap-in-ep
## Timeline duration ## Timeline duration
> Introduced in [GitLab Ultimate](https://about.gitlab.com/pricing/) 11.0. > - Introduced in [GitLab Ultimate](https://about.gitlab.com/pricing/) 11.0.
> - In [GitLab 12.9](https://gitlab.com/gitlab-org/gitlab/issues/198062), Timelines were moved to the Premium tier.
Roadmap supports the following date ranges: Roadmap supports the following date ranges:
......
...@@ -181,7 +181,7 @@ To minimize the number of notifications that do not require any action, from [Gi ...@@ -181,7 +181,7 @@ To minimize the number of notifications that do not require any action, from [Gi
| Remove milestone merge request | Subscribers, participants mentioned, and Custom notification level with this event selected | | Remove milestone merge request | Subscribers, participants mentioned, and Custom notification level with this event selected |
| New comment | The above, plus anyone mentioned by `@username` in the comment, with notification level "Mention" or higher | | New comment | The above, plus anyone mentioned by `@username` in the comment, with notification level "Mention" or higher |
| Failed pipeline | The author of the pipeline | | Failed pipeline | The author of the pipeline |
| Fixed pipeline | The author of the pipeline | | Fixed pipeline | The author of the pipeline. Disabled by default. To activate it you must [enable the `ci_pipeline_fixed_notifications` feature flag](../../development/feature_flags/development.md#enabling-a-feature-flag-in-development). |
| Successful pipeline | The author of the pipeline, if they have the custom notification setting for successful pipelines set. If the pipeline failed previously, a `Fixed pipeline` message will be sent for the first successful pipeline after the failure, then a `Successful pipeline` message for any further successful pipelines. | | Successful pipeline | The author of the pipeline, if they have the custom notification setting for successful pipelines set. If the pipeline failed previously, a `Fixed pipeline` message will be sent for the first successful pipeline after the failure, then a `Successful pipeline` message for any further successful pipelines. |
| New epic **(ULTIMATE)** | | | New epic **(ULTIMATE)** | |
| Close epic **(ULTIMATE)** | | | Close epic **(ULTIMATE)** | |
......
# frozen_string_literal: true
module Gitlab
module Checks
class PushFileCountCheck < BaseChecker
attr_reader :repository, :newrev, :limit, :logger
LOG_MESSAGES = {
diff_content_check: "Validating diff contents being single file..."
}.freeze
ERROR_MESSAGES = {
upper_limit: "The repository can contain at most %{limit} file(s).",
lower_limit: "The repository must contain at least 1 file."
}.freeze
def initialize(change, repository:, limit:, logger:)
@repository = repository
@newrev = change[:newrev]
@limit = limit
@logger = logger
end
def validate!
file_count = repository.ls_files(newrev).size
if file_count > limit
raise ::Gitlab::GitAccess::ForbiddenError, ERROR_MESSAGES[:upper_limit] % { limit: limit }
end
if file_count == 0
raise ::Gitlab::GitAccess::ForbiddenError, ERROR_MESSAGES[:lower_limit]
end
end
end
end
end
...@@ -20,14 +20,11 @@ module Gitlab ...@@ -20,14 +20,11 @@ module Gitlab
@logger.append_message("Running checks for ref: #{@branch_name || @tag_name}") @logger.append_message("Running checks for ref: #{@branch_name || @tag_name}")
end end
def exec def validate!
if creation? || deletion? if creation? || deletion?
raise GitAccess::ForbiddenError, ERROR_MESSAGES[:create_delete_branch] raise GitAccess::ForbiddenError, ERROR_MESSAGES[:create_delete_branch]
end end
# TODO: https://gitlab.com/gitlab-org/gitlab/issues/205628
# Check operation will not result in more than one file in the repository
true true
end end
......
...@@ -97,9 +97,8 @@ module Gitlab ...@@ -97,9 +97,8 @@ module Gitlab
end end
def check_single_change_access(change) def check_single_change_access(change)
change_access = Checks::SnippetCheck.new(change, logger: logger) Checks::SnippetCheck.new(change, logger: logger).validate!
Checks::PushFileCountCheck.new(change, repository: repository, limit: Snippet::MAX_FILE_COUNT, logger: logger).validate!
change_access.exec
rescue Checks::TimedLogger::TimeoutError rescue Checks::TimedLogger::TimeoutError
raise TimeoutError, logger.full_message raise TimeoutError, logger.full_message
end end
......
...@@ -44,11 +44,21 @@ module QA ...@@ -44,11 +44,21 @@ module QA
new.visit(address, page_class, &block) new.visit(address, page_class, &block)
end end
# rubocop: disable Metrics/AbcSize
def self.configure! def self.configure!
RSpec.configure do |config| RSpec.configure do |config|
config.define_derived_metadata(file_path: %r{/qa/specs/features/}) do |metadata| config.define_derived_metadata(file_path: %r{/qa/specs/features/}) do |metadata|
metadata[:type] = :feature metadata[:type] = :feature
end end
config.around(:each) do |example|
example.run
if example.metadata[:screenshot]
screenshot = example.metadata[:screenshot][:image] || example.metadata[:screenshot][:html]
example.metadata[:stdout] = %{[[ATTACHMENT|#{screenshot}]]}
end
end
end end
Capybara.server_port = 9887 + ENV['TEST_ENV_NUMBER'].to_i Capybara.server_port = 9887 + ENV['TEST_ENV_NUMBER'].to_i
...@@ -140,6 +150,7 @@ module QA ...@@ -140,6 +150,7 @@ module QA
config.default_normalize_ws = true config.default_normalize_ws = true
end end
end end
# rubocop: enable Metrics/AbcSize
class Session class Session
include Capybara::DSL include Capybara::DSL
......
...@@ -7,7 +7,6 @@ describe 'Projects > Show > User manages notifications', :js do ...@@ -7,7 +7,6 @@ describe 'Projects > Show > User manages notifications', :js do
before do before do
sign_in(project.owner) sign_in(project.owner)
visit project_path(project)
end end
def click_notifications_button def click_notifications_button
...@@ -15,6 +14,7 @@ describe 'Projects > Show > User manages notifications', :js do ...@@ -15,6 +14,7 @@ describe 'Projects > Show > User manages notifications', :js do
end end
it 'changes the notification setting' do it 'changes the notification setting' do
visit project_path(project)
click_notifications_button click_notifications_button
click_link 'On mention' click_link 'On mention'
...@@ -26,6 +26,7 @@ describe 'Projects > Show > User manages notifications', :js do ...@@ -26,6 +26,7 @@ describe 'Projects > Show > User manages notifications', :js do
end end
it 'changes the notification setting to disabled' do it 'changes the notification setting to disabled' do
visit project_path(project)
click_notifications_button click_notifications_button
click_link 'Disabled' click_link 'Disabled'
...@@ -50,11 +51,13 @@ describe 'Projects > Show > User manages notifications', :js do ...@@ -50,11 +51,13 @@ describe 'Projects > Show > User manages notifications', :js do
:reassign_merge_request, :reassign_merge_request,
:merge_merge_request, :merge_merge_request,
:failed_pipeline, :failed_pipeline,
:fixed_pipeline,
:success_pipeline :success_pipeline
] ]
end end
it 'shows notification settings checkbox' do it 'shows notification settings checkbox' do
visit project_path(project)
click_notifications_button click_notifications_button
page.find('a[data-notification-level="custom"]').click page.find('a[data-notification-level="custom"]').click
...@@ -64,12 +67,27 @@ describe 'Projects > Show > User manages notifications', :js do ...@@ -64,12 +67,27 @@ describe 'Projects > Show > User manages notifications', :js do
end end
end end
end end
context 'when ci_pipeline_fixed_notifications is disabled' do
before do
stub_feature_flags(ci_pipeline_fixed_notifications: false)
end
it 'hides fixed_pipeline checkbox' do
visit project_path(project)
click_notifications_button
page.find('a[data-notification-level="custom"]').click
expect(page).not_to have_selector("input[name='notification_setting[fixed_pipeline]']")
end
end
end end
context 'when project emails are disabled' do context 'when project emails are disabled' do
let(:project) { create(:project, :public, :repository, emails_disabled: true) } let(:project) { create(:project, :public, :repository, emails_disabled: true) }
it 'is disabled' do it 'is disabled' do
visit project_path(project)
expect(page).to have_selector('.notifications-btn.disabled', visible: true) expect(page).to have_selector('.notifications-btn.disabled', visible: true)
end end
end end
......
...@@ -44,12 +44,14 @@ describe('Diff File Row component', () => { ...@@ -44,12 +44,14 @@ describe('Diff File Row component', () => {
level: 4, level: 4,
file: {}, file: {},
hideFileStats: false, hideFileStats: false,
showTooltip: true,
}); });
expect(wrapper.find(ChangedFileIcon).props()).toEqual( expect(wrapper.find(ChangedFileIcon).props()).toEqual(
expect.objectContaining({ expect.objectContaining({
file: {}, file: {},
size: 16, size: 16,
showTooltip: true,
}), }),
); );
}); });
......
...@@ -5,6 +5,7 @@ import Icon from '~/vue_shared/components/icon.vue'; ...@@ -5,6 +5,7 @@ import Icon from '~/vue_shared/components/icon.vue';
const changedFile = () => ({ changed: true }); const changedFile = () => ({ changed: true });
const stagedFile = () => ({ changed: true, staged: true }); const stagedFile = () => ({ changed: true, staged: true });
const newFile = () => ({ changed: true, tempFile: true }); const newFile = () => ({ changed: true, tempFile: true });
const deletedFile = () => ({ changed: false, tempFile: false, staged: false, deleted: true });
const unchangedFile = () => ({ changed: false, tempFile: false, staged: false, deleted: false }); const unchangedFile = () => ({ changed: false, tempFile: false, staged: false, deleted: false });
describe('Changed file icon', () => { describe('Changed file icon', () => {
...@@ -58,6 +59,7 @@ describe('Changed file icon', () => { ...@@ -58,6 +59,7 @@ describe('Changed file icon', () => {
${changedFile()} | ${'file-modified'} | ${'Modified'} | ${'with file changed'} ${changedFile()} | ${'file-modified'} | ${'Modified'} | ${'with file changed'}
${stagedFile()} | ${'file-modified-solid'} | ${'Modified'} | ${'with file staged'} ${stagedFile()} | ${'file-modified-solid'} | ${'Modified'} | ${'with file staged'}
${newFile()} | ${'file-addition'} | ${'Added'} | ${'with file new'} ${newFile()} | ${'file-addition'} | ${'Added'} | ${'with file new'}
${deletedFile()} | ${'file-deletion'} | ${'Deleted'} | ${'with file deleted'}
`('$desc', ({ file, iconName, tooltipText }) => { `('$desc', ({ file, iconName, tooltipText }) => {
beforeEach(() => { beforeEach(() => {
factory({ file }); factory({ file });
......
# frozen_string_literal: true
require 'spec_helper'
describe Gitlab::Checks::PushFileCountCheck do
let(:snippet) { create(:personal_snippet, :repository) }
let(:changes) { { oldrev: oldrev, newrev: newrev, ref: ref } }
let(:timeout) { Gitlab::GitAccess::INTERNAL_TIMEOUT }
let(:logger) { Gitlab::Checks::TimedLogger.new(timeout: timeout) }
subject { described_class.new(changes, repository: snippet.repository, limit: 1, logger: logger) }
describe '#validate!' do
using RSpec::Parameterized::TableSyntax
before do
allow(snippet.repository).to receive(:new_commits).and_return(
snippet.repository.commits_between(oldrev, newrev)
)
end
context 'initial creation' do
let(:oldrev) { Gitlab::Git::EMPTY_TREE_ID }
let(:newrev) { TestEnv::BRANCH_SHA["snippet/single-file"] }
let(:ref) { "refs/heads/snippet/single-file" }
it 'allows creation' do
expect { subject.validate! }.not_to raise_error
end
end
where(:old, :new, :valid, :message) do
'single-file' | 'edit-file' | true | nil
'single-file' | 'multiple-files' | false | 'The repository can contain at most 1 file(s).'
'single-file' | 'no-files' | false | 'The repository must contain at least 1 file.'
'edit-file' | 'rename-and-edit-file' | true | nil
end
with_them do
let(:oldrev) { TestEnv::BRANCH_SHA["snippet/#{old}"] }
let(:newrev) { TestEnv::BRANCH_SHA["snippet/#{new}"] }
let(:ref) { "refs/heads/snippet/#{new}" }
it "verifies" do
if valid
expect { subject.validate! }.not_to raise_error
else
expect { subject.validate! }.to raise_error(Gitlab::GitAccess::ForbiddenError, message)
end
end
end
end
end
...@@ -10,16 +10,16 @@ describe Gitlab::Checks::SnippetCheck do ...@@ -10,16 +10,16 @@ describe Gitlab::Checks::SnippetCheck do
subject { Gitlab::Checks::SnippetCheck.new(changes, logger: logger) } subject { Gitlab::Checks::SnippetCheck.new(changes, logger: logger) }
describe '#exec' do describe '#validate!' do
it 'does not raise any error' do it 'does not raise any error' do
expect { subject.exec }.not_to raise_error expect { subject.validate! }.not_to raise_error
end end
context 'trying to delete the branch' do context 'trying to delete the branch' do
let(:newrev) { '0000000000000000000000000000000000000000' } let(:newrev) { '0000000000000000000000000000000000000000' }
it 'raises an error' do it 'raises an error' do
expect { subject.exec }.to raise_error(Gitlab::GitAccess::ForbiddenError, 'You can not create or delete branches.') expect { subject.validate! }.to raise_error(Gitlab::GitAccess::ForbiddenError, 'You can not create or delete branches.')
end end
end end
...@@ -28,14 +28,14 @@ describe Gitlab::Checks::SnippetCheck do ...@@ -28,14 +28,14 @@ describe Gitlab::Checks::SnippetCheck do
let(:ref) { 'refs/heads/feature' } let(:ref) { 'refs/heads/feature' }
it 'raises an error' do it 'raises an error' do
expect { subject.exec }.to raise_error(Gitlab::GitAccess::ForbiddenError, 'You can not create or delete branches.') expect { subject.validate! }.to raise_error(Gitlab::GitAccess::ForbiddenError, 'You can not create or delete branches.')
end end
context "when branch is 'master'" do context "when branch is 'master'" do
let(:ref) { 'refs/heads/master' } let(:ref) { 'refs/heads/master' }
it "allows the operation" do it "allows the operation" do
expect { subject.exec }.not_to raise_error expect { subject.validate! }.not_to raise_error
end end
end end
end end
......
...@@ -188,12 +188,15 @@ describe Gitlab::GitAccessSnippet do ...@@ -188,12 +188,15 @@ describe Gitlab::GitAccessSnippet do
end end
context 'when changes are specific' do context 'when changes are specific' do
let(:changes) { 'oldrev newrev ref' } let(:changes) { "2d1db523e11e777e49377cfb22d368deec3f0793 ddd0f15ae83993f5cb66a927a28673882e99100b master" }
let(:user) { snippet.author } let(:user) { snippet.author }
it 'does not raise error if SnippetCheck does not raise error' do it 'does not raise error if SnippetCheck does not raise error' do
expect_next_instance_of(Gitlab::Checks::SnippetCheck) do |check| expect_next_instance_of(Gitlab::Checks::SnippetCheck) do |check|
expect(check).to receive(:exec).and_call_original expect(check).to receive(:validate!).and_call_original
end
expect_next_instance_of(Gitlab::Checks::PushFileCountCheck) do |check|
expect(check).to receive(:validate!)
end end
expect { push_access_check }.not_to raise_error expect { push_access_check }.not_to raise_error
...@@ -201,7 +204,7 @@ describe Gitlab::GitAccessSnippet do ...@@ -201,7 +204,7 @@ describe Gitlab::GitAccessSnippet do
it 'raises error if SnippetCheck raises error' do it 'raises error if SnippetCheck raises error' do
expect_next_instance_of(Gitlab::Checks::SnippetCheck) do |check| expect_next_instance_of(Gitlab::Checks::SnippetCheck) do |check|
allow(check).to receive(:exec).and_raise(Gitlab::GitAccess::ForbiddenError, 'foo') allow(check).to receive(:validate!).and_raise(Gitlab::GitAccess::ForbiddenError, 'foo')
end end
expect { push_access_check }.to raise_forbidden('foo') expect { push_access_check }.to raise_forbidden('foo')
......
...@@ -2509,27 +2509,53 @@ describe Ci::Pipeline, :mailer do ...@@ -2509,27 +2509,53 @@ describe Ci::Pipeline, :mailer do
end end
end end
context 'with success pipeline' do shared_examples 'enqueues the notification worker' do
before do it 'enqueues PipelineUpdateCiRefStatusWorker' do
perform_enqueued_jobs do expect(PipelineUpdateCiRefStatusWorker).to receive(:perform_async).with(pipeline.id)
expect(PipelineNotificationWorker).not_to receive(:perform_async).with(pipeline.id)
pipeline.succeed
end
context 'when ci_pipeline_fixed_notifications is disabled' do
before do
stub_feature_flags(ci_pipeline_fixed_notifications: false)
end
it 'enqueues PipelineNotificationWorker' do
expect(PipelineUpdateCiRefStatusWorker).not_to receive(:perform_async).with(pipeline.id)
expect(PipelineNotificationWorker).to receive(:perform_async).with(pipeline.id)
pipeline.succeed pipeline.succeed
end end
end end
end
it_behaves_like 'sending a notification' context 'with success pipeline' do
it_behaves_like 'sending a notification' do
before do
perform_enqueued_jobs do
pipeline.succeed
end
end
end
it_behaves_like 'enqueues the notification worker'
end end
context 'with failed pipeline' do context 'with failed pipeline' do
before do it_behaves_like 'sending a notification' do
perform_enqueued_jobs do before do
create(:ci_build, :failed, pipeline: pipeline) perform_enqueued_jobs do
create(:generic_commit_status, :failed, pipeline: pipeline) create(:ci_build, :failed, pipeline: pipeline)
create(:generic_commit_status, :failed, pipeline: pipeline)
pipeline.drop pipeline.drop
end
end end
end end
it_behaves_like 'sending a notification' it_behaves_like 'enqueues the notification worker'
end end
context 'with skipped pipeline' do context 'with skipped pipeline' do
......
...@@ -12,6 +12,7 @@ describe API::Internal::Base do ...@@ -12,6 +12,7 @@ describe API::Internal::Base do
let_it_be(:personal_snippet) { create(:personal_snippet, :repository, author: user) } let_it_be(:personal_snippet) { create(:personal_snippet, :repository, author: user) }
let_it_be(:project_snippet) { create(:project_snippet, :repository, author: user, project: project) } let_it_be(:project_snippet) { create(:project_snippet, :repository, author: user, project: project) }
let(:snippet_changes) { "#{TestEnv::BRANCH_SHA['snippet/single-file']} #{TestEnv::BRANCH_SHA['snippet/edit-file']} refs/heads/snippet/edit-file" }
describe "GET /internal/check" do describe "GET /internal/check" do
it do it do
...@@ -336,7 +337,7 @@ describe API::Internal::Base do ...@@ -336,7 +337,7 @@ describe API::Internal::Base do
end end
context 'git push with personal snippet' do context 'git push with personal snippet' do
subject { push(key, personal_snippet, env: env.to_json) } subject { push(key, personal_snippet, env: env.to_json, changes: snippet_changes) }
it 'responds with success' do it 'responds with success' do
subject subject
...@@ -371,7 +372,7 @@ describe API::Internal::Base do ...@@ -371,7 +372,7 @@ describe API::Internal::Base do
end end
context 'git push with project snippet' do context 'git push with project snippet' do
subject { push(key, project_snippet, env: env.to_json) } subject { push(key, project_snippet, env: env.to_json, changes: snippet_changes) }
it 'responds with success' do it 'responds with success' do
subject subject
...@@ -1104,9 +1105,11 @@ describe API::Internal::Base do ...@@ -1104,9 +1105,11 @@ describe API::Internal::Base do
) )
end end
def push(key, container, protocol = 'ssh', env: nil) def push(key, container, protocol = 'ssh', env: nil, changes: nil)
changes ||= 'd14d6c0abdd253381df51a723d58691b2ee1ab08 570e7b2abdd848b95f2f578043fc23bd6f6fd24d refs/heads/master'
params = { params = {
changes: 'd14d6c0abdd253381df51a723d58691b2ee1ab08 570e7b2abdd848b95f2f578043fc23bd6f6fd24d refs/heads/master', changes: changes,
key_id: key.id, key_id: key.id,
project: full_path_for(container), project: full_path_for(container),
gl_repository: gl_repository_for(container), gl_repository: gl_repository_for(container),
......
...@@ -126,6 +126,12 @@ RSpec.configure do |config| ...@@ -126,6 +126,12 @@ RSpec.configure do |config|
Capybara.raise_server_errors = false Capybara.raise_server_errors = false
example.run example.run
if example.metadata[:screenshot]
screenshot = example.metadata[:screenshot][:image] || example.metadata[:screenshot][:html]
example.metadata[:stdout] = %{[[ATTACHMENT|#{screenshot}]]}
end
ensure ensure
Capybara.raise_server_errors = true Capybara.raise_server_errors = true
end end
......
...@@ -61,6 +61,11 @@ module TestEnv ...@@ -61,6 +61,11 @@ module TestEnv
'merge-commit-analyze-before' => '1adbdef', 'merge-commit-analyze-before' => '1adbdef',
'merge-commit-analyze-side-branch' => '8a99451', 'merge-commit-analyze-side-branch' => '8a99451',
'merge-commit-analyze-after' => '646ece5', 'merge-commit-analyze-after' => '646ece5',
'snippet/single-file' => '43e4080',
'snippet/multiple-files' => 'b80faa8',
'snippet/rename-and-edit-file' => '220a1e4',
'snippet/edit-file' => 'c2f074f',
'snippet/no-files' => '671aaa8',
'2-mb-file' => 'bf12d25', '2-mb-file' => 'bf12d25',
'before-create-delete-modify-move' => '845009f', 'before-create-delete-modify-move' => '845009f',
'between-create-delete-modify-move' => '3f5f443', 'between-create-delete-modify-move' => '3f5f443',
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment