Commit b9aa76fe authored by GitLab Bot's avatar GitLab Bot

Merge remote-tracking branch 'upstream/master' into ce-to-ee-2018-10-11

# Conflicts:
#	.rubocop.yml
#	doc/ci/triggers/README.md

[ci skip]
parents 1288b6e0 e5ae0be4
......@@ -50,7 +50,8 @@ Style/FrozenStringLiteralComment:
- 'danger/**/*'
- 'db/**/*'
- 'ee/**/*'
- 'lib/**/*'
- 'lib/gitlab/**/*'
- 'lib/tasks/**/*'
- 'qa/**/*'
- 'rubocop/**/*'
- 'scripts/**/*'
......@@ -85,7 +86,10 @@ Naming/FileName:
- JSON
- LDAP
- SAML
<<<<<<< HEAD
- SSO
=======
>>>>>>> upstream/master
- IO
- HMAC
- QA
......
......@@ -22,7 +22,7 @@
SharedRunner,
},
props: {
runnerHelpUrl: {
runnerSettingsUrl: {
type: String,
required: false,
default: null,
......@@ -81,7 +81,7 @@
class="js-job-stuck"
:has-no-runners-for-project="job.runners.available"
:tags="job.tags"
:runners-path="runnerHelpUrl"
:runners-path="runnerSettingsUrl"
/>
<shared-runner
......
......@@ -33,7 +33,7 @@ export default () => {
props: {
isLoading: this.isLoading,
job: this.job,
runnerHelpUrl: dataset.runnerHelpUrl,
runnerSettingsUrl: dataset.runnerSettingsUrl,
},
});
},
......
......@@ -139,7 +139,7 @@ export const fetchStages = ({ state, dispatch }) => {
dispatch('requestStages');
axios
.get(state.job.pipeline.path)
.get(`${state.job.pipeline.path}.json`)
.then(({ data }) => {
dispatch('receiveStagesSuccess', data.details.stages);
dispatch('fetchJobsForStage', data.details.stages[0]);
......
......@@ -7,8 +7,9 @@ class BranchesFinder
end
def execute
branches = @repository.branches_sorted_by(sort)
filter_by_name(branches)
branches = repository.branches_sorted_by(sort)
branches = by_search(branches)
branches
end
private
......@@ -23,11 +24,39 @@ class BranchesFinder
@params[:sort].presence || 'name'
end
def filter_by_name(branches)
if search
branches.select { |branch| branch.name.upcase.include?(search.upcase) }
def by_search(branches)
return branches unless search
case search
when ->(v) { v.starts_with?('^') }
filter_branches_with_prefix(branches, search.slice(1..-1).upcase)
when ->(v) { v.ends_with?('$') }
filter_branches_with_suffix(branches, search.chop.upcase)
else
branches
matches = filter_branches_by_name(branches, search.upcase)
set_exact_match_as_first_result(matches, search)
end
end
def filter_branches_with_prefix(branches, prefix)
branches.select { |branch| branch.name.upcase.starts_with?(prefix) }
end
def filter_branches_with_suffix(branches, suffix)
branches.select { |branch| branch.name.upcase.ends_with?(suffix) }
end
def filter_branches_by_name(branches, term)
branches.select { |branch| branch.name.upcase.include?(term) }
end
def set_exact_match_as_first_result(matches, term)
exact_match_index = find_exact_match_index(matches, term)
matches.insert(0, matches.delete_at(exact_match_index)) if exact_match_index
matches
end
def find_exact_match_index(matches, term)
matches.index { |branch| branch.name.casecmp(term) == 0 }
end
end
......@@ -50,15 +50,21 @@ module SortingHelper
def groups_sort_options_hash
{
sort_value_name => sort_title_name,
sort_value_name_desc => sort_title_name_desc,
sort_value_name => sort_title_name,
sort_value_name_desc => sort_title_name_desc,
sort_value_recently_created => sort_title_recently_created,
sort_value_oldest_created => sort_title_oldest_created,
sort_value_oldest_created => sort_title_oldest_created,
sort_value_recently_updated => sort_title_recently_updated,
sort_value_oldest_updated => sort_title_oldest_updated
sort_value_oldest_updated => sort_title_oldest_updated
}
end
def subgroups_sort_options_hash
groups_sort_options_hash.merge(
sort_value_most_stars => sort_title_most_stars
)
end
def admin_groups_sort_options_hash
groups_sort_options_hash.merge(
sort_value_largest_group => sort_title_largest_group
......
......@@ -1805,7 +1805,7 @@ class Project < ActiveRecord::Base
return unless export_file_exists?
import_export_upload.remove_export_file!
import_export_upload.save
import_export_upload.save unless import_export_upload.destroyed?
end
def export_file_exists?
......
......@@ -22,7 +22,7 @@
.input-group
%input.label.label-monospace{ id: "secret", type: "text", autocomplete: 'off', value: @application.secret, readonly: true }
.input-group-append
= clipboard_button(target: '#application_id', title: _("Copy secret to clipboard"), class: "btn btn btn-default")
= clipboard_button(target: '#secret', title: _("Copy secret to clipboard"), class: "btn btn btn-default")
%tr
%td
= _('Callback URL')
......
......@@ -25,7 +25,7 @@
.input-group
%input.label.label-monospace{ id: "secret", type: "text", autocomplete: 'off', value: @application.secret, readonly: true }
.input-group-append
= clipboard_button(target: '#application_id', title: _("Copy secret to clipboard"), class: "btn btn btn-default")
= clipboard_button(target: '#secret', title: _("Copy secret to clipboard"), class: "btn btn btn-default")
%tr
%td
= _('Callback URL')
......
......@@ -53,7 +53,7 @@
= _("Archived projects")
.nav-controls
= render "shared/groups/dropdown"
= render "shared/groups/dropdown", options_hash: subgroups_sort_options_hash
.tab-content
#subgroups_and_projects.tab-pane
......
......@@ -47,4 +47,6 @@
.js-build-options{ data: javascript_build_options }
#js-job-details-vue{ data: { endpoint: project_job_path(@project, @build, format: :json), runner_help_url: help_page_path('ci/runners/README.html', anchor: 'setting-maximum-job-timeout-for-a-runner') } }
#js-job-details-vue{ data: { endpoint: project_job_path(@project, @build, format: :json),
runner_help_url: help_page_path('ci/runners/README.html', anchor: 'setting-maximum-job-timeout-for-a-runner'),
runner_settings_url: project_runners_path(@build.project, anchor: 'js-runners-settings') } }
---
title: Add new sort option "most_stars" to "Group > Children" pages
merge_request: 22121
author: Rene Hennig
---
title: Fix caching issue with pipelines URL
merge_request: 22293
author:
type: fixed
---
title: Fixes stuck block URL linking to documentation instead of settings page
merge_request: 22286
author:
type: fixed
---
title: Enable even more frozen string in lib/**/*.rb
merge_request:
author: gfyoung
type: performance
---
title: Improving branch filter sorting by listing exact matches first and added support
for begins_with (^) and ends_with ($) matching.
merge_request: 22166
author: Jason Rutherford
type: changed
---
title: Update copy to clipboard button data for application secret
merge_request: 22268
author: George Tsiolis
type: fixed
---
title: Fix project deletion when there is a export available
merge_request: 22276
author:
type: fixed
......@@ -25,15 +25,13 @@ gitaly['prometheus_listen_addr'] = 'localhost:9236'
```
To change a Gitaly setting in installations from source you can edit
`/home/git/gitaly/config.toml`.
`/home/git/gitaly/config.toml`. Changes will be applied when you run
`service gitlab restart`.
```toml
prometheus_listen_addr = "localhost:9236"
```
Changes to `/home/git/gitaly/config.toml` are applied when you run `service
gitlab restart`.
## Client-side GRPC logs
Gitaly uses the [gRPC](https://grpc.io/) RPC framework. The Ruby gRPC
......
......@@ -2,7 +2,7 @@
> **Notes**:
>
> - [Introduced][ci-229] in GitLab CE 7.14.
> - Introduced in GitLab 7.14.
> - GitLab 8.12 has a completely redesigned job permissions system. Read all
> about the [new model and its implications](../../user/project/new_ci_build_permissions_model.md#job-triggers).
......@@ -210,10 +210,10 @@ This information is also exposed in the UI.
Using trigger variables can be proven useful for a variety of reasons:
* Identifiable jobs. Since the variable is exposed in the UI you can know
- Identifiable jobs. Since the variable is exposed in the UI you can know
why the rebuild was triggered if you pass a variable that explains the
purpose.
* Conditional job processing. You can have conditional jobs that run whenever
- Conditional job processing. You can have conditional jobs that run whenever
a certain variable is present.
Consider the following `.gitlab-ci.yml` where we set three
......@@ -277,8 +277,11 @@ removed with one of the future versions of GitLab. You are advised to
[take ownership](#taking-ownership) of any legacy triggers.
[ee-2017]: https://gitlab.com/gitlab-org/gitlab-ee/merge_requests/2017
<<<<<<< HEAD
[ee-2346]: https://gitlab.com/gitlab-org/gitlab-ee/merge_requests/2346
[ci-229]: https://gitlab.com/gitlab-org/gitlab-ci/merge_requests/229
=======
>>>>>>> upstream/master
[ee]: https://about.gitlab.com/pricing/
[variables]: ../variables/README.md
[predef]: ../variables/README.md#predefined-variables-environment-variables
......
......@@ -415,7 +415,7 @@ Four keys are now available: `refs`, `kubernetes` and `variables` and `changes`.
Refs strategy equals to simplified only/except configuration, whereas
kubernetes strategy accepts only `active` keyword.
### `variables`
### `only:variables`
`variables` keyword is used to define variables expressions. In other words
you can use predefined variables / project / group or
......@@ -460,7 +460,7 @@ end-to-end:
Learn more about variables expressions on [a separate page][variables-expressions].
### `changes`
### `only:changes`
Using `changes` keyword with `only` or `except` makes it possible to define if
a job should be created based on files modified by a git push event.
......
......@@ -69,6 +69,37 @@ For more information about rolling out changes using feature flags, refer to the
[Rolling out changes using feature flags](rolling_out_changes_using_feature_flags.md)
guide.
### Frontend
For frontend code you can use the method `push_frontend_feature_flag`, which is
available to all controllers that inherit from `ApplicationController`. Using
this method you can expose the state of a feature flag as follows:
```ruby
before_action do
push_frontend_feature_flag(:vim_bindings)
end
def index
# ...
end
def edit
# ...
end
```
You can then check for the state of the feature flag in JavaScript as follows:
```javascript
if ( gon.features.vimBindings ) {
// ...
}
```
The name of the feature flag in JavaScript will always be camelCased, meaning
that checking for `gon.features.vim_bindings` would not work.
### Specs
In the test environment `Feature.enabled?` is stubbed to always respond to `true`,
......
......@@ -12,9 +12,11 @@ to cherry-pick the changes introduced by that merge request.
![Cherry-pick Merge Request](img/cherry_pick_changes_mr.png)
After you click that button, a modal will appear where you can choose to
cherry-pick the changes directly into the selected branch or you can opt to
create a new merge request with the cherry-pick changes
After you click that button, a modal will appear showing a [branch filter search box](../repository/branches/index.md#branch-filter-search-box)
where you can choose to either:
- Cherry-pick the changes directly into the selected branch.
- Create a new merge request with the cherry-picked changes.
## Cherry-picking a Commit
......
......@@ -6,6 +6,7 @@ Read through GiLab's branching documentation:
- [Default branch](#default-branch)
- [Protected branches](../../protected_branches.md#protected-branches)
- [Delete merged branches](#delete-merged-branches)
- [Branch filter search box](#branch-filter-search-box)
See also:
......@@ -40,5 +41,22 @@ this operation.
It's particularly useful to clean up old branches that were not deleted
automatically when a merge request was merged.
## Branch filter search box
> [Introduced][https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/22166] in GitLab 11.5.
![Branch filter search box](img/branch_filter_search_box.png)
This feature allows you to search and select branches quickly. Search results appear in the following order:
- Branches with names that matched search terms exactly.
- Other branches with names that include search terms, sorted alphabetically.
Sometimes when you have hundreds of branches you may want a more flexible matching pattern. In such cases you can use the following:
- `^feature` will only match branch names that begin with 'feature'.
- `feature$` will only match branch names that end with 'feature'.
[ce-6449]: https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/6449 "Add button to delete all merged branches"
[protected]: ../../protected_branches.md
......@@ -85,12 +85,13 @@ You can live preview changes submitted to a new branch with
With [GitLab Starter](https://about.gitlab.com/pricing/), you can also request
[approval](https://docs.gitlab.com/ee/user/project/merge_requests/merge_request_approvals.html) from your managers.
To create, delete, and [branches](branches/index.md) via GitLab's UI:
To create, delete, and view [branches](branches/index.md) via GitLab's UI:
- [Default branches](branches/index.md#default-branch)
- [Create a branch](web_editor.md#create-a-new-branch)
- [Protected branches](../protected_branches.md#protected-branches)
- [Delete merged branches](branches/index.md#delete-merged-branches)
- [Branch filter search box](branches/index.md#branch-filter-search-box)
Alternatively, you can use the
[command line](../../../gitlab-basics/start-using-git.md#create-a-branch).
......@@ -169,7 +170,7 @@ vendored code, and most markup languages are excluded.
## Compare
Select branches to compare and view the changes inline:
Select branches to compare using the [branch filter search box](branches/index.md#branch-filter-search-box), then click the **Compare** button to view the changes inline:
![compare branches](img/compare_branches.png)
......
# frozen_string_literal: true
require 'rails/generators'
module Rails
......
# frozen_string_literal: true
module Gitaly
class Server
def self.all
......
......@@ -30,5 +30,20 @@ module Gitlab
gon.current_user_avatar_url = current_user.avatar_url
end
end
# Exposes the state of a feature flag to the frontend code.
#
# name - The name of the feature flag, e.g. `my_feature`.
# args - Any additional arguments to pass to `Feature.enabled?`. This allows
# you to check if a flag is enabled for a particular user.
def push_frontend_feature_flag(name, *args)
var_name = name.to_s.camelize(:lower)
enabled = Feature.enabled?(name, *args)
# Here the `true` argument signals gon that the value should be merged
# into any existing ones, instead of overwriting them. This allows you to
# use this method to push multiple feature flags.
gon.push({ features: { var_name => enabled } }, true)
end
end
end
# frozen_string_literal: true
module GoogleApi
class Auth
attr_reader :access_token, :redirect_uri, :state
......
# frozen_string_literal: true
require 'google/apis/compute_v1'
require 'google/apis/container_v1'
require 'google/apis/cloudbilling_v1'
......
unless Rails.env.production? # rubocop:disable Naming/FileName
# rubocop:disable Naming/FileName
# frozen_string_literal: true
unless Rails.env.production?
require 'haml_lint/haml_visitor'
require 'haml_lint/linter'
require 'haml_lint/linter_registry'
......
# frozen_string_literal: true
module JSONWebToken
class RSAToken < Token
attr_reader :key_file
......
# frozen_string_literal: true
module JSONWebToken
class Token
attr_accessor :issuer, :subject, :audience, :id
......
# frozen_string_literal: true
module Mattermost
ClientError = Class.new(Mattermost::Error)
......
# frozen_string_literal: true
module Mattermost
class Command < Client
def create(params)
......
# frozen_string_literal: true
module Mattermost
Error = Class.new(StandardError)
end
# frozen_string_literal: true
module Mattermost
class NoSessionError < Mattermost::Error
def message
......
# frozen_string_literal: true
module Mattermost
class Team < Client
# Returns all teams that the current user is a member of
......
# frozen_string_literal: true
module MicrosoftTeams
class Activity
def initialize(title:, subtitle:, text:, image:)
......
# frozen_string_literal: true
module MicrosoftTeams
class Notifier
def initialize(webhook)
......
# frozen_string_literal: true
module ObjectStorage
#
# The DirectUpload c;ass generates a set of presigned URLs
......
# frozen_string_literal: true
require 'omniauth-oauth2'
module OmniAuth
......
# frozen_string_literal: true
require 'omniauth'
require 'jwt'
......
# frozen_string_literal: true
module Peek
module Rblineprof
module CustomControllerHelpers
......@@ -41,7 +43,7 @@ module Peek
]
end.sort_by{ |a,b,c,d,e,f| -f }
output = "<div class='modal-dialog modal-xl'><div class='modal-content'>"
output = ["<div class='modal-dialog modal-xl'><div class='modal-content'>"]
output << "<div class='modal-header'>"
output << "<h4>Line profiling: #{human_description(params[:lineprofiler])}</h4>"
output << "<button class='close' type='button' data-dismiss='modal' aria-label='close'><span aria-hidden='true'>&times;</span></button>"
......@@ -93,7 +95,7 @@ module Peek
output << "</div></div></div>"
response.body += "<div class='modal' id='modal-peek-line-profile' tabindex=-1>#{output}</div>".html_safe
response.body += "<div class='modal' id='modal-peek-line-profile' tabindex=-1>#{output.join}</div>".html_safe
end
ret
......
# frozen_string_literal: true
module Peek
module Views
class Gitaly < View
......
# frozen_string_literal: true
module Peek
module Views
class Host < View
......
# frozen_string_literal: true
module Rouge
module Formatters
class HTMLGitlab < Rouge::Formatters::HTML
......
# frozen_string_literal: true
# A rouge plugin for CommonMark markdown engine.
# Used to highlight code generated by CommonMark.
......
# frozen_string_literal: true
module RspecFlaky
class Config
def self.generate_report?
......
# frozen_string_literal: true
module RspecFlaky
# This is a wrapper class for RSpec::Core::Example
class Example
......
# frozen_string_literal: true
module RspecFlaky
# This represents a flaky RSpec example and is mainly meant to be saved in a JSON file
class FlakyExample < OpenStruct
......
# frozen_string_literal: true
require 'active_support/hash_with_indifferent_access'
require_relative 'flaky_example'
......
# frozen_string_literal: true
require 'json'
require_dependency 'rspec_flaky/config'
......
# frozen_string_literal: true
require 'json'
require 'time'
......
# frozen_string_literal: true
module SystemCheck
module App
class ActiveUsersCheck < SystemCheck::BaseCheck
......
# frozen_string_literal: true
module SystemCheck
module App
class DatabaseConfigExistsCheck < SystemCheck::BaseCheck
......
# frozen_string_literal: true
module SystemCheck
module App
class GitConfigCheck < SystemCheck::BaseCheck
......
# frozen_string_literal: true
module SystemCheck
module App
class GitUserDefaultSSHConfigCheck < SystemCheck::BaseCheck
......
# frozen_string_literal: true
module SystemCheck
module App
class GitVersionCheck < SystemCheck::BaseCheck
......
# frozen_string_literal: true
module SystemCheck
module App
class GitlabConfigExistsCheck < SystemCheck::BaseCheck
......
# frozen_string_literal: true
module SystemCheck
module App
class GitlabConfigUpToDateCheck < SystemCheck::BaseCheck
......
# frozen_string_literal: true
module SystemCheck
module App
class InitScriptExistsCheck < SystemCheck::BaseCheck
......
# frozen_string_literal: true
module SystemCheck
module App
class InitScriptUpToDateCheck < SystemCheck::BaseCheck
......
# frozen_string_literal: true
module SystemCheck
module App
class LogWritableCheck < SystemCheck::BaseCheck
......
# frozen_string_literal: true
module SystemCheck
module App
class MigrationsAreUpCheck < SystemCheck::BaseCheck
......
# frozen_string_literal: true
module SystemCheck
module App
class OrphanedGroupMembersCheck < SystemCheck::BaseCheck
......
# frozen_string_literal: true
module SystemCheck
module App
class ProjectsHaveNamespaceCheck < SystemCheck::BaseCheck
......
# frozen_string_literal: true
module SystemCheck
module App
class RedisVersionCheck < SystemCheck::BaseCheck
......
# frozen_string_literal: true
module SystemCheck
module App
class RubyVersionCheck < SystemCheck::BaseCheck
......
# frozen_string_literal: true
module SystemCheck
module App
class TmpWritableCheck < SystemCheck::BaseCheck
......
# frozen_string_literal: true
module SystemCheck
module App
class UploadsDirectoryExistsCheck < SystemCheck::BaseCheck
......
# frozen_string_literal: true
module SystemCheck
module App
class UploadsPathPermissionCheck < SystemCheck::BaseCheck
......
# frozen_string_literal: true
module SystemCheck
module App
class UploadsPathTmpPermissionCheck < SystemCheck::BaseCheck
......
# frozen_string_literal: true
module SystemCheck
# Base class for Checks. You must inherit from here
# and implement the methods below when necessary
......
# frozen_string_literal: true
module SystemCheck
module Helpers
include ::Gitlab::TaskHelpers
......
# frozen_string_literal: true
module SystemCheck
module IncomingEmail
class ForemanConfiguredCheck < SystemCheck::BaseCheck
......
# frozen_string_literal: true
module SystemCheck
module IncomingEmail
class ImapAuthenticationCheck < SystemCheck::BaseCheck
......
# frozen_string_literal: true
module SystemCheck
module IncomingEmail
class InitdConfiguredCheck < SystemCheck::BaseCheck
......
# frozen_string_literal: true
module SystemCheck
module IncomingEmail
class MailRoomRunningCheck < SystemCheck::BaseCheck
......
# frozen_string_literal: true
module SystemCheck
module Orphans
class NamespaceCheck < SystemCheck::BaseCheck
......
# frozen_string_literal: true
module SystemCheck
module Orphans
class RepositoryCheck < SystemCheck::BaseCheck
......
# frozen_string_literal: true
module SystemCheck
# Simple Executor is current default executor for GitLab
# It is a simple port from display logic in the old check.rake
......
......@@ -101,4 +101,25 @@ describe 'Group show page' do
expect(page).to have_emoji('smile')
end
end
context 'where group has projects' do
let(:user) { create(:user) }
before do
group.add_owner(user)
sign_in(user)
end
it 'allows users to sorts projects by most stars', :js do
project1 = create(:project, namespace: group, star_count: 2)
project2 = create(:project, namespace: group, star_count: 3)
project3 = create(:project, namespace: group, star_count: 0)
visit group_path(group, sort: :stars_desc)
expect(find('.group-row:nth-child(1) .namespace-title > a')).to have_content(project2.title)
expect(find('.group-row:nth-child(2) .namespace-title > a')).to have_content(project1.title)
expect(find('.group-row:nth-child(3) .namespace-title > a')).to have_content(project3.title)
end
end
end
......@@ -66,7 +66,7 @@ describe BranchesFinder do
context 'filter and sort' do
it 'filters branches by name and sorts by recently_updated' do
params = { sort: 'updated_desc', search: 'feature' }
params = { sort: 'updated_desc', search: 'feat' }
branches_finder = described_class.new(repository, params)
result = branches_finder.execute
......@@ -75,6 +75,17 @@ describe BranchesFinder do
expect(result.count).to eq(2)
end
it 'filters branches by name and sorts by recently_updated, with exact matches first' do
params = { sort: 'updated_desc', search: 'feature' }
branches_finder = described_class.new(repository, params)
result = branches_finder.execute
expect(result.first.name).to eq('feature')
expect(result.second.name).to eq('feature_conflict')
expect(result.count).to eq(2)
end
it 'filters branches by name and sorts by last_updated' do
params = { sort: 'updated_asc', search: 'feature' }
branches_finder = described_class.new(repository, params)
......@@ -84,6 +95,26 @@ describe BranchesFinder do
expect(result.first.name).to eq('feature')
expect(result.count).to eq(2)
end
it 'filters branches by name that begins with' do
params = { search: '^feature_' }
branches_finder = described_class.new(repository, params)
result = branches_finder.execute
expect(result.first.name).to eq('feature_conflict')
expect(result.count).to eq(1)
end
it 'filters branches by name that ends with' do
params = { search: 'feature$' }
branches_finder = described_class.new(repository, params)
result = branches_finder.execute
expect(result.first.name).to eq('feature')
expect(result.count).to eq(1)
end
end
end
end
......@@ -41,7 +41,7 @@ describe('Job App ', () => {
};
const props = {
runnerHelpUrl: 'help/runners',
runnerSettingsUrl: 'settings/ci-cd/runners',
};
beforeEach(() => {
......
......@@ -422,7 +422,7 @@ describe('Job State actions', () => {
beforeEach(() => {
mockedState.job.pipeline = {
path: `${TEST_HOST}/endpoint.json/stages`,
path: `${TEST_HOST}/endpoint`,
};
mock = new MockAdapter(axios);
});
......@@ -434,7 +434,7 @@ describe('Job State actions', () => {
describe('success', () => {
it('dispatches requestStages and receiveStagesSuccess, fetchJobsForStage ', done => {
mock
.onGet(`${TEST_HOST}/endpoint.json/stages`)
.onGet(`${TEST_HOST}/endpoint.json`)
.replyOnce(200, { details: { stages: [{ id: 121212, name: 'build' }] } });
testAction(
......
# frozen_string_literal: true
require 'spec_helper'
describe Gitlab::GonHelper do
let(:helper) do
Class.new do
include Gitlab::GonHelper
end.new
end
describe '#push_frontend_feature_flag' do
it 'pushes a feature flag to the frontend' do
gon = instance_double('gon')
allow(helper)
.to receive(:gon)
.and_return(gon)
expect(Feature)
.to receive(:enabled?)
.with(:my_feature_flag, 10)
.and_return(true)
expect(gon)
.to receive(:push)
.with({ features: { 'myFeatureFlag' => true } }, true)
helper.push_frontend_feature_flag(:my_feature_flag, 10)
end
end
end
......@@ -65,10 +65,12 @@ describe Projects::DestroyService do
context 'Sidekiq inline' do
before do
# Run sidekiq immediatly to check that renamed repository will be removed
# Run sidekiq immediately to check that renamed repository will be removed
perform_enqueued_jobs { destroy_project(project, user, {}) }
end
it_behaves_like 'deleting the project'
context 'when has remote mirrors' do
let!(:project) do
create(:project, :repository, namespace: user.namespace).tap do |project|
......@@ -82,13 +84,28 @@ describe Projects::DestroyService do
end
end
it_behaves_like 'deleting the project'
it 'invalidates personal_project_count cache' do
expect(user).to receive(:invalidate_personal_projects_count)
destroy_project(project, user)
end
context 'when project has exports' do
let!(:project_with_export) do
create(:project, :repository, namespace: user.namespace).tap do |project|
create(:import_export_upload,
project: project,
export_file: fixture_file_upload('spec/fixtures/project_export.tar.gz'))
end
end
let!(:async) { true }
it 'destroys project and export' do
expect { destroy_project(project_with_export, user) }.to change(ImportExportUpload, :count).by(-1)
expect(Project.all).not_to include(project_with_export)
end
end
end
context 'Sidekiq fake' do
......
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